1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-24 06:22:57 +02:00

Add option to encode interlaced PNG format

This commit is contained in:
Oliver Vogel
2024-04-14 09:24:26 +02:00
parent 968f9e498e
commit 490b8ae5c4
6 changed files with 62 additions and 4 deletions

View File

@@ -13,8 +13,11 @@ class PngEncoder extends GenericPngEncoder implements SpecializedInterface
{ {
public function encode(ImageInterface $image): EncodedImage public function encode(ImageInterface $image): EncodedImage
{ {
$data = $this->buffered(function () use ($image) { $gd = $image->core()->native();
imagepng($image->core()->native(), null, -1); $data = $this->buffered(function () use ($gd) {
imageinterlace($gd, $this->interlaced);
imagepng($gd, null, -1);
imageinterlace($gd, false);
}); });
return new EncodedImage($data, 'image/png'); return new EncodedImage($data, 'image/png');

View File

@@ -23,6 +23,10 @@ class PngEncoder extends GenericPngEncoder implements SpecializedInterface
$imagick->setCompression($compression); $imagick->setCompression($compression);
$imagick->setImageCompression($compression); $imagick->setImageCompression($compression);
if ($this->interlaced) {
$imagick->setInterlaceScheme(Imagick::INTERLACE_LINE);
}
return new EncodedImage($imagick->getImagesBlob(), 'image/png'); return new EncodedImage($imagick->getImagesBlob(), 'image/png');
} }
} }

View File

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

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Traits;
use Intervention\Image\Traits\CanBuildFilePointer;
trait CanDetectInterlacedPng
{
use CanBuildFilePointer;
/**
* Checks if the given image data is interlaced encoded PNG format
*
* @param string $imagedata
* @return bool
*/
private function isInterlacedPng(string $imagedata): bool
{
$f = $this->buildFilePointer($imagedata);
$contents = fread($f, 32);
fclose($f);
return ord($contents[28]) != 0;
}
}

View File

@@ -8,12 +8,15 @@ use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use Intervention\Image\Encoders\PngEncoder; use Intervention\Image\Encoders\PngEncoder;
use Intervention\Image\Tests\GdTestCase; use Intervention\Image\Tests\GdTestCase;
use Intervention\Image\Tests\Traits\CanDetectInterlacedPng;
#[RequiresPhpExtension('gd')] #[RequiresPhpExtension('gd')]
#[CoversClass(\Intervention\Image\Encoders\PngEncoder::class)] #[CoversClass(\Intervention\Image\Encoders\PngEncoder::class)]
#[CoversClass(\Intervention\Image\Drivers\Gd\Encoders\PngEncoder::class)] #[CoversClass(\Intervention\Image\Drivers\Gd\Encoders\PngEncoder::class)]
final class PngEncoderTest extends GdTestCase final class PngEncoderTest extends GdTestCase
{ {
use CanDetectInterlacedPng;
public function testEncode(): void public function testEncode(): void
{ {
$image = $this->createTestImage(3, 2); $image = $this->createTestImage(3, 2);
@@ -21,4 +24,13 @@ final class PngEncoderTest extends GdTestCase
$result = $encoder->encode($image); $result = $encoder->encode($image);
$this->assertMediaType('image/png', (string) $result); $this->assertMediaType('image/png', (string) $result);
} }
public function testEncodeInterlaced(): void
{
$image = $this->createTestImage(3, 2);
$encoder = new PngEncoder(interlaced: true);
$result = $encoder->encode($image);
$this->assertMediaType('image/png', (string) $result);
$this->assertTrue($this->isInterlacedPng((string) $result));
}
} }

View File

@@ -8,17 +8,29 @@ use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use Intervention\Image\Encoders\PngEncoder; use Intervention\Image\Encoders\PngEncoder;
use Intervention\Image\Tests\ImagickTestCase; use Intervention\Image\Tests\ImagickTestCase;
use Intervention\Image\Tests\Traits\CanDetectInterlacedPng;
#[RequiresPhpExtension('imagick')] #[RequiresPhpExtension('imagick')]
#[CoversClass(\Intervention\Image\Encoders\PngEncoder::class)] #[CoversClass(\Intervention\Image\Encoders\PngEncoder::class)]
#[CoversClass(\Intervention\Image\Drivers\Imagick\Encoders\PngEncoder::class)] #[CoversClass(\Intervention\Image\Drivers\Imagick\Encoders\PngEncoder::class)]
final class PngEncoderTest extends ImagickTestCase final class PngEncoderTest extends ImagickTestCase
{ {
use CanDetectInterlacedPng;
public function testEncode(): void public function testEncode(): void
{ {
$image = $this->createTestImage(3, 2); $image = $this->createTestImage(3, 2);
$encoder = new PngEncoder(75); $encoder = new PngEncoder();
$result = $encoder->encode($image); $result = $encoder->encode($image);
$this->assertMediaType('image/png', (string) $result); $this->assertMediaType('image/png', (string) $result);
} }
public function testEncodeInterlaced(): void
{
$image = $this->createTestImage(3, 2);
$encoder = new PngEncoder(interlaced: true);
$result = $encoder->encode($image);
$this->assertMediaType('image/png', (string) $result);
$this->assertTrue($this->isInterlacedPng((string) $result));
}
} }