选择PHP的图像调整算法

9

函数 imagecopyresampled 用于生成缩略图或调整图像大小,同时保持纵横比:

$fn = $_FILES['data']['tmp_name'];
$size = getimagesize($fn);
$width = $size[0];
$height = $size[1];
$ratio = $width / $height;
if ($ratio > 1 && $size[0] > 500) { $width = 500; $height = 500 / $ratio; }
else { if ($ratio <= 1 && $size[1] > 500) { $width = 500 * $ratio; $height = 500; }}
$src = imagecreatefromstring(file_get_contents($fn));
$dst = imagecreatetruecolor($width, $height);
imagecopyresampled($dst, $src, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
imagedestroy($src);
imagejpeg($dst, 'test.jpg');
imagedestroy($dst);

我该如何选择PHP使用的调整大小算法?
注意:如此问题所述,设置imagesetinterpolation($dst, IMG_BILINEAR_FIXED);等内容似乎无效。
根据我进行的测试(使用另一种语言),"双线性调整大小"有时比双三次更好,有时则相反(取决于是缩小还是放大)。 (来源:dpchallenge.com

正如某人在这里所指出的:“值得注意的是,imagecopyresampled()函数比Photoshop CS的默认双三次函数模糊得多。并且看起来类似于Photoshop的双线性函数的模糊版本。文档没有说明在重采样中使用了哪种算法。” - Basj
1
看起来它不适用于imagecopyresampled - 我会将其删除,同时尝试解决问题。抱歉。 - Mark Setchell
正如这个问题所述,设置imagesetinterpolation($dst, IMG_BILINEAR_FIXED);之类的东西似乎不起作用。 - Basj
“我该如何修改 PHP 使用的调整大小算法?”也许编写自定义的 PHP 函数比修改编程语言本身更容易(如果这是允许的)? - VC.One
1
我已经编辑了你的问题中的一个关键词,因为我现在更好地理解它了。当你真正想表达“我想选择算法X的选项”时,请不要说“我想修改算法X”,因为前者暗示你想修改PHP源代码的函数。你只是想启用一些调整大小的选项... 对吗? - VC.One
4个回答

12

另一种选择是使用imagescale() 函数,该函数允许将插值算法指定为参数:

imagescale($image, $new_width, $new_height, $algorithm);

根据文档,$algorithm 可以是以下之一:

IMG_NEAREST_NEIGHBOURIMG_BILINEAR_FIXEDIMG_BICUBICIMG_BICUBIC_FIXED 或者其他(将使用两次传递)。

在 PHP 7.0.15 中进行的测试(比较文件哈希值)显示,BICUBIC 和 BICUBIC_FIXED 会产生不同的图像,而 BILINEAR_FIXED 和 NEAREST_NEIGHBOUR 会产生相同的图像。


太好了!我会尽快测试。 - Basj
1
@Basj 这就是我本来要给自己的答案。我认为它符合你的需求,对吗? - VC.One
对我来说,在使用imagescale()时,加上IMG_BICUBIC会使图像更模糊,并在平坦颜色中引入奇怪的伪影。 - Chris Seufert
2
我不能确定哪种滤镜会产生最佳效果,但避免使用 IMG_BICUBIC_FIXEDIMG_BILINEAR_FIXEDIMG_NEAREST_NEIGHBOUR 这些方法,因为它们会产生非常糟糕的图像(我进行了缩放测试)。 - mgutt
3
重要提示是手册中的“或其他任何内容”。我注意到我可以使用更多滤镜类型,列在这里 https://www.php.net/manual/de/function.imagesetinterpolation.php。可能除了IMG_WEIGHTED4(请参阅imagescale的php手册)之外的所有类型都可以使用。例如,我在缩小图像时使用了IMG_CATMULLROM(在PHP 7中测试过),效果不错。 - Jens

5

imagecopyresampled是LibGD的一部分,通过查看LibGD的源代码,可以清楚地看到它的实现方式,文档也明确说明了所使用的算法,即:

如果源区域和目标区域的大小不同,则对于真彩色图像将使用双线性插值进行调整大小,对于调色板图像则使用最近邻插值

那么如何选择PHP使用的调整大小算法呢?

如果你坚持必须使用LibGD函数,那么你无法选择(除非你重新编译PHP并使用一个专门针对此问题的LibGD分支)。

然而,如果你可以自由使用另一个图像处理库,你可以简单地使用一个使用不同调整大小算法的库,例如 Imagick 似乎提供了广泛的插值方法,但是由于文档对此相当缄默,这里是需要使用 Imagick::setImageInterpolateMethod(int $) 方法的常量:
const INTERPOLATE_UNDEFINED = 0;
const INTERPOLATE_AVERAGE = 1;
const INTERPOLATE_BICUBIC = 2;
const INTERPOLATE_BILINEAR = 3;
const INTERPOLATE_FILTER = 4;
const INTERPOLATE_INTEGER = 5;
const INTERPOLATE_MESH = 6;
const INTERPOLATE_NEARESTNEIGHBOR = 7;
const INTERPOLATE_SPLINE = 8;

0

为什么不使用库呢?我认为如果你使用PHP库会更容易。尝试一下这个。希望它能帮到你。


@Cakpep请检查新编辑并重新阅读问题的真正含义。如果您愿意,可以使用新信息edit您的答案.... - VC.One
这个库不允许更改算法。请参见此评论http://php.net/manual/en/function.imagecopyresampled.php 这是库内部使用的函数。我找不到有关该函数使用哪种算法的信息。 - Basj

0

这个答案没有问题。它适用于之前的问题措辞,该措辞暗示提问者想要修改重新采样算法的源代码。我已经编辑了问题。@VitalijMik,如果您希望更改您的答案,请检查新的编辑... - VC.One

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