使用 PHP Imagick 将 ICO 转换为 PNG

Convert ICO to PNG using PHP Imagick

我目前正在尝试使用 PHP-Imagick 将 ICO 文件转换为 16x16 像素的 PNG。到目前为止我尝试了什么:

<?php
if (empty(\Imagick::queryFormats("ICO"))) {
    throw new \Exception('Unsupported format');
}

$sourceFile = __DIR__ . '/favicon.ico';
$targetFile = __DIR__ . '/favicon.png';

$im = new \Imagick($sourceFile);
$im->writeImages($targetFile, true);

部分有效。问题是,一个 ICO 文件可能包含多个图像,所以上面的代码创建了多个 PNG 文件

每个尺码。这没关系,但是,我需要找到接近 16x16 像素的那个,缩小它(如果需要)并删除所有其他的。为此,我已经尝试了一些方法,这就是我目前遇到的问题:

<?php
if (empty(\Imagick::queryFormats("ICO"))) {
    throw new \Exception('Unsupported format');
}

$sourceFile = __DIR__ . '/favicon.ico';
$targetFile = __DIR__ . '/favicon.png';

$im = new \Imagick($sourceFile);
$count = $im->getNumberImages();

if ($count > 1) {
    for ($x = 1; $x <= $count; $x++) {
        $im->previousImage();

        $tmpImageWidth = $im->getImageWidth();
        $tmpImageHeight = $im->getImageHeight();

        // ???
    }
}

$im->writeImages($targetFile, true);

我想,我会通过反复试验找到一种可行的方法。但我想知道,是否有更简单的方法来实现这一点。

TL;DR:我需要一种简单的方法将任意大小的 ICO 文件转换为 16x16 像素的 PNG,使用 PHP-Imagick(不能使用 GD)。

更新:

我的(目前有效但可能不是最佳的)解决方案:

<?php
if (empty(\Imagick::queryFormats("ICO"))) {
    throw new \Exception('Unsupported format');
}

$sourceFile = __DIR__ . '/favicon.ico';
$targetFile = __DIR__ . '/favicon.png';

$im = new \Imagick($sourceFile);
$count = $im->getNumberImages();
$targetWidth = $targetHeight = 16;

if ($count > 1) {
    $images = [];

    for ($x = 1; $x <= $count; $x++) {
        $im->previousImage();

        $images[] = [
            'object' => $im,
            'size' => $im->getImageWidth() + $im->getImageHeight()
        ];
    }

    $minSize = min(array_column($images, 'size'));
    $image = array_values(array_filter($images, function($image) use ($minSize) {
        return $minSize === $image['size'];
    }))[0];

    $im = $image['object'];

    if ($image['size'] <> $targetWidth + $targetHeight) {
        $im->cropThumbnailImage($targetWidth, $targetHeight);
    }
}
else {
    if ($im->getImageWidth() <> $targetWidth || $im->getImageHeight() <> $targetHeight) {
        $im->cropThumbnailImage($targetWidth, $targetHeight);
    }
}

$im->writeImage($targetFile);

更新答案

重新阅读您的问题后,您似乎真的想从 ICO 文件制作 PNG 文件。我已经阅读了 Wikipedia entry for ICO files 并且和往常一样,它是一团乱七八糟的封闭源 Microsoft 东西。我不知道它们是按某种顺序出现的……最小的在前,还是最大的在前,所以我认为我的建议是按照您的计划简单地遍历 ICO 文件中的所有图像,并获得最大的图像像素数并将其调整为 16x16。

原答案

太多的评论,也许还不够回答...我根本不使用 PHP Imagick,但是如果你使用 ImageMagick 在终端的命令行中,您可以设置 ICO 大小,如 this:

magick INPUT -define icon:auto-resize="256,128,96,64,16" output.ico

说明您希望在输出文件中嵌入什么分辨率。正如我所说,我不使用 PHP,但我相信等同于:

$imagick->setOption('icon:auto-resize', "16");

抱歉,我帮不上忙,我只是没有设置使用 PHP 和 Imagick,但希望你能从这里解决。

我的最终解决方案:

<?php
if (empty(\Imagick::queryFormats("ICO"))) {
    throw new \Exception('Unsupported format');
}

$sourceFile = __DIR__ . '/favicon.ico';
$targetFile = __DIR__ . '/favicon.png';

$im = new \Imagick($sourceFile);
$count = $im->getNumberImages();
$targetWidth = $targetHeight = 16;

if ($count > 1) {
    $images = [];

    for ($x = 1; $x <= $count; $x++) {
        $im->previousImage();

        $images[] = [
            'object' => $im,
            'size' => $im->getImageWidth() + $im->getImageHeight()
        ];
    }

    $minSize = min(array_column($images, 'size'));
    $image = array_values(array_filter($images, function($image) use ($minSize) {
        return $minSize === $image['size'];
    }))[0];

    $im = $image['object'];

    if ($image['size'] <> $targetWidth + $targetHeight) {
        $im->cropThumbnailImage($targetWidth, $targetHeight);
    }
}
else {
    if ($im->getImageWidth() <> $targetWidth || $im->getImageHeight() <> $targetHeight) {
        $im->cropThumbnailImage($targetWidth, $targetHeight);
    }
}

$im->writeImage($targetFile);