1. Introduction
Merging multiple images into one to create a sprite file can be tedious. It can get especially time-consuming when there are plenty of images, or they change often, and the process needs to be repeated.
In this tutorial, we’ll learn how to merge images quickly in the Linux terminal with one command.
2. Use Case
Let’s say we have a web application project that uses images as buttons in navigation. We have a directory called “icons” that stores needed jpeg files for that purpose. We want to merge all these files into one sprite file that we’ll later use as a CSS sprite.
We often want to update them, so we would like to have a command or a script that will merge these icons during the project’s build.
3. Merging Images Using ImageMagick
To operate on images in the terminal we’ll use ImageMagick. We’ll get all images from the “icons” directory and append them vertically:
$ magick ./icons/*.jpg -append nav-sprite.jpg
If, for some reason, we need a horizontal sprite, we need to substitute “-append” for “+append” in the command:
$ magick ./icons/*.jpg +append nav-sprite.jpg
If we’re interested in shaving seconds from the execution time, we can also use a lightweight fork of ImageMagick called GraphicsMagick. Its usage in terms of appending images is the same:
$ gm convert ./icons/*.jpg -append nav-sprite.jpg
4. Processing Large Images
Images used as sprites are usually small. However, if we would like to process some big files, we could run into problems because of the default limits of ImageMagick. Fortunately, we can change those limits by editing ImageMagick’s “policy.xml” file.
We can find it in the “/etc/ImageMagick-7” directory (where 7 is the version of the currently installed ImageMagick). Alternatively, we can use the find command:
$ find / -name policy.xml
We are particularly interested in lines in the “resource” domain:
<policy domain="resource" name="memory" value="2GiB"/>
<policy domain="resource" name="map" value="4GiB"/>
<policy domain="resource" name="width" value="10KP"/>
<policy domain="resource" name="height" value="10KP"/>
<policy domain="resource" name="area" value="100MP"/>
<policy domain="resource" name="disk" value="16EiB"/>
<policy domain="resource" name="file" value="768"/>
<policy domain="resource" name="thread" value="4"/>
<policy domain="resource" name="time" value="3600"/>
For example, we could extend pixel limits two-fold and adjust memory accordingly:
<policy domain="resource" name="memory" value="8GiB"/>
<policy domain="resource" name="map" value="16GiB"/>
<policy domain="resource" name="width" value="20KP"/>
<policy domain="resource" name="height" value="20KP"/>
<policy domain="resource" name="area" value="400MP"/>
5. Merging Images Using Netpbm
We can also concatenate images using the Netpbm toolkit. There is a simple tool called pnmcat created to do just the thing we want, but it operates on pnm images. We will first convert our images to the pnm format, then concatenate them and finally convert them back to the desired format:
$ pnmcat -lr <(pngtopnm ./icons/1.png) <(pngtopnm ./icons/2.png) | pnmtopng > nav-sprite.png
That will work correctly as long as we merge images of the exact same sizes without transparency. If we work with images of different sizes, we need to add the “-jtop” parameter to justify images to the top of the final picture. If we work with transparency, we need to create an alpha channel mask and pass it to the pnmtopng command:
$ pnmcat -jtop -lr <(pngtopnm ./icons/1.png) <(pngtopnm ./icons/2.png) | pnmtopng -alpha <(pnmcat -black -jtop -lr <(pngtopnm -alpha ./icons/1.png) <(pngtopnm -alpha ./icons/2.png))> nav-sprite.png
6. Conclusion
In this tutorial, we learned how to use ImageMagick to merge multiple images into one. We also looked at some configuration options and extended the default memory limits. Then, we explored using the Netpbm toolkit to do the same job.