Fruits of YAPC::Europe - Image::JpegMinimal
In which we create "instant" image previews in HTML (with a smidgen of Javascript)
After reading a bit of how Facebook makes the transfer of profile images faster for low bandwidth connections and bringing my photo gallery generator up to speed to exhibit my pictures of YAPC::Europe 2015 and Granada (that's a transient link), I thought about reimplementing the "compression" in Perl and some Javascript on the client side to reconstruct the image. I was surprised that a JPEG header is so big (around 500 bytes) and so constant between images. For pages with many images. It seems like a nice latency win to do "compression of repeating data" and send a chunk of preview images with the HTML.
With the help of Imager, it turns this image
into a tiny, tiny preview image like this
and then blows that image up and blurs it in the browser,
so that the user sees the following image until the real
image data has been loaded:
Currently, loading the thumbnails takes 200 HTTP requests and during that time, the users see nothing. Adding "frosted" pre-previews inline in the HTML increases the page size by 250 bytes for each pre-preview and 2k for the HTML but gives an instant rendering of the whole page where the complete information gets loaded afterwards. The page still works without Javascript enabled, which is important to me.
Implementing this was quite straightforward thanks to Imager. I had to build a JPEG frame parser to strip out the unwanted JPEG frames from images and to reorder them so that the header can be patched in the
same position every time. I had to write the Javascript "decoder" which reassembles the fixed header and the image data to a data: inline image again, but all of those were quite simple to do.
The CPAN release is quite rough on the edges and the Javascript can certainly be golfed to be smaller/faster. You will have to keep the Javascript inline, as the main goal of using this technique is to make a page appear to load faster even though not all assets have been loaded yet. Making a separate request for a Javascript file somewhat ruins this idea :-)
Maybe there could be a JPEGmin standard which declares the header as constant and only sends the dimensions and the payload data and some magic bytes to identify JPEGmin files. At least for thumbnails, this could really reduce the amount of data transferred by 50%.
Of course, declaring such a preview JPEGmin standard would ruin the complete idea of sending the image data together with the HTML, as then the latency and size of the HTTP requests for the JPEGmin files dwarfs the payload of the JPEGmin data.
I hope you enjoy the photos and maybe have some ideas on how this could be improved. The Github repo for the module is at https://github.com/Corion/image-jpegminimal, everything is licensed under the same terms as Perl.
And... Progressive JPEG?
https://en.wikipedia.org/wiki/JPEG#JPEG_compression
Your comment has prompted me to revisit progressive JPEGs. A cursory web search seems to suggest that browser support was spotty but might be there now. It is unclear though whether progressive JPEGs actually get rendered progressively or just pop in like normal baseline JPEGs. Also, it seems there are no convenient tools or libraries to encode JPEGs in the progressive format.
I should really set up a benchmark that tallies up the time and network traffic taken to download and display a HTML image gallery page with images inline and until the full thumbnails have loaded...
Thanks for your suggestion!