Resize an Image (on the fly) & Keep its Aspect Ratio using PHP and GD

Posted on September 28, 2008, under PHP 

This is a PHP Class useful if you need to resize images keeping their aspect ratio, using the GD Library. The new height is calculated proportionally to the new width’s size and reverse. For instance you have an image with the following dimensions: width – 1000, height – 800. Its thumbnail with a width of 250 will have the height of 200 (the ratio is kept).

Here’s the class (I will explain you how it works below):

resize.image.class.php

<?php
/*
---------------------------------------------------------------------
Credits: Bit Repository

Source URL: http://www.bitrepository.com/resize-an-image-keeping-its-aspect-ratio-using-php-and-gd.html
---------------------------------------------------------------------
*/
class Resize_Image {

var $image_to_resize;
var $new_width;
var $new_height;
var $ratio;
var $new_image_name;
var $save_folder;

function resize()
{
if(!file_exists($this->image_to_resize))
{
  exit("File ".$this->image_to_resize." does not exist.");
}

$info = GetImageSize($this->image_to_resize);

if(empty($info))
{
  exit("The file ".$this->image_to_resize." doesn't seem to be an image.");
}

$width = $info[0];
$height = $info[1];
$mime = $info['mime'];

/*
Keep Aspect Ratio?

Improved, thanks to Larry
*/

if($this->ratio)
{
// if preserving the ratio, only new width or new height
// is used in the computation. if both
// are set, use width

if (isset($this->new_width))
{
$factor = (float)$this->new_width / (float)$width;
$this->new_height = $factor * $height;
}
else if (isset($this->new_height))
{
$factor = (float)$this->new_height / (float)$height;
$this->new_width = $factor * $width;
}
else
exit(”neither new height or new width has been set”);
}

// What sort of image?

$type = substr(strrchr($mime, '/'), 1);

switch ($type)
{
case 'jpeg':
    $image_create_func = 'ImageCreateFromJPEG';
    $image_save_func = 'ImageJPEG';
	$new_image_ext = 'jpg';
    break;

case 'png':
    $image_create_func = 'ImageCreateFromPNG';
    $image_save_func = 'ImagePNG';
	$new_image_ext = 'png';
    break;

case 'bmp':
    $image_create_func = 'ImageCreateFromBMP';
    $image_save_func = 'ImageBMP';
	$new_image_ext = 'bmp';
    break;

case 'gif':
    $image_create_func = 'ImageCreateFromGIF';
    $image_save_func = 'ImageGIF';
	$new_image_ext = 'gif';
    break;

case 'vnd.wap.wbmp':
    $image_create_func = 'ImageCreateFromWBMP';
    $image_save_func = 'ImageWBMP';
	$new_image_ext = 'bmp';
    break;

case 'xbm':
    $image_create_func = 'ImageCreateFromXBM';
    $image_save_func = 'ImageXBM';
	$new_image_ext = 'xbm';
    break;

default:
	$image_create_func = 'ImageCreateFromJPEG';
    $image_save_func = 'ImageJPEG';
	$new_image_ext = 'jpg';
}

	// New Image
	$image_c = ImageCreateTrueColor($this->new_width, $this->new_height);

	$new_image = $image_create_func($this->image_to_resize);

	ImageCopyResampled($image_c, $new_image, 0, 0, 0, 0, $this->new_width, $this->new_height, $width, $height);

        if($this->save_folder)
		{
	       if($this->new_image_name)
	       {
	       $new_name = $this->new_image_name.'.'.$new_image_ext;
	       }
	       else
	       {
	       $new_name = $this->new_thumb_name( basename($this->image_to_resize) ).'_resized.'.$new_image_ext;
	       }

		$save_path = $this->save_folder.$new_name;
		}
		else
		{
		/* Show the image without saving it to a folder */
		   header("Content-Type: ".$mime);

	       $image_save_func($image_c);

		   $save_path = '';
		}

	    $process = $image_save_func($image_c, $save_path);

		return array('result' => $process, 'new_file_path' => $save_path);

	}

	function new_thumb_name($filename)
	{
	$string = trim($filename);
	$string = strtolower($string);
	$string = trim(ereg_replace("[^ A-Za-z0-9_]", " ", $string));
	$string = ereg_replace("[ tnr]+", "_", $string);
	$string = str_replace(" ", '_', $string);
	$string = ereg_replace("[ _]+", "_", $string);

	return $string;
	}
}
?>

Variables Info

$image_to_resize – Here we set the full path (i.e. /home/www.mysite.com/public_html/images/myimage.jpg) to the image we wish to resize. If the image is in the same folder with the class, then you can just set the filename as the path (i.e. mywallpaper.jpg).

The $new_width & $new_height are the new dimensions for the resized image.

$ratio – Do you wish to keep the image’s ratio aspect after resize? If it’s set to true it will calculate the new dimensions based on the new width (if it’s bigger than the height) or the new height (if it’s bigger than width).

$new_image_name – It’s used to set a name for the new resized image. If it’s not set a name will be assigned automatically.

$save_folder – The path to the folder where the new image will be saved. Make sure it’s writable (0777). It no folder is set the new image will show in the browser without being saved.

Here’s an example of how you can use this class:

<?php
include 'resize.image.class.php';

$image = new Resize_Image;

$image->new_width = 200;
$image->new_height = 200;

$image->image_to_resize = "/home/mysite.com/public_html/images/sunset_wallpaper.jpg"; // Full Path to the file

$image->ratio = true; // Keep Aspect Ratio?

// Name of the new image (optional) - If it's not set a new will be added automatically

$image->new_image_name = 'sunset_wallpaper_thumbnail';

/* Path where the new image should be saved. If it's not set the script will output the image without saving it */

$image->save_folder = 'thumbs/';

$process = $image->resize();

if($process['result'] && $image->save_folder)
{
echo 'The new image ('.$process['new_file_path'].') has been saved.';
}
?>

How to invoke this class to generate thumbnails in a HTML page?

This class has an advantage: you can resize images ‘on the fly’ with it. This way you don’t have to necessarily save the resized image on the server. You can just output it. Here’s how you can call this class from a HTML page without using any PHP code in it:

demo.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
 <head>
  <title> Show Resized Image </title>
  <meta name="Author" content="Bit Repository">
  <meta name="Keywords" content="src, image, resize, on the fly">
  <meta name="Description" content="Display a resized image">
 </head>
 <body>
  <img src="resize_image.php?image=sunset.jpg&new_width=200&new_height=200">
 </body>
</html>

As you can see, the resize_image.php script is called. Some info is needed to make the resize: original image (‘image’), a width (‘new_width’) and a height (‘new_height’). In many cases, if the ‘ratio aspect’ is enabled, you can specify only one measurement. The new dimensions will be calculated based on whether you choose: width or height. Here’s the resize_image.php script:

resize_image.php

<?php
set_time_limit(10000);

error_reporting(E_ALL ^ E_NOTICE);

include 'resize.image.class.php';

$resize_image = new Resize_Image;

// Folder where the (original) images are located with trailing slash at the end
$images_dir = 'images/';

// Image to resize
$image = $_GET['image'];

/* Some validation */
if(!@file_exists($images_dir.$image))
{
exit('The requested image does not exist.');
}

// Get the new with & height
$new_width = (int)$_GET['new_width'];
$new_height = (int)$_GET['new_height'];

$resize_image->new_width = $new_width;
$resize_image->new_height = $new_height;

$resize_image->image_to_resize = $images_dir.$image; // Full Path to the file

$resize_image->ratio = true; // Keep aspect ratio

$process = $resize_image->resize(); // Output image
?>

Comment via Facebook

comments

36 Replies to "Resize an Image (on the fly) & Keep its Aspect Ratio using PHP and GD"

  1. [...] The class checks if the image is already a square. If it is, it will output a message to the user. If it’s not it will calculate the necessary coordinates and crop it: to left, center or right (default is ‘center’). [...]

  2. [...] class we’re using to resize images (requires GD) doesn’t do a particularly good job of compressing the resulting images. Ideally [...]

  3. Hello,
    Use this script to resize image to differect aspect ratio:

    http://nashruddin.com/Resize_Image_to_Different_Aspect_Ratio_on_the_fly

    Nash

  4. Nice work on this. But there is one problem I found. If you choose to keep the aspect ratio but select a width and height one of which is larger than orig and other smaller than orig the logic for keeping the ratio fails. Here’s a simplification that works. Note that the logic is the same whether the new image is going to be larger or smaller.

    /* Keep Aspect Ratio? */
    if($this->ratio)
    {
    // if preserving the ratio, only new width or new height
    // is used in the computation. if both
    // are set, use width

    if (isset($this->new_width))
    {
    $factor = (float)$this->new_width / (float)$width;
    $this->new_height = $factor * $height;
    }
    else if (isset($this->new_height))
    {
    $factor = (float)$this->new_height / (float)$height;
    $this->new_width = $factor * $width;
    }
    else
    exit(“neither new height or new width has been set”);
    }

    1. Thanks, Larry! I’ve tested it and really works smoothly.

    2. i find that resizing based on the larger dimension suits my needs better:

      if($this->ratio){
      if (isset($this->new_width) and isset($this->new_height)){
      // width and height set, find the largest and resize based on that
      if($this->new_width > $this->new_height){
      // width is larger
      $factor = (float)$this->new_width / (float)$width;
      $this->new_height = $factor * $height;
      }else{
      // height is larger
      $factor = (float)$this->new_height / (float)$height;
      $this->new_width = $factor * $width;
      }
      }else if (isset($this->new_width)){
      // only width set
      $factor = (float)$this->new_width / (float)$width;
      $this->new_height = $factor * $height;
      }else if (isset($this->new_height)){
      // only height set
      $factor = (float)$this->new_height / (float)$height;
      $this->new_width = $factor * $width;
      }else{
      exit; //(“neither new height nor new width has been set”);
      }
      }

      1. oops! just realised it should be like this instead:

        // width and height set, find the largest and resize based on that
        if($width > $height){
        // width is larger

  5. Exactly what I’ve been looking for.

  6. I have one question. Is it posible to create an function and point the source to it, instead of the approach in the example?
    example:
    to use:
    <code><?php
    print "<IMG SRC=\"".resize_image(sunset.jpg,200,200)."\"">";
    ?>
    </code>
    <code>
    insead of:
    <IMG SRC="resize_image.php?image=sunset.jpg&new_width=200&new_height=200">
    </code>
    p.s.: aaaaa, this stupid code. sorry for spaming. I ask moderator to delete above posts.

  7. [...] upload, on the fly resized by PHP5 in the [...]

  8. There is an another error or additional function:

    I want to use this parameters:

    $image->new_width = 128;
    $image->new_height = 100;

    And if i upload a picture (500*500), it produces a128*128 pixel thumbinalk, but I set 100px for maximal height, so i want a 100*100px image in this case.

    Solution:

    PART ONE:

    function resize()
    {

    ##########################
    ## Mattias’s extension
    ##########################

    $eredeti_w = $this->new_width;
    $eredeti_h = $this->new_height;

    ##########################
    ## Mattias’s extension END
    ##########################

    .
    .
    .

    PART TWO:

    ##########################
    ## Mattias’s extension
    ##########################

    if($this->new_height > $eredeti_h)
    {
    $faktor = $eredeti_h / $this->new_height;
    $this->new_height = $this->new_height * $faktor;
    $this->new_width = $this->new_width * $faktor;
    }

    if($this->new_width > $eredeti_w)
    {
    $faktor = $eredeti_w / $this->new_width;
    $this->new_height = $this->new_height * $faktor;
    $this->new_width = $this->new_width * $faktor;
    }

    ##########################
    ## Mattias’s extension END
    ##########################

    // New Image
    $image_c = ImageCreateTrueColor($this->new_width, $this->new_height);
    .
    .
    .

    Only need to insert code between the comment…

    1. What he is trying to say is true. If someone tries to re-size an image it should re-size it depending on which dimension is smaller.

      The fix Mattias proposes is OK but involves to many checks. Instead, just switch the original statement of

      if($this->ratio)
      {
      ………..
      }

      with:

      if($this->ratio)
      {
      // if preserving the ratio, only new width or new height
      // is used in the computation. if both
      // are set, use width

      if (isset($this->new_width))
      {
      if (isset($this->new_height)&&($this->new_width > $this->new_height))
      {
      $factor = (float)$this->new_height / (float)$height;
      $this->new_width = $factor * $width;
      }else
      {
      $factor = (float)$this->new_width / (float)$width;
      $this->new_height = $factor * $height;
      }
      }
      else if (isset($this->new_height))
      {
      $factor = (float)$this->new_height / (float)$height;
      $this->new_width = $factor * $width;
      }
      else
      exit(‘neither new height or new width has been set’);
      }

  9. Hi,

    Perhaps my requirements are different to others, but I prefer that if I set a new_height & new_width then these numbers are essentially the maximum value I want for either dimension when maintaining aspect ratio. To achieve this I added an extra check before resizing:


    ...
    if($this->ratio)
    {
    if (isset($this->new_width) && isset($this->new_height)){
    if ($width > $height)
    {
    $factor = (float)$this->new_width / (float)$width;
    $this->new_height = $factor * $height;
    }
    else
    {
    $factor = (float)$this->new_height / (float)$height;
    $this->new_width = $factor * $width;
    }
    }
    else if (isset($this->new_width))
    {
    ...

  10. this is nice plugin i used it do we fixed the with and height.

  11. i get this error with large size image

    Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 3168 bytes)

    1. I get the same. Anyone know how to set the size limit?

  12. Would that be possibile to resize an image on a remote server using this script?

  13. Hi, thanks, that works fine, for local images.

    What would I need to do to get images from my another domain?

    I can do it with locally placed directories, e.g: ../ images but not with remote directories, e.g:
    http://www.anotherdomain.xxx/image.jpg

    Thank you,

    James R

    1. Accidentally deleted your email response, please resend, thank you!

  14. hi having problem with transparency for PNG image. Anyone else?

    Thanks

    em

  15. I think I had a similar problem as Ashley. I check to see which source image dimension exceeds the target dimensions by the biggest scale factor and set it to that. It probably could use some cleanup but it seems to do the job. I didn’t check for issues if scaling up, I only need to scale down.


    if($this->ratio) {
    if (isset($this->new_width)) {
    if (isset($this->new_height)) {
    if (($this->new_height/$height) new_width/$width)) {
    $factor = (float)$this->new_height / (float)$height;
    $this->new_width = $factor * $width;
    } else {
    $factor = (float)$this->new_width / (float)$width;
    $this->new_height = $factor * $height;
    }
    } else {
    $factor = (float)$this->new_width / (float)$width;
    $this->new_height = $factor * $height;
    }
    } else if (isset($this->new_height)) {
    $factor = (float)$this->new_height / (float)$height;
    $this->new_width = $factor * $width;
    }
    else
    exit("neither new height or new width has been set");
    }

  16. The code got messed up because of the less than angle bracket getting confused with a tag opening.

    This is the corrected conditional:

    if (($this->new_height/$height) < ($this->new_width/$width))

  17. BRAVOS and THANKS JD !
    now work !!!!!

  18. Someone was asking about images with transparency not being preserved. I was using this with transparent GIFs and the transparency was turning black. I hacked the class file to support GIF transparency. You may be able to include PNGs by including that format in the if statement. Find the first line of this code in the existing class, and paste the rest in:

    // New Image
    $image_c = ImageCreateTrueColor($this->new_width, $this->new_height);

    $new_image = $image_create_func($this->image_to_resize);

    if ($new_image_ext == “gif”) {
    $trnprt_indx = imagecolortransparent($new_image);

    // If we have a specific transparent color
    if ($trnprt_indx >= 0) {

    // Get the original image’s transparent color’s RGB values
    $trnprt_color = imagecolorsforindex($new_image, $trnprt_indx);

    // Allocate the same color in the new image resource
    $trnprt_indx = imagecolorallocate($image_c, $trnprt_color['red'], $trnprt_color['green'], $trnprt_color['blue']);

    // Completely fill the background of the new image with allocated color.
    imagefill($image_c, 0, 0, $trnprt_indx);

    // Set the background color for new image to transparent
    imagecolortransparent($image_c, $trnprt_indx);
    }
    }

  19. good stuff!!,. like it very much,. especially combined with js

  20. hi i am using your script, it works fine for smaller images, if i post larger image (4mb size) then i ll get the error:
    Fatal error: Out of memory (allocated 36438016) (tried to allocate 16112 bytes) in /

    so how can I resolve this problem?

  21. How can we get this to work with images supplied as a full url path to our other server? e.g:

    http://www.mysite.net/images/changingurl/image.jpg

    …instead of just …

    image.jpg

    Thank you :-)

  22. where I think the new code updated?

  23. I did this: ( as the imageMagick 20×30> syntax)

    if ($this->ratio) {
    if ( ($width / $height) > ($this->new_width / $this->new_height) ) {
    $this->new_height = ($height * ($this->new_width / $width));
    }
    else {
    $this->new_width = ($width * ($this->new_height / $height));
    }
    }

  24. Hi, i’m using this script for a while and returning a good result, but there is a problem when i try to upload .GIF file, the animated gif stopped(doesn’t work) when it was re-sized. any clue ?

  25. Check this one out. This is Way too simpler than the here.

    http://www.rahulkate.com/blogs/php_upload_reisze_and_trim_images_with_gd_library

    In simpler words just One line of code to upload, resize save to disk or render to browser.

    Also support generating unique names.

  26. i use a page header location loop so every time the page is refreshed is do this
    new_width = 120;
    $image->new_height = 160;

    $image->image_to_resize = $bulk;// Full Path to the file

    $image->ratio = false; // Keep Aspect Ratio?

    // Name of the new image (optional) – If it’s not set a new will be added automatically

    $image->new_image_name = $filename;

    /* Path where the new image should be saved. If it’s not set the script will output the image without saving it */

    $image->save_folder = $new_location.$category.”/thumbs/” ;

    $process = $image->resize();
    if($process['result'] && $image->save_folder)
    {
    echo ‘The new thumb (‘.$process['new_file_path'].’) has been saved.’;
    }
    but for some strange reason sometimes the logo is not generate , i have an idea to use a if for that but i need some info for you script im beginer in to php and i need dome help if it is posible the idea will be something like this
    if some var = false then insert in to sql 1 else insert in to sql 0 header location this file :P

  27. Thanks for the code.

    I want to use this script for mobile site, meaning the images (logo) would resize on the fly for any mobile phone.

    responsive layout wont support all screen sizes.

    what i want to know is how to set the generated image size based on the width or height of a mobile screen?

    as i see it, you need to define the output size for the script to generate the new image. but i want it to generate an image according to the size of the screen.

    Id have to use jQuery to get.width and use that outpu to determine the width of the php generated image (with aspect ratio on)

    Any ideas?

  28. this script is no longer work for me. and is work fine for about 2 mounts now i have big problem.
    fist pages display in blank but when i remove the include is worked.
    mai it be the host changed some thing what do you think about this ?
    and is posible to fix this sheet.

  29. I used this class file to resize my image. But I found an error to insert bmp and tif file.
    my file type is bmp and as i print $type value that was "x-ms-bmp" and for tif image the $type value was "tif" as it is not avaliavle in switch case. What to do? can anybody help me?
    Your reply will be appriciate.
    Thank you

Leave a Reply


* = required fields

  (will not be published)


XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Note: If you want to post CODE Snippets, please make them postable first!
(e.g. <br /> should be converted to &lt;br /&gt;)

POSTING RULES:

  • The comment must be relevant with the topic of the post.
  • Only comments with real email addresses will get approved. So, emails like 'abc@domain.com' will not be accepted.
  • Do not post the same message in multiple articles through the site.
  • Do not post advertisements, junk mail or pyramid schemes.
  • In case you post a link to another site, please explain briefly where the link goes as a courtesy to other users.
  • Do not post comments such as: "Thank you", "Awesome", "Nice tutorial", "Merci", etc.