【问题标题】:PHP Resize image down and crop using imagemagickPHP使用imagemagick缩小图像大小并裁剪
【发布时间】:2012-11-08 19:19:31
【问题描述】:

我正在尝试缩小用户在上传时上传的图片。
这没问题,但我现在想具体说明尺寸。

我正在寻找一些关于我努力生成的算法的建议,该算法将采用任何形状的图像 - 任何宽度/高度的正方形或矩形并缩小它。

此图像需要缩小到目标框大小(这会发生变化,但存储在变量中)..
所以它需要缩小图像,使宽度和高度都大于目标的宽度和高度,保持纵横比。但只是..
目标尺寸将用于裁剪图像,因此边缘等周围没有空白。

我正在寻找基于不同尺寸图像创建正确调整大小背后的算法 - 我可以处理裁剪,甚至在大多数情况下调整大小,但它在少数情况下失败,所以我伸出手来。

我并不是真的要求 PHP 代码更伪。显然两者都可以。

非常感谢。

当前代码.. 但我已经经历了这么多迭代,这可能不再适用了.. :P

$image = $image_orig->clone();
$wRatio = $imageprops['width'] / $dimensions[0];   // imageprops = original image dimens.
$hRatio = $imageprops['height'] / $dimensions[1];  // $dimensions[0] = new width
$maxRatio = max($wRatio,$hRatio);                  // $dimensions[1] = new height

var_dump('thumb');

$ratio = ($imageprops['width'] - $dimensions[0]) > ($imageprops['height'] - $dimensions[1]);
$shape = ($imageprops['width'] > $imageprops['height']);
$error = ($imageprops['width'] / $imageprops['height']);

if( $error < 0.95 || $error > 1.05 ) { // its NOT a square
    if($shape){  // longer width
        $scale = $imageprops['height'] / $dimensions[0];
        var_dump('1');

        $height = $imageprops['height'] / $scale;
        $image->scaleImage(0, $height);
    } else {
        $scale = $imageprops['width'] / $dimensions[1];
        var_dump('2');

        $width = $imageprops['width'] / $scale;
        $image->scaleImage($width, 0);


    }
} elseif($ratio) { // is square
    $scale = $imageprops['height'] / $dimensions[1];
    $newWidth = $imageprops['width'] / $scale;
    $extra = 0;

    $height = $dimensions[1]+$extra;
    $image->scaleImage(0, $height);
} else {
    $scale = $imageprops['width'] / $dimensions[0];
    $newHeight = $imageprops['height'] / $scale;
    $extra = 0;

    $width = $dimensions[0]+$extra;
    $image->scaleImage($width, 0);

}


$image_size = $image->getImageGeometry();

$image->cropImage($dimensions[0], $dimensions[1],($image_size['width']-$dimensions[0])/2,($image_size['height']-$dimensions[1])/2);

【问题讨论】:

  • 你大概已经知道了盒子的尺寸,所以只在 resize 调用中使用它们?还是您的意思是要按比例调整大小,以免图像失真?
  • 假设我有一个 600w x 457h,我希望它达到 120x90.. 保持原始的纵横比。在这种情况下,如果我按比例将 457 减小到 90,则宽度会达到 118 .. 太小了。现在对于某些图像,这可行,但对于此图像,我必须使用宽度作为调整大小的起始尺寸。但我需要一种适用于所有图像尺寸的算法。
  • 我真的很生气你没有在你原来的问题中包含这些信息。你刚刚发布的内容完全改变了原帖的原意,我刚刚花了最后 15分钟写一个可靠的答案,这根本不是你需要的。
  • 真的很抱歉。我累了——天色已晚。随意张贴。它可能仍然有用。

标签: php algorithm imagemagick crop pseudocode


【解决方案1】:

注意:我在原始发帖人编辑他的问题之前写了这个答案,以包括澄清点的内容,这些内容已经改变了我认为原始问题所问的内容。


因此,您可以提出一些概念和想法来尝试解决您打算实现的目标。 (重力裁剪、Content Aware Cropping、内容感知重新缩放等)

因为您总是在减小原始图像的大小,所以您实际上只是想“切掉”图像的一部分。很像这样:

但问题是,您经常希望确保选择图像的最佳区域,以免裁剪图像的不相关部分。这称为内容感知图像裁剪,只需使用“内容感知图像裁剪”进行搜索,您就可以找到大量信息。

无论如何,继续前进,根据您的具体用例,您可能会发现实际上您不想从图像中切掉任何东西,而是想要“液体缩放和裁剪”图像,以便您做“内容感知调整大小”。内容感知调整大小的区别在于,调整大小会忽略图像的所有纵横比,而是查看相邻边缘和颜色,以便以流体方式调整图像大小。

所以,幸运的是,Imagick 带有它自己的[liquidRescaleImage][3] 功能。

你可以像这样使用它

$im-&gt;liquidRescaleImage(480, 260, 3, 18);

使用 Liquid Rescale 可以很好地重新缩放。下面是一个不完美的示例,但我故意创建了一个不完美的示例,因此您实际上可以看到liquidRescale 改变了图像的组成,而不仅仅是调整纵横比。

原创

内容感知液体重新缩放 (450x350)

但是,如果您只想缩放图像并保持纵横比,您可能需要像 Flickr 这样的网站所做的那样,它们使图像的最长长度等于一个值。 (例如 Flickr 有 6 种左右不同的尺寸)

我们会将您的照片调整为更适合网络使用的尺寸。每个图像都有 75x75 和 150x150 方形缩略图和 100-、240-、320-、500-、640- 800*-、1024-、1600*- 和 2048*-像素版本(即 最长的一面),以及您的原始文件。

复制 Flickr 调整大小策略的基本类...

<?php    
class Scale {        
    public function getImageScale($x, $y, $longestLength, $allowDistort = false) {
        //Set the default NEW values to be the old, in case it doesn't even need scaling
        list($nx, $ny) = array($x, $y);            
            if ($x > $y) {                   
                if ($longestLength > $x && !$allowDistort) {
                    return array($x, $y);
                }
                $r = $x / $longestLength;
                return array($longestLength, $y / $r);
            } else {
                if ($longestLength > $x && !$allowDistort) {
                    return array($x, $y);
                }
                $r = $y / $longestLength;
                return array($x / $r, $longestLength);
            }
        return array($nx, $ny);
    }       
}

然后,如果您要像这样传递图像尺寸:

$originalImageX = 480;
$originalImageY = 260;    
$scale = new Scale();
var_dump($scale->getImageScale($originalImageX,$originalImageY,120 ) );    

/* Outputs
   array(2) {
  [0]=>
  int(120)
  [1]=>
  int(65)
} */

另外,Git 上有这个 Content Aware Cropping 类,我之前已经调整了基类/结构,以便在我自己的项目中使用,所以我知道它工作得很好。我不确定这个类的许可,但你显然可以看看它,并像我之前所做的那样找出对你有用的东西。

https://gist.github.com/2468935#file_content_aware_image.php

(还有 PS。下次直接在你的问题中提供所有信息......)

【讨论】:

  • 超级有用的帖子。谢谢!
【解决方案2】:

不知道这是不是你想要的,来自我的个人脚本库 xD: 您只需为缩略图指定所需的 $maxW $maxH 和相同的值,它会按比例缩小图像。

脚本有两部分几乎相同,一个是缩略图,一个是实际图像。

list($w, $h) = getimagesize($file);
$maxW = 1024;
$maxH = 786;
$thumbMaxW = 138;
$thumbMaxH = 92;

$newW = $w;
$newH = $h;

if($w > $thumbMaxW OR $h > $thumbMaxH){
    if($w>=$h){
        $thumbW = $thumbMaxW;
        $thumbRatio = $w/$thumbMaxW;
        $thumbH = (int)($h/$thumbRatio);
    } else {
        $thumbH = $thumbMaxH;
        $thumbRatio = $h/$thumbMaxH;
        $thumbW = (int)($w/$thumbRatio);
    }
} else {
    $thumbW = $w;
    $thumbH = $h;
}
--------------------------------------------

if($w > $maxW OR $h > $maxH){
    if($w >= $h){
        $newW = $maxW;
        $reduction = $w/$newW;
        $newH = (int)   ($h/$reduction);
    }

    if($h > $w){
        $newH = $maxH;
        $reduction = $h/$newH;
        $newW = (int)($w/$reduction);
    }
} else {
    $newW = $w;
    $newH = $h;
}

【讨论】:

  • 而且,我非常希望看到投反对票的人提出建设性意见,主要是为了确保将来不会犯同样的错误。
猜你喜欢
  • 2012-05-19
  • 1970-01-01
  • 2017-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多