PHP: How to proportionally resize an uploaded image

Big mug and tiny mug
Say you have a form where someone can upload a profile image. The uploaded image can be of any size of course, but you want all the profile images to fit inside a certain frame. You could just set the dimensions on the image tag to this size, but in most browsers that would look ugly, and it would also most likely stretch the image. It would look awful. In addition you would be serving a image which most likely was a lot larger than you wanted it to be. This would cost you bandwidth.

In this case you might want to proportionally resize the image to the appropriate size when you get it uploaded. You can then store the resized image instead and serve it directly with no problems afterwards. It doesn’t have to be difficult! Here’s how πŸ™‚

The form

To keep this ultra simple, we will just have a tiny form with one field and a submit button.

<form action="upload.php" method="post" enctype="multipart/form-data">

    <input type="file" name="image" />
    <input type="submit" value="Upload" />

Notice that the form has enctype="multipart/form-data". If it’s not, the file upload won’t work. Up next is the file which catches the uploaded data.

Processing the upload

First thing we need to do is to check that the upload went alright.

// Check if file was uploaded ok
if( ! is_uploaded_file($_FILES['image']['tmp_name']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK)
    exit('File not uploaded. Possibly too large.');

If all good, we can turn the uploaded file into an image resource.

// Create image from file
    case 'image/jpeg':
        $image = imagecreatefromjpeg($_FILES['image']['tmp_name']);
    case 'image/png':
        $image = imagecreatefrompng($_FILES['image']['tmp_name']);
    case 'image/gif':
        $image = imagecreatefromgif($_FILES['image']['tmp_name']);
        exit('Unsupported type: '.$_FILES['image']['type']);

Before we can actually resize this image, we need to figure out a couple of things. We need the size of the frame we want to fit this image into, the current size, and the size it should have to fit inside the frame without messing up its aspect ratio.

// Target dimensions
$max_width = 240;
$max_height = 180;

// Get current dimensions
$old_width  = imagesx($image);
$old_height = imagesy($image);

// Calculate the scaling we need to do to fit the image inside our frame
$scale      = min($max_width/$old_width, $max_height/$old_height);

// Get the new dimensions
$new_width  = ceil($scale*$old_width);
$new_height = ceil($scale*$old_height);

We calculate the scaling by dividing the wanted dimension with the current one. I do this for both the width and the height, and then choose the lesser of the two. This makes sure that both wide and tall images will fit into our frame. When we have the scale, we simply multiply it with the current height and width to get our new dimensions.

With that calculated, we can then create a new empty image resource and fill it with a resized copy of the original image.

// Create new empty image
$new = imagecreatetruecolor($new_width, $new_height);

// Resize old image into new
imagecopyresampled($new, $image,
    0, 0, 0, 0,
    $new_width, $new_height, $old_width, $old_height);

Where you go from here is a bit up to you. You could turn the image resource into a PNG or a JPEG and then store it as a file, in a database, or whatever you feel like. Just as an example I’ll turn it into a JPEG, catch the data in a versatile variable and output it to the browser.

First I create a JPEG image out of it and catch it using output buffering. With the data in a variable it can easily be stored in a database, dumped to a file or to the browser. If you wanted to dump it to a file, you’d probably want to swap NULL with the filename. And if you wanted to output it to the browser, you could just skip the output buffering and let the data flow to the browser freely. But, just so you can see how to catch the data in a variable, I will do it the hard way :p

// Catch the imagedata
imagejpeg($new, NULL, 90);
$data = ob_get_clean();

Next up we need to clean up after ourselves. Never forget that!

// Destroy resources

Finally we’ll set a proper content-type so the browser understands what it gets and output the data.

// Set new content-type and status code
header("Content-type: image/jpeg", true, 200);

// Output data
echo $data;

And that’s all πŸ™‚

Working sample

You can check out a working sample and complete source code at Don’t abuse it πŸ˜‰

Let me know if this was useful or if you have some ideas for improvement. Also, if I have messed up somewhere, please do let me know so I can fix it and possibly learn something new πŸ™‚

  • Drew

    Awesome!! Now how can we save the image or have it automatically upload to an FTP location or something, since it’s created with PHP?

    • Just dump the data to a file or upload it to an FTP location or something πŸ™‚

      If you want to write it to a file, you can skip the output buffering I use and just do

      imagejpeg($new, 'filename.jpg', 90);
  • phipher

    any explanation why the resizing process took so long?

    • If the resizing process takes too long, you can swap imagecopyresampled with imagecopyresized.

      It will work a lot quicker, but the result will not be as good. So, you’ll have to choose what’s most important. Quality or speed πŸ™‚

      If it’s a one time thing per upload I would probably go for quality, but totally up to what you need it for.

  • Brian

    Thanx so much,
    brilliant post nice and simple code and explanation πŸ™‚

    • You’re welcome! Thanks for the feedback πŸ™‚

      • arun

        pls send me the same with saving the file in some folder

        • Just change some change NULL to a filename when calling imagejpeg.

  • whiterabbitfcuk

    Thanks very much !

    I want a poster with your face on it so I can hero-worship you.

    • Um, thanks? But… please don’t? :p

  • Kaustubh

    The example and explanation are just awesome. Thanks for the post.

    • Thank you! Good to hear it’s helpful πŸ™‚

  • softboxkid

    how to save the catches $data into DB (Blob) ?

    • Think you would just insert it into a blob column like you would with any other kind of data. Maybe a good idea to also have a column with the mime type so you know what to serve it as when reading it back out.

      Depending on your usage, amount of images, et cetera, it might be a better idea to store them on disk though, and then store the filename instead in the database. Might be a bit easier to work with too when it comes to caching and such. Web servers are good at serving files. If you store the image data in a database, you have to sort of serve it yourself from PHP, meaning you’ll have to send correct headers and such manually.

  • Dyllan

    Nice tutorial. I would recommend a more verbose error message when attempting to upload the file. Below is an updated version of // Check if file was uploaded ok calling on ini_get and looking for PHP Error Message 1

    // Check if file was uploaded ok
    if( ! is_uploaded_file($_FILES['image']['tmp_name']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK)
        if ($_FILES['image']['error'] == 1){
        exit('File not uploaded. Exceeds Max Upload Size of ' . ini_get('upload_max_filesize'));
        exit('Error: File not uploaded.');
    • Well, the point here wasn’t really the uploading, but the proportional resizing of the image afterwards πŸ˜› But, yes, that is indeed a very important thing to have if you have a page where users can upload images. Having them wait for an upload, which fails, and tell them nothing about what happened, is not very user friendly πŸ˜‰

  • santiago

    Excellent tutorial, how could upload images with transparency?

    Busque bastante y este es el ΓΊnico tutorial que me sirviΓ³, en realidad muy bueno.

    Saludos desde Cuenca-Ecuador… Thanks…

    • Good question. Made me curious! Shouldn’t be impossible, so will try to figure that out and merge it into here πŸ™‚

      • Niels

        Did you ever work this out? Would like to upload transparant PNG’s or GIF’s as well πŸ™‚

        • Ah, sorry, never got around to it unfortunately. Maybe you could do some research on it? If you do, let me know about your findings, cause I’m still curious πŸ™‚

  • ian

    trying to run this offline so i can understand this code very new to this, but it seems i need a config file, which is not in the source????

  • James McMinn

    Thanks! Your a legend.

  • James McMinn

    Is there anyway that the image dimensions can be removed from the ?

    • James McMinn

      From the title?

      • Removed from the title? What do you mean?

        • James McMinn

          When the image is resized and displayed, up the in navigation area where the page title is it displays the new dimension

          • Might be the browser doing that. I get those dimensions in the browser title in Opera, but not in IE.

  • Oneill

    I have a upload code, but looking for a way to integrate your image resize code, can you please help πŸ™‚

    Here is my code:

    $uploaddir = '../_gallery/';
    $uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
    move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile);

    If you can it would be highly appreciated πŸ™‚

    • Can’t help you much, but you mostly just have to provide a file name instead of NULL when creating the image file in the end.

      imagejpeg($new, 'gallery/filename.jpeg', 90);
  • aaa

    Its not good for transparent images…

    • No, for that you’d first of all have to create an image which supports it, which jpeg doesn’t. So you’d have to use the imagepng function or whatever it’s called. Might have do do some other special calls as well. Never got around to test that out.

  • jaimin vaja

    Nice tutorial!

  • Kevin Delgado

    Great tutorial! I was wondering, though, is it also necessary to do anything to purge the old image from the temporary directory, or is that automatic?

    Also, you might add a note that you can NOT use imagejpeg to create a new file if PHP’s safe mode is enabled.

    • I think temporary files are removed automatically, but you can always test it out πŸ™‚

    • Think tmp files are cleaned out automatically at the end of scripts, but check out the docs if you want to be sure. About safemode I can’t really say I care enough about it to even mention it :p



  • nancy

    nice……..but i want to save that resized image in my folder

    • Just give the imagejpeg function a filename rather than NULL (and obviously skip the ob_get_clean, header and echo stuff). Check out the PHP docs for examples.

  • A+

  • Thanks a lot! I got it to save by just proving an image name in the imagejpeg() function. I’m gonna try adding PNG support though since converting to JPEG can mess some images up sometimes. πŸ™‚

    • Yeah, if you upload a PNG with transparency it definitely won’t look great if you convert it to JPEG πŸ˜‰ Let me know if you figure out how to do it well with PNG. I’d be interested to know πŸ™‚

  • binil john

    can you resize 1600×1200 to 961×516 with these calculation?

    • Set max width to 961 and max height 516. This will resize it proportionally to fit within a frame that size. If you want to force it to be exactly 961 by 516, then just resize directly to that size without the scaling stuff.

  • Larry

    Love the script. It does what it should. However . . . when the resized image is displayed in the browser, and I go to save it, the file name always comes up as “upload.php”. I played around with it some, and got it to display “upload.php.jpg”. But either way, it was not the resized image. Any suggestions to be able to right click and save as an image. This is the whole purpose for my use for it. Appreciate any help or suggestions.

    • You can try to set the disposition header which should work when someone clicks on the link, but not sure it works when you do the right-click stuff.

      header('Content-Disposition: attachment; filename="'.$name.'.txt"');

      Otherwise I suppose you can do something with URL rewriting, if you’re using that, or you can always just name the script file ‘upload.jpg’ and tell your web server that its actually PHP (through an .htaccess file if you’re using Apache).

  • Totor

    Here a simple class using GD to resize easily images in 1 method !

  • kiwiplayer

    Excellent tutorial – very easy to follow, and does exactly what it says on the tin (now all I’ve got to do is figure out how to compress images to reduce bandwidth) Thanks a lot!

    • Just remember to cache the result so that you’re not recompressing the images on every single request.

  • Auke

    Hi, I was wondering how to use this script if you want to load image path from a table in a mysql database? Anyone?

    • Just swap $_FILES[‘image’][‘tmp_name’] with the path you got from your database and instead of getting the file type from $_FILES[‘image’][‘type’] you should use the getimagesize function to figure out which imagecreate function you should use.

  • Reiko

    Nice! Thanks a lot!!!
    But… How can I upload the image in a directory?

    • The file is already uploaded to a tmp directory. The path to it is $_FILES[‘image’][‘tmp_name’], as you should see in the code. So either move the file from there to wherever you want it, or save the resized one there. You should find what you need to do that in the PHP docs or

  • Gatis

    This script upload and resize image. Select your image and image will resize to 200×200 px and 50×50 px

  • pixel

    give binary value of $data please help

  • PaoLdP

    This.. i really need to thank you for this. Looked for days to get this started, and you are the only one who explained it in “English”, without all the mambo-jumbo and covered stuffs that should be known first before moving to the more advance stuffs. Kudos for this

  • dc

    i cannot see the source code… ;-(

  • Swortle

    Very good tuto, i was wondering, does it work if i upload a jpg file and not a jpeg one ?

    Does the function imagecreatefromjpeg works with jpg file ?
    Thks in advance πŸ™‚

    • Filenames doesn’t matter at all really. It’s the content that matters. As far as I know the only difference between jpg and jpeg is just that, the file extension. Just like html and htm. Usually same type of content, just different extension.

      I think you can use the getimagesize function to get the actual type of image, irregardless of name (

  • Swortle

    Do u know how to make the background image identifier created by imagetruecolor transparent? because i try your upload sample and if i upload a white photo background, the background is logically black, as imagetrucolor returns a black image color….
    Have you any idea on that subject,i’m interested πŸ™‚

    • The default color is probably black since that’s 0. So if you want it to be white I guess you’d just have to fill the image with white before you do the resized copy. So right after the imagecreatetruecolor line do for example

      imagefill($new, 0, 0, imagecolorallocate($new, 255, 255, 255));

      Which should fill it with white. Untested, so let me know how it goes πŸ™‚

      As with transparency I haven’t looked into that, but if you google php image transparency you find a function called imagecolortransparent which might be of interest. You’d probably have to save the image as gif or something though and not jpeg. As for real transparency (non-binary) you’d have to use PNG and such. Some googling should help you get started there as well.