Recipe: compress PNG with zopflipng

uhop edited this page Dec 1, 2014 · 5 revisions

PNG files produced by grunt-tight-sprite are ultimately created using node-canvas package, which is not very good at compression. 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 zopflipng of zopfli. In this recipe I call it using grunt-exec plugin.

Installing dependencies

First, you should install and compile zopfli, if it is not readily available on your platform:

git clone https://code.google.com/p/zopfli/
cd zopfli
make zopflipng

Now you can move it to be in your default path, or call it directly by absolute name. The example below assumes a default path.

Gruntfile

Now we are ready to write a gruntfile:

grunt.loadNpmTasks('grunt-tight-sprite');
grunt.loadNpmTasks('grunt-exec');

grunt.initConfig({
  tight_sprite: {
    icons: {
      options: {
        hide: "tests/icons"
      }
      src: ["tests/icons/*/**/*.{png,jpg,jpeg,gif}"],
      dest: "tests/icons/sprite.png"
    }
  },
  exec: {
    compress_icons: {
        cmd: [
          "zopflipng -m <%= tight_sprite.icons.dest %> " +
            "<%= tight_sprite.icons.dest %>.zopfli",
          "mv <%= tight_sprite.icons.dest %>.zopfli " +
            "<%= tight_sprite.icons.dest %>"
        ].join(" && ")
    }
  }
});

grunt.registerTask("sprite", ["tight_sprite:icons", "exec:compress_icons"]);

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