Search code examples
phpgd

How to maintain aspect ratio while resizing the uploaded image


I have a problem statement that requires maintaining aspect ratio of uploaded image.

When a photo is uploaded, you will need to create three sizes, a) 310X230 (Thumnail) b) 960X400 (Detail Image) c) Original Size (Full Image) The sizes will be created with exact dimensions. If a photo is not in equal aspect ratio of any of the size, then scale to that size, and crop the extra portion.

I have achieved to upload image with 3 different sizes using php GD library with the code below

    if($_SERVER["REQUEST_METHOD"] == "POST")
 {
    $image =$_FILES["file"]["name"];
    $uploadedfile = $_FILES['file']['tmp_name'];


    if ($image) 
    {

        $filename = stripslashes($_FILES['file']['name']);

        $extension = getExtension($filename);
        $extension = strtolower($extension);


 if (($extension != "jpg") && ($extension != "jpeg") && ($extension != "png") && ($extension != "gif")) 
        {

            $change='<div class="msgdiv">Unknown Image extension </div> ';
            $errors=1;
        }
        else
        {

 $size=filesize($_FILES['file']['tmp_name']);


if ($size > MAX_SIZE*1024)
{
    $change='<div class="msgdiv">You have exceeded the size limit!</div> ';
    $errors=1;
}


if($extension=="jpg" || $extension=="jpeg" )
{
$uploadedfile = $_FILES['file']['tmp_name'];
$src = imagecreatefromjpeg($uploadedfile);

}
else if($extension=="png")
{
$uploadedfile = $_FILES['file']['tmp_name'];
$src = imagecreatefrompng($uploadedfile);

}
else 
{
$src = imagecreatefromgif($uploadedfile);
}

//echo $src;

list($width,$height)=getimagesize($uploadedfile);


$newwidth=$width;
$newheight=($height/$width)*$newwidth;
$tmp=imagecreatetruecolor($newwidth,$newheight);


$newwidth1=310;
$newheight1=230;
$tmp1=imagecreatetruecolor($newwidth1,$newheight1);


$newwidth2=960;
$newheight2=400;
$tmp2=imagecreatetruecolor($newwidth2,$newheight2);

imagecopyresampled($tmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);

imagecopyresampled($tmp1,$src,0,0,0,0,$newwidth1,$newheight1,$width,$height);

imagecopyresampled($tmp2,$src,0,0,0,0,$newwidth2,$newheight2,$width,$height);

$filename = "images/medium/". $_FILES['file']['name'];

$filename1 = "images/thumbnail/small". $_FILES['file']['name'];

$filename2 = "images/full/". $_FILES['file']['name'];


imagejpeg($tmp,$filename,100);

imagejpeg($tmp1,$filename1,100);

imagejpeg($tmp2,$filename2,100);

imagedestroy($src);
imagedestroy($tmp);
imagedestroy($tmp1);
imagedestroy($tmp2);
}}

}

Solution

  • It is quite complicated to both resize and crop multiple images, but here's a solution that might work for you:

     if($_SERVER["REQUEST_METHOD"] == "POST"){
        $image =$_FILES["file"]["name"];
        $uploadedfile = $_FILES['file']['tmp_name'];
    
        if($image){
            $filename = stripslashes($_FILES['file']['name']);
            $extension = getExtension($filename);
            $extension = strtolower($extension);
    
            if(($extension != "jpg") && ($extension != "jpeg") && ($extension != "png") && ($extension != "gif")) {
                $change='<div class="msgdiv">Unknown Image extension </div> ';
                $errors=1;
            } else {
                $size=filesize($_FILES['file']['tmp_name']);
    
                if($size > MAX_SIZE*1024){
                    $change='<div class="msgdiv">You have exceeded the size limit!</div> ';
                    $errors=1;
                }
    
                if($extension=="jpg" || $extension=="jpeg" ) {
                    $uploadedfile = $_FILES['file']['tmp_name'];
                    $src = imagecreatefromjpeg($uploadedfile);
                } else if($extension=="png"){
                    $uploadedfile = $_FILES['file']['tmp_name'];
                    $src = imagecreatefrompng($uploadedfile);
                } else {
                    $src = imagecreatefromgif($uploadedfile);
                }
    
    
            list($width,$height)=getimagesize($uploadedfile);
    
            /* ORIGINAL ASPECT RATIO */     
            $original_aspect_ratio = $width / $height;
    
            /* RESIZE AND CROP THUMBNAIL (MEDIUM SIZE) */
            $new_width = 960; // SET DESIRED WIDTH
            $new_height = 400; // SET DESIRED HEIGHT    
            $new_aspect_ratio = $new_width / $new_height;
    
            if ($original_aspect_ratio > $new_aspect_ratio) {
                /* source image is wider */
                $temp_height = $new_height;
                $temp_width = (int) ($new_height * $original_aspect_ratio);
            } else {
                /* source image is similar or taller */
                $temp_width = $new_width;
                $temp_height = (int) ($new_width / $original_aspect_ratio);
            }
    
            /* Resize to a temporary GD image */
            $temp = imagecreatetruecolor($temp_width, $temp_height);
            imagecopyresampled($temp,$src,0,0,0,0,$temp_width,$temp_height,$width,$height);
    
            /* Copy cropped region from temporary image into the desired GD image */
            $x0 = ($temp_width - $new_width) / 2;
            $y0 = ($temp_height - $new_height) / 2;
            $medium = imagecreatetruecolor($new_width, $new_height);
            imagecopy($medium,$temp,0,0,$x0,$y0,$new_width,$new_height);
    
            /* SAVE TO FILE AND CLEAN UP */
            imagedestroy($temp);// CLEANUP TEMP IMAGE
            $medium_filename = "images/medium/". $_FILES['file']['name'];
            imagejpeg($medium,$medium_filename,100);
            imagedestroy($medium);
    
            /* RESIZE AND CROP SMALL IMAGES, SAME PROCEDURE AS ABOVE */
            $new_width = 310; // SET DESIRED WIDTH
            $new_height = 230; // SET DESIRED HEIGHT    
            $new_aspect_ratio = $new_width / $new_height;
    
            if ($original_aspect_ratio > $new_aspect_ratio) {
                $temp_height = $new_height;
                $temp_width = (int) ($new_height * $original_aspect_ratio);
            } else {
                $temp_width = $new_width;
                $temp_height = (int) ($new_width / $original_aspect_ratio);
            }
    
            $temp = imagecreatetruecolor($temp_width, $temp_height);
            imagecopyresampled($temp,$src,0,0,0,0,$temp_width,$temp_height,$width,$height);
    
            $x0 = ($temp_width - $new_width) / 2;
            $y0 = ($temp_height - $new_height) / 2;
            $small = imagecreatetruecolor($new_width, $new_height);
            imagecopy($small,$temp,0,0,$x0,$y0,$new_width,$new_height);
    
            /* SAVE TO FILE AND CLEAN UP */
            imagedestroy($temp);// CLEANUP TEMP IMAGE
            $small_filename = "images/thumbnail/small". $_FILES['file']['name'];
            imagejpeg($small,$small_filename,100);
            imagedestroy($small);
    
    
            /* ORIGINAL SIZE. NO RESIZING OR CROPPING... NOT NEEDED? YOU DECIDE... */           
            $full=imagecreatetruecolor($width,$height);
            imagecopyresampled($full,$src,0,0,0,0,$width,$height,$width,$height);
    
            /* SAVE TO FILE AND CLEAN UP */
            $full_filename = "images/full/". $_FILES['file']['name']; // ORIGINAL
            imagejpeg($full,$full_filename,100);
            imagedestroy($full);
    
            imagedestroy($src); // CLEAN UP ORIGINAL SOURCE FILE
    
            }
        }
    }
    

    The code is not tested and mainly inspired from this blog post: http://salman-w.blogspot.se/2009/04/crop-to-fit-image-using-aspphp.html

    It is a lot of repeating code in my suggested solution since you have multiple images. You could consider to chunk some of the repeated code into smaller reusable functions, for instance the calculation of aspect ratio for the different images.