使用 PHP 缩放图像并保持纵横比

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16774521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 11:41:14  来源:igfitidea点击:

Scale Image Using PHP and Maintaining Aspect Ratio

phpimagescale

提问by Steve_M

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 image.

基本上我想上传一个图像(我已经排序)并将其缩小到某些限制,例如最大宽度和高度,但保持原始图像的纵横比。

I don't have Imagick installed on the server - otherwise this would be easy.

我没有在服务器上安装 Imagick - 否则这很容易。

Any help is appreciated as always. Thanks.

一如既往地感谢任何帮助。谢谢。

EDIT: I don't need the whole code or anything, just a push in the right direction would be fantastic.

编辑:我不需要整个代码或任何东西,只要朝着正确的方向推动就会很棒。

采纳答案by Phil Cross

I had written a peice of code like this for another project I've done. I've copied it below, might need a bit of tinkering! (It does required the GD library)

我为我完成的另一个项目编写了一段这样的代码。我在下面复制了它,可能需要一些修补!(它确实需要 GD 库)

These are the parameters it needs:

这些是它需要的参数:

$image_name - Name of the image which is uploaded
$new_width - Width of the resized photo (maximum)
$new_height - Height of the resized photo (maximum)
$uploadDir - Directory of the original image
$moveToDir - Directory to save the resized image

It will scale down or up an image to the maximum width or height

它会将图像缩小或放大到最大宽度或高度

function createThumbnail($image_name,$new_width,$new_height,$uploadDir,$moveToDir)
{
    $path = $uploadDir . '/' . $image_name;

    $mime = getimagesize($path);

    if($mime['mime']=='image/png') { 
        $src_img = imagecreatefrompng($path);
    }
    if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $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    =   $new_width;
        $thumb_h    =   $old_y*($new_height/$old_x);
    }

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

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

    $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 . $image_name;

    if($mime['mime']=='image/png') {
        $result = imagepng($dst_img,$new_thumb_loc,8);
    }
    if($mime['mime']=='image/jpg' || $mime['mime']=='image/jpeg' || $mime['mime']=='image/pjpeg') {
        $result = imagejpeg($dst_img,$new_thumb_loc,80);
    }

    imagedestroy($dst_img); 
    imagedestroy($src_img);

    return $result;
}

回答by Florin Sima

Actually the accepted solution it is notthe 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:

请注意 PHP.net 网站上给出的示例中的相关行:

$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

完整的例子可以在这里找到: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.

在 stackoverflow 上还有其他类似问题(以不同方式制定的同一问题)的其他答案(带有示例),这些问题遇到了相同的问题。

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:

假设我们有一张 1630 x 2400 像素的图像,我们希望自动调整大小并保持纵横比为 160 x 240。让我们用公认的解决方案做一些数学计算:

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.

高度 = 240 宽度 = 1630 * ( 160/2400 ) = 1630 * 0.0666666666666667 = 108.6666666666667 108.6 x 240 这不是正确的解决方案。

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.

高度 = 240;width = 1630 / 2400 * 240 = 163 更好(因为它保持纵横比),但它超过了最大可接受的宽度。

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 elseclause). 160 x 236 (rounded) is the correct answer.

我们根据 PHP.net 提出的解决方案进行数学计算:width = 160 height = 160/(1630 / 2400) = 160/0.67916666666666667 = 235.5828220858896(else子句)。160 x 236(四舍五入)是正确答案。

回答by user2809327

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

保持纵横比的公式是错误的。应该是:原始高度/原始宽度x新宽度=新高度

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;
}

回答by Pit B. Groove

I was thinking about how to achieve this and i came with a pretty nice solution that works in any case... Lets say you want to resize heavy images that users upload to your site but you need it to maintain the ratio. So i came up with this :

我正在考虑如何实现这一点,我提出了一个在任何情况下都可以使用的非常好的解决方案......假设您想调整用户上传到您网站的重图像的大小,但您需要它来保持比例。所以我想出了这个:

<?php
// File 
$filename = 'test.jpg';



// Get sizes
list($width, $height) = getimagesize($filename);
//obtain ratio
$imageratio = $width/$height;

if($imageratio >= 1){
    $newwidth = 600;
    $newheight = 600 / $imageratio; 
}
else{
     $newidth = 400;
     $newheight = 400 / $imageratio;
};




// Load
$thumb = imagecreatetruecolor($newwidth, $newheight);
$source = imagecreatefromjpeg($filename);

// Resize
imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, 
$height);

// Output
imagejpeg($thumb, "img/test.jpg");
imagedestroy();
?>

In this case if width is bigger than height, i wanted the width to be 600px and if the height was bigger than the width, i wanted the width to be 400px

在这种情况下,如果宽度大于高度,我希望宽度为 600px,如果高度大于宽度,我希望宽度为 400px

回答by gungott

works perfecly for me

非常适合我

    static function getThumpnail($file){

    $THUMBNAIL_IMAGE_MAX_WIDTH  = 150; # exmpl.
    $THUMBNAIL_IMAGE_MAX_HEIGHT = 150;

    $src_size = filesize($file);
    $filename = basename($file);

    list($src_width, $src_height, $src_type) = getimagesize($file);
    $src_im = false;
    switch ($src_type) {
        case IMAGETYPE_GIF  : $src_im = imageCreateFromGif($file);  break;
        case IMAGETYPE_JPEG : $src_im = imageCreateFromJpeg($file); break;
        case IMAGETYPE_PNG  : $src_im = imageCreateFromPng($file);  break;
        case IMAGETYPE_WBMP  : $src_im = imagecreatefromwbmp($file);  break;
    }   
    if ($src_im === false) { return false; }

    $src_aspect_ratio = $src_width / $src_height;
    $thu_aspect_ratio = $THUMBNAIL_IMAGE_MAX_WIDTH / $THUMBNAIL_IMAGE_MAX_HEIGHT;

    if ($src_width <= $THUMBNAIL_IMAGE_MAX_WIDTH && $src_height <= $THUMBNAIL_IMAGE_MAX_HEIGHT) {
        $thu_width  = $src_width;
        $thu_height = $src_height;
    } elseif ($thu_aspect_ratio > $src_aspect_ratio) {
        $thu_width  = (int) ($THUMBNAIL_IMAGE_MAX_HEIGHT * $src_aspect_ratio);
        $thu_height = $THUMBNAIL_IMAGE_MAX_HEIGHT;
    } else {
        $thu_width = $THUMBNAIL_IMAGE_MAX_WIDTH;
        $thu_height = (int) ($THUMBNAIL_IMAGE_MAX_WIDTH / $src_aspect_ratio);
    }

    $thu_im = imagecreatetruecolor($thu_width, $thu_height);
    imagecopyresampled($thu_im, $src_im, 0, 0, 0, 0, $thu_width, $thu_height, $src_width, $src_height);

    $dst_im    = imagecreatetruecolor($THUMBNAIL_IMAGE_MAX_WIDTH,$THUMBNAIL_IMAGE_MAX_WIDTH);
    $backcolor = imagecolorallocate($dst_im,192,192,192);
    imagefill($dst_im,0,0,$backcolor);
    imagecopy($dst_im, $thu_im, (imagesx($dst_im)/2)-(imagesx($thu_im)/2), (imagesy($dst_im)/2)-(imagesy($thu_im)/2), 0, 0, imagesx($thu_im), imagesy($thu_im));
    imagedestroy($src_im);
    imagedestroy($thu_im);
    }

回答by GHosT

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

这是我使用 X、Y 或两个轴的保存纵横比缩放图像的功能。

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

它还按其大小的百分比缩放图像。

Compatibe with PHP 5.4

与 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

回答by Daniel Nyamasyo

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

让我们假设我们的原始图像具有宽度 x 和高度 y;x=300 和 y = 700

Maximum height and maximum width is 200;

最大高度和最大宽度为 200;

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

首先,我们将检查图像的哪个维度大于另一个。我们的高度(y)大于宽度(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.

查看完整示例并使用工作演示进行尝试。

回答by Gayan Sandamal

I found a mathematical way to get this job done

我找到了一种数学方法来完成这项工作

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

Github 存储库 - https://github.com/gayanSandamal/easy-php-image-resizer

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

现场示例 - 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);
}
?>

回答by coban

<?php
Class ResizedImage
{
    public $imgfile;
    public $string      = '';
    public $new_width   = 0;
    public $new_height  = 0;
    public $angle       = 0;
    public $max_font_size = 1000;
    public $cropped = false;//whether crop the original image if h or w > new h or w
    public $font = 'fonts/arialbd.ttf';

    private $img;
    private $trans_colour;
    private $orange;
    private $white; 
    private $whitetr;
    private $blacktr;

    public function PrintAsBase64()
    {
        $this->SetImage();
        ob_start();
        imagepng($this->img);
        $b64img = ob_get_contents();
        ob_clean();
        imagedestroy($this->img);
        $b64img = base64_encode($b64img);
        echo($b64img);
    }
    public function PrintAsImage()
    {
        $this->SetImage();

        header('Content-type: image/png');

        imagepng($this->img);
        imagedestroy($this->img);
    }

    private function SetImage()
    {
        if ($this->imgfile == '') {$this->imgfile='NoImageAvailable.jpg';}
        $this->img          = imagecreatefromstring(file_get_contents($this->imgfile));
        $this->trans_colour = imagecolorallocatealpha($this->img, 0, 0, 0, 127);
        $this->orange       = imagecolorallocate($this->img, 220, 210, 60);
        $this->white        = imagecolorallocate($this->img, 255,255, 255);
        $this->whitetr      = imagecolorallocatealpha($this->img, 255,255, 255, 95);
        $this->blacktr      = imagecolorallocatealpha($this->img, 0, 0, 0, 95);

        if ((!$this->cropped) && ($this->string !=''))
        {$this->watermarkimage();}

        if (($this->new_height > 0) && ($this->new_width > 0)) {$this->ResizeImage();};

        if (($this->cropped) && ($this->string !=''))
        {$this->watermarkimage();}

        imageAlphaBlending($this->img, true);
        imageSaveAlpha($this->img, true);
    }
    ////
    private function ResizeImage()
    {
        # v_fact and h_fact are the factor by which the original vertical / horizontal
        # image sizes should be multiplied to get the image to your target size.
        $v_fact = $this->new_height / imagesy($this->img);//target_height / im_height; 
        $h_fact = $this->new_width / imagesx($this->img);//target_width / im_width;
        # you want to resize the image by the same factor in both vertical 
        # and horizontal direction, so you need to pick the correct factor from
        # v_fact / h_fact so that the largest (relative to target) of the new height/width
        # equals the target height/width and the smallest is lower than the target.
        # this is the lowest of the two factors
        if($this->cropped) 
        {   $im_fact = max($v_fact, $h_fact);   }
        else
        {   $im_fact = min($v_fact, $h_fact);   }

        $new_height = round(imagesy($this->img) * $im_fact);
        $new_width  = round(imagesx($this->img) * $im_fact);

        $img2 = $this->img;     
        $this->img = imagecreatetruecolor($new_width, $new_height);     
        imagecopyresampled($this->img, $img2, 0, 0, 0, 0, $new_width, $new_height, imagesx($img2), imagesy($img2));

        $img2 = $this->img;     
        $this->img = imagecreatetruecolor($this->new_width, $this->new_height);
        imagefill($this->img, 0, 0, $this->trans_colour);

        $dstx = 0;
        $dsty = 0;
        if ($this->cropped)
        {
            if (imagesx($this->img) < imagesx($img2))
            {   $dstx = round((imagesx($this->img)-imagesx($img2))/2); }

            if (imagesy($this->img) < imagesy($img2))
            {   $dsty = round((imagesy($this->img)-imagesy($img2))/2); }
        }
        else
        {
            if (imagesx($this->img) > imagesx($img2))
            {   $dstx = round((imagesx($this->img)-imagesx($img2))/2); }

            if (imagesy($this->img) > imagesy($img2))
            {   $dsty = round((imagesy($this->img)-imagesy($img2))/2); }
        }

        imagecopy ( $this->img, $img2, $dstx, $dsty, 0, 0, imagesx($img2) , imagesy($img2));
        imagedestroy($img2);        
    }   

    ////

    private function calculateTextBox($text,$fontFile,$fontSize,$fontAngle) 
    { 
        /************ 
        simple function that calculates the *exact* bounding box (single pixel precision). 
        The function returns an associative array with these keys: 
        left, top:  coordinates you will pass to imagettftext 
        width, height: dimension of the image you have to create 
        *************/ 
        $rect = imagettfbbox($fontSize,$fontAngle,$fontFile,$text); 
        $minX = min(array($rect[0],$rect[2],$rect[4],$rect[6])); 
        $maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6])); 
        $minY = min(array($rect[1],$rect[3],$rect[5],$rect[7])); 
        $maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7])); 

        return array( 
        "left"   => abs($minX) - 1, 
        "top"    => abs($minY) - 1, 
        "width"  => $maxX - $minX, 
        "height" => $maxY - $minY,
        "box"    => $rect ); 
    }

    private function watermarkimage($font_size=0)
    {
        if ($this->string == '')
        {die('Watermark function call width empty string!');}

        $box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle);
        while ( ($box['width'] < imagesx($this->img)) && ($box['height'] < imagesy($this->img)) && ($font_size <= $this->max_font_size) )
        {
            $font_size++;
            $box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle);   
        }

        $font_size--;
        $box = $this->calculateTextBox($this->string, $this->font, $font_size, $this->angle);

        $vcenter = round((imagesy($this->img) / 2) + ($box['height'] / 2));  
        $hcenter = round((imagesx($this->img) - $box['width']) / 2 );

        imagettftext($this->img, $font_size, $this->angle, $hcenter, $vcenter, $this->blacktr, $this->font, $this->string);     
        imagettftext($this->img, $font_size, $this->angle, $hcenter+1, $vcenter-2, $this->whitetr, $this->font, $this->string);
    }
}
?>

Also I have been using the accepted answer but it does not keep the ratio in some cases. I have found some good answers on the forum and have put them in together and finally created a Class which resizes an image. As extra function u can put a watermark text.

我也一直在使用接受的答案,但在某些情况下它没有保持比例。我在论坛上找到了一些很好的答案,并将它们放在一起,最后创建了一个可以调整图像大小的类。作为额外功能,您可以添加水印文本。

u can see what happens when choose to crop or not, if not a transparent area will be added to the new resized image.

您可以看到选择裁剪与否时会发生什么,如果没有,透明区域将添加到新调整大小的图像中。

This example is more than asked, but I think it is a good example.

这个例子不仅仅是问,但我认为这是一个很好的例子。

回答by Tarik

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 //##//