将图片调整/裁剪/填充到固定大小

8

我需要将一张图片调整到固定大小,但是它必须保持宽度和高度之间的比例关系。

比如我想把一张 238 (w) X 182 (h) 的图片调整到 210 / 150 的大小。

现在我需要做的是:

Original width / target width = 1.333333
Original Height / target Height = 1.213333

现在我取最小的因素。

现在我总是有正确的宽度,因为 238 / 1.333333 = 210。但高度仍然是160

如何将高度减少到 160而不破坏图片?

我需要裁剪吗?如果需要,应该怎么做?

11个回答

26

这个解决方案基本与Can Berk Güder的相同,但经过花费一些时间编写和注释后,我觉得有必要发帖。

此函数创建一个缩略图,大小完全由您给出。 图像被调整大小以最佳适应缩略图的大小。 如果两个方向都不完全符合,则在缩略图中居中。 详细的注释解释了整个过程。

function thumbnail_box($img, $box_w, $box_h) {
    //create the image, of the required size
    $new = imagecreatetruecolor($box_w, $box_h);
    if($new === false) {
        //creation failed -- probably not enough memory
        return null;
    }


    //Fill the image with a light grey color
    //(this will be visible in the padding around the image,
    //if the aspect ratios of the image and the thumbnail do not match)
    //Replace this with any color you want, or comment it out for black.
    //I used grey for testing =)
    $fill = imagecolorallocate($new, 200, 200, 205);
    imagefill($new, 0, 0, $fill);

    //compute resize ratio
    $hratio = $box_h / imagesy($img);
    $wratio = $box_w / imagesx($img);
    $ratio = min($hratio, $wratio);

    //if the source is smaller than the thumbnail size, 
    //don't resize -- add a margin instead
    //(that is, dont magnify images)
    if($ratio > 1.0)
        $ratio = 1.0;

    //compute sizes
    $sy = floor(imagesy($img) * $ratio);
    $sx = floor(imagesx($img) * $ratio);

    //compute margins
    //Using these margins centers the image in the thumbnail.
    //If you always want the image to the top left, 
    //set both of these to 0
    $m_y = floor(($box_h - $sy) / 2);
    $m_x = floor(($box_w - $sx) / 2);

    //Copy the image data, and resample
    //
    //If you want a fast and ugly thumbnail,
    //replace imagecopyresampled with imagecopyresized
    if(!imagecopyresampled($new, $img,
        $m_x, $m_y, //dest x, y (margins)
        0, 0, //src x, y (0,0 means top left)
        $sx, $sy,//dest w, h (resample to this size (computed above)
        imagesx($img), imagesy($img)) //src w, h (the full size of the original)
    ) {
        //copy failed
        imagedestroy($new);
        return null;
    }
    //copy successful
    return $new;
}

使用示例:

$i = imagecreatefromjpeg("img.jpg");
$thumb = thumbnail_box($i, 210, 150);
imagedestroy($i);

if(is_null($thumb)) {
    /* image creation or copying failed */
    header('HTTP/1.1 500 Internal Server Error');
    exit();
}
header('Content-Type: image/jpeg');
imagejpeg($thumb);

1
这个脚本会复制原始图像。当重新采样图像时,您需要进行复制。我的示例使用会破坏原始图像(imagedestroy($i))。如果您想要覆盖图像文件,则只需在示例中将$thumb写入文件“img.jpg”即可。 - gnud
好的,谢谢。如果我想要整张图片调整大小而不是裁剪怎么办? - sanders
感谢您提供优秀的代码。如果我想让图像位于右上角,我需要哪些值?我猜 $m_y = 0 $m_x = ? - Khawer Zeshan
@KhawerZeshan 我想 $m_y = 0; $m_x = $box_w - $sx; 就可以了。 - gnud
@gnud,这正是我所做的,谢谢您的回复 :) - Khawer Zeshan
显示剩余5条评论

11

这不会裁剪图片,但是如果需要的话会在新图像周围留下空间。我认为这是创建缩略图时比裁剪更好的方法。

$w = 210;
$h = 150;

$orig_w = imagesx($original);
$orig_h = imagesy($original);

$w_ratio = $orig_w / $w;
$h_ratio = $orig_h / $h;

$ratio = $w_ratio > $h_ratio ? $w_ratio : $h_ratio;

$dst_w = $orig_w / $ratio;
$dst_h = $orig_h / $ratio;
$dst_x = ($w - $dst_w) / 2;
$dst_y = ($h - $dst_h) / 2;

$thumbnail = imagecreatetruecolor($w, $h);

imagecopyresampled($thumbnail, $original, $dst_x, $dst_y,
                   0, 0, $dst_w, $dst_h, $orig_w, $orig_h);

你测试过这个吗?因为在我的例子中,高度仍然是160像素,而不是应该的150像素。 - sanders
高度为150,宽度为196。因此左右两侧有7像素的边距。 - Can Berk Güder
身高196?应该是150! - sanders

2

你是否安装了Imagick?如果是,你可以使用它来加载图像,并使用thumbnailimage()之类的方法进行操作。

在这里,你可以跳过参数中的高度或宽度,它会自动调整大小。


我更喜欢使用GD,因为这是我用于所有事情的工具。不知道我是否有安装ImageMagick。 - sanders
以下是使用Imagick PHP的示例: http://arturito.net/2011/01/08/imagemagick-php-image-resizing-imagick-with-canvas/ - Artur Kedzior

2
也许可以看一下PHPThumb(它能够使用GD和ImageMagick工具处理图片)。

2

关于从大图像快速生成高质量缩略图的小提示:(来自php.net网站

如果您在两个阶段内进行缩略图生成:

  1. 使用快速调整大小将原始图像转换为具有两倍最终尺寸的中间图像
  2. 使用高质量重新采样将中间图像转换为最终缩略图

那么这样会更快;步骤1中的调整大小相对较差,但分辨率足够高,因此在步骤2中质量是不错的,并且中间图像足够小,高质量的重新采样(在2:1调整大小上表现良好)非常快速。


谢谢你的贡献。你有一些示例代码吗?这将如何适用于Gnut代码中? - sanders

1

在 PHP 页面中调整图像大小可能会有问题。较大的图像(接近磁盘上的 2MB+)可能会非常大,需要超过 32MB 的内存来处理。

因此,我倾向于使用基于 CLI 的脚本,有多达 128MB 的可用内存,或者标准命令行,它也使用所需的所有内存。

# where to put the original file/image. It gets resized back 
# it was originally found (current directory)
SAFE=/home/website/PHOTOS/originals
# no more than 640x640 when finished, and always proportional
MAXSIZE=640
# the larger image is in /home/website/PHOTOS/, moved to .../originals
# and the resized image back to the parent dir.
cd $SAFE/.. && mv "$1" "$SAFE/$1" && \
   convert "$SAFE/$1" -resize $MAXSIZE\x$MAXSIZE\> "$1"

'convert' 是 ImageMagick 命令行工具的一部分。


1

我认为有一点混淆了.. 如果你只想按比例调整大小,正确的操作是:

$ratio = $originalWidth / $originalHeight;
if(//you start from the width, and want to find the height){
 $newWidth = $x;
 $newHeight = $x / $ratio;
}else if(//you start from the height, and want to find the width){
 $newHeight = $x;
 $newWidth = $x * $ratio;
}

否则,如果预设的新宽度和新高度无法更改,并且缩略图比例与原始比例不同,则唯一的方法是裁剪或添加边框到缩略图。

如果你想采取简单的方式,这个函数可以帮助你(我几年前写的,可能需要一些改进.. 它只适用于jpg格式的图片;):

    function thumb_cut($nomeimage, $source_path, $destination_path, $new_width, $new_height){
      list($width, $height, $type, $attr) = getimagesize($source_path.$nomeimage);
      if($type == 2){
        if($width > $new_width){
          $new_width = $width;
          $new_height = $height;
        }
        $compression = 100;
        $destimg = imagecreatetruecolor($new_width,$new_height) or die("Problems creating the image");
        $srcimg = ImageCreateFromJPEG($source_path.$nomeimage) or die("problem opening the image");
        $w = ImageSX($srcimg);
        $h = ImageSY($srcimg);
        $ro = $new_width/$new_height;
        $ri = $w/$h;
        if($ro<$ri){
          $par = "h";
        }else{
          $par = "w";
        }
        if($par == "h"){
          $ih = $h;
          $conv = $new_width/$new_height;
          $iw = $conv*$ih;
          $cw = ($w/2)-($iw/2);
          $ch = ($h/2)-($ih/2);
        }else if($par == "w"){
          $iw = $w;
          $conv = $new_height/$new_width;
          $ih = $conv*$iw;
          $cw = ($w/2)-($iw/2);
          $ch = ($h/2)-($ih/2);
        }
        ImageCopyResampled($destimg,$srcimg,0,0,$cw,$ch,$new_width,$new_height,$iw,$ih) or die("problems with resize");
        ImageJPEG($destimg,$destination_path.$nomeimage,$compression) or die("problems with storing new image");
      }
    }

1

我更愿意调整大小,使图像包含在您的限制范围内,然后填补空白部分。因此,在上面的示例中,您将调整大小,使高度正常,然后使用背景颜色填充左右两侧(我认为是每侧7个像素)。


1

这些是缩略图吗?如果是的话,裁剪不是什么大问题。我们经常这样做。我甚至不会避免将任意比例裁剪成残缺的正方形缩略图,完全破坏了图片(是的,我就是那个“硬派”),只要它看起来好看就行。虽然这是一个设计师对技术问题的回答,但也是有参考价值的。不要害怕裁剪!


1

技巧是:

  1. 调整图像大小,使其中一个维度匹配,而另一个维度超过所需尺寸
  2. 从调整后的图像中心取出所需尺寸的图像。

最后,如果您对如何进行调整大小的数学计算感到困惑,请记住,如果源图像和目标图像的比例相同,则以下关系成立:

SourceWidth / SourceHeight = DestinationWidth / DestinationHeight

如果你知道三个参数,你可以轻松地计算出第四个。

我写了一篇关于此的文章:
使用ASP/PHP裁剪图像以适应大小


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接