[cairo] Premultiplied transparency causes streaks in images

Paril paril at alteredsoftworks.com
Fri Nov 12 03:31:45 PST 2010

Oh, I missed your one message about GDI+ a while back. You missed my point;
I knew that Cairo was pre-multiplied and that GDI+ can do both, and I
expected that the output would contain the black outline. What I was
testing, effectively, is if the output of the premultiplied data was the
same as what happens when this premultiplied data is painted in Cairo. I
expected that the data (as from my understanding with premultiplied alpha)
would somehow be de-multiplied back into the original white-and-transparent
one (which apparently.. makes it do less operations? I really don't
understand the whole concept, and from my googling a lot of people come to
the same conclusion, probably just due to lack of understanding why
premultiplication is important). This was not the case, and what Cairo is
showing ALSO contains the black outline, which leads me to concur that
Cairos' usage of the premultiplication is causing the image to draw this
black halo in the transparent portions of the image.

On Fri, Nov 12, 2010 at 5:32 AM, Paril <paril at alteredsoftworks.com> wrote:

> The fixed code you provided outputs a single dot (you forgot the Paint()
> call, but I extrapolated), which appears fine when you look at it at face
> value, but again, if you re-add that loop I had in the first place you see
> the transparency around the corners of the circle creating black streaks.
> This is the problem.
> If you weren't able to see the output, here it is:
> http://alteredsoftworks.com/cairo/output.png
> Here's a slightly modified version with no y modification. This shows you
> the clear black outline when the brush is continuously drawn in one spot:
> http://alteredsoftworks.com/cairo/output_red.png
> I don't entirely understand your explanation; the only time you can really
> tell that it's happening is when you are drawing a bunch of lines around,
> hence why in the example I drew a capsule shape.
> ...which replaces the PaintWithAlpha operation with a
>> multiplication of the source alpha
> Actually, PaintWithAlpha was my second attempt at fixing the original code,
> which DID multiply the source alpha. I thought maybe the problem was because
> I was not using PaintWithAlpha, which appeared not to be the case.
> -P
> On Fri, Nov 12, 2010 at 5:20 AM, Andrea Canciani <ranma42 at gmail.com>wrote:
>> On Fri, Nov 12, 2010 at 10:46 AM, Paril <paril at alteredsoftworks.com>
>> wrote:
>> > Here, I just threw this together very very quickly in C#; it CLEARLY
>> shows
>> > the output "streaking" black transparent pixels down the purple brush
>> > stroke, when the expected output should show a complete purple circle
>> with
>> > the same color on the inside of the capsule-like shape.
>> >
>> > http://alteredsoftworks.com/cairo/streaking.txt
>> >
>> > It should be rather easy to convert to C/C++. I used no .NET-specific
>> > classes; DevIL for the image loading and Cairo for the drawing, just as
>> I
>> > use in the actual program.
>> >
>> > The reason I suspect premultiplication is because the only time these
>> > streaks can be created is when the background transparency is turned
>> from
>> > white to black - which is done by multiplying the color values by their
>> > alpha. If all of the images' alpha and color values remain, when they
>> are
>> > blended they should not create any streaks at all.
>> Observation: your code is (should be, as I'm unable to test it) equivalent
>> to the attached one, which replaces the PaintWithAlpha operation with a
>> multiplication of the source alpha
>> The problem is caused by color quantization (and amplified by
>> premultiplication).
>> In your case:
>> Brush color: ARGB = (0.16, 0.42, 0.7, 1) -> [40, 17, 28, 40] premultiplied
>> 8bit
>> Where the brush image is opaque, you actually get this values, but where
>> it
>> is not, you end up with smaller values, for example:
>> Image alpha: 15 (in 8 bit integer) -> [2, 1, 1, 2] (or something like
>> that)
>> When you composite multiple times this pixel over itself you would expect
>> the original color, you obviously will get something very different
>> (something like: 40, 20, 20, 40, if my example computations were correct).
>> I think that integer formats are not well suited for repeated compositing
>> of the
>> same image as they obviously break the assumption:
>> n*color OVER clear == color OVER^n clear
>> which you seem to rely on.
>> NB: this would be a problem with nonpremultiplied as well, but it would be
>> much
>> harder to notice (because it would only affect alpha, instead of both
>> alpha and
>> color).
>> Example: (assuming 8-bit nonpremultiplied compositing)
>> Start color: opaque red (1, 0, 0, 1) = [255, 0, 0, 255]
>> Use it with a very light brush (1/1000), so that the color becomes [0,
>> 0, 0, 255]
>> Even if you composite it 1000 times, you don't get opaque red.
>> I hope I managed to guess what is the real issue.
>> I'm not sure as I'm unable to test it, but it would be be confirmed if
>> the attachment streaking-working.txt (or something along that lines)
>> worked
>> (or at least showed much less artifacts).
>> Andrea
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cairographics.org/archives/cairo/attachments/20101112/a705ea54/attachment-0001.htm>

More information about the cairo mailing list