Skip to content

Commit

Permalink
Add option to encode interlaced PNG format
Browse files Browse the repository at this point in the history
  • Loading branch information
olivervogel committed Apr 14, 2024
1 parent 968f9e4 commit 490b8ae
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 4 deletions.
7 changes: 5 additions & 2 deletions src/Drivers/Gd/Encoders/PngEncoder.php
Expand Up @@ -13,8 +13,11 @@ class PngEncoder extends GenericPngEncoder implements SpecializedInterface
{
public function encode(ImageInterface $image): EncodedImage
{
$data = $this->buffered(function () use ($image) {
imagepng($image->core()->native(), null, -1);
$gd = $image->core()->native();
$data = $this->buffered(function () use ($gd) {
imageinterlace($gd, $this->interlaced);
imagepng($gd, null, -1);
imageinterlace($gd, false);
});

return new EncodedImage($data, 'image/png');
Expand Down
4 changes: 4 additions & 0 deletions src/Drivers/Imagick/Encoders/PngEncoder.php
Expand Up @@ -23,6 +23,10 @@ public function encode(ImageInterface $image): EncodedImage
$imagick->setCompression($compression);
$imagick->setImageCompression($compression);

if ($this->interlaced) {
$imagick->setInterlaceScheme(Imagick::INTERLACE_LINE);
}

return new EncodedImage($imagick->getImagesBlob(), 'image/png');
}
}
2 changes: 1 addition & 1 deletion src/Encoders/PngEncoder.php
Expand Up @@ -8,7 +8,7 @@

class PngEncoder extends SpecializableEncoder
{
public function __construct()
public function __construct(public bool $interlaced = false)
{
}
}
27 changes: 27 additions & 0 deletions tests/Traits/CanDetectInterlacedPng.php
@@ -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;
}
}
12 changes: 12 additions & 0 deletions tests/Unit/Drivers/Gd/Encoders/PngEncoderTest.php
Expand Up @@ -8,17 +8,29 @@
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use Intervention\Image\Encoders\PngEncoder;
use Intervention\Image\Tests\GdTestCase;
use Intervention\Image\Tests\Traits\CanDetectInterlacedPng;

#[RequiresPhpExtension('gd')]
#[CoversClass(\Intervention\Image\Encoders\PngEncoder::class)]
#[CoversClass(\Intervention\Image\Drivers\Gd\Encoders\PngEncoder::class)]
final class PngEncoderTest extends GdTestCase
{
use CanDetectInterlacedPng;

public function testEncode(): void
{
$image = $this->createTestImage(3, 2);
$encoder = new PngEncoder();
$result = $encoder->encode($image);
$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));
}
}
14 changes: 13 additions & 1 deletion tests/Unit/Drivers/Imagick/Encoders/PngEncoderTest.php
Expand Up @@ -8,17 +8,29 @@
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use Intervention\Image\Encoders\PngEncoder;
use Intervention\Image\Tests\ImagickTestCase;
use Intervention\Image\Tests\Traits\CanDetectInterlacedPng;

#[RequiresPhpExtension('imagick')]
#[CoversClass(\Intervention\Image\Encoders\PngEncoder::class)]
#[CoversClass(\Intervention\Image\Drivers\Imagick\Encoders\PngEncoder::class)]
final class PngEncoderTest extends ImagickTestCase
{
use CanDetectInterlacedPng;

public function testEncode(): void
{
$image = $this->createTestImage(3, 2);
$encoder = new PngEncoder(75);
$encoder = new PngEncoder();
$result = $encoder->encode($image);
$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));
}
}

0 comments on commit 490b8ae

Please sign in to comment.