4

I was doing some image editing with PHP, since GD provides less functionalities, I switched to Imagick.

One of the processes is to greyscale images. Everything went fine (locally on Windows 7, Imagick 2.2.1-dev 6.5.8-7 Q16) till I uploaded the script to my web hosting server (Linux, Imagick 3.0.1, 6.2.8, 2010-10-20, Q16).

I'v tried to change the quality, but it didn't improve anything.

$img->setImageCompression(imagick::COMPRESSION_JPEG); 
$img->setImageCompressionQuality(100);

Here is the results from GD, Imagick and Photoshop enter image description here

I believe something's wrong with version 3.0.1. Can someone please confirm that?

Q1: Is there an alternative way to convert an image to greyscale with Imagick?

Q2: Is it possible to convert a GD resource to Imagick? So I can use imagefilter($img, IMG_FILTER_GRAYSCALE); to get the correct result and then output with Imagick.

ps: For Q2, you might suggest me to just use GD to process the image. But the problem is that imagejpeg() cannot save images with resolution preserved. and that is actually the reason I switched to Imagick.

Community
  • 1
  • 1
user1643156
  • 4,407
  • 10
  • 36
  • 59
  • 2
    what code are you using to convert to grayscale with Imagick? Are you using $image->setColorspace(imagick::COLORSPACE_GRAY); Take a look at this as well http://stackoverflow.com/questions/4539307/php-imagicklevelimage-usage?rq=1 – Jeremy C Nov 25 '12 at 01:43
  • it's `$img->modulateImage(100, 0, 100);` where parameters are `(brightness, saturation, hue)`. I believe it's the right function to use, and indeed it works fine with version 2.2.1. – user1643156 Nov 25 '12 at 01:50
  • Just because it works in a particular version does not mean it is the right function to use. Using what Jeremy mentions ensures your picture is actually in grey-scale, even as the JPEG file format. What you're doing instead is just a filter. **Edit:** 3 out of five search results on Google suggest Jeremy's approach. – Christian Nov 25 '12 at 01:54
  • Looks like that has only been available since version 6.5.7, and the version on your server may be older. modulateImage should work, but apparently not as well as it could. http://php.net/manual/en/imagick.setcolorspace.php – Jeremy C Nov 25 '12 at 02:04
  • @Christian come on, have you read the manual? `modulateImage` *is* indeed the function to change brightness, saturation and hue. how come it's not the right function to use? version 2.2.1 produces almost the same result as with Photoshop. and the result from 3.0.1 is apprently wrong. – user1643156 Nov 25 '12 at 02:12
  • @user1643156 `modulateImage()` does a lot more than you need, making it more prone to problems (as you've just seen). The colorspace way is much more foolproof since you're telling imagick to specificially switch to grey-scale, not just applying a random colour filter (I mean, does imagick know your end result should be grey-scale?). – Christian Nov 25 '12 at 02:18

4 Answers4

3

This is my preferred way to make a B&W photo in php/imagick: $im = $im->fxImage('intensity');

That applies a function to the image, where intensity is equal to 0.299*red+0.587*green+0.114*blue.

That formula is based on how our eyes are more sensitive to different colours, and as such the difference between that and a "flat" grayscale image really is night and day.

More details here:

Codemonkey
  • 4,455
  • 5
  • 44
  • 76
0
function ImagickToGD($imagick){
    $tmpfile = tmpfile();
    $imagick->writeImage($tmpfile);
    return imagecreatefromstring(file_get_contents($tmpfile));
}

Note that this function does not do any cleanup (except the temp file, which PHP cleans automatically).

So, for example, your code should look like:

$img = new Imagick();
// ...
$gd = ImagickToGD($img);
unset($img); // destroy imagick
imagefilter($gd, IMG_FILTER_GRAYSCALE);
imagejpeg($gd, $target_name, 100);
imagedestroy($gd);

Also, I did not understand the part about "preserving resolution". There is nothing in these operations relating to resolution. My guess is you meant compression? If you want full quality (ie, no compression) simply use 100 as compression value (as I did).

This results in maintaining the existing quality, since opening an image of 70% quality and saving it back with 70% quality actually decreases the final quality by 49% (70% of 70%).


function GDToImagickTo($gd){
    $tmpfile = tmpfile();
    imagepng($tmpfile); // Png is our best image deal:
                        // lossless compression, transparency etc..
    $imagick = new Imagick()
    $imagick->readImage($tmpfile);
    return $imagick;
}
Christian
  • 27,509
  • 17
  • 111
  • 155
  • sorry, I actually meant `GDToImagick`....so I can greyscale with gd -> gd2imagick() -> and then output image with imagick. – user1643156 Nov 25 '12 at 02:00
  • no, I did mean resolution. 72dpi, 150dpi, 300dpi...even though they don't normally matter to jpeg files. The thing I'm doing here is to let clients upload scanned images (150dpi or 300 dpi), and they choose some watermarks to combine with. and then they download the file and print them out. if you hit `Print Preview` in Photoshop, you'll see the image gets much smaller because GD's imagejpeg() outputs images with 72dpi only, which is unlike imagick, you can preserve the dpi (150 or 300). – user1643156 Nov 25 '12 at 02:08
  • I've updated the answer with the function you wanted. Regarding the DPI issue; it can be changed from the client side (unlike compression, which actually destroys the image). Also, I've seen a couple of script around for changing the DPI. You can always `imagejpg(); $imagick->readImage(); $imagick->setImageResolution(); $imagick->writeImage();` (to keep it short) – Christian Nov 25 '12 at 02:15
  • ... imagepng(), imagejpeg()...they are the same thing. as long as these functions are used. the image's resolution will be reduced to 72dpi, it will still be seen as clear on monitor. but when you print them out with a printer. it's only half size (72 out of 150) of the original image. and, you can't expect clients to know image editing, with neither scripting nor photoshop, as least not my clients. they scan, upload, combine, download, print... – user1643156 Nov 25 '12 at 02:34
  • False! The resolution only tells the printer how to print the image; the image data does not change. As an example, get a scanner and scan the same image twice but with different resolutions; as you will see, both are different images since a rasterized image contains pixels and the resolution only tells how big the pixels should look on paper. As such, a high-density image is simply a zoomed-in image (ie, the actual image has to change). This is not the case with your image where the input is exactly the same as the output. – Christian Nov 25 '12 at 12:10
  • To wrap up, JPEG resolution is just meta-data. **It does not affect the actual image.** An image with higher resolution needs to be larger (in terms of pixels). When you change the resolution meta-data, the image stays the same. If you don't change the meta data, the image stays the same anyway. For more info, please [read this](http://www.microscope-microscope.org/imaging/image-resolution.htm) (there are many more out there). – Christian Nov 25 '12 at 12:15
  • @user1643156 See also: http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format#Resolution_and_aspect_ratio – Christian Nov 26 '12 at 10:16
  • Thanks for the info Christian. But the problem with GD is that imagejpeg changes the dpi to 72, even though the size of px can be remained the same, the actual size (aka print size -> cm) is changed as well. it's like producing in Photoshop: you take a 300 dpi image, change the dpi to 72, you'll notice that the px will reduce, you change the px back the same size as the original, the actual size (cm) changes as well (gets much bigger), and you cannot avoid that. But this does not happen with Imagick. – user1643156 Nov 26 '12 at 13:59
  • @user1643156 You're mixing things. Photoshop behaves that way because it actually modifies the image when you change DPI. JPEG DPI, on the other hand, is just meta data. In fact, most often then not, there won't be any DPI meta data set in the first place (as the link explained). Either case, just use the DPI hack I mentioned above. Alternatively, you can use PHP's exif functionality instead. – Christian Nov 26 '12 at 14:04
0

Refer this website and check out the image Magick operators found here www.rubblewebs.co.uk/imagemagick/

Also go with www.fmwconcepts.com/imagemagick/ you will find some examples out here...

raduns
  • 765
  • 7
  • 18
  • ImageMagick and Imagick are totally different things here in this case. I'm talking about programming, not desktop applications... – user1643156 Nov 25 '12 at 11:51
0

You can use the image class what you prefer and then use the method readImageBlob to send it to the imagick http://www.php.net/manual/en/imagick.readimageblob.php

Thiago Mata
  • 2,825
  • 33
  • 32