Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ext/gd/tests/avif_decode_encode.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ gd

// Note we could also forgive a certain number of pixel differences.
// With the current test image, we just didn't need to.
echo 'How many pixels are different in the two images? ';
print_r(calc_image_dissimilarity($img, $img_from_avif));
echo 'What is the mean squared error of the two images? ';
print_r(mse($img, $img_from_avif));

unlink($outfile);

Expand All @@ -79,4 +79,4 @@ Encoding AVIF with illegal quality: imageavif(): Argument #3 ($quality) must be
Encoding AVIF with illegal speed: imageavif(): Argument #4 ($speed) must be between -1 and 10
Encoding AVIF losslessly... ok
Decoding the AVIF we just wrote...
How many pixels are different in the two images? 0
What is the mean squared error of the two images? 0
37 changes: 10 additions & 27 deletions ext/gd/tests/func.inc
Original file line number Diff line number Diff line change
Expand Up @@ -156,39 +156,22 @@ function trycatch_dump(...$tests) {
}

/**
* A very simple algorithm for finding the dissimilarity between images,
* mainly useful for checking lossy compression.
* Calculate the mean squared error (in range 0..255**2)
*/

/**
* Calculates the euclidean distance of two RGB values.
*/
function calc_pixel_distance(int $color1, int $color2): float
{
return sqrt(
((($color1 >> 16) & 0xFF) - (($color2 >> 16) & 0xFF)) ** 2 +
((($color1 >> 8) & 0xFF) - (($color2 >> 8) & 0xFF)) ** 2 +
((($color1 >> 0) & 0xFF) - (($color2 >> 0) & 0xFF)) ** 2
);
}

/**
* Calculates dissimilarity of two images.
*
* The dissimilarity. 0 means the images are identical. The higher
* the value, the more dissimilar are the images.
*/
function calc_image_dissimilarity(GdImage $image1, GdImage $image2): float
function mse(GdImage $image1, GdImage $image2): float
{
assert(imageistruecolor($image1) && imageistruecolor($image2));
assert(imagesx($image1) === imagesx($image2) && imagesy($image1) === imagesy($image2));
$dissimilarity = 0;
$e = $count = 0;
for ($j = 0, $m = imagesy($image1); $j < $m; $j++) {
for ($i = 0, $n = imagesx($image1); $i < $n; $i++) {
$color1 = imagecolorat($image1, $i, $j);
$color2 = imagecolorat($image2, $i, $j);
$dissimilarity += calc_pixel_distance($color1, $color2);
$c1 = imagecolorat($image1, $i, $j);
$c2 = imagecolorat($image2, $i, $j);
$e += ((($c1 >> 16) & 255) - (($c2 >> 16) & 255)) ** 2
+ ((($c1 >> 8) & 255) - (($c2 >> 8) & 255)) ** 2
+ ((($c1 >> 0) & 255) - (($c2 >> 0) & 255)) ** 2;
Comment on lines +170 to +172
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just stumbled upon libgd/libgd#751, where the differences are divided by the maximum value, thus yielding values in range [0, 1] (instead of [0, 255]), so the squares would stay in range [0, 1] (instead of [0, 65025]), as would the final result of mse(). That might be even better (at least wrt possibly adding alpha support later).

$count += 3;
}
}
return $dissimilarity;
return $e / $count;
}
4 changes: 2 additions & 2 deletions ext/gd/tests/webp_basic.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ imagewebp($im1, $filename);
$im2 = imagecreatefromwebp($filename);
imagewebp($im2, $filename);
echo 'Is lossy conversion close enough? ';
var_dump(calc_image_dissimilarity($im1, $im2) < 10e5);
var_dump(mse($im1, $im2) < 500);

imagewebp($im1, $filename, IMG_WEBP_LOSSLESS);
$im_lossless = imagecreatefromwebp($filename);
echo 'Does lossless conversion work? ';
var_dump(calc_image_dissimilarity($im1, $im_lossless) == 0);
var_dump(mse($im1, $im_lossless) == 0);

try {
imagewebp($im1, $filename, -10);
Expand Down
Loading