This article is part of a series. To read the former article click here.

This is part 2 of an article I wrote about a theoretical technique to reduce the filesize of PNG images with alpha-channel information by about 70% to 80%.

As this project has left the "proof of concept" phase in the meantime this article will be far more practical than its predecessor and give you a fully functional jQuery plugin and additional sources to implement the automatic generation of the reduced images.

The best and only way I found to avoid multiple requests but keep the result easily usable in javascript was to use JSON as a container format for the compressed files.

The shrinkImage jQuery plugin

The plugin for jQuery 1.7.2 should work on all major browsers across all operating systems and gracefully fallback to the original PNG image in case canvas is not supported or the AJAX request fails for any reason. As the plugin normally requires other jQuery extensions I developed I combined them all in this package. The plugin uses strict mode and passes jsHint linting with checks for bitwise operators and defined but unused variables disabled.

You will find a complete package in ZIP format available for download at the end of this article.

How to use the plugin

<script type="text/javascript">
;(function($, window, document, undefined) {
    'use strict';

    $(document).ready(function() {
		$('img[data-shrinkimage],.shrinkimage').shrinkimage({
			attribute: 'data-shrinkimage', // default
			debug:     false,              // default
			quality:   80                  // default
        });
    });
})(jQuery, window, document);
</script>

<!-- Foreground image -->
<img alt="" data-shrinkimage="img/example.png" />

<!-- Background image -->
<div class="shrinkimage" style="background-image: url(data:image/shrink,img/example.png);"></div>

<!-- Foreground image with non default quality -->
<img alt="" data-shrinkimage="img/example.png?quality=75" />

<!-- Background image with non default quality -->
<div class="shrinkimage" style="background-image: url(data:image/shrink,img/example.png?quality=75);"></div>

<!-- Foreground image with non default storage location -->
<img alt="" data-shrinkimage="img/example.png?target=img/custom.shrunk" />
         

The passed options reflect the plugins built-in default options so could be left out in this case. Remember to not use the images src attribute for this plugin because if an image has this attribute it will be requested no matter what you do afterwards. If "debug" is set to true the plugin will fallback to PNG. I implemented this because during development any kind of DOM inspector (Firebug or Chrome built-in) can become annoyingly slow due to the massive attribute values.

One thing to note is that shrinkImage always checks for the presence of a background image set via CSS and also tries to shrink it. For the same reason the images src-attribute cannot be used for foreground images shrinkImage requires a special form of data-URI for CSS background images (see example above).

You can also listen to the custom (namespaced) events shrinkimage provides to e.g. show a loading animation or whatever comes to your mind. See the following example to learn how to use shrinkImages' events:

<script type="text/javascript">
	;(function($, window, document, undefined) {
		'use strict';

		$(document).ready(function() {
			$('img[data-shrinkimage],.shrinkimage')
				.on('requested.shrinkimage', function(event, file) {
					// do something when shrinkimage requests the
					// shrunk image
				})
				.on('queued.shrinkimage', function(event, file) {
					// do something when shrinkimage queued a request
					// because the same resource is already requested
				})
				.on('cached.shrinkimage', function(event, file, compressedSize, originalSize) {
					// do something whenever shrinkimage adds a
					// shrunk version to its temporary cache
				})
				.on('loaded.shrinkimage', function(event, file, usedCache, usedFallback) {
					// do something when shrinkimage loaded/processed
					// the shrunk image (includes cache hits)
				})
				.shrinkimage({
					attribute: 'data-shrinkimage', // default
					debug:     false,              // default
					quality:   80                  // default
				});
		});
	})(jQuery, window, document);
</script>
            

ShrinkImage stores all processed shrunk images in a temporary cache at the latest processing stage possible to not have to request and/or process them again and therefore further reduces time, requests and resources needed for subsequent requests of the same file.

A practical example

Recycling the example from the previous article this is what the plugin comes up with (original image is left, compressed one is right):

Note: Again, the background pattern assigned is not part of the images but only used to visualize transparency.

Automatic serverside generation

.htaccess redirection

As mentioned in the prior article a little .htaccess magic is needed to make automatic generation possible. Make sure you have mod-rewrite enabled in Apache and put the following lines into the corresponding section:

AddType application/json .shrunk
AddType application/javascript .shrunk.jsonp

<IfModule mod_rewrite.c>
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteRule ^(.+.q(?:[0-9]+).shrunk)$ shrinkimage.php?file=$1 [QSA,L]
	RewriteRule ^(.+.q(?:[0-9]+).shrunk.jsonp)$ shrinkimage.php?file=$1&jsonp=1 [QSA,L]
</IfModule>

<Ifmodule mod_deflate.c>
	AddOutputFilterByType DEFLATE application/json application/javascript
</IfModule>
            

What these lines do is very simple: Whenever a file with the prefix ".shrunk" is requested and the file does not already exist on the servers filesystem that request is redirected to a PHP script (in the webservers root directory in this case). Requests to a file with the prefix ".shrunk.jsonp" will, in contrast, always get redirected because of the custom callback name required for JSONP. The other lines define proper content-types and enable gzip compression if supported by the requesting client.

PHP image processing

The PHP file doing all the hard work is also part of the download package and is, in the end, only an advanced example of how the processing can or has to be done. I will not go too much into details in this article but will only very briefly summarize (as promised) what the file does:

At first the file checks if the compressed version already exists. If it does not exist it will be created and stored in the directory where the original image is located (so make sure PHP has write permission to these directories). Afterwards the script will output the compressed version as JSON or JSONP, depending on what the jQuery plugin requested.

The PHP file from the download package assumes being stored in the webservers document root which might not be suitable in your case. If that is the case simply alter line 12 of the file according to your needs and also adjust your .htaccess!

Download shrinkImage package

Feel free to download the plugin and use it on your website. Any credits, feedback and bug reports are greatly appreciated :)

If you would like to stay up to date I also set up a GitHub repository for all my experiments.

› Download package

This article is part of a series. To read the former article click here.
blog comments powered by Disqus

Dirk Lüth Dirk Lüth, 41
MINISTRY
Code poetry in Javascript and PHP