将PHP/GD包装器移植到Imagick的问题

将PHP/GD包装器移植到Imagick的问题,php,image,imagemagick,gd,imagick,Php,Image,Imagemagick,Gd,Imagick,我最近发现Imagick可以支持颜色配置文件,因此与GD相比可以生成质量更好的图像(请参阅/了解更多详细信息),因此我尝试移植我的GD包装器以使用Imagick类,而我当前的GD实现如下所示: function Image($input, $crop = null, $scale = null, $merge = null, $output = null, $sharp = true) { if (isset($input, $output) === true) {

我最近发现Imagick可以支持颜色配置文件,因此与GD相比可以生成质量更好的图像(请参阅/了解更多详细信息),因此我尝试移植我的GD包装器以使用Imagick类,而我当前的GD实现如下所示:

function Image($input, $crop = null, $scale = null, $merge = null, $output = null, $sharp = true)
{
    if (isset($input, $output) === true)
    {
        if (is_string($input) === true)
        {
            $input = @ImageCreateFromString(@file_get_contents($input));
        }

        if (is_resource($input) === true)
        {
            $size = array(ImageSX($input), ImageSY($input));
            $crop = array_values(array_filter(explode('/', $crop), 'is_numeric'));
            $scale = array_values(array_filter(explode('*', $scale), 'is_numeric'));

            if (count($crop) == 2)
            {
                $crop = array($size[0] / $size[1], $crop[0] / $crop[1]);

                if ($crop[0] > $crop[1])
                {
                    $size[0] = round($size[1] * $crop[1]);
                }

                else if ($crop[0] < $crop[1])
                {
                    $size[1] = round($size[0] / $crop[1]);
                }

                $crop = array(ImageSX($input) - $size[0], ImageSY($input) - $size[1]);
            }

            else
            {
                $crop = array(0, 0);
            }

            if (count($scale) >= 1)
            {
                if (empty($scale[0]) === true)
                {
                    $scale[0] = round($scale[1] * $size[0] / $size[1]);
                }

                else if (empty($scale[1]) === true)
                {
                    $scale[1] = round($scale[0] * $size[1] / $size[0]);
                }
            }

            else
            {
                $scale = array($size[0], $size[1]);
            }

            $image = ImageCreateTrueColor($scale[0], $scale[1]);

            if (is_resource($image) === true)
            {
                ImageFill($image, 0, 0, IMG_COLOR_TRANSPARENT);
                ImageSaveAlpha($image, true);
                ImageAlphaBlending($image, true);

                if (ImageCopyResampled($image, $input, 0, 0, round($crop[0] / 2), round($crop[1] / 2), $scale[0], $scale[1], $size[0], $size[1]) === true)
                {
                    $result = false;

                    if ((empty($sharp) !== true) && (is_array($matrix = array_fill(0, 9, -1)) === true))
                    {
                        array_splice($matrix, 4, 1, (is_int($sharp) === true) ? $sharp : 16);

                        if (function_exists('ImageConvolution') === true)
                        {
                            ImageConvolution($image, array_chunk($matrix, 3), array_sum($matrix), 0);
                        }
                    }

                    if ((isset($merge) === true) && (is_resource($merge = @ImageCreateFromString(@file_get_contents($merge))) === true))
                    {
                        ImageCopy($image, $merge, round(0.95 * $scale[0] - ImageSX($merge)), round(0.95 * $scale[1] - ImageSY($merge)), 0, 0, ImageSX($merge), ImageSY($merge));
                    }

                    foreach (array('gif' => 0, 'png' => 9, 'jpe?g' => 90) as $key => $value)
                    {
                        if (preg_match('~' . $key . '$~i', $output) > 0)
                        {
                            $type = str_replace('?', '', $key);
                            $output = preg_replace('~^[.]?' . $key . '$~i', '', $output);

                            if (empty($output) === true)
                            {
                                header('Content-Type: image/' . $type);
                            }

                            $result = call_user_func_array('Image' . $type, array($image, $output, $value));
                        }
                    }

                    return (empty($output) === true) ? $result : self::Chmod($output);
                }
            }
        }
    }

    else if (count($result = @GetImageSize($input)) >= 2)
    {
        return array_map('intval', array_slice($result, 0, 2));
    }

    return false;
}
具有将透明PNG图像转换为PNG输出时的效果。但是,如果尝试将透明PNG图像转换为JPEG格式,则透明像素的颜色应设置为白色。到目前为止,使用ImageMagick,我只能做到这一点,但如果输出格式支持,我就无法保持透明度


2-压缩输出格式(即JPEG和PNG) 我最初的实现在PNG上使用9级压缩,在JPEG上使用90级质量:

foreach (array('gif' => 0, 'png' => 9, 'jpe?g' => 90) as $key => $value)
台词:

$image->setImageCompression(Imagick::COMPRESSION_JPEG);
$image->setImageCompressionQuality($value);
$image->stripImage();
似乎可以压缩JPEG图像-但是,GD能够使用相同的
$value
作为质量参数来压缩它更多-为什么?我也不清楚以下两者之间的区别:

  • /及
  • /
我应该使用哪一种,它们的区别是什么?此外,最关键的问题与PNG压缩有关,以下列表似乎不支持PNG格式:

imagick::COMPRESSION_UNDEFINED (integer)
imagick::COMPRESSION_NO (integer)
imagick::COMPRESSION_BZIP (integer)
imagick::COMPRESSION_FAX (integer)
imagick::COMPRESSION_GROUP4 (integer)
imagick::COMPRESSION_JPEG (integer)
imagick::COMPRESSION_JPEG2000 (integer)
imagick::COMPRESSION_LOSSLESSJPEG (integer)
imagick::COMPRESSION_LZW (integer)
imagick::COMPRESSION_RLE (integer)
imagick::COMPRESSION_ZIP (integer)
imagick::COMPRESSION_DXT1 (integer)
imagick::COMPRESSION_DXT3 (integer)
imagick::COMPRESSION_DXT5 (integer)
这是一个画龙点睛的问题,因为碰巧大小为100-200 KB的GD PNG输出如果使用Imagick(大小约为2 MB)输出会变得非常胖

有,但我还没有找到任何不依赖外部应用程序的工作解决方案。用ImageMagick真的不可能吗


3-图像卷积 在GD实现中,我调用
ImageConvolution()
来稍微锐化图像,我知道Imagick有内置的锐化图像的方法(我还没有机会尝试它们),但我想知道Imagick是否有一个与
ImageConvolution()相当的函数


4-颜色配置文件 这与最初的实现无关,但我也希望它正确

我是否应该始终将Imagick/International Color Consortium sRGB颜色配置文件添加到所有图像?或者,只有当存在(或不存在)特定的颜色配置文件时,才应添加此选项

此外,我是否应该删除现有的颜色配置文件

我知道这可能是一个广泛的问题,但我对颜色配置文件的理解非常有限,对此提供一些一般性指导将不胜感激


5-打开远程映像 GD本机支持通过
ImageCreateFrom*
函数打开远程图像,或者像我这样使用
file\u get\u contents()
结合
ImageCreateFromString()
打开远程图像

Imagick似乎只能打开本地图像或打开文件句柄。是否有任何简单的方法可以让Imagick读取远程图像(无需打开和关闭文件句柄)


如果有人能对这些问题中的任何一个有所了解,我将非常感激


提前谢谢

PNG图像的大小可能会增加,原因有很多,最明显的原因是GM/IM无法将透明度作为tRNS块传递(PNG图像基本上是布尔透明度)。不幸的是,GraphicsMagick和ImageMagick的维护人员尚未实现此功能。我和他们交换了电子邮件,所以我确信这一点

我知道你不想使用外部工具,但相信我,你会的。Image/GraphicsMagick在压缩PNG图像方面非常糟糕。我使用的解决方案是,使用GraphicsMagick操作图像,并检查图像是否包含透明像素,如果确实包含透明像素,则在图像上运行OptiPNG。OptiPNG将看到透明度可以作为tRNS块来传达,并相应地采取行动。实际上,在使用Image/GraphicsMagick之后,您应该在所有PNG图像上运行optPNG,因为我发现您可以实现更高的压缩。还可以通过禁用抖动和使用YUV颜色空间来节省空间

至于GM比IM更好地缩小图像大小,您应该知道,GM在缩小图像颜色时默认使用8位颜色空间,而ImageMagick默认使用16位。这就是为什么在将图像颜色减少到255种颜色以上时,GM比IM快得多。也许你应该在压缩后检查每个图像中的颜色数量以确认。

你可以使用(另一个PNG命令行工具)优化PNG文件的大小。

因为这些配置文件实际上是在浪费带宽。因此,如果您的图像在sRGB中,您可以安全地丢弃配置文件,否则最好将图像转换为sRGB,然后丢弃其配置文件

删除sRGB图像配置文件的原因是,sRGB实际上是Internet、计算机和打印机上的标准,甚至Firefox也将sRGB颜色配置文件应用于 未标记的图像

完全删除所有配置文件还有另一个原因,我不确定它是否适用于您的情况:如果您计划将嵌入配置文件的图像与其他无配置文件的图像(例如GIF图像)混合,而这些图像不能定义为包含配置文件,那么在启用ICC的浏览器上,您将得到一个混乱的结果。它将根据嵌入的颜色空间和其他颜色空间渲染一些图像,这将导致一种情况,即您将看到嵌入ICC配置文件的图像与具有相同颜色背景颜色的其他无配置文件图像相邻的具有纯色背景色的图像之间的边界。即使你能为你的页面上的每一张图片获得一个配置文件,也有很多用户使用古老的禁用ICC的浏览器

底线:颜色配置文件是邪恶的。只有在你真正需要的时候才使用它们


我所说的是正确的,只有当你的目标是你的网站为最广泛的观众可能。否则,我不确定您是否还需要a
$image->setImageCompression(Imagick::COMPRESSION_JPEG);
$image->setImageCompressionQuality($value);
$image->stripImage();
imagick::COMPRESSION_UNDEFINED (integer)
imagick::COMPRESSION_NO (integer)
imagick::COMPRESSION_BZIP (integer)
imagick::COMPRESSION_FAX (integer)
imagick::COMPRESSION_GROUP4 (integer)
imagick::COMPRESSION_JPEG (integer)
imagick::COMPRESSION_JPEG2000 (integer)
imagick::COMPRESSION_LOSSLESSJPEG (integer)
imagick::COMPRESSION_LZW (integer)
imagick::COMPRESSION_RLE (integer)
imagick::COMPRESSION_ZIP (integer)
imagick::COMPRESSION_DXT1 (integer)
imagick::COMPRESSION_DXT3 (integer)
imagick::COMPRESSION_DXT5 (integer)
$handle = fopen('http://example.com/foo.jpg', 'rb');
$img = new Imagick();
$img->readImageFile($handle);