Masking With A Grayscale Image With PHP And ImageMagick - php

I am trying to create a grayscale mask in Imagemagick (v7.0.11) that behaves like a layer mask in Photoshop where white areas are completely opaque and black areas are fully masked.
function grayscaleMaskTest () {
//Create a black and white mask
$mask = new Imagick();
$mask->newImage(300, 300, "#ffffff");
$mask->setImageType(IMAGICK::IMGTYPE_GRAYSCALE);
$mask->setImageFormat('gif');
//draw black circle
$draw = new ImagickDraw();
$draw->setStrokeWidth(1);
$draw->setStrokeOpacity(1);
$draw->setStrokeColor(new ImagickPixel("#000000"));
$draw->setFillColor(new ImagickPixel("#000000"));
$draw->circle(300/2, 300/2, 300/2, 300/2 + 100);
$mask->drawImage($draw);
//$mask->writeImage('C:\Users\Mike\Documents\images\mask.png'); //export mask
//Create final image
$final = new Imagick();
$final->newImage(300, 300, "#FF0000");
//Not sure if I had this right but tried writing the mask data to the alpha channel
//$final->compositeImage($mask, IMAGICK::COMPOSITE_COPYOPACITY, 0, 0, IMAGICK::CHANNEL_ALPHA);
$final->compositeImage($mask, IMAGICK::COMPOSITE_COPYOPACITY, 0, 0);
$final->writeImage('C:\Users\Mike\Documents\images\final.png');
}
The mask looks like this :
The desired result from this code if it worked would be this (minus the fake transparency) :

With help from #fmw42 this ended up working. Thanks!
//Create a black and white mask
$mask = new Imagick();
$mask->newImage(300, 300, "#ffffff");
//draw black circle
$draw = new ImagickDraw();
$draw->setStrokeWidth(1);
$draw->setStrokeOpacity(1);
$draw->setStrokeColor(new ImagickPixel("#0"));
$draw->setFillColor(new ImagickPixel("#0"));
$draw->circle(300/2, 300/2, 300/2, 300/2 + 100);
$mask->drawImage($draw);
$mask->setImageMatte(false); //<-------This got it going!
//Create final image
$final = new Imagick();
$final->newImage(300, 300, "#FF0000");
$final->compositeImage($mask, imagick::COMPOSITE_COPYOPACITY, 0, 0);`

Related

PHP imagick COMPOSITE_DSTIN result has black background

I try to set a text gradient from this solution here https://www.sitepoint.com/community/t/gd-text-gradient/82127/9
But the background color of the final image is black, I try $im->flattenImages and $img->setBackgroundColor but it's not working.
$im = new Imagick();
$draw = new ImagickDraw();
$draw->setFontSize(90);
$draw->setFillColor(new ImagickPixel("black"));
$draw->setTextEncoding('UTF-8');
$draw->setGravity(Imagick::GRAVITY_CENTER);
$metric = $im->queryFontMetrics($draw, $text);
$width = $metric['textWidth'];
$height = $metric['textHeight'];
/* Create and save the gradiant */
$Imagick = new Imagick();
$Imagick->newPseudoImage($height, $width, "gradient:#FB7F4C-#FF409C");
/*** rotate the image ***/
$Imagick->rotateImage(new ImagickPixel(), 270);
$Imagick->setImageFormat('png');
$Imagick->writeImage("gradiant.png");
/* Create and save the canvas */
$im->newPseudoImage($width, $height, "null:");
$im->setImageFormat('png');
$im->writeImage("canvas.png");
/* Add the text to the canvas ( Make the mask )*/
$im = new Imagick("canvas.png");
// Write the text on the image
$im->annotateImage($draw, 0, 0, 0, $text);
$im->setImageBackgroundColor("transparent"); // <= Here
/* Final image */
$canvas = new Imagick("gradiant.png");
$canvas->compositeImage($im, imagick::COMPOSITE_DSTIN, 0, 0, Imagick::CHANNEL_ALPHA);
$canvas->setImageFormat('png');
$canvas->writeImage(__DIR__ . "/../../final.png");
header('Content-Type: image/' . $im->getImageFormat());
echo $canvas;
unlink("canvas.png");
unlink("gradiant.png");
I found after the COMPOSITE_DSTIN the background color goes black, I try many way but its not working
How to remove black background?
I'm solved it by adding alphachannel
I try $canvas->setImageAlphaChannel(Imagick::ALPHACHANNEL_RESET); and after that the background stay transparent
UPDATE
After I updated my imagick library it's stop working and search for similar issue and found this Imagemagick compose image inverted
And here the code that works well
$canvas->transformImageColorspace(Imagick::COLORSPACE_SRGB);

Imagick not working and showing null image

I am using shared hosting and extensions is installed too, the following code not working and just showing blank image in output I have tried many of code/function of Imagick all of codes showing the following image.
Please help me out.
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Create objects
$image = new Imagick('image.png');
$watermark = new Imagick();
$mask = new Imagick();
$draw = new ImagickDraw();
// Define dimensions
$width = $image->getImageWidth();
$height = $image->getImageHeight();
// Create some palettes
$watermark->newImage($width, $height, new ImagickPixel('grey30'));
$mask->newImage($width, $height, new ImagickPixel('black'));
// Watermark text
$text = 'Copyright';
// Set font properties
$draw->setFont('arial.ttf');
$draw->setFontSize(20);
$draw->setFillColor('grey70');
// Position text at the bottom right of the image
$draw->setGravity(Imagick::GRAVITY_SOUTHEAST);
// Draw text on the watermark palette
$watermark->annotateImage($draw, 10, 12, 0, $text);
// Draw text on the mask palette
$draw->setFillColor('white');
$mask->annotateImage($draw, 11, 13, 0, $text);
$mask->annotateImage($draw, 10, 12, 0, $text);
$draw->setFillColor('black');
$mask->annotateImage($draw, 9, 11, 0, $text);
// This is needed for the mask to work
$mask->setImageMatte(false);
// Apply mask to watermark
$watermark->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
// Overlay watermark on image
$image->compositeImage($watermark, Imagick::COMPOSITE_DISSOLVE, 0, 0);
// Set output image format
$image->setImageFormat('png');
// Output the new image
header('Content-type: image/png');
echo $image;

how do i use imagecropauto() with IMG_CROP_TRANSPARENT?

When I try to crop transparant area of an image, its get to keep it original size, and the transparant areas are turned black.
If i run this code:
<?php
// Create a 300x300px transparant image with a 100px wide red circle in the middle
$i = imagecreatetruecolor(300, 300);
imagealphablending($i, FALSE);
imagesavealpha($i, TRUE);
$transparant = imagecolorallocatealpha($i, 0xDD, 0xDD, 0xDD, 0x7F);
imagefill($i, 0, 0, $transparant);
$red = imagecolorallocate($i, 0xFF, 0x0, 0x0);
imagefilledellipse($i, 150, 150, 100, 100, $red);
imagepng($i, "red_300.png");
// Crop away transparant parts and save
$i2 = imagecropauto($i, IMG_CROP_TRANSPARENT);
imagepng($i2, "red_crop_trans.png");
imagedestroy($i2);
// Crop away bg-color parts and save
$i2 = imagecropauto($i, IMG_CROP_SIDES);
imagepng($i2, "red_crop_sides.png");
imagedestroy($i2);
// clean up org image
imagedestroy($i);
I end up with a red_crop_trans.png image that is a 300x300px black image with an 100x100px red circle in it.
And a red_crop_sides.png that is a 100x100px black image with a 100x100px red circle in it.
Why is red_crop_trans.png not croped to 100x100px? and why is the background of both images black? And how do I crop them while keeping the transparace?
It took me a while to figure out what exactly was going on. It turned out $i2 = imagecropauto($i, IMG_CROP_TRANSPARENT); was returning false instead of true. According to the docs:
imagecropauto() returns FALSE when there is either nothing to crop or
the whole image would be cropped.
So instead of IMG_CROP_TRANSPARENT I used IMG_CROP_DEFAULT:
Attempts to use IMG_CROP_TRANSPARENT and if it fails it falls back to
IMG_CROP_SIDES.
This gave me the expected result. Now I didn't get any black backgrounds myself. But it's a known issue so the solution was quite easily found:
imagecolortransparent($i, $transparant); // Set background transparent
And that brings me to the final completed code:
<?php
// Create a 300x300px transparant image with a 100px wide red circle in the middle
$i = imagecreatetruecolor(300, 300);
imagealphablending($i, FALSE);
imagesavealpha($i, TRUE);
$transparant = imagecolorallocatealpha($i, 0xDD, 0xDD, 0xDD, 0x7F);
imagecolortransparent($i, $transparant); // Set background transparent
imagefill($i, 0, 0, $transparant);
$red = imagecolorallocate($i, 0xFF, 0x0, 0x0);
imagefilledellipse($i, 150, 150, 100, 100, $red);
imagepng($i, "red_300.png");
// Crop away transparant parts and save
$i2 = imagecropauto($i, IMG_CROP_DEFAULT); //Attempts to use IMG_CROP_TRANSPARENT and if it fails it falls back to IMG_CROP_SIDES.
imagepng($i2, "red_crop_trans.png");
imagedestroy($i2);
// Crop away bg-color parts and save
$i2 = imagecropauto($i, IMG_CROP_SIDES);
imagepng($i2, "red_crop_sides.png");
imagedestroy($i2);
// clean up org image
imagedestroy($i);
?>

Cannot draw proper rectangular border with ImageMagick PHP

I am using PHP ImageMagic and I am trying to put a border around a Rectangle. I am following this, and this to create the border. It seems to be working fine for them, but for me, if I make the stroke width more than 2, it starts to break.
Here is the code, that I am using
$white = new ImagickPixel("rgb(255, 255, 255)");
$borderWidth = 10;
$draw = new ImagickDraw();
$strokeColor = new ImagickPixel("rgb(255, 255, 255)");
$fillColor = new ImagickPixel("none");
$draw->setStrokeColor($strokeColor);
$draw->setFillColor($fillColor);
//$draw->setStrokeOpacity(1);
$draw->setStrokeWidth(2);
$draw->rectangle(5, 5, 295, 295);
$imagick = new Imagick();
$imagick->newImage(300, 300, "rgb(225, 225, 225)");
$imagick->setImageFormat("png");
$imagick->drawImage($draw);
header("Content-type:image/png");
echo $imagick;die;
This is the result, with $draw->setStrokeWidth(2)
And this is the result, with $draw->setStrokeWidth(5) which obviously seems broken.
What might be the issue?

Imagick - soft polygon edges with image mask

How can I draw image with smooth edges using setImageClipMask?
My code produces like this:
which has sharp jagged edges where the edge of the clip mask is.
The code I am using:
// Draw clip mask
$clipMask = new \Imagick();
$clipMask->newPseudoImage($width, $height, "canvas:white");
$draw = new \ImagickDraw();
$draw->setFillColor(new ImagickPixel('black'));
$draw->polygon($myCoordinates);
$clipMask->drawImage($draw);
// Set mask
$img_main->setImageClipMask($clipMask);
// Draw image
$img_main->compositeImage($myImage, Imagick::COMPOSITE_DEFAULT, $x, $y);
tl:dr don't use masks use a gradient instead.
Masks are a binary choice; the pixel either gets through or it doesn't and are designed to have sharp edges.
Gradients (which don't have to be linear) allow for effects to be applied smoothly. The code below generates a gradient and then uses it to blend between the two images smoothly.
Gradient generated:
Output image:
<?php
$background = new \Imagick(realpath('./Skyline_400.jpg'));
$overlay = new \Imagick(realpath('./background.jpg'));
$overlay->scaleimage(
$background->getImageWidth(),
$background->getImageHeight()
);
$gradient = createGradient($background);
//If you need to see the gradient for debugging.
$gradient->setImageFormat("png");
$gradient->writeImage("./gradient.png");
$gradient2 = clone $gradient;
//The overlay needs to have the gradient reversed
$gradient2->negateimage(false);
$gradient2->setImageAlphaChannel(\Imagick::ALPHACHANNEL_DEACTIVATE);
$background->compositeImage($gradient2, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);
$gradient->setImageAlphaChannel(\Imagick::ALPHACHANNEL_DEACTIVATE);
$overlay->compositeimage($gradient, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);
//Create a new canvas to render everything in to.
$canvas = new \Imagick();
$canvas->newImage($gradient->getImageWidth(), $gradient->getImageHeight(), new \ImagickPixel('black'));
//Blend background into canvas
$canvas->compositeimage($background, \Imagick::COMPOSITE_BLEND, 0, 0);
//Blend overlay into canvas
$canvas->compositeimage($overlay, \Imagick::COMPOSITE_BLEND, 0, 0);
//Output the final image
$canvas->setImageFormat('png');
$canvas->writeImage("./output_test.png");
// Create a gradient/mask to allow images to be blended smoothly.
function createGradient(\Imagick $background)
{
$myCoordinates = [
['x' => 20, 'y' => 20,],
['x' => 360, 'y' => 20,],
['x' => 350, 'y' => 350,],
['x' => 25, 'y' => 350,],
];
$backgroundMask = new \Imagick();
$backgroundMask->newPseudoImage(
$background->getImageWidth(),
$background->getImageHeight(),
'canvas:white'
);
$draw = new \ImagickDraw();
$draw->setFillColor(new ImagickPixel('black'));
$draw->polygon($myCoordinates);
$backgroundMask->setImageFormat('png');
$backgroundMask->drawImage($draw);
// Blur the edges to make the transition between black and white
// be smooth
$backgroundMask->blurImage(2, 0.5);
return $backgroundMask;
}

Categories