В настоящее время я пытаюсь преобразовать файл ICO в PNG размером 16x16 пикселей, используя 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);
$im->writeImages($targetFile, true);

Это работает частично. Проблема в том, что файл ICO может содержать несколько изображений, поэтому приведенный выше код создает несколько файлов PNG.

  • Favicon - 0.png
  • Favicon - 1.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 любого размера в PNG размером 16x16 пикселей, используя PHP-Imagick (использование GD не вариант).

< Сильный > Update :

Мое (в настоящее время работает, но, возможно, неоптимальное) решение:

<?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);
1
Sgl 25 Апр 2020 в 17:01

2 ответа

Лучший ответ

Мое окончательное решение:

<?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);
0
Sgl 28 Апр 2020 в 16:56

Обновленный ответ

Перечитывая ваш вопрос, кажется, вы действительно хотите сделать файл PNG из файла ICO. Я прочитал запись в Википедии для файлов ICO и, как обычно, это плохо указанная сложная путаница с закрытыми исходниками Microsoft. Я не могу сказать, идут ли они в каком-то порядке ... сначала наименьшим, либо наибольшим первым, поэтому я думаю, что я бы порекомендовал просто перебрать все изображения в вашем файле ICO, как вы планировали, и получить изображение с самым большим количество пикселей и изменить его до 16x16.

Оригинальный ответ

Слишком много для комментария, возможно, недостаточно для ответа ... Я не использую PHP Imagick во всех случаях, но если вы используете ImageMagick в командной строке в Терминале вы можете установить размеры ICO, например, этот :

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

Сказать, какие разрешения вы хотите встроить в выходной файл. Как я уже сказал, я не использую PHP, но я считаю, что эквивалент это что-то вроде:

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

Извините, я не могу помочь лучше, я просто не настроен на использование PHP и Imagick , но, надеюсь, вы можете решить это отсюда.

1
Mark Setchell 25 Апр 2020 в 18:05