Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transparent png resizing with Python Image Library and the halo effect

There are a couple similar questions on SO, but none of them really helped. Basically I am trying to resize a simple png image, as seen here:

http://media.spiralknights.com/wiki-images/3/3e/Equipment-Proto_Sword_icon.png (from the mmo Spiral Knights, copyright Three Rings Entertainment)

I had originally implemented a utility which uses these images in php, and the resizing utility there worked perfectly well. I used the method described on the imagecopyresampled page in PHP's documentation.

Honestly I can't even get it to resize better in Photoshop, but the results are almost disastrous in python. I consistently get a halo effect, and I believe this is at least in part to the actual RGBA values of the transparent pixels. Here, this picture tells it better:

resize examples

(the second to last resize was just a suggestion I saw on another forum to resize first to twice the final size, and it DID help at least a little, but not enough)

The image is already in RGBA mode when it is being resized.

As you can see the PHP and Photoshop resizes are halo-free. Honestly everything but the PHP resize does TOO much work, I like the minimal palette in the php image (if you look at the larger versions you can see that the PHP resize uses less in between colours), but I could live with the way Photoshop has resized it, or even the inner part of the python resize, but the halo is unacceptable.

It seems to me -- and correct me if I'm wrong -- that PHP and Photoshop seem to know not to use the colour of the pixels in the alpha channel when interpolating, but python is using that light border, which is otherwise transparent, in its resize.

Unfortunately there are a lot of different icons that I need to resize, with varying profiles, so they're not all as simple as this circular one, but this was just the first one I was using while experimenting.

It's not much of a code question in and of itself, but if you need something to look at then this is the gist:

>> import Image
>> img = Image.open('swordorig.png')
>> img
<PngImagePlugin.PngImageFile image mode=RGBA size=256x256 at 0x2A3AF58>
>> img.resize((36,36), Image.ANTIALIAS).save('swordresize.png')

Eventual question being: is there a way to tell PIL NOT to use the colour of a pixel that has an alpha of 0 while resampling?

like image 996
cogs Avatar asked Feb 04 '12 17:02

cogs


1 Answers

Thanks to everyone for answering! And especially to rotoglup for telling me the term for what I was actually looking for. Going through the stack overflow pages for premultiplied alpha in PIL I found a solution that works; here is an updated sheet of resize graphics:

resize sheet 2

The gray bars are just to give an impression of what they would look like on a lighter background.

https://stackoverflow.com/a/6882161/1189554

Thanks to madlag

So my code ends up looking like this:

>> import Image, numpy
>> img = Image.open('swordorig.png')
>> premult = numpy.fromstring(img.tostring(), dtype=numpy.uint8)
>> alphaLayer = premult[3::4] / 255.0
>> premult[::4] *= alphaLayer
>> premult[1::4] *= alphaLayer
>> premult[2::4] *= alphaLayer
>> img = Image.fromstring("RGBA", img.size, premult.tostring())
>> img.resize((36,36), Image.ANTIALIAS).save('swordresize.png')

And you get the icon that is on the bottom of the sheet. Still more colours than the PHP version, and a very mild ring, but overall much, much nicer. I'm sure the algorithm could be tweaked to improve it even more. Thanks again to everyone for responding!

like image 79
cogs Avatar answered Sep 28 '22 07:09

cogs