Pixel Perfect Freehand Drawing

Share

What is a Pixel Perfect Freehand Drawing?

A pixel perfect freehand drawing is a feature of pixel art editors that lets you draw pixels on an image using a freehand brush tool that paints over only a single pixel when moving diagonally.

Explanation

There are three ways to implement the brush tool in a drawing application:

Naive method: just paint a circle (called the brush dab) where the mouse cursor is when it moves. This doesn't work because if you move the mouse too quickly it will "jump" from one point to another leaving a gap between the two dabs.

Common method: when the mouse moves from coordinates X1, Y1 to X2, Y2, draw multiple dabs from one point to the other in a certain frequency. For example, if we take the difference between the two points as a vector and its length is 10, that means point 1 is 10 pixels of distance away from point 2. We can use a normalization of the vector (the same direction with length 1) to incrementally move from point 1 to point 2 at one pixel of distance at a time. This works but may be excessive for large brushes, so what typical applications do is that they use the diameter of the brush to calculate how often a dab should be painted, e.g. if a brush has 50 pixels of diameter, draw a dab every 10 pixels of distance traversed.

Pixel perfect method: the pixel perfect method follows the same idea as the common method but implements a line-drawing algorithm instead of dabs—usually the Bresenham's line algorithm. Essentially, the drawing application uses the "line tool" to draw a line between two points every time it detects the mouse cursor has moved to a new position. An implementation in C of a line drawing algorithm looks like this [https://zingl.github.io/bresenham.html] (accessed 2025-04-19):

void plotLine(int x0, int y0, int x1, int y1)
{
   int dx =  abs(x1-x0), sx = x0<x1 ? 1 : -1;
   int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1; 
   int err = dx+dy, e2; /* error value e_xy */
 
   for(;;){  /* loop */
      setPixel(x0,y0);
      if (x0==x1 && y0==y1) break;
      e2 = 2*err;
      if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
      if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
   }
}

Other methods: Aseprite and Libresprite have a rather confusing way of performing this task. Instead of simply drawing a line between two points, its algorithm temporarily draws pixels when you move the mouse from one pixel to another, and can "undo" them if you move the mouse to a different position. In other words, there is one "fixed" pixel that acts as the anchor, and when you move your mouse to any pixel around it, the newest pixel drawn is temporary until you move your mouse 2 pixels away from the anchor, making the temporary pixel the new anchor.

Written by Noel Santos.

About the Author

I'm a self-taught Brazilian programmer graduated in IT from a FATEC. In a world of increasingly complex and essential computers, I decided to use my technical expertise in hardware, desktop applications, and web technologies to create an informative resource to make PC's easier to understand.

View Comments