[cairo] Premultiplied transparency causes streaks in images

Bill Spitzak spitzak at gmail.com
Fri Nov 12 11:34:52 PST 2010

This does look like quantization errors.

The actual problem is (if C is a color and A is an alpha value) assuming 
that compositing C*A over C will produce C. The problem is that if C*A 
is stored in an integer it is rounded, and the composite will produce 
the average of this rounded value and C. Drawing the brush many times 
will eventually make the result equal to this rounded value.

The solution is to use unpremultiplied compositing. Cairo can be made to 
do this (I think, can somebody confirm?) by using the alpha of the 
source image as the mask and doing a SOURCE operation.

The other problem is that it might be impossible to tell Cairo to read 
the png file and not perform the premultiplication. Since supposedly the 
png api is "toy" it probably wont be fixed, but you could use another 
library to read the png.

Even if this is done perfectly however this is not really how you want 
to do painting. Even in infinite resolution floating point, if you draw 
your antialiased brush repeatedly in the same point, all the 
partially-transparent pixels will converge on a fully opaque value. This 
will destroy the antialiasing. It also prevents you from using 
partially-transparent paint.

The real solution is to somehow figure out the exact antialiasing of the 
entire brush stroke. I think modern programs just do this by making a 
much bigger "stroke buffer" where the a much larger aliased brush draws 
opaque, this is then scaled down to introduce the antialiasing and 
multiplied by the color and temporarily drawn atop the image. It is 
finally composited into the image when the user raises the pen to finish 
the stroke. Some older programs used elaborate math to directly 
calculate the antialiased pen stroke, similar to Cairo's stroke algorithm.

More information about the cairo mailing list