diff --git a/src/Decoders/GifDataStreamDecoder.php b/src/Decoders/GifDataStreamDecoder.php index 6bec50c..d207d8f 100644 --- a/src/Decoders/GifDataStreamDecoder.php +++ b/src/Decoders/GifDataStreamDecoder.php @@ -4,7 +4,9 @@ namespace Intervention\Gif\Decoders; +use Intervention\Gif\AbstractExtension; use Intervention\Gif\Blocks\ColorTable; +use Intervention\Gif\Blocks\CommentExtension; use Intervention\Gif\Blocks\FrameBlock; use Intervention\Gif\Blocks\Header; use Intervention\Gif\Blocks\LogicalScreenDescriptor; @@ -38,7 +40,16 @@ public function decode(): GifDataStream } while ($this->viewNextByte() != Trailer::MARKER) { - $gif->addFrame(FrameBlock::decode($this->handle)); + match ($this->viewNextBytes(2)) { + // trailing "global" comment blocks which are not part of "FrameBlock" + AbstractExtension::MARKER . CommentExtension::LABEL + => $gif->addComment( + CommentExtension::decode($this->handle) + ), + default => $gif->addFrame( + FrameBlock::decode($this->handle) + ), + }; } return $gif; diff --git a/src/Encoders/GifDataStreamEncoder.php b/src/Encoders/GifDataStreamEncoder.php index 239e6ab..16098f1 100644 --- a/src/Encoders/GifDataStreamEncoder.php +++ b/src/Encoders/GifDataStreamEncoder.php @@ -30,6 +30,7 @@ public function encode(): string $this->source->getLogicalScreenDescriptor()->encode(), $this->maybeEncodeGlobalColorTable(), $this->encodeFrames(), + $this->encodeComments(), $this->source->getTrailer()->encode(), ]); } @@ -54,4 +55,16 @@ protected function encodeFrames(): string return $frame->encode(); }, $this->source->getFrames())); } + + /** + * Encode comment extension blocks of source + * + * @return string + */ + protected function encodeComments(): string + { + return implode('', array_map(function ($commentExtension) { + return $commentExtension->encode(); + }, $this->source->getComments())); + } } diff --git a/src/GifDataStream.php b/src/GifDataStream.php index a180375..1e4a391 100644 --- a/src/GifDataStream.php +++ b/src/GifDataStream.php @@ -5,6 +5,7 @@ namespace Intervention\Gif; use Intervention\Gif\Blocks\ColorTable; +use Intervention\Gif\Blocks\CommentExtension; use Intervention\Gif\Blocks\FrameBlock; use Intervention\Gif\Blocks\Header; use Intervention\Gif\Blocks\LogicalScreenDescriptor; @@ -20,7 +21,8 @@ public function __construct( protected Header $header = new Header(), protected LogicalScreenDescriptor $logicalScreenDescriptor = new LogicalScreenDescriptor(), protected ?ColorTable $globalColorTable = null, - protected array $frames = [] + protected array $frames = [], + protected array $comments = [] ) { } @@ -122,6 +124,16 @@ public function getFrames(): array return $this->frames; } + /** + * Return array of "global" comments + * + * @return array + */ + public function getComments(): array + { + return $this->comments; + } + /** * Return first frame * @@ -149,6 +161,19 @@ public function addFrame(FrameBlock $frame): self return $this; } + /** + * Add comment extension + * + * @param CommentExtension $comment + * @return GifDataStream + */ + public function addComment(CommentExtension $comment): self + { + $this->comments[] = $comment; + + return $this; + } + /** * Set the current data * diff --git a/tests/GifDataStreamTest.php b/tests/GifDataStreamTest.php index be539d2..e295043 100644 --- a/tests/GifDataStreamTest.php +++ b/tests/GifDataStreamTest.php @@ -33,6 +33,7 @@ public function testEncode() $gif = new GifDataStream(); $gif->setLogicalScreenDescriptor($this->getTestLogicalScreenDescriptor()); $gif->addFrame($this->getTestFrame()); + $gif->addComment($this->getTestCommentExtension()); $result = implode('', [ (string) $this->getTestHeader(), @@ -42,6 +43,7 @@ public function testEncode() (string) $this->getTestGraphicControlExtension(), (string) $this->getTestImageDescriptor(), (string) $this->getTestImageData(), + (string) $this->getTestCommentExtension(), Trailer::MARKER, ]); @@ -153,4 +155,16 @@ public function testDecode() }, $gif->getFrames())); $this->assertEquals([0, 0, 0, 0, 0, 0, 0, 0], $sizes); } + + public function testDecodeTrailingComment(): void + { + $gif = GifDataStream::decode( + $this->getTestHandle( + file_get_contents(__DIR__ . '/images/animation_trailing_comment.gif') + ), + ); + + $this->assertInstanceOf(GifDataStream::class, $gif); + $this->assertCount(1, $gif->getComments()); + } } diff --git a/tests/images/animation_trailing_comment.gif b/tests/images/animation_trailing_comment.gif new file mode 100644 index 0000000..9387e5f Binary files /dev/null and b/tests/images/animation_trailing_comment.gif differ