The problem in the code you pointed to can be improved by rounding the
result (add 0x80 before shifting by 8).

result = S + D * (((256 - (A + (A>>7))) + 0x80) >> 8)

What you're proposing is interesting, essentially:

result = S + (D * (256 - A))>>8

Basically, this has a bigger error, but it is biased on the "opaque"
side, so it never causes a pixel to become more transparent. It looks
like it works very well for the premultiplied alpha case above. I'll
put this on the list of stuff to investigate further :-)
Thanks for the feedback.


Mathias



On Feb 27, 1:56 am, Eric <[email protected]> wrote:
> Correct, that is why I mentioned it cannot be used in all cases. The
> fact is that for some PorterDuff modes (see the SrcOver example
> above ) the current implementation with the shift optimization
> produces incorrect results because fully opaque pixels (with alpha
> 255) that should remain fully opaque turn into partially transparent
> pixels (with alpha 254). It is only a very slight difference but it
> can be avoided.
>
> On Feb 27, 8:52 am, pixelflinger <[email protected]> wrote:
>
> > Hello,
>
> > If you compute the errors, that is:
>
> > a*float(256/255) - (a + (a>>7))
>
> > and
>
> > a*float(256/255) - (a + 1)
>
> > you'll see that the former is a better choice; the maximum error is
> > smaller (0.5 instead of 1.0)
>
> > The later is also incorrect per the OpenGL blending specification
> > because it doesn't map "0" to "0" (you're lucky in that specific
> > example, but if you were to dither the result, it wouldn't work).
>
> > Additionally, doing the actual computation in integer:
>
> > (a * 256)/255
>
> > will give you the same result than with the equation used in skia.
>
> > Mathias
>
> > On Feb 26, 11:04 am, Eric <[email protected]> wrote:
>
> > > When using some of the PorterDuff modes in the Android SDK incorrect
> > > alpha values are produced. For example the following:
>
> > > Bitmap bitmap = Bitmap.createBitmap(100, 100,
> > > Bitmap.Config.ARGB_8888);
> > > bitmap.eraseColor(0xff000000); // Black with alpha 255
> > > Canvas canvas = new Canvas(bitmap);
> > > canvas.drawColor(0x80000000, PorterDuff.Mode.SRC_OVER);  // Black with
> > > alpha 128
>
> > > results in 0xfe000000 so an alpha value of 254 instead of 255
>
> > > After some digging in the source code I traced it back to incorrect
> > > use of SkAlpha255To256 defined in
>
> > > platform/external/skia.git/include/core/SkColorPriv.h
>
> > > 34 static inline unsigned SkAlpha255To256(U8CPU alpha) {
> > > 35     SkASSERT(SkToU8(alpha) == alpha);
> > > 36     return alpha + (alpha >> 7);
> > > 37 }
>
> > > It is frequently used in the PorterDuff blending functions, below is
> > > SRC_OVER from:
>
> > > platform/external/skia.git/src/core/SkXfermode.cpp
>
> > > 347 //  kSrcOver_Mode,  //!< [Sa + (1 - Sa)*Da, Sc + (1 - Sa)*Dc]
> > > 348 static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
> > > 349     return src + SkAlphaMulQ(dst, SkAlpha255To256(255 -
> > > SkGetPackedA32(src)));
> > > 350 }
>
> > > Running the above numbers for alpha it produces 128 + (255 * 127) >> 8
> > > = 254. Doing it without the shift optimization returns 128 + (255 *
> > > 127) / 255 = 255.
>
> > > Fro some of these functions (not all) it would be better to use a
> > > SkAlpha255To256 defined as
>
> > > static inline unsigned SkAlpha255To256(U8CPU alpha) {
> > >      SkASSERT(SkToU8(alpha) == alpha);
> > >      return alpha + 1;
>
> > > }
>
> > > which is not 100% accurate either but you can still use the shift
> > > trick and it does produce correct result when alpha is 0 and when
> > > alpha is 255. Any thoughts?
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"android-framework" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/android-framework?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to