[Image-SIG] Antialiased text on transparent image fails?

Laszlo Nagy gandalf at shopzeus.com
Tue Nov 20 18:59:49 CET 2007

  Hi Coen,

I'm sorry for the late answer.  I was out of the country.

> Isn't this the way it should work? The alpha value of a pixel is 
> treated the same way as any other channel. When a pixel is half 
> covered by a shape, PIL wil draw 50% of the foreground and 50% of the 
> background. In your case: a green shape 0, 255, 0, 255 (rgba) and 
> background 255, 0, 0, 0. If you take the average of the two you come 
> up with R=128 in the pixel and will be visible for 50% A=128. Isn't 
> this the desired effect?
Not desired for me. When you put a transparent image I1 on another image 
I2, then you should see what you would see from I2, plus what you would 
see from I2 that is under I1. Let me tell you an example. Let's have two 
pieces of glass, G1 and G2.

G1 is:  (0,255,0,128), representing a material that is, when you put 
white light on it:

    a.) 50% the red component is absorbed, 50% goes through
    b.) 50% is reflected, 50% goes through
    c.) 50% the blue component is absorbed, 50% goes through

G2 is:  (255,0,0,2), representing an almost clear, fully transparent 
glass, when you put white light on it:

    a.) a very few of the red component is reflected, the remaining goes 
    b.) a very few of the green component is absorbed, the remaining 
goes through
    c.) a very few of the blue component is absorbed, the remaining goes 

Maybe my interpretation is bad, but this is how I think it is - the 
alpha channel gives transparency, the other channels tells us how many 
of the remaining light is reflected vs. absorbed. 255 means full 
reflect, whereas 0 means full absorption.

Now what happens if you put a piece of G1 on top of G2, put a white lamp 
(255,255,255) over it and examine the result? How much red you will see 
in it? Will it be (128,128,0) or (1,128,0)? Of course, the later.

There are other scenarios: you can put the lamp behind it, you can let 
them shine etc. Any scenario you choose, you will not see too much red 
in it because there is nothing in G1 or G2 that could reflect or let 
throught much more red then green or blue.

Maybe I'm wrong and I have misinterpreted the meaning of the alpha 
channel. In that case I wonder what it means?

And finally, I'm still interested in the good method, e.g. how can I 
achieve the same effect with PIL, effectively? I'm asking this because 
all of the methods in PIL will take the average of the two alpha 
channels, and this is bad for me. Calculating pixels values one by one 
would work but it is not effective.



p.s.: I do not like top posting, but once you started with it, I did not 
want to "mid post". :-)

> And if it would be a color? Don't you want the same to happen?
> The solution? Render the shape on a 0,0,0,0 background. No red will be 
> added, your half filled pixel with a correct alpha value will blend 
> with new backgrounds as it is supposed to. You can save this image in 
> various ways for later use.
> Just my thought... and i hope it helps.
> Greetings,
> Coen
> Laszlo Nagy wrote:
>> Hi All,
>> I tried to put a text on a transparent image. Here is a test:
>> import Image
>> import ImageDraw
>> import ImageFont
>> img = Image.new('RGBA',(100,20),(255,0,0,0))
>> drawer = ImageDraw.Draw(img)
>> fnt = ImageFont.truetype("Vera.ttf",20) # 
>> http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/1.10/
>> drawer.text((0,0),"ABCDE",font=fnt,fill="#00ff00")
>> img.save("test.png") # Result image
>> I'm working on a rendering engine but I created this example to show 
>> the problem. The rendering engine should be able to create an image 
>> with transparent parts, and one should be able to put the rendered 
>> image on top of any other image.
>> The problem itself: font edges are interpolated between the 
>> background and foreground color. You can see it on the resulting 
>> image. If you open the created "test.png" file in GIMP and use the 
>> color picker tool then you can see values like:
>> (203,52,0,52)
>> (215,40,0,40)
>> I think that this is bad. The background was fully transparent. If 
>> you put a green object on a fully transparent thing, you should never 
>> see any red in it. I believe that the result should be something like
>> (0,52,0,52)
>> (0,40,0,40)
>> In other words, when antialiasing a text, the background pixel's 
>> color should be weighted with its transparency. In my example, the 
>> background pixel is fully red but should have zero weight.
>> Workarounds?
>> Working with black or white initial background is not a workaround, 
>> because PIL will darken/lighten the pixels. I used red+green just to 
>> make the problem more visible. A correct workaround is to use the 
>> actual target background that will finally be used, but it is not a 
>> good workaround. This is obvious: I want to render the result image 
>> once, then put it on different target images. Rendering the result 
>> image each time I need to put it on a target would be very slow.
>> Can you please confirm if this is a bug in PIL?  Comments welcome.
>> Best,
>>   Laszlo
>> ------------------------------------------------------------------------
>> ------------------------------------------------------------------------
>> _______________________________________________
>> Image-SIG maillist  -  Image-SIG at python.org
>> http://mail.python.org/mailman/listinfo/image-sig

More information about the Image-SIG mailing list