Resize large images in php with imagemagick

Resizing images

Web applications often need to work with images like pictures of users or photos etc. So the need to need to resize images comes up when creating thumbnails for example or compressing images for storage. The default library to handle image operations in php is GD. It can be used to resize images.

Resize with GD

The function imagecopyresampled is used to resize an image with gd library.

Here is a quick example


function resize_image($src , $dest , $toWidth , $toHeight , $options = array()) 
{
	if(!file_exists($src))
	{
		die("$src file does not exist");
	}
	
	//OPEN THE IMAGE INTO A RESOURCE
	$img = imagecreatefromjpeg ($src);	//try jpg
	
	if(!$img)
	{
		$img = imagecreatefromgif ($src);	//try gif
	}
	
	if(!$img)
	{
		$img = imagecreatefrompng ($src);	//try png
	}
	
	if(!$img)
	{
		die("Could Not create image resource $src");
	}
	
	//ORIGINAL DIMENTIONS
	list( $width , $height ) = getimagesize( $src );
	
	//ORIGINAL SCALE
	$xscale=$width/$toWidth;
	$yscale=$height/$toHeight;
	
	//NEW DIMENSIONS WITH SAME SCALE
	if ($yscale > $xscale) 
	{
		$new_width = round($width * (1/$yscale));
		$new_height = round($height * (1/$yscale));
	}
	else 
	{
		$new_width = round($width * (1/$xscale));
		$new_height = round($height * (1/$xscale));
	}
	
	//NEW IMAGE RESOURCE
	if(!($imageResized = imagecreatetruecolor($new_width, $new_height)))
	{
		die("Could not create new image resource of width : $new_width , height : $new_height");
	}
	
	//RESIZE IMAGE
	if(! imagecopyresampled($imageResized, $img , 0 , 0 , 0 , 0 , $new_width , $new_height , $width , $height))
	{
		die('Resampling failed');
	}
	
	//STORE IMAGE INTO DESTINATION
	if(! imagejpeg($imageResized , $dest))
	{
		die("Could not save new file");
	}
	
	//Free the memory
	imagedestroy($img);
	imagedestroy($imageResized);
	
	return true;
}

The above program can resize a gif, jpg, or png image and the output is a jpg image.

However the above has some problems. If a jpg image for example , is 5000px x 5000px then imagecreatefromjpg would uncompress it and use a large amount of memory (5000 x 5000 pixels) to store it. This memory is taken from RAM or the memory allocated to php. The amount of memory needed in uncompressed form can easily go upto several hunder MBs which is much higher than what php normally has. And then memory exceeded error might be thrown depending on how much memory is available to php.

Resize with Imagemagick







To overcome the memory problem, imagemagick is an excellent solution. Imagemagick can resize large images by using disk space instead of RAM memory.

Here is a quick example of how to resize an image using imagemagick library.

//Resize using imagemagick , it is memory efficient, GD fails since images are uncompressed.
try
{
	$img = new Imagick($old_path);
	$img->thumbnailImage(500 , 500 , TRUE);
	$img->writeImage($new_path);
	
	$count++;
}
catch(Exception $e)
{
	echo 'Caught exception: ',  $e->getMessage(), "n";
	$error++;
}						

This should work where gd fails due to memory limitations.

Memory usage can be limited by using :

$img->setResourceLimit( Imagick::RESOURCETYPE_MEMORY, 5 );

Source

When memory limit is reached , disk space is used for memory.

Other ways of resizing images using imagemagick

<?php
/**
 * Calculate new image dimensions to new constraints
 *
 * @param Original X size in pixels
 * @param Original Y size in pixels
 * @return New X maximum size in pixels
 * @return New Y maximum size in pixels
 */
function scaleImage($x,$y,$cx,$cy) {
    //Set the default NEW values to be the old, in case it doesn't even need scaling
    list($nx,$ny)=array($x,$y);
    
    //If image is generally smaller, don't even bother
    if ($x>=$cx || $y>=$cx) {
            
        //Work out ratios
        if ($x>0) $rx=$cx/$x;
        if ($y>0) $ry=$cy/$y;
        
        //Use the lowest ratio, to ensure we don't go over the wanted image size
        if ($rx>$ry) {
            $r=$ry;
        } else {
            $r=$rx;
        }
        
        //Calculate the new size based on the chosen ratio
        $nx=intval($x*$r);
        $ny=intval($y*$r);
    }    
    
    //Return the results
    return array($nx,$ny);
}
?>

Use it like this:

<?php
//Read original image and create Imagick object
$thumb=new Imagick($originalImageFilename);

//Work out new dimensions
list($newX,$newY)=scaleImage(
        $thumb->getImageWidth(),
        $thumb->getImageHeight(),
        $newMaximumWidth,
        $newMaximumHeight);

//Scale the image
$thumb->thumbnailImage($newX,$newY);

//Write the new image to a file
$thumb->writeImage($thumbnailFilename);
?>
$fitbyWidth = (($maxWidth/$w)<($maxHeight/$h)) ?true:false;

if($fitbyWidth){
    $im->thumbnailImage($maxWidth, 0, false);
}else{
    $im->thumbnailImage(0, $maxHeight, false);
}

Maximum width and height

For example if the resized image should have a maximum width of 200px , and maximum height of 82 px , then the limits can be applied easily like this :

// Create thumbnail max of 200x82
$width=$im->getImageWidth();
if ($width > 200) 
{ 
    $im->thumbnailImage(200,null,0); 
}

//now check height
$height=$im->getImageHeight();
if ($height > 82) 
{ 
    $im->thumbnailImage(null,82,0); 
}

Resources

1. Imagemagick tutorials - http://valokuva.org/?cat=1

2. http://www.php.net/manual/en/function.imagick-thumbnailimage.php

3. http://www.php.net/manual/en/book.imagick.php

Last Updated On : 19th July 2011

Subscribe to get updates delivered to your inbox

3 Comments + Add Comment

  • Thank you for opinion ;)

  • Dear Blogger

    I’m going to change my code from using GD to Imagemagick (Fred’s ImageMagick Scripts inspired me). What should I used to? Included in php ImageMagick or with system() command? What in your opinion is more efficient?

    • Use the php extension for imagemagick.

Leave a comment