Using the CLI to Optimise Images

By James Steel on

5 minutes | Performance

Use the CLI to optimise images

The Problem

Images are a great way to add interest to your site, but handled badly and they can really drag down your sites performance. There are some tools you can use as part of your build process to keep them shipshape.

There are two main ways you can deal with this. Desktop tools can do a great job if you want to just optimise a few images by hand. ImageOptim can handle png, gif and jpeg files, and allows you to drag and drop a batch of them into its window.

It runs the images through a number of CLI tools to find the best optimisation. PNG images can be further enhanced if you run the image through it's partner tool first. ImageAlpha uses palette reduction and other techniques to make a huge difference on your images, particularly if they have alpha transparency.

Thats great if you have just a few images to worry about, but it doesn't help much on large projects with dozens of images. How can we automate this, and how can also optimise SVG files?

Enter the CLI.

The Solution

Time to tool up. Once you have ImageOptim-CLI and ImageOptim itself installed, we can add some new rules to our package file to help us out.

First of all, we should add some paths as variables to our config block in package.json. This will make them easier to manage, and save us some typing. Depending on the CMS you are using, you may not need three of these, but our weapon of choice is Kirby. For us, there are three places that images can be placed:

"config": {
  "content": "./public/content",
  "thumbs": "./public/thumbs",
  "assets": "./public/assets/images",
},

With those set, lets deal with our first rules to optimise images within those folders:

"images:assets:min": "imageoptim -d $npm_package_config_assets",
"images:thumbs:min": "imageoptim -d $npm_package_config_thumbs",
"images:content:min": "imageoptim -d $npm_package_config_content",

If you run those commands, it should launch ImageOptim and recursively work through all the images below that directory. That's pretty awesome, but it will get tedious running those commands individually. Let's tie them all into one, and still keep the option to run individually:

"images:min": "yarn images:content:min && yarn images:thumbs:min && yarn images:assets:min",
"images:assets:min": "imageoptim -d $npm_package_config_assets",
"images:thumbs:min": "imageoptim -d $npm_package_config_thumbs",
"images:content:min": "imageoptim -d $npm_package_config_content",

Now, running yarn images:min will rip through all those folders optimise any images it finds, as long as they are PNG, Gif, or Jpeg files. Fantastic, but we may have SVG files in those directories which won't be touched. Let's take things a little further…

Optimising SVG Files

We can also use the CLI for this - SVGO. Install it globally.

You may have noticed that we have a small problem here. SVGO can only handle a single input and output. It can optimise images in a folder as long as they are all in the same folder. This is obviously still no good - we need it to work anywhere within the tree, at any level.

Fortunately, thanks to bash and Unix, were there is a will, there is a way. We can use the Unix find command to locate all .svg files below a given path and pipe the results through to svgo.

find $npm_package_config_assets -name '*.svg' -type f -exec svgo  {} \\;

Magic!

Wrapping up

Finally, we can combine the SVG rules with the ImageOptim CLI rules, so we end up with a single command image optimising powerhouse:

"images:min": "yarn images:content:min && yarn images:thumbs:min && yarn images:assets:min",
"images:content:min": "imageoptim -d $npm_package_config_content && find $npm_package_config_content -name '*.svg' -type f -exec svgo  {} \\;",
"images:thumbs:min": "imageoptim -d $npm_package_config_thumbs && find $npm_package_config_thumbs -name '*.svg' -type f -exec svgo  {} \\;",
"images:assets:min": "imageoptim -d $npm_package_config_assets && find $npm_package_config_assets -name '*.svg' -type f -exec svgo  {} \\;",

The Windows Problem

These are all Mac tools, so what if your on Windows? You can use ImageMagick instead, and SVGO should work fine on Windows via the Ubuntu terminal that is available in the most recent builds of Windows 10.

With some tweaking, there may be other ways to do this if your on earlier versions of Windows. Google is your friend here.

A basic rule for ImageMagik looks like this:

find $npm_package_config_content -name '*.jpg' -exec convert {} -sampling-factor 4:2:0 -strip -quality 80 -interlace JPEG -colorspace RGB {} \\; -exec echo {} \\;

Here's a full set of ImageMagick compatible rules:

"images:min": "yarn magick:content:min && yarn magick:thumbs:min && yarn magick:assets:min",
"magick:content:min": "find $npm_package_config_content -name '*.jpg' -exec convert {} -sampling-factor 4:2:0 -strip -quality 80 -interlace JPEG -colorspace RGB {} \\; -exec echo {} \\; && find $npm_package_config_content -name '*.png' -exec convert {} -strip {} \\; -exec echo {} \\; && find $npm_package_config_content -name '*.svg' -type f -exec svgo  {} \\;",
"magick:thumbs:min": "find $npm_package_config_thumbs -name '*.jpg' -exec convert {} -sampling-factor 4:2:0 -strip -quality 80 -interlace JPEG -colorspace RGB {} \\; -exec echo {} \\;  && find $npm_package_config_thumbs -name '*.png' -exec convert {} -strip {} \\; -exec echo {} \\; && find $npm_package_config_thumbs -name '*.svg' -type f -exec svgo  {} \\;",
"magick:assets:min": "find $npm_package_config_assets -name '*.jpg' -exec convert {} -sampling-factor 4:2:0 -strip -quality 80 -interlace JPEG -colorspace RGB {} \\; -exec echo {} \\;  && find $npm_package_config_assets -name '*.png' -exec convert {} -strip {} \\; -exec echo {} \\; && find $npm_package_config_assets -name '*.svg' -type f -exec svgo  {} \\;",

Conclusion

It's as simple as that. In jut a few short rules, we now have an effective way to optimise the imagery in your site with ease.

Go forth and optimise.