Was having fun today with idiff.php
- a PHP shell script to tell you if two images are visually different by comparing them pixel by pixel. If there's a difference, the script creates a third image - black background with the different pixels in green. Only after writing the script I found that there's an imagemagick command compare
that does the same 🙂
the script
The idea is that two GD images are created from the input files, also a third GD image with black background to store the diff. Loop through all the pixels and compare them one by one. If one is different, write a green pixel at the same location of the diff image.
/** * Shell script to tell if two images are identical. * If not, a third image is written - black background with the different pixels painted green * Code partially inspired by and borrowed from http://pear.php.net/Image_Text test cases */ // check if there's enough input if (empty($argv[1]) || empty($argv[2])) { echo 'gimme at least two image filenames, please.', "\n"; echo 'e.g. "php idiff.php img1.png img2.png"'; echo "\n", 'third filename is the image diff, optional, default is "diffy.png"'; exit(1); } // create images $i1 = @imagecreatefromstring(file_get_contents($argv[1])); $i2 = @imagecreatefromstring(file_get_contents($argv[2])); // check if we were given garbage if (!$i1) { echo $argv[1] . ' is not a valid image'; exit(1); } if (!$i2) { echo $argv[2] . ' is not a valid image'; exit(1); } // dimensions of the first image $sx1 = imagesx($i1); $sy1 = imagesy($i1); // compare dimensions if ($sx1 !== imagesx($i2) || $sy1 !== imagesy($i2)) { echo "The images are not even the same size"; exit(1); } // create a diff image $diffi = imagecreatetruecolor($sx1, $sy1); $green = imagecolorallocate($diffi, 0, 255, 0); imagefill($diffi, 0, 0, imagecolorallocate($diffi, 0, 0, 0)); // increment this counter when encountering a pixel diff $different_pixels = 0; // loop x and y for ($x = 0; $x < $sx1; $x++) { for ($y = 0; $y < $sy1; $y++) { $rgb1 = imagecolorat($i1, $x, $y); $pix1 = imagecolorsforindex($i1, $rgb1); $rgb2 = imagecolorat($i2, $x, $y); $pix2 = imagecolorsforindex($i2, $rgb2); if ($pix1 !== $pix2) { // different pixel // increment and paint in the diff image $different_pixels++; imagesetpixel($diffi, $x, $y, $green); } } } if (!$different_pixels) { echo "Image is the same"; exit(0); } else { if (empty($argv[3])) { $argv[3] = 'diffy.png'; // default result filename } imagepng($diffi, $argv[3]); $total = $sx1 * $sy1; echo "$different_pixels/$total different pixels, or ", number_format(100 * $different_pixels / $total, 2), '%'; exit(1); }
usage
Type in the command line something like:
php idiff.php img1.png img2.png result.png
This command will compare img1.png
with img2.png
. If they are not the same dimensions, will exit with error code. If their pixels exactly the same will exit with success code 0 and print a success message. If the images are not the same, will write the file result.png
.
If you omit result.png
, the generated file will be called diffy.png
example
img1.png:
img2.png
running the command:
>php idiff.php img1.png img2.png 70/24600 different pixels, or 0.28%
the result diffy.png:
imagemagick
yep, so after I did this I found that imagemagick has a command called compare
that does the same, only with more features, like the -fuzz option for example that allows you to specify how different should the pixels be, in order to consider them important.
the command:
>compare img1.png img2.png diffy-im.png
the diffy-im.png
result
As you can see the different pixels are red and the actual image is a very pale background. Nice.
Comments? Feedback? Find me on Twitter, Mastodon, Bluesky, LinkedIn, Threads