The benefits of PNGs are obvious: it’s lossless and it supports transparency (alpha).
Unfortunately, that means these files are humongous. As PNGs get more complex, every pixel gets recorded so a product shot might be 1000KB as PNG, and 50KB as a JPEG looking not all that much worse.
If you try to convert a PNG to a JPEG via Sorl thumbnail library, it will by default use a white background, and for some reason causes artifacting as well on partial alphas such as shadows.
Ideally, we have a super high quality PNG that can be converted and optimized to a JPG on the fly, so I created a PIL sorl thumbnail engine that accepts a new template tag argument: “background” – which is an RGB color that will be applied as the background color to an RGBA image source.
Apparently, my solution is the simplest, and fastest of the RGBA->JPG methods described at this stack overflow question.
The Code: Converting Transparent PNGs to JPEGs with Background Colors
""" Sorl Thumbnail Engine that accepts background color --------------------------------------------------- Created on Sunday, February 2012 by Yuji Tomita """ from PIL import Image, ImageColor from sorl.thumbnail.engines.pil_engine import Engine class Engine(Engine): def create(self, image, geometry, options): thumb = super(Engine, self).create(image, geometry, options) if options.get('background'): try: background = Image.new('RGB', thumb.size, ImageColor.getcolor(options.get('background'), 'RGB')) background.paste(thumb, mask=thumb.split()[3]) # 3 is the alpha of an RGBA image. return background except Exception, e: return thumb return thumb
Now, just modify your thumbnail engine setting
THUMBNAIL_ENGINE = 'path.to.Engine'
Usage
{% thumbnail my_file "100x100" format="JPEG" background="#333333" as thumb %} <img src="{{ thumb.url }}" /> {% endthumbnail %}
Done!
Conclusion
Now, we can store/upload one copy of a perfect PNG and have the website automatically generate an optimized JPEG regardless of the situation. Seriously amazing.
Need a smaller PNG? done.
Need a smaller JPEG with background color black? done.
3 Comments