The recent PR #14877 [1] proposes to add the imagecompare gd function that
mimics the gdImageCompare function from libgd. I always thought that a
pixel-by-pixel matching function for two images was a big missing feature
in PHP, as the corresponding userland implementation is really, REALLY slow.
The problem with gdImageCompare is that it checks several aspects of the
two images, and fails on its core purpose. The behavior is better seen in
its source code [2] rather than explained. I see the following problems:
- The gdImageCompare is kind of buggy, as it completely disregards the
alpha channel. As a user, I would expect that two images that have a pixel
rgba(255, 0, 0, 100%) and one rgba(255, 0, 0, 50%) are considered
different, but the current implementation reports them as identical. - Checking for bitmasks is cumbersome, and it requires 9 new constants in
the global namespace (the IMG_CMP_*), which are nearly useless. Most use
cases will just want to check for this: imagecompare($im1, $im2) &
IMG_CMP_IMAGE. - The checks in gdImageCompare are also a bit arbitrary, why compare the
interlace flag but not the palette order? Why check the number of colors in
the palette if they are not even used in the image? - If a user is interested in the other checks, they can all be implemented
in userland with existing functions: imageinterlace, imagecolortransparent,
imageistruecolor, imagesx, imagesy, imagecolorstotal.
I believe PHP should only offer required building blocks and leave to the
libraries the implementation of more structured functionality. My proposal
is a completely different function called imagematch() that solves the
exact problem of the pixel-by-pixel matching, with the added value of
optionally matching portions of the images, using the following signature:
function imagematch(GdImage $image1, GdImage $image2, int $x1 = 0, int $y1
= 0, int $x2 = 0, int $y2 = 0, ?int $width = null, ?int $height = null):
bool {}
I already drafted PR #14914 [3] with the first two parameters. There is not
an equivalent libgd implementation, so the implementation is entirely on
the php side, but as you can see it's quite trivial. Even with the extended
functionality of matching portions of the images it would be just a few
extra lines of code, so not a big maintenance burden.
If an RFC is required, I'm happy to redact it after the initial feedback
round.
[1] https://github.com/php/php-src/pull/14877
[2]
https://github.com/php/php-src/blob/5586d0c7de00acbfb217e1c6321da918b96ef960/ext/gd/libgd/gd.c#L2834
[3] https://github.com/php/php-src/pull/14914
hi,
as I mentioned in the PR, this is an old function which we did not touch
for bc reasons.
I also linked a better image comparison function used for the gd tests
suite. It covers exaxf match which is what it seems you are aiming to get.
Additionally that function also return an image with the difference (the
diff images contains the channels differences).
A key, more tricky, but nevertheless important compared is a perceptual
difference, but that can be done additionally.
best,
Pierre
On Thu, Jul 11, 2024, 4:39 PM Giovanni Giacobbi giovanni@giacobbi.net
wrote:
The recent PR #14877 [1] proposes to add the imagecompare gd function that
mimics the gdImageCompare function from libgd. I always thought that a
pixel-by-pixel matching function for two images was a big missing feature
in PHP, as the corresponding userland implementation is really, REALLY slow.The problem with gdImageCompare is that it checks several aspects of the
two images, and fails on its core purpose. The behavior is better seen in
its source code [2] rather than explained. I see the following problems:
- The gdImageCompare is kind of buggy, as it completely disregards the
alpha channel. As a user, I would expect that two images that have a pixel
rgba(255, 0, 0, 100%) and one rgba(255, 0, 0, 50%) are considered
different, but the current implementation reports them as identical.- Checking for bitmasks is cumbersome, and it requires 9 new constants in
the global namespace (the IMG_CMP_*), which are nearly useless. Most use
cases will just want to check for this: imagecompare($im1, $im2) &
IMG_CMP_IMAGE.- The checks in gdImageCompare are also a bit arbitrary, why compare the
interlace flag but not the palette order? Why check the number of colors in
the palette if they are not even used in the image?- If a user is interested in the other checks, they can all be implemented
in userland with existing functions: imageinterlace, imagecolortransparent,
imageistruecolor, imagesx, imagesy, imagecolorstotal.I believe PHP should only offer required building blocks and leave to the
libraries the implementation of more structured functionality. My proposal
is a completely different function called imagematch() that solves the
exact problem of the pixel-by-pixel matching, with the added value of
optionally matching portions of the images, using the following signature:function imagematch(GdImage $image1, GdImage $image2, int $x1 = 0, int $y1
= 0, int $x2 = 0, int $y2 = 0, ?int $width = null, ?int $height = null):
bool {}I already drafted PR #14914 [3] with the first two parameters. There is
not an equivalent libgd implementation, so the implementation is entirely
on the php side, but as you can see it's quite trivial. Even with the
extended functionality of matching portions of the images it would be just
a few extra lines of code, so not a big maintenance burden.If an RFC is required, I'm happy to redact it after the initial feedback
round.[1] https://github.com/php/php-src/pull/14877
[2]
https://github.com/php/php-src/blob/5586d0c7de00acbfb217e1c6321da918b96ef960/ext/gd/libgd/gd.c#L2834
[3] https://github.com/php/php-src/pull/14914