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:
parent
ce4d2bc75c
commit
66040006f3
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user