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:

Bad JPEG from transparent PNG

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:

Best JPEG from transparent PNG

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 image info
  • For GIF output, if the original image’s mode is RGBA, convert to RGB 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!

Best quality transparent GIF

Feel free to check the GIF files that were produced for each algorithm:

Devil is in the details. Check out my implementation.

References