I have been writing PySmile - a tool for batch processing (resize, convert) images. Resizing by ratio, to fixed width, fixed height was easy-peasy. So was conversion from non-transparent formats to any format (from JPG, BMP to JPG, BMP, PDF, PNG, GIF). However, there was a challenge converting transparent PNG to other formats: JPG, BMP, GIF, PDF. Have a look at the output:
There are 2 problems with the output:
- The background was white - We can tolerate this for non-transparent formats, otherwise what colour the transparent pixels should be?
- The surrounding boxes around the text was black - This is the real problem we need to fix
Solution for Non-transparent Output Formats (BMP, JPEG, PDF, GIF)
The problem with black surrounding boxes happens for all output formats (except PNG): BMP, GIF, JPEG, PDF.
I did a bit of digging and the solution was rather simple:
- Only do the following steps for PNG images in
RGBA
mode - Create a new image in
RGB
mode with the same size as the original, pre-fill it with default colour (I chose white, but that’s customisable) - Extract alpha channel from the original image and treat it as a mask
- Paste the original image to new image with mask = alpha channel
By doing this we will remove the black surrounding boxes and also preserve quality of the original image on the pasted content. Follow this link to see the code. Now we have high quality output:
There is a simplistic implementation that replaces transparent pixels with a specified colour (white by default, but customisable). The resulting image of such algorithm is blocky and its performance is worse that the one above. So, we have no reason to use it. Click to see for yourself: Blocky JPEG from transparent PNG
You can also check the PDF files that were produced for each algorithm:
Solution for Transparent Output Formats (PNG, GIF)
Are we done yet? Not quite. Above we have saved GIF images that are not transparent. Note that GIF does offer transparency and requires Palette
mode. So for perfection, we need to accomplish one more task: Preserve transparency for GIF & PNG files when converting/resizing from GIF & PNG.
Solution for this problem is rather straightforward. I did a bit of googling and adapted to my algorithm:
- If we are converting to PNG, go ahead, remember to preserve image
info
- For GIF output, if the original image’s mode is
Palette
, save with transparency by using imageinfo
- For GIF output, if the original image’s mode is
RGBA
, convert toRGB
like we did above - Afterwards we need to convert to
Palette
mode for GIF and have a mask extracted - Create a mask from alpha channel of the
RGBA
image:- If 0 <= alpha <= 128 => transparency mask = 255 (transparent)
- If 129 <= alpha <= 255 => transparency mask = 0 (opaque)
- We need to paste the
Palette
image created to new image through the mask - Now save the resulting
Palette
image and voila, you have transparent GIF with highest quality possible!
Feel free to check the GIF files that were produced for each algorithm:
Devil is in the details. Check out my implementation.