Here's what you'll need
- Computer running linux (My example uses Ubuntu, but other variations may apply)
- Images to compress
Here are a few examples utilizing the optipng, that I have used to compress and optimize png images for my website...
Installing Optipng (Ubuntu/Debian)
sudo apt-get update
sudo apt-get install optipng
Using Optipng
It's extremely easy to use, and can compress and optimize your image files without any noticeable loss. For developers dealing with many large images, this can be crucial in saving bandwidth and speeding up load times. Optipng will also work with BMP, GIF, PNM, or TIFF image formats as well. I use PNG in my examples as the image formats below.
I like to use the -o7 option as shown in the examples below, but keep in mind, although description of quickly referred to in the title of this article, is meant more in the terms of a "set it and forget it' task. Large high resolution and complex images can take a long time to compress. As an example, I had some images shot with my Panasonic DMC-ZS7 ( a common middle of the road point-n-shoot) camera which were 4320x2432px and over 10MB in size took about an hour for optipng to optimise and compress each image. If that high of a resolution is not needed, you can resize them and compress the smaller image much more efficiently.
On the same machine, I ran 27 images that were scaled down to approximately 1280x720px took less than an hour.
Compress and overwrite an image
This will overwrite your existing image, if you want to preserve the existing image, without modification, see the example "Compress and write a new image" below
optipng -o7 <path-and-directory><image.png>
- -o7 - highest optimization
example:
optipng -o7 ~/images/Image_0034.png
Optimize all of the files in a single directory, writing over the existing images
optipng -o7 ~/images/*.png
Recursively optimize all of the files in a directory and it's children directories, writing over the existing images
cd <path-and-directory>find -name '*.png' -print0 | xargs -0 optipng -o7
Compress and write a new Image
This will write new images (with a different name) into the same directory (preserving your existing files)
optipng -o7 <path-and-directory><image.png> -out <path-and-directory><new-image.png>
- -o7 - highest optimization
example:
optipng -o7 ~/images/Image_0034.png -out ~/images/Image_0034_Compressed.png
Optimize all of the files in a single directory and write to a new directory with the same file names (preserving your existing files). This is the command that I tend to use the most.
optipng -o7 ~/images/*.png -dir ~/images/compressed/
Something a little extra...get your geek on!
This is completely optional and will not provide any further benefit in compressing your images. I like to easily view and compare the amount of reduction optipng was able to perform. Utilizing the power of the command line and tools such as awk, we can quickly do this. Optipng will output the percentage of compression as its completed each file, but rather then to scroll through all of the files, I decided to find another way.
Print all the file names and sizes that are located in a directory
This is optional but you can use this for a later time to do a side-by-side comparison of the size reduction to each individual image you compress. In the example shown below I use the command ls to retrieve the file names and file sizes from a particular directory. Typically it may not be the best idea to rely on the output of ls to retrieve the information needed. This is partially due to being able to use non-printable characters in the use of file names in linux, where ls maybe substituting non-printable characters in its output and possibly could differ on different distributions. For my everyday needs this is not an issue.
Below examples are assuming you only have image files in your directory that you are compressing. It does not take into account directories that may have other types of files.
ls -lp ~/images/| grep -v / | awk '{ if ($5 > 0) printf ("%i ", $5); else next; for (i=9; i<=NF; i++)printf("%s ", $i); printf("\n")}'
or better yet, print both directory listings into a temporary file for later analysis
ls -lp ~/images/| grep -v / | awk '{ if ($5 > 0) printf ("%i ", $5); else next; for (i=9; i<=NF; i++)printf("%s ", $i); printf("\n")}' > /tmp/before.txt
ls -lp ~/images/compressed | grep -v / | awk '{ if ($5 > 0) printf ("%i ", $5); else next; for (i=9; i<=NF; i++)printf("%s ", $i); printf("\n")}' > /tmp/after.txt
This example uses the directories "~/images/" and "~/images/compressed" for the image directories used to compare the file sizes, you can modify that as needed. The command ls lists out the contents of the directories "~/images", -lp lists out in long file names and indicates directories with "/". Grep with "-v /" states to grab any line except with a "/", and finally awk prints columns 5 and 9 and anything after 9 (in case of spaces in a file name) to the temporary file "/tmp/before.txt".
Compare on-screen the file size and percentage reduction on each image
This does work, but Ok, this gets a little silly. There are better ways of achieving this, and much less cryptic to read, but just as a fun challenge I wanted to see if I could mange to do this with awk with a single line. It worked for me, but YMMV. If you saved two separate txt files as described above (before.txt and after.txt), you can run this to see the results
awk 'BEGIN { OFS="\t"} FNR==NR { a[(FNR"")] = $1; next } { if((a[(FNR"")]) > 0) printf ("%d%%\t"), ((((((a[(FNR"")]) - $1)/ (a[(FNR"")])) * 100))) ; else next; printf (a[(FNR"")]) ; printf ("\t%i\t", $1); for (i=2; i<=NF; i++)printf("%s ",$i); printf ("\n") }' /tmp/before.txt /tmp/after.txt
or if you completed multiple image optimizations while saving them into a new directory, combine the actions (saving a temporary file of both directory listings, and compare the size of each file) into a single line.
ls -lp ~/images/| grep -v / | awk '{ if ($5 > 0) printf ("%i ", $5); else next; for (i=9; i<=NF; i++)printf("%s ", $i); printf("\n")}' > /tmp/before.txt && ls -lp ~/images/compressed | grep -v / | awk '{ if ($5 > 0) printf ("%i ", $5); else next; for (i=9; i<=NF; i++)printf("%s ", $i); printf("\n")}' > /tmp/after.txt && awk 'BEGIN { OFS="\t"} FNR==NR { a[(FNR"")] = $1; next } { if((a[(FNR"")]) > 0) printf ("%d%%\t"), ((((((a[(FNR"")]) - $1)/ (a[(FNR"")])) * 100))) ; else next; printf (a[(FNR"")]) ; printf ("\t%i\t", $1); for (i=2; i<=NF; i++)printf("%s ",$i); printf ("\n") }' /tmp/before.txt /tmp/after.txt
Below is my screen output showing the results of some misc images that I had compressed, starting with percentage (rounded to a whole number), file size before compression, file size after compression, and file name.
References
http://mywiki.wooledge.org/ParsingLs
http://www.math.utah.edu/docs/info/gawk_7.html
http://optipng.sourceforge.net/pngtech/optipng.html
http://stackoverflow.com/questions/14984340/using-awk-to-process-input-from-multiple-files
http://stackoverflow.com/questions/1602035/print-third-column-to-last-column