Friday, 20 September 2019

PHP wrong result for imagetruecolortopalette with PNG with transparency

I'm trying to write a script that resizes a PNG image and then converts it to PNG-8 bit mode, so the size of the resulting file will be smaller but without a too high quality loss.

originalImage

The resize works perfectly, preserving also the transparency.

The problem is when I convert it in 8 bit:

imagetruecolortopalette($resizedImg, true, 255);

imagealphablending($resizedImg, false);

$transparent = imagecolorallocatealpha($resizedImg, 255, 255, 255, 127);
if(!imagefill($resizedImg, 0, 0, $transparent)) return false;

imagesavealpha($resizedImg, true);

The resulting image is this, with the transparency all around and a little inside the image:

enter image description here

If I set 256 colors instead of 255:

imagetruecolortopalette($resizedImg, true, 256);

the image will be with black background:

enter image description here

A similar result occurs with this image (note the half transparency for the case with 255 colors):

original: enter image description here 255 colors: enter image description here 256 colors: enter image description here

The complete function's code:

function resizePng($originalPath, $xImgNew='', $yImgNew='', $newPath='')
{
    if(!trim($originalPath) || !$xyOriginalPath = getimagesize("$originalPath")) return false;
    list($xImg, $yImg) = $xyOriginalPath;

    if(!$originalImg = imagecreatefrompng($originalPath)) return false;

    if(!$resizedImg = imagecreatetruecolor($xImgNew, $yImgNew)) return false;

    // preserve alpha
    imagealphablending($resizedImg, false);
    $transparent = imagecolorallocatealpha($resizedImg, 255, 255, 255, 127);
    if(!imagefill($resizedImg, 0, 0, $transparent)) return false;
    imagesavealpha($resizedImg, true);

    // copy content from originalImg to resizedImg
    if(!imagecopyresampled($resizedImg, $originalImg, 0, 0, 0, 0, $xImgNew, $yImgNew, $xImg, $yImg)) return false;

    // PNG-8 bit conversion
    imagetruecolortopalette($resizedImg, true, 255);

    // preserve alpha
    imagealphablending($resizedImg, false);
    $transparent = imagecolorallocatealpha($resizedImg, 255, 255, 255, 127);
    if(!imagefill($resizedImg, 0, 0, $transparent)) return false;
    imagesavealpha($resizedImg, true);

    if(!imagepng($resizedImg, ($newPath) ?: null, 8)) return false;

    return true;
}

What I tried:

  • https://stackoverflow.com/a/8144620/2342558

    // PNG-8 bit conversion
    imagetruecolortopalette($resizedImg, true, 255);
    
    imagesavealpha($resizedImg, true);
    imagecolortransparent($resizedImg, imagecolorat($resizedImg,0,0));
    
    // preserve alpha
    imagealphablending($resizedImg, false);
    $transparent = imagecolorallocatealpha($resizedImg, 255, 255, 255, 127);
    if(!imagefill($resizedImg, 0, 0, $transparent)) return false;
    imagesavealpha($resizedImg, true);
    
    if(!imagepng($resizedImg, ($newPath) ?: null, 8)) return false;
    
    

results:

enter image description here enter image description here

nothing change

  • others SO posts and some on the Web

Also without resizing the image (removing imagecopyresampled and adapting the variables name) the result is the same.

Can you please help me to make it work and to understand the reason of this strange behavior?

Some info in phpinfo():

  • PHP 7.0.33
  • GD bundled (2.1.0 compatible)
  • PNG Support enabled
  • libPNG 1.5.13.

Edit:

In GIMP I can save an image for Web with these properties:

PNG-8
256 colors palette
Dither: Floyd-Steinberg / Floyd-Steinberg 2 / positioned

enter image description here

and it produce a reduced image almost identical of the original.

Also pngquant, tinypng, and many others do the same work.

Thanks a lot!



from PHP wrong result for imagetruecolortopalette with PNG with transparency

1 comment: