This is my first time fiddling with imagick/dynamic images. All of my images used for the layers to build an image are transparent PNG files. However, when compressing the images into one image via imagick for some reason the transparency is lost, resulting in a white background and white wherever it should be transparent. Is this a normal problem, and is there a way to fix it? Here is my section right after I list the images to use;
$composed_image = new \Imagick($images);
$image = $composed_image->mergeImageLayers(\Imagick::LAYERMETHOD_FLATTEN);
$image->setImageFormat('png');
header('Content-type: image/png');
echo $image->getImageBlob();
Figured out that I needed to go through and apply this to every image layer:
$composed_image->setImageBackgroundColor('transparent'); $composed_image->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE);
Related
I need to generate jpg images from PDF files (first page only). The PDF files are user generated, so they can contain anything. I'm currently using the following code:
// Load PDF.
$i = new Imagick;
// Create thumbnail of first page of PDF.
$i->setResolution(150, 150);
$i->loadImage("test.pdf[0]");
$i->thumbnailImage(640, 480, true);
// Remove transparency, fill transparent areas with white rather than black.
$i->setImageBackgroundColor("white");
$i->setImageAlphaChannel(11); // Imagick::ALPHACHANNEL_REMOVE
$i->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
// Output.
$i->writeImage("test.jpg");
This works as expected in that transparency becomes white instead of black. However, I've run into problems with some generated jpg images, so I ran jpeginfo on them:
$ jpeginfo -c test.jpg
test.jpg 960 x 480 32bit JFIF N 9481 Unsupported color conversion request [ERROR]
It turns out that some source PDFs actually use CMYK, and apparently are not converted to RGB when saved as jpg. So I changed my code to the following (addition of a single line) to explicitly convert to RGB:
// Load PDF.
$i = new Imagick;
// Create thumbnail of first page of PDF.
$i->setResolution(150, 150);
$i->loadImage("test.pdf[0]");
$i->thumbnailImage(640, 480, true);
// Remove transparency, fill transparent areas with white rather than black.
$i->setImageBackgroundColor("white");
$i->setImageAlphaChannel(11); // Imagick::ALPHACHANNEL_REMOVE
$i->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
// Convert to RGB to prevent creating a jpg with CMYK colors.
$i->setImageColorspace(Imagick::COLORSPACE_RGB);
// Output.
$i->writeImage("test.jpg");
This creates a jpeg with an RGB color profile, all right. However, for some obscure reason it results in an image with a black background again. In other words: the transparency problem is back. Why does Imagick do this, and more importantly, what's the solution to both the transparency problem and the CMYK problem?
The correct function to use is transformImageColorspace not setImageColorspace. transformImageColorspace is used for existing images, setImageColorspace is for new images e.g. svg drawing..
I've added it to the manual and it should show up soon.
I have a script that handles/scales uploaded images. I noticed that some of the images come out significantly darkened, and through a process of elimination tracked the darkening back to this section of code:
$scaled = new IMagick();
$scaled->newPseudoImage($original->getImageWidth(), $original->getImageHeight(), 'xc:white');
$scaled->compositeImage($original, Imagick::COMPOSITE_DEFAULT, 0, 0);
$scaled->flattenImages();
What I'm doing here is trying to eliminate issues with transparent backgrounds in some images coming through as black when I convert to jpg.
Does anyone have any idea which part of this code is darkening the image and what a good way to fix it might be?
Edit: Still haven't figured out the heart of this issue, but I did find that I can avoid doing this to images that don't need it by wrapping it in:
if($original->getImageAlphaChannel()){
I am making an avatar script from scratch and am having some problems. I got transparency working, and multi-image support for heads, bodies, shirts, etc.
Anyhow, I want to be able to generate specific sizes of the avatar within the PHP script. At this time, I have the variable $baseImage, which is an image generated using the GD script below:
$baseImage = imagecreatefrompng($startAsset);
imagealphablending($baseImage, true);
imagesavealpha($baseImage, true);
... combine all images into $base here
header("Content-type: image/png");
imagepng($baseImage);
The size of the image this generates is 350x550 (pixels) and I want to be able to get a smaller size.
I've done research but cannot find a working solution. What built-in PHP GD functions can resize this, retain transparency, and keep the great quality/colors?
There is no way to change the size of an image resource directly. Instead, you need to create a new image of the desired size and use imagecopyresampled to copy from the fullsize image to the resized one.
I had troubles resizing a PNG and maintaining small file sizes. Solution found here.
When resizing the PNG, however, I ran into problems regarding image quality. As far as I could see, GD uses indexed 8-bit-color palette which distorts text and colors get lost, see:
Original Image
Resized Image with solution given above
Resized Image with a tweak²
²The idea for the tweak I found here in stackoverflow: Create truecolor-image, resize it, and copy it to a new image, so the palette is determined based on the resampled result and the image quality is better as you can see in the image above.
// create new image
$newImageTmp = imagecreatetruecolor($newwidth,$newheight);
// we create a temporary truecolor image
// do the image resizing by copying from the original into $newImageTmp image
imagecopyresampled($newImageTmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);
// create output image
$newImage = imagecreate($newwidth,$newheight);
// copy resized truecolor image onto index-color image
imagecopy($newImage,$newImageTmp,0,0,0,0,$newwidth,$newheight);
// write image to buffer and save in variable
ob_start(); // stdout --> buffer
imagepng($newImage,NULL,6);
$newImageToSave = ob_get_contents(); // store stdout in $newImageToSave
ob_end_clean(); // clear buffer
// remove images from php buffer
imagedestroy($src);
imagedestroy($newImageTmp);
imagedestroy($newImage);
Problem: None of both results are satisfactory.
I am quite sure that there must be a way to 1. determine the color palette, and 2. maintain most of the image's colors, so that 3. the PNG looks similar to the original and has an acceptable file size.
Now, I only see going for JPG instead of PNG. But if you know a solution, it would greatly be appreciated if you let me/us know.
Thank you!
All you need is to replace
$newImage = imagecreate($newwidth,$newheight);
With
$newImage = imagecreatetruecolor($newwidth, $newheight);
Output $maxImgWidth = 200;
PHP's fork of GD doesn't have usable palette generation, so you only get PNG32 with vanialla libpng compression.
For small PNG8 with palette use pngquant, e.g. http://pngquant.org/php.html
And then compress it further with advpng or zopfli-png.
In PHP I'm trying to process an image, that is, I'm trying to make the surrounding color transparent in a jpg file. I'm using the GD library by the way.
I can directly output the image by converting it into a png using imagecreatefromjpeg and imagepng functions. But I can't find a way to make the specified color transparent. Also, some images have lighter gray artifacts around black graphics, created during saving. Is there any way I can include those as well?
I'm kind of lost. I found some answers to make a color transparent on an image but I don't know how to first convert the image without saving it into the server and then process it.
Any ideas?
EDIT: Here's my code so far. I managed to make a specified color transparent but I can't make it detect the surrounding one yet.
Most of the time images will be closed because they'l be logos or texts, saved in the allowed image formats. So I don't think I will have a major issue with gradients but it would be great if I could manage to manipulate transparency in the surrounding gradients, if any, such as drop shadows.
Is there also any way to detect if the png/gif image is already transparent? My code paints the transparent parts into black for those files now.
$file = 'images/18.jpg';
$specs = getimagesize($file);
if($specs[2] == 1) $img = imagecreatefromgif($file); //gif
elseif($specs[2] == 2) $img = imagecreatefromjpeg($file); //jpg
elseif($specs[2] == 3) $img = imagecreatefrompng($file); //png
else exit('unsupported file type!');
$newimg = imagecreatetruecolor(imagesx($img), imagesy($img));
// create a new image with the size of the old one
imagecopy($newimg,$img,0,0,0,0,imagesx($img),imagesy($img));
// copy the old one
imagedestroy($img);
// free the memory
$white = imagecolorallocate($newimg,255,255,255);
imagecolortransparent($newimg,$white);
// make white pixels transparent
header('Content-Type: image/png');
imagepng($newimg);
imagedestroy($newimg);
// and finally output the new image
You can set the transparent color with the imagecolortransparent function.