I am moving to a new hosting company that will not allow me to exec a convert command for ImageMagick. So I now have to attempt to do it through straight PHP. I have spent quite a bit of time trying to figure it out and every where that I look, people recommend using the convert command like I am. I would appreciate any help or guidance in writing the following commands in straight PHP.
# Applies overlay $filter_image to the original $image
convert $image ( -clone 0 -alpha off $filter_image -compose SoftLight -composite ) -compose SrcIn -composite $output_image
and
# Apply a blur to an image
convert $image -blur 0x$blur_radius $output_image
UPDATE:
I have figured out the syntax and posted it as an answer.
Best of luck Joe; I would recomend changing to a host that will let you use exec.
I have some examples of the imagick functions on my site that you may be able to cobble something together with: http://www.rubblewebs.co.uk/imagick/functions/function.php
I have just noticed I posted the Imagemagick code not the Imagick !
This is as you now know the blur code for Imagick:
bool blurImage ( float $radius , float $sigma [, int $channel ] )
<?php
$im = new Imagick($input);
$im->blurImage( 0, 3 );
$im->writeImage('blurImage.jpg');
$im->destroy();
?>
Might be worth adding an Imagick tag to your post as that is what you want to use?
I finally figured it out on my own. Here is the solution in case anyone else runs into this.
Blur an image...
$imagick = new Imagick($image);
$imagick->blurImage(0,$blur_radius);
$imagick->writeImage($output_image);
Add an overlay to an image...
$imagick = new Imagick($image);
$overlay = new Imagick($filter_image);
$imagick->compositeImage($overlay, imagick::COMPOSITE_SOFTLIGHT, 0, 0);
$imagick->writeImage($output_image);
You can easily combine the two methods as well and blur the image and then add a composite overlay to it.
$imagick = new Imagick($image);
$imagick->blurImage(0,$blur_radius);
$overlay = new Imagick($filter_image);
$imagick->compositeImage($overlay, imagick::COMPOSITE_SOFTLIGHT, 0, 0);
$imagick->writeImage($output_image);
Related
I have a simple HTML form where the user can upload their image and I need to convert this uploaded image into a specific color with the help of PHP
For example, user upload some image I need to convert the entire image into a specific color (this color is dynamic)
Is there any PHPGD library that can help me to achieve this?
EDIT
For example, user is uploading this kind of Image,
then I need to convert into below type of Image,
I'm still unsure exactly what you are trying to do, but think one of the following may be close. Maybe you can try them in the Terminal until we can finally work out the correct operations then we can hopefully translate them into PHP. This is ImageMagick v7 syntax:
magick image.png -channel RGB -colorspace gray +level-colors red, result.png
Or this:
magick image.png -fill red +opaque white result2.png
You can specify the colour in hex like this for magenta:
magick image.png -channel RGB -colorspace gray -auto-level +level-colors '#ff00ff', result.png
If using v6 ImageMagick, replace magick with convert.
My PHP is pretty rusty, but something like this:
#!/usr/local/bin/php -f
<?php
// Emulating something akin to this ImageMagick command:
// magick image.png -fill red +opaque white result.png
// Open input image and get dimensions
$im = new \Imagick('image.png');
// Temporarily deactivate alpha channel
$im->setImageAlphaChannel(Imagick::ALPHACHANNEL_DEACTIVATE);
// Apply colour to non-white areas
$im->opaquePaintImage('white','red', 0, true);
// Reactivate alpha channel
$im->setImageAlphaChannel(Imagick::ALPHACHANNEL_ACTIVATE);
// Save
$im->writeImage('result.png');
?>
I have tried to produce something similar. Please test the following code if that satisfies your requirement.
<?PHP
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
/*
#desc replaces target color of an image with the provided fill color
*/
function color_replace($img,$target,$fill,$fuzz){
$img->opaquePaintImage($target, $fill, $fuzz, false, Imagick::CHANNEL_DEFAULT);
return $img;
}
$img = new Imagick('source.png');
$img->setImageAlphaChannel(Imagick::ALPHACHANNEL_DEACTIVATE);
$fuzz = 0.44 * $img->getQuantumRange()['quantumRangeLong'];
$img=color_replace($img,'rgba(50,173,186,255)','red',$fuzz); // replace paste like color with red
$img=color_replace($img,'rgb(230,218,30)','#9c1f24',$fuzz); // replace golden like color with dark red
$img->setImageAlphaChannel(Imagick::ALPHACHANNEL_ACTIVATE);
$img->setImageFormat ("jpeg");
file_put_contents ("test_1.jpg", $img);
?>
Produced output with my program:
With this program, you will be able to change each individual color by calling the color_replace method every time you want to change color. The following image is an example of that.
You need some library like Imagick. To replace some color, you need clutImage
$image = new Imagick('test.jpg');
$clut = new Imagick();
$clut->newImage(1, 1, new ImagickPixel('rgb(255, 0, 0)'));
$image->clutImage($clut);
$image->writeImage('test_out.jpg');
I have another solution for you here, again of course with Imagick:
$im = new Imagick('path/to/start-image')
$im->transformimagecolorspace(Imagick::IMGTYPE_GRAYSCALE);
$im->writeImage('path/to/gray.jpg'));
$im->clear();
$im = new Imagick('path/to/gray.jpg'));
$im->blackThresholdImage( "#cdcdcd" );
$im->writeImage('path/to/black-white.jpg'));
$im->clear();
$im = new Imagick('path/to/black-white.jpg'));
$im->colorizeImage('rgba(209, 15, 16, 1)', 1, true);
$im->writeImage('path/to/red.jpg'));
$im->clear();
Then just delete the intermediate files gray.jpg and black-white.jpg and you will achieve the result you are looking for as here:
I'm assembling a bunch of .tif using Imagick. Everything is going good, except that the color depth of the output image is always reduced (16 on the input, 1 on the output). I'm using setImageDepth() during the process, but it looks like it has no effect at all. Here's a snippet:
$imagick = new Imagick();
foreach ($_pile_of_tiles as $_index_to_append) {
$_tmp_buffer = new Imagick();
$_tmp_buffer->readImage($_index_to_append . ".tif");
$_imagick->addImage($_tmp_buffer);
}
$_imagick->resetIterator();
$_appended_images = $_imagick->appendImages(true);
$_appended_images->setImageFormat("tiff");
$_appended_images->setImageDepth(16);
file_put_contents("output.tif", $_appended_images);
That gives me a 1-bit image. I tried doing this using the command-line, and it works fine (-depth 16).
Does someone encountered a similar issue?
After looking at the code for the underlying ImageMagick library, apparently this works:
$imagick = new Imagick();
$imagick->newPseudoImage(200, 200, 'xc:white');
$imagick->setType(\Imagick::IMGTYPE_TRUECOLOR);
$imagick->setImageFormat('tiff');
$imagick->setImageDepth(16);
$imagick->writeImage("./output.tif");
system("identify output.tif");
Output is:
output.tif TIFF 200x200 200x200+0+0 16-bit sRGB 241KB 0.000u 0:00.000
No. That's not documented anywhere in the ImageMagick docs. Woo.
I have cobbled together the following code, which very nearly works:
<?php
$img = new Imagick("quote_blank.jpg");
$txt = new Imagick();
$txt->setBackgroundColor("transparent");
$txt->newPseudoImage(380,250, "Caption:".htmlspecialchars($_GET['quote']) );
$txt->colorizeImage('#468847',1);
$img->compositeImage($txt, imagick::COMPOSITE_OVER, 10, 80);
$draw = new ImagickDraw();
$draw->setFillColor('#468847');
$draw->setGravity(Imagick::GRAVITY_SOUTHEAST);
$draw->setFontSize(25);
$draw->setFontStyle(3);
$img->annotateImage($draw, 5,5,0, htmlspecialchars($_GET['attrib']) );
$img->setImageFormat('jpg');
header('Content-Type: image/jpeg');
echo $img;
?>
(please note that quote_blank.jpg is a 400x400 image background over which the text is rendered and resides in the same directory as the php file).
The issue is that the caption only fills the 380x250 PseudoImage with a very small number of short words. Anything of any length results in just the top half (or less) of the box having any text in it (aside from the attribution annotation).
It seems like the PseudoImage is working correctly but that ImageMagick's algorithm for calculating the font size is only designed to fill the width, not the height. I have no idea how it decides what line length to go for (which would presumably in turn dictate the font size and therefore number of lines and vertical coverage of the caption box).
So I guess my question is this: Is there any way of changing how it does it's calculations in order to fill as much of the caption box as possible, horizontal AND vertical?
Sample of just a few words, showing the caption can go full-height:
Sample of a more typical length of text, showing it doesn't fill the box vertically
I tested your code with ImageMagick 6.8.9-8 and got the following output, which is better than what you're getting. If you're using an older version, try updating ImageMagick.
Vinicius Pinto had the right answer right off the bat. But updating wasn't so easy on a shared server- I have not figured out how to get Imagick to use the updated version. So I had to rewrite my code to access ImageMagick via the commandline, which I wanted to share. Code doesn't show up well as far as I can tell on a comment, so sorry for cheating the answer feature a little.
$location='/home/user/local/bin/convert';
$command='convert -background none -size 380x250 -fill "#468847" caption:"'.htmlspecialchars($_GET['quote']).'" quote_blank.jpg +swap -gravity southeast -geometry +10+80 -composite convert -fill "#468847" -gravity southeast -pointsize 25 -annotate 0x20+5+5 "'.htmlspecialchars($_GET['attrib']).'" anno_label.jpg';
exec ($location . ' ' .$command);
header('Content-Type: image/jpeg');
readfile('anno_label.jpg');
unlink('anno_label.jpg');
I'm attempting to try and assign a value to an image based on its 'saturation level', to see if the image is black and white or color. I'm using Imagick, and have found what seems to be the perfect code for the command line and am trying to replicate it using the PHP library.
I think I understand the concept:
Convert image to HSL.
Extract the 'g' channel (which is the S channel in HSL).
Calculate the mean of this channel.
Command line code
convert '$image_path' -colorspace HSL -channel g -separate +channel -format '%[fx:mean]' info:
My PHP code
$imagick = new Imagick($image_path);
$imagick->setColorspace(imagick::COLORSPACE_HSL);
print_r($imagick->getImageChannelMean(imagick::CHANNEL_GREEN));
Output
My PHP code isn't outputting the same sort of values as the command line code, though. For example, a grayscale image gives 0 for the command line code, but the PHP code gives [mean] => 10845.392051182 [standardDeviation] => 7367.5888849872.
Similarly, another grayscale image gives 0 vs. [mean] => 31380.528443457 [standardDeviation] => 19703.501101904.
A colorful image gives 0.565309 vs. [mean] => 33991.552881892 [standardDeviation] => 16254.018540044.
There just doesn't seem to be any kind of pattern between the different values. Am I doing something obviously wrong?
Thanks.
Just to add, I've also tried this PHP code
$imagick = new Imagick($image_path);
$imagick->setColorspace(imagick::COLORSPACE_HSL);
$imagick->separateImageChannel(imagick::CHANNEL_GREEN);
$imagick->setFormat('%[fx:mean]');
But I get an Unable to set format error when I try and set the format. I've also tried setFormat('%[fx:mean] info:'), setFormat('%[mean]'), setFormat('%mean'), etc.
Update — FIXED!
Thanks to #danack for figuring out I needed to use transformImageColorspace() and not setColorspace(). The working code is below.
$imagick = new Imagick($image_path);
$imagick->transformImageColorspace(imagick::COLORSPACE_HSL);
$saturation_channel = $imagick->getImageChannelMean(imagick::CHANNEL_GREEN);
$saturation_level = $saturation_channel['mean']/65535;
setFormat doesn't replicate the command line option -format - the one in Imagick tries to set the image format, which should be png, jpg etc. The one in the command line is setting the format for info - the closest match for which in Imagick is calling $imagick->identifyImage(true) and parsing the results of that.
Also you're just calling the wrong function - it should be transformImageColorspace not setColorSpace. If you use that you can use the statistics from getImageChannelMean.
There are other ways to test for greyness which may be more appropriate under certain circumstances. The first is to convert the a clone of the image to grayscale, and then compare it to the original image:
$imagick = new Imagick($image_path);
$imagickGrey = clone $imagick;
$imagickGrey->setimagetype(\Imagick::IMGTYPE_GRAYSCALE);
$differenceInfo = $imagick->compareimages($imagickGrey, \Imagick::METRIC_MEANABSOLUTEERROR);
if ($differenceInfo['mean'] <= 0.0000001) {
echo "Grey enough";
}
That would probably be appropriate if you image had areas of color that were also transparent - so they theoretically have color, but not visibly.
Or if you only care about whether the image is of a grayscale format:
$imageType = $imagick->getImageType();
if ($imageType === \Imagick::IMGTYPE_GRAYSCALE ||
$imageType === Imagick::IMGTYPE_GRAYSCALEMATTE) {
//This is grayscale
}
I found a command line here:
convert image.png -colorspace HSL -channel g -separate +channel -format "%[fx:mean]" info:
It prints a number between 0 and 1, where zero means grayscale.
If your images have tint. (from scanner as example) you should do auto color for them before detecting gray scale.
You should normalizeImage(imagick::CHANNEL_ALL) for all separate channels of image. separateImageChannel()
But
I've got the following two commands for imagemagick in the command line:
convert in.png container-mask.png +matte -compose CopyOpacity -composite out.png
composite container.png out.png -compose multiply final.png
Those two commands include 3 files:
in.png: the file that should be masked
container-mask.png: the back/white mask of the areas of container.png where in.png should be visible
container.png image that includes the container for in.png, the one that has been masked in black/white with container-mask.png
Now the question is how to transpose this commands into PHP calls. I've played around quite a bit, but I can't make sense of the API at http://php.net/manual/en/book.imagick.php
Thanks and Bests,
Charly
I've found the answer. Well, that was not too complicated after all:
$original = new Imagick("in.png");
$mask = new Imagick("container-mask.png");
$container = new Imagick("container.png");
$mask->setImageMatte(0);
$original->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
$container->compositeImage($original, Imagick::COMPOSITE_MULTIPLY, 0,0);
$container->setImageFormat( "png" );
echo $container;