text colour in GB image not correct - php

I have the following code which creates an image based on whats in a mySQL db based on what has been uploaded via a form
if($bg_img){
list($img_width, $img_height, $img_type, $img_attr) = getimagesize('./images/'.$bg_img);
}
// Use image in background
$im = imagecreatefrompng(IS_DIR."/images/".$bg_img);
$fn = rgb2array($font_color);
$font_color = imagecolorallocate($im, $fn[0], $fn[1], $fn[2]);
This creates the image then assigns a font colour, and later in the code, text is added etc. All that works fine.
I have a strange issue though. I have two 8 bit PNG's. One of them is just a plain grey colour, the other one is an actual graphical image with a logo on it. If I use the basic one, the text uses the colour I have defined in $font_color (which comes from DB) without issues. If I use the more graphical one, the colour is incorrect and the imagecollorallocate doesn't seem to return a set of RGB values.
Is there something that needs to be done with certain types of PNG?

Related

PHP: How do I change a color in an 8 bit PNG (png has transparency) using GD Library

I have an 8 bit PNG (original is here: https://i.ibb.co/s3024Y8/1000x1500-autumn-leaves.png) and I want to change the colour of the leaves.
I have a list of the hex colours that need to be changed and a list of the colours they need to be changed to - all to be done dynamically. I'm working towards a solution that has to work off those lists - but that can wait. For this question, being able to change the colour of just one leaf will do.
After changing the colour of the leaf I need the image to retain its transparent areas (so I can lay it on top of another image - that part I can do).
I am quite new to the GD library and am getting confused. I understand that an 8-bit PNG (as created in Photoshop) has full alpha - and that needs to be preserved.
That leads me to the start of my code:
$im = ImageCreateFromPNG('https://i.ibb.co/s3024Y8/1000x1500-autumn-leaves.png');
ImageAlphaBlending($im, false);
imagesavealpha($im, true);
Everything I've tried after that fails miserably. By that, I mean that the colour doesn't change. No error message, just no change in colour. It seems that the following has no effect when using that image:
$myColourToChange = imagecolorallocatealpha($im, 100, 24, 11, 0); // colour of dark brown leaf
imagecolorset($im, $myColourToChange, 255, 0, 0, 0); // try changing it to red, fully opaque
I've even tried (which gives 6559755)
$myColourToChange = imagecolorresolvealpha($im, 100, 24, 11, 0);
I think things are failing (ie the colour doesn't change) because the image I'm using isn't a paletted image in the way that GD needs it to be, in order for me to use imagecolorset
I've tried converting it to one using imagetruecolortopalette but that gives unpredictable results on the image, with all sorts of artifacts not visibly present in the original image - and the colour values change slightly.
Note that the following are representations if you want to experiment, use the image link above.
Original image before imagetruecolortopalette - dark brown leaf colour: #64180B
After imagetruecolortopalette - dark brown leaf colour: #631A0C
So how do I specify the colour that needs to be changed and then change it to the given colour? If it means I must use imagetruecolortopalette how do I deal with the artifacts and the colour change I get when using it?
(I won't know in advance the location of colours that need changing, so imagecolorat won't help)
Thanks in advance :)

change color range image

I am using PHP-Imagick to convert a PDF into images, which works fine.
A simplified example:
$im = new imagick();
$im->setResolution(250,250);
$page = $pdfPath."[0]";
$im->readImage($page);
if($im->getImageColorspace() == Imagick::COLORSPACE_CMYK)
{
$im->transformImageColorspace(Imagick::COLORSPACE_SRGB);
$im->autoLevelImage();
}
$im->setImageFormat('jpg');
$im->setImageCompression(imagick::COMPRESSION_JPEG);
$im->setImageCompressionQuality(90);
$im->writeImage("page1.jpg");
However the coloring seems to differ from the original PDF, for example (see image)
left side is original PDF.
right side the rendered image, which has different colors than the original.
It seems that the original color of dark-pink turns into purle. Also red colors seem to saturate.
I have tried the following, but none worked:
reduce saturation (e.g. $im->modulateImage(100, 80, 100); ) But this causes red to become orange and yellow colors to turn greenish.(see example below)
playing around with image filter (e.g. imagefilter($im, IMG_FILTER_COLORIZE,100, 0, 0); ), but this also changes all colors.
Thinking it had to do with differences between CMYK and RGB, I have added $im->transformImageColorspace() doesn't do anything to fix this.
playing with various hue filters, but these change all colors of the image also.
Question: it seems I need to reduce the redness of the image? (I think it's the excessive red color causing the difference) without affecting the other colors, so that for example yellow remains yellow. Is there a way to do this in PHP?
The solution is to add the following line before reading the image:
The code should be:
$im->setColorspace(Imagick::COLORSPACE_SRGB);
$im->readImage($page);

How to create png from array of pixel color data in PHP?

Lets say I have an arrays of pixels. Basically an array of this data {x,y,r,g,b,a} for each pixel.
How would I go about converting all this data into an actual image file (png preferably)?
Could not find a solution. Any help would be very appreciated.
I had some time to code up a little example. You should be able to see and note that:
the red component increases towards the bottom of the image
the green component increases towards the right of the image
the blue component is absent
the alpha channel is random and between 0 (opaque) and 127 (fully transparent)
// Define width and height
$w=800;
$h=600;
// Create truecolour image so we can have infinitely many colours rather than a limited palette
$img=imagecreatetruecolor($w,$h);
imagesavealpha($img,true);
imagealphablending($img,false);
// Iterate over all pixels
for($y=0;$y<$h;$y++){
for($x=0;$x<$w;$x++){
$r = round(255*$y/$h);
$g = round(255*$x/$w);
$b = 0;
$alpha = rand(0,127);
$color = imagecolorallocatealpha($img,$r,$g,$b,$alpha);
imagesetpixel($img,$x,$y,$color);
}
}
// Save result
imagepng($img,"result.png");
I'll admit I haven't actually used this API, but looks like PHP has what you're looking for.
You create an image identifier with imagecreate or one of the related functions, then color in each pixel with imagesetpixel, using a color identifier created with imagecolorallocatealpha. From there you should be able to output as a PNG with imagepng.
It's worth noting that this image library seems to support drawing lines and shapes and other structures higher than the per-pixel level, so I'd also look into whether your code necessarily needs to build a big pixel array, rather than drawing the image some other way.

php image filter "colorize" destroys image details

i am trying to to colorize a black and white picture on my server.
i have tried doing this with multiple methods and the only one that kind-of-works is gd imagefilter via filter IMG_FILTER_COLORIZE.
it does kind of colorize the image in exactly the same color that i want, but it loses all the details on the image, as if it just trimmed black dots that were not black enough and thinned all the black lines, making them almost invisible. here is what i'm talking about:
this result was achieved with this code
$im=imagecreatefromjpeg($orig_file);
imagefilter($im, IMG_FILTER_COLORIZE, 71, 92, 10);
imagejpeg($im, $output_file, 95);
why is this happening? are there any other methods how i could colorize the image? my original image is quite large and i can't iterate over it as it is too slow; that's why i'm trying to use a library that would do this
i have managed to achieve the desired result with help of Imagick and compositeImage. here is the result
how i achieved it is kind of a trick that works only in a very specific condition- which is the need to have the background white and only black/gray objects in front (or the exact opposite). this technique wouldn't work on a background with transparency
the idea is to have 2 layers- underneath is the layer with original grayscale image and the top layer- fully filled with the desired color. then you composite these images using "COMPOSITE_LIGHTEN" (you might use other methods, like darken for example- if you have white objects on a black background)
this is the code
$base_color="#475c0a";
$im=new Imagick($orig_file);
$im2 = new Imagick();
$im2->newImage($im->getImageWidth(), $im->getImageHeight(), new ImagickPixel($base_color) );
$im->compositeImage($im2, Imagick::COMPOSITE_LIGHTEN, 0, 0);
$im->writeImage($new_image_path);
hope this will help someone out

PHP Imagemagick convert greyscale to RGB

I made a tool where people can upload photos and modify them, including desaturation, resulting in a greyscale image.
I generate the final image using PHP's GD library.
When printing these images the colors appear wrong so using Image Magick I add a color profile.
This works great except for images that have been greyscaled. The color profile gets added, but when I open the image in Photoshop, it says "The embedded ICC profile cannot be used because the ICC profile is invalid. Ignoring the profile".
In Photoshop the image is set to Greyscale rather than RGB, hence the attached RGB profile is wrong. I need it to be RGB.
I'm using the following code to add all the possible information in an attempt to make the image RGB:
<?php
$i = new Imagick();
$i->readimage('image.jpg');
$i->setimagetype(Imagick::IMGTYPE_TRUECOLOR);
$i->setimagecolorspace(Imagick::COLORSPACE_RGB);
$i->profileimage('icc', file_get_contents('AdobeRGB1998.icc'));
$i->writeimage($d);
$i->destroy();
?>
Does anyone know how to successfully set the image to RGB and attach the profile?
I did try the different methods and combinations for 'setImageProfile' and 'profileImage', also for colorspace and imagetype, but the result is always the same.
#a34z says in a comment:
"Somehow I must let PS know it is an RGB image with only grey pixels in it or something like that."
It is a fundamental error to assume that an RGB image could even contain 'gray' pixels as such!
RGB images do have pixels that are always composed of a mix of 3 colors: R ed + G reen + B lue. These are the 3 channels which are available, no more. There is no such thing as a gray channel in RGB.
What makes an RGB image look gray to our eyes is the fact that each of the 3 numerical channel values are equal or less strictly speaking, at least 'similar enough'. Of course, there is also software that can analyze the color values of the 3 channels and tell you which pixels are 'gray'. ImageMagick's histogram output would happily tell you which shades of gray you would say and use different names for those Grays. But don't be fooled by that color name: the pixel will still be composed from 3 colors with the same (or very similar) intensities, and ImageMagick will also report these values.
If you really need a pure grayscale image (that uses only one channel for the level of gray, not three), then you have to convert it to such an image type.
The two images may still look the same (if the conversion was done correctly, and if your monitor is calibrated, and if your not red-green-blind) -- but their internal file structure is different.
RGB images need ICC profiles that deal with RGB (if any), such as sRGB. For grayscale you cannot use sRGB, there you may want to use DeviceGray or something...
This worked for me to have it recognized as a truecolor image. Assuming $img is the Imagick object containing the greyscaled image, I check if it is indeed greyscale and then edit 1 random pixel and modify its red value by adding or substracting 5 values, depending on red being greater than 5 or not.
<?php
if ($img->getImageType() == Imagick::IMGTYPE_GRAYSCALE)
{
// Get the image dimensions
$dim = $img->getimagegeometry();
// Pick a random pixel
$x = rand(0, $dim['width']-1);
$y = rand(0, $dim['height']-1);
// Define our marge
$marge = 5;
//$x = 0;
//$y = 0;
// Debug info
echo "\r\nTransform greyscale to true color\r\n";
echo "Pixel [$x,$y]\n";
// Get the pixel from the image and get its color value
$pixel = $img->getimagepixelcolor($x, $x);
$color = $pixel->getcolor();
array_pop($color); // remove alpha value
// Determine old color for debug
$oldColor = 'rgb(' . implode(',',$color) . ')';
// Set new red value
$color['r'] = $color['r'] >= $marge ? $color['r']-$marge : $color['r'] + $marge;
// Build new color string
$newColor = 'rgb(' . implode(',',$color) . ')';
// Set the pixel's new color value
$pixel->setcolor($newColor);
echo "$oldColor -> $newColor\r\n\r\n";
// Draw the pixel on the image using an ImagickDraw object on the given coordinates
$draw = new ImagickDraw();
$draw->setfillcolor($pixel);
$draw->point($x, $y);
$img->drawimage($draw);
// Done,
unset($draw, $pixel);
}
// Do other stuff with $img here
?>
Hope this helps anyone in the future.

Categories