RESIZING TRANSPARENT IMAGES WITH DJANGO + PIL
I can’t seem to get sorl thumbnail to play nice with transparent PNGs, it keeps adding weird black and grey backgrounds because it’s doesn’t maintain the alpha channel in it’s output.


Python’s PIL Module uses different versions of the Image.save() method depending on the format of the image being saved. sorl thumbnail uses the following call when it creates the final image output:
im.save(self.dest, quality=self.quality)
This call utilizes a parameter call quality which, according to the documentation is only available on JPEGs. Even changing the THUMBNAIL_EXTENSION in my settings.py file to “png” still didn’t make it maintain the alpha channel the way I had expected it to. Bug 56 is currently open for this issue at the sorl thumbnail project home.
The solution
I wanted to setup a way to pull the images off of the transparency resize them and then drop them on an opaque background of it’s own independent size.
So the first thing I did was to load in an image via PIL:

im = Image.open(filename)
So now that we’ve got our image we need to create the opaque background for it… right now we’ll just use a solid black one. Use the following PIL method call to create a background at an identical size to the original image:

bg = Image.new('RGBA', im.size, (0, 0, 0))
At this point I’ve got two images, im the logo file and bg the opaque black background. Using the PIL paste method I can stick there two together.
bg.paste(im)
which gives us the following image:

If you’re like me, you’re like – “WHAT THE HELL?!?! I just pasted a transparent PNG on a black background, why is it all white???” The answer is because you didn’t tell Python to maintain the alpha channel when it pasted.
The way that PIL deals with transparency when saving or pasting PNGs (that have a mode of “RGBA” or “P”) is to allow for a “transparency” parameter which is an integer from 0 – 255 which is sort of like a transparency tolerance for that image, and represents the “opaqueness” of the pixels to maintain transparency for. Since this is different for every image what we need to do is just maintain the value of the PNG we’re working with.
Note: that if you paste an “RGBA” image (WE ARE!), the alpha band is ignored in a paste. You can work around this by using the same image as both source image and mask – like we have below. More information at the PIL Handbook
Change the paste call to look like this:
bg.paste(im, (0, 0), im)
which produces this:


