Archive for August, 2008

Bulk Image Compression with Photoshop Droplets

Aug ‘08 10

I recently exported a bunch of photos from iPhoto for an article I am working on, and discovered there was very little compression applied. Even at a lower 640 by 480 dimension size, the 30 images totaled 5.4 MB in size!

I needed a way to quickly compress these, and then I remembered Photoshop’s ability to create Droplets. A Droplet is an icon created by Photoshop that launches Actions on files that you drag on top of it. The resulting file is then saved in a folder of your choice.

This allows me to drag all 30 images on to the Droplet, and have Photoshop compress the entire batch automatically.

For those of you that learn by watching, I created a 5 minute screencast showing how it’s done.

Get the Flash Player to see this player.

For those of you that learn by reading, read on!

Step 1: Open a Test Image

In Photoshop, open up any image. The image is not important, you simply want something you can record your actions on.

Step 2: Record a New Action

In Photoshop, open the Window…Actions panel.

actions panel

Click the Create new action button.

create new action in actions panel

Give the Action a name descriptive of what it does. We will name ours JPEG50, because this Action will save out a JPEG at 50 Quality.

Click Record.

Step 3: Save For Web

Your Action is now recording, so be careful from here on out!

Tip: If you wanted to resize the image, or apply Filters before saving, you could do that and Photoshop will record these steps!

file save for web

Click File…Save for Web & Devices.

save for web jpeg settings

Set the compression type to JPEG, and choose a Quality setting you like. We recommend 50 Quality for optimum visual quality to file size.

Unless these files will be used in Flash, always use the Progressive option. It enables your JPEGs to render progressively in your user’s browser.

Click Save.

Step 4: Choose a Location for Compressed Images

You will need to create a folder for the compressed images, so when the Action or Droplet is run you know where the resulting files go.

compressed images save folder

We will create a new folder on our Desktop called Compressed JPEG 50 Progressive, descriptive so we know what it’s for.

Create the folder and click Save.

Step 5: Stop Recording Actions

stop recording the action

Click the Stop button on the Actions panel to stop recording.

Step 6: Create a Droplet

create droplet menu

To create your Droplet, click File…Automate…Create Droplet…

save droplet in a new folder

Choose a location to save your droplet that is easy to get to, like the Desktop.

choose action for droplet

Choose the Set and Action you just created for the Droplet.

Ensure Suppress File Open Options Dialogs and Suppress Color Profile Warnings are both checked.

When finished, click OK.

Step 7: Try it!

drag files on to the droplet

Drag the images you want to compress on to the Droplet.

If all goes well, the resulting optimized JPEGs will be in the Compressed folder you created in Step 4.

Step 8: Review Results

Let’s check out the before and after in terms of quality and file size.

Before at 234 KB:

photo before optimization

After at 84 KB:

optimized photo at 50 quality

We had a savings of 150 KB, 64% of the original size! The quality is also quite good.

If you happen to be viewing this page in Safari, you will notice that the colors are different than the original. This is because Safari supports color management, and we should address this.

For you non-Safari users, here is an image showing the original (top) against the optimized (bottom) version:

grass needing color correction

Notice how the grass in the original is much richer than the optimized version. See what you are missing out on? This is because I don’t have Photoshop configured to automatically convert Color Profile mismatches to the Working Space.

Color Correction in Photoshop

To fix this, go to Edit…Color Settings.

color management in photoshop

When working on the web (RGB), you always want to use your Monitor’s profile to ensure your images look the same across browsers. In my case, it is the Color LCD profile.

Under Color Management Policies, ensure RGB is set to Convert to Working RGB and all checkboxes are off. This way you won’t be bothered again.

Finally, run your images through the Droplet again. The colors should more closely match the originals now.

After Color Correction (84 KB):

after color correction

Much better, as it was meant to be seen. Good thing we checked for quality!

Image Compression Impact on Page Load Times

Altogether, we were able to quickly optimize 30 images from 5.4 MB to 1.9 MB, a savings of 3.5 MB or 65%. Let’s see how this plays out in page load times.

I created two test pages, one with our original photos and one with our optimized photos, and ran them through Pagetest to see the difference.

Original Photos – Speed Test Results

  • Average Load Time: 33 seconds
  • Bytes In: 5439 KB

Optimized Photos – Speed Test Results

  • Average Load Time: 13 seconds
  • Bytes In: 1865 KB

Savings

  • Load Time: 20 seconds (60%)
  • Bytes In: 3574 KB (66%)

The results are in amigo – the optimized images loaded 20 seconds faster!

Final Thoughts

Droplets can be a nice way of getting your optimization work done quickly, but at the cost of missing opportunities where you might save even more bytes by saving at lower a Quality – or the reverse, compromising quality at the cost of lower bytes. Always experiment and push to find a balance between low KB and image quality.

Did you know that Pagetest has an image compression check? It tests all JPEGs to see if they are saved at the equivalent of 50% Quality in Photoshop. Use the Pagetest Optimization Report (sample of our test here) to help you spot areas of your site where you might need to share our JPEG 50 Droplet with those responsible for the heavy images.

By loading images faster, you are helping your users consume them faster and thus giving them more reason to stay around.

§

Using mod_concat to Speed Up Start Render Times

Aug ‘08 1

The most critical part of a page’s load time is the time before rendering starts. During this time, users may be tempted to bail, or try a different search result. For this reason, it is critical to optimize the <head> of your HTML to maximum performance, as nothing will be visible until it finishes loading the objects inside.

One easy way to speed up rendering during this crucial time is to combine your CSS and JavaScript, saving the performance tax associated with every outbound request. While easy in theory, in practice this can be difficult, especially for large organizations.

For example, say your ad provider wants you to include their script in a separate file so they can make updates whenever they choose. So much for combining it into your site’s global JS to reduce the request, eh?

mod_concat makes combining shared libraries easy by providing a way to dynamically concatenate many files into one.

See mod_concat in Action

We created a couple test pages to show the benefits here. In our first example without mod_concat, we see a typical large scale website with many shared CSS and JavaScript files loaded in the <head> of the HTML. There are scripts for shared widgets (two of them video players), ad code, and more that typically plague many major web sites.

You can check out the Pagetest results here, and check out the time to start render (green bar):

pagetest waterfall with mod concat disabled

In the test page, we have 12 JavaScript files and 2 CSS files, a total of 14 HTTP requests in the <head>. I have seen worse. The green vertical bar is our Start Render time, or the time it took for the user to see something, at 4 seconds!

We can see that the time spent downloading is typically the green time, or the time to first byte. This happens on every object, simply for existing! A way to make this not happen, is to combine those files into one, larger file. Page weight (bytes) stay the same, but Requests are reduced significantly.

Let’s take a look at our Pagetest results of a second example with mod_concat enabled.

pagetest waterfall of music page with modconcat enables

Notice our the number of Requests went from 14 to 5, and we saved 1.5 seconds! We probably could have made an even faster example by moving to just 2 requests (one for CSS and one for JS), but the speed win here is clear.

How mod_concat Works

mod_concat is a module for Apache built by Ian Holsman, my manager at AOL and a contributor to Apache. Ian gives credit in the mod_concat documentation to David Davis, who did it while working at Vox, and perlbal.

The idea is straightforward, and you can pretty much figure out how it works by viewing the source code of our second example:

<link rel="stylesheet" type="text/css" media="screen" ←
	href="http://lemon.holsman.net:8001/cdn/??music2.css,common.css" />
<script type="text/javascript"  ←
	src="http://lemon.holsman.net:8001/cdn/??music2.js,mp.js,dalai_llama.js,ratings_widget.js,widget_config.js,common.js"></script>
<script language="javascript" type="text/javascript" ←
	src="http://tangerine.holsman.net:8001/o/??journals_blog_this.js,adsWrapper.js,flashtag.js,feeds_subscribe.js"></script>
<script type="text/javascript"  ←
	src="http://orange.holsman.net:8001/digital/??dm_client_aol.js,cannae.js"></script>

You can see in the highlighted code above that a single request is referencing multiple files, and the server is returning the concatenated version. The URL takes the following format:

http://www.yourdomain.com/optional/path/??filename1.js,directory/filename2.js,filename3.js

Let’s break it down.

http://www.yourdomain.com/

The first bit should be straight forward, it’s the host name.

http://www.yourdomain.com/optional/path/

Next comes the optional path to the files. This is important, because you can’t concatenate files above this directory if you include it. However, it allows you to optimize a bit so you don’t need to keep referencing the same path for files below this directory.

http://www.yourdomain.com/optional/path/??

The ?? then triggers the magic for the files that come next. It’s a special signal to Apache that it’s time to combine files!

http://www.yourdomain.com/optional/path/??filename1.js,

If the file is in the current directory, you can simply include it next, followed by a comma “,”.

http://www.yourdomain.com/optional/path/??filename1.js,directory/filename2.js,

If you need to go a bit further in the directory hierarchy, you can do that too.

http://www.yourdomain.com/optional/path/??filename1.js,directory/filename2.js,filename3.js

You can include as many files as you wish as long as they fall within the same server directory path defined early on in your optional/path/.

Performance and Caching Considerations

mod_concat uses the Last-Modified date of the most recently modified file when it generates the concatenated version. It should honor any max-age or expires Cache Control headers you set for the path in your server or htaccess configuration.

If you have a far future expires or max-age header, to bust the cache you will need to rename one of the files or directory names in the string, and then the user will download the entire concatenated version again.

Because mod_concat is an Apache module, performance is near instantaneous. Performance is improved further still if the server happens to be an origin point for a CDN, as it gets cached on the edge like an ordinary text file for as long as you tell it to, rarely hitting your servers.

Same Idea, Different Platforms

For regular folks like myself who don’t have the ability to install Apache modules with their hosting provider (cough, Lunarpages, cough), mod_concat is not the best option. The idea of concatenating JavaScript and CSS has been implemented on other platforms, and I will briefly call out those I found in my brief Googling – feel free to list more that you know of.

Rakaz’s PHP Combine Solution

Niels Leenheer of rakaz.nl has a nice solution for PHP. Niels writes:

Take for example the following URLs:

  • http://www.creatype.nl/javascript/prototype.js
  • http://www.creatype.nl/javascript/builder.js
  • http://www.creatype.nl/javascript/effects.js
  • http://www.creatype.nl/javascript/dragdrop.js
  • http://www.creatype.nl/javascript/slider.js

You can combine all these files to a single file by simply changing the URL to:

  • http://www.creatype.nl/javascript/prototype.js,builder.js,effects.js,dragdrop.js,slider.js

Niels takes advantage of Apache’s Rewrite rules as such to make the combine PHP script transparent to the template designer:

RewriteEngine On
RewriteBase /
RewriteRule ^css/(.*\.css) /combine.php?type=css&files=$1
RewriteRule ^javascript/(.*\.js) /combine.php?type=javascript&files=$1

This is nice because it keeps the PHP script and HTML template separate from each other, just like mod_concat.

Ed Elliot’s PHP Combine Solution

Ed’s solution for combining CSS and JavaScript is less flexible from a front-end template designer’s perspective, as you’ll need to touch PHP code to update the files being merged together. However, the advantages I see to his take on the problem are:

  • He masks the actual file names being combined, and
  • A new version number is automatically generated to automatically bust the cache

For folks who don’t mind digging into PHP, the above benefits may be worth the effort. I especially like the cache-busting, as it allows me to put a far future expires header without worrying if my users will get the update or not.

PHPSpeedy

Finally among the PHP scripts I found is PHPSpeedy. Also available as a plug-in for WordPress, PHPSpeedy appears to get the job done like the others, with the added benefit of automatic minification.

This might be useful for folks, but I’m the obfuscator type and promote that for production build processes. I’d love to see a safe obfuscator like YUICompressor written in C so we could turn it into a module for Apache.

Lighthttpd and mod_magnet

For users of Lighthttpd, mod_magnet can be used to do the concatenation. It appears similar in nature to Rakaz’s solution, though I will leave it to you to dig in further as it seems to be fairly involved. This blog post by Christian Winther should help get you started.

ASP.Net Combiner Control

Cozi has developed an ASP.net control to combine multiple JS and CSS into a single file, and includes a cool versioning feature much like Ed Elliot’s script. It’s very easy to use; you simply wrap the script with the control tag in the template:

<WebClientCode:CombinerControl ID="CombineScript" runat="server"><script src=" ←
	script/third-party/jquery.js" type="text/javascript"></script><script src=" ←
	script/third-party/sifr.js" type="text/javascript"></script><script src=" ←
	script/third-party/soundmanager.js" type="text/javascript"></script><script src=" ←
	script/cozi_date.js" type="text/javascript"></script></WebClientCode:CombinerControl>

It then outputs the following code at runtime:

<script src="../Combiner/Combiner.ashx?ext=js ←
	&ver=59169b00 ←
	&type=text%2fjavascript ←
	&files=!script'third-party*jquery*sifr*soundmanager*!script*cozi_date*" ←
	type="text/javascript"></script>

The only problem I see with their approach is that since the output file has query parameters, Safari and Opera won’t honor cache control headers as it assumes it is a dynamic file. This is why simply adding ?ver=123 to bust the cache is not a good idea for those browsers.

Java JSP Taglib – pack:tag

Daniel Galán y Martins developed a combine solution for Java called packtag. It follows in the spirit of PHPSpeedy and provides additional optimizations such as minification, GZIP, and caching.

It’s not obvious from the documentation what the output of the combined script looks like, but in a flow graphic it seems to include a version number, which would be cool.

The code to do the combination goes right in the JSP template, and looks like this:

<pack:script>
<src>/js/validation.js</src>
<src>/js/tracking.js</src>
<src>/js/edges.js</src>
</pack:script>

CSS can be combined too. The syntax appears to be quite flexible:

<pack:style>
<src>/main.css</src>
<src>../logout/logout.css</src>
<src>/css/**</src>
<src>http://www.example.com/css/browserfixes.css</src>
<src>/WEB-INF/css/hidden.css</src>
</pack:style>

As you can see this idea has been implemented in many languages, some with additional innovations worth considering, so if you can’t leverage mod_concat, at least use something similar as the benefits are well worth it.

Final Thoughts

mod_concat is a performant, cross-language, high-scale way to build concatenation into your build process while maintaining files separately. While it lacks automatic versioning (Ian, can we do this?), it provides a clean way to dynamically merge JS and CSS together without touching a bit of server-side code, and it works across server-side languages.

One feature I’d like to see added is a debug mode. For example, if the code throws an error it may not be apparent based on line number what file is having issues. Perhaps the filename could be included in comments at the start.

Remember, improving the time to start rendering the page is critical and you should focus on this first. With tools like mod_concat and the others mentioned here, there should be little excuse to implement this into your routine. Little pain, a lot to gain.

Please index me, experiment!

“Chlorophyll? More like BOREophyll.” — Billy Madison