[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