Optimize your website images

If you check your page with Google’s Pagespeed, you’ll probably notice that your images are not properly compressed. It’s useful to compress images for atleast two reasons:

  • Save bandwith
    • Image lossless compression and removing of meta-data will save you atleast 10% of bandwidth. Probably even more.
  • Higher SEO score
    • I’ve noticed that better optimized images are also indicators that you care about your site and bandwidth and Google and others might reward that.

Compressing images

There are few tools that are recommened by Google’s Pagespeed and I’ve decided to use two tools for optimizing images. For JPEG images, I use JPEGTran. It’s free, it’s available for Windows and Linux and it’s pretty fast. For PNG images, I use OptiPNG. Also free and available for Windows and Linux.

Compressing JPEG images

Here’s an example on how much bandwidth you can safe using jpegtran to compress the image. My sample image is 107.594 bytes in size. Issuing the following command from shell:

/usr/local/bin/jpegtran -copy none -optimize -outfile t_opt.jpg t.jpg

This command will perform optimization of entropy encoding parameters (-optimize flag) and will also suppress all comments and other excess baggage present in the source file (-copy none flag). The final image size is 73.085 bytes, which is 34.509 smaller than original (more that 30%!).

Compressing PNG images

Here’s an example on how much bandwidth you can safe using optipng to compress PNG images.  My sample image is 714.215 bytes in size. Issuing the follwing command from shell:

/usr/local/bin/optipng -o5 -quiet -strip all -out t_opt.png t.png

This command will perform multiple IDAT compression trials (-o5 flag) and strip all metadata objects from PNG file (-strip all flag). The final image size is 432.635, which is 281.580 smaller than original (almost 40%!).

Automatically compress images

I’ve written a small PHP script, that will scan my sites directories and compress all JPEG and PNG images that are not already compressed. It’s simple and rather fast. Feel free to use or change it.

#!/usr/bin/php -q
<?php
/**
 * Compress all JPEG and PNG images.
 *
 * @author Dejan Markic <d@blrf.net>
 * @licence Use it as you wish
 */

// specify path to optipng
define('OPTIPNG_BIN', '/usr/local/bin/optipng');
// specify path to jpegtran
define('JPEGTRAN_BIN', '/usr/local/bin/jpegtran');

/**
 * Specify directories to check
 */
$arrDirs = 
    array(
        __DIR__ . '/example.net'
    );

$compressed_files =
$dirs = 
$files = 0;

$finfo = finfo_open(FILEINFO_MIME_TYPE);

foreach($arrDirs as $dir){
    echo ">>> Processing: $dir\n";
    check_dir($dir);
}

echo " ----------------------\n";
echo " Processed $dirs dir(s) and $files file(s)\n";
echo " Optimized $compressed_files file(s)\n";
echo "\n";

function optimize_file($mime, $filename){
    $check_file = $filename . '.opt';
    if (file_exists($check_file))
        return true;
    $optimized = false;
    switch($mime){
        case 'image/png':
            echo " +++ Compressing: $filename\n";
            $cmd = OPTIPNG_BIN . ' -fix -o5 -quiet -strip all ' . $filename;
            $arrOutput = array();
            $ret = NULL;
            exec($cmd, $arrOutput, $ret);
            if ($ret != 0){
                throw new Exception('Command: ' . $cmd . ' returned non-0 value: ' . $ret);
            }
            echo " +++ Done: $filename\n";
            $optimized = true;
            break;
        case 'image/jpeg':
            echo " +++ Compressing: $filename\n";
            $cmd = JPEGTRAN_BIN . ' -copy none -optimize -outfile ' . $filename . ' ' . $filename;
            $arrOutput = array();
            $ret = NULL;
            exec($cmd, $arrOutput, $ret);
            if ($ret != 0){
                throw new Exception('Command: ' . $cmd . ' returned non-0 value: ' . $ret);
            }
            echo " +++ Done: $filename\n";
            break;
        default:
            return true;
    }
    if ($optimized === true){
        if (touch($check_file) === false){
            throw new Exception('Failed to create check file: ' . $check_file);
        }
    }
    return true;
}

function check_dir($dir){
        global $compress_files, $dirs, $files, $finfo;
        echo ">> DIRECTORY: $dir ==\n";
        $ret = 0;
        $d = dir($dir);
        while (false !== ($entry = $d->read())){
                if ($entry == '.' || $entry == '..')
                        continue;
                $filename = $dir . '/' . $entry;
                if (is_file($filename)){
                        ++$files;
                        ++$ret;
                        $mime = finfo_file($finfo, $filename);
                        echo " - " . basename($filename) . ": $mime\n";
                        if (fnmatch('image/*', $mime)){
                            optimize_file($mime, $filename);
                        }
                }
                elseif(is_dir($filename)){
                        ++$dirs;
                        $dret = check_dir($filename);
                        $ret += $dret;
                }
        }
        echo " << RETURN: $dir: $ret\n";
        return $ret;
}
?>

Sometimes, jpegtran will return error code 2 and script will fail. Don’t worry, simply rerun it and it will go on. I have to check why it returns 2.

Final toughts

I’ve noticed that on some occasions, if the image was previously already optimized, running those commands might acctualy increase it’s size for a fraction. On the other hand, some images are reduced by 30%, so I think it’s still better. Share your thoughts on image optimization my comments section.


Tags: , , , , , , , , , , , , ,

 
 
 

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close