Recipe: compress JPEG with jpegtran

Eugene Lazutkin edited this page Mar 18, 2014 · 4 revisions

JPEG files produced by grunt-tight-sprite are ultimately created using node-canvas package, which is not very good at compression. While we can always tweak the quality of a produced JPEG, the result is always can be compressed even further losslessly. While there are many utilities to do this compressing as a post-processing step, I came to rely on jpegtran, which is a part of official JPEG tools package. In this recipe I call it using grunt-exec plugin.

Recently Mozilla introduced a new project: mozjpeg. Its goal is "to provide a production-quality JPEG encoder that improves compression while maintaining compatibility with the vast majority of deployed decoders." The project looks promising. If you want to experiment with it, you can apply this recipe using mozjpeg utilities instead of jpegtran.

Installing dependencies

First, you should install jpegtran as described on its web page. You can move it to be in your default path, or call it directly by absolute name. The example below assumes a default path.


Now we are ready to write a gruntfile:


  tight_sprite: {
    pics: {
      options: {
        jpeg: {
          quality: 65
        hide: "tests/pics"
      src: ["tests/pics/*/**/*.{png,jpg,jpeg,gif}"],
      dest: "tests/pics/sprite.jpg"
  exec: {
    compress_pics: {
        cmd: [
          "jpegtran -copy none -optimize -outfile " +
            "<%= %>.jpegtran <%= %>",
          "mv <%= %>.jpegtran <%= %>"
        ].join(" && ")

grunt.registerTask("sprite", ["tight_sprite:pics", "exec:compress_pics"]);

As you can see, our compression command uses a reference to access a sprite file. Leveraging this grunt feature helps to keep all information in one place: later on we can modify the location of a sprite, and our compression task will "know" that automatically.

With this gruntfile we can build our sprite any time we want manually, or incorporate it in other tasks:

grunt sprite