Scale Image Using PHP and Maintaining Aspect Ratio

前端 未结 10 1910
孤独总比滥情好
孤独总比滥情好 2020-11-30 07:38

Basically I want to upload an image (which i\'ve sorted) and scale it down to certain constraints such as max width and height but maintain the aspect ratio of the original

相关标签:
10条回答
  • 2020-11-30 08:07

    Formule is wrong for keeping aspect ratio. It should be: original height / original width x new width = new height

    function createThumbnail($imageName,$newWidth,$newHeight,$uploadDir,$moveToDir)
    {
        $path = $uploadDir . '/' . $imageName;
    
        $mime = getimagesize($path);
    
        if($mime['mime']=='image/png'){ $src_img = imagecreatefrompng($path); }
        if($mime['mime']=='image/jpg'){ $src_img = imagecreatefromjpeg($path); }
        if($mime['mime']=='image/jpeg'){ $src_img = imagecreatefromjpeg($path); }
        if($mime['mime']=='image/pjpeg'){ $src_img = imagecreatefromjpeg($path); }
    
        $old_x = imageSX($src_img);
        $old_y = imageSY($src_img);
    
        if($old_x > $old_y)
        {
            $thumb_w    =   $newWidth;
            $thumb_h    =   $old_y/$old_x*$newWidth;
        }
    
        if($old_x < $old_y)
        {
            $thumb_w    =   $old_x/$old_y*$newHeight;
            $thumb_h    =   $newHeight;
        }
    
        if($old_x == $old_y)
        {
            $thumb_w    =   $newWidth;
            $thumb_h    =   $newHeight;
        }
    
        $dst_img        =   ImageCreateTrueColor($thumb_w,$thumb_h);
    
        imagecopyresampled($dst_img,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y);
    
    
        // New save location
        $new_thumb_loc = $moveToDir . $imageName;
    
        if($mime['mime']=='image/png'){ $result = imagepng($dst_img,$new_thumb_loc,8); }
        if($mime['mime']=='image/jpg'){ $result = imagejpeg($dst_img,$new_thumb_loc,80); }
        if($mime['mime']=='image/jpeg'){ $result = imagejpeg($dst_img,$new_thumb_loc,80); }
        if($mime['mime']=='image/pjpeg'){ $result = imagejpeg($dst_img,$new_thumb_loc,80); }
    
        imagedestroy($dst_img);
        imagedestroy($src_img);
        return $result;
    }
    
    0 讨论(0)
  • 2020-11-30 08:10

    Actually the accepted solution it is not the correct solution. The reason is simple: there will be cases when the ratio of the source image and the ratio of the destination image will be different. Any calculation should reflect this difference.

    Please note the relevant lines from the example given on PHP.net website:

    $ratio_orig = $width_orig/$height_orig;
    
    if ($width/$height > $ratio_orig) {
       $width = $height*$ratio_orig;
    } else {
       $height = $width/$ratio_orig;
    }
    

    The full example may be found here: http://php.net/manual/en/function.imagecopyresampled.php

    There are other answers (with examples) on stackoverflow to similar questions (the same question formulated in a different manner) that suffer of the same problem.

    Example:

    Let's say we have an image of 1630 x 2400 pixels that we want to be auto resized keeping the aspect ratio to 160 x 240. Let's do some math taking the accepted solution:

    if($old_x < $old_y) 
        {
            $thumb_w    =   $old_x*($new_width/$old_y);
            $thumb_h    =   $new_height;
        }
    

    height = 240 width = 1630 * ( 160/2400 ) = 1630 * 0.0666666666666667 = 108.6666666666667 108.6 x 240 it's not the correct solution.

    The next solution proposed is the following:

    if($old_x < $old_y)
        {
            $thumb_w    =   $old_x/$old_y*$newHeight;
            $thumb_h    =   $newHeight;
        }
    

    height = 240; width = 1630 / 2400 * 240 = 163 It is better (as it maintain the aspect ratio), but it exceeded the maximum accepted width.

    Both fail.

    We do the math according to the solution proposed by PHP.net: width = 160 height = 160/(1630 / 2400) = 160/0.6791666666666667 = 235.5828220858896 (the else clause). 160 x 236 (rounded) is the correct answer.

    0 讨论(0)
  • 2020-11-30 08:16

    Here is a comprehensive application that I worked hard on it to include most common operations like scale up & scale down, thumbnail, preserve aspect ratio, convert file type, change quality/file size and more...

    <?php
    //##// Resize (and convert) image (Scale up & scale down, thumbnail, preserve aspect ratio) //##//
    ///////////////////////////////////////////////
    ///////////////// Begin.Setup /////////////////
    // Source File:
    $src_file = "/your/server/path/to/file.png";// png or jpg files only
    
    // Resize Dimensions:
    // leave blank for no size change (convert only)
    // if you specify one dimension, the other dimension will be calculated according to the aspect ratio
    // if you specify both dimensions system will take care of it depending on the actual image size 
    // $newWidth = 2000;
    // $newHeight = 1500;
    
    // Destination Path: (optional, if none: download image)
    $dst_path = "/your/server/path/new/";
    
    // Destination File Name: (Leave blank for same file name)
    // $dst_name = 'image_name_only_no_extension';
    
    // Destination File Type: (Leave blank for same file extension)
    // $dst_type = 'png';
    $dst_type = 'jpg';
    
    // Reduce to 8bit - 256 colors (Very low quality but very small file & transparent PNG. Only for thumbnails!)
    // $palette_8bit = true;
    
    ///////////////// End.Setup /////////////////
    ///////////////////////////////////////////////
    if (!$dst_name){$dst_name = strtolower(pathinfo($src_file, PATHINFO_FILENAME));}
    if (!$dst_type){$dst_type = strtolower(pathinfo($src_file, PATHINFO_EXTENSION));}
    if ($palette_8bit){$dst_type = 'png';}
    if ($dst_path){$dst_file = $dst_path . $dst_name . '.' . $dst_type;}
    
    $mime = getimagesize($src_file);// Get image dimensions and type
    
    // Destination File Parameters:
    if ($dst_type == 'png'){
        $dst_content = 'image/png';
        $quality = 9;// All same quality! 0 too big file // 0(no comp.)-9 (php default: 6)
    } elseif ($dst_type == 'jpg'){
        $dst_content = 'image/jpg';
        $quality = 85;// 30 Min. 60 Mid. 85 Cool. 90 Max. (100 Full) // 0-100 (php default: 75)
    } else {
        exit('Unknown Destination File Type');
    }
    
    // Source File Parameters:
    if ($mime['mime']=='image/png'){$src_img = imagecreatefrompng($src_file);}
    elseif ($mime['mime']=='image/jpg'){$src_img = imagecreatefromjpeg($src_file);}
    elseif ($mime['mime']=='image/jpeg'){$src_img = imagecreatefromjpeg($src_file);}
    elseif ($mime['mime']=='image/pjpeg'){$src_img = imagecreatefromjpeg($src_file);}
    else {exit('Unknown Source File Type');}
    
    // Define Dimensions:
    $old_x = imageSX($src_img);
    $old_y = imageSY($src_img);
    
    if ($newWidth AND $newHeight){
        if($old_x > $old_y){
            $new_x    =   $newWidth;
            $new_y    =   $old_y / $old_x * $newWidth;
        } elseif($old_x < $old_y){
            $new_y    =   $newHeight;
            $new_x    =   $old_x / $old_y * $newHeight;
        } elseif($old_x == $old_y){
            $new_x    =   $newWidth;
            $new_y    =   $newHeight;
        }
    } elseif ($newWidth){
        $new_x    =   $newWidth;
        $new_y    =   $old_y / $old_x * $newWidth;
    } elseif ($newHeight){
        $new_y    =   $newHeight;
        $new_x    =   $old_x / $old_y * $newHeight;
    } else {
        $new_x    =   $old_x;
        $new_y    =   $old_y;
    }
    
    $dst_img = ImageCreateTrueColor($new_x, $new_y);
    
    if ($palette_8bit){//////// Reduce to 8bit - 256 colors ////////
        $transparent = imagecolorallocatealpha($dst_img, 255, 255, 255, 127); 
        imagecolortransparent($dst_img, $transparent);
        imagefill($dst_img, 0, 0, $transparent);
        imagecopyresampled($dst_img,$src_img,0,0,0,0,$new_x,$new_y,$old_x,$old_y);// Great quality resize.
        imagetruecolortopalette($dst_img, false, 255);
        imagesavealpha($dst_img, true);
    } else {
        // Check image and set transparent for png or white background for jpg
        if ($dst_type == 'png'){
            imagealphablending($dst_img, false);
            imagesavealpha($dst_img, true);
            $transparent = imagecolorallocatealpha($dst_img, 255, 255, 255, 127);
            imagefilledrectangle($dst_img, 0, 0, $new_x, $new_y, $transparent);
        } elseif ($dst_type == 'jpg'){
            $white = imagecolorallocate($dst_img, 255, 255, 255);
            imagefilledrectangle($dst_img, 0, 0, $new_x, $new_y, $white);
        }
    
        imagecopyresampled($dst_img,$src_img,0,0,0,0,$new_x,$new_y,$old_x,$old_y);// Great quality resize.
    }
    
    // Skip the save to parameter using NULL, then set the quality; imagejpeg($dst_img);=> Default quality
    if ($dst_file){
        if ($dst_type == 'png'){
            imagepng($dst_img, $dst_file, $quality);
        } elseif ($dst_type == 'jpg'){
            imagejpeg($dst_img, $dst_file, $quality);
        }
    } else {
        header('Content-Disposition: Attachment;filename=' . $dst_name . '.' . $dst_type);// comment this line to show image in browser instead of download
        header('Content-type: ' . $dst_content);
        if ($dst_type == 'png'){
            imagepng($dst_img, NULL, $quality);
        } elseif ($dst_type == 'jpg'){
            imagejpeg($dst_img, NULL, $quality);
        }
    }
    imagedestroy($src_img);
    imagedestroy($dst_img);
    //##// END : Resize image (Scale Up & Down) (thumbnail, bigger image, preserve aspect ratio) END //##//
    
    0 讨论(0)
  • 2020-11-30 08:23

    This is my function to scale an image with save aspect ration for X, Y or both axes.

    It's also scales an image for percent of it size.

    Compatibe with PHP 5.4

    /** Use X axis to scale image. */
    define('IMAGES_SCALE_AXIS_X', 1);
    /** Use Y axis to scale image. */
    define('IMAGES_SCALE_AXIS_Y', 2);
    /** Use both X and Y axes to calc image scale. */
    define('IMAGES_SCALE_AXIS_BOTH', IMAGES_SCALE_AXIS_X ^ IMAGES_SCALE_AXIS_Y);
    /** Compression rate for JPEG image format. */
    define('JPEG_COMPRESSION_QUALITY', 90);
    /** Compression rate for PNG image format. */
    define('PNG_COMPRESSION_QUALITY', 9);
    
    /**
     * Scales an image with save aspect ration for X, Y or both axes.
     *
     * @param string $sourceFile Absolute path to source image.
     * @param string $destinationFile Absolute path to scaled image.
     * @param int|null $toWidth Maximum `width` of scaled image.
     * @param int|null $toHeight Maximum `height` of scaled image.
     * @param int|null $percent Percent of scale of the source image's size.
     * @param int $scaleAxis Determines how of axis will be used to scale image.
     *
     * May take a value of {@link IMAGES_SCALE_AXIS_X}, {@link IMAGES_SCALE_AXIS_Y} or {@link IMAGES_SCALE_AXIS_BOTH}.
     * @return bool True on success or False on failure.
     */
    function scaleImage($sourceFile, $destinationFile, $toWidth = null, $toHeight = null, $percent = null, $scaleAxis = IMAGES_SCALE_AXIS_BOTH) {
        $toWidth = (int)$toWidth;
        $toHeight = (int)$toHeight;
        $percent = (int)$percent;
        $result = false;
    
        if (($toWidth | $toHeight | $percent)
            && file_exists($sourceFile)
            && (file_exists(dirname($destinationFile)) || mkdir(dirname($destinationFile), 0777, true))) {
    
            $mime = getimagesize($sourceFile);
    
            if (in_array($mime['mime'], ['image/jpg', 'image/jpeg', 'image/pjpeg'])) {
                $src_img = imagecreatefromjpeg($sourceFile);
            } elseif ($mime['mime'] == 'image/png') {
                $src_img = imagecreatefrompng($sourceFile);
            }
    
            $original_width = imagesx($src_img);
            $original_height = imagesy($src_img);
    
            if ($scaleAxis == IMAGES_SCALE_AXIS_BOTH) {
                if (!($toWidth | $percent)) {
                    $scaleAxis = IMAGES_SCALE_AXIS_Y;
                } elseif (!($toHeight | $percent)) {
                    $scaleAxis = IMAGES_SCALE_AXIS_X;
                }
            }
    
            if ($scaleAxis == IMAGES_SCALE_AXIS_X && $toWidth) {
                $scale_ratio = $original_width / $toWidth;
            } elseif ($scaleAxis == IMAGES_SCALE_AXIS_Y && $toHeight) {
                $scale_ratio = $original_height / $toHeight;
            } elseif ($percent) {
                $scale_ratio = 100 / $percent;
            } else {
                $scale_ratio_width = $original_width / $toWidth;
                $scale_ratio_height = $original_height / $toHeight;
    
                if ($original_width / $scale_ratio_width < $toWidth && $original_height / $scale_ratio_height < $toHeight) {
                    $scale_ratio = min($scale_ratio_width, $scale_ratio_height);
                } else {
                    $scale_ratio = max($scale_ratio_width, $scale_ratio_height);
                }
            }
    
            $scale_width = $original_width / $scale_ratio;
            $scale_height = $original_height / $scale_ratio;
    
            $dst_img = imagecreatetruecolor($scale_width, $scale_height);
    
            imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $scale_width, $scale_height, $original_width, $original_height);
    
            if (in_array($mime['mime'], ['image/jpg', 'image/jpeg', 'image/pjpeg'])) {
                $result = imagejpeg($dst_img, $destinationFile, JPEG_COMPRESSION_QUALITY);
            } elseif ($mime['mime'] == 'image/png') {
                $result = imagepng($dst_img, $destinationFile, PNG_COMPRESSION_QUALITY);
            }
    
            imagedestroy($dst_img);
            imagedestroy($src_img);
        }
    
        return $result;
    }
    

    Tests:

    $sourceFile = '/source/file.jpg'; // Original size: 672x100
    $destinationPath = '/destination/path/';
    
    scaleImage($sourceFile, $destinationPath . 'file_original_size.jpg', 672, 100);
    // Result: Image 672x100
    scaleImage($sourceFile, $destinationPath . 'file_scaled_75_PERCENT.jpg', null, null, 75);
    // Result: Image 504x75
    scaleImage($sourceFile, $destinationPath . 'file_scaled_336_X.jpg', 336, null, null, IMAGES_SCALE_AXIS_X);
    // Result: Image 336x50
    scaleImage($sourceFile, $destinationPath . 'file_scaled_50_Y.jpg', null, 50, null, IMAGES_SCALE_AXIS_Y);
    // Result: Image 336x50
    scaleImage($sourceFile, $destinationPath . 'file_scaled_500x70_BOTH.jpg', 500, 70, null, IMAGES_SCALE_AXIS_BOTH);
    // Result: Image 470x70
    scaleImage($sourceFile, $destinationPath . 'file_scaled_450x70_BOTH.jpg', 450, 70, null, IMAGES_SCALE_AXIS_BOTH);
    // Result: Image 450x66
    scaleImage($sourceFile, $destinationPath . 'file_scaled_500x70_40_PERCENT_BOTH.jpg', 500, 70, 40, IMAGES_SCALE_AXIS_BOTH);
    // Result: Image 268x40
    
    0 讨论(0)
  • 2020-11-30 08:24

    I know you are looking for a divisor that will allow resize your image proportionally. Check this demo

    How to get our divisor mathematically

    lets assume our original image has width x and height y; x=300 and y = 700

    Maximum height and maximum width is 200;

    First, we will check which dimension of the image is greater than the other. Our height (y) is greater than width(x)

    Secondly, we check if our height is greater than our maximum height. For our case, our height is greater than the maximum height. In a case where it less that the maximum height, we set our new height to our original height.

    Finally, we look for our divisor as shown below

    if y is set to maximum height 200 and max-y=200;
    y=max-y, that is 
    if y=max-y
    what about 
    x=?
    that is, 
    if 700 is resized to 200
    what about 300?
    700=200
    300=?
    new width = (200 (new height) * 300(width)) / 700 (height)
    so our divisor is
    divisor= new height (300) / height(700) 
    new width = divisor * width or width / (1/divisor)
    

    and vice versa for the width if it greater than height

    if ($width > $height) {
        if($width < $max_width)
            $newwidth = $width;
    
        else
    
        $newwidth = $max_width; 
    
    
        $divisor = $width / $newwidth;
        $newheight = floor( $height / $divisor);
    }
    else {
    
         if($height < $max_height)
             $newheight = $height;
         else
             $newheight =  $max_height;
    
        $divisor = $height / $newheight;
        $newwidth = floor( $width / $divisor );
    }
    

    See the full example and try it using the working demo .

    0 讨论(0)
  • 2020-11-30 08:25

    I found a mathematical way to get this job done

    Github repo - https://github.com/gayanSandamal/easy-php-image-resizer

    Live example - https://plugins.nayague.com/easy-php-image-resizer/

    <?php
    //path for the image
    $source_url = '2018-04-01-1522613288.PNG';
    
    //separate the file name and the extention
    $source_url_parts = pathinfo($source_url);
    $filename = $source_url_parts['filename'];
    $extension = $source_url_parts['extension'];
    
    //define the quality from 1 to 100
    $quality = 10;
    
    //detect the width and the height of original image
    list($width, $height) = getimagesize($source_url);
    $width;
    $height;
    
    //define any width that you want as the output. mine is 200px.
    $after_width = 200;
    
    //resize only when the original image is larger than expected with.
    //this helps you to avoid from unwanted resizing.
    if ($width > $after_width) {
    
        //get the reduced width
        $reduced_width = ($width - $after_width);
        //now convert the reduced width to a percentage and round it to 2 decimal places
        $reduced_radio = round(($reduced_width / $width) * 100, 2);
    
        //ALL GOOD! let's reduce the same percentage from the height and round it to 2 decimal places
        $reduced_height = round(($height / 100) * $reduced_radio, 2);
        //reduce the calculated height from the original height
        $after_height = $height - $reduced_height;
    
        //Now detect the file extension
        //if the file extension is 'jpg', 'jpeg', 'JPG' or 'JPEG'
        if ($extension == 'jpg' || $extension == 'jpeg' || $extension == 'JPG' || $extension == 'JPEG') {
            //then return the image as a jpeg image for the next step
            $img = imagecreatefromjpeg($source_url);
        } elseif ($extension == 'png' || $extension == 'PNG') {
            //then return the image as a png image for the next step
            $img = imagecreatefrompng($source_url);
        } else {
            //show an error message if the file extension is not available
            echo 'image extension is not supporting';
        }
    
        //HERE YOU GO :)
        //Let's do the resize thing
        //imagescale([returned image], [width of the resized image], [height of the resized image], [quality of the resized image]);
        $imgResized = imagescale($img, $after_width, $after_height, $quality);
    
        //now save the resized image with a suffix called "-resized" and with its extension. 
        imagejpeg($imgResized, $filename . '-resized.'.$extension);
    
        //Finally frees any memory associated with image
        //**NOTE THAT THIS WONT DELETE THE IMAGE
        imagedestroy($img);
        imagedestroy($imgResized);
    }
    ?>
    
    0 讨论(0)
提交回复
热议问题