Intereting Posts
Необычный результат при слиянии двух прозрачных изображений в php Передача переменных $ _GET (или $ _POST) с разбиением на страницы (SESSION не работает) Загрузите Joomla 3.x Framework и модули во внешний файл PHP React / ZMQ / Ratchet – ответ сервера Websocket Как загрузить Ajax в WordPress Использовать PHP в скрипте для отправки данных также Диспетчер тегов Google Странный текст при преобразовании XML-массива в XML Как передать переменные на странице PHP на другую страницу без использования формы? " child pid XXXX сигнал выхода Ошибка сегментации (11)" в apache error.log Неожиданное наблюдение: var_dump () массива помещает ссылки на элементы … с каких пор? Не удается подключиться к PDO с помощью ssl, но mysqli с помощью ssl works Возможная ошибка: значения таблиц API-интерфейсов Facebook отображаются с десятичными точками raw Отправка значений latlng в mysql-запрос для обновления маркеров Google Maps через routeboxer Перенаправить одну страницу из HTTPS в HTTP Как поместить проверку ошибок для simplexml_load_file?

Проблемы с переносом оболочки PHP / 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) { 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; } 

Я экспериментировал с методами класса Imagick, и это то, что я получил до сих пор:

 function Imagick($input, $crop = null, $scale = null, $merge = null, $output = null, $sharp = true) { if (isset($input, $output) === true) { if (is_file($input) === true) { $input = new Imagick($input); } if (is_object($input) === true) { $size = array_values($input->getImageGeometry()); $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($input->getImageWidth() - $size[0], $input->getImageHeight() - $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 = new IMagick(); $image->newImage($scale[0], $scale[1], new ImagickPixel('white')); $input->cropImage($size[0], $size[1], round($crop[0] / 2), round($crop[1] / 2)); $input->resizeImage($scale[0], $scale[1], Imagick::FILTER_LANCZOS, 1); // $image->scaleImage($scale[0], $scale[1]); //if (in_array('icc', $image->getImageProfiles('*', false)) === true) { $version = preg_replace('~([^-]*).*~', '$1', ph()->Value($image->getVersion(), 'versionString')); if (is_file($profile = sprintf('/usr/share/%s/config/sRGB.icm', str_replace(' ', '-', $version))) !== true) { $profile = 'http://www.color.org/sRGB_v4_ICC_preference.icc'; } if ($input->profileImage('icc', file_get_contents($profile)) === true) { $input->setImageColorSpace(Imagick::COLORSPACE_SRGB); } } $image->compositeImage($input, Imagick::COMPOSITE_OVER, 0, 0); if ((isset($merge) === true) && (is_object($merge = new Imagick($merge)) === true)) { $image->compositeImage($merge, Imagick::COMPOSITE_OVER, round(0.95 * $scale[0] - $merge->getImageWidth()), round(0.95 * $scale[1] - $merge->getImageHeight())); } 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); } $image->setImageFormat($type); if (strcmp('jpeg', $type) === 0) { $image->setImageCompression(Imagick::COMPRESSION_JPEG); $image->setImageCompressionQuality($value); $image->stripImage(); } if (strlen($output) > 0) { $image->writeImage($output); } else { echo $image->getImageBlob(); } } } 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; } 

Базовая функциональность (crop / resize / watermark) уже поддерживается, однако у меня все еще есть некоторые проблемы. Поскольку документация по PHP Imagick выглядит отстойной, у меня нет другого выбора, кроме как попытаться объединить все доступные методы и аргументы с пробным и ошибочным методом, что требует много времени.

Мои текущие проблемы / сомнения:


1 – Сохранение прозрачности

В моей первоначальной реализации строки:

 ImageFill($image, 0, 0, IMG_COLOR_TRANSPARENT); ImageSaveAlpha($image, true); ImageAlphaBlending($image, true); 

Эффект сохранения прозрачности при преобразовании прозрачного PNG-изображения в выход PNG. Если, однако, вы пытаетесь преобразовать прозрачное изображение PNG в формат JPEG, прозрачные пиксели должны иметь свой цвет в белый. Пока, с ImageMagick, я смог преобразовать все прозрачные пиксели в белый , но я не могу сохранить прозрачность, если формат вывода поддерживает его.


2 – Сжатие выходных форматов (а именно JPEG и PNG)

Моя первоначальная реализация использует уровень сжатия 9 в PNG и качество 90 в JPEG:

 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 что и аргумент качества – почему? Я также в темноте относительно различий между:

  • Imagick::setCompression() / Imagick::setImageCompression() и
  • Imagick::setCompressionQuality() / Imagick::setImageCompressionQuality()

Какой из них я должен использовать и каковы их отличия? Кроме того, самая важная проблема связана с сжатием PNG, список констант сжатия Imagick, похоже, не поддерживает форматы 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) 

Это краска в заднице, поскольку вывод GD PNG, который имеет размер 100-200 КБ, становится чрезвычайно толще, если вместо него выводится Imagick (размер порядка 2 МБ) …

Есть несколько вопросов по поводу этой проблемы , но я не смог найти какое-либо рабочее решение, которое не полагается на внешние приложения. Это действительно невозможно сделать с ImageMagick ?!


3 – Конверты изображений

В реализации GD я вызываю ImageConvolution() чтобы немного улучшить изображение, я знаю, что у Imagick есть встроенные методы для резкости изображений (у меня еще не было возможности их опробовать), но я хотел бы знать, если Imagick имеет эквивалент функции ImageConvolution() .


4 – Цветные профили

Это не связано с первоначальной реализацией, но я также хотел бы, чтобы все было правильно.

Должен ли я всегда добавлять цветовой профиль sRGB Imagick / International Color Consortium ко всем изображениям? Или это должно быть добавлено только тогда, когда есть (или нет) конкретный цветной профиль?

Кроме того, следует ли удалить существующие цветовые профили?

Я понимаю, что это может быть широкий вопрос, но мое понимание цветовых профилей очень ограничено, и некоторые общие рекомендации по этому вопросу будут очень оценены.


5 – Открытие удаленных изображений

GD изначально поддерживает открытие удаленных изображений либо с помощью функций ImageCreateFrom* , либо с помощью file_get_contents() в сочетании с ImageCreateFromString() как я делаю.

Imagick, похоже, только может открывать локальные изображения или открывать дескрипторы файлов. Есть ли простой способ заставить Imagick читать удаленные изображения (без необходимости открывать и закрывать файлы)?


Если кто-то может пролить свет на любой из этих вопросов, я буду очень благодарен.

Заранее спасибо!

Существует ряд причин, по которым ваши изображения в PNG могут увеличиваться по размеру, наиболее очевидным из которых вы столкнетесь, является неспособность GM / IM передать прозрачность в виде фрагмента tRNS (в основном булевская прозрачность для изображений PNG). К сожалению, разработчики GraphicsMagick и ImageMagick еще не реализовали эту функцию. Я обменялся с ними электронными письмами, поэтому я точно знаю это.

Я знаю, что вы не хотите использовать внешние инструменты, но доверьтесь мне. Изображение / GraphicsMagick действительно плохо при сжатии изображений PNG. Решение, которое я использую, использует GraphicsMagick для управления изображением, а также проверяет, содержит ли изображение прозрачные пиксели, если оно содержит прозрачные пиксели, затем запустите OptiPNG на изображении. OptiPNG увидит, что прозрачность может передаваться как часть tRNS и действовать соответственно. На самом деле вы должны запускать OptiPNG на всех изображениях PNG после использования Image / GraphicsMagick, потому что я обнаружил, что вы можете добиться гораздо большего сжатия. Вы также можете сэкономить место, отключив сглаживание и используя цветовое пространство YUV.

Что касается GM, уменьшающего размер изображений лучше, чем IM, вы должны знать, что GM по умолчанию использует 8-битное цветовое пространство, когда цвет уменьшает изображения, а ImageMagick по умолчанию использует 16 бит. Вот почему GM намного быстрее, чем IM, когда цвет уменьшает изображения до значения более 255 цветов. Возможно, вам нужно проверить количество цветов на каждом изображении после сжатия для подтверждения.

Вы можете использовать optipng (другой инструмент командной строки PNG), чтобы оптимизировать размер ваших файлов PNG.

Поскольку в браузерах ICM не так много поддержки, профили по существу являются пустой тратой пропускной способности. Таким образом, если ваши изображения находятся в sRGB, вы можете безопасно уничтожить профиль, иначе лучше преобразовать изображение в sRGB и затем удалить его профиль.

Причиной удаления профиля изображений sRGB является то, что sRGB является стандартом в Интернете, на компьютерах и принтерах, и даже Firefox применяет цветной профиль sRGB к непомеченным изображениям.

Есть еще одна причина для удаления всех профилей в целом, я не уверен, применимо ли это к вашему делу: если вы планируете смешивать изображения со встроенными профилями с другими изображениями без профиля, например изображениями GIF, которые не могут содержать профиль по определению, вы получите беспорядочный результат в браузере с поддержкой ICC. Он будет отображать некоторые изображения в соответствии с их встроенным цветовым пространством и другими с каким-либо другим цветовым профилем , что приведет к ситуации, когда вы увидите границу между изображением со встроенным профилем ICC с сплошным цветом фона, примыкающим к другому профилю без изображения с тем же цветом цвета фона. Даже если вам удастся получить профиль для каждого изображения на вашей странице, есть много пользователей, которые используют старые браузеры с ограничениями ICC.

Итог: цветовые профили злы. Используйте их только в том случае, если они вам действительно нужны.

Я сказал, что это правильно, только если вы нацеливаете свой сайт на самую широкую аудиторию. В противном случае YMMV.

Я не уверен, что вам все еще нужен ответ, но я пишу библиотеку обработки изображений, которая обертывает GD и Imagick, поэтому я столкнулся с некоторыми из ваших проблем.

2 – Сжатие выходных форматов (а именно JPEG и PNG)

ImageMagick не обеспечивает сжатие для PNG для простого факта, что PNG представляет собой формат без потерь, в отличие от JPEG, который является «потерянным» форматом. Я бы сказал, что ImageMagick правильно понял это.

Просто отбросьте параметр сжимать в PNG и просто поставьте стандартное значение по умолчанию для imagepng в GD.

3 – Конверты изображений

Просто зациклируйте на каждом пикселе с помощью getPixelIterator и выполните ручную свертку. У Wikipedia есть хорошая статья об этом с псевдокодом.

5 – Открытие удаленных изображений

Вы можете открыть изображение отдельно и передать его в Imagick

 $handle = fopen('http://example.com/foo.jpg', 'rb'); $img = new Imagick(); $img->readImageFile($handle);