How to make specified area of an image transparent with Imagick? - php

I want to make a part of an image transparent, I tried the code below, even tried many constants as COMPOSITE_DSTOUT, but all didn't work, does anyone know how to?
$fooImage->newImage(256, 256, new ImagickPixel('transparent'));
$Image->compositeImage($fooImage, Imagick::COMPOSITE_DSTOUT, $offsetX, offsetY);
I tested the code below, just got yellow with black, not transparent:
$width = 256;
$height = 256;
$image = new Imagick();
$image->newImage($width, $height, new ImagickPixel('yellow'));
$x = 50;
$y = 100;
$fooWidth = 100;
$fooHeight = 60;
//Create a new transparent image of the same size
$mask = new Imagick();
$mask->newImage($width, $height, new ImagickPixel('none'));
$mask->setImageFormat('png');
//Draw onto the new image the areas you want to be transparent in the original
$draw = new ImagickDraw();
$draw->setFillColor('black');
$draw->rectangle($x, $y, $x + $fooWidth, $y + $fooHeight);
$mask->drawImage($draw);
//Composite the images
$image->compositeImage($mask, Imagick::COMPOSITE_DSTOUT, 0, 0,
Imagick::CHANNEL_ALPHA);
$image->setImageFormat('png');
$image->writeImage($path);
Got black inside yellow, not transparent in yellow

You need to make a black and white mask image the size of your input (white where you want it to be opaque and black where you want it to be transparent). Then use the equivalent of -compose copyopacity -composite to put the mask into the alpha channel of the image. Sorry, I do not code Imagick.
Here is an example using ImageMagick command line syntax:
Input:
convert logo.jpg \( -size 640x480 xc:white -size 200x200 xc:black -geometry +200+100 -compose over -composite \) +geometry -alpha off -compose copy_opacity -composite result.png
You can see it is transparent by compositing it over another image (in this case a checkerboard).
convert ( -size 640x480 pattern:checkerboard ) result.png -compose over -composite result2.jpg

Do you try \Imagick::COMPOSITE_COPYOPACITY ?
Because that's probably the right one.

Related

PHP Imagick: problem converting ImageMagick command-line code

I'm using ImageMagick 7.0.8-66 Q16 x64 on Windows 8.1
My PHP is 7.4.1 on XAMPP.
I've been running the following command successfully with exec() in PHP:
convert _temp_.jpg
( +clone -background black -shadow 88x3+2+2 )
+swap -background none -layers merge
+repage -background #eeeeee -layers flatten
+repage -shave 3x3
( -size 100x100 xc:#eeeeee )
+swap -gravity northwest -geometry +5+5 -compose over -composite output.jpg
It takes an image, resizes it to fit in a 100x100 thumbnail, and adds a drop shadow to the image over a neutral #eeeeee background canvas. It works.
I want to rewrite it to use the Imagick PHP extension, but I'm having trouble translating it. Here's how I've translated it (with annotations), which is not working:
// convert _temp_.jpg
$im = new imagick();
$im->readImage('_temp_.jpg');
// ( +clone -background black -shadow 88x3+2+2 )
$im_clone = clone $im;
$im_clone->setImageBackgroundColor('black');
$im_clone->shadowImage(88, 3, 2, 2);
// +swap -background none -layers merge
$im->setImageBackgroundColor('none');
$im->addImage($im_clone);
$im->mergeImageLayers(imagick::LAYERMETHOD_MERGE);
// +repage -background #eeeeee -layers flatten
$im->cropImage(88, 88, +5, +5);
$im->setImagePage(88, 88, 0, 0);
$im->setImageBackgroundColor('#eeeeee');
$im->mergeImageLayers(imagick::LAYERMETHOD_FLATTEN);
// +repage -shave 3x3
$im->cropImage(88, 88, +5, +5);
$im->setImagePage(88, 88, 0, 0);
$im->shaveImage(3, 3);
// ( -size 100x100 xc:#eeeeee )
$im_pseudo = new Imagick();
$im_pseudo->newPseudoImage(100, 100, 'xc:#eeeeee');
// +swap -gravity northwest -geometry +5+5 -compose over -composite output.jpg
$im->setImageGravity(imagick::GRAVITY_NORTHWEST);
$im->compositeImage($im_pseudo, Imagick::COMPOSITE_OVER, 5, 5);
$im->writeImage('output.jpg');
What am I missing?
Source image:
Resulting image:
As I say if you go in steps you can see what is happening. This is from the php Imagick manual and creates the Shadow:
/* Read the image into the object */
$im = new Imagick( 'DOqeZ.jpg' );
$im->setImageFormat("png");
/* Make the image a little smaller, maintain aspect ratio */
$im->thumbnailImage( 200, null );
/* Clone the current object */
$shadow = $im->clone();
/* Set image background color to black
(this is the color of the shadow) */
$shadow->setImageBackgroundColor( new ImagickPixel( 'black' ) );
/* Create the shadow */
$shadow->shadowImage( 80, 3, 5, 5 );
/* Imagick::shadowImage only creates the shadow.
That is why the original image is composited over it */
$shadow->compositeImage( $im, Imagick::COMPOSITE_OVER, 0, 0 );
/* Display the image */
$shadow->writeImage('shadow.png');
UPDATE:
I thought I would let you see if you could do the rest
The creating the background and compositing it should work but extent should be better. I have other things to be getting on with but some updated code below for you to play with:
/* Read the image into the object */
$im = new Imagick( 'DOqeZ.jpg' );
$im->setImageFormat("png");
/* Make the image a little smaller, maintain aspect ratio */
$im->thumbnailImage( 80, null );
/* Clone the current object */
$shadow = $im->clone();
/* Set image background color to black
(this is the color of the shadow) */
$shadow->setImageBackgroundColor( new ImagickPixel( 'black' ) );
/* Create the shadow */
$shadow->shadowImage( 80, 3, 5, 5 );
/* Imagick::shadowImage only creates the shadow.
That is why the original image is composited over it */
$shadow->compositeImage( $im, Imagick::COMPOSITE_OVER, 0, 0 );
/* Create the background image 100x100 with a background colour */
/* Gravity seems to have no effect */
/* $shadow->setImageGravity(imagick::GRAVITY_CENTER);*/
$shadow->setImageBackgroundColor( '#eeeeee' );
$height = $shadow->getImageHeight();
$width = $shadow->getImageWidth();
$shadow->extentImage( 100, 100, (((100 - $width)/2)*-1 ), (((100 - $height)/2)*-1 ));
$shadow->writeImage('shadow.jpg');
**** Code updated to centre the image and use a hex value for the colour ****

padding images using php imagick

I need to create square images with no image loss. I found a tool that does the job as a bash script using ImageMagick but can never seem to be able to do it with php Imagick.
The script I found is called squareup from http://www.fmwconcepts.com/imagemagick/squareup/index.php
My code looks like this currently:
$image = new Imagick($srcimage);
$image->setCompressionQuality(100);
if ($image->getImageHeight() <= $image->getImageWidth())
$image->resizeImage($maxsize, 0, Imagick::FILTER_MITCHELL, 1);
else
$image->resizeImage(0, $maxsize, Imagick::FILTER_MITCHELL, 1);
$h=$image->getImageHeight();
$w=$image->getimagewidth();
$hlarge=0;
$wlarge=0;
if ($w>$h) {
$diff=intval(($w-$h)/2);
$wlarge=1;
$h=$w;
} else {
$diff=intval(($h-$w)/2);
$w=$h;
$hlarge=1;
}
$newimage = new Imagick();
if ($image->getImageColorspace() == Imagick::COLORSPACE_CMYK) {
$fg="cmyk(0,0,0,0)";
$fg_pixel=new ImagickPixel($fg);
$newimage->newImage($w, $h, $fg_pixel);
$newimage->setImageColorspace(Imagick::COLORSPACE_CMYK);
} else {
$newimage->newImage($w, $h, new ImagickPixel('#ffffff'));
}
$newimage->compositeImage($image,\Imagick::COMPOSITE_OVER,0,0);
$newimage->setImageCompression(Imagick::COMPRESSION_JPEG);
$newimage->setImageCompressionQuality(100);
$newimage->stripImage();
$newimage->writeImage($contactimage);
$newimage->destroy();
$image->destroy();
The simplest way to do pad to square or crop to square in ImageMagick 6 is as follows:
Input:
size=`convert hatching_orig.jpg -format "%[fx:max(w,h)]" info:`
convert hatching_orig.jpg -background red -gravity center -extent ${size}x${size} hatching_pad.jpg
size=`convert hatching_orig.jpg -format "%[fx:min(w,h)]" info:`
convert hatching_orig.jpg -background red -gravity center -extent ${size}x${size} hatching_crop.jpg
Same command, but different size variable.
In IM 7, you can do each in one command line.
These commands should be easy to convert to Imagick, I would expect. But should be done in sRGB colorspace. See http://us3.php.net/manual/en/imagick.extentimage.php

Removing red eye in PHP using Imagick

I'm trying to adapt the script available here [http://www.fmwconcepts.com/imagemagick/redeye/index.php][1] in PHP using the API version of Imagick.
Actually, the selection is done in jQuery then passed to the following script to draw the selection.
Here's my code so far:
<?php
extract($_POST);
// Load the original image
$image = new Imagick($path);
// Duplicate and desaturate the original image
$image2 = clone $image;
$image2->modulateImage(15, 0, 100);
// Create the mask on which the selection will be drawn
$image3 = clone $image;
$image3->colorfloodfillimage(new ImagickPixel('white'), 18, new ImagickPixel('white'), 0, 1);
foreach ($redeye as $selection){
try{
$draw = new ImagickDraw();
$draw->setstrokewidth(0);
$draw->setstrokecolor(new ImagickPixel('black'));
$draw->setFillColor(new ImagickPixel( 'black' ));
$draw->setfillalpha(1);
$draw->ellipse( $selection['ox'], $selection['oy'], $selection['rx'], $selection['ry'], 0, 360 );
$image3->drawImage($draw);
} catch (ImagickException $ie){
echo $ie->getMessage();
}
}
?>
I know very little about image processing and don't know how to merge the 3 layers.
I don't really understand the code of the convert function when merging the layer.
Any help would be greatly appreciated!
EDIT:
convert $tmpA1 $tmpA2 $tmpA3 -compose over -composite $tmpA2
As I understand this should be written like the following using the API:
$image2->compositeImage($image3,Imagick::COMPOSITE_OVER, 0, 0);
$image2->compositeImage($image2,Imagick::COMPOSITE_OVER, 0, 0);
$image2->compositeImage($image,Imagick::COMPOSITE_OVER, 0, 0);
Then
convert $tmpA2 \( $tmpA1 -modulate 100,0,100 \) $tmpA4 -compose over -composite $outfile
Should be written like that:
$image->modulateImage(100, 0, 100);
$image->compositeImage($image,Imagick::COMPOSITE_OVER,0, 0);
$image->compositeImage($image2,Imagick::COMPOSITE_OVER,0, 0);
But I don't understand this part:
convert $tmpA3 ( +clone -morphology close disk:$rad $dilation ) -compose difference -composite -auto-level -negate -threshold 0 -negate $tmpA4

Imagick Equivalent Of This Imagemagick Command?

I'm trying to create a vignette effect, and I can get desired result through command line. But when I try it with Imagick, I'm not getting the desired result
convert i.jpg ( -size 150x150 radial-gradient:black-white -gravity center -crop 100x100+0+0 +repage ) -compose multiply -flatten o.jpg
I tried the following Imagick commands
$gra = new Imagick();
$gra->newPseudoImage(150, 150, "radial-gradient:black-white");
$gra->cropThumbnailImage(100, 100);
$gra->setImagePage(100, 100, 0, 0);
$img = new Imagick("i.jpg");
$img->compositeImage($gra, Imagick::COMPOSITE_MULTIPLY, 0, 0);
$img->flattenImages();
$img->writeImage("o.jpg");
Thanks for any help!

PHP: PNG tinitng (1 color)

Before I start, I just want to note that I am a PHP noob. What I want to do is tint a PNG image to one color. So all transparent pixels will remain transparent, and all non-transparent pixels will be that color. I have searched many sites for this answer but for some reason I can't find what I want.
Here is my first attempt based on different examples I found:
<?php
header('Content-Type: image/png');
$color = $_GET['color'];
$im = imagecreatefrompng($_GET['img']);
$width = imagesx($im);
$height = imagesy($im);
$imn = imagecreatetruecolor($width, $height);
imagealphablending($imn,false);
$col=imagecolorallocatealpha($imn,255,255,255,127);
imagesavealpha($imn,true);
imagefilledrectangle($imn,0,0,$width,$height,$col);
imagealphablending($imn,true);
imagecopy($imn, $im, 0, 0, 0, 0, $width, $height);
imagefilter($imn, IMG_FILTER_GRAYSCALE);
if ($color[0] == '#')
$color = substr($color, 1);
if (strlen($color) == 6)
$r = $color[0].$color[1];
$g = $color[2].$color[3];
$b = $color[4].$color[5];
$r = hexdec($r);
$g = hexdec($g);
$b = hexdec($b);
imagefilter($imn, IMG_FILTER_COLORIZE, $r, $g, $b);
imagepng($imn);
imagedestroy($imn);
?>
Essentially a perfect example of what I want can be seen here. The only change will be that instead of black, I want it to be converted to the color the user specifies.
Convert non-transparent pixels to black
Thank You
===============================
10/17/2012 Update
So based on xception's answer, here is the code that I used to execute his script:
<?php
$source = "test.png";
$temp = "temp.png";
$color = "red";
$final = "FINAL.png";
exec("convert $source -alpha extract -threshold 0 -negate -transparent white $temp");
exec("convert $temp -fill $color -opaque black $final");
?>
It worked, however there is a small problem. As illustrated in the screenshots below, there are jagged edges. Any ideas on how to smooth the image so it looks as nice as it did in the BEFORE screenshot?
BEFORE:
AFTER:
Example in 2 steps based on the link you pointed to:
convert <source> -alpha extract -threshold 0 -negate -transparent white <tmp>
convert <tmp> -fill red -opaque black <destination>
replace <source>, <tmp>, <destination> with appropriate file names, replace red with the color you want.
EDIT:
shorter version found by question author:
exec("convert $source -threshold 100% +level-colors '#00FF00', $final");

Categories