On Friday, October 21, 2011, Michael Droettboom <mdroe@stsci.edu> wrote:
> On 10/21/2011 09:49 AM, Daniel Hyams wrote:
>> All sounds reasonable Mike; I do agree that patching the agg source
>> code is not that desirable; I was operating under the (incorrect)
>> assumption that most, if not all, backends used straight alpha.
>> I'll certainly test the patch tonight, but I can only test it under
>> wxAgg reasonably, which is one of the backends that expects straight
>> alpha as far as I know.
>> The "loss in picture detail" comment was just discomfort with the fact
>> that once the alphas are premultiplied in, there is not an exact
>> reverse transformation to get your original color back. In googling
>> around to better explain here, I found this, which is a much more in
>> depth and better explanation than what I would have come up with:
>> http://www.quasimondo.com/archives/000665.php
>> The crux is here:
>>> An example: when you set the alpha value of a pixel to 16 all color values will be multiplied with
>>> a factor of 16/256 = 0.0625. So a gray pixel of 128 will become 128 * 0.0625 = 8, a darker pixel
>>> of 64 will become 64 * 0.0625 = 4. But a slightly lighter pixel of maybe 67 will become 67 *
>>> 0.0625 = 4.1875 - yet there are no decimals in integer pixels which means it will also become
>>> 4. The effect that you will get posterization - setting your alpha channel to 8 means that you
>>> also reduce your color channels to 8 levels, this means instead = 256*256*256 different colors
>>> you will end up with a maximum of 8*8*8 = 512 different colors.
>> One might argue that the loss of color information is not that
>> crucial, because for very low alpha (where the problem is most
>> pronounced), the image is almost invisible anyway... so it won't
>> matter. That's true, but what if I want to (for whatever reason) take
>> the image's pixels again, before draw, and boost the alpha up again?
>> What I'll get is a posterized mess.  So, I'm still of the opinion that
>> patching agg in this situation might be the best solution to this.
>> This way, straight alphas are used throughout, and for backends that
>> require premultiplied alpha, the alpha can be premultiplied in at the
>> latest possible moment.
> Thanks for clarifying.  I understand what you're saying now.  I think
> what we want to do is store the unmultiplied alpha as a "canonical"
> version of the image, and premultiply a copy (or use some C++ iterator
> magic to avoid the copy) right before sending it off to Agg.  Then the
> alpha can be fully "tweakable" at runtime.
> I'll try to tackle this problem, as well as the problem that set_alpha
> simply doesn't work, at the same time when I get a chance (or patches
> are always welcome, of course :).
> Mike


This idea is sort of along the same vein of the idea that I have been having for unifying the colors framework and allowing for transforms to be performed upon access of the colors.  If you think about it, the issue of different backends wanting different information can be dealt with by having a transform that returns pre multiplied alphas and another that returns straight alphas.  The backends can then solely the desired transform that it expects.

I guess the question is whether the transformation step should be generalized at the python level, or specialized down at the python/c++ boundary.

I really wish I had more time this semester to try and come up with a proof of concept.

Ben Root

P.S. - I had also noticed alpha-blending issues before (and asked about it), but I ended up convincing myself (apparently wrongly) that it was correct.