3

I'm trying to create a function that receives a PNG image and returns it with inverted colors. However, I'm having trouble with the transparency/alpha channel: basically, transparent pixels are coming back as either black or white, and thus transparency is not retained.

This is an example of a source image (which will of course vary), a PNG with a transparent background:

enter image description here

I would like to invert those colors while preserving transparency/alpha channel, like a CTRL+I in Photoshop. I'm using GD imagefilter function with the IMG_FILTER_NEGATE parameter

With the code:

$im = imagecreatefrompng($image_file);

imagefilter($im, IMG_FILTER_NEGATE);

header('image/png');

imagepng($im,NULL,0);

But it yields:

enter image description here

As you can see, transparent pixels turned black.

I then tried adding the alpha channel to the function imagecreatefrompng (like this):

$im = imagecreatefrompng($image_file);

imagealphablending($im, false);

imagesavealpha($im, true);

imagefilter($im, IMG_FILTER_NEGATE);

header('image/png');

imagepng($im,NULL,0);

But now I get white instead of black:

enter image description here

Now the issue seems to happen after the imagefilter function is applied. For example, if I run this code:

$im = imagecreatefrompng($image_file);

imagealphablending($im, false);

imagesavealpha($im, true);

//imagefilter($im, IMG_FILTER_NEGATE);

header('image/png');

imagepng($im,NULL,0);

The output image retains its transparent background, while remaining identical to the original image.

How can I invert colors of transparent PNGs without losing the transparent background?

NOTE: this is not the same question as imagecreatefrompng() Makes a black background instead of transparent? - the inversion step is the tricky part here

steps
  • 774
  • 2
  • 16
  • 38
  • Is the PNG format 32-bit with a real alpha channel or 24-bit with one RGB value marked as transparent? – Dave S Jun 17 '17 at 22:32
  • The source images will likely come as 32-bit PNG with a real alpha channel. However since images are user-inputted, a universal solution without this knowledge in advance would be ideal – steps Jun 19 '17 at 02:26
  • I don't see any "get raw bytes" type function in GD (so you could XOR the RGB but not A), nor do I see a transform that lets you ignore the alpha channel. You could ask the GD devs for an "invert colors only" variant. – Dave S Jun 19 '17 at 03:40
  • With a 32-bit PNG your second code block works perfectly for me on PHP 7.0.17. What version are you using? – timclutton Jun 19 '17 at 13:55

1 Answers1

0

Here's what worked for me, dealing with transparent background and inverting image. Note that I'm using base64.

$im = imagecreatefromstring(base64_decode(str_replace('data:image/png;base64,', '', $base64)));
$width = imagesx($im);
$height = imagesy($im);
$dest_image = imagecreatetruecolor($width, $height);
imagealphablending($dest_image, FALSE);
imagesavealpha($dest_image, TRUE);
imagefilter($im, IMG_FILTER_NEGATE);
imagecopyresampled($dest_image, $im, 0, 0, 0, 0, $width, $height, $width, $height); 

//optional output back to base64 or use imagepng with destination
ob_start();
imagepng($dest_image);
$contents = ob_get_contents();
ob_end_clean();
$base64 = 'data:image/png;base64,'.base64_encode($contents);
Eric
  • 9,870
  • 14
  • 66
  • 102