While investigating ways to get the Cairo graphics API to draw a single-pixel line, I found this explanation in the FAQ. It explains why often a single-pixel line gets drawn as a half-intensity line two pixels wide.

The reason that cairo does it this way is so that fills align nicely, at the cost that some strokes do not. It is not possible to set up sample locations in a way so that both fills and strokes with integer coordinates work nicely, so one had to be preferred over the other. One argument in favor of preferring fills is that all fills with integer coordinates align nicely this way. The best that can be done with strokes is to make all even-integer-width strokes align nicely (as they do in cairo) or to make odd-integer-width strokes align (which would then break the fill alignment).

After reading this explanation, I still don't understand why this is a problem with graphics generally. What do they mean by odd-integer-width strokes breaking the fill alignment? Why is it such a problem to have both fill and stroke aligned to whole pixels?

I guess I don't really understand why or how the stroke width affects the fill at all.


Why is it such a problem to have both fill and stroke aligned to whole pixels?

It's not a problem at all. But you have to understand the used coordinate system and specify your coordinates accordingly.

Here, use integer coordinates for fills and even-width lines, but pixel-midpoint coordinates (i.e. floating point numbers ending with .5) for odd-width lines.

I don't really understand why or how the stroke width affects the fill at all.

It's not the stroke width, it's the choice of coordinate system. By choosing a coordinate grid aligned with pixel boundaries, fills bounded by integer coordinates align with pixel boundaries, while a line centered at an integer coordinate will extend to the pixels on both sides of the grid line. For lines with a width of 1, this means the line will only cover half of the pixel. Obviously, it is not possible to fill only half of a pixel, so the line will be drawn anti-aliased instead, i.e. The entire pixel will be filled with half intensity.

  • I understand why a line drawn in between a pixel will cover half on either side, but I don't understand why you need to draw the stroke from the middle of a pixel in the first place. Why can't you draw a filled box from (0,0) to (10,10) and then have your line occupy pixel at x=0 from y=0..10? – Malvineous Mar 10 '15 at 6:08
  • This would mean that the "pen" used to draw the line is not centered at the specified coordinates, but "hangs" below and to the right of them. This would be a strange and arbitrary asymmetry — why to the bottom right, and not e.g. To the top left? And how would this work with arbitrary coordinate transformations? This would cause a lot of mathematical problems and oddities. QuickDraw (the drawing API of the classic MacOS) did this, as it worked with integer coordinates, so .5 offsets were not possible. Also, QuickDraw didn't have coordinate transformations, so that problem didn't apply. – oefe Mar 10 '15 at 22:13
  • Why to the bottom right, and not the top left? Design decision, either would work. But if you assume your coordinates are pixels it doesn't matter. Instead of drawing lines between pixels, you draw them centered inside a pixel, so a stroke +0.5 either side of the mid-pixel coordinate occupies the whole pixel. How would it work with arbitrary coordinate transformations? I have no idea, which is why I'm asking the question :-) What I was really hoping for was a good example explaining the problem you encounter if you do it in a different way. – Malvineous Mar 12 '15 at 0:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.