PHP imagecopyresampled 生成图片质量差

11

我有一个PHP脚本,它会保存原始图像,然后调整大小 - 一个缩略图和一个更大的图像用于在Web上查看。这个过程效果很好,但是对于某些图像来说,质量却很糟糕。似乎保存的颜色调色板非常低。您可以在http://kalpaitch.com/index.php?filter=white上查看结果 - 点击标题为“white white white”的第一个缩略图。

以下是用于图像重采样的代码:

function resizeImg($name, $extension, $size1, $size2) {
if (preg_match('/jpg|jpeg|JPG|JPEG/',$extension)){
    $image = imagecreatefromjpeg($name);
}
if (preg_match('/gif|GIF/',$extension)){
    $image = imagecreatefromgif($name);
}

$old_width = imageSX($image);
$old_height = imageSY($image);
$old_aspect_ratio = $old_width/$old_height; 

if($size2 == 0){
    $new_aspect_ratio = $old_aspect_ratio;
    if($old_width > $old_height){
        $new_width = $size1;
        $new_height = $new_width / $old_aspect_ratio;
    } else {
        $new_height = $size1;
        $new_width = $new_height * $old_aspect_ratio;
    }
} elseif($size2 > 0){
    $new_aspect_ratio = $size1/$size2;
    //for landscape potographs
    if($old_aspect_ratio >= $new_aspect_ratio) {
        $x1 = round(($old_width - ($old_width * ($new_aspect_ratio/$old_aspect_ratio)))/2);
        $old_width = round($old_width * ($new_aspect_ratio/$old_aspect_ratio));
        $y1 = 0;
        $new_width = $size1;
        $new_height = $size2;
        //for portrait photographs
    } else{
        $x1 = 0;
        $y1 = 0;
        $old_height = round($old_width/$new_aspect_ratio);
        $new_width = $size1;
        $new_height = $size2;
    }
}

$new_image = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($new_image, $image, 0, 0, $x1, $y1, $new_width, $new_height, $old_width, $old_height);

return $new_image;

非常感谢

P.S. [照片已从服务器中删除]

这里是剩余的上传代码:

// Move the original to the right place
        $result = @move_uploaded_file($image['tmp_name'], $origlocation);

        // Resize the image and save the thumbnail
        $new_image = resizeImg($origlocation, $extension, 500, 0);

        if (preg_match("/gif/",$extension)){
            imagegif($new_image, $normallocation); 
        } else {
            imagejpeg($new_image, $normallocation); 
        }

        // Resize the image and save the thumbnail
        $new_image = resizeImg($origlocation, $extension, 190, 120);

        if (preg_match("/gif/",$extension)){
            imagegif($new_image, $thumblocation); 
        } else { 
            imagejpeg($new_image, $thumblocation);
        }

2
你能展示一个前后的例子吗? - Pekka
我不是100%清楚,但听起来你得到的一些图像是特定大小的,而你的脚本实际上将其调整为比原始尺寸更大?如果你这样做,质量会非常糟糕。 - Jage
如果只给定一个尺寸,则该脚本将按比例调整图像大小。如果给定两个尺寸,则它将调整大小并裁剪其余部分,而不改变纵横比。重新采样的图像始终比原始图像低得多。上面的“before”照片不是原始照片,它们都具有相同的分辨率,但“before”是使用Photoshop保存的,而“after”则是使用我的脚本保存的。 - kalpaitch
2
剩下的脚本在哪里?可能是你正在使用的图像输出函数。尝试使用imagepng()来输出图像,并将压缩质量设置为'0'进行测试。http://us2.php.net/manual/zh/function.imagepng.php - John Himmelman
我进行了一个快速测试,imagepng()似乎并没有产生太大的差异。实际上没有任何差别。但是我会将脚本的另一半相关部分发布出来供您参考。 - kalpaitch
4个回答

27

图像质量下降不是因为imagecopyresampled(),而是由于JPEG压缩。不幸的是,GD的压缩算法远远不及Photoshop的 - 实际上,很少有压缩算法能与之匹敌。但是您可以通过更改GD的默认JPG压缩级别(为100的75)来改善结果:

您可以使用imagejpeg()的第三个参数来提高质量(我假设您用它进行最终输出):

imagejpeg  ( $new_image, null, 99);

尝试在90-100范围内进行调整。图像的文件大小将比原始大小更大 - 这就是你要付出的代价。但是应该可以实现可比较的质量。

另外,正如John Himmelman在评论中已经提到的,尝试使用imagepng()以获得更好的质量 - 当然价格是显着更大的文件大小。


5
对于任何好奇的人,我有一个小建议。我把imagejpeg()的质量改成了99,得到了一张更好的图片。不过需要注意的是,与默认设置相比,文件大小增加了1000%(默认大小为12kb,高质量压缩后为110kb)。 - kalpaitch
1
阅读后我想提出一个建议。使用我的缩略图系统,缩略图图像不需要与原始全尺寸图像具有相同的格式,我的实用函数会被询问“这个图像的缩略图文件是什么,并且它是否已经存在?”因此,如果询问file.jpg,则会返回thumbnail_cache/file.jpg。我已经改变了这种方法,始终回复.png格式的缩略图,因此如果询问file.jpg,则会返回thumbnail_cache/file.png并生成png缩略图。这避免了对GD jpg压缩的任何担忧。 - Neek
重采样的结果很模糊,这是一个GD问题,不支持lanczos。一个hack方法是使用imagescale将大小调整到200%,然后再调整回100%(50%),这样可以得到更清晰的图像。虽然不是lanczos,但比较锐利。ImageMagick总是更好的选择。 - Teson

3

好的,php.net文档表示如果您想避免仅使用255色调色板,则应该为dest_image创建一个imagecreatetruecolor()图像,但是您已经这样做了。

我猜另一种选择是使用外部工具,比如通过system()调用imagemagick


是的,不确定 PHP 是否很有帮助。正如您所见,我使用 imagecopyresized 做了第三个测试图像,效果略好,但还不够。 - kalpaitch
1
谢谢,使用imagecreatetruecolor解决了我在自定义图像中遇到的低颜色计数问题! - CodeShaman

2
快速而简单的技巧是在 imagecopyresized() 上将缩略图制作为 1000 x 1000 像素(或更大),然后在 imagejpeg($img, $savePath, 20); 上将JPEG质量设置为 20 或更低。输出通常会小于 100 kb。
让客户端 CSS 进行调整大小,图片加载快速,在缩略图大小时在现代浏览器中看起来无瑕疵。

-1
function img_resize( $tmpname, $size, $save_dir, $save_name, $maxisheight = 0 )
{
    $save_dir .= ( substr($save_dir,-1) != "/") ? "/" : "";
    $gis = getimagesize($tmpname);
    $type = $gis[2];

    switch($type)
    {
        case "1": $imorig = imagecreatefromgif($tmpname); break;
        case "2": $imorig = imagecreatefromjpeg($tmpname);break;
        case "3": $imorig = imagecreatefrompng($tmpname); break;
        default:  $imorig = imagecreatefromjpeg($tmpname);
    }

    $x = imagesx($imorig);
    $y = imagesy($imorig);

    $woh = (!$maxisheight)? $gis[0] : $gis[1] ;
    if($woh <= $size)
    {
        $aw = $x;
        $ah = $y;
    }
    else
    {
        if(!$maxisheight)
        {
            $aw = $size;
            $ah = $size * $y / $x;
        }
        else
        {
            $aw = $size * $x / $y;
            $ah = $size;
        }
    }
    $im = imagecreatetruecolor($aw,$ah);

    if (imagecopyresampled($im,$imorig , 0,0,0,0,$aw,$ah,$x,$y))

    if (imagejpeg($im, $save_dir.$save_name))

        return true;

    else

        return false;

}

1
这个函数中实际上很少提供有关正在发生的事情的信息。size应该是什么?一个数组?一个字符串?百分比? - Typewar

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