SonataMediaBundle увеличивает размер изображения PNG со следующими настройками:
video_image:
providers:
- sonata.media.provider.image
formats:
medium: { width: 1306, quality: 100 }
Исходный размер изображения составляет 246 КБ (с той же шириной и высотой), а размер «измененного» изображения составляет 3 МБ. Это происходит из-за того, что quality: 100
устанавливает png_compression_level => 0
.
Если я установлю quality: 0
, размер PNG почти в порядке (и изображение выглядит очень хорошо), но сжатие JPG делает изображение похожим на импрессионизм.
Поэтому я решил это с помощью пользовательского изменения размера изображений PNG.
Но при установке png_compression_level => 9
размер сжатого изображения все равно не идеален, 664Кб.
Преобразование изображения PNG в PNG8 решило эту проблему, и размер стал очень приличным - 233 КБ (то есть даже меньше, чем исходное изображение), но у меня возникли некоторые проблемы с альфа-каналом.
Большинство изображений с прозрачностью сжаты нормально, но некоторые из них были повреждены:
исходное изображение (оно белое на прозрачном фоне)
сжатое изображение
Это мой пользовательский ресайзер (код немного уродлив, потому что это всего лишь черновик):
<?php
namespace AppBundle\Resizer;
use Gaufrette\File;
use Imagine\Gd\Image;
use Sonata\MediaBundle\Model\MediaInterface;
use Sonata\MediaBundle\Resizer\SimpleResizer;
class PngCustomResizer extends SimpleResizer
{
public function resize(MediaInterface $media, File $in, File $out, $format, array $settings)
{
/** @var Image $image */
$image = $this->adapter->load($in->getContent());
$thumbnail = $image->thumbnail($this->getBox($media, $settings), $this->mode);
$resource = $thumbnail->getGdResource();
$width = $thumbnail->getSize()->getWidth();
$height = $thumbnail->getSize()->getHeight();
// convert to png8 with alpha
$img = imagecreatetruecolor($width, $height);
$bga = imagecolorallocatealpha($img, 0, 0, 0, 127);
imagecolortransparent($img, $bga);
imagefill($img, 0, 0, $bga);
imagecopy($img, $resource, 0, 0, 0, 0, $width, $height);
imagetruecolortopalette($img, false, 255);
imagealphablending($img, false);
imagesavealpha($img, true);
$optimizedImage = new Image($img, $image->palette(), $image->metadata());
// set quality 0 to set png compression = 9
$content = $optimizedImage->get($format, ['quality' => 0]);
$out->setContent($content, $this->metadata->get($media, $out->getName()));
}
}
Что-то не так с моим кодом, или, может быть, я должен использовать другой способ?
Все, что я хочу, это изменить размер файлов JPG и PNG без увеличения размера и без заметной потери качества.
ОБНОВЛЕНИЕ
imagetruecolortopalette
сбрасывает альфа-значения на 0 или 127, без значений 2-126. Таким образом, края изображения теряют свою гладкость. Я пытаюсь исправить это, устанавливая старое альфа-значение для каждого пикселя, но пока не добился успеха.артефакты на вышеупомянутом изображении проявляются только при уменьшении размера (в данном конфиге "большой палец")
formats: wide: { width: 1306, quality: 95} mobile: { width: 640, quality: 95} thumb: { height: 50 , quality: 95}
так что я предполагаю, что проблема в соединении некоторых не полностью прозрачных пикселей