PHP - ImageCopyResampled max size - php

What is the maximum width and height that ImageCopyResampled can handle? My code works for smaller images in terms of width and height. For larger images, it will disregard the coordinates, meaning the cropping starts from the upper left corner of the image.
Is there a workaround? Here's a portion:
$trgt_width = 500;
$trgt_height = 400;
if(copy($src_file, $trgt_file)):
$src_image = imageCreateFromJpeg($src_file);
$trgt_image = imageCreateTrueColor($trgt_width, $trgt_height);
imageCopyResampled($trgt_image, $src_image, 0, 0, $x, $y, $trgt_width, $trgt_height, $width ,$height);
imageJpeg($trgt_image, $thumb_file, 75);
endif;
Thanks.

It depends on the maximum amount of RAM your scripts may occupy. This is usually set on your server by the administrator. The setting is called memory_limit
You can find it out using phpinfo() and searching for "memory_limit".
A rough calculation on the size needed to resize an image:
number of bytes width x number of bytes height x 3
3 for each channel of a true color image: Red, Green and blue.
So, an image 1000 x 1000 Pixels in size will take up at least 3 MB of memory. Probably more during the resize process, because the function will have to keep both the large and the resized version in memory at the same time.
In your case though, I would suspect that the image does not get cropped at all, probably because the copy operation fails because $src_file does not exist at all.

Related

My php image server using Imagick produces much larger png8 files after cropping / scaling down

I'm trying to set up a simple PHP image server to allow me to add just large file for each of my images and then scale and crop them as needed. For my test file I start with a png8 exported via "save for web" from illustrator of size 2400 x 1200, which has a filesize of 21.6KB.
When I use Imagick's cropThumbnailImage function to reduce it to 600 x 600 the resulting file is 62.1KB (three times the size for a substantially smaller image). A 600 x 600 crop of the same image saved from illustrator clocks in at about 8.2KB. I can accept a modest file size increase for the added convenience, but an ~8x increase is just too much.
When saving the file I make sure to force the output to png8 so it doesn't default to a lossless png format, but other than that I'm clueless as to how to resolve it.
Here is my processing code:
//create working image
$image = new Imagick( $this->orig_file );
// Set Compression
$image->setImageCompressionQuality( 9 );
//scale image to height
$image->cropThumbnailImage ( $this->w, $this->h );
// strip extra data
$image->stripImage();
// save file
$image->writeImage( 'png8:'.$this->output_file );
Here are my test files:
Original Full scale image outputted by illustrator.
Cropped 600 x 600 image generated by imagick.
[EDIT: As per Mark's suggestion below I added the following changes]
// replacing cropThumbnailImage with:
$image->resizeImage(0, $this->h, imagick::FILTER_TRIANGLE, 1);
// crop
$start = ($image->getImageWidth() / 2) - ($this->w / 2);
$image->cropimage($this->w, $this->h, $start, 0);
// reduce colors to 20
$image->quantizeImage($this->q, 1, 0, true, false); // using 20 as $this->q
The end result goes from 62.1KB to 50.4KB, better but still over double the size of the fullsized image, and many times larger that the illustrator save for web version at that size.
600x600 image reduced to 20 colors and resized not thumbnailed
Your original image has 33 colours and weighs in at 22kB.
If you resize like this (albeit at the command line):
convert jabba.png -resize 600x600 -strip png8:result.png
the output file will be 6.6kB.
If you resize like I suggested with -scale:
convert jabba.png -scale 600x600 -strip png8:result.png
the output file will be 5.0kB.
If you retain -quality 9 in there, you will end up with > 25kB.

Fill an Image with white color to have square dimensions

Let's say I have an Image of 300 x 500 (width x height) pixels.
Now I need to generate an image with square dimensions of it.
Instead of cropping the image, I want to fill the missing space with white color.
In this example the with should be filled by 200 pixels (100 pixels on each side so the image is in the middle) so that the Image would be 500 x 500 px.
If it was opposite (500 x 300) the same should happen but with the height.
I have almost no experience in using imagemagick so how could I do that?
Use Imagick::borderImage()!
Example for your case of filling 100px left and right each:
// let's assume that $im is your image object
$color=new ImagickPixel();
$color->setColor("white");
$im->borderImage($color,100,0);

how to deal with unexpected width and height

I am currently using the following code to re size all images bigger than 800 x600 to the required size.
if (($width>800) and ($height>600))
{
WideImage::load($img_path.$name)->resize(800, 600)->saveToFile($img_path.$name);
}
However this won't work if for example an image has a width of 1024 and height 559
I can use an or but I am not sure how to deal with resizing those Images .
I have always found the most reliable method to resize an image is to use a ratio of the height to the width.
The psuedocode code would look like this:
$widthRatio=$originalImageHeight/$originalImageWidth;
$newImage=resize(800, 800*$widthRatio);
This will then resize it to be 800 while maintaining the original ratio.
Also, you might want to set or at least check the ratio so that you don't get an image that is 1000 x 20,000 uploaded which will still mess up your site if you resize it to 800 x 16,000

Image file size differences between Imagemagick and GD library

I have been doing some tests and found out that Imagemagick creates larger file sized images compared to GD library.
I have tried using thumbnailImage method and also resizeImage method (with different filters) of Imagemagick for creating an image of max dimension 1024x680 jpeg with JPEG compression and quality 80 and at 72 pixels per inch resolution and am also using stripImage method to remove unneeded meta data. The file size created by Imagemagick is always in the range of 700KB to 800KB depending upon various filters. On the other hand GD library produces an image of size 1024x680 which is only 41KB in size.
Can anyone please explain the difference in file sizes. I opened up the 2 files in Photo shop and checked to see any differences but could not find any (DPI, color profile, 8 bit channel etc), but still cant explain the difference in file sizes.
$srgbPath = "pathTosrgbColorProfile";
$srgb = file_get_contents($srgbPath);
$image->profileImage('icc', $srgb);
$image->stripImage();
$image->setImageResolution(72,72);
$image->setImageUnits(1);
$image->setInterlaceScheme(Imagick::INTERLACE_JPEG);
$image->setImageCompression(imagick::COMPRESSION_JPEG);
$image->setImageCompressionQuality(80);
$image->setColorspace(imagick::COLORSPACE_SRGB);
$image->resizeImage($thumb_width,$thumb_nheight,imagick::FILTER_CATROM,1);
$image->writeImage($destination);
The size went down by 40KB giving an output of 711KB which is still pretty big. The Hi-res original file I am testing on is a jpeg of size 3008x2000 (4.2MB).
Edit:
I think I figured it out, the method setCompression() does it for the Object and not the image, instead I used setImageCompression() and setImageCompressionQuality() and now the size has reduced to 100KB.. All good now!
Maybe the Quality settings of GD and ImageMagick aren't easily comparable, 80% in one does not mean the same as 80% in the other. I found the following note in an article form Smashing Magazine:
It turns out that JPEG quality scales are not defined in a specification or standard, and they are not uniform across encoders. A quality of 60 in Photoshop might be the same as a quality of 40 in one program, quality B+ in another and quality fantastico in a third. In my tests, I found that Photoshop’s 60 is closest to -quality 82 in ImageMagick.
So you may pay more attention on quality when comparing the different result files. Maybe the colors differ or the gd image has more artifacts.
The differnce seems rather large; when I did some tests a couple of years ago the file size of IM was about 5x the size of GD.
It would be interesting to see your actual code used.
I am at work at the moment but have a photo resized to 592 x 592 and the filesize is 50.3KB I know it is not the same size as yours but it was saved at quality 100
You can run this and see what IM says about the output files:
convert image -verbose -identify
EDIT:
You must be doing something wrong I have just run a test and the results are below - For some reason the thumbnail size is the same as the resize size! Maybe a bug.
Original file size: 4700 x 3178 2.31MB
-resize dimensions = 1021 x 680 186kb
-thumbnail dimensions = 1021 x 680 186kb
GD dimensions = 1024 x 682 100kb
$original = 'IMG_4979_1.CR2';
// Convert to jpg as GD will not work with CR2 files
exec("convert $original image.jpg");
$image = "image.jpg";
exec("convert $image -resize 1024x680 output1.jpg");
exec("convert $image -thumbnail 1024x680 -strip output2.jpg");
// Set the path to the image to resize
$input_image = 'image.jpg';
// Get the size of the original image into an array
$size = getimagesize( $input_image );
// Set the new width of the image
$thumb_width = "1024";
// Calculate the height of the new image to keep the aspect ratio
$thumb_height = ( int )(( $thumb_width/$size[0] )*$size[1] );
// Create a new true color image in the memory
$thumbnail = ImageCreateTrueColor( $thumb_width, $thumb_height );
// Create a new image from file
$src_img = ImageCreateFromJPEG( $input_image );
// Create the resized image
ImageCopyResampled( $thumbnail, $src_img, 0, 0, 0, 0, $thumb_width, $thumb_height, $size[0], $size[1] );
// Save the image as resized.jpg
ImageJPEG( $thumbnail, "output3.jpg" );
// Clear the memory of the tempory image
ImageDestroy( $thumbnail );

Resize panoramic image to fixed size

I want to resize the images to fixed width and height (i.e. 150px). However, theres a problem, if there is lots of difference in height and width of original photo (for example, panoramic photo), the resized thumbnail looks bad. Is there any any smart solution to resize the photos to a fixed width and height? For example, please have a look at this
image:
Here's my code:
<?php
$params = getimagesize($tempFile);
$width = $params[0];
$height = $params[1];
$newwidth=150;
$newheight= 150;
$tmp=imagecreatetruecolor($newwidth,$newheight);
imagecopyresampled($tmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);
imagejpeg($tmp,$img_name,80);
imagedestroy($src);
imagedestroy($tmp);
?>
Is there any smart way to resize the images in smart way?
Thanks.
There's a smart solution, it's called Seam Carving, and if your server supports ImageMagick, you do it like this:
<?php
$im = new Imagick( 'image.jpg' );
$im->liquidRescaleImage( 600, 100, 3, 25 );
header( 'Content-Type: image/jpg' );
echo $im;
?>
Or alternatively, if it doesn't support, use exec() (carefully) in order to pass image as an argument to executable which can perform seam carving.
BTW it looks like twitpic just crop's the squared image extract.
In one of my previous projects I used following code:
if ($image->width > $image->height){
//crop image in proportions 4/3, then resize to 500x300 (or proportionally lower resolution),
//sharp it a little and decrease quality.
//I used one of the Yii framework extensions.
$image->crop($image->width, $image->width/4*3)->resize(500, 300, Image::WIDTH)->sharpen(15)->quality(75);
}
It looks like twitpic is finding out how long the short axis is, then takes a square centered on the original image with sides equal to the short axis length, then shrinking that down to 150x150.
Not, resmaple, get only center 150x150 pixels.
You will need to calculate the appropriate coordinates for the original area you want to copy:
imagecopyresampled($tmp,$src,0,0,[THIS VALUE],[THIS VALUE],$newwidth,$newheight, [THIS VALUE],[THIS VALUE]);
As of now, you take the area from 0,0 (x,y) to width,height (x,y) of the original area and try to cramp it into 150x150.
you will need to calculate which of width and height that is the "biggest" and crop that and make sure that the ratio is the same as your resulting image (in your case, ratio is 1.0 because of 150x150).
In your example, where width is 1050 and height is 317 pixels so you want a portion of the original image that is 317x317 (ratio 1.0), you need to:
subtract 317 from 1050 = 733; // this is the excessive area for both sides
divide by 2 =~ 366; // to get the excessive area for one side
Now, use first x coordinate 366, to start 366 pixels from the left.
Use second x coordinate 1050 - 366 start 366 pixels from the right.
So your example should be (just guessing here):
imagecopyresampled($tmp,$src,0,0,366,0,$newwidth,$newheight, $width - 366, 0);
You will of course need some logic in order to calculate this correctly for any other size.

Categories