Anti-aliased Line | Xiaolin Wu's algorithm
Last Updated :
23 Jul, 2025
Anti-Aliased Line Drawing
Below is the image showing line drawn with Bresenham's line algorithm (left) and Xiaolin Wu's line algorithm (right) which smooths the line. Which one looks better to you ?

Anti Aliasing concept
Suppose we want to draw a line from point(1 , 1) to point(8 , 4) with rectangular edges. The ideal line would be the one shown in figure A . Since I want to display it on screen I cannot use that. Line needs to go through a process called
Rasterization
which would determine color of individual pixels. Several algorithms can be used like
Bresenham's Line Algorithm
,
Digital Differential Analyzer , Xiaolin Wu's line algorithm , Gupta-Sproull algorithm . Later two perform anti-aliasing or line smoothing. The result produced by first two algorithm is show in figure B.


There are few problems in Line( figure B ). 1. Pixel (4,2) has less coverage than Pixel (3,2), yet they're both drawn fully black. 2. Pixel (2,2) has almost as much coverage as (4,2), and yet it's drawn fully white. To overcome these drawbacks and produce a much smoother looking line we use Xiaolin Wu's line algorithm
Xiaolin Wu's line algorithm
Consider the figure shown below which is drawn using Bresenham’s Line Generation Algorithm . Take a segment and its initial coordinate x. By the X in the loop is added 1 towards the end of the segment. At each step, the error is calculated - the distance between the actual y-coordinate at that location and the nearest grid cell. If the error does not exceed half the height of the cell, it is filled. That's the whole algorithm.

We will modify this algorithm so that it can produce an anti-aliased line . Xiaolin Wu's line algorithm is characterized by the fact that at each step of the calculation is carried out for the two closest to the line of pixels, and they are colored with different intensity, depending on the distance. Current intersection middle pixel intensity gives 100% if the pixel is within 0.9 pixel, the intensity will be 10%. In other words, one hundred percent of the intensity is divided between the pixels which limit vector line on both sides.

In the picture the red and green color shows the distance to the two adjacent pixels. To calculate the error, you can use floating point and take the error value of the fractional part.
NOTE:
The following implementation uses
SDL library to draw pixels on screen . If you are on debian system like ubuntu just run following command to install SDL library.
sudo apt-get install libsdl2-dev
To build use
gcc filename.c -lSDL2
Note:
If the projection of the segment on the x-axis is less than the projection on the y-axis, or the beginning and end of the segment are swapped, then the algorithm will not work. To avoid this, you need to check the direction of the vector and its slope, and then swap the coordinates of the line , ultimately to reduce everything to some one or at least two cases. Following algorithm assumes that only integer co-ordinates will be given as inputs since pixel value cannot be floating point.
CPP
#include <SDL2/SDL.h>
// SDL stuff
SDL_Window* pWindow = 0;
SDL_Renderer* pRenderer = 0;
// swaps two numbers
void swap(int* a , int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// returns absolute value of number
float absolute(float x)
{
if (x < 0) return -x;
else return x;
}
// returns integer part of a floating point number
int iPartOfNumber(float x)
{
return (int)x;
}
// rounds off a number
int roundNumber(float x)
{
return iPartOfNumber(x + 0.5);
}
// returns fractional part of a number
float fPartOfNumber(float x)
{
if (x > 0) return x - iPartOfNumber(x);
else return x - (iPartOfNumber(x)+1);
}
// returns 1 - fractional part of number
float rfPartOfNumber(float x)
{
return 1 - fPartOfNumber(x);
}
// draws a pixel on screen of given brightness
// 0 <= brightness <= 1. We can use your own library
// to draw on screen
void drawPixel(int x, int y, float brightness)
{
int c = 255 * brightness;
SDL_SetRenderDrawColor(pRenderer, c, c, c, 255);
SDL_RenderDrawPoint(pRenderer, x, y);
}
void drawAALine(int x0, int y0, int x1, int y1)
{
int steep = absolute(y1 - y0) > absolute(x1 - x0);
// swap the co-ordinates if slope > 1 or we
// draw backwards
if (steep)
{
swap(&x0, &y0);
swap(&x1, &y1);
}
if (x0 > x1)
{
swap(&x0, &x1);
swap(&y0, &y1);
}
// compute the slope
float dx = x1 - x0;
float dy = y1 - y0;
float gradient = dy / dx;
if (dx == 0.0)
gradient = 1;
int xpxl1 = x0;
int xpxl2 = x1;
float intersectY = y0;
// main loop
if (steep)
{
int x;
for (x = xpxl1; x <= xpxl2; x++)
{
// pixel coverage is determined by fractional
// part of y co-ordinate
drawPixel(iPartOfNumber(intersectY), x,
rfPartOfNumber(intersectY));
drawPixel(iPartOfNumber(intersectY) - 1, x,
fPartOfNumber(intersectY));
intersectY += gradient;
}
}
else
{
int x;
for (x = xpxl1; x <= xpxl2; x++)
{
// pixel coverage is determined by fractional
// part of y co-ordinate
drawPixel(x, iPartOfNumber(intersectY),
rfPartOfNumber(intersectY));
drawPixel(x, iPartOfNumber(intersectY) - 1,
fPartOfNumber(intersectY));
intersectY += gradient;
}
}
}
// Driver code
int main(int argc, char* args[])
{
SDL_Event event;
// initialize SDL
if (SDL_Init(SDL_INIT_EVERYTHING) >= 0)
{
// if succeeded create our window
pWindow = SDL_CreateWindow("Anti-Aliased Line ",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480,
SDL_WINDOW_SHOWN);
// if the window creation succeeded create our renderer
if (pWindow != 0)
pRenderer = SDL_CreateRenderer(pWindow, -1, 0);
}
else
return 1; // sdl could not initialize
while (1)
{
if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
break;
// Sets background color to white
SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255);
SDL_RenderClear(pRenderer);
// draws a black AALine
drawAALine(80, 200, 550, 150);
// show the window
SDL_RenderPresent(pRenderer);
}
// clean up SDL
SDL_Quit();
return 0;
}
Java
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
// Class to represent a pixel
class Pixel {
int x, y;
float brightness;
public Pixel(int x, int y, float brightness) {
this.x = x;
this.y = y;
this.brightness = brightness;
}
}
public class Main extends JFrame {
private BufferedImage canvas;
// Constructor to set up the canvas and the JFrame
public Main() {
canvas = new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB);
setContentPane(new JLabel(new ImageIcon(canvas)));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(640, 480);
setLocationRelativeTo(null);
setVisible(true);
}
// Method to draw a pixel on the canvas with a given brightness
// 0 <= brightness <= 1
public void drawPixel(int x, int y, float brightness) {
int c = (int)(255 * brightness);
int color = new Color(c, c, c).getRGB();
canvas.setRGB(x, y, color);
}
// Method to swap two integers
public void swap(Pixel p1, Pixel p2) {
Pixel temp = new Pixel(p1.x, p1.y, p1.brightness);
p1.x = p2.x;
p1.y = p2.y;
p1.brightness = p2.brightness;
p2.x = temp.x;
p2.y = temp.y;
p2.brightness = temp.brightness;
}
// Method to get the absolute value of a number
public float absolute(float x) {
if (x < 0) return -x;
else return x;
}
// Method to get the integer part of a floating point number
public int iPartOfNumber(float x) {
return (int)x;
}
// Method to round off a number
public int roundNumber(float x) {
return iPartOfNumber(x + 0.5f);
}
// Method to get the fractional part of a number
public float fPartOfNumber(float x) {
if (x > 0) return x - iPartOfNumber(x);
else return x - (iPartOfNumber(x)+1);
}
// Method to get 1 - fractional part of number
public float rfPartOfNumber(float x) {
return 1 - fPartOfNumber(x);
}
// Method to draw an anti-aliased line
public void drawAALine(int x0, int y0, int x1, int y1) {
boolean steep = absolute(y1 - y0) > absolute(x1 - x0);
Pixel p1 = new Pixel(x0, y0, 1);
Pixel p2 = new Pixel(x1, y1, 1);
// Swap the coordinates if slope > 1 or we draw backwards
if (steep) {
swap(p1, p2);
}
if (p1.x > p2.x) {
swap(p1, p2);
}
// Compute the slope
float dx = p2.x - p1.x;
float dy = p2.y - p1.y;
float gradient = dy / dx;
if (dx == 0.0)
gradient = 1;
float intersectY = p1.y;
// Main loop
if (steep) {
for (int x = p1.x; x <= p2.x; x++) {
// Pixel coverage is determined by fractional part of y coordinate
drawPixel(iPartOfNumber(intersectY), x, rfPartOfNumber(intersectY));
drawPixel(iPartOfNumber(intersectY) - 1, x, fPartOfNumber(intersectY));
intersectY += gradient;
}
} else {
for (int x = p1.x; x <= p2.x; x++) {
// Pixel coverage is determined by fractional part of y coordinate
drawPixel(x, iPartOfNumber(intersectY), rfPartOfNumber(intersectY));
drawPixel(x, iPartOfNumber(intersectY) - 1, fPartOfNumber(intersectY));
intersectY += gradient;
}
}
}
// Driver code
public static void main(String[] args) {
Main frame = new Main();
frame.drawAALine(80, 200, 550, 150);
}
}
Python
# Importing required modules
import pygame
import sys
# Function to swap two numbers
def swap(a, b):
return b, a
# Function to return absolute value of number
def absolute(x):
return abs(x)
# Function to return integer part of a floating point number
def iPartOfNumber(x):
return int(x)
# Function to round off a number
def roundNumber(x):
return round(x)
# Function to return fractional part of a number
def fPartOfNumber(x):
return x - iPartOfNumber(x)
# Function to return 1 - fractional part of number
def rfPartOfNumber(x):
return 1 - fPartOfNumber(x)
# Function to draw a pixel on screen of given brightness
def drawPixel(screen, x, y, brightness):
c = int(255 * brightness)
pygame.draw.line(screen, (c, c, c), (x, y), (x+1, y))
# Function to draw an anti-aliased line
def drawAALine(screen, x0, y0, x1, y1):
steep = absolute(y1 - y0) > absolute(x1 - x0)
if steep:
x0, y0 = swap(x0, y0)
x1, y1 = swap(x1, y1)
if x0 > x1:
x0, x1 = swap(x0, x1)
y0, y1 = swap(y0, y1)
dx = x1 - x0
dy = y1 - y0
gradient = dy / dx if dx != 0 else 1
xpxl1 = x0
xpxl2 = x1
intersectY = y0
if steep:
for x in range(xpxl1, xpxl2 + 1):
drawPixel(screen, iPartOfNumber(intersectY), x, rfPartOfNumber(intersectY))
drawPixel(screen, iPartOfNumber(intersectY) - 1, x, fPartOfNumber(intersectY))
intersectY += gradient
else:
for x in range(xpxl1, xpxl2 + 1):
drawPixel(screen, x, iPartOfNumber(intersectY), rfPartOfNumber(intersectY))
drawPixel(screen, x, iPartOfNumber(intersectY) - 1, fPartOfNumber(intersectY))
intersectY += gradient
# Main function
def main():
pygame.init()
# Creating a window
screen = pygame.display.set_mode((640, 480))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Setting background color to white
screen.fill((255, 255, 255))
# Drawing a black anti-aliased line
drawAALine(screen, 80, 200, 550, 150)
# Updating the window
pygame.display.flip()
if __name__ == "__main__":
main()
JavaScript
// Function to draw a pixel on the canvas with given brightness
// 0 <= brightness <= 1
function drawPixel(ctx, x, y, brightness) {
const c = Math.floor(255 * brightness);
ctx.fillStyle = `rgb(${c}, ${c}, ${c})`;
ctx.fillRect(x, y, 1, 1);
}
function drawAALine(ctx, x0, y0, x1, y1) {
const steep = Math.abs(y1 - y0) > Math.abs(x1 - x0);
if (steep) {
[x0, y0] = [y0, x0];
[x1, y1] = [y1, x1];
}
if (x0 > x1) {
[x0, x1] = [x1, x0];
[y0, y1] = [y1, y0];
}
const dx = x1 - x0;
const dy = y1 - y0;
const gradient = dy / dx || 1;
let xpxl1 = Math.floor(x0);
let xpxl2 = Math.floor(x1);
let intersectY = y0;
if (steep) {
for (let x = xpxl1; x <= xpxl2; x++) {
drawPixel(ctx, Math.floor(intersectY), x, rfPartOfNumber(intersectY));
drawPixel(ctx, Math.floor(intersectY) - 1, x, fPartOfNumber(intersectY));
intersectY += gradient;
}
} else {
for (let x = xpxl1; x <= xpxl2; x++) {
drawPixel(ctx, x, Math.floor(intersectY), rfPartOfNumber(intersectY));
drawPixel(ctx, x, Math.floor(intersectY) - 1, fPartOfNumber(intersectY));
intersectY += gradient;
}
}
}
// Main function to draw the anti-aliased line
function main() {
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Draws the white background
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draws the black anti-aliased line
drawAALine(ctx, 80, 200, 550, 150);
}
// Execute the main function when the DOM content is loaded
document.addEventListener('DOMContentLoaded', main);
// This code is contributed by SHIVAM GUPTA
Output:

Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem