Initial commit
This commit is contained in:
21
vendor/intervention/gif/LICENSE
vendored
Executable file
21
vendor/intervention/gif/LICENSE
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020-present Oliver Vogel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
101
vendor/intervention/gif/README.md
vendored
Executable file
101
vendor/intervention/gif/README.md
vendored
Executable file
@@ -0,0 +1,101 @@
|
||||
# Intervention GIF
|
||||
## Native PHP GIF Encoder/Decoder
|
||||
|
||||
[](https://packagist.org/packages/intervention/gif)
|
||||

|
||||
[](https://packagist.org/packages/intervention/gif/stats)
|
||||
[](https://ko-fi.com/interventionphp)
|
||||
|
||||
Intervention GIF is a PHP encoder and decoder for the GIF image format that
|
||||
does not depend on any image processing extension.
|
||||
|
||||
Only the special `Splitter::class` class divides the data stream of an animated
|
||||
GIF into individual `GDImage` objects for each frame and is therefore dependent
|
||||
on the GD library.
|
||||
|
||||
The library is the main component of [Intervention
|
||||
Image](https://github.com/Intervention/image) for processing animated GIF files
|
||||
with the GD library, but also works independently.
|
||||
|
||||
## Installation
|
||||
|
||||
You can easily install this package using [Composer](https://getcomposer.org).
|
||||
Just request the package with the following command:
|
||||
|
||||
```bash
|
||||
composer require intervention/gif
|
||||
```
|
||||
|
||||
## Code Examples
|
||||
|
||||
### Decoding
|
||||
|
||||
```php
|
||||
use Intervention\Gif\Decoder;
|
||||
|
||||
// Decode filepath to Intervention\Gif\GifDataStream::class
|
||||
$gif = Decoder::decode('images/animation.gif');
|
||||
|
||||
// Decoder can also handle binary content directly
|
||||
$gif = Decoder::decode($contents);
|
||||
```
|
||||
|
||||
### Encoding
|
||||
|
||||
Use the Builder class to create a new GIF image.
|
||||
|
||||
```php
|
||||
use Intervention\Gif\Builder;
|
||||
|
||||
// create new gif canvas
|
||||
$gif = Builder::canvas(width: 32, height: 32);
|
||||
|
||||
// add animation frames to canvas
|
||||
$delay = .25; // delay in seconds after next frame is displayed
|
||||
$left = 0; // position offset (left)
|
||||
$top = 0; // position offset (top)
|
||||
|
||||
// add animation frames with optional delay in seconds
|
||||
// and optional position offset for each frame
|
||||
$gif->addFrame('images/frame01.gif', $delay, $left, $top);
|
||||
$gif->addFrame('images/frame02.gif', $delay, $left);
|
||||
$gif->addFrame('images/frame03.gif', $delay);
|
||||
$gif->addFrame('images/frame04.gif');
|
||||
|
||||
// set loop count; 0 for infinite looping
|
||||
$gif->setLoops(12);
|
||||
|
||||
// encode
|
||||
$data = $gif->encode();
|
||||
```
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP >= 8.1
|
||||
|
||||
## Development & Testing
|
||||
|
||||
With this package comes a Docker image to build a test suite and analysis
|
||||
container. To build this container you have to have Docker installed on your
|
||||
system. You can run all tests with this command.
|
||||
|
||||
```bash
|
||||
docker-compose run --rm --build tests
|
||||
```
|
||||
|
||||
Run the static analyzer on the code base.
|
||||
|
||||
```bash
|
||||
docker-compose run --rm --build analysis
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
This library is developed and maintained by [Oliver Vogel](https://intervention.io)
|
||||
|
||||
Thanks to the community of [contributors](https://github.com/Intervention/gif/graphs/contributors) who have helped to improve this project.
|
||||
|
||||
## License
|
||||
|
||||
Intervention GIF is licensed under the [MIT License](LICENSE).
|
||||
44
vendor/intervention/gif/composer.json
vendored
Executable file
44
vendor/intervention/gif/composer.json
vendored
Executable file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "intervention/gif",
|
||||
"description": "Native PHP GIF Encoder/Decoder",
|
||||
"homepage": "https://github.com/intervention/gif",
|
||||
"keywords": [
|
||||
"image",
|
||||
"gd",
|
||||
"gif",
|
||||
"animation"
|
||||
],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Oliver Vogel",
|
||||
"email": "oliver@intervention.io",
|
||||
"homepage": "https://intervention.io/"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.0 || ^11.0 || ^12.0",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"squizlabs/php_codesniffer": "^3.8",
|
||||
"slevomat/coding-standard": "~8.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Intervention\\Gif\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Intervention\\Gif\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
13
vendor/intervention/gif/phpunit.xml.dist
vendored
Executable file
13
vendor/intervention/gif/phpunit.xml.dist
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" beStrictAboutTestsThatDoNotTestAnything="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||
<testsuites>
|
||||
<testsuite name="Unit Tests">
|
||||
<directory suffix=".php">./tests/Unit/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<source>
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</source>
|
||||
</phpunit>
|
||||
40
vendor/intervention/gif/src/AbstractEntity.php
vendored
Normal file
40
vendor/intervention/gif/src/AbstractEntity.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif;
|
||||
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
use Intervention\Gif\Traits\CanDecode;
|
||||
use Intervention\Gif\Traits\CanEncode;
|
||||
use ReflectionClass;
|
||||
use Stringable;
|
||||
|
||||
abstract class AbstractEntity implements Stringable
|
||||
{
|
||||
use CanEncode;
|
||||
use CanDecode;
|
||||
|
||||
public const TERMINATOR = "\x00";
|
||||
|
||||
/**
|
||||
* Get short classname of current instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getShortClassname(): string
|
||||
{
|
||||
return (new ReflectionClass(static::class))->getShortName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast object to string
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->encode();
|
||||
}
|
||||
}
|
||||
10
vendor/intervention/gif/src/AbstractExtension.php
vendored
Normal file
10
vendor/intervention/gif/src/AbstractExtension.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif;
|
||||
|
||||
abstract class AbstractExtension extends AbstractEntity
|
||||
{
|
||||
public const MARKER = "\x21";
|
||||
}
|
||||
95
vendor/intervention/gif/src/Blocks/ApplicationExtension.php
vendored
Normal file
95
vendor/intervention/gif/src/Blocks/ApplicationExtension.php
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractExtension;
|
||||
|
||||
class ApplicationExtension extends AbstractExtension
|
||||
{
|
||||
public const LABEL = "\xFF";
|
||||
|
||||
/**
|
||||
* Application Identifier & Auth Code
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $application = '';
|
||||
|
||||
/**
|
||||
* Data Sub Blocks
|
||||
*
|
||||
* @var array<DataSubBlock>
|
||||
*/
|
||||
protected array $blocks = [];
|
||||
|
||||
/**
|
||||
* Get size of block
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBlockSize(): int
|
||||
{
|
||||
return strlen($this->application);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set application name
|
||||
*
|
||||
* @param string $value
|
||||
* @return ApplicationExtension
|
||||
*/
|
||||
public function setApplication(string $value): self
|
||||
{
|
||||
$this->application = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get application name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getApplication(): string
|
||||
{
|
||||
return $this->application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add block to application extension
|
||||
*
|
||||
* @param DataSubBlock $block
|
||||
* @return ApplicationExtension
|
||||
*/
|
||||
public function addBlock(DataSubBlock $block): self
|
||||
{
|
||||
$this->blocks[] = $block;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set data sub blocks of instance
|
||||
*
|
||||
* @param array<DataSubBlock> $blocks
|
||||
* @return ApplicationExtension
|
||||
*/
|
||||
public function setBlocks(array $blocks): self
|
||||
{
|
||||
$this->blocks = $blocks;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocks of ApplicationExtension
|
||||
*
|
||||
* @return array<DataSubBlock>
|
||||
*/
|
||||
public function getBlocks(): array
|
||||
{
|
||||
return $this->blocks;
|
||||
}
|
||||
}
|
||||
100
vendor/intervention/gif/src/Blocks/Color.php
vendored
Normal file
100
vendor/intervention/gif/src/Blocks/Color.php
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class Color extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param int $r
|
||||
* @param int $g
|
||||
* @param int $b
|
||||
*/
|
||||
public function __construct(
|
||||
protected int $r = 0,
|
||||
protected int $g = 0,
|
||||
protected int $b = 0
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get red value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRed(): int
|
||||
{
|
||||
return $this->r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set red value
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function setRed(int $value): self
|
||||
{
|
||||
$this->r = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get green value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getGreen(): int
|
||||
{
|
||||
return $this->g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set green value
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function setGreen(int $value): self
|
||||
{
|
||||
$this->g = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blue value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBlue(): int
|
||||
{
|
||||
return $this->b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set blue value
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function setBlue(int $value): self
|
||||
{
|
||||
$this->b = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return hash value of current color
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHash(): string
|
||||
{
|
||||
return md5($this->r . $this->g . $this->b);
|
||||
}
|
||||
}
|
||||
140
vendor/intervention/gif/src/Blocks/ColorTable.php
vendored
Normal file
140
vendor/intervention/gif/src/Blocks/ColorTable.php
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class ColorTable extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param array<Color> $colors
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected array $colors = [])
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of current colors
|
||||
*
|
||||
* @return array<Color>
|
||||
*/
|
||||
public function getColors(): array
|
||||
{
|
||||
return array_values($this->colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add color to table
|
||||
*
|
||||
* @param int $r
|
||||
* @param int $g
|
||||
* @param int $b
|
||||
* @return self
|
||||
*/
|
||||
public function addRgb(int $r, int $g, int $b): self
|
||||
{
|
||||
$this->addColor(new Color($r, $g, $b));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add color to table
|
||||
*
|
||||
* @param Color $color
|
||||
* @return self
|
||||
*/
|
||||
public function addColor(Color $color): self
|
||||
{
|
||||
$this->colors[] = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset colors to array of color objects
|
||||
*
|
||||
* @param array<Color> $colors
|
||||
* @return self
|
||||
*/
|
||||
public function setColors(array $colors): self
|
||||
{
|
||||
$this->empty();
|
||||
foreach ($colors as $color) {
|
||||
$this->addColor($color);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count colors of current instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countColors(): int
|
||||
{
|
||||
return count($this->colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if any colors are present on the current table
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasColors(): bool
|
||||
{
|
||||
return $this->countColors() >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty color table
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function empty(): self
|
||||
{
|
||||
$this->colors = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of color table in logical screen descriptor
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLogicalSize(): int
|
||||
{
|
||||
return match ($this->countColors()) {
|
||||
4 => 1,
|
||||
8 => 2,
|
||||
16 => 3,
|
||||
32 => 4,
|
||||
64 => 5,
|
||||
128 => 6,
|
||||
256 => 7,
|
||||
default => 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the number of bytes contained by the current table
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getByteSize(): int
|
||||
{
|
||||
if (!$this->hasColors()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 3 * pow(2, $this->getLogicalSize() + 1);
|
||||
}
|
||||
}
|
||||
52
vendor/intervention/gif/src/Blocks/CommentExtension.php
vendored
Normal file
52
vendor/intervention/gif/src/Blocks/CommentExtension.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractExtension;
|
||||
|
||||
class CommentExtension extends AbstractExtension
|
||||
{
|
||||
public const LABEL = "\xFE";
|
||||
|
||||
/**
|
||||
* Comment blocks
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected array $comments = [];
|
||||
|
||||
/**
|
||||
* Get all or one comment
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getComments(): array
|
||||
{
|
||||
return $this->comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one comment by key
|
||||
*
|
||||
* @param int $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getComment(int $key): mixed
|
||||
{
|
||||
return array_key_exists($key, $this->comments) ? $this->comments[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set comment text
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public function addComment(string $value): self
|
||||
{
|
||||
$this->comments[] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
47
vendor/intervention/gif/src/Blocks/DataSubBlock.php
vendored
Normal file
47
vendor/intervention/gif/src/Blocks/DataSubBlock.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
use Intervention\Gif\Exceptions\FormatException;
|
||||
|
||||
class DataSubBlock extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param string $value
|
||||
* @throws FormatException
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected string $value)
|
||||
{
|
||||
if ($this->getSize() > 255) {
|
||||
throw new FormatException(
|
||||
'Data Sub-Block can not have a block size larger than 255 bytes.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return size of current block
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSize(): int
|
||||
{
|
||||
return strlen($this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return block value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
262
vendor/intervention/gif/src/Blocks/FrameBlock.php
vendored
Normal file
262
vendor/intervention/gif/src/Blocks/FrameBlock.php
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class FrameBlock extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* @var null|GraphicControlExtension $graphicControlExtension
|
||||
*/
|
||||
protected ?GraphicControlExtension $graphicControlExtension = null;
|
||||
|
||||
/**
|
||||
* @var null|ColorTable $colorTable
|
||||
*/
|
||||
protected ?ColorTable $colorTable = null;
|
||||
|
||||
/**
|
||||
* @var null|PlainTextExtension $plainTextExtension
|
||||
*/
|
||||
protected ?PlainTextExtension $plainTextExtension = null;
|
||||
|
||||
/**
|
||||
* @var array<ApplicationExtension> $applicationExtensions
|
||||
*/
|
||||
protected array $applicationExtensions = [];
|
||||
|
||||
/**
|
||||
* @var array<CommentExtension> $commentExtensions
|
||||
*/
|
||||
protected array $commentExtensions = [];
|
||||
|
||||
public function __construct(
|
||||
protected ImageDescriptor $imageDescriptor = new ImageDescriptor(),
|
||||
protected ImageData $imageData = new ImageData()
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
public function addEntity(AbstractEntity $entity): self
|
||||
{
|
||||
return match (true) {
|
||||
$entity instanceof TableBasedImage => $this->setTableBasedImage($entity),
|
||||
$entity instanceof GraphicControlExtension => $this->setGraphicControlExtension($entity),
|
||||
$entity instanceof ImageDescriptor => $this->setImageDescriptor($entity),
|
||||
$entity instanceof ColorTable => $this->setColorTable($entity),
|
||||
$entity instanceof ImageData => $this->setImageData($entity),
|
||||
$entity instanceof PlainTextExtension => $this->setPlainTextExtension($entity),
|
||||
$entity instanceof NetscapeApplicationExtension,
|
||||
$entity instanceof ApplicationExtension => $this->addApplicationExtension($entity),
|
||||
$entity instanceof CommentExtension => $this->addCommentExtension($entity),
|
||||
default => $this,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return application extensions of current frame block
|
||||
*
|
||||
* @return array<ApplicationExtension>
|
||||
*/
|
||||
public function getApplicationExtensions(): array
|
||||
{
|
||||
return $this->applicationExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return comment extensions of current frame block
|
||||
*
|
||||
* @return array<CommentExtension>
|
||||
*/
|
||||
public function getCommentExtensions(): array
|
||||
{
|
||||
return $this->commentExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the graphic control extension
|
||||
*
|
||||
* @param GraphicControlExtension $extension
|
||||
* @return self
|
||||
*/
|
||||
public function setGraphicControlExtension(GraphicControlExtension $extension): self
|
||||
{
|
||||
$this->graphicControlExtension = $extension;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the graphic control extension of the current frame block
|
||||
*
|
||||
* @return null|GraphicControlExtension
|
||||
*/
|
||||
public function getGraphicControlExtension(): ?GraphicControlExtension
|
||||
{
|
||||
return $this->graphicControlExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the image descriptor
|
||||
*
|
||||
* @param ImageDescriptor $descriptor
|
||||
* @return self
|
||||
*/
|
||||
public function setImageDescriptor(ImageDescriptor $descriptor): self
|
||||
{
|
||||
$this->imageDescriptor = $descriptor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image descriptor of the frame block
|
||||
*
|
||||
* @return ImageDescriptor
|
||||
*/
|
||||
public function getImageDescriptor(): ImageDescriptor
|
||||
{
|
||||
return $this->imageDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color table of the current frame block
|
||||
*
|
||||
* @param ColorTable $table
|
||||
* @return FrameBlock
|
||||
*/
|
||||
public function setColorTable(ColorTable $table): self
|
||||
{
|
||||
$this->colorTable = $table;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get color table
|
||||
*
|
||||
* @return null|ColorTable
|
||||
*/
|
||||
public function getColorTable(): ?ColorTable
|
||||
{
|
||||
return $this->colorTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if frame block has color table
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasColorTable(): bool
|
||||
{
|
||||
return !is_null($this->colorTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set image data of frame block
|
||||
*
|
||||
* @param ImageData $data
|
||||
* @return self
|
||||
*/
|
||||
public function setImageData(ImageData $data): self
|
||||
{
|
||||
$this->imageData = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image data of current frame block
|
||||
*
|
||||
* @return ImageData
|
||||
*/
|
||||
public function getImageData(): ImageData
|
||||
{
|
||||
return $this->imageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set plain text extension
|
||||
*
|
||||
* @param PlainTextExtension $extension
|
||||
* @return self
|
||||
*/
|
||||
public function setPlainTextExtension(PlainTextExtension $extension): self
|
||||
{
|
||||
$this->plainTextExtension = $extension;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plain text extension
|
||||
*
|
||||
* @return null|PlainTextExtension
|
||||
*/
|
||||
public function getPlainTextExtension(): ?PlainTextExtension
|
||||
{
|
||||
return $this->plainTextExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given application extension to the current frame block
|
||||
*
|
||||
* @param ApplicationExtension $extension
|
||||
* @return self
|
||||
*/
|
||||
public function addApplicationExtension(ApplicationExtension $extension): self
|
||||
{
|
||||
$this->applicationExtensions[] = $extension;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given comment extension to the current frame block
|
||||
*
|
||||
* @param CommentExtension $extension
|
||||
* @return self
|
||||
*/
|
||||
public function addCommentExtension(CommentExtension $extension): self
|
||||
{
|
||||
$this->commentExtensions[] = $extension;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return netscape extension of the frame block if available
|
||||
*
|
||||
* @return null|NetscapeApplicationExtension
|
||||
*/
|
||||
public function getNetscapeExtension(): ?NetscapeApplicationExtension
|
||||
{
|
||||
$extensions = array_filter(
|
||||
$this->applicationExtensions,
|
||||
fn(ApplicationExtension $extension): bool => $extension instanceof NetscapeApplicationExtension,
|
||||
);
|
||||
|
||||
return count($extensions) ? reset($extensions) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table based image of the current frame block
|
||||
*
|
||||
* @param TableBasedImage $tableBasedImage
|
||||
* @return self
|
||||
*/
|
||||
public function setTableBasedImage(TableBasedImage $tableBasedImage): self
|
||||
{
|
||||
$this->setImageDescriptor($tableBasedImage->getImageDescriptor());
|
||||
|
||||
if ($colorTable = $tableBasedImage->getColorTable()) {
|
||||
$this->setColorTable($colorTable);
|
||||
}
|
||||
|
||||
$this->setImageData($tableBasedImage->getImageData());
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
159
vendor/intervention/gif/src/Blocks/GraphicControlExtension.php
vendored
Normal file
159
vendor/intervention/gif/src/Blocks/GraphicControlExtension.php
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractExtension;
|
||||
use Intervention\Gif\DisposalMethod;
|
||||
|
||||
class GraphicControlExtension extends AbstractExtension
|
||||
{
|
||||
public const LABEL = "\xF9";
|
||||
public const BLOCKSIZE = "\x04";
|
||||
|
||||
/**
|
||||
* Existance flag of transparent color
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $transparentColorExistance = false;
|
||||
|
||||
/**
|
||||
* Transparent color index
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $transparentColorIndex = 0;
|
||||
|
||||
/**
|
||||
* User input flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $userInput = false;
|
||||
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param int $delay
|
||||
* @param DisposalMethod $disposalMethod
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected int $delay = 0,
|
||||
protected DisposalMethod $disposalMethod = DisposalMethod::UNDEFINED,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set delay time (1/100 second)
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function setDelay(int $value): self
|
||||
{
|
||||
$this->delay = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return delay time (1/100 second)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDelay(): int
|
||||
{
|
||||
return $this->delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set disposal method
|
||||
*
|
||||
* @param DisposalMethod $method
|
||||
* @return self
|
||||
*/
|
||||
public function setDisposalMethod(DisposalMethod $method): self
|
||||
{
|
||||
$this->disposalMethod = $method;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get disposal method
|
||||
*
|
||||
* @return DisposalMethod
|
||||
*/
|
||||
public function getDisposalMethod(): DisposalMethod
|
||||
{
|
||||
return $this->disposalMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transparent color index
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTransparentColorIndex(): int
|
||||
{
|
||||
return $this->transparentColorIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set transparent color index
|
||||
*
|
||||
* @param int $index
|
||||
*/
|
||||
public function setTransparentColorIndex(int $index): self
|
||||
{
|
||||
$this->transparentColorIndex = $index;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current transparent color existance
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getTransparentColorExistance(): bool
|
||||
{
|
||||
return $this->transparentColorExistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set existance flag of transparent color
|
||||
*
|
||||
* @param bool $existance
|
||||
*/
|
||||
public function setTransparentColorExistance(bool $existance = true): self
|
||||
{
|
||||
$this->transparentColorExistance = $existance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user input flag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUserInput(): bool
|
||||
{
|
||||
return $this->userInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user input flag
|
||||
*
|
||||
* @param bool $value
|
||||
*/
|
||||
public function setUserInput(bool $value = true): self
|
||||
{
|
||||
$this->userInput = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
42
vendor/intervention/gif/src/Blocks/Header.php
vendored
Normal file
42
vendor/intervention/gif/src/Blocks/Header.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class Header extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Header signature
|
||||
*/
|
||||
public const SIGNATURE = 'GIF';
|
||||
|
||||
/**
|
||||
* Current GIF version
|
||||
*/
|
||||
protected string $version = '89a';
|
||||
|
||||
/**
|
||||
* Set GIF version
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public function setVersion(string $value): self
|
||||
{
|
||||
$this->version = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion(): string
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
}
|
||||
80
vendor/intervention/gif/src/Blocks/ImageData.php
vendored
Normal file
80
vendor/intervention/gif/src/Blocks/ImageData.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class ImageData extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* LZW min. code size
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $lzw_min_code_size;
|
||||
|
||||
/**
|
||||
* Sub blocks
|
||||
*
|
||||
* @var array<DataSubBlock>
|
||||
*/
|
||||
protected array $blocks = [];
|
||||
|
||||
/**
|
||||
* Get LZW min. code size
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLzwMinCodeSize(): int
|
||||
{
|
||||
return $this->lzw_min_code_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lzw min. code size
|
||||
*
|
||||
* @param int $size
|
||||
* @return ImageData
|
||||
*/
|
||||
public function setLzwMinCodeSize(int $size): self
|
||||
{
|
||||
$this->lzw_min_code_size = $size;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current data sub blocks
|
||||
*
|
||||
* @return array<DataSubBlock>
|
||||
*/
|
||||
public function getBlocks(): array
|
||||
{
|
||||
return $this->blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Addd sub block
|
||||
*
|
||||
* @param DataSubBlock $block
|
||||
* @return ImageData
|
||||
*/
|
||||
public function addBlock(DataSubBlock $block): self
|
||||
{
|
||||
$this->blocks[] = $block;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if data sub blocks are present
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasBlocks(): bool
|
||||
{
|
||||
return count($this->blocks) >= 1;
|
||||
}
|
||||
}
|
||||
246
vendor/intervention/gif/src/Blocks/ImageDescriptor.php
vendored
Normal file
246
vendor/intervention/gif/src/Blocks/ImageDescriptor.php
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class ImageDescriptor extends AbstractEntity
|
||||
{
|
||||
public const SEPARATOR = "\x2C";
|
||||
|
||||
/**
|
||||
* Width of frame
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $width = 0;
|
||||
|
||||
/**
|
||||
* Height of frame
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $height = 0;
|
||||
|
||||
/**
|
||||
* Left position of frame
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $left = 0;
|
||||
|
||||
/**
|
||||
* Top position of frame
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $top = 0;
|
||||
|
||||
/**
|
||||
* Determine if frame is interlaced
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $interlaced = false;
|
||||
|
||||
/**
|
||||
* Local color table flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $localColorTableExistance = false;
|
||||
|
||||
/**
|
||||
* Sort flag of local color table
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $localColorTableSorted = false;
|
||||
|
||||
/**
|
||||
* Size of local color table
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $localColorTableSize = 0;
|
||||
|
||||
/**
|
||||
* Get current width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getWidth(): int
|
||||
{
|
||||
return intval($this->width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHeight(): int
|
||||
{
|
||||
return intval($this->height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current Top
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTop(): int
|
||||
{
|
||||
return intval($this->top);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current Left
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLeft(): int
|
||||
{
|
||||
return intval($this->left);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set size of current instance
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
*/
|
||||
public function setSize(int $width, int $height): self
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set position of current instance
|
||||
*
|
||||
* @param int $left
|
||||
* @param int $top
|
||||
*/
|
||||
public function setPosition(int $left, int $top): self
|
||||
{
|
||||
$this->left = $left;
|
||||
$this->top = $top;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if frame is interlaced
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInterlaced(): bool
|
||||
{
|
||||
return $this->interlaced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or unset interlaced value
|
||||
*
|
||||
* @param bool $value
|
||||
*/
|
||||
public function setInterlaced(bool $value = true): self
|
||||
{
|
||||
$this->interlaced = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if local color table is present
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getLocalColorTableExistance(): bool
|
||||
{
|
||||
return $this->localColorTableExistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for getLocalColorTableExistance
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasLocalColorTable(): bool
|
||||
{
|
||||
return $this->getLocalColorTableExistance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set local color table flag
|
||||
*
|
||||
* @param bool $existance
|
||||
* @return self
|
||||
*/
|
||||
public function setLocalColorTableExistance(bool $existance = true): self
|
||||
{
|
||||
$this->localColorTableExistance = $existance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local color table sorted flag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getLocalColorTableSorted(): bool
|
||||
{
|
||||
return $this->localColorTableSorted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set local color table sorted flag
|
||||
*
|
||||
* @param bool $sorted
|
||||
* @return self
|
||||
*/
|
||||
public function setLocalColorTableSorted(bool $sorted = true): self
|
||||
{
|
||||
$this->localColorTableSorted = $sorted;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of local color table
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLocalColorTableSize(): int
|
||||
{
|
||||
return $this->localColorTableSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get byte size of global color table
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLocalColorTableByteSize(): int
|
||||
{
|
||||
return 3 * pow(2, $this->getLocalColorTableSize() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set size of local color table
|
||||
*
|
||||
* @param int $size
|
||||
*/
|
||||
public function setLocalColorTableSize(int $size): self
|
||||
{
|
||||
$this->localColorTableSize = $size;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
254
vendor/intervention/gif/src/Blocks/LogicalScreenDescriptor.php
vendored
Normal file
254
vendor/intervention/gif/src/Blocks/LogicalScreenDescriptor.php
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class LogicalScreenDescriptor extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Width
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $width;
|
||||
|
||||
/**
|
||||
* Height
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $height;
|
||||
|
||||
/**
|
||||
* Global color table flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $globalColorTableExistance = false;
|
||||
|
||||
/**
|
||||
* Sort flag of global color table
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $globalColorTableSorted = false;
|
||||
|
||||
/**
|
||||
* Size of global color table
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $globalColorTableSize = 0;
|
||||
|
||||
/**
|
||||
* Background color index
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $backgroundColorIndex = 0;
|
||||
|
||||
/**
|
||||
* Color resolution
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $bitsPerPixel = 8;
|
||||
|
||||
/**
|
||||
* Pixel aspect ration
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected int $pixelAspectRatio = 0;
|
||||
|
||||
/**
|
||||
* Set size
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
*/
|
||||
public function setSize(int $width, int $height): self
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get width of current instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getWidth(): int
|
||||
{
|
||||
return intval($this->width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get height of current instance
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHeight(): int
|
||||
{
|
||||
return intval($this->height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if global color table is present
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getGlobalColorTableExistance(): bool
|
||||
{
|
||||
return $this->globalColorTableExistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of getGlobalColorTableExistance
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasGlobalColorTable(): bool
|
||||
{
|
||||
return $this->getGlobalColorTableExistance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set global color table flag
|
||||
*
|
||||
* @param bool $existance
|
||||
* @return self
|
||||
*/
|
||||
public function setGlobalColorTableExistance(bool $existance = true): self
|
||||
{
|
||||
$this->globalColorTableExistance = $existance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global color table sorted flag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getGlobalColorTableSorted(): bool
|
||||
{
|
||||
return $this->globalColorTableSorted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set global color table sorted flag
|
||||
*
|
||||
* @param bool $sorted
|
||||
* @return self
|
||||
*/
|
||||
public function setGlobalColorTableSorted(bool $sorted = true): self
|
||||
{
|
||||
$this->globalColorTableSorted = $sorted;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of global color table
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getGlobalColorTableSize(): int
|
||||
{
|
||||
return $this->globalColorTableSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get byte size of global color table
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getGlobalColorTableByteSize(): int
|
||||
{
|
||||
return 3 * pow(2, $this->getGlobalColorTableSize() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set size of global color table
|
||||
*
|
||||
* @param int $size
|
||||
*/
|
||||
public function setGlobalColorTableSize(int $size): self
|
||||
{
|
||||
$this->globalColorTableSize = $size;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get background color index
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBackgroundColorIndex(): int
|
||||
{
|
||||
return $this->backgroundColorIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set background color index
|
||||
*
|
||||
* @param int $index
|
||||
*/
|
||||
public function setBackgroundColorIndex(int $index): self
|
||||
{
|
||||
$this->backgroundColorIndex = $index;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current pixel aspect ration
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPixelAspectRatio(): int
|
||||
{
|
||||
return $this->pixelAspectRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pixel aspect ratio
|
||||
*
|
||||
* @param int $ratio
|
||||
*/
|
||||
public function setPixelAspectRatio(int $ratio): self
|
||||
{
|
||||
$this->pixelAspectRatio = $ratio;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get color resolution
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBitsPerPixel(): int
|
||||
{
|
||||
return $this->bitsPerPixel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set color resolution
|
||||
*
|
||||
* @param int $value
|
||||
*/
|
||||
public function setBitsPerPixel(int $value): self
|
||||
{
|
||||
$this->bitsPerPixel = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
52
vendor/intervention/gif/src/Blocks/NetscapeApplicationExtension.php
vendored
Normal file
52
vendor/intervention/gif/src/Blocks/NetscapeApplicationExtension.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\Exceptions\FormatException;
|
||||
|
||||
class NetscapeApplicationExtension extends ApplicationExtension
|
||||
{
|
||||
public const IDENTIFIER = "NETSCAPE";
|
||||
public const AUTH_CODE = "2.0";
|
||||
public const SUB_BLOCK_PREFIX = "\x01";
|
||||
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @throws FormatException
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setApplication(self::IDENTIFIER . self::AUTH_CODE);
|
||||
$this->setBlocks([new DataSubBlock(self::SUB_BLOCK_PREFIX . "\x00\x00")]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of loops
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLoops(): int
|
||||
{
|
||||
return unpack('v*', substr($this->getBlocks()[0]->getValue(), 1))[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set number of loops
|
||||
*
|
||||
* @param int $loops
|
||||
* @throws FormatException
|
||||
* @return self
|
||||
*/
|
||||
public function setLoops(int $loops): self
|
||||
{
|
||||
$this->setBlocks([
|
||||
new DataSubBlock(self::SUB_BLOCK_PREFIX . pack('v*', $loops))
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
63
vendor/intervention/gif/src/Blocks/PlainTextExtension.php
vendored
Normal file
63
vendor/intervention/gif/src/Blocks/PlainTextExtension.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractExtension;
|
||||
|
||||
class PlainTextExtension extends AbstractExtension
|
||||
{
|
||||
public const LABEL = "\x01";
|
||||
|
||||
/**
|
||||
* Array of text
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected array $text = [];
|
||||
|
||||
/**
|
||||
* Get current text
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getText(): array
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text
|
||||
*
|
||||
* @param string $text
|
||||
*/
|
||||
public function addText(string $text): self
|
||||
{
|
||||
$this->text[] = $text;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set text array of extension
|
||||
*
|
||||
* @param array<string> $text
|
||||
*/
|
||||
public function setText(array $text): self
|
||||
{
|
||||
$this->text = $text;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if any text is present
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasText(): bool
|
||||
{
|
||||
return $this->text !== [];
|
||||
}
|
||||
}
|
||||
50
vendor/intervention/gif/src/Blocks/TableBasedImage.php
vendored
Normal file
50
vendor/intervention/gif/src/Blocks/TableBasedImage.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class TableBasedImage extends AbstractEntity
|
||||
{
|
||||
protected ImageDescriptor $imageDescriptor;
|
||||
protected ?ColorTable $colorTable = null;
|
||||
protected ImageData $imageData;
|
||||
|
||||
public function getImageDescriptor(): ImageDescriptor
|
||||
{
|
||||
return $this->imageDescriptor;
|
||||
}
|
||||
|
||||
public function setImageDescriptor(ImageDescriptor $descriptor): self
|
||||
{
|
||||
$this->imageDescriptor = $descriptor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImageData(): ImageData
|
||||
{
|
||||
return $this->imageData;
|
||||
}
|
||||
|
||||
public function setImageData(ImageData $data): self
|
||||
{
|
||||
$this->imageData = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getColorTable(): ?ColorTable
|
||||
{
|
||||
return $this->colorTable;
|
||||
}
|
||||
|
||||
public function setColorTable(ColorTable $table): self
|
||||
{
|
||||
$this->colorTable = $table;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
12
vendor/intervention/gif/src/Blocks/Trailer.php
vendored
Normal file
12
vendor/intervention/gif/src/Blocks/Trailer.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Blocks;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
|
||||
class Trailer extends AbstractEntity
|
||||
{
|
||||
public const MARKER = "\x3b";
|
||||
}
|
||||
219
vendor/intervention/gif/src/Builder.php
vendored
Normal file
219
vendor/intervention/gif/src/Builder.php
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif;
|
||||
|
||||
use Exception;
|
||||
use Intervention\Gif\Blocks\FrameBlock;
|
||||
use Intervention\Gif\Blocks\GraphicControlExtension;
|
||||
use Intervention\Gif\Blocks\ImageDescriptor;
|
||||
use Intervention\Gif\Blocks\NetscapeApplicationExtension;
|
||||
use Intervention\Gif\Blocks\TableBasedImage;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
use Intervention\Gif\Traits\CanHandleFiles;
|
||||
|
||||
class Builder
|
||||
{
|
||||
use CanHandleFiles;
|
||||
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param GifDataStream $gif
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected GifDataStream $gif = new GifDataStream())
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GifDataStream object we're currently building
|
||||
*
|
||||
* @return GifDataStream
|
||||
*/
|
||||
public function getGifDataStream(): GifDataStream
|
||||
{
|
||||
return $this->gif;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set canvas size of gif
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @return Builder
|
||||
*/
|
||||
public function setSize(int $width, int $height): self
|
||||
{
|
||||
$this->gif->getLogicalScreenDescriptor()->setSize($width, $height);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new canvas
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @return self
|
||||
*/
|
||||
public static function canvas(int $width, int $height): self
|
||||
{
|
||||
return (new self())->setSize($width, $height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set loop count
|
||||
*
|
||||
* @param int $loops
|
||||
* @return Builder
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setLoops(int $loops): self
|
||||
{
|
||||
if ($this->gif->getFrames() === []) {
|
||||
throw new Exception('Add at least one frame before setting the loop count');
|
||||
}
|
||||
|
||||
if ($loops >= 0) {
|
||||
// add frame count to existing or new netscape extension on first frame
|
||||
if (!$this->gif->getFirstFrame()->getNetscapeExtension()) {
|
||||
$this->gif->getFirstFrame()->addApplicationExtension(
|
||||
new NetscapeApplicationExtension()
|
||||
);
|
||||
}
|
||||
$this->gif->getFirstFrame()->getNetscapeExtension()->setLoops($loops);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new animation frame from given source
|
||||
* which can be path to a file or GIF image data
|
||||
*
|
||||
* @param string|resource $source
|
||||
* @param float $delay time delay in seconds
|
||||
* @param int $left position offset in pixels from left
|
||||
* @param int $top position offset in pixels from top
|
||||
* @param bool $interlaced
|
||||
* @throws DecoderException
|
||||
* @return Builder
|
||||
*/
|
||||
public function addFrame(
|
||||
mixed $source,
|
||||
float $delay = 0,
|
||||
int $left = 0,
|
||||
int $top = 0,
|
||||
bool $interlaced = false
|
||||
): self {
|
||||
$frame = new FrameBlock();
|
||||
$source = Decoder::decode($source);
|
||||
|
||||
// store delay
|
||||
$frame->setGraphicControlExtension(
|
||||
$this->buildGraphicControlExtension(
|
||||
$source,
|
||||
intval($delay * 100)
|
||||
)
|
||||
);
|
||||
|
||||
// store image
|
||||
$frame->setTableBasedImage(
|
||||
$this->buildTableBasedImage($source, $left, $top, $interlaced)
|
||||
);
|
||||
|
||||
// add frame
|
||||
$this->gif->addFrame($frame);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build new graphic control extension with given delay & disposal method
|
||||
*
|
||||
* @param GifDataStream $source
|
||||
* @param int $delay
|
||||
* @param DisposalMethod $disposalMethod
|
||||
* @return GraphicControlExtension
|
||||
*/
|
||||
protected function buildGraphicControlExtension(
|
||||
GifDataStream $source,
|
||||
int $delay,
|
||||
DisposalMethod $disposalMethod = DisposalMethod::BACKGROUND
|
||||
): GraphicControlExtension {
|
||||
// create extension
|
||||
$extension = new GraphicControlExtension($delay, $disposalMethod);
|
||||
|
||||
// set transparency index
|
||||
$control = $source->getFirstFrame()->getGraphicControlExtension();
|
||||
if ($control && $control->getTransparentColorExistance()) {
|
||||
$extension->setTransparentColorExistance();
|
||||
$extension->setTransparentColorIndex(
|
||||
$control->getTransparentColorIndex()
|
||||
);
|
||||
}
|
||||
|
||||
return $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build table based image object from given source
|
||||
*
|
||||
* @param GifDataStream $source
|
||||
* @param int $left
|
||||
* @param int $top
|
||||
* @param bool $interlaced
|
||||
* @return TableBasedImage
|
||||
*/
|
||||
protected function buildTableBasedImage(
|
||||
GifDataStream $source,
|
||||
int $left,
|
||||
int $top,
|
||||
bool $interlaced
|
||||
): TableBasedImage {
|
||||
$block = new TableBasedImage();
|
||||
$block->setImageDescriptor(new ImageDescriptor());
|
||||
|
||||
// set global color table from source as local color table
|
||||
$block->getImageDescriptor()->setLocalColorTableExistance();
|
||||
$block->setColorTable($source->getGlobalColorTable());
|
||||
|
||||
$block->getImageDescriptor()->setLocalColorTableSorted(
|
||||
$source->getLogicalScreenDescriptor()->getGlobalColorTableSorted()
|
||||
);
|
||||
|
||||
$block->getImageDescriptor()->setLocalColorTableSize(
|
||||
$source->getLogicalScreenDescriptor()->getGlobalColorTableSize()
|
||||
);
|
||||
|
||||
$block->getImageDescriptor()->setSize(
|
||||
$source->getLogicalScreenDescriptor()->getWidth(),
|
||||
$source->getLogicalScreenDescriptor()->getHeight()
|
||||
);
|
||||
|
||||
// set position
|
||||
$block->getImageDescriptor()->setPosition($left, $top);
|
||||
|
||||
// set interlaced flag
|
||||
$block->getImageDescriptor()->setInterlaced($interlaced);
|
||||
|
||||
// add image data from source
|
||||
$block->setImageData($source->getFirstFrame()->getImageData());
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the current build
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return $this->gif->encode();
|
||||
}
|
||||
}
|
||||
47
vendor/intervention/gif/src/Decoder.php
vendored
Normal file
47
vendor/intervention/gif/src/Decoder.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif;
|
||||
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
use Intervention\Gif\Traits\CanHandleFiles;
|
||||
|
||||
class Decoder
|
||||
{
|
||||
use CanHandleFiles;
|
||||
|
||||
/**
|
||||
* Decode given input
|
||||
*
|
||||
* @param string|resource $input
|
||||
* @throws DecoderException
|
||||
* @return GifDataStream
|
||||
*/
|
||||
public static function decode(mixed $input): GifDataStream
|
||||
{
|
||||
$handle = match (true) {
|
||||
self::isFilePath($input) => self::getHandleFromFilePath($input),
|
||||
is_string($input) => self::getHandleFromData($input),
|
||||
self::isFileHandle($input) => $input,
|
||||
default => throw new DecoderException(
|
||||
'Decoder input must be either file path, file pointer resource or binary data.'
|
||||
)
|
||||
};
|
||||
|
||||
rewind($handle);
|
||||
|
||||
return GifDataStream::decode($handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if input is file pointer resource
|
||||
*
|
||||
* @param mixed $input
|
||||
* @return bool
|
||||
*/
|
||||
private static function isFileHandle(mixed $input): bool
|
||||
{
|
||||
return is_resource($input) && get_resource_type($input) === 'stream';
|
||||
}
|
||||
}
|
||||
165
vendor/intervention/gif/src/Decoders/AbstractDecoder.php
vendored
Normal file
165
vendor/intervention/gif/src/Decoders/AbstractDecoder.php
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
abstract class AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current source
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function decode(): mixed;
|
||||
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param resource $handle
|
||||
* @param null|int $length
|
||||
*/
|
||||
public function __construct(protected $handle, protected ?int $length = null)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Set source to decode
|
||||
*
|
||||
* @param resource $handle
|
||||
*/
|
||||
public function setHandle($handle): self
|
||||
{
|
||||
$this->handle = $handle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read given number of bytes and move file pointer
|
||||
*
|
||||
* @param int $length
|
||||
* @throws DecoderException
|
||||
* @return string
|
||||
*/
|
||||
protected function getNextBytesOrFail(int $length): string
|
||||
{
|
||||
$bytes = fread($this->handle, $length);
|
||||
|
||||
if (strlen($bytes) !== $length) {
|
||||
throw new DecoderException('Unexpected end of file.');
|
||||
}
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read given number of bytes and move pointer back to previous position
|
||||
*
|
||||
* @param int $length
|
||||
* @throws DecoderException
|
||||
* @return string
|
||||
*/
|
||||
protected function viewNextBytesOrFail(int $length): string
|
||||
{
|
||||
$bytes = $this->getNextBytesOrFail($length);
|
||||
$this->movePointer($length * -1);
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read next byte and move pointer back to previous position
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return string
|
||||
*/
|
||||
protected function viewNextByteOrFail(): string
|
||||
{
|
||||
return $this->viewNextBytesOrFail(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all remaining bytes from file handler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRemainingBytes(): string
|
||||
{
|
||||
$all = '';
|
||||
do {
|
||||
$byte = fread($this->handle, 1);
|
||||
$all .= $byte;
|
||||
} while (!feof($this->handle));
|
||||
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next byte in stream and move file pointer
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return string
|
||||
*/
|
||||
protected function getNextByteOrFail(): string
|
||||
{
|
||||
return $this->getNextBytesOrFail(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move file pointer on handle by given offset
|
||||
*
|
||||
* @param int $offset
|
||||
* @return self
|
||||
*/
|
||||
protected function movePointer(int $offset): self
|
||||
{
|
||||
fseek($this->handle, $offset, SEEK_CUR);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode multi byte value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeMultiByte(string $bytes): int
|
||||
{
|
||||
return unpack('v*', $bytes)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set length
|
||||
*
|
||||
* @param int $length
|
||||
*/
|
||||
public function setLength(int $length): self
|
||||
{
|
||||
$this->length = $length;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get length
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
public function getLength(): ?int
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current handle position
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPosition(): int
|
||||
{
|
||||
return ftell($this->handle);
|
||||
}
|
||||
}
|
||||
43
vendor/intervention/gif/src/Decoders/AbstractPackedBitDecoder.php
vendored
Normal file
43
vendor/intervention/gif/src/Decoders/AbstractPackedBitDecoder.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
abstract class AbstractPackedBitDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode packed byte
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodePackedByte(string $byte): int
|
||||
{
|
||||
return unpack('C', $byte)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if packed bit is set
|
||||
*
|
||||
* @param int $num from left to right, starting with 0
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasPackedBit(string $byte, int $num): bool
|
||||
{
|
||||
return (bool) $this->getPackedBits($byte)[$num];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get packed bits
|
||||
*
|
||||
* @param int $start
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
protected function getPackedBits(string $byte, int $start = 0, int $length = 8): string
|
||||
{
|
||||
$bits = str_pad(decbin($this->decodePackedByte($byte)), 8, '0', STR_PAD_LEFT);
|
||||
|
||||
return substr($bits, $start, $length);
|
||||
}
|
||||
}
|
||||
71
vendor/intervention/gif/src/Decoders/ApplicationExtensionDecoder.php
vendored
Normal file
71
vendor/intervention/gif/src/Decoders/ApplicationExtensionDecoder.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\ApplicationExtension;
|
||||
use Intervention\Gif\Blocks\DataSubBlock;
|
||||
use Intervention\Gif\Blocks\NetscapeApplicationExtension;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
use Intervention\Gif\Exceptions\FormatException;
|
||||
|
||||
class ApplicationExtensionDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current source
|
||||
*
|
||||
* @throws FormatException
|
||||
* @throws DecoderException
|
||||
* @return ApplicationExtension
|
||||
*/
|
||||
public function decode(): ApplicationExtension
|
||||
{
|
||||
$result = new ApplicationExtension();
|
||||
|
||||
$this->getNextByteOrFail(); // marker
|
||||
$this->getNextByteOrFail(); // label
|
||||
$blocksize = $this->decodeBlockSize($this->getNextByteOrFail());
|
||||
$application = $this->getNextBytesOrFail($blocksize);
|
||||
|
||||
if ($application === NetscapeApplicationExtension::IDENTIFIER . NetscapeApplicationExtension::AUTH_CODE) {
|
||||
$result = new NetscapeApplicationExtension();
|
||||
|
||||
// skip length
|
||||
$this->getNextByteOrFail();
|
||||
|
||||
$result->setBlocks([
|
||||
new DataSubBlock(
|
||||
$this->getNextBytesOrFail(3)
|
||||
)
|
||||
]);
|
||||
|
||||
// skip terminator
|
||||
$this->getNextByteOrFail();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result->setApplication($application);
|
||||
|
||||
// decode data sub blocks
|
||||
$blocksize = $this->decodeBlockSize($this->getNextByteOrFail());
|
||||
while ($blocksize > 0) {
|
||||
$result->addBlock(new DataSubBlock($this->getNextBytesOrFail($blocksize)));
|
||||
$blocksize = $this->decodeBlockSize($this->getNextByteOrFail());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode block size of ApplicationExtension from given byte
|
||||
*
|
||||
* @param string $byte
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeBlockSize(string $byte): int
|
||||
{
|
||||
return (int) @unpack('C', $byte)[1];
|
||||
}
|
||||
}
|
||||
38
vendor/intervention/gif/src/Decoders/ColorDecoder.php
vendored
Normal file
38
vendor/intervention/gif/src/Decoders/ColorDecoder.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\Color;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class ColorDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current source to Color
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return Color
|
||||
*/
|
||||
public function decode(): Color
|
||||
{
|
||||
$color = new Color();
|
||||
|
||||
$color->setRed($this->decodeColorValue($this->getNextByteOrFail()));
|
||||
$color->setGreen($this->decodeColorValue($this->getNextByteOrFail()));
|
||||
$color->setBlue($this->decodeColorValue($this->getNextByteOrFail()));
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode red value from source
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeColorValue(string $byte): int
|
||||
{
|
||||
return unpack('C', $byte)[1];
|
||||
}
|
||||
}
|
||||
28
vendor/intervention/gif/src/Decoders/ColorTableDecoder.php
vendored
Normal file
28
vendor/intervention/gif/src/Decoders/ColorTableDecoder.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\Color;
|
||||
use Intervention\Gif\Blocks\ColorTable;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class ColorTableDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode given string to ColorTable
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return ColorTable
|
||||
*/
|
||||
public function decode(): ColorTable
|
||||
{
|
||||
$table = new ColorTable();
|
||||
for ($i = 0; $i < ($this->getLength() / 3); $i++) {
|
||||
$table->addColor(Color::decode($this->handle));
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
}
|
||||
61
vendor/intervention/gif/src/Decoders/CommentExtensionDecoder.php
vendored
Normal file
61
vendor/intervention/gif/src/Decoders/CommentExtensionDecoder.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\CommentExtension;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class CommentExtensionDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current source
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return CommentExtension
|
||||
*/
|
||||
public function decode(): CommentExtension
|
||||
{
|
||||
$this->getNextBytesOrFail(2); // skip marker & label
|
||||
|
||||
$extension = new CommentExtension();
|
||||
foreach ($this->decodeComments() as $comment) {
|
||||
$extension->addComment($comment);
|
||||
}
|
||||
|
||||
return $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode comment from current source
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return array<string>
|
||||
*/
|
||||
protected function decodeComments(): array
|
||||
{
|
||||
$comments = [];
|
||||
|
||||
do {
|
||||
$byte = $this->getNextByteOrFail();
|
||||
$size = $this->decodeBlocksize($byte);
|
||||
if ($size > 0) {
|
||||
$comments[] = $this->getNextBytesOrFail($size);
|
||||
}
|
||||
} while ($byte !== CommentExtension::TERMINATOR);
|
||||
|
||||
return $comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode blocksize of following comment
|
||||
*
|
||||
* @param string $byte
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeBlocksize(string $byte): int
|
||||
{
|
||||
return (int) @unpack('C', $byte)[1];
|
||||
}
|
||||
}
|
||||
27
vendor/intervention/gif/src/Decoders/DataSubBlockDecoder.php
vendored
Normal file
27
vendor/intervention/gif/src/Decoders/DataSubBlockDecoder.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\DataSubBlock;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
use Intervention\Gif\Exceptions\FormatException;
|
||||
|
||||
class DataSubBlockDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current sourc
|
||||
*
|
||||
* @throws FormatException
|
||||
* @throws DecoderException
|
||||
* @return DataSubBlock
|
||||
*/
|
||||
public function decode(): DataSubBlock
|
||||
{
|
||||
$char = $this->getNextByteOrFail();
|
||||
$size = (int) unpack('C', $char)[1];
|
||||
|
||||
return new DataSubBlock($this->getNextBytesOrFail($size));
|
||||
}
|
||||
}
|
||||
53
vendor/intervention/gif/src/Decoders/FrameBlockDecoder.php
vendored
Normal file
53
vendor/intervention/gif/src/Decoders/FrameBlockDecoder.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\AbstractExtension;
|
||||
use Intervention\Gif\Blocks\ApplicationExtension;
|
||||
use Intervention\Gif\Blocks\CommentExtension;
|
||||
use Intervention\Gif\Blocks\FrameBlock;
|
||||
use Intervention\Gif\Blocks\GraphicControlExtension;
|
||||
use Intervention\Gif\Blocks\ImageDescriptor;
|
||||
use Intervention\Gif\Blocks\NetscapeApplicationExtension;
|
||||
use Intervention\Gif\Blocks\PlainTextExtension;
|
||||
use Intervention\Gif\Blocks\TableBasedImage;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class FrameBlockDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode FrameBlock
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return FrameBlock
|
||||
*/
|
||||
public function decode(): FrameBlock
|
||||
{
|
||||
$frame = new FrameBlock();
|
||||
|
||||
do {
|
||||
$block = match ($this->viewNextBytesOrFail(2)) {
|
||||
AbstractExtension::MARKER . GraphicControlExtension::LABEL
|
||||
=> GraphicControlExtension::decode($this->handle),
|
||||
AbstractExtension::MARKER . NetscapeApplicationExtension::LABEL
|
||||
=> NetscapeApplicationExtension::decode($this->handle),
|
||||
AbstractExtension::MARKER . ApplicationExtension::LABEL
|
||||
=> ApplicationExtension::decode($this->handle),
|
||||
AbstractExtension::MARKER . PlainTextExtension::LABEL
|
||||
=> PlainTextExtension::decode($this->handle),
|
||||
AbstractExtension::MARKER . CommentExtension::LABEL
|
||||
=> CommentExtension::decode($this->handle),
|
||||
default => match ($this->viewNextByteOrFail()) {
|
||||
ImageDescriptor::SEPARATOR => TableBasedImage::decode($this->handle),
|
||||
default => throw new DecoderException('Unable to decode Data Block'),
|
||||
}
|
||||
};
|
||||
|
||||
$frame->addEntity($block);
|
||||
} while (!($block instanceof TableBasedImage));
|
||||
|
||||
return $frame;
|
||||
}
|
||||
}
|
||||
59
vendor/intervention/gif/src/Decoders/GifDataStreamDecoder.php
vendored
Normal file
59
vendor/intervention/gif/src/Decoders/GifDataStreamDecoder.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
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;
|
||||
use Intervention\Gif\Blocks\Trailer;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
use Intervention\Gif\GifDataStream;
|
||||
|
||||
class GifDataStreamDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current source to GifDataStream
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return GifDataStream
|
||||
*/
|
||||
public function decode(): GifDataStream
|
||||
{
|
||||
$gif = new GifDataStream();
|
||||
|
||||
$gif->setHeader(
|
||||
Header::decode($this->handle),
|
||||
);
|
||||
|
||||
$gif->setLogicalScreenDescriptor(
|
||||
LogicalScreenDescriptor::decode($this->handle),
|
||||
);
|
||||
|
||||
if ($gif->getLogicalScreenDescriptor()->hasGlobalColorTable()) {
|
||||
$length = $gif->getLogicalScreenDescriptor()->getGlobalColorTableByteSize();
|
||||
$gif->setGlobalColorTable(
|
||||
ColorTable::decode($this->handle, $length)
|
||||
);
|
||||
}
|
||||
|
||||
while ($this->viewNextByteOrFail() !== Trailer::MARKER) {
|
||||
match ($this->viewNextBytesOrFail(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;
|
||||
}
|
||||
}
|
||||
97
vendor/intervention/gif/src/Decoders/GraphicControlExtensionDecoder.php
vendored
Normal file
97
vendor/intervention/gif/src/Decoders/GraphicControlExtensionDecoder.php
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\GraphicControlExtension;
|
||||
use Intervention\Gif\DisposalMethod;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class GraphicControlExtensionDecoder extends AbstractPackedBitDecoder
|
||||
{
|
||||
/**
|
||||
* Decode given string to current instance
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return GraphicControlExtension
|
||||
*/
|
||||
public function decode(): GraphicControlExtension
|
||||
{
|
||||
$result = new GraphicControlExtension();
|
||||
|
||||
// bytes 1-3
|
||||
$this->getNextBytesOrFail(3); // skip marker, label & bytesize
|
||||
|
||||
// byte #4
|
||||
$packedField = $this->getNextByteOrFail();
|
||||
$result->setDisposalMethod($this->decodeDisposalMethod($packedField));
|
||||
$result->setUserInput($this->decodeUserInput($packedField));
|
||||
$result->setTransparentColorExistance($this->decodeTransparentColorExistance($packedField));
|
||||
|
||||
// bytes 5-6
|
||||
$result->setDelay($this->decodeDelay($this->getNextBytesOrFail(2)));
|
||||
|
||||
// byte #7
|
||||
$result->setTransparentColorIndex($this->decodeTransparentColorIndex(
|
||||
$this->getNextByteOrFail()
|
||||
));
|
||||
|
||||
// byte #8 (terminator)
|
||||
$this->getNextByteOrFail();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode disposal method
|
||||
*
|
||||
* @return DisposalMethod
|
||||
*/
|
||||
protected function decodeDisposalMethod(string $byte): DisposalMethod
|
||||
{
|
||||
return DisposalMethod::from(
|
||||
bindec($this->getPackedBits($byte, 3, 3))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode user input flag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function decodeUserInput(string $byte): bool
|
||||
{
|
||||
return $this->hasPackedBit($byte, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode transparent color existance
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function decodeTransparentColorExistance(string $byte): bool
|
||||
{
|
||||
return $this->hasPackedBit($byte, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode delay value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeDelay(string $bytes): int
|
||||
{
|
||||
return unpack('v*', $bytes)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode transparent color index
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeTransparentColorIndex(string $byte): int
|
||||
{
|
||||
return unpack('C', $byte)[1];
|
||||
}
|
||||
}
|
||||
42
vendor/intervention/gif/src/Decoders/HeaderDecoder.php
vendored
Normal file
42
vendor/intervention/gif/src/Decoders/HeaderDecoder.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
use Intervention\Gif\Blocks\Header;
|
||||
|
||||
class HeaderDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current sourc
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return Header
|
||||
*/
|
||||
public function decode(): Header
|
||||
{
|
||||
$header = new Header();
|
||||
$header->setVersion($this->decodeVersion());
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode version string
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return string
|
||||
*/
|
||||
protected function decodeVersion(): string
|
||||
{
|
||||
$parsed = (bool) preg_match("/^GIF(?P<version>[0-9]{2}[a-z])$/", $this->getNextBytesOrFail(6), $matches);
|
||||
|
||||
if ($parsed === false) {
|
||||
throw new DecoderException('Unable to parse file header.');
|
||||
}
|
||||
|
||||
return $matches['version'];
|
||||
}
|
||||
}
|
||||
42
vendor/intervention/gif/src/Decoders/ImageDataDecoder.php
vendored
Normal file
42
vendor/intervention/gif/src/Decoders/ImageDataDecoder.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
use Intervention\Gif\Blocks\DataSubBlock;
|
||||
use Intervention\Gif\Blocks\ImageData;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
use Intervention\Gif\Exceptions\FormatException;
|
||||
|
||||
class ImageDataDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current source
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @throws FormatException
|
||||
* @return ImageData
|
||||
*/
|
||||
public function decode(): ImageData
|
||||
{
|
||||
$data = new ImageData();
|
||||
|
||||
// LZW min. code size
|
||||
$char = $this->getNextByteOrFail();
|
||||
$size = (int) unpack('C', $char)[1];
|
||||
$data->setLzwMinCodeSize($size);
|
||||
|
||||
do {
|
||||
// decode sub blocks
|
||||
$char = $this->getNextByteOrFail();
|
||||
$size = (int) unpack('C', $char)[1];
|
||||
if ($size > 0) {
|
||||
$data->addBlock(new DataSubBlock($this->getNextBytesOrFail($size)));
|
||||
}
|
||||
} while ($char !== AbstractEntity::TERMINATOR);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
94
vendor/intervention/gif/src/Decoders/ImageDescriptorDecoder.php
vendored
Normal file
94
vendor/intervention/gif/src/Decoders/ImageDescriptorDecoder.php
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\ImageDescriptor;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class ImageDescriptorDecoder extends AbstractPackedBitDecoder
|
||||
{
|
||||
/**
|
||||
* Decode given string to current instance
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return ImageDescriptor
|
||||
*/
|
||||
public function decode(): ImageDescriptor
|
||||
{
|
||||
$descriptor = new ImageDescriptor();
|
||||
|
||||
$this->getNextByteOrFail(); // skip separator
|
||||
|
||||
$descriptor->setPosition(
|
||||
$this->decodeMultiByte($this->getNextBytesOrFail(2)),
|
||||
$this->decodeMultiByte($this->getNextBytesOrFail(2))
|
||||
);
|
||||
|
||||
$descriptor->setSize(
|
||||
$this->decodeMultiByte($this->getNextBytesOrFail(2)),
|
||||
$this->decodeMultiByte($this->getNextBytesOrFail(2))
|
||||
);
|
||||
|
||||
$packedField = $this->getNextByteOrFail();
|
||||
|
||||
$descriptor->setLocalColorTableExistance(
|
||||
$this->decodeLocalColorTableExistance($packedField)
|
||||
);
|
||||
|
||||
$descriptor->setLocalColorTableSorted(
|
||||
$this->decodeLocalColorTableSorted($packedField)
|
||||
);
|
||||
|
||||
$descriptor->setLocalColorTableSize(
|
||||
$this->decodeLocalColorTableSize($packedField)
|
||||
);
|
||||
|
||||
$descriptor->setInterlaced(
|
||||
$this->decodeInterlaced($packedField)
|
||||
);
|
||||
|
||||
return $descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode local color table existance
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function decodeLocalColorTableExistance(string $byte): bool
|
||||
{
|
||||
return $this->hasPackedBit($byte, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode local color table sort method
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function decodeLocalColorTableSorted(string $byte): bool
|
||||
{
|
||||
return $this->hasPackedBit($byte, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode local color table size
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeLocalColorTableSize(string $byte): int
|
||||
{
|
||||
return bindec($this->getPackedBits($byte, 5, 3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode interlaced flag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function decodeInterlaced(string $byte): bool
|
||||
{
|
||||
return $this->hasPackedBit($byte, 1);
|
||||
}
|
||||
}
|
||||
139
vendor/intervention/gif/src/Decoders/LogicalScreenDescriptorDecoder.php
vendored
Normal file
139
vendor/intervention/gif/src/Decoders/LogicalScreenDescriptorDecoder.php
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\LogicalScreenDescriptor;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class LogicalScreenDescriptorDecoder extends AbstractPackedBitDecoder
|
||||
{
|
||||
/**
|
||||
* Decode given string to current instance
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return LogicalScreenDescriptor
|
||||
*/
|
||||
public function decode(): LogicalScreenDescriptor
|
||||
{
|
||||
$logicalScreenDescriptor = new LogicalScreenDescriptor();
|
||||
|
||||
// bytes 1-4
|
||||
$logicalScreenDescriptor->setSize(
|
||||
$this->decodeWidth($this->getNextBytesOrFail(2)),
|
||||
$this->decodeHeight($this->getNextBytesOrFail(2))
|
||||
);
|
||||
|
||||
// byte 5
|
||||
$packedField = $this->getNextByteOrFail();
|
||||
|
||||
$logicalScreenDescriptor->setGlobalColorTableExistance(
|
||||
$this->decodeGlobalColorTableExistance($packedField)
|
||||
);
|
||||
|
||||
$logicalScreenDescriptor->setBitsPerPixel(
|
||||
$this->decodeBitsPerPixel($packedField)
|
||||
);
|
||||
|
||||
$logicalScreenDescriptor->setGlobalColorTableSorted(
|
||||
$this->decodeGlobalColorTableSorted($packedField)
|
||||
);
|
||||
|
||||
$logicalScreenDescriptor->setGlobalColorTableSize(
|
||||
$this->decodeGlobalColorTableSize($packedField)
|
||||
);
|
||||
|
||||
// byte 6
|
||||
$logicalScreenDescriptor->setBackgroundColorIndex(
|
||||
$this->decodeBackgroundColorIndex($this->getNextByteOrFail())
|
||||
);
|
||||
|
||||
// byte 7
|
||||
$logicalScreenDescriptor->setPixelAspectRatio(
|
||||
$this->decodePixelAspectRatio($this->getNextByteOrFail())
|
||||
);
|
||||
|
||||
return $logicalScreenDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode width
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeWidth(string $source): int
|
||||
{
|
||||
return unpack('v*', $source)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode height
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeHeight(string $source): int
|
||||
{
|
||||
return unpack('v*', $source)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode existance of global color table
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function decodeGlobalColorTableExistance(string $byte): bool
|
||||
{
|
||||
return $this->hasPackedBit($byte, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode color resolution in bits per pixel
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeBitsPerPixel(string $byte): int
|
||||
{
|
||||
return bindec($this->getPackedBits($byte, 1, 3)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode global color table sorted status
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function decodeGlobalColorTableSorted(string $byte): bool
|
||||
{
|
||||
return $this->hasPackedBit($byte, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode size of global color table
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeGlobalColorTableSize(string $byte): int
|
||||
{
|
||||
return bindec($this->getPackedBits($byte, 5, 3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode background color index
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodeBackgroundColorIndex(string $source): int
|
||||
{
|
||||
return unpack('C', $source)[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode pixel aspect ratio
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function decodePixelAspectRatio(string $source): int
|
||||
{
|
||||
return unpack('C', $source)[1];
|
||||
}
|
||||
}
|
||||
9
vendor/intervention/gif/src/Decoders/NetscapeApplicationExtensionDecoder.php
vendored
Normal file
9
vendor/intervention/gif/src/Decoders/NetscapeApplicationExtensionDecoder.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
class NetscapeApplicationExtensionDecoder extends ApplicationExtensionDecoder
|
||||
{
|
||||
}
|
||||
65
vendor/intervention/gif/src/Decoders/PlainTextExtensionDecoder.php
vendored
Normal file
65
vendor/intervention/gif/src/Decoders/PlainTextExtensionDecoder.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\PlainTextExtension;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class PlainTextExtensionDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode current source
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return PlainTextExtension
|
||||
*/
|
||||
public function decode(): PlainTextExtension
|
||||
{
|
||||
$extension = new PlainTextExtension();
|
||||
|
||||
// skip marker & label
|
||||
$this->getNextBytesOrFail(2);
|
||||
|
||||
// skip info block
|
||||
$this->getNextBytesOrFail($this->getInfoBlockSize());
|
||||
|
||||
// text blocks
|
||||
$extension->setText($this->decodeTextBlocks());
|
||||
|
||||
return $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of bytes in header block
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return int
|
||||
*/
|
||||
protected function getInfoBlockSize(): int
|
||||
{
|
||||
return unpack('C', $this->getNextByteOrFail())[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode text sub blocks
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return array<string>
|
||||
*/
|
||||
protected function decodeTextBlocks(): array
|
||||
{
|
||||
$blocks = [];
|
||||
|
||||
do {
|
||||
$char = $this->getNextByteOrFail();
|
||||
$size = (int) unpack('C', $char)[1];
|
||||
if ($size > 0) {
|
||||
$blocks[] = $this->getNextBytesOrFail($size);
|
||||
}
|
||||
} while ($char !== PlainTextExtension::TERMINATOR);
|
||||
|
||||
return $blocks;
|
||||
}
|
||||
}
|
||||
42
vendor/intervention/gif/src/Decoders/TableBasedImageDecoder.php
vendored
Normal file
42
vendor/intervention/gif/src/Decoders/TableBasedImageDecoder.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Decoders;
|
||||
|
||||
use Intervention\Gif\Blocks\ColorTable;
|
||||
use Intervention\Gif\Blocks\ImageData;
|
||||
use Intervention\Gif\Blocks\ImageDescriptor;
|
||||
use Intervention\Gif\Blocks\TableBasedImage;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
class TableBasedImageDecoder extends AbstractDecoder
|
||||
{
|
||||
/**
|
||||
* Decode TableBasedImage
|
||||
*
|
||||
* @throws DecoderException
|
||||
* @return TableBasedImage
|
||||
*/
|
||||
public function decode(): TableBasedImage
|
||||
{
|
||||
$block = new TableBasedImage();
|
||||
|
||||
$block->setImageDescriptor(ImageDescriptor::decode($this->handle));
|
||||
|
||||
if ($block->getImageDescriptor()->hasLocalColorTable()) {
|
||||
$block->setColorTable(
|
||||
ColorTable::decode(
|
||||
$this->handle,
|
||||
$block->getImageDescriptor()->getLocalColorTableByteSize()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$block->setImageData(
|
||||
ImageData::decode($this->handle)
|
||||
);
|
||||
|
||||
return $block;
|
||||
}
|
||||
}
|
||||
13
vendor/intervention/gif/src/DisposalMethod.php
vendored
Normal file
13
vendor/intervention/gif/src/DisposalMethod.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif;
|
||||
|
||||
enum DisposalMethod: int
|
||||
{
|
||||
case UNDEFINED = 0;
|
||||
case NONE = 1; // overlay each frame in sequence
|
||||
case BACKGROUND = 2; // clear to background (as indicated by the logical screen descriptor)
|
||||
case PREVIOUS = 3; // restore the canvas to its previous state
|
||||
}
|
||||
24
vendor/intervention/gif/src/Encoders/AbstractEncoder.php
vendored
Normal file
24
vendor/intervention/gif/src/Encoders/AbstractEncoder.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
abstract class AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param mixed $source
|
||||
*/
|
||||
public function __construct(protected mixed $source)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function encode(): string;
|
||||
}
|
||||
40
vendor/intervention/gif/src/Encoders/ApplicationExtensionEncoder.php
vendored
Normal file
40
vendor/intervention/gif/src/Encoders/ApplicationExtensionEncoder.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\ApplicationExtension;
|
||||
use Intervention\Gif\Blocks\DataSubBlock;
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
|
||||
class ApplicationExtensionEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new decoder instance
|
||||
*
|
||||
* @param ApplicationExtension $source
|
||||
*/
|
||||
public function __construct(ApplicationExtension $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
ApplicationExtension::MARKER,
|
||||
ApplicationExtension::LABEL,
|
||||
pack('C', $this->source->getBlockSize()),
|
||||
$this->source->getApplication(),
|
||||
implode('', array_map(fn(DataSubBlock $block): string => $block->encode(), $this->source->getBlocks())),
|
||||
ApplicationExtension::TERMINATOR,
|
||||
]);
|
||||
}
|
||||
}
|
||||
44
vendor/intervention/gif/src/Encoders/ColorEncoder.php
vendored
Normal file
44
vendor/intervention/gif/src/Encoders/ColorEncoder.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\Color;
|
||||
|
||||
class ColorEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param Color $source
|
||||
*/
|
||||
public function __construct(Color $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
$this->encodeColorValue($this->source->getRed()),
|
||||
$this->encodeColorValue($this->source->getGreen()),
|
||||
$this->encodeColorValue($this->source->getBlue()),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode color value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeColorValue(int $value): string
|
||||
{
|
||||
return pack('C', $value);
|
||||
}
|
||||
}
|
||||
36
vendor/intervention/gif/src/Encoders/ColorTableEncoder.php
vendored
Normal file
36
vendor/intervention/gif/src/Encoders/ColorTableEncoder.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\Color;
|
||||
use Intervention\Gif\Blocks\ColorTable;
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
|
||||
class ColorTableEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param ColorTable $source
|
||||
*/
|
||||
public function __construct(ColorTable $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', array_map(
|
||||
fn(Color $color): string => $color->encode(),
|
||||
$this->source->getColors(),
|
||||
));
|
||||
}
|
||||
}
|
||||
47
vendor/intervention/gif/src/Encoders/CommentExtensionEncoder.php
vendored
Normal file
47
vendor/intervention/gif/src/Encoders/CommentExtensionEncoder.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\CommentExtension;
|
||||
|
||||
class CommentExtensionEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new decoder instance
|
||||
*
|
||||
* @param CommentExtension $source
|
||||
*/
|
||||
public function __construct(CommentExtension $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
CommentExtension::MARKER,
|
||||
CommentExtension::LABEL,
|
||||
$this->encodeComments(),
|
||||
CommentExtension::TERMINATOR,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode comment blocks
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeComments(): string
|
||||
{
|
||||
return implode('', array_map(function (string $comment): string {
|
||||
return pack('C', strlen($comment)) . $comment;
|
||||
}, $this->source->getComments()));
|
||||
}
|
||||
}
|
||||
30
vendor/intervention/gif/src/Encoders/DataSubBlockEncoder.php
vendored
Normal file
30
vendor/intervention/gif/src/Encoders/DataSubBlockEncoder.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\DataSubBlock;
|
||||
|
||||
class DataSubBlockEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param DataSubBlock $source
|
||||
*/
|
||||
public function __construct(DataSubBlock $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return pack('C', $this->source->getSize()) . $this->source->getValue();
|
||||
}
|
||||
}
|
||||
49
vendor/intervention/gif/src/Encoders/FrameBlockEncoder.php
vendored
Normal file
49
vendor/intervention/gif/src/Encoders/FrameBlockEncoder.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\ApplicationExtension;
|
||||
use Intervention\Gif\Blocks\CommentExtension;
|
||||
use Intervention\Gif\Blocks\FrameBlock;
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
|
||||
class FrameBlockEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new decoder instance
|
||||
*
|
||||
* @param FrameBlock $source
|
||||
*/
|
||||
public function __construct(FrameBlock $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws EncoderException
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
$graphicControlExtension = $this->source->getGraphicControlExtension();
|
||||
$colorTable = $this->source->getColorTable();
|
||||
$plainTextExtension = $this->source->getPlainTextExtension();
|
||||
|
||||
return implode('', [
|
||||
implode('', array_map(
|
||||
fn(ApplicationExtension $extension): string => $extension->encode(),
|
||||
$this->source->getApplicationExtensions(),
|
||||
)),
|
||||
implode('', array_map(
|
||||
fn(CommentExtension $extension): string => $extension->encode(),
|
||||
$this->source->getCommentExtensions(),
|
||||
)),
|
||||
$plainTextExtension ? $plainTextExtension->encode() : '',
|
||||
$graphicControlExtension ? $graphicControlExtension->encode() : '',
|
||||
$this->source->getImageDescriptor()->encode(),
|
||||
$colorTable ? $colorTable->encode() : '',
|
||||
$this->source->getImageData()->encode(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
78
vendor/intervention/gif/src/Encoders/GifDataStreamEncoder.php
vendored
Normal file
78
vendor/intervention/gif/src/Encoders/GifDataStreamEncoder.php
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\CommentExtension;
|
||||
use Intervention\Gif\Blocks\FrameBlock;
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
use Intervention\Gif\GifDataStream;
|
||||
|
||||
class GifDataStreamEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param GifDataStream $source
|
||||
*/
|
||||
public function __construct(GifDataStream $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
$this->source->getHeader()->encode(),
|
||||
$this->source->getLogicalScreenDescriptor()->encode(),
|
||||
$this->maybeEncodeGlobalColorTable(),
|
||||
$this->encodeFrames(),
|
||||
$this->encodeComments(),
|
||||
$this->source->getTrailer()->encode(),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function maybeEncodeGlobalColorTable(): string
|
||||
{
|
||||
if (!$this->source->hasGlobalColorTable()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->source->getGlobalColorTable()->encode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode data blocks of source
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeFrames(): string
|
||||
{
|
||||
return implode('', array_map(
|
||||
fn(FrameBlock $frame): string => $frame->encode(),
|
||||
$this->source->getFrames(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode comment extension blocks of source
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeComments(): string
|
||||
{
|
||||
return implode('', array_map(
|
||||
fn(CommentExtension $commentExtension): string => $commentExtension->encode(),
|
||||
$this->source->getComments()
|
||||
));
|
||||
}
|
||||
}
|
||||
73
vendor/intervention/gif/src/Encoders/GraphicControlExtensionEncoder.php
vendored
Normal file
73
vendor/intervention/gif/src/Encoders/GraphicControlExtensionEncoder.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\GraphicControlExtension;
|
||||
|
||||
class GraphicControlExtensionEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param GraphicControlExtension $source
|
||||
*/
|
||||
public function __construct(GraphicControlExtension $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
GraphicControlExtension::MARKER,
|
||||
GraphicControlExtension::LABEL,
|
||||
GraphicControlExtension::BLOCKSIZE,
|
||||
$this->encodePackedField(),
|
||||
$this->encodeDelay(),
|
||||
$this->encodeTransparentColorIndex(),
|
||||
GraphicControlExtension::TERMINATOR,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode delay time
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeDelay(): string
|
||||
{
|
||||
return pack('v*', $this->source->getDelay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode transparent color index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeTransparentColorIndex(): string
|
||||
{
|
||||
return pack('C', $this->source->getTransparentColorIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode packed field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodePackedField(): string
|
||||
{
|
||||
return pack('C', bindec(implode('', [
|
||||
str_pad('0', 3, '0', STR_PAD_LEFT),
|
||||
str_pad(decbin($this->source->getDisposalMethod()->value), 3, '0', STR_PAD_LEFT),
|
||||
(int) $this->source->getUserInput(),
|
||||
(int) $this->source->getTransparentColorExistance(),
|
||||
])));
|
||||
}
|
||||
}
|
||||
30
vendor/intervention/gif/src/Encoders/HeaderEncoder.php
vendored
Normal file
30
vendor/intervention/gif/src/Encoders/HeaderEncoder.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\Header;
|
||||
|
||||
class HeaderEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param Header $source
|
||||
*/
|
||||
public function __construct(Header $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return Header::SIGNATURE . $this->source->getVersion();
|
||||
}
|
||||
}
|
||||
45
vendor/intervention/gif/src/Encoders/ImageDataEncoder.php
vendored
Normal file
45
vendor/intervention/gif/src/Encoders/ImageDataEncoder.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\AbstractEntity;
|
||||
use Intervention\Gif\Blocks\DataSubBlock;
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
use Intervention\Gif\Blocks\ImageData;
|
||||
|
||||
class ImageDataEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param ImageData $source
|
||||
*/
|
||||
public function __construct(ImageData $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
if (!$this->source->hasBlocks()) {
|
||||
throw new EncoderException("No data blocks in ImageData.");
|
||||
}
|
||||
|
||||
return implode('', [
|
||||
pack('C', $this->source->getLzwMinCodeSize()),
|
||||
implode('', array_map(
|
||||
fn(DataSubBlock $block): string => $block->encode(),
|
||||
$this->source->getBlocks(),
|
||||
)),
|
||||
AbstractEntity::TERMINATOR,
|
||||
]);
|
||||
}
|
||||
}
|
||||
113
vendor/intervention/gif/src/Encoders/ImageDescriptorEncoder.php
vendored
Normal file
113
vendor/intervention/gif/src/Encoders/ImageDescriptorEncoder.php
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\ImageDescriptor;
|
||||
|
||||
class ImageDescriptorEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param ImageDescriptor $source
|
||||
*/
|
||||
public function __construct(ImageDescriptor $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
ImageDescriptor::SEPARATOR,
|
||||
$this->encodeLeft(),
|
||||
$this->encodeTop(),
|
||||
$this->encodeWidth(),
|
||||
$this->encodeHeight(),
|
||||
$this->encodePackedField(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode left value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeLeft(): string
|
||||
{
|
||||
return pack('v*', $this->source->getLeft());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode top value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeTop(): string
|
||||
{
|
||||
return pack('v*', $this->source->getTop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode width value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeWidth(): string
|
||||
{
|
||||
return pack('v*', $this->source->getWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode height value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeHeight(): string
|
||||
{
|
||||
return pack('v*', $this->source->getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode size of local color table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeLocalColorTableSize(): string
|
||||
{
|
||||
return str_pad(decbin($this->source->getLocalColorTableSize()), 3, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode reserved field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeReservedField(): string
|
||||
{
|
||||
return str_pad('0', 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode packed field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodePackedField(): string
|
||||
{
|
||||
return pack('C', bindec(implode('', [
|
||||
(int) $this->source->getLocalColorTableExistance(),
|
||||
(int) $this->source->isInterlaced(),
|
||||
(int) $this->source->getLocalColorTableSorted(),
|
||||
$this->encodeReservedField(),
|
||||
$this->encodeLocalColorTableSize(),
|
||||
])));
|
||||
}
|
||||
}
|
||||
111
vendor/intervention/gif/src/Encoders/LogicalScreenDescriptorEncoder.php
vendored
Normal file
111
vendor/intervention/gif/src/Encoders/LogicalScreenDescriptorEncoder.php
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\LogicalScreenDescriptor;
|
||||
|
||||
class LogicalScreenDescriptorEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param LogicalScreenDescriptor $source
|
||||
*/
|
||||
public function __construct(LogicalScreenDescriptor $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
$this->encodeWidth(),
|
||||
$this->encodeHeight(),
|
||||
$this->encodePackedField(),
|
||||
$this->encodeBackgroundColorIndex(),
|
||||
$this->encodePixelAspectRatio(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode width of current instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeWidth(): string
|
||||
{
|
||||
return pack('v*', $this->source->getWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode height of current instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeHeight(): string
|
||||
{
|
||||
return pack('v*', $this->source->getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode background color index of global color table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeBackgroundColorIndex(): string
|
||||
{
|
||||
return pack('C', $this->source->getBackgroundColorIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode pixel aspect ratio
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodePixelAspectRatio(): string
|
||||
{
|
||||
return pack('C', $this->source->getPixelAspectRatio());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return color resolution for encoding
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeColorResolution(): string
|
||||
{
|
||||
return str_pad(decbin($this->source->getBitsPerPixel() - 1), 3, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode size of global color table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeGlobalColorTableSize(): string
|
||||
{
|
||||
return str_pad(decbin($this->source->getGlobalColorTableSize()), 3, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode packed field of current instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodePackedField(): string
|
||||
{
|
||||
return pack('C', bindec(implode('', [
|
||||
(int) $this->source->getGlobalColorTableExistance(),
|
||||
$this->encodeColorResolution(),
|
||||
(int) $this->source->getGlobalColorTableSorted(),
|
||||
$this->encodeGlobalColorTableSize(),
|
||||
])));
|
||||
}
|
||||
}
|
||||
39
vendor/intervention/gif/src/Encoders/NetscapeApplicationExtensionEncoder.php
vendored
Normal file
39
vendor/intervention/gif/src/Encoders/NetscapeApplicationExtensionEncoder.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\ApplicationExtension;
|
||||
use Intervention\Gif\Blocks\DataSubBlock;
|
||||
use Intervention\Gif\Blocks\NetscapeApplicationExtension;
|
||||
|
||||
class NetscapeApplicationExtensionEncoder extends ApplicationExtensionEncoder
|
||||
{
|
||||
/**
|
||||
* Create new decoder instance
|
||||
*
|
||||
* @param NetscapeApplicationExtension $source
|
||||
*/
|
||||
public function __construct(NetscapeApplicationExtension $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
ApplicationExtension::MARKER,
|
||||
ApplicationExtension::LABEL,
|
||||
pack('C', $this->source->getBlockSize()),
|
||||
$this->source->getApplication(),
|
||||
implode('', array_map(fn(DataSubBlock $block): string => $block->encode(), $this->source->getBlocks())),
|
||||
ApplicationExtension::TERMINATOR,
|
||||
]);
|
||||
}
|
||||
}
|
||||
63
vendor/intervention/gif/src/Encoders/PlainTextExtensionEncoder.php
vendored
Normal file
63
vendor/intervention/gif/src/Encoders/PlainTextExtensionEncoder.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\PlainTextExtension;
|
||||
|
||||
class PlainTextExtensionEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param PlainTextExtension $source
|
||||
*/
|
||||
public function __construct(PlainTextExtension $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
if (!$this->source->hasText()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return implode('', [
|
||||
PlainTextExtension::MARKER,
|
||||
PlainTextExtension::LABEL,
|
||||
$this->encodeHead(),
|
||||
$this->encodeTexts(),
|
||||
PlainTextExtension::TERMINATOR,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode head block
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeHead(): string
|
||||
{
|
||||
return "\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode text chunks
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeTexts(): string
|
||||
{
|
||||
return implode('', array_map(
|
||||
fn(string $text): string => pack('C', strlen($text)) . $text,
|
||||
$this->source->getText(),
|
||||
));
|
||||
}
|
||||
}
|
||||
29
vendor/intervention/gif/src/Encoders/TableBasedImageEncoder.php
vendored
Normal file
29
vendor/intervention/gif/src/Encoders/TableBasedImageEncoder.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\TableBasedImage;
|
||||
|
||||
class TableBasedImageEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param TableBasedImage $source
|
||||
*/
|
||||
public function __construct(TableBasedImage $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
public function encode(): string
|
||||
{
|
||||
return implode('', [
|
||||
$this->source->getImageDescriptor()->encode(),
|
||||
$this->source->getColorTable() ? $this->source->getColorTable()->encode() : '',
|
||||
$this->source->getImageData()->encode(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
30
vendor/intervention/gif/src/Encoders/TrailerEncoder.php
vendored
Normal file
30
vendor/intervention/gif/src/Encoders/TrailerEncoder.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Encoders;
|
||||
|
||||
use Intervention\Gif\Blocks\Trailer;
|
||||
|
||||
class TrailerEncoder extends AbstractEncoder
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param Trailer $source
|
||||
*/
|
||||
public function __construct(Trailer $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode current source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return Trailer::MARKER;
|
||||
}
|
||||
}
|
||||
9
vendor/intervention/gif/src/Exceptions/DecoderException.php
vendored
Normal file
9
vendor/intervention/gif/src/Exceptions/DecoderException.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Exceptions;
|
||||
|
||||
class DecoderException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
9
vendor/intervention/gif/src/Exceptions/EncoderException.php
vendored
Normal file
9
vendor/intervention/gif/src/Exceptions/EncoderException.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Exceptions;
|
||||
|
||||
class EncoderException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
9
vendor/intervention/gif/src/Exceptions/FormatException.php
vendored
Normal file
9
vendor/intervention/gif/src/Exceptions/FormatException.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Exceptions;
|
||||
|
||||
class FormatException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
9
vendor/intervention/gif/src/Exceptions/NotReadableException.php
vendored
Normal file
9
vendor/intervention/gif/src/Exceptions/NotReadableException.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Exceptions;
|
||||
|
||||
class NotReadableException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
225
vendor/intervention/gif/src/GifDataStream.php
vendored
Normal file
225
vendor/intervention/gif/src/GifDataStream.php
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
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;
|
||||
use Intervention\Gif\Blocks\NetscapeApplicationExtension;
|
||||
use Intervention\Gif\Blocks\Trailer;
|
||||
|
||||
class GifDataStream extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param Header $header
|
||||
* @param LogicalScreenDescriptor $logicalScreenDescriptor
|
||||
* @param null|ColorTable $globalColorTable
|
||||
* @param array<FrameBlock> $frames
|
||||
* @param array<CommentExtension> $comments
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected Header $header = new Header(),
|
||||
protected LogicalScreenDescriptor $logicalScreenDescriptor = new LogicalScreenDescriptor(),
|
||||
protected ?ColorTable $globalColorTable = null,
|
||||
protected array $frames = [],
|
||||
protected array $comments = []
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get header
|
||||
*
|
||||
* @return Header
|
||||
*/
|
||||
public function getHeader(): Header
|
||||
{
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set header
|
||||
*
|
||||
* @param Header $header
|
||||
*/
|
||||
public function setHeader(Header $header): self
|
||||
{
|
||||
$this->header = $header;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get logical screen descriptor
|
||||
*
|
||||
* @return LogicalScreenDescriptor
|
||||
*/
|
||||
public function getLogicalScreenDescriptor(): LogicalScreenDescriptor
|
||||
{
|
||||
return $this->logicalScreenDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set logical screen descriptor
|
||||
*
|
||||
* @param LogicalScreenDescriptor $descriptor
|
||||
* @return GifDataStream
|
||||
*/
|
||||
public function setLogicalScreenDescriptor(LogicalScreenDescriptor $descriptor): self
|
||||
{
|
||||
$this->logicalScreenDescriptor = $descriptor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return global color table if available else null
|
||||
*
|
||||
* @return null|ColorTable
|
||||
*/
|
||||
public function getGlobalColorTable(): ?ColorTable
|
||||
{
|
||||
return $this->globalColorTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set global color table
|
||||
*
|
||||
* @param ColorTable $table
|
||||
* @return GifDataStream
|
||||
*/
|
||||
public function setGlobalColorTable(ColorTable $table): self
|
||||
{
|
||||
$this->globalColorTable = $table;
|
||||
$this->logicalScreenDescriptor->setGlobalColorTableExistance(true);
|
||||
$this->logicalScreenDescriptor->setGlobalColorTableSize(
|
||||
$table->getLogicalSize()
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get main graphic control extension
|
||||
*
|
||||
* @return NetscapeApplicationExtension
|
||||
*/
|
||||
public function getMainApplicationExtension(): ?NetscapeApplicationExtension
|
||||
{
|
||||
foreach ($this->frames as $frame) {
|
||||
if ($extension = $frame->getNetscapeExtension()) {
|
||||
return $extension;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of frames
|
||||
*
|
||||
* @return array<FrameBlock>
|
||||
*/
|
||||
public function getFrames(): array
|
||||
{
|
||||
return $this->frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of "global" comments
|
||||
*
|
||||
* @return array<CommentExtension>
|
||||
*/
|
||||
public function getComments(): array
|
||||
{
|
||||
return $this->comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return first frame
|
||||
*
|
||||
* @return null|FrameBlock
|
||||
*/
|
||||
public function getFirstFrame(): ?FrameBlock
|
||||
{
|
||||
if (!array_key_exists(0, $this->frames)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->frames[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add frame
|
||||
*
|
||||
* @param FrameBlock $frame
|
||||
* @return GifDataStream
|
||||
*/
|
||||
public function addFrame(FrameBlock $frame): self
|
||||
{
|
||||
$this->frames[] = $frame;
|
||||
|
||||
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
|
||||
*
|
||||
* @param array<FrameBlock> $frames
|
||||
*/
|
||||
public function setFrames(array $frames): self
|
||||
{
|
||||
$this->frames = $frames;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get trailer
|
||||
*
|
||||
* @return Trailer
|
||||
*/
|
||||
public function getTrailer(): Trailer
|
||||
{
|
||||
return new Trailer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if gif is animated
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAnimated(): bool
|
||||
{
|
||||
return count($this->getFrames()) > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if global color table is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasGlobalColorTable(): bool
|
||||
{
|
||||
return !is_null($this->globalColorTable);
|
||||
}
|
||||
}
|
||||
283
vendor/intervention/gif/src/Splitter.php
vendored
Normal file
283
vendor/intervention/gif/src/Splitter.php
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif;
|
||||
|
||||
use ArrayIterator;
|
||||
use GdImage;
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* @implements IteratorAggregate<GifDataStream>
|
||||
*/
|
||||
class Splitter implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Single frames resolved to GifDataStream
|
||||
*
|
||||
* @var array<GifDataStream>
|
||||
*/
|
||||
protected array $frames = [];
|
||||
|
||||
/**
|
||||
* Delays of each frame
|
||||
*
|
||||
* @var array<int>
|
||||
*/
|
||||
protected array $delays = [];
|
||||
|
||||
/**
|
||||
* Create new instance
|
||||
*
|
||||
* @param GifDataStream $stream
|
||||
*/
|
||||
public function __construct(protected GifDataStream $stream)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator
|
||||
*
|
||||
* @return Traversable<GifDataStream>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->frames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get frames
|
||||
*
|
||||
* @return array<GifDataStream>
|
||||
*/
|
||||
public function getFrames(): array
|
||||
{
|
||||
return $this->frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get delays
|
||||
*
|
||||
* @return array<int>
|
||||
*/
|
||||
public function getDelays(): array
|
||||
{
|
||||
return $this->delays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stream of instance
|
||||
*
|
||||
* @param GifDataStream $stream
|
||||
*/
|
||||
public function setStream(GifDataStream $stream): self
|
||||
{
|
||||
$this->stream = $stream;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static constructor method
|
||||
*
|
||||
* @param GifDataStream $stream
|
||||
* @return Splitter
|
||||
*/
|
||||
public static function create(GifDataStream $stream): self
|
||||
{
|
||||
return new self($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split current stream into array of seperate streams for each frame
|
||||
*
|
||||
* @return Splitter
|
||||
*/
|
||||
public function split(): self
|
||||
{
|
||||
$this->frames = [];
|
||||
|
||||
foreach ($this->stream->getFrames() as $frame) {
|
||||
// create separate stream for each frame
|
||||
$gif = Builder::canvas(
|
||||
$this->stream->getLogicalScreenDescriptor()->getWidth(),
|
||||
$this->stream->getLogicalScreenDescriptor()->getHeight()
|
||||
)->getGifDataStream();
|
||||
|
||||
// check if working stream has global color table
|
||||
if ($this->stream->hasGlobalColorTable()) {
|
||||
$gif->setGlobalColorTable($this->stream->getGlobalColorTable());
|
||||
$gif->getLogicalScreenDescriptor()->setGlobalColorTableExistance(true);
|
||||
|
||||
$gif->getLogicalScreenDescriptor()->setGlobalColorTableSorted(
|
||||
$this->stream->getLogicalScreenDescriptor()->getGlobalColorTableSorted()
|
||||
);
|
||||
|
||||
$gif->getLogicalScreenDescriptor()->setGlobalColorTableSize(
|
||||
$this->stream->getLogicalScreenDescriptor()->getGlobalColorTableSize()
|
||||
);
|
||||
|
||||
$gif->getLogicalScreenDescriptor()->setBackgroundColorIndex(
|
||||
$this->stream->getLogicalScreenDescriptor()->getBackgroundColorIndex()
|
||||
);
|
||||
|
||||
$gif->getLogicalScreenDescriptor()->setPixelAspectRatio(
|
||||
$this->stream->getLogicalScreenDescriptor()->getPixelAspectRatio()
|
||||
);
|
||||
|
||||
$gif->getLogicalScreenDescriptor()->setBitsPerPixel(
|
||||
$this->stream->getLogicalScreenDescriptor()->getBitsPerPixel()
|
||||
);
|
||||
}
|
||||
|
||||
// copy original frame
|
||||
$gif->addFrame($frame);
|
||||
|
||||
$this->frames[] = $gif;
|
||||
$this->delays[] = match (is_object($frame->getGraphicControlExtension())) {
|
||||
true => $frame->getGraphicControlExtension()->getDelay(),
|
||||
default => 0,
|
||||
};
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of GD library resources for each frame
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return array<GdImage>
|
||||
*/
|
||||
public function toResources(): array
|
||||
{
|
||||
$resources = [];
|
||||
|
||||
foreach ($this->frames as $frame) {
|
||||
$resource = imagecreatefromstring($frame->encode());
|
||||
imagepalettetotruecolor($resource);
|
||||
imagesavealpha($resource, true);
|
||||
$resources[] = $resource;
|
||||
}
|
||||
|
||||
return $resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of coalesced GD library resources for each frame
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return array<GdImage>
|
||||
*/
|
||||
public function coalesceToResources(): array
|
||||
{
|
||||
$resources = $this->toResources();
|
||||
|
||||
// static gif files don't need to be coalesced
|
||||
if (count($resources) === 1) {
|
||||
return $resources;
|
||||
}
|
||||
|
||||
$width = imagesx($resources[0]);
|
||||
$height = imagesy($resources[0]);
|
||||
$transparent = imagecolortransparent($resources[0]);
|
||||
|
||||
foreach ($resources as $key => $resource) {
|
||||
// get meta data
|
||||
$gif = $this->frames[$key];
|
||||
$descriptor = $gif->getFirstFrame()->getImageDescriptor();
|
||||
$offset_x = $descriptor->getLeft();
|
||||
$offset_y = $descriptor->getTop();
|
||||
$w = $descriptor->getWidth();
|
||||
$h = $descriptor->getHeight();
|
||||
|
||||
if (in_array($this->getDisposalMethod($gif), [DisposalMethod::NONE, DisposalMethod::PREVIOUS])) {
|
||||
if ($key >= 1) {
|
||||
// create normalized gd image
|
||||
$canvas = imagecreatetruecolor($width, $height);
|
||||
if (imagecolortransparent($resource) != -1) {
|
||||
$transparent = imagecolortransparent($resource);
|
||||
} else {
|
||||
$transparent = imagecolorallocatealpha($resource, 255, 0, 255, 127);
|
||||
}
|
||||
|
||||
// fill with transparent
|
||||
imagefill($canvas, 0, 0, $transparent);
|
||||
imagecolortransparent($canvas, $transparent);
|
||||
imagealphablending($canvas, true);
|
||||
|
||||
// insert last as base
|
||||
imagecopy(
|
||||
$canvas,
|
||||
$resources[$key - 1],
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
$width,
|
||||
$height
|
||||
);
|
||||
|
||||
// insert resource
|
||||
imagecopy(
|
||||
$canvas,
|
||||
$resource,
|
||||
$offset_x,
|
||||
$offset_y,
|
||||
0,
|
||||
0,
|
||||
$w,
|
||||
$h
|
||||
);
|
||||
} else {
|
||||
imagealphablending($resource, true);
|
||||
$canvas = $resource;
|
||||
}
|
||||
} else {
|
||||
// create normalized gd image
|
||||
$canvas = imagecreatetruecolor($width, $height);
|
||||
if (imagecolortransparent($resource) != -1) {
|
||||
$transparent = imagecolortransparent($resource);
|
||||
} else {
|
||||
$transparent = imagecolorallocatealpha($resource, 255, 0, 255, 127);
|
||||
}
|
||||
|
||||
// fill with transparent
|
||||
imagefill($canvas, 0, 0, $transparent);
|
||||
imagecolortransparent($canvas, $transparent);
|
||||
imagealphablending($canvas, true);
|
||||
|
||||
// insert frame resource
|
||||
imagecopy(
|
||||
$canvas,
|
||||
$resource,
|
||||
$offset_x,
|
||||
$offset_y,
|
||||
0,
|
||||
0,
|
||||
$w,
|
||||
$h
|
||||
);
|
||||
}
|
||||
|
||||
$resources[$key] = $canvas;
|
||||
}
|
||||
|
||||
return $resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and return disposal method of given gif data stream
|
||||
*
|
||||
* @param GifDataStream $gif
|
||||
* @return DisposalMethod
|
||||
*/
|
||||
private function getDisposalMethod(GifDataStream $gif): DisposalMethod
|
||||
{
|
||||
return $gif->getFirstFrame()->getGraphicControlExtension()->getDisposalMethod();
|
||||
}
|
||||
}
|
||||
53
vendor/intervention/gif/src/Traits/CanDecode.php
vendored
Normal file
53
vendor/intervention/gif/src/Traits/CanDecode.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Traits;
|
||||
|
||||
use Intervention\Gif\Decoders\AbstractDecoder;
|
||||
use Intervention\Gif\Exceptions\DecoderException;
|
||||
|
||||
trait CanDecode
|
||||
{
|
||||
/**
|
||||
* Decode current instance
|
||||
*
|
||||
* @param resource $source
|
||||
* @param null|int $length
|
||||
* @throws DecoderException
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode($source, ?int $length = null): mixed
|
||||
{
|
||||
return self::getDecoder($source, $length)->decode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get decoder for current instance
|
||||
*
|
||||
* @param resource $source
|
||||
* @param null|int $length
|
||||
* @throws DecoderException
|
||||
* @return AbstractDecoder
|
||||
*/
|
||||
protected static function getDecoder($source, ?int $length = null): AbstractDecoder
|
||||
{
|
||||
$classname = self::getDecoderClassname();
|
||||
|
||||
if (!class_exists($classname)) {
|
||||
throw new DecoderException("Decoder for '" . static::class . "' not found.");
|
||||
}
|
||||
|
||||
return new $classname($source, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get classname of decoder for current classname
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getDecoderClassname(): string
|
||||
{
|
||||
return sprintf('Intervention\Gif\Decoders\%sDecoder', self::getShortClassname());
|
||||
}
|
||||
}
|
||||
49
vendor/intervention/gif/src/Traits/CanEncode.php
vendored
Normal file
49
vendor/intervention/gif/src/Traits/CanEncode.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Traits;
|
||||
|
||||
use Intervention\Gif\Encoders\AbstractEncoder;
|
||||
use Intervention\Gif\Exceptions\EncoderException;
|
||||
|
||||
trait CanEncode
|
||||
{
|
||||
/**
|
||||
* Encode current entity
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return string
|
||||
*/
|
||||
public function encode(): string
|
||||
{
|
||||
return $this->getEncoder()->encode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get encoder object for current entity
|
||||
*
|
||||
* @throws EncoderException
|
||||
* @return AbstractEncoder
|
||||
*/
|
||||
protected function getEncoder(): AbstractEncoder
|
||||
{
|
||||
$classname = $this->getEncoderClassname();
|
||||
|
||||
if (!class_exists($classname)) {
|
||||
throw new EncoderException("Encoder for '" . $this::class . "' not found.");
|
||||
}
|
||||
|
||||
return new $classname($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get encoder classname for current entity
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getEncoderClassname(): string
|
||||
{
|
||||
return sprintf('Intervention\Gif\Encoders\%sEncoder', $this->getShortClassname());
|
||||
}
|
||||
}
|
||||
56
vendor/intervention/gif/src/Traits/CanHandleFiles.php
vendored
Normal file
56
vendor/intervention/gif/src/Traits/CanHandleFiles.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Intervention\Gif\Traits;
|
||||
|
||||
trait CanHandleFiles
|
||||
{
|
||||
/**
|
||||
* Determines if input is file path
|
||||
*
|
||||
* @param mixed $input
|
||||
* @return bool
|
||||
*/
|
||||
private static function isFilePath(mixed $input): bool
|
||||
{
|
||||
return is_string($input) && !self::hasNullBytes($input) && @is_file($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if given string contains null bytes
|
||||
*
|
||||
* @param string $string
|
||||
* @return bool
|
||||
*/
|
||||
private static function hasNullBytes(string $string): bool
|
||||
{
|
||||
return str_contains($string, chr(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create file pointer from given gif image data
|
||||
*
|
||||
* @param string $data
|
||||
* @return resource
|
||||
*/
|
||||
private static function getHandleFromData($data)
|
||||
{
|
||||
$handle = fopen('php://temp', 'r+');
|
||||
fwrite($handle, $data);
|
||||
rewind($handle);
|
||||
|
||||
return $handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create file pounter from given file path
|
||||
*
|
||||
* @param string $path
|
||||
* @return resource
|
||||
*/
|
||||
private static function getHandleFromFilePath(string $path)
|
||||
{
|
||||
return fopen($path, 'rb');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user