Get Imagick instance out of PHP Imagine instance - php

I have an instance of PHP Imagine:
$imagine = new \Imagine\Imagick\Imagine();
Is there a way to get the wrapped Imagick instance? I need this to remove transparency from an image. If there is no way to get the instance, how can I remove transparency from an image using PHP Imagine?

I got it. The documentation of Imagine is so poor, it's ridiculous...
I had to go into the source code of Imagine to find what I needed:
$imagine = new \Imagine\Imagick\Imagine();
$image = $imagine->open($this->getFile()->getRealPath());
$imagick = $image->getImagick();
Is it save to use the imagick instance?

Here is the working code:
$imagine = new \Imagine\Imagick\Imagine();
$image = $imagine->open($source);
$imagick = $image->getImagick();
if($imagick->getImageAlphaChannel()) { #only if it has transparency
$imagick->setImageBackgroundColor("white");
$imagick = $imagick->flattenImages();
$imagick->writeImage();
$image = $imagine->open($source);
}
$image->strip(); //remove GPS, EXIF, comments, ....
$image->interlace(\Imagine\Image\ImageInterface::INTERLACE_LINE);
$image->save($dest);
This is not the optimal solution, I think. I would need a way to replace the imagick instance of Imagine, but there is no such method. So I am using a workaround:
$imagick->writeImage();
$image = $imagine->open($source);
After removing transparency, I override the original file. Then I reopen the same file with imagine, which means that Imagine is then using the right image (the one without transparency)
I tested it and it works. But I think it is not really the best solution.
How can I remove transparency in Imagick without getting a new imagick instance? This would do the trick, I think.

Related

PHP imagick or GD merge image from an array

I was looking in google but I can't find any solution.
I need merge multiple png file via php. Everything works when I declarate image path like this:
<?php
$img1 = new Imagick('face.png');
$img2 = new Imagick('glasses-1.png');
$img1->compositeImage( $img2, imagick::COMPOSITE_DEFAULT, 0, 0 );
$img1->setImageBackgroundColor('transparent');
$img_wynik = $img1->flattenImages();
$img_wynik->setImageFormat('png');
$img_wynik->writeImage( 'avatar.png' );
header('Content-type: image/png');
echo $img_wynik;
?>
But I realy need to use images array, so i made test file and it doesn't work.
I thought I can use simple array like this
$srcImagesPath = array('glasses-1.png', 'mouth-1.png') //for example
and later change my testing code to this
$img2 = new Imagick ($srcImagesPath)
but it's always give me merged face.png and last image from array.
Any idea how to build it?
$srcImagesPath is an array, so you'll need to specify an element of it instead of passing the array itself. I guess you want:
$img2 = new Imagick ($srcImagesPath[0])
or
$img2 = new Imagick ($srcImagesPath[1])
if you have the GD library installed (assuming you have):
$image1 = imagefrompng('glasses-1.png');
$image2 = imagefrompng('mouth-1.png');
Once this is done you can create a frame in a new image using:
imagecopymerge()
I'll let you sort the destination, sources and coordinates... call it a challenge ;)
From there all you have to do is output the composited image to a file using imagepng:
imagepng($compositedImage, $path_to_filesystem_destination);
Using the command directly will output the image to the browser, the second parameter saves the image to a file.

php Imagemagick jpg black background

I have a php script to create jpg thumbnail of pdf as follows;
<?php
$file ="test.pdf";
$im = new imagick(realpath($file).'[0]');
$im->setImageFormat("jpg");
$im->resizeImage(200,200,1,0);
// start buffering
ob_start();
$thumbnail = $im->getImageBlob();
$contents = ob_get_contents();
ob_end_clean();
echo "<img src='data:image/jpg;base64,".base64_encode($thumbnail)."' />";
?>
But the resulting jpg have black background instead of white.. How can I fix this??
None of the previously posted answers worked for me however the below did:
$image = new Imagick;
$image->setResolution(300, 300);
$image->readImage("{$originalPath}[0]");
$image->setImageFormat('jpg');
$image->scaleImage(500, 500, true);
$image->setImageAlphaChannel(Imagick::VIRTUALPIXELMETHOD_WHITE);
As I'm using the Laravel framework I then take the converted image and store it using Laravels filesystem.
Storage::put($storePath, $image->getImageBlob());
Update: So I recently changed OS and whereas this previously worked on my Ubuntu machine on my Mac certain images were still coming out black.
I had to change the script to the below:
$image = new Imagick;
$image->setResolution(300, 300);
$image->setBackgroundColor('white');
$image->readImage("{$originalPath}[0]");
$image->setImageFormat('jpg');
$image->scaleImage(500, 500, true);
$image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
$image->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE);
Seems important to set the background colour before reading in the image. I also flatten any possible layers and remove the alpha channel. I feel like I tried ALPHACHANNEL_REMOVE on my Ubuntu machine and it didn't work so hopefully between these answers readers can find something that works for them.
If your version of Imagick is not up to date, the setImageBackgroundColor may be wrong.
Swap the following line
$im->setImageBackgroundColor("red");
to this (Imagick version >= 2.1.0)
$im->setBackgroundColor(new ImagickPixel("red"));
or (Imagick version < 2.1.0)
$im->setBackgroundColor("red");
I solved it by;
$im = new imagick(realpath($file).'[0]');
$im->setCompression(Imagick::COMPRESSION_JPEG);
$im->setCompressionQuality(100);
$im->setImageFormat("jpeg");
$im->writeImage("imagename.jpg");
Simply adding this prevents the JPG to be created with a black background
-alpha off
change this code $im->setimageformat("jpg"); to this code
$im->setimageformat("png"); if you face a background colour issue.
Just use flattenImages() right after creating a new imagick():
$im = new Imagick('file.pdf[0]');
$im = $im->flattenImages();
Edit: The flattenImages method has been deprecated & removed. Use
$im = $im->mergeImageLayers( imagick::LAYERMETHOD_FLATTEN );
After endless attempts to append a pdf file with a jpeg image without getting black areas, I found the solution: the function transformImageColorspace
Used in this order works perfectly:
$im = new Imagick();
$im->readImage("file.pdf");
$im->transformImageColorspace(Imagick::COLORSPACE_SRGB);
$im->setImageFormat('jpeg');
$im->writeImage('image.jpg');
I would like to add to the excellent and helpful answers by saying that a slightly different approach is required if your PDF has multiple pages.
Something I was surprised to discover is that the Imagick class implements Iterable, which means you can run it through a foreach loop and operate on each page in turn (which it turns out is necessary because the layer, colour, and alpha channel changes appear to only take effect on the last page) which will be presented to you as a separate Imagick object:
$im = new Imagick('path/to/file.pdf');
foreach ($im as $c => $page)
{
// do what you need to do with each page and then...
$im->writeImage('path/to/image-'.$c.'.jpg');
}

Transparent to white in Imagick for PHP

I have a png image with a transparent background and I want to convert it to a jpg image with a white background.
The code is basically this:
$image = new Imagick('transparent.png');
$image->writeImage('opaque.jpg');
But that creates a black background jpg. I've been struggling with the worst documentation ever trying to find a way to convert the transparent to white to no avail.
Edit:
Well, I tried Marc B's idea and kind of got it to work.
$image = new Imagick('transparent.png');
$white = new Imagick();
$white->newImage($image->getImageWidth(), $image->getImageHeight(), "white");
$white->compositeimage($image, Imagick::COMPOSITE_OVER, 0, 0);
$white->writeImage('opaque.jpg');
$image->destroy();
$white->destroy();
The problem now is, it always causes the script to segfault.
flattenImages() actually works.
But keep in mind that it doesn't modify the given \Imagick() object but returns a new one:
$image = new \Imagick('transparent.png');
// Need to use the result of $image->flattenImages() here!
$image = $image->flattenImages();
$image->writeImage('opaque.jpg');
flattenImages() defaults to the background color white. If you want to use another background color you have to set it before loading the image:
$image = new \Imagick();
// Needs to be called before the image is loaded!
$image->setbackgroundcolor('green');
$image->readimage('transparent.png');
$image = $image->flattenImages();
$image->writeImage('opaque.jpg');
In general the Imagick API is very sensible when it comes to the order of function calls (just like convert and its parameters on the command line) so always check if your order is correct.
Good luck!
Edit April 2016:
$image->flattenImages() was deprecated and should be replaced by:
$image->mergeImageLayers(\Imagick::LAYERMETHOD_FLATTEN)
It's hard to find exact informations about this, but it seems that this applies to PHP >= 5.6.
Thanks to vee for the tip!
Try:
$image = new Imagick('transparent.png');
$image->setImageMatte(true);
$image->setImageMatteColor('white');
$image->setImageAlphaChannel(Imagick::ALPHACHANNEL_OPAQUE);
$image->writeImage('opaque.jpg');
I ran into the same problem when converting PDFs to PNGs, and I used flattenImages().
//get the first page of the PDF
$im = new imagick( $file.'[0]' );
//set the background to white
$im->setImageBackgroundColor('white');
//flatten the image
$im = $im->flattenImages();
//do the rest of the image operations
$im->setResolution( 181, 181 );
$im->setCompressionQuality(100);
$im->resizeImage ( 181, 181, imagick::FILTER_LANCZOS, 1, TRUE);
$im->setImageFormat('png');
$imageName = $title.'_thumb.png';
$image = new Imagick('transparent.pdf');
$image->setImageType (imagick::IMGTYPE_TRUECOLOR);
$image->writeImage('opaque.tif');
did for me!
(instead of the formerly imagick::IMGTYPE_TRUECOLORMATTE)
Try this one:
$white->newImage($image->getImageWidth(), $image->getImageHeight(), "transparent");
You can try it by changing Imagick constant as shown below
//$image will conatains image which needs background to be transparent
$white = new Imagick();
$white->newImage($image->getImageWidth(), $image->getImageHeight(), new ImagickPixel( "white" ));
$white->compositeimage($image, Imagick::COMPOSITE_DEFAULT, $x1OfTransparentImage, $y1OfTransparentImage,);
$white->flattenImages();
$white->writeImage('opaque.jpg');
$white->destroy();
Try the following, it works for me:
$im = new Imagick('trans.png');
$im->setimagebackgroundcolor('white');
$im = $im->flattenimages();
$im->writeimage('transToWhite.jpg');
Hope that helps!
Regarding the issue with segfault I ran into the same issue.
Apparently $image->writeImage('somename') destroys $image or the reference to it.
I was running into the same issue. The way I got around it was by removing the call to destroy on the object that I had finished writing. Seems sloppy but that solved the issue with the segfault
Segfault issue:
I had a similar problem (script kept giving me segfault, even when the image was properly processed and written), the solution I found came after checking bug reports, see:
https://bugs.php.net/bug.php?id=61122
Knowing that, try adding
$white->setResourceLimit(6, 1); // 6 means "limit threads to"
before the problematic line (in my case I had to put it before $im->resizeImage(...);)
I had a situation where I was trying to replace transparent background with white (but keep as png). Tried several different methods (including setImageAlphaChannel with setImageBackgroundColor). Combining OP's use of compositeImage I came up with this (hopefully helpful to someone else):
$pic = new Imagick($filelocation); //specify file name
$pic->setResourceLimit(6, 1);
if ($pic->getImageAlphaChannel()) {
$white = new Imagick();
$white->newImage($pic->getImageWidth(), $pic->getImageHeight(), "white");
$white->compositeImage($pic, Imagick::COMPOSITE_OVER, 0, 0);
$pic = clone $white;
$white->destroy();
$pic->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
}
//do more things with $pic

Imagick PHP Extension -- Montage help?

I've been having some trouble generating an image with the Imagick PHP extension. Everything works fine, except my following "montage" has a white background and therefore I cannot overlay it on top of something else. How can I generate a montage with a transparent background?
$Montage = $Icons->montageImage(new imagickdraw(), "3x2+0+0", "34x34+3+3", imagick::MONTAGEMODE_UNFRAME, "0x0+0+0");
$Canvas->compositeImage($Montage, $Montage->getImageCompose(), 5, 5);
Thanks!!
I know this is an old question, but I found another way to do this using Imagick's montageImage function. After you create your Imagick object you must declare the background as transparent like this:
$Icons->setBackgroundColor( new ImagickPixel('transparent') );
Once that is set, you can run the object through montageImage which will create a montageImage with a transparent background:
$Montage = $Icons->montageImage(new imagickdraw(), "3x2+0+0", "34x34+3+3", imagick::MONTAGEMODE_UNFRAME, "0x0+0+0");
Then you can add the new montage image to your composite image making sure to use the predefined Imagick composite constant COMPOSITE_ATOP or your desired constant(s) like this:
$Canvas->compositeImage($Montage, imagick::COMPOSITE_ATOP, 5, 5);
Just ran across this question and decided to post another solution in case someone else wants another way to do this without a manual loop.
I had the same problem and discovered that the MagickWand C API, which powers imagick), doesn't support the option for montage.
I ended up montaging it manually like this:
// Add them to an array of Imagick objects, instead of using addImage().
$images = new Array();
// Make a transparent canvas.
$target = new Imagick();
$target->newImage($width, $height * count(images), 'none');
$i = 0;
foreach ($images as $image) {
$target->compositeImage($image, imagick::COMPOSITE_COPY, 0, $height * $i++);
}

Creating two pdf pages with Imagick

Currently i can create PDF files from images in Imagick with this function
$im->setImageFormat("pdf");
$im->writeImage("file.pdf");
And it's possible to fetch multiple pages with imagick like this
$im = new imagick("file.pdf[0]");
$im2 = new imagick("file.pdf[1]");
But is it possible to save two image objects to two pages?
(example of what i am thinking, its not possible like this)
$im->setImageFormat("pdf");
$im->writeImage("file.pdf[0]");
$im2->setImageFormat("pdf");
$im2->writeImage("file.pdf[1]");
I know this is long past due, but this result came up when I was trying to do the same thing. Here is how you create a multi-page PDF file in PHP and Imagick.
$images = array(
'page_1.png',
'page_2.png'
);
$pdf = new Imagick($images);
$pdf->setImageFormat('pdf');
if (!$pdf->writeImages('combined.pdf', true)) {
die('Could not write!');
}
Accepted answer wasn't working for me, as a result, it always generated one page pdf (last image from constructor), to make this work I had to get file descriptor first, like this:
$images = array(
'img1.png', 'img2.png'
);
$fp = fopen('combined.pdf', 'w');
$pdf = new Imagick($images);
$pdf->resetiterator();
$pdf->setimageformat('pdf');
$pdf->writeimagesfile($fp);
fclose($fp);
Is this working?
$im->setImageFormat("pdf");
$im->writeImage("file1.pdf");
$im2->setImageFormat("pdf");
$im2->writeImage("file2.pdf");
exec("convert file*.pdf all.pdf");
CAM::PDF is a pure-Perl solution for low-level PDF manipulation like this. You can either use the appendpdf.pl command-line tool, or do it programmatically like this:
use CAM::PDF;
my $doc1 = CAM::PDF->new('file1.pdf');
my $doc2 = CAM::PDF->new('file2.pdf');
$doc1->appendPDF($doc2);
$doc1->cleanoutput('out.pdf');
If you can figure out how to make ImageMagick write to a string instead of to a file (I'm not an ImageMagick expert...) then you save some performance overhead by keeping it all in Perl.
(I'm the author of CAM::PDF. It's free software: GPL+Artistic dual-licensed).
I do not know php or this Imagick library, but if calling an external program is acceptable I can recommend the program pdfjoin to merge pdf files.
It does have an dependency to pdflatex, so if this is something you intend to run on a server you might have to install extra latex stuff, but the end result from pdfjoin is very good, so I think it will be worth it.

Categories