How to use pngquant with PHP

How to use pngquant with PHP

GIF, JPG and PNG files are the three main image formats used for the web, the difference between them is the resulting image. Each one has its place for use on websites (either as part of the UI or just user uploads). PNG files were developed to build upon the purpose of gifs. Designers need the ability to incorporate low-resolution images that load quickly but also look great, too (not as well as SVG that can be scaled, but acceptable). This is where PNG comes in. PNG files are a lossless format, meaning that compression doesn't affect the quality of the image. Unlike JPGs, which create artifacts and blur images at a certain point, a PNG file will always look at least as sharp as the original image.

For you as a developer, the format is not of importance (unless you explicitly need a special format), what matters here, is the way in which you handle the images and if you compress them, specially if you want to take care about the loading time of your website, the space they occupy in the hard disk of your server etc. To compress PNG files, you can use the known png compression library pngquant.

pngquant is a command-line utility and a library for lossy compression of PNG images. The conversion reduces file sizes significantly (in most of the case up to 70% of the filesize and almost with the same quality) and preserves full alpha transparency. Generated images are compatible with all modern web browsers, and have better fallback in IE6 than 24-bit PNGs. The best of all, it can be used with PHP.

In this article, you will learn how to use pngquant with PHP using either a library or with plain PHP.

Requirements

You will need the command line version of pngquant installed on your machine and it needs (not a must, but recommendable) accesible from the path. pngquant is available for almost all the operative systems and can be downloaded directly from the official website here.

Windows

You can download an executable of pngquant for windows from this link.

Ubuntu

To install pngquant in ubuntu, you can install it from a custom repository executing the following command in a terminal:

sudo add-apt-repository ppa:danmbox/ppa

sudo apt-get update

sudo apt-get install pngquant

MacOS

You can install pngquant using brew:

brew install pngquant

If the installation method for your operative system isn't available here, please refer to the homepage of pngquant. As mentioned previously, you can use pngquant with PHP using a wrapper library that will make the usage pretty easy or you can execute with plain PHP a console command to achieve your goal.

A. Using a library

You can use the php-pngquant library to work with pngquant. php-pngquant is a simple wrapper for the awesome pngquant CLI. If you use composer, you can install it executing the following command in your console:

composer require ourcodeworld/php-pngquant

Or in case that you don't use Composer, just download the PNGQuant.php class of the repository and add it into your code using require_once.

The PNGQuant class will do the trick for you. In the same way that the command line does, the PNGQuant class adds a method for every argument and option available in the CLI of pngquant, which makes the usage with php very intuitive.

To compress a PNG image you will need to use at least 3 methods in a instance of PNGQuant:

<?php

use ourcodeworld\PNGQuant\PNGQuant;

$instance = new PNGQuant();

// The instance of PNGQuant is chainable

$instance
    // Set image to compress
    ->setImage("/a-folder/image-original.png")
    // Path (and filename) of the output compress image
    ->setOutputImage("/a-folder/image-compressed.png")
    // pngquant throws an error if the output file exists
    // Use this method to overwrite if it exists
    ->overwriteExistingFile()
    // Set the rangeo of the quality of the image
    ->setQuality(50,80)
    // Execute the build command (compress the image)
    ->execute();

You will only need to provide the input image, and output image path and the quality range that you want for your PNG file and that's it, now you're using pngquant with PHP. However, in case of any error that pngquant may have, you won't know what happened, therefore you need to retrieve the status code generated by pngquant and compare the code with the error table:

<?php

use ourcodeworld\PNGQuant\PNGQuant;

$instance = new PNGQuant();

// Retrieve the status code generated by pngquant (with the execute method)
$status_code = $instance
    // Set image to compress
    ->setImage("/a-folder/image-original.png")
    // Path (and filename) of the output compress image
    ->setOutputImage("/a-folder/image-compressed.png")
    // pngquant throws an error if the output file exists
    // Use this method to overwrite if it exists
    ->overwriteExistingFile()
    // Set the rangeo of the quality of the image
    ->setQuality(50,80)
    // Execute the build command (compress the image)
    ->execute();

// if exit code is equal to 0 then everything went right !
if(!$exit_code){
    echo "Image succesfully compressed";
}else{
    $description = $instance->getErrorTable()[(string) $exit_code];
    
    echo "Something went wrong (status code $exit_code)  with description: ". $description;
}

A status code of 0 means that everything went as expected and the image has been compressed, otherwise please refer to the error table of pngquant here. We recommend you to read the official documentation of php-pngquant to see all the available methods and other examples.

In case that pngquant isn't available in the path, you can change the path of it using the setBinaryPath method:

<?php

use ourcodeworld\PNGQuant\PNGQuant;

$instance = new PNGQuant();

// Retrieve the status code generated by pngquant
$status_code = $instance
    // Set path to pngquant in windows
    ->setBinaryPath("C:\\Users\\sdkca\\Desktop\\pngquant.exe")
    ->setImage("/a-folder/image-original.png")
    ->setOutputImage("/a-folder/image-compressed.png")
    ->overwriteExistingFile()
    ->setQuality(50,80)
    ->execute();

Note

There are other libraries that allow you to use phpquant, however they're not specialized only with pngquant (they use other libraries and their implementation of pngquant is pretty basic) and they don't provide error handling. (This wrapper has been written by Our Code World )

B. Plain PHP

As pngquant is a command line utility, we will use the system method of php to execute a command line instruction. The command to execute is up to you, the main point is that you need to use the system method of php to retrieve the status code to know what happened with the command.

The following example shows how to use system to execute a command with a function named compress_png that expects as first parameter the path to the image to compress and as second parameter the path where the compressed file should be saved:

<?php 

function compress_png($image_input,$image_output)
{
    // Executable pngquant (or path)
    $path_pngquant = "pngquant";

    $image_output_escaped = escapeshellarg($image_output);

    // Generates a commands like:
    // pngquant image-original.png --output "/a-folder/image-compressed.png" --force --quality 50-80
    $cmd = "$path_pngquant $image_input --output $image_output_escaped --force --quality 50-80";

    $status_code = null;

    // Execute the command
    system($cmd, $status_code);

    return $status_code;
}

$exit_code = compress_png("image.png", "image-compressed.png");
 
/* Compare the exit code as you want
"0" => "SUCCESS",
"1" => "MISSING_ARGUMENT",
"2" => "READ_ERROR",
"4" => "INVALID_ARGUMENT",
"15" => "NOT_OVERWRITING_ERROR",
"16" => "CANT_WRITE_ERROR",
"17" => "OUT_OF_MEMORY_ERROR",
"18" => "WRONG_ARCHITECTURE", // Missing SSE
"24" => "PNG_OUT_OF_MEMORY_ERROR",
"25" => "LIBPNG_FATAL_ERROR",
"26" => "WRONG_INPUT_COLOR_TYPE",
"35" => "LIBPNG_INIT_ERROR",
"98" => "TOO_LARGE_FILE",
"99" => "TOO_LOW_QUALITY"
*/

Happy coding !

Become a more social person