1
0
mirror of https://github.com/Intervention/image.git synced 2025-01-17 12:18:14 +01:00

Implement 'indexed' option in PNG encoders

This commit is contained in:
Oliver Vogel 2024-08-03 10:56:34 +02:00
parent ce4d2bc75c
commit 66040006f3
No known key found for this signature in database
GPG Key ID: 1B19D214C02D69BB
3 changed files with 116 additions and 15 deletions

View File

@ -4,22 +4,72 @@ declare(strict_types=1);
namespace Intervention\Image\Drivers\Gd\Encoders; namespace Intervention\Image\Drivers\Gd\Encoders;
use GdImage;
use Intervention\Image\Drivers\Gd\Cloner;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Encoders\PngEncoder as GenericPngEncoder; use Intervention\Image\Encoders\PngEncoder as GenericPngEncoder;
use Intervention\Image\Exceptions\AnimationException;
use Intervention\Image\Exceptions\ColorException;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SpecializedInterface; use Intervention\Image\Interfaces\SpecializedInterface;
class PngEncoder extends GenericPngEncoder implements SpecializedInterface class PngEncoder extends GenericPngEncoder implements SpecializedInterface
{ {
/**
* {@inheritdoc}
*
* @see EncoderInterface::encode()
*/
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$gd = $image->core()->native(); $output = $this->prepareOutput($image);
$data = $this->buffered(function () use ($gd) {
imageinterlace($gd, $this->interlaced); // encode
imagepng($gd, null, -1); $data = $this->buffered(function () use ($output) {
imageinterlace($gd, false); imageinterlace($output, $this->interlaced);
imagepng($output, null, -1);
}); });
return new EncodedImage($data, 'image/png'); return new EncodedImage($data, 'image/png');
} }
/**
* Prepare given image instance for PNG format output according to encoder settings
*
* @param ImageInterface $image
* @param bool $indexed
* @throws RuntimeException
* @throws ColorException
* @throws AnimationException
* @return GdImage
*/
private function prepareOutput(ImageInterface $image): GdImage
{
if ($this->indexed === false) {
return Cloner::clone($image->core()->native());
}
// get blending color
$blendingColor = $this->driver()->colorProcessor($image->colorspace())->colorToNative(
$this->driver()->handleInput($this->driver()->config()->blendingColor)
);
// clone output instance
$output = Cloner::cloneEmpty($image->core()->native());
// fill with blending color
imagefill($output, 0, 0, $blendingColor);
// set transparency
imagecolortransparent($output, $blendingColor);
// copy original into output
imagecopy($output, $image->core()->native(), 0, 0, 0, 0, imagesx($output), imagesy($output));
// reduce to indexed color palette
imagetruecolortopalette($output, true, 255);
return $output;
}
} }

View File

@ -5,28 +5,79 @@ declare(strict_types=1);
namespace Intervention\Image\Drivers\Imagick\Encoders; namespace Intervention\Image\Drivers\Imagick\Encoders;
use Imagick; use Imagick;
use ImagickException;
use Intervention\Image\EncodedImage; use Intervention\Image\EncodedImage;
use Intervention\Image\Encoders\PngEncoder as GenericPngEncoder; use Intervention\Image\Encoders\PngEncoder as GenericPngEncoder;
use Intervention\Image\Exceptions\AnimationException;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Exceptions\ColorException;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SpecializedInterface; use Intervention\Image\Interfaces\SpecializedInterface;
class PngEncoder extends GenericPngEncoder implements SpecializedInterface class PngEncoder extends GenericPngEncoder implements SpecializedInterface
{ {
/**
* {@inheritdoc}
*
* @see EncoderInterface::encode()
*/
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$format = 'PNG'; $output = $this->prepareOutput($image);
$compression = Imagick::COMPRESSION_ZIP;
$imagick = $image->core()->native(); $output->setCompression(Imagick::COMPRESSION_ZIP);
$imagick->setFormat($format); $output->setImageCompression(Imagick::COMPRESSION_ZIP);
$imagick->setImageFormat($format);
$imagick->setCompression($compression);
$imagick->setImageCompression($compression);
if ($this->interlaced) { if ($this->interlaced) {
$imagick->setInterlaceScheme(Imagick::INTERLACE_LINE); $output->setInterlaceScheme(Imagick::INTERLACE_LINE);
} }
return new EncodedImage($imagick->getImagesBlob(), 'image/png'); return new EncodedImage($output->getImagesBlob(), 'image/png');
}
/**
* Prepare given image instance for PNG format output according to encoder settings
*
* @param ImageInterface $image
* @throws AnimationException
* @throws RuntimeException
* @throws ColorException
* @throws ImagickException
* @return Imagick
*/
private function prepareOutput(ImageInterface $image): Imagick
{
if ($this->indexed === false) {
$output = clone $image->core()->native();
// ensure to encode PNG image type 6 true color alpha
$output->setFormat('PNG32');
$output->setImageFormat('PNG32');
return $output;
}
// get blending color
$blendingColor = $this->driver()->colorProcessor($image->colorspace())->colorToNative(
$this->driver()->handleInput($this->driver()->config()->blendingColor)
);
// create new image with blending color as background
$output = new Imagick();
$output->newImage($image->width(), $image->height(), $blendingColor, 'PNG');
// set transparency of original image
$output->compositeImage($image->core()->native(), Imagick::COMPOSITE_DSTIN, 0, 0);
$output->transparentPaintImage('#000000', 0, 0, false);
// copy original and create indexed color palette version
$output->compositeImage($image->core()->native(), Imagick::COMPOSITE_DEFAULT, 0, 0);
$output->quantizeImage(255, $output->getImageColorSpace(), 0, false, false);
// ensure to encode PNG image type 3 (indexed)
$output->setFormat('PNG8');
$output->setImageFormat('PNG8');
return $output;
} }
} }

View File

@ -8,7 +8,7 @@ use Intervention\Image\Drivers\SpecializableEncoder;
class PngEncoder extends SpecializableEncoder class PngEncoder extends SpecializableEncoder
{ {
public function __construct(public bool $interlaced = false) public function __construct(public bool $interlaced = false, public bool $indexed = false)
{ {
} }
} }