Imagemagick resizing control quality and extension - php

I am trying to learn Imagemagick, php.net docs are terrible T_T, and I cannot seem to find any answers to my questions. I am wanting to allow people to upload images then resize them and lose EXIF data.
Heres what I have currently.
$thumbnail = new Imagick("http://4.bp.blogspot.com/-hsypkqxCH6g/UGHEHIH43sI/AAAAAAAADGE/0JBu9izewQs/s1600/luna-llena1.jpg");
$thumbnail->thumbnailImage( 100, 100, true );
$thumbnail->writeImage( "avatar/thumbnail.jpg" );
Now how do I control the image file that it is being saved as? Lets say the user submits a gif/png/jpg how would I go about taking that image then saving it as the same input format or changing them all to .png?

This IMO produces the best results for imagick thumbnails;
Load the picture
$img = new imagick( $_FILES['Picture']['tmp_name'] );
Trim an excess off the picture
$img->trimImage(0);
Create the thumbnail, in this case, I'm using 'cropThumbnailImage'
$img->cropThumbnailImage( 180, 180 );
Set the format so all pics can now be the same standard format
$img->setImageFormat( 'jpeg' );
Set the Image compression to that of a jpg
$img->setImageCompression(Imagick::COMPRESSION_JPEG);
Set the quality to be 100
$img->setImageCompressionQuality(100);
The resulting thumbnail is then a little bit blury IMO, so I add a slight sharpening effect to make it 'sharper'. . play around with these settings, but I like..
$img->unsharpMaskImage(0.5 , 1 , 1 , 0.05);

I agree, the PHP.net docs are not very helpful. I've found that it's easiest to find how to do things using commands, then match the commands up with the PHP methods. I'm a little late replying so you might have figured it out by now, but if not, or for the benefit of anyone else:
If you want to change the image format before saving, add this before your writeImage line:
$thumbnail->setImageFormat('png');
Then change the extension in your writeImage line to match, e.g. thumbnail.png
To change the quality, write:
$thumbnail->setImageCompressionQuality(40); // Adjust the number 40
In some cases you might also want to set the compression type by writing:
$thumbnail->setImageCompression(Imagick::COMPRESSION_JPEG);
You can find the COMPRESSION constants here: http://www.php.net/manual/en/imagick.constants.php
Note: These are just examples. This compression would not actually work with a png file.

Related

PHP GD imagejpeg: output file size is bigger size than original

The following script is supposed to create an image with lower quality and so smaller file size (kb), instead it create an image with lower quality but bigger file size.
On my test the original is about 300kb, using 90% quality the output is almost the double and using 100% quality, the output is more than 1mb ...
<?php
$quality = 90;
$path = '/var/www/TEST/';
$inputSrc = $path . 'original.jpg';
$outputSrc = $path . 'after' . $quality . '.jpg';
$handler = imagecreatefromjpeg($inputSrc);
imagejpeg($handler, $outputSrc, $quality);
I assume the issue is related to imagejpeg bad implementation ...
is there any way to workaround this ?
isImageMagicka better solution ?
Thanks
Update
I was curious so I gave a try to ImageMagick and unfortunately I have similar result (slightly better).
Full test results:
Original size: 294.6Kb
GD (imagejpeg) 90%: 581.7Kb
GD (imagejpeg) 100%: 1.1Mb
ImageMagick 90%: 431.7Kb
ImageMagick 100%: 780.9kb
Update 2
I did some more test with GIMP and looks that in order to obtain a file with very similar size to the original one you have to check the option use quality setting from original image.
Now I'm confused more ... since when I select that setting Gimp automatically change the output quality to 74% (for the example image).
I was assuming that the JPEG quality value, if lower that 100%, decrease the image quality at every iteration of a save ... but I start to think I'm wrong here.
Update 3
With ImageMagick is not necessary to specify the quality of the sample and if you leave it emptyImageMagick will use the same quality detected in the input image.
So for the example image it is detected as a quality of 69 and the outfile is 326kb. That is the best result so far.
Here the image I'm using:
I had a little look at this. You can work backwards in ImageMagick and, rather than define the quality and see what size results, you can define the size and see what quality results. So, for a concrete example, you can say you want the output file not to exceed 100kB, like this:
convert MShRR.jpg -define jpeg:extent=100k out.jpg
and you get 99kB like this:
-rw-r--r--# 1 mark staff 294608 14 Jan 09:36 MShRR.jpg
-rw-r--r--# 1 mark staff 99989 14 Jan 09:44 out.jpg
To my eyes, the resulting image is a little posterised:
You can often add a tiny amount of blur to disguise this, as follows:
convert MShRR.jpg -blur x0.5 -define jpeg:extent=100k out.jpg
YMMV - Your Mileage May Vary !!!

Add round corners to a jpeg file

I am trying to add round corners to a jpeg file, but the problem is that after adding round corners, I am getting a black background color. Somehow I am not able to change it to any other color (white, transparent, red). It just simply shows black background where the image has rounded corners.
The code that I am using is:
<?php
$image = new Imagick('example.jpg');
$image->setBackgroundColor("red");
$image->setImageFormat("jpg");
$image->roundCorners(575,575);
$image->writeImage("rounded.jpg");
header('Content-type: image/jpeg');
echo $image;
?>
I cannot use png as the jpeg files are huge, about 5 MB, so if I used png, the file size would go up to 26 MB, even though the png adds transparent round corners.
Also the IMagick version that i am using is:
ImageMagick 6.6.2-10 2010-06-29 Q16 http://www.imagemagick.org
Also the output(image generated) will get printed so I don't know if css will work over here.
Sorry, I am trying to actually create a new jpeg file with rounded corners from an already existing jpeg file that doesn't have round corners this is actually a photograph taken from a camera, so there are multiple/too many colors so I can't use gif as well.
Also my site will only just generate the round corner image then afterwards it will get downloaded using a FTP program by the admin of the site and then using a system software will get printed, so in short my website will not be printing the image but rather just generate it
Try this:
<?php
$input = 'example.jpg';
$size = getimagesize($input);
$background = new Imagick();
$background->newImage($size[0], $size[1], new ImagickPixel('red'));
$image = new Imagick($input);
$image->setImageFormat("png");
$image->roundCorners(575,575);
$image->compositeImage($background, imagick::COMPOSITE_DSTATOP, 0, 0);
$image->writeImage("rounded.jpg");
?>
I may get downvoted, but I say let css deal with the corners and take some load off of your server :)
CSS rounded corners.
JPG doesn't have a transparent color(s) (alpha channels) in its palette.
The output image must use either PNG or GIF (or another image format that supports alpha channels).
setImageBackgroundColor is another option if you want an opaque background.
EDIT
Your comment reminds me that you could try to use the command line; shell_exec() will run a command line argument from PHP. The command in the ImageMagick API you'll need to start with is convert example.jpg, and then you can pass flags with the various parameters you want.
Since ImageMagick is already installed, it will work right away. You may need to point your system PATH to the ImageMagick directory where all of the executables are.
There's plenty of questions and forums dedicated to rounded corners with this method so I'll leave that up to you.
Here's a helpful tip though - there is a silly confusion with the convert command, since Windows also has a convert.exe that is rarely used, but will confuse your command line, so make sure you're calling the right convert. ;) To test if it's working, try convert example.jpg example.gif (which should convert your example to a gif).
To get output from your command line, finish all commands with 2>&1 which will pipe cmd output back into PHP.

Using imagejpeg to make image files unnoticeable smaller

I'm making an image sharing website with php. I was reading about google's pagespeed, and they said I needed to optimize my images, so I've been trying to do that with imagejpeg, then hopefully I'll be able to use basically the same code with png and gif.
This is the code I have at the moment:
$img = imagecreatefromjpeg($original);
if ($extension === "jpg" || $extension === "jpeg"){
$location = $_SERVER['DOCUMENT_ROOT'] . "/uploads/" . $id . "/fullsize." . $extension;
$temp = fopen($location, 'w');
imagejpeg($img, $location, 80);
fclose($temp);
}
And it does the job of taking the image at $original, and saving a copy that's been through imagejpeg to $location.
But sometimes the resulting file is larger than the original was! This is where I get stumped.
Why is this happening?
How can I make it stop happening?
I'm trying to reduce image file sizes without hurting their appearance, is there a better way to do it than this?
Thanks,
Liam
imagejpeg will only shrink the file if you save it at a lower quality setting than the original was produced with
e.g.
imagejpeg($gd, 'temp.jpg', 50);
$temp = imagecreatefromjpeg('temp.jpg');
imagejpeg($gd, 'temp2.jpg', 70);
will probably produce a larger temp2 file, because it's at a higher quality setting, which roughly translates to "don't compress as much".
There's no way to predict what the final output size will be for a given image and quality setting without actually going through the whole jpeg compress process. You may have to do a few trial recompresses of an image and lower the quality setting each time until you start getting some shrinkage.
of course, if you lower the quality TOO low, you'll basically trash the image and definitely introduce visible artifacts.
It definitely depends on the quality of the original image. If your image is quality 60 originally, saving at quality 80 will generally result in a larger file size.
However, it also depends on what software created the original image. For example, I've observed many times where Adobe Photoshop can save an image at quality 60 that looks as good as 80 from GD (the graphics library you are using). Also, Photoshop can often save images at the same quality as another graphics package but with a smaller size. This is subjective, of course. I'm not necessarily concluding Photoshop is "better," but it does appear to have it's options well tuned.
I recommend you try ImageMagick, as I've seen it generally do a better job (file sizes, image quality) than GD. You should also determine the original quality setting per image so you don't accidentally grow images.

php imagerotate() ruins alpha on png?

I've been bashing my head agains something simple..
// ....all prev code is fine....
$pasteboard =imagecreatetruecolor($imgs['bg']["width"],$imgs['bg']["height"]);
imagealphablending($pasteboard, false);
imagecopyresampled($pasteboard, $imgs['bg']["img"],0,0,0,0,$imgs['bg']["width"],$imgs['bg']["width"],imagesx($imgs['bg']["img"]),imagesy($imgs['bg']["img"]));
imagecopyresampled($pasteboard, $imgs['photo']["img"],20,20,0,0,$imgs['photo']["width"],$imgs['photo']["width"],imagesx($imgs['photo']["img"]),imagesy($imgs['photo']["img"]));
imagesavealpha($pasteboard,true);
//send it out
$out = $pasteboard;
header('Content-type: image/png');
imagepng($out);
//then garbage collection
gives me this:
HORAY!
perfect alpha png composite...
Now I want to rotate it, so instead of the $out=$pasteboard i do this:
imagesavealpha($pasteboard,true);
//rotate it
$out = imagerotate($pasteboard,5,imagecolorexactalpha($pasteboard,255,255,255,50),0);
header('Content-type: image/png');
imagepng($out);
which sadly gives me this:
BOOOO!
Ive tried setting the color like:
imagerotate($pasteboard,5,0x00000000,0);
also the last attr like:
imagerotate($pasteboard,5,0x00000000,1);
new empty images sampled etc etc...
no dice....
Can anyone help?
I'm answering my question simply because I've tried 10-15 suggestions i've seen allover the web all of which offering 'nearly' right solutions but nothing exact, Also I've seen this question posted a few places now, and hopefully if anyone reaches this page in future it would be best to show the solution as the direct answer.
MASSIVE thanks to #cristobal for the help and efforts, if I could vote you up any more I would !
The knack seems to be:
//rotate it
$pasteboard = imagerotate($pasteboard,5,0XFFFFFF00,0); //<-- here must be RRGGBBAA, also last attr set to 0
imagesavealpha($pasteboard, true); // <-- then to save it... dont ask me why..
//send it out
header('Content-type: image/png');
imagepng($pasteboard);
produces this (it has a perfect alpha even though you cant see against the white page):
REALLY not the most fun 5 hrs of my life... hopefully it will stop someone else going through the same pain..
Using the same code above and using a blue color for the third parameter in the imagerotate operation, which will be it used to fill the uncovered zone after the rotation i.e.:
imagerotate($pasteboard, 5, 255);
We get the following image
we see the blue area is the uncovered zone which it fills, while the black color is the to be the border shadow from the image which GD does not seem to handle well along the interpolation used in the rotation.
The same image rotated using the convert for imagemagick. commmand i.e. $> convert -rotate 5 image.png image_rotated.png results in the image below
Clearly GD does not handle alpha colors well when rotating.
If you have access to use the convert commmand using exec or process, you should pipe those image operation to imagemagick instead. GD is a simple image library which has not been updated much the latest years. Otherwise try Imagemagick, Cairo or Gmagick which there are pecl plugins for too http://php.net/manual/en/book.image.php.
Last resort somebody made a function that which uses GD http://www.exorithm.com/algorithm/view/rotate_image_alpha for what you are looking after but the result is not pretty since its a simple linear interpolation:
taken from How to rotate an image in GD Image Library while keeping transparency?. Perhaps if you convert the linear interpolation function to a Bicubic or Quad it will look better.
Note these answers did not work for me but this did.
$destimg = imagecreatefromjpeg("image.png");
$rotatedImage = imagerotate($destimg, 200, 0);
imagesavealpha($rotatedImage, true);
imagepng($rotatedImage,"rotated.png");

php get original image type [duplicate]

I have a sever which people can upload files to. The problem is that some of the filenames are mangled (dont have any extension) and so I cannot immediately determine file type. This question is two part: for the files which do have filenames what is the best way to determine whether or not it is an image? (Just a big long if/else if list?) Secondly, for the files which dont have extensions, how can I determine if they are images?
You can use exif_imagetype()
<?php
$type =exif_imagetype($image);
where $type is a value
IMAGETYPE_GIF
IMAGETYPE_JPEG
IMAGETYPE_PNG
IMAGETYPE_SWF
IMAGETYPE_PSD
IMAGETYPE_BMP
IMAGETYPE_TIFF_II (intel byte order)
IMAGETYPE_TIFF_MM (motorola byte order)
IMAGETYPE_JPC
IMAGETYPE_JP2
IMAGETYPE_JPX
IMAGETYPE_JB2
IMAGETYPE_SWC
IMAGETYPE_IFF
IMAGETYPE_WBMP
IMAGETYPE_XBM
IMAGETYPE_ICO
From the manual:
When a correct signature is found, the appropriate constant value will be returned otherwise the return value is FALSE. The return value is the same value that getimagesize() returns in index 2 but exif_imagetype() is much faster.
You can use getimagesize
It does not require the GD image library and it returns same information about image type.
http://it2.php.net/manual/en/function.getimagesize.php
If you have the GD2 extension enabled, you could just use that to load the file as an image, then if it returns invalid you can catch the error and return FALSE, otherwise return TRUE.
You have two options here, one's simple and pre-built with some shortfalls, the other is complex and requires math.
PHP's fileinfo can be used to detect file types based on the file's actual header information. For instance, I just grabbed your gravitar:
But the actual code is this:
‰PNG
IHDR szzô
IDATX…­—OL\UÆZÀhëT)¡ c•1T:1‘Š‘.Ú(]4†A“ÒEY˜à.................................
So, even without the file name I could detect it quite obviously. This is what the PHP Fileinfo extension will do. Most PNG and JPG files tend to have this header in them, but this is not so for every single file type.
That being said, fileinfo is dead simple to use, from the manual:
$fi = new finfo(FILEINFO_MIME,'/usr/share/file/magic');
$mime_type = $fi->buffer(file_get_contents($file));
Your other option is more complex and it depends on your own personal ambitions, you could generate a histogram and profile files based on their content.
Something like this looks like a GIF file:
And something like this looks like a TIFF file:
From there you'd need to generate a model over multiple types of files for what the histogram of each type should be, and then use that to guess. This is a good method to use for files that don't really have those "magic headers" that can be read easily. Keep in mind, you'll need to learn some math and how to model an average histogram function and match them against files.
You can try to load the image into PHP's GD library, and see if it works.
$file = file_get_contents('file');
$img = imagecreatefromstring($file);
if($img === FALSE){
// file is NOT an image
}
else{
// file IS an image
}
Look at image magic identify. http://www.imagemagick.org/script/identify.php
The php wrapper is here: http://www.php.net/manual/en/function.imagick-identifyimage.php
Or if you just want to validate that it's an image (and don't care about the meta data): http://www.php.net/manual/en/function.imagick-valid.php
exif_imagetype() might work
make sure you have exif enabled.
Try looking at exif_imagetype
If you need a fast solution, use imagesx() and imagesy(). There is also a fast way to check large image file dimensions, by reading just a small amount of data from the file header. Explained in more detail in the following url:
http://hungred.com/useful-information/php-fastest-image-width-height/
You can use the Fileinfo extension:
http://www.php.net/manual/en/function.finfo-file.php
finfo_file() uses magic bytes and does not have to load the whole image into memory. The result is a string with the corresponding MIME type, e.g.:
text/html
image/gif
application/vnd.ms-excel
The type of the image is typically going to be able to be inferenced from the header information of the file.
For the first question is extension is known you could use the PHP function in_array() Documentation

Categories