diff --git a/.gitignore b/.gitignore index a72d87b..895c1a9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ composer.lock runtime /.htaccess /public/nginx.htaccess +/public/children_meals_cookbook +/public/teaching_video +/public/food_img +/public/kitchenscale_all diff --git a/vendor/bacon/bacon-qr-code/LICENSE b/vendor/bacon/bacon-qr-code/LICENSE new file mode 100644 index 0000000..d45a356 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2017, Ben Scholzen 'DASPRiD' +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/bacon/bacon-qr-code/README.md b/vendor/bacon/bacon-qr-code/README.md new file mode 100644 index 0000000..9c099fe --- /dev/null +++ b/vendor/bacon/bacon-qr-code/README.md @@ -0,0 +1,39 @@ +# QR Code generator + +[![PHP CI](https://github.com/Bacon/BaconQrCode/actions/workflows/ci.yml/badge.svg)](https://github.com/Bacon/BaconQrCode/actions/workflows/ci.yml) +[![codecov](https://codecov.io/gh/Bacon/BaconQrCode/branch/master/graph/badge.svg?token=rD0HcAiEEx)](https://codecov.io/gh/Bacon/BaconQrCode) +[![Latest Stable Version](https://poser.pugx.org/bacon/bacon-qr-code/v/stable)](https://packagist.org/packages/bacon/bacon-qr-code) +[![Total Downloads](https://poser.pugx.org/bacon/bacon-qr-code/downloads)](https://packagist.org/packages/bacon/bacon-qr-code) +[![License](https://poser.pugx.org/bacon/bacon-qr-code/license)](https://packagist.org/packages/bacon/bacon-qr-code) + + +## Introduction +BaconQrCode is a port of QR code portion of the ZXing library. It currently +only features the encoder part, but could later receive the decoder part as +well. + +As the Reed Solomon codec implementation of the ZXing library performs quite +slow in PHP, it was exchanged with the implementation by Phil Karn. + + +## Example usage +```php +use BaconQrCode\Renderer\ImageRenderer; +use BaconQrCode\Renderer\Image\ImagickImageBackEnd; +use BaconQrCode\Renderer\RendererStyle\RendererStyle; +use BaconQrCode\Writer; + +$renderer = new ImageRenderer( + new RendererStyle(400), + new ImagickImageBackEnd() +); +$writer = new Writer($renderer); +$writer->writeFile('Hello World!', 'qrcode.png'); +``` + +## Available image renderer back ends +BaconQrCode comes with multiple back ends for rendering images. Currently included are the following: + +- `ImagickImageBackEnd`: renders raster images using the Imagick library +- `SvgImageBackEnd`: renders SVG files using XMLWriter +- `EpsImageBackEnd`: renders EPS files diff --git a/vendor/bacon/bacon-qr-code/composer.json b/vendor/bacon/bacon-qr-code/composer.json new file mode 100644 index 0000000..7f193da --- /dev/null +++ b/vendor/bacon/bacon-qr-code/composer.json @@ -0,0 +1,44 @@ +{ + "name": "bacon/bacon-qr-code", + "description": "BaconQrCode is a QR code generator for PHP.", + "license" : "BSD-2-Clause", + "homepage": "https://github.com/Bacon/BaconQrCode", + "require": { + "php": "^7.1 || ^8.0", + "ext-iconv": "*", + "dasprid/enum": "^1.0.3" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "require-dev": { + "phpunit/phpunit": "^7 | ^8 | ^9", + "spatie/phpunit-snapshot-assertions": "^4.2.9", + "squizlabs/php_codesniffer": "^3.4", + "phly/keep-a-changelog": "^2.1" + }, + "config": { + "allow-plugins": { + "ocramius/package-versions": true + } + }, + "archive": { + "exclude": [ + "/test", + "/phpunit.xml.dist" + ] + } +} diff --git a/vendor/bacon/bacon-qr-code/phpunit.xml.dist b/vendor/bacon/bacon-qr-code/phpunit.xml.dist new file mode 100644 index 0000000..d9e4d57 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/phpunit.xml.dist @@ -0,0 +1,13 @@ + + + + + src + + + + + ./test + + + diff --git a/vendor/bacon/bacon-qr-code/src/Common/BitArray.php b/vendor/bacon/bacon-qr-code/src/Common/BitArray.php new file mode 100644 index 0000000..158384f --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/BitArray.php @@ -0,0 +1,372 @@ + + */ + private $bits; + + /** + * Size of the bit array in bits. + * + * @var int + */ + private $size; + + /** + * Creates a new bit array with a given size. + */ + public function __construct(int $size = 0) + { + $this->size = $size; + $this->bits = SplFixedArray::fromArray(array_fill(0, ($this->size + 31) >> 3, 0)); + } + + /** + * Gets the size in bits. + */ + public function getSize() : int + { + return $this->size; + } + + /** + * Gets the size in bytes. + */ + public function getSizeInBytes() : int + { + return ($this->size + 7) >> 3; + } + + /** + * Ensures that the array has a minimum capacity. + */ + public function ensureCapacity(int $size) : void + { + if ($size > count($this->bits) << 5) { + $this->bits->setSize(($size + 31) >> 5); + } + } + + /** + * Gets a specific bit. + */ + public function get(int $i) : bool + { + return 0 !== ($this->bits[$i >> 5] & (1 << ($i & 0x1f))); + } + + /** + * Sets a specific bit. + */ + public function set(int $i) : void + { + $this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f); + } + + /** + * Flips a specific bit. + */ + public function flip(int $i) : void + { + $this->bits[$i >> 5] ^= 1 << ($i & 0x1f); + } + + /** + * Gets the next set bit position from a given position. + */ + public function getNextSet(int $from) : int + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = $this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while (0 === $currentBits) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = $this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + return $result > $this->size ? $this->size : $result; + } + + /** + * Gets the next unset bit position from a given position. + */ + public function getNextUnset(int $from) : int + { + if ($from >= $this->size) { + return $this->size; + } + + $bitsOffset = $from >> 5; + $currentBits = ~$this->bits[$bitsOffset]; + $bitsLength = count($this->bits); + $currentBits &= ~((1 << ($from & 0x1f)) - 1); + + while (0 === $currentBits) { + if (++$bitsOffset === $bitsLength) { + return $this->size; + } + + $currentBits = ~$this->bits[$bitsOffset]; + } + + $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits); + return $result > $this->size ? $this->size : $result; + } + + /** + * Sets a bulk of bits. + */ + public function setBulk(int $i, int $newBits) : void + { + $this->bits[$i >> 5] = $newBits; + } + + /** + * Sets a range of bits. + * + * @throws InvalidArgumentException if end is smaller than start + */ + public function setRange(int $start, int $end) : void + { + if ($end < $start) { + throw new InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return; + } + + --$end; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; ++$i) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if (0 === $firstBit && 31 === $lastBit) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j < $lastBit; ++$j) { + $mask |= 1 << $j; + } + } + + $this->bits[$i] = $this->bits[$i] | $mask; + } + } + + /** + * Clears the bit array, unsetting every bit. + */ + public function clear() : void + { + $bitsLength = count($this->bits); + + for ($i = 0; $i < $bitsLength; ++$i) { + $this->bits[$i] = 0; + } + } + + /** + * Checks if a range of bits is set or not set. + + * @throws InvalidArgumentException if end is smaller than start + */ + public function isRange(int $start, int $end, bool $value) : bool + { + if ($end < $start) { + throw new InvalidArgumentException('End must be greater or equal to start'); + } + + if ($end === $start) { + return true; + } + + --$end; + + $firstInt = $start >> 5; + $lastInt = $end >> 5; + + for ($i = $firstInt; $i <= $lastInt; ++$i) { + $firstBit = $i > $firstInt ? 0 : $start & 0x1f; + $lastBit = $i < $lastInt ? 31 : $end & 0x1f; + + if (0 === $firstBit && 31 === $lastBit) { + $mask = 0x7fffffff; + } else { + $mask = 0; + + for ($j = $firstBit; $j <= $lastBit; ++$j) { + $mask |= 1 << $j; + } + } + + if (($this->bits[$i] & $mask) !== ($value ? $mask : 0)) { + return false; + } + } + + return true; + } + + /** + * Appends a bit to the array. + */ + public function appendBit(bool $bit) : void + { + $this->ensureCapacity($this->size + 1); + + if ($bit) { + $this->bits[$this->size >> 5] = $this->bits[$this->size >> 5] | (1 << ($this->size & 0x1f)); + } + + ++$this->size; + } + + /** + * Appends a number of bits (up to 32) to the array. + + * @throws InvalidArgumentException if num bits is not between 0 and 32 + */ + public function appendBits(int $value, int $numBits) : void + { + if ($numBits < 0 || $numBits > 32) { + throw new InvalidArgumentException('Num bits must be between 0 and 32'); + } + + $this->ensureCapacity($this->size + $numBits); + + for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) { + $this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) === 1); + } + } + + /** + * Appends another bit array to this array. + */ + public function appendBitArray(self $other) : void + { + $otherSize = $other->getSize(); + $this->ensureCapacity($this->size + $other->getSize()); + + for ($i = 0; $i < $otherSize; ++$i) { + $this->appendBit($other->get($i)); + } + } + + /** + * Makes an exclusive-or comparision on the current bit array. + * + * @throws InvalidArgumentException if sizes don't match + */ + public function xorBits(self $other) : void + { + $bitsLength = count($this->bits); + $otherBits = $other->getBitArray(); + + if ($bitsLength !== count($otherBits)) { + throw new InvalidArgumentException('Sizes don\'t match'); + } + + for ($i = 0; $i < $bitsLength; ++$i) { + $this->bits[$i] = $this->bits[$i] ^ $otherBits[$i]; + } + } + + /** + * Converts the bit array to a byte array. + * + * @return SplFixedArray + */ + public function toBytes(int $bitOffset, int $numBytes) : SplFixedArray + { + $bytes = new SplFixedArray($numBytes); + + for ($i = 0; $i < $numBytes; ++$i) { + $byte = 0; + + for ($j = 0; $j < 8; ++$j) { + if ($this->get($bitOffset)) { + $byte |= 1 << (7 - $j); + } + + ++$bitOffset; + } + + $bytes[$i] = $byte; + } + + return $bytes; + } + + /** + * Gets the internal bit array. + * + * @return SplFixedArray + */ + public function getBitArray() : SplFixedArray + { + return $this->bits; + } + + /** + * Reverses the array. + */ + public function reverse() : void + { + $newBits = new SplFixedArray(count($this->bits)); + + for ($i = 0; $i < $this->size; ++$i) { + if ($this->get($this->size - $i - 1)) { + $newBits[$i >> 5] = $newBits[$i >> 5] | (1 << ($i & 0x1f)); + } + } + + $this->bits = $newBits; + } + + /** + * Returns a string representation of the bit array. + */ + public function __toString() : string + { + $result = ''; + + for ($i = 0; $i < $this->size; ++$i) { + if (0 === ($i & 0x07)) { + $result .= ' '; + } + + $result .= $this->get($i) ? 'X' : '.'; + } + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php b/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php new file mode 100644 index 0000000..10bf8fe --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php @@ -0,0 +1,313 @@ + + */ + private $bits; + + /** + * @throws InvalidArgumentException if a dimension is smaller than zero + */ + public function __construct(int $width, int $height = null) + { + if (null === $height) { + $height = $width; + } + + if ($width < 1 || $height < 1) { + throw new InvalidArgumentException('Both dimensions must be greater than zero'); + } + + $this->width = $width; + $this->height = $height; + $this->rowSize = ($width + 31) >> 5; + $this->bits = SplFixedArray::fromArray(array_fill(0, $this->rowSize * $height, 0)); + } + + /** + * Gets the requested bit, where true means black. + */ + public function get(int $x, int $y) : bool + { + $offset = $y * $this->rowSize + ($x >> 5); + return 0 !== (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1); + } + + /** + * Sets the given bit to true. + */ + public function set(int $x, int $y) : void + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f)); + } + + /** + * Flips the given bit. + */ + public function flip(int $x, int $y) : void + { + $offset = $y * $this->rowSize + ($x >> 5); + $this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f)); + } + + /** + * Clears all bits (set to false). + */ + public function clear() : void + { + $max = count($this->bits); + + for ($i = 0; $i < $max; ++$i) { + $this->bits[$i] = 0; + } + } + + /** + * Sets a square region of the bit matrix to true. + * + * @throws InvalidArgumentException if left or top are negative + * @throws InvalidArgumentException if width or height are smaller than 1 + * @throws InvalidArgumentException if region does not fit into the matix + */ + public function setRegion(int $left, int $top, int $width, int $height) : void + { + if ($top < 0 || $left < 0) { + throw new InvalidArgumentException('Left and top must be non-negative'); + } + + if ($height < 1 || $width < 1) { + throw new InvalidArgumentException('Width and height must be at least 1'); + } + + $right = $left + $width; + $bottom = $top + $height; + + if ($bottom > $this->height || $right > $this->width) { + throw new InvalidArgumentException('The region must fit inside the matrix'); + } + + for ($y = $top; $y < $bottom; ++$y) { + $offset = $y * $this->rowSize; + + for ($x = $left; $x < $right; ++$x) { + $index = $offset + ($x >> 5); + $this->bits[$index] = $this->bits[$index] | (1 << ($x & 0x1f)); + } + } + } + + /** + * A fast method to retrieve one row of data from the matrix as a BitArray. + */ + public function getRow(int $y, BitArray $row = null) : BitArray + { + if (null === $row || $row->getSize() < $this->width) { + $row = new BitArray($this->width); + } + + $offset = $y * $this->rowSize; + + for ($x = 0; $x < $this->rowSize; ++$x) { + $row->setBulk($x << 5, $this->bits[$offset + $x]); + } + + return $row; + } + + /** + * Sets a row of data from a BitArray. + */ + public function setRow(int $y, BitArray $row) : void + { + $bits = $row->getBitArray(); + + for ($i = 0; $i < $this->rowSize; ++$i) { + $this->bits[$y * $this->rowSize + $i] = $bits[$i]; + } + } + + /** + * This is useful in detecting the enclosing rectangle of a 'pure' barcode. + * + * @return int[]|null + */ + public function getEnclosingRectangle() : ?array + { + $left = $this->width; + $top = $this->height; + $right = -1; + $bottom = -1; + + for ($y = 0; $y < $this->height; ++$y) { + for ($x32 = 0; $x32 < $this->rowSize; ++$x32) { + $bits = $this->bits[$y * $this->rowSize + $x32]; + + if (0 !== $bits) { + if ($y < $top) { + $top = $y; + } + + if ($y > $bottom) { + $bottom = $y; + } + + if ($x32 * 32 < $left) { + $bit = 0; + + while (($bits << (31 - $bit)) === 0) { + $bit++; + } + + if (($x32 * 32 + $bit) < $left) { + $left = $x32 * 32 + $bit; + } + } + } + + if ($x32 * 32 + 31 > $right) { + $bit = 31; + + while (0 === BitUtils::unsignedRightShift($bits, $bit)) { + --$bit; + } + + if (($x32 * 32 + $bit) > $right) { + $right = $x32 * 32 + $bit; + } + } + } + } + + $width = $right - $left; + $height = $bottom - $top; + + if ($width < 0 || $height < 0) { + return null; + } + + return [$left, $top, $width, $height]; + } + + /** + * Gets the most top left set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return int[]|null + */ + public function getTopLeftOnBit() : ?array + { + $bitsOffset = 0; + + while ($bitsOffset < count($this->bits) && 0 === $this->bits[$bitsOffset]) { + ++$bitsOffset; + } + + if (count($this->bits) === $bitsOffset) { + return null; + } + + $x = intdiv($bitsOffset, $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (0 === ($bits << (31 - $bit))) { + ++$bit; + } + + $x += $bit; + + return [$x, $y]; + } + + /** + * Gets the most bottom right set bit. + * + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return int[]|null + */ + public function getBottomRightOnBit() : ?array + { + $bitsOffset = count($this->bits) - 1; + + while ($bitsOffset >= 0 && 0 === $this->bits[$bitsOffset]) { + --$bitsOffset; + } + + if ($bitsOffset < 0) { + return null; + } + + $x = intdiv($bitsOffset, $this->rowSize); + $y = ($bitsOffset % $this->rowSize) << 5; + + $bits = $this->bits[$bitsOffset]; + $bit = 0; + + while (0 === BitUtils::unsignedRightShift($bits, $bit)) { + --$bit; + } + + $x += $bit; + + return [$x, $y]; + } + + /** + * Gets the width of the matrix, + */ + public function getWidth() : int + { + return $this->width; + } + + /** + * Gets the height of the matrix. + */ + public function getHeight() : int + { + return $this->height; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php b/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php new file mode 100644 index 0000000..0c575b4 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php @@ -0,0 +1,41 @@ +>>" in other + * languages. + */ + public static function unsignedRightShift(int $a, int $b) : int + { + return ( + $a >= 0 + ? $a >> $b + : (($a & 0x7fffffff) >> $b) | (0x40000000 >> ($b - 1)) + ); + } + + /** + * Gets the number of trailing zeros. + */ + public static function numberOfTrailingZeros(int $i) : int + { + $lastPos = strrpos(str_pad(decbin($i), 32, '0', STR_PAD_LEFT), '1'); + return $lastPos === false ? 32 : 31 - $lastPos; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php b/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php new file mode 100644 index 0000000..9049ccb --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php @@ -0,0 +1,183 @@ +|null + */ + private static $valueToEci; + + /** + * @var array|null + */ + private static $nameToEci; + + /** + * @param int[] $values + */ + public function __construct(array $values, string ...$otherEncodingNames) + { + $this->values = $values; + $this->otherEncodingNames = $otherEncodingNames; + } + + /** + * Returns the primary value. + */ + public function getValue() : int + { + return $this->values[0]; + } + + /** + * Gets character set ECI by value. + * + * Returns the representing ECI of a given value, or null if it is legal but unsupported. + * + * @throws InvalidArgumentException if value is not between 0 and 900 + */ + public static function getCharacterSetEciByValue(int $value) : ?self + { + if ($value < 0 || $value >= 900) { + throw new InvalidArgumentException('Value must be between 0 and 900'); + } + + $valueToEci = self::valueToEci(); + + if (! array_key_exists($value, $valueToEci)) { + return null; + } + + return $valueToEci[$value]; + } + + /** + * Returns character set ECI by name. + * + * Returns the representing ECI of a given name, or null if it is legal but unsupported + */ + public static function getCharacterSetEciByName(string $name) : ?self + { + $nameToEci = self::nameToEci(); + $name = strtolower($name); + + if (! array_key_exists($name, $nameToEci)) { + return null; + } + + return $nameToEci[$name]; + } + + private static function valueToEci() : array + { + if (null !== self::$valueToEci) { + return self::$valueToEci; + } + + self::$valueToEci = []; + + foreach (self::values() as $eci) { + foreach ($eci->values as $value) { + self::$valueToEci[$value] = $eci; + } + } + + return self::$valueToEci; + } + + private static function nameToEci() : array + { + if (null !== self::$nameToEci) { + return self::$nameToEci; + } + + self::$nameToEci = []; + + foreach (self::values() as $eci) { + self::$nameToEci[strtolower($eci->name())] = $eci; + + foreach ($eci->otherEncodingNames as $name) { + self::$nameToEci[strtolower($name)] = $eci; + } + } + + return self::$nameToEci; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php b/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php new file mode 100644 index 0000000..a9a1d07 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php @@ -0,0 +1,49 @@ +count = $count; + $this->dataCodewords = $dataCodewords; + } + + /** + * Returns how many times the block is used. + */ + public function getCount() : int + { + return $this->count; + } + + /** + * Returns the number of data codewords. + */ + public function getDataCodewords() : int + { + return $this->dataCodewords; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php b/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php new file mode 100644 index 0000000..172b5f2 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php @@ -0,0 +1,74 @@ +ecCodewordsPerBlock = $ecCodewordsPerBlock; + $this->ecBlocks = $ecBlocks; + } + + /** + * Returns the number of EC codewords per block. + */ + public function getEcCodewordsPerBlock() : int + { + return $this->ecCodewordsPerBlock; + } + + /** + * Returns the total number of EC block appearances. + */ + public function getNumBlocks() : int + { + $total = 0; + + foreach ($this->ecBlocks as $ecBlock) { + $total += $ecBlock->getCount(); + } + + return $total; + } + + /** + * Returns the total count of EC codewords. + */ + public function getTotalEcCodewords() : int + { + return $this->ecCodewordsPerBlock * $this->getNumBlocks(); + } + + /** + * Returns the EC blocks included in this collection. + * + * @return EcBlock[] + */ + public function getEcBlocks() : array + { + return $this->ecBlocks; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php b/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php new file mode 100644 index 0000000..9bbf440 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php @@ -0,0 +1,63 @@ +bits = $bits; + } + + /** + * @throws OutOfBoundsException if number of bits is invalid + */ + public static function forBits(int $bits) : self + { + switch ($bits) { + case 0: + return self::M(); + + case 1: + return self::L(); + + case 2: + return self::H(); + + case 3: + return self::Q(); + } + + throw new OutOfBoundsException('Invalid number of bits'); + } + + /** + * Returns the two bits used to encode this error correction level. + */ + public function getBits() : int + { + return $this->bits; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php b/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php new file mode 100644 index 0000000..38295fc --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php @@ -0,0 +1,203 @@ +ecLevel = ErrorCorrectionLevel::forBits(($formatInfo >> 3) & 0x3); + $this->dataMask = $formatInfo & 0x7; + } + + /** + * Checks how many bits are different between two integers. + */ + public static function numBitsDiffering(int $a, int $b) : int + { + $a ^= $b; + + return ( + self::BITS_SET_IN_HALF_BYTE[$a & 0xf] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 4) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 8) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 12) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 16) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 20) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 24) & 0xf)] + + self::BITS_SET_IN_HALF_BYTE[(BitUtils::unsignedRightShift($a, 28) & 0xf)] + ); + } + + /** + * Decodes format information. + */ + public static function decodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self + { + $formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2); + + if (null !== $formatInfo) { + return $formatInfo; + } + + // Should return null, but, some QR codes apparently do not mask this info. Try again by actually masking the + // pattern first. + return self::doDecodeFormatInformation( + $maskedFormatInfo1 ^ self::FORMAT_INFO_MASK_QR, + $maskedFormatInfo2 ^ self::FORMAT_INFO_MASK_QR + ); + } + + /** + * Internal method for decoding format information. + */ + private static function doDecodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self + { + $bestDifference = PHP_INT_MAX; + $bestFormatInfo = 0; + + foreach (self::FORMAT_INFO_DECODE_LOOKUP as $decodeInfo) { + $targetInfo = $decodeInfo[0]; + + if ($targetInfo === $maskedFormatInfo1 || $targetInfo === $maskedFormatInfo2) { + // Found an exact match + return new self($decodeInfo[1]); + } + + $bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + + if ($maskedFormatInfo1 !== $maskedFormatInfo2) { + // Also try the other option + $bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo); + + if ($bitsDifference < $bestDifference) { + $bestFormatInfo = $decodeInfo[1]; + $bestDifference = $bitsDifference; + } + } + } + + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match. + if ($bestDifference <= 3) { + return new self($bestFormatInfo); + } + + return null; + } + + /** + * Returns the error correction level. + */ + public function getErrorCorrectionLevel() : ErrorCorrectionLevel + { + return $this->ecLevel; + } + + /** + * Returns the data mask. + */ + public function getDataMask() : int + { + return $this->dataMask; + } + + /** + * Hashes the code of the EC level. + */ + public function hashCode() : int + { + return ($this->ecLevel->getBits() << 3) | $this->dataMask; + } + + /** + * Verifies if this instance equals another one. + */ + public function equals(self $other) : bool + { + return ( + $this->ecLevel === $other->ecLevel + && $this->dataMask === $other->dataMask + ); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/Mode.php b/vendor/bacon/bacon-qr-code/src/Common/Mode.php new file mode 100644 index 0000000..af5a113 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/Mode.php @@ -0,0 +1,79 @@ +characterCountBitsForVersions = $characterCountBitsForVersions; + $this->bits = $bits; + } + + /** + * Returns the number of bits used in a specific QR code version. + */ + public function getCharacterCountBits(Version $version) : int + { + $number = $version->getVersionNumber(); + + if ($number <= 9) { + $offset = 0; + } elseif ($number <= 26) { + $offset = 1; + } else { + $offset = 2; + } + + return $this->characterCountBitsForVersions[$offset]; + } + + /** + * Returns the four bits used to encode this mode. + */ + public function getBits() : int + { + return $this->bits; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php b/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php new file mode 100644 index 0000000..a5aad0b --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php @@ -0,0 +1,468 @@ + 8) { + throw new InvalidArgumentException('Symbol size must be between 0 and 8'); + } + + if ($firstRoot < 0 || $firstRoot >= (1 << $symbolSize)) { + throw new InvalidArgumentException('First root must be between 0 and ' . (1 << $symbolSize)); + } + + if ($numRoots < 0 || $numRoots >= (1 << $symbolSize)) { + throw new InvalidArgumentException('Num roots must be between 0 and ' . (1 << $symbolSize)); + } + + if ($padding < 0 || $padding >= ((1 << $symbolSize) - 1 - $numRoots)) { + throw new InvalidArgumentException( + 'Padding must be between 0 and ' . ((1 << $symbolSize) - 1 - $numRoots) + ); + } + + $this->symbolSize = $symbolSize; + $this->blockSize = (1 << $symbolSize) - 1; + $this->padding = $padding; + $this->alphaTo = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + $this->indexOf = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false); + + // Generate galous field lookup table + $this->indexOf[0] = $this->blockSize; + $this->alphaTo[$this->blockSize] = 0; + + $sr = 1; + + for ($i = 0; $i < $this->blockSize; ++$i) { + $this->indexOf[$sr] = $i; + $this->alphaTo[$i] = $sr; + + $sr <<= 1; + + if ($sr & (1 << $symbolSize)) { + $sr ^= $gfPoly; + } + + $sr &= $this->blockSize; + } + + if (1 !== $sr) { + throw new RuntimeException('Field generator polynomial is not primitive'); + } + + // Form RS code generator polynomial from its roots + $this->generatorPoly = SplFixedArray::fromArray(array_fill(0, $numRoots + 1, 0), false); + $this->firstRoot = $firstRoot; + $this->primitive = $primitive; + $this->numRoots = $numRoots; + + // Find prim-th root of 1, used in decoding + for ($iPrimitive = 1; ($iPrimitive % $primitive) !== 0; $iPrimitive += $this->blockSize) { + } + + $this->iPrimitive = intdiv($iPrimitive, $primitive); + + $this->generatorPoly[0] = 1; + + for ($i = 0, $root = $firstRoot * $primitive; $i < $numRoots; ++$i, $root += $primitive) { + $this->generatorPoly[$i + 1] = 1; + + for ($j = $i; $j > 0; $j--) { + if ($this->generatorPoly[$j] !== 0) { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1] ^ $this->alphaTo[ + $this->modNn($this->indexOf[$this->generatorPoly[$j]] + $root) + ]; + } else { + $this->generatorPoly[$j] = $this->generatorPoly[$j - 1]; + } + } + + $this->generatorPoly[$j] = $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[0]] + $root)]; + } + + // Convert generator poly to index form for quicker encoding + for ($i = 0; $i <= $numRoots; ++$i) { + $this->generatorPoly[$i] = $this->indexOf[$this->generatorPoly[$i]]; + } + } + + /** + * Encodes data and writes result back into parity array. + */ + public function encode(SplFixedArray $data, SplFixedArray $parity) : void + { + for ($i = 0; $i < $this->numRoots; ++$i) { + $parity[$i] = 0; + } + + $iterations = $this->blockSize - $this->numRoots - $this->padding; + + for ($i = 0; $i < $iterations; ++$i) { + $feedback = $this->indexOf[$data[$i] ^ $parity[0]]; + + if ($feedback !== $this->blockSize) { + // Feedback term is non-zero + $feedback = $this->modNn($this->blockSize - $this->generatorPoly[$this->numRoots] + $feedback); + + for ($j = 1; $j < $this->numRoots; ++$j) { + $parity[$j] = $parity[$j] ^ $this->alphaTo[ + $this->modNn($feedback + $this->generatorPoly[$this->numRoots - $j]) + ]; + } + } + + for ($j = 0; $j < $this->numRoots - 1; ++$j) { + $parity[$j] = $parity[$j + 1]; + } + + if ($feedback !== $this->blockSize) { + $parity[$this->numRoots - 1] = $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[0])]; + } else { + $parity[$this->numRoots - 1] = 0; + } + } + } + + /** + * Decodes received data. + */ + public function decode(SplFixedArray $data, SplFixedArray $erasures = null) : ?int + { + // This speeds up the initialization a bit. + $numRootsPlusOne = SplFixedArray::fromArray(array_fill(0, $this->numRoots + 1, 0), false); + $numRoots = SplFixedArray::fromArray(array_fill(0, $this->numRoots, 0), false); + + $lambda = clone $numRootsPlusOne; + $b = clone $numRootsPlusOne; + $t = clone $numRootsPlusOne; + $omega = clone $numRootsPlusOne; + $root = clone $numRoots; + $loc = clone $numRoots; + + $numErasures = (null !== $erasures ? count($erasures) : 0); + + // Form the Syndromes; i.e., evaluate data(x) at roots of g(x) + $syndromes = SplFixedArray::fromArray(array_fill(0, $this->numRoots, $data[0]), false); + + for ($i = 1; $i < $this->blockSize - $this->padding; ++$i) { + for ($j = 0; $j < $this->numRoots; ++$j) { + if ($syndromes[$j] === 0) { + $syndromes[$j] = $data[$i]; + } else { + $syndromes[$j] = $data[$i] ^ $this->alphaTo[ + $this->modNn($this->indexOf[$syndromes[$j]] + ($this->firstRoot + $j) * $this->primitive) + ]; + } + } + } + + // Convert syndromes to index form, checking for nonzero conditions + $syndromeError = 0; + + for ($i = 0; $i < $this->numRoots; ++$i) { + $syndromeError |= $syndromes[$i]; + $syndromes[$i] = $this->indexOf[$syndromes[$i]]; + } + + if (! $syndromeError) { + // If syndrome is zero, data[] is a codeword and there are no errors to correct, so return data[] + // unmodified. + return 0; + } + + $lambda[0] = 1; + + if ($numErasures > 0) { + // Init lambda to be the erasure locator polynomial + $lambda[1] = $this->alphaTo[$this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[0]))]; + + for ($i = 1; $i < $numErasures; ++$i) { + $u = $this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[$i])); + + for ($j = $i + 1; $j > 0; --$j) { + $tmp = $this->indexOf[$lambda[$j - 1]]; + + if ($tmp !== $this->blockSize) { + $lambda[$j] = $lambda[$j] ^ $this->alphaTo[$this->modNn($u + $tmp)]; + } + } + } + } + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $b[$i] = $this->indexOf[$lambda[$i]]; + } + + // Begin Berlekamp-Massey algorithm to determine error+erasure locator polynomial + $r = $numErasures; + $el = $numErasures; + + while (++$r <= $this->numRoots) { + // Compute discrepancy at the r-th step in poly form + $discrepancyR = 0; + + for ($i = 0; $i < $r; ++$i) { + if ($lambda[$i] !== 0 && $syndromes[$r - $i - 1] !== $this->blockSize) { + $discrepancyR ^= $this->alphaTo[ + $this->modNn($this->indexOf[$lambda[$i]] + $syndromes[$r - $i - 1]) + ]; + } + } + + $discrepancyR = $this->indexOf[$discrepancyR]; + + if ($discrepancyR === $this->blockSize) { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + continue; + } + + $t[0] = $lambda[0]; + + for ($i = 0; $i < $this->numRoots; ++$i) { + if ($b[$i] !== $this->blockSize) { + $t[$i + 1] = $lambda[$i + 1] ^ $this->alphaTo[$this->modNn($discrepancyR + $b[$i])]; + } else { + $t[$i + 1] = $lambda[$i + 1]; + } + } + + if (2 * $el <= $r + $numErasures - 1) { + $el = $r + $numErasures - $el; + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $b[$i] = ( + $lambda[$i] === 0 + ? $this->blockSize + : $this->modNn($this->indexOf[$lambda[$i]] - $discrepancyR + $this->blockSize) + ); + } + } else { + $tmp = $b->toArray(); + array_unshift($tmp, $this->blockSize); + array_pop($tmp); + $b = SplFixedArray::fromArray($tmp, false); + } + + $lambda = clone $t; + } + + // Convert lambda to index form and compute deg(lambda(x)) + $degLambda = 0; + + for ($i = 0; $i <= $this->numRoots; ++$i) { + $lambda[$i] = $this->indexOf[$lambda[$i]]; + + if ($lambda[$i] !== $this->blockSize) { + $degLambda = $i; + } + } + + // Find roots of the error+erasure locator polynomial by Chien search. + $reg = clone $lambda; + $reg[0] = 0; + $count = 0; + $i = 1; + + for ($k = $this->iPrimitive - 1; $i <= $this->blockSize; ++$i, $k = $this->modNn($k + $this->iPrimitive)) { + $q = 1; + + for ($j = $degLambda; $j > 0; $j--) { + if ($reg[$j] !== $this->blockSize) { + $reg[$j] = $this->modNn($reg[$j] + $j); + $q ^= $this->alphaTo[$reg[$j]]; + } + } + + if ($q !== 0) { + // Not a root + continue; + } + + // Store root (index-form) and error location number + $root[$count] = $i; + $loc[$count] = $k; + + if (++$count === $degLambda) { + break; + } + } + + if ($degLambda !== $count) { + // deg(lambda) unequal to number of roots: uncorrectable error detected + return null; + } + + // Compute err+eras evaluate poly omega(x) = s(x)*lambda(x) (modulo x**numRoots). In index form. Also find + // deg(omega). + $degOmega = $degLambda - 1; + + for ($i = 0; $i <= $degOmega; ++$i) { + $tmp = 0; + + for ($j = $i; $j >= 0; --$j) { + if ($syndromes[$i - $j] !== $this->blockSize && $lambda[$j] !== $this->blockSize) { + $tmp ^= $this->alphaTo[$this->modNn($syndromes[$i - $j] + $lambda[$j])]; + } + } + + $omega[$i] = $this->indexOf[$tmp]; + } + + // Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = inv(X(l))**(firstRoot-1) and + // den = lambda_pr(inv(X(l))) all in poly form. + for ($j = $count - 1; $j >= 0; --$j) { + $num1 = 0; + + for ($i = $degOmega; $i >= 0; $i--) { + if ($omega[$i] !== $this->blockSize) { + $num1 ^= $this->alphaTo[$this->modNn($omega[$i] + $i * $root[$j])]; + } + } + + $num2 = $this->alphaTo[$this->modNn($root[$j] * ($this->firstRoot - 1) + $this->blockSize)]; + $den = 0; + + // lambda[i+1] for i even is the formal derivativelambda_pr of lambda[i] + for ($i = min($degLambda, $this->numRoots - 1) & ~1; $i >= 0; $i -= 2) { + if ($lambda[$i + 1] !== $this->blockSize) { + $den ^= $this->alphaTo[$this->modNn($lambda[$i + 1] + $i * $root[$j])]; + } + } + + // Apply error to data + if ($num1 !== 0 && $loc[$j] >= $this->padding) { + $data[$loc[$j] - $this->padding] = $data[$loc[$j] - $this->padding] ^ ( + $this->alphaTo[ + $this->modNn( + $this->indexOf[$num1] + $this->indexOf[$num2] + $this->blockSize - $this->indexOf[$den] + ) + ] + ); + } + } + + if (null !== $erasures) { + if (count($erasures) < $count) { + $erasures->setSize($count); + } + + for ($i = 0; $i < $count; $i++) { + $erasures[$i] = $loc[$i]; + } + } + + return $count; + } + + /** + * Computes $x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, without a slow divide. + */ + private function modNn(int $x) : int + { + while ($x >= $this->blockSize) { + $x -= $this->blockSize; + $x = ($x >> $this->symbolSize) + ($x & $this->blockSize); + } + + return $x; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Common/Version.php b/vendor/bacon/bacon-qr-code/src/Common/Version.php new file mode 100644 index 0000000..917d048 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Common/Version.php @@ -0,0 +1,596 @@ +|null + */ + private static $versions; + + /** + * @param int[] $alignmentPatternCenters + */ + private function __construct( + int $versionNumber, + array $alignmentPatternCenters, + EcBlocks ...$ecBlocks + ) { + $this->versionNumber = $versionNumber; + $this->alignmentPatternCenters = $alignmentPatternCenters; + $this->ecBlocks = $ecBlocks; + + $totalCodewords = 0; + $ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock(); + + foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) { + $totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords); + } + + $this->totalCodewords = $totalCodewords; + } + + /** + * Returns the version number. + */ + public function getVersionNumber() : int + { + return $this->versionNumber; + } + + /** + * Returns the alignment pattern centers. + * + * @return int[] + */ + public function getAlignmentPatternCenters() : array + { + return $this->alignmentPatternCenters; + } + + /** + * Returns the total number of codewords. + */ + public function getTotalCodewords() : int + { + return $this->totalCodewords; + } + + /** + * Calculates the dimension for the current version. + */ + public function getDimensionForVersion() : int + { + return 17 + 4 * $this->versionNumber; + } + + /** + * Returns the number of EC blocks for a specific EC level. + */ + public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel) : EcBlocks + { + return $this->ecBlocks[$ecLevel->ordinal()]; + } + + /** + * Gets a provisional version number for a specific dimension. + * + * @throws InvalidArgumentException if dimension is not 1 mod 4 + */ + public static function getProvisionalVersionForDimension(int $dimension) : self + { + if (1 !== $dimension % 4) { + throw new InvalidArgumentException('Dimension is not 1 mod 4'); + } + + return self::getVersionForNumber(intdiv($dimension - 17, 4)); + } + + /** + * Gets a version instance for a specific version number. + * + * @throws InvalidArgumentException if version number is out of range + */ + public static function getVersionForNumber(int $versionNumber) : self + { + if ($versionNumber < 1 || $versionNumber > 40) { + throw new InvalidArgumentException('Version number must be between 1 and 40'); + } + + return self::versions()[$versionNumber - 1]; + } + + /** + * Decodes version information from an integer and returns the version. + */ + public static function decodeVersionInformation(int $versionBits) : ?self + { + $bestDifference = PHP_INT_MAX; + $bestVersion = 0; + + foreach (self::VERSION_DECODE_INFO as $i => $targetVersion) { + if ($targetVersion === $versionBits) { + return self::getVersionForNumber($i + 7); + } + + $bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion); + + if ($bitsDifference < $bestDifference) { + $bestVersion = $i + 7; + $bestDifference = $bitsDifference; + } + } + + if ($bestDifference <= 3) { + return self::getVersionForNumber($bestVersion); + } + + return null; + } + + /** + * Builds the function pattern for the current version. + */ + public function buildFunctionPattern() : BitMatrix + { + $dimension = $this->getDimensionForVersion(); + $bitMatrix = new BitMatrix($dimension); + + // Top left finder pattern + separator + format + $bitMatrix->setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + $bitMatrix->setRegion($dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + $bitMatrix->setRegion(0, $dimension - 8, 9, 8); + + // Alignment patterns + $max = count($this->alignmentPatternCenters); + + for ($x = 0; $x < $max; ++$x) { + $i = $this->alignmentPatternCenters[$x] - 2; + + for ($y = 0; $y < $max; ++$y) { + if (($x === 0 && ($y === 0 || $y === $max - 1)) || ($x === $max - 1 && $y === 0)) { + // No alignment patterns near the three finder paterns + continue; + } + + $bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5); + } + } + + // Vertical timing pattern + $bitMatrix->setRegion(6, 9, 1, $dimension - 17); + // Horizontal timing pattern + $bitMatrix->setRegion(9, 6, $dimension - 17, 1); + + if ($this->versionNumber > 6) { + // Version info, top right + $bitMatrix->setRegion($dimension - 11, 0, 3, 6); + // Version info, bottom left + $bitMatrix->setRegion(0, $dimension - 11, 6, 3); + } + + return $bitMatrix; + } + + /** + * Returns a string representation for the version. + */ + public function __toString() : string + { + return (string) $this->versionNumber; + } + + /** + * Build and cache a specific version. + * + * See ISO 18004:2006 6.5.1 Table 9. + * + * @return array + */ + private static function versions() : array + { + if (null !== self::$versions) { + return self::$versions; + } + + return self::$versions = [ + new self( + 1, + [], + new EcBlocks(7, new EcBlock(1, 19)), + new EcBlocks(10, new EcBlock(1, 16)), + new EcBlocks(13, new EcBlock(1, 13)), + new EcBlocks(17, new EcBlock(1, 9)) + ), + new self( + 2, + [6, 18], + new EcBlocks(10, new EcBlock(1, 34)), + new EcBlocks(16, new EcBlock(1, 28)), + new EcBlocks(22, new EcBlock(1, 22)), + new EcBlocks(28, new EcBlock(1, 16)) + ), + new self( + 3, + [6, 22], + new EcBlocks(15, new EcBlock(1, 55)), + new EcBlocks(26, new EcBlock(1, 44)), + new EcBlocks(18, new EcBlock(2, 17)), + new EcBlocks(22, new EcBlock(2, 13)) + ), + new self( + 4, + [6, 26], + new EcBlocks(20, new EcBlock(1, 80)), + new EcBlocks(18, new EcBlock(2, 32)), + new EcBlocks(26, new EcBlock(3, 24)), + new EcBlocks(16, new EcBlock(4, 9)) + ), + new self( + 5, + [6, 30], + new EcBlocks(26, new EcBlock(1, 108)), + new EcBlocks(24, new EcBlock(2, 43)), + new EcBlocks(18, new EcBlock(2, 15), new EcBlock(2, 16)), + new EcBlocks(22, new EcBlock(2, 11), new EcBlock(2, 12)) + ), + new self( + 6, + [6, 34], + new EcBlocks(18, new EcBlock(2, 68)), + new EcBlocks(16, new EcBlock(4, 27)), + new EcBlocks(24, new EcBlock(4, 19)), + new EcBlocks(28, new EcBlock(4, 15)) + ), + new self( + 7, + [6, 22, 38], + new EcBlocks(20, new EcBlock(2, 78)), + new EcBlocks(18, new EcBlock(4, 31)), + new EcBlocks(18, new EcBlock(2, 14), new EcBlock(4, 15)), + new EcBlocks(26, new EcBlock(4, 13), new EcBlock(1, 14)) + ), + new self( + 8, + [6, 24, 42], + new EcBlocks(24, new EcBlock(2, 97)), + new EcBlocks(22, new EcBlock(2, 38), new EcBlock(2, 39)), + new EcBlocks(22, new EcBlock(4, 18), new EcBlock(2, 19)), + new EcBlocks(26, new EcBlock(4, 14), new EcBlock(2, 15)) + ), + new self( + 9, + [6, 26, 46], + new EcBlocks(30, new EcBlock(2, 116)), + new EcBlocks(22, new EcBlock(3, 36), new EcBlock(2, 37)), + new EcBlocks(20, new EcBlock(4, 16), new EcBlock(4, 17)), + new EcBlocks(24, new EcBlock(4, 12), new EcBlock(4, 13)) + ), + new self( + 10, + [6, 28, 50], + new EcBlocks(18, new EcBlock(2, 68), new EcBlock(2, 69)), + new EcBlocks(26, new EcBlock(4, 43), new EcBlock(1, 44)), + new EcBlocks(24, new EcBlock(6, 19), new EcBlock(2, 20)), + new EcBlocks(28, new EcBlock(6, 15), new EcBlock(2, 16)) + ), + new self( + 11, + [6, 30, 54], + new EcBlocks(20, new EcBlock(4, 81)), + new EcBlocks(30, new EcBlock(1, 50), new EcBlock(4, 51)), + new EcBlocks(28, new EcBlock(4, 22), new EcBlock(4, 23)), + new EcBlocks(24, new EcBlock(3, 12), new EcBlock(8, 13)) + ), + new self( + 12, + [6, 32, 58], + new EcBlocks(24, new EcBlock(2, 92), new EcBlock(2, 93)), + new EcBlocks(22, new EcBlock(6, 36), new EcBlock(2, 37)), + new EcBlocks(26, new EcBlock(4, 20), new EcBlock(6, 21)), + new EcBlocks(28, new EcBlock(7, 14), new EcBlock(4, 15)) + ), + new self( + 13, + [6, 34, 62], + new EcBlocks(26, new EcBlock(4, 107)), + new EcBlocks(22, new EcBlock(8, 37), new EcBlock(1, 38)), + new EcBlocks(24, new EcBlock(8, 20), new EcBlock(4, 21)), + new EcBlocks(22, new EcBlock(12, 11), new EcBlock(4, 12)) + ), + new self( + 14, + [6, 26, 46, 66], + new EcBlocks(30, new EcBlock(3, 115), new EcBlock(1, 116)), + new EcBlocks(24, new EcBlock(4, 40), new EcBlock(5, 41)), + new EcBlocks(20, new EcBlock(11, 16), new EcBlock(5, 17)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(5, 13)) + ), + new self( + 15, + [6, 26, 48, 70], + new EcBlocks(22, new EcBlock(5, 87), new EcBlock(1, 88)), + new EcBlocks(24, new EcBlock(5, 41), new EcBlock(5, 42)), + new EcBlocks(30, new EcBlock(5, 24), new EcBlock(7, 25)), + new EcBlocks(24, new EcBlock(11, 12), new EcBlock(7, 13)) + ), + new self( + 16, + [6, 26, 50, 74], + new EcBlocks(24, new EcBlock(5, 98), new EcBlock(1, 99)), + new EcBlocks(28, new EcBlock(7, 45), new EcBlock(3, 46)), + new EcBlocks(24, new EcBlock(15, 19), new EcBlock(2, 20)), + new EcBlocks(30, new EcBlock(3, 15), new EcBlock(13, 16)) + ), + new self( + 17, + [6, 30, 54, 78], + new EcBlocks(28, new EcBlock(1, 107), new EcBlock(5, 108)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(1, 47)), + new EcBlocks(28, new EcBlock(1, 22), new EcBlock(15, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(17, 15)) + ), + new self( + 18, + [6, 30, 56, 82], + new EcBlocks(30, new EcBlock(5, 120), new EcBlock(1, 121)), + new EcBlocks(26, new EcBlock(9, 43), new EcBlock(4, 44)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(1, 23)), + new EcBlocks(28, new EcBlock(2, 14), new EcBlock(19, 15)) + ), + new self( + 19, + [6, 30, 58, 86], + new EcBlocks(28, new EcBlock(3, 113), new EcBlock(4, 114)), + new EcBlocks(26, new EcBlock(3, 44), new EcBlock(11, 45)), + new EcBlocks(26, new EcBlock(17, 21), new EcBlock(4, 22)), + new EcBlocks(26, new EcBlock(9, 13), new EcBlock(16, 14)) + ), + new self( + 20, + [6, 34, 62, 90], + new EcBlocks(28, new EcBlock(3, 107), new EcBlock(5, 108)), + new EcBlocks(26, new EcBlock(3, 41), new EcBlock(13, 42)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(5, 25)), + new EcBlocks(28, new EcBlock(15, 15), new EcBlock(10, 16)) + ), + new self( + 21, + [6, 28, 50, 72, 94], + new EcBlocks(28, new EcBlock(4, 116), new EcBlock(4, 117)), + new EcBlocks(26, new EcBlock(17, 42)), + new EcBlocks(28, new EcBlock(17, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(19, 16), new EcBlock(6, 17)) + ), + new self( + 22, + [6, 26, 50, 74, 98], + new EcBlocks(28, new EcBlock(2, 111), new EcBlock(7, 112)), + new EcBlocks(28, new EcBlock(17, 46)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(16, 25)), + new EcBlocks(24, new EcBlock(34, 13)) + ), + new self( + 23, + [6, 30, 54, 78, 102], + new EcBlocks(30, new EcBlock(4, 121), new EcBlock(5, 122)), + new EcBlocks(28, new EcBlock(4, 47), new EcBlock(14, 48)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(16, 15), new EcBlock(14, 16)) + ), + new self( + 24, + [6, 28, 54, 80, 106], + new EcBlocks(30, new EcBlock(6, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(6, 45), new EcBlock(14, 46)), + new EcBlocks(30, new EcBlock(11, 24), new EcBlock(16, 25)), + new EcBlocks(30, new EcBlock(30, 16), new EcBlock(2, 17)) + ), + new self( + 25, + [6, 32, 58, 84, 110], + new EcBlocks(26, new EcBlock(8, 106), new EcBlock(4, 107)), + new EcBlocks(28, new EcBlock(8, 47), new EcBlock(13, 48)), + new EcBlocks(30, new EcBlock(7, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(13, 16)) + ), + new self( + 26, + [6, 30, 58, 86, 114], + new EcBlocks(28, new EcBlock(10, 114), new EcBlock(2, 115)), + new EcBlocks(28, new EcBlock(19, 46), new EcBlock(4, 47)), + new EcBlocks(28, new EcBlock(28, 22), new EcBlock(6, 23)), + new EcBlocks(30, new EcBlock(33, 16), new EcBlock(4, 17)) + ), + new self( + 27, + [6, 34, 62, 90, 118], + new EcBlocks(30, new EcBlock(8, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(22, 45), new EcBlock(3, 46)), + new EcBlocks(30, new EcBlock(8, 23), new EcBlock(26, 24)), + new EcBlocks(30, new EcBlock(12, 15), new EcBlock(28, 16)) + ), + new self( + 28, + [6, 26, 50, 74, 98, 122], + new EcBlocks(30, new EcBlock(3, 117), new EcBlock(10, 118)), + new EcBlocks(28, new EcBlock(3, 45), new EcBlock(23, 46)), + new EcBlocks(30, new EcBlock(4, 24), new EcBlock(31, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(31, 16)) + ), + new self( + 29, + [6, 30, 54, 78, 102, 126], + new EcBlocks(30, new EcBlock(7, 116), new EcBlock(7, 117)), + new EcBlocks(28, new EcBlock(21, 45), new EcBlock(7, 46)), + new EcBlocks(30, new EcBlock(1, 23), new EcBlock(37, 24)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(26, 16)) + ), + new self( + 30, + [6, 26, 52, 78, 104, 130], + new EcBlocks(30, new EcBlock(5, 115), new EcBlock(10, 116)), + new EcBlocks(28, new EcBlock(19, 47), new EcBlock(10, 48)), + new EcBlocks(30, new EcBlock(15, 24), new EcBlock(25, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(25, 16)) + ), + new self( + 31, + [6, 30, 56, 82, 108, 134], + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(3, 116)), + new EcBlocks(28, new EcBlock(2, 46), new EcBlock(29, 47)), + new EcBlocks(30, new EcBlock(42, 24), new EcBlock(1, 25)), + new EcBlocks(30, new EcBlock(23, 15), new EcBlock(28, 16)) + ), + new self( + 32, + [6, 34, 60, 86, 112, 138], + new EcBlocks(30, new EcBlock(17, 115)), + new EcBlocks(28, new EcBlock(10, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(10, 24), new EcBlock(35, 25)), + new EcBlocks(30, new EcBlock(19, 15), new EcBlock(35, 16)) + ), + new self( + 33, + [6, 30, 58, 86, 114, 142], + new EcBlocks(30, new EcBlock(17, 115), new EcBlock(1, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(21, 47)), + new EcBlocks(30, new EcBlock(29, 24), new EcBlock(19, 25)), + new EcBlocks(30, new EcBlock(11, 15), new EcBlock(46, 16)) + ), + new self( + 34, + [6, 34, 62, 90, 118, 146], + new EcBlocks(30, new EcBlock(13, 115), new EcBlock(6, 116)), + new EcBlocks(28, new EcBlock(14, 46), new EcBlock(23, 47)), + new EcBlocks(30, new EcBlock(44, 24), new EcBlock(7, 25)), + new EcBlocks(30, new EcBlock(59, 16), new EcBlock(1, 17)) + ), + new self( + 35, + [6, 30, 54, 78, 102, 126, 150], + new EcBlocks(30, new EcBlock(12, 121), new EcBlock(7, 122)), + new EcBlocks(28, new EcBlock(12, 47), new EcBlock(26, 48)), + new EcBlocks(30, new EcBlock(39, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(22, 15), new EcBlock(41, 16)) + ), + new self( + 36, + [6, 24, 50, 76, 102, 128, 154], + new EcBlocks(30, new EcBlock(6, 121), new EcBlock(14, 122)), + new EcBlocks(28, new EcBlock(6, 47), new EcBlock(34, 48)), + new EcBlocks(30, new EcBlock(46, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(2, 15), new EcBlock(64, 16)) + ), + new self( + 37, + [6, 28, 54, 80, 106, 132, 158], + new EcBlocks(30, new EcBlock(17, 122), new EcBlock(4, 123)), + new EcBlocks(28, new EcBlock(29, 46), new EcBlock(14, 47)), + new EcBlocks(30, new EcBlock(49, 24), new EcBlock(10, 25)), + new EcBlocks(30, new EcBlock(24, 15), new EcBlock(46, 16)) + ), + new self( + 38, + [6, 32, 58, 84, 110, 136, 162], + new EcBlocks(30, new EcBlock(4, 122), new EcBlock(18, 123)), + new EcBlocks(28, new EcBlock(13, 46), new EcBlock(32, 47)), + new EcBlocks(30, new EcBlock(48, 24), new EcBlock(14, 25)), + new EcBlocks(30, new EcBlock(42, 15), new EcBlock(32, 16)) + ), + new self( + 39, + [6, 26, 54, 82, 110, 138, 166], + new EcBlocks(30, new EcBlock(20, 117), new EcBlock(4, 118)), + new EcBlocks(28, new EcBlock(40, 47), new EcBlock(7, 48)), + new EcBlocks(30, new EcBlock(43, 24), new EcBlock(22, 25)), + new EcBlocks(30, new EcBlock(10, 15), new EcBlock(67, 16)) + ), + new self( + 40, + [6, 30, 58, 86, 114, 142, 170], + new EcBlocks(30, new EcBlock(19, 118), new EcBlock(6, 119)), + new EcBlocks(28, new EcBlock(18, 47), new EcBlock(31, 48)), + new EcBlocks(30, new EcBlock(34, 24), new EcBlock(34, 25)), + new EcBlocks(30, new EcBlock(20, 15), new EcBlock(61, 16)) + ), + ]; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php b/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php new file mode 100644 index 0000000..be54afa --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php @@ -0,0 +1,58 @@ + + */ + private $dataBytes; + + /** + * Error correction bytes in the block. + * + * @var SplFixedArray + */ + private $errorCorrectionBytes; + + /** + * Creates a new block pair. + * + * @param SplFixedArray $data + * @param SplFixedArray $errorCorrection + */ + public function __construct(SplFixedArray $data, SplFixedArray $errorCorrection) + { + $this->dataBytes = $data; + $this->errorCorrectionBytes = $errorCorrection; + } + + /** + * Gets the data bytes. + * + * @return SplFixedArray + */ + public function getDataBytes() : SplFixedArray + { + return $this->dataBytes; + } + + /** + * Gets the error correction bytes. + * + * @return SplFixedArray + */ + public function getErrorCorrectionBytes() : SplFixedArray + { + return $this->errorCorrectionBytes; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php b/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php new file mode 100644 index 0000000..b58cc0a --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php @@ -0,0 +1,150 @@ +> + */ + private $bytes; + + /** + * Width of the matrix. + * + * @var int + */ + private $width; + + /** + * Height of the matrix. + * + * @var int + */ + private $height; + + public function __construct(int $width, int $height) + { + $this->height = $height; + $this->width = $width; + $this->bytes = new SplFixedArray($height); + + for ($y = 0; $y < $height; ++$y) { + $this->bytes[$y] = SplFixedArray::fromArray(array_fill(0, $width, 0)); + } + } + + /** + * Gets the width of the matrix. + */ + public function getWidth() : int + { + return $this->width; + } + + /** + * Gets the height of the matrix. + */ + public function getHeight() : int + { + return $this->height; + } + + /** + * Gets the internal representation of the matrix. + * + * @return SplFixedArray> + */ + public function getArray() : SplFixedArray + { + return $this->bytes; + } + + /** + * @return Traversable + */ + public function getBytes() : Traversable + { + foreach ($this->bytes as $row) { + foreach ($row as $byte) { + yield $byte; + } + } + } + + /** + * Gets the byte for a specific position. + */ + public function get(int $x, int $y) : int + { + return $this->bytes[$y][$x]; + } + + /** + * Sets the byte for a specific position. + */ + public function set(int $x, int $y, int $value) : void + { + $this->bytes[$y][$x] = $value; + } + + /** + * Clears the matrix with a specific value. + */ + public function clear(int $value) : void + { + for ($y = 0; $y < $this->height; ++$y) { + for ($x = 0; $x < $this->width; ++$x) { + $this->bytes[$y][$x] = $value; + } + } + } + + public function __clone() + { + $this->bytes = clone $this->bytes; + + foreach ($this->bytes as $index => $row) { + $this->bytes[$index] = clone $row; + } + } + + /** + * Returns a string representation of the matrix. + */ + public function __toString() : string + { + $result = ''; + + for ($y = 0; $y < $this->height; $y++) { + for ($x = 0; $x < $this->width; $x++) { + switch ($this->bytes[$y][$x]) { + case 0: + $result .= ' 0'; + break; + + case 1: + $result .= ' 1'; + break; + + default: + $result .= ' '; + break; + } + } + + $result .= "\n"; + } + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php b/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php new file mode 100644 index 0000000..3208460 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php @@ -0,0 +1,668 @@ + + */ + private static $codecs = []; + + /** + * Encodes "content" with the error correction level "ecLevel". + */ + public static function encode( + string $content, + ErrorCorrectionLevel $ecLevel, + string $encoding = self::DEFAULT_BYTE_MODE_ECODING, + ?Version $forcedVersion = null + ) : QrCode { + // Pick an encoding mode appropriate for the content. Note that this + // will not attempt to use multiple modes / segments even if that were + // more efficient. Would be nice. + $mode = self::chooseMode($content, $encoding); + + // This will store the header information, like mode and length, as well + // as "header" segments like an ECI segment. + $headerBits = new BitArray(); + + // Append ECI segment if applicable + if (Mode::BYTE() === $mode && self::DEFAULT_BYTE_MODE_ECODING !== $encoding) { + $eci = CharacterSetEci::getCharacterSetEciByName($encoding); + + if (null !== $eci) { + self::appendEci($eci, $headerBits); + } + } + + // (With ECI in place,) Write the mode marker + self::appendModeInfo($mode, $headerBits); + + // Collect data within the main segment, separately, to count its size + // if needed. Don't add it to main payload yet. + $dataBits = new BitArray(); + self::appendBytes($content, $mode, $dataBits, $encoding); + + // Hard part: need to know version to know how many bits length takes. + // But need to know how many bits it takes to know version. First we + // take a guess at version by assuming version will be the minimum, 1: + $provisionalBitsNeeded = $headerBits->getSize() + + $mode->getCharacterCountBits(Version::getVersionForNumber(1)) + + $dataBits->getSize(); + $provisionalVersion = self::chooseVersion($provisionalBitsNeeded, $ecLevel); + + // Use that guess to calculate the right version. I am still not sure + // this works in 100% of cases. + $bitsNeeded = $headerBits->getSize() + + $mode->getCharacterCountBits($provisionalVersion) + + $dataBits->getSize(); + $version = self::chooseVersion($bitsNeeded, $ecLevel); + + if (null !== $forcedVersion) { + // Forced version check + if ($version->getVersionNumber() <= $forcedVersion->getVersionNumber()) { + // Calculated minimum version is same or equal as forced version + $version = $forcedVersion; + } else { + throw new WriterException( + 'Invalid version! Calculated version: ' + . $version->getVersionNumber() + . ', requested version: ' + . $forcedVersion->getVersionNumber() + ); + } + } + + $headerAndDataBits = new BitArray(); + $headerAndDataBits->appendBitArray($headerBits); + + // Find "length" of main segment and write it. + $numLetters = (Mode::BYTE() === $mode ? $dataBits->getSizeInBytes() : strlen($content)); + self::appendLengthInfo($numLetters, $version, $mode, $headerAndDataBits); + + // Put data together into the overall payload. + $headerAndDataBits->appendBitArray($dataBits); + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numDataBytes = $version->getTotalCodewords() - $ecBlocks->getTotalEcCodewords(); + + // Terminate the bits properly. + self::terminateBits($numDataBytes, $headerAndDataBits); + + // Interleave data bits with error correction code. + $finalBits = self::interleaveWithEcBytes( + $headerAndDataBits, + $version->getTotalCodewords(), + $numDataBytes, + $ecBlocks->getNumBlocks() + ); + + // Choose the mask pattern. + $dimension = $version->getDimensionForVersion(); + $matrix = new ByteMatrix($dimension, $dimension); + $maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix); + + // Build the matrix. + MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix); + + return new QrCode($mode, $ecLevel, $version, $maskPattern, $matrix); + } + + /** + * Gets the alphanumeric code for a byte. + */ + private static function getAlphanumericCode(int $code) : int + { + if (isset(self::ALPHANUMERIC_TABLE[$code])) { + return self::ALPHANUMERIC_TABLE[$code]; + } + + return -1; + } + + /** + * Chooses the best mode for a given content. + */ + private static function chooseMode(string $content, string $encoding = null) : Mode + { + if (null !== $encoding && 0 === strcasecmp($encoding, 'SHIFT-JIS')) { + return self::isOnlyDoubleByteKanji($content) ? Mode::KANJI() : Mode::BYTE(); + } + + $hasNumeric = false; + $hasAlphanumeric = false; + $contentLength = strlen($content); + + for ($i = 0; $i < $contentLength; ++$i) { + $char = $content[$i]; + + if (ctype_digit($char)) { + $hasNumeric = true; + } elseif (-1 !== self::getAlphanumericCode(ord($char))) { + $hasAlphanumeric = true; + } else { + return Mode::BYTE(); + } + } + + if ($hasAlphanumeric) { + return Mode::ALPHANUMERIC(); + } elseif ($hasNumeric) { + return Mode::NUMERIC(); + } + + return Mode::BYTE(); + } + + /** + * Calculates the mask penalty for a matrix. + */ + private static function calculateMaskPenalty(ByteMatrix $matrix) : int + { + return ( + MaskUtil::applyMaskPenaltyRule1($matrix) + + MaskUtil::applyMaskPenaltyRule2($matrix) + + MaskUtil::applyMaskPenaltyRule3($matrix) + + MaskUtil::applyMaskPenaltyRule4($matrix) + ); + } + + /** + * Checks if content only consists of double-byte kanji characters. + */ + private static function isOnlyDoubleByteKanji(string $content) : bool + { + $bytes = @iconv('utf-8', 'SHIFT-JIS', $content); + + if (false === $bytes) { + return false; + } + + $length = strlen($bytes); + + if (0 !== $length % 2) { + return false; + } + + for ($i = 0; $i < $length; $i += 2) { + $byte = $bytes[$i] & 0xff; + + if (($byte < 0x81 || $byte > 0x9f) && $byte < 0xe0 || $byte > 0xeb) { + return false; + } + } + + return true; + } + + /** + * Chooses the best mask pattern for a matrix. + */ + private static function chooseMaskPattern( + BitArray $bits, + ErrorCorrectionLevel $ecLevel, + Version $version, + ByteMatrix $matrix + ) : int { + $minPenalty = PHP_INT_MAX; + $bestMaskPattern = -1; + + for ($maskPattern = 0; $maskPattern < QrCode::NUM_MASK_PATTERNS; ++$maskPattern) { + MatrixUtil::buildMatrix($bits, $ecLevel, $version, $maskPattern, $matrix); + $penalty = self::calculateMaskPenalty($matrix); + + if ($penalty < $minPenalty) { + $minPenalty = $penalty; + $bestMaskPattern = $maskPattern; + } + } + + return $bestMaskPattern; + } + + /** + * Chooses the best version for the input. + * + * @throws WriterException if data is too big + */ + private static function chooseVersion(int $numInputBits, ErrorCorrectionLevel $ecLevel) : Version + { + for ($versionNum = 1; $versionNum <= 40; ++$versionNum) { + $version = Version::getVersionForNumber($versionNum); + $numBytes = $version->getTotalCodewords(); + + $ecBlocks = $version->getEcBlocksForLevel($ecLevel); + $numEcBytes = $ecBlocks->getTotalEcCodewords(); + + $numDataBytes = $numBytes - $numEcBytes; + $totalInputBytes = intdiv($numInputBits + 8, 8); + + if ($numDataBytes >= $totalInputBytes) { + return $version; + } + } + + throw new WriterException('Data too big'); + } + + /** + * Terminates the bits in a bit array. + * + * @throws WriterException if data bits cannot fit in the QR code + * @throws WriterException if bits size does not equal the capacity + */ + private static function terminateBits(int $numDataBytes, BitArray $bits) : void + { + $capacity = $numDataBytes << 3; + + if ($bits->getSize() > $capacity) { + throw new WriterException('Data bits cannot fit in the QR code'); + } + + for ($i = 0; $i < 4 && $bits->getSize() < $capacity; ++$i) { + $bits->appendBit(false); + } + + $numBitsInLastByte = $bits->getSize() & 0x7; + + if ($numBitsInLastByte > 0) { + for ($i = $numBitsInLastByte; $i < 8; ++$i) { + $bits->appendBit(false); + } + } + + $numPaddingBytes = $numDataBytes - $bits->getSizeInBytes(); + + for ($i = 0; $i < $numPaddingBytes; ++$i) { + $bits->appendBits(0 === ($i & 0x1) ? 0xec : 0x11, 8); + } + + if ($bits->getSize() !== $capacity) { + throw new WriterException('Bits size does not equal capacity'); + } + } + + /** + * Gets number of data- and EC bytes for a block ID. + * + * @return int[] + * @throws WriterException if block ID is too large + * @throws WriterException if EC bytes mismatch + * @throws WriterException if RS blocks mismatch + * @throws WriterException if total bytes mismatch + */ + private static function getNumDataBytesAndNumEcBytesForBlockId( + int $numTotalBytes, + int $numDataBytes, + int $numRsBlocks, + int $blockId + ) : array { + if ($blockId >= $numRsBlocks) { + throw new WriterException('Block ID too large'); + } + + $numRsBlocksInGroup2 = $numTotalBytes % $numRsBlocks; + $numRsBlocksInGroup1 = $numRsBlocks - $numRsBlocksInGroup2; + $numTotalBytesInGroup1 = intdiv($numTotalBytes, $numRsBlocks); + $numTotalBytesInGroup2 = $numTotalBytesInGroup1 + 1; + $numDataBytesInGroup1 = intdiv($numDataBytes, $numRsBlocks); + $numDataBytesInGroup2 = $numDataBytesInGroup1 + 1; + $numEcBytesInGroup1 = $numTotalBytesInGroup1 - $numDataBytesInGroup1; + $numEcBytesInGroup2 = $numTotalBytesInGroup2 - $numDataBytesInGroup2; + + if ($numEcBytesInGroup1 !== $numEcBytesInGroup2) { + throw new WriterException('EC bytes mismatch'); + } + + if ($numRsBlocks !== $numRsBlocksInGroup1 + $numRsBlocksInGroup2) { + throw new WriterException('RS blocks mismatch'); + } + + if ($numTotalBytes !== + (($numDataBytesInGroup1 + $numEcBytesInGroup1) * $numRsBlocksInGroup1) + + (($numDataBytesInGroup2 + $numEcBytesInGroup2) * $numRsBlocksInGroup2) + ) { + throw new WriterException('Total bytes mismatch'); + } + + if ($blockId < $numRsBlocksInGroup1) { + return [$numDataBytesInGroup1, $numEcBytesInGroup1]; + } else { + return [$numDataBytesInGroup2, $numEcBytesInGroup2]; + } + } + + /** + * Interleaves data with EC bytes. + * + * @throws WriterException if number of bits and data bytes does not match + * @throws WriterException if data bytes does not match offset + * @throws WriterException if an interleaving error occurs + */ + private static function interleaveWithEcBytes( + BitArray $bits, + int $numTotalBytes, + int $numDataBytes, + int $numRsBlocks + ) : BitArray { + if ($bits->getSizeInBytes() !== $numDataBytes) { + throw new WriterException('Number of bits and data bytes does not match'); + } + + $dataBytesOffset = 0; + $maxNumDataBytes = 0; + $maxNumEcBytes = 0; + + $blocks = new SplFixedArray($numRsBlocks); + + for ($i = 0; $i < $numRsBlocks; ++$i) { + list($numDataBytesInBlock, $numEcBytesInBlock) = self::getNumDataBytesAndNumEcBytesForBlockId( + $numTotalBytes, + $numDataBytes, + $numRsBlocks, + $i + ); + + $size = $numDataBytesInBlock; + $dataBytes = $bits->toBytes(8 * $dataBytesOffset, $size); + $ecBytes = self::generateEcBytes($dataBytes, $numEcBytesInBlock); + $blocks[$i] = new BlockPair($dataBytes, $ecBytes); + + $maxNumDataBytes = max($maxNumDataBytes, $size); + $maxNumEcBytes = max($maxNumEcBytes, count($ecBytes)); + $dataBytesOffset += $numDataBytesInBlock; + } + + if ($numDataBytes !== $dataBytesOffset) { + throw new WriterException('Data bytes does not match offset'); + } + + $result = new BitArray(); + + for ($i = 0; $i < $maxNumDataBytes; ++$i) { + foreach ($blocks as $block) { + $dataBytes = $block->getDataBytes(); + + if ($i < count($dataBytes)) { + $result->appendBits($dataBytes[$i], 8); + } + } + } + + for ($i = 0; $i < $maxNumEcBytes; ++$i) { + foreach ($blocks as $block) { + $ecBytes = $block->getErrorCorrectionBytes(); + + if ($i < count($ecBytes)) { + $result->appendBits($ecBytes[$i], 8); + } + } + } + + if ($numTotalBytes !== $result->getSizeInBytes()) { + throw new WriterException( + 'Interleaving error: ' . $numTotalBytes . ' and ' . $result->getSizeInBytes() . ' differ' + ); + } + + return $result; + } + + /** + * Generates EC bytes for given data. + * + * @param SplFixedArray $dataBytes + * @return SplFixedArray + */ + private static function generateEcBytes(SplFixedArray $dataBytes, int $numEcBytesInBlock) : SplFixedArray + { + $numDataBytes = count($dataBytes); + $toEncode = new SplFixedArray($numDataBytes + $numEcBytesInBlock); + + for ($i = 0; $i < $numDataBytes; $i++) { + $toEncode[$i] = $dataBytes[$i] & 0xff; + } + + $ecBytes = new SplFixedArray($numEcBytesInBlock); + $codec = self::getCodec($numDataBytes, $numEcBytesInBlock); + $codec->encode($toEncode, $ecBytes); + + return $ecBytes; + } + + /** + * Gets an RS codec and caches it. + */ + private static function getCodec(int $numDataBytes, int $numEcBytesInBlock) : ReedSolomonCodec + { + $cacheId = $numDataBytes . '-' . $numEcBytesInBlock; + + if (isset(self::$codecs[$cacheId])) { + return self::$codecs[$cacheId]; + } + + return self::$codecs[$cacheId] = new ReedSolomonCodec( + 8, + 0x11d, + 0, + 1, + $numEcBytesInBlock, + 255 - $numDataBytes - $numEcBytesInBlock + ); + } + + /** + * Appends mode information to a bit array. + */ + private static function appendModeInfo(Mode $mode, BitArray $bits) : void + { + $bits->appendBits($mode->getBits(), 4); + } + + /** + * Appends length information to a bit array. + * + * @throws WriterException if num letters is bigger than expected + */ + private static function appendLengthInfo(int $numLetters, Version $version, Mode $mode, BitArray $bits) : void + { + $numBits = $mode->getCharacterCountBits($version); + + if ($numLetters >= (1 << $numBits)) { + throw new WriterException($numLetters . ' is bigger than ' . ((1 << $numBits) - 1)); + } + + $bits->appendBits($numLetters, $numBits); + } + + /** + * Appends bytes to a bit array in a specific mode. + * + * @throws WriterException if an invalid mode was supplied + */ + private static function appendBytes(string $content, Mode $mode, BitArray $bits, string $encoding) : void + { + switch ($mode) { + case Mode::NUMERIC(): + self::appendNumericBytes($content, $bits); + break; + + case Mode::ALPHANUMERIC(): + self::appendAlphanumericBytes($content, $bits); + break; + + case Mode::BYTE(): + self::append8BitBytes($content, $bits, $encoding); + break; + + case Mode::KANJI(): + self::appendKanjiBytes($content, $bits); + break; + + default: + throw new WriterException('Invalid mode: ' . $mode); + } + } + + /** + * Appends numeric bytes to a bit array. + */ + private static function appendNumericBytes(string $content, BitArray $bits) : void + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + $num1 = (int) $content[$i]; + + if ($i + 2 < $length) { + // Encode three numeric letters in ten bits. + $num2 = (int) $content[$i + 1]; + $num3 = (int) $content[$i + 2]; + $bits->appendBits($num1 * 100 + $num2 * 10 + $num3, 10); + $i += 3; + } elseif ($i + 1 < $length) { + // Encode two numeric letters in seven bits. + $num2 = (int) $content[$i + 1]; + $bits->appendBits($num1 * 10 + $num2, 7); + $i += 2; + } else { + // Encode one numeric letter in four bits. + $bits->appendBits($num1, 4); + ++$i; + } + } + } + + /** + * Appends alpha-numeric bytes to a bit array. + * + * @throws WriterException if an invalid alphanumeric code was found + */ + private static function appendAlphanumericBytes(string $content, BitArray $bits) : void + { + $length = strlen($content); + $i = 0; + + while ($i < $length) { + $code1 = self::getAlphanumericCode(ord($content[$i])); + + if (-1 === $code1) { + throw new WriterException('Invalid alphanumeric code'); + } + + if ($i + 1 < $length) { + $code2 = self::getAlphanumericCode(ord($content[$i + 1])); + + if (-1 === $code2) { + throw new WriterException('Invalid alphanumeric code'); + } + + // Encode two alphanumeric letters in 11 bits. + $bits->appendBits($code1 * 45 + $code2, 11); + $i += 2; + } else { + // Encode one alphanumeric letter in six bits. + $bits->appendBits($code1, 6); + ++$i; + } + } + } + + /** + * Appends regular 8-bit bytes to a bit array. + * + * @throws WriterException if content cannot be encoded to target encoding + */ + private static function append8BitBytes(string $content, BitArray $bits, string $encoding) : void + { + $bytes = @iconv('utf-8', $encoding, $content); + + if (false === $bytes) { + throw new WriterException('Could not encode content to ' . $encoding); + } + + $length = strlen($bytes); + + for ($i = 0; $i < $length; $i++) { + $bits->appendBits(ord($bytes[$i]), 8); + } + } + + /** + * Appends KANJI bytes to a bit array. + * + * @throws WriterException if content does not seem to be encoded in SHIFT-JIS + * @throws WriterException if an invalid byte sequence occurs + */ + private static function appendKanjiBytes(string $content, BitArray $bits) : void + { + if (strlen($content) % 2 > 0) { + // We just do a simple length check here. The for loop will check + // individual characters. + throw new WriterException('Content does not seem to be encoded in SHIFT-JIS'); + } + + $length = strlen($content); + + for ($i = 0; $i < $length; $i += 2) { + $byte1 = ord($content[$i]) & 0xff; + $byte2 = ord($content[$i + 1]) & 0xff; + $code = ($byte1 << 8) | $byte2; + + if ($code >= 0x8140 && $code <= 0x9ffc) { + $subtracted = $code - 0x8140; + } elseif ($code >= 0xe040 && $code <= 0xebbf) { + $subtracted = $code - 0xc140; + } else { + throw new WriterException('Invalid byte sequence'); + } + + $encoded = (($subtracted >> 8) * 0xc0) + ($subtracted & 0xff); + + $bits->appendBits($encoded, 13); + } + } + + /** + * Appends ECI information to a bit array. + */ + private static function appendEci(CharacterSetEci $eci, BitArray $bits) : void + { + $mode = Mode::ECI(); + $bits->appendBits($mode->getBits(), 4); + $bits->appendBits($eci->getValue(), 8); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php b/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php new file mode 100644 index 0000000..ba97dfb --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php @@ -0,0 +1,271 @@ +getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height - 1; ++$y) { + for ($x = 0; $x < $width - 1; ++$x) { + $value = $array[$y][$x]; + + if ($value === $array[$y][$x + 1] + && $value === $array[$y + 1][$x] + && $value === $array[$y + 1][$x + 1] + ) { + ++$penalty; + } + } + } + + return self::N2 * $penalty; + } + + /** + * Applies mask penalty rule 3 and returns the penalty. + * + * Finds consecutive cells of 00001011101 or 10111010000, and gives penalty + * to them. If we find patterns like 000010111010000, we give penalties + * twice (i.e. 40 * 2). + */ + public static function applyMaskPenaltyRule3(ByteMatrix $matrix) : int + { + $penalty = 0; + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; ++$y) { + for ($x = 0; $x < $width; ++$x) { + if ($x + 6 < $width + && 1 === $array[$y][$x] + && 0 === $array[$y][$x + 1] + && 1 === $array[$y][$x + 2] + && 1 === $array[$y][$x + 3] + && 1 === $array[$y][$x + 4] + && 0 === $array[$y][$x + 5] + && 1 === $array[$y][$x + 6] + && ( + ( + $x + 10 < $width + && 0 === $array[$y][$x + 7] + && 0 === $array[$y][$x + 8] + && 0 === $array[$y][$x + 9] + && 0 === $array[$y][$x + 10] + ) + || ( + $x - 4 >= 0 + && 0 === $array[$y][$x - 1] + && 0 === $array[$y][$x - 2] + && 0 === $array[$y][$x - 3] + && 0 === $array[$y][$x - 4] + ) + ) + ) { + $penalty += self::N3; + } + + if ($y + 6 < $height + && 1 === $array[$y][$x] + && 0 === $array[$y + 1][$x] + && 1 === $array[$y + 2][$x] + && 1 === $array[$y + 3][$x] + && 1 === $array[$y + 4][$x] + && 0 === $array[$y + 5][$x] + && 1 === $array[$y + 6][$x] + && ( + ( + $y + 10 < $height + && 0 === $array[$y + 7][$x] + && 0 === $array[$y + 8][$x] + && 0 === $array[$y + 9][$x] + && 0 === $array[$y + 10][$x] + ) + || ( + $y - 4 >= 0 + && 0 === $array[$y - 1][$x] + && 0 === $array[$y - 2][$x] + && 0 === $array[$y - 3][$x] + && 0 === $array[$y - 4][$x] + ) + ) + ) { + $penalty += self::N3; + } + } + } + + return $penalty; + } + + /** + * Applies mask penalty rule 4 and returns the penalty. + * + * Calculates the ratio of dark cells and gives penalty if the ratio is far + * from 50%. It gives 10 penalty for 5% distance. + */ + public static function applyMaskPenaltyRule4(ByteMatrix $matrix) : int + { + $numDarkCells = 0; + + $array = $matrix->getArray(); + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + + for ($y = 0; $y < $height; ++$y) { + $arrayY = $array[$y]; + + for ($x = 0; $x < $width; ++$x) { + if (1 === $arrayY[$x]) { + ++$numDarkCells; + } + } + } + + $numTotalCells = $height * $width; + $darkRatio = $numDarkCells / $numTotalCells; + $fixedPercentVariances = (int) (abs($darkRatio - 0.5) * 20); + + return $fixedPercentVariances * self::N4; + } + + /** + * Returns the mask bit for "getMaskPattern" at "x" and "y". + * + * See 8.8 of JISX0510:2004 for mask pattern conditions. + * + * @throws InvalidArgumentException if an invalid mask pattern was supplied + */ + public static function getDataMaskBit(int $maskPattern, int $x, int $y) : bool + { + switch ($maskPattern) { + case 0: + $intermediate = ($y + $x) & 0x1; + break; + + case 1: + $intermediate = $y & 0x1; + break; + + case 2: + $intermediate = $x % 3; + break; + + case 3: + $intermediate = ($y + $x) % 3; + break; + + case 4: + $intermediate = (BitUtils::unsignedRightShift($y, 1) + (int) ($x / 3)) & 0x1; + break; + + case 5: + $temp = $y * $x; + $intermediate = ($temp & 0x1) + ($temp % 3); + break; + + case 6: + $temp = $y * $x; + $intermediate = (($temp & 0x1) + ($temp % 3)) & 0x1; + break; + + case 7: + $temp = $y * $x; + $intermediate = (($temp % 3) + (($y + $x) & 0x1)) & 0x1; + break; + + default: + throw new InvalidArgumentException('Invalid mask pattern: ' . $maskPattern); + } + + return 0 == $intermediate; + } + + /** + * Helper function for applyMaskPenaltyRule1. + * + * We need this for doing this calculation in both vertical and horizontal + * orders respectively. + */ + private static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, bool $isHorizontal) : int + { + $penalty = 0; + $iLimit = $isHorizontal ? $matrix->getHeight() : $matrix->getWidth(); + $jLimit = $isHorizontal ? $matrix->getWidth() : $matrix->getHeight(); + $array = $matrix->getArray(); + + for ($i = 0; $i < $iLimit; ++$i) { + $numSameBitCells = 0; + $prevBit = -1; + + for ($j = 0; $j < $jLimit; $j++) { + $bit = $isHorizontal ? $array[$i][$j] : $array[$j][$i]; + + if ($bit === $prevBit) { + ++$numSameBitCells; + } else { + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + + $numSameBitCells = 1; + $prevBit = $bit; + } + } + + if ($numSameBitCells >= 5) { + $penalty += self::N1 + ($numSameBitCells - 5); + } + } + + return $penalty; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php b/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php new file mode 100644 index 0000000..0967e29 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php @@ -0,0 +1,513 @@ +clear(-1); + } + + /** + * Builds a complete matrix. + */ + public static function buildMatrix( + BitArray $dataBits, + ErrorCorrectionLevel $level, + Version $version, + int $maskPattern, + ByteMatrix $matrix + ) : void { + self::clearMatrix($matrix); + self::embedBasicPatterns($version, $matrix); + self::embedTypeInfo($level, $maskPattern, $matrix); + self::maybeEmbedVersionInfo($version, $matrix); + self::embedDataBits($dataBits, $maskPattern, $matrix); + } + + /** + * Removes the position detection patterns from a matrix. + * + * This can be useful if you need to render those patterns separately. + */ + public static function removePositionDetectionPatterns(ByteMatrix $matrix) : void + { + $pdpWidth = count(self::POSITION_DETECTION_PATTERN[0]); + + self::removePositionDetectionPattern(0, 0, $matrix); + self::removePositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix); + self::removePositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix); + } + + /** + * Embeds type information into a matrix. + */ + private static function embedTypeInfo(ErrorCorrectionLevel $level, int $maskPattern, ByteMatrix $matrix) : void + { + $typeInfoBits = new BitArray(); + self::makeTypeInfoBits($level, $maskPattern, $typeInfoBits); + + $typeInfoBitsSize = $typeInfoBits->getSize(); + + for ($i = 0; $i < $typeInfoBitsSize; ++$i) { + $bit = $typeInfoBits->get($typeInfoBitsSize - 1 - $i); + + $x1 = self::TYPE_INFO_COORDINATES[$i][0]; + $y1 = self::TYPE_INFO_COORDINATES[$i][1]; + + $matrix->set($x1, $y1, (int) $bit); + + if ($i < 8) { + $x2 = $matrix->getWidth() - $i - 1; + $y2 = 8; + } else { + $x2 = 8; + $y2 = $matrix->getHeight() - 7 + ($i - 8); + } + + $matrix->set($x2, $y2, (int) $bit); + } + } + + /** + * Generates type information bits and appends them to a bit array. + * + * @throws RuntimeException if bit array resulted in invalid size + */ + private static function makeTypeInfoBits(ErrorCorrectionLevel $level, int $maskPattern, BitArray $bits) : void + { + $typeInfo = ($level->getBits() << 3) | $maskPattern; + $bits->appendBits($typeInfo, 5); + + $bchCode = self::calculateBchCode($typeInfo, self::TYPE_INFO_POLY); + $bits->appendBits($bchCode, 10); + + $maskBits = new BitArray(); + $maskBits->appendBits(self::TYPE_INFO_MASK_PATTERN, 15); + $bits->xorBits($maskBits); + + if (15 !== $bits->getSize()) { + throw new RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Embeds version information if required. + */ + private static function maybeEmbedVersionInfo(Version $version, ByteMatrix $matrix) : void + { + if ($version->getVersionNumber() < 7) { + return; + } + + $versionInfoBits = new BitArray(); + self::makeVersionInfoBits($version, $versionInfoBits); + + $bitIndex = 6 * 3 - 1; + + for ($i = 0; $i < 6; ++$i) { + for ($j = 0; $j < 3; ++$j) { + $bit = $versionInfoBits->get($bitIndex); + --$bitIndex; + + $matrix->set($i, $matrix->getHeight() - 11 + $j, (int) $bit); + $matrix->set($matrix->getHeight() - 11 + $j, $i, (int) $bit); + } + } + } + + /** + * Generates version information bits and appends them to a bit array. + * + * @throws RuntimeException if bit array resulted in invalid size + */ + private static function makeVersionInfoBits(Version $version, BitArray $bits) : void + { + $bits->appendBits($version->getVersionNumber(), 6); + + $bchCode = self::calculateBchCode($version->getVersionNumber(), self::VERSION_INFO_POLY); + $bits->appendBits($bchCode, 12); + + if (18 !== $bits->getSize()) { + throw new RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize()); + } + } + + /** + * Calculates the BCH code for a value and a polynomial. + */ + private static function calculateBchCode(int $value, int $poly) : int + { + $msbSetInPoly = self::findMsbSet($poly); + $value <<= $msbSetInPoly - 1; + + while (self::findMsbSet($value) >= $msbSetInPoly) { + $value ^= $poly << (self::findMsbSet($value) - $msbSetInPoly); + } + + return $value; + } + + /** + * Finds and MSB set. + */ + private static function findMsbSet(int $value) : int + { + $numDigits = 0; + + while (0 !== $value) { + $value >>= 1; + ++$numDigits; + } + + return $numDigits; + } + + /** + * Embeds basic patterns into a matrix. + */ + private static function embedBasicPatterns(Version $version, ByteMatrix $matrix) : void + { + self::embedPositionDetectionPatternsAndSeparators($matrix); + self::embedDarkDotAtLeftBottomCorner($matrix); + self::maybeEmbedPositionAdjustmentPatterns($version, $matrix); + self::embedTimingPatterns($matrix); + } + + /** + * Embeds position detection patterns and separators into a byte matrix. + */ + private static function embedPositionDetectionPatternsAndSeparators(ByteMatrix $matrix) : void + { + $pdpWidth = count(self::POSITION_DETECTION_PATTERN[0]); + + self::embedPositionDetectionPattern(0, 0, $matrix); + self::embedPositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix); + self::embedPositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix); + + $hspWidth = 8; + + self::embedHorizontalSeparationPattern(0, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern($matrix->getWidth() - $hspWidth, $hspWidth - 1, $matrix); + self::embedHorizontalSeparationPattern(0, $matrix->getWidth() - $hspWidth, $matrix); + + $vspSize = 7; + + self::embedVerticalSeparationPattern($vspSize, 0, $matrix); + self::embedVerticalSeparationPattern($matrix->getHeight() - $vspSize - 1, 0, $matrix); + self::embedVerticalSeparationPattern($vspSize, $matrix->getHeight() - $vspSize, $matrix); + } + + /** + * Embeds a single position detection pattern into a byte matrix. + */ + private static function embedPositionDetectionPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; ++$y) { + for ($x = 0; $x < 7; ++$x) { + $matrix->set($xStart + $x, $yStart + $y, self::POSITION_DETECTION_PATTERN[$y][$x]); + } + } + } + + private static function removePositionDetectionPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; ++$y) { + for ($x = 0; $x < 7; ++$x) { + $matrix->set($xStart + $x, $yStart + $y, 0); + } + } + } + + /** + * Embeds a single horizontal separation pattern. + * + * @throws RuntimeException if a byte was already set + */ + private static function embedHorizontalSeparationPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($x = 0; $x < 8; $x++) { + if (-1 !== $matrix->get($xStart + $x, $yStart)) { + throw new RuntimeException('Byte already set'); + } + + $matrix->set($xStart + $x, $yStart, 0); + } + } + + /** + * Embeds a single vertical separation pattern. + * + * @throws RuntimeException if a byte was already set + */ + private static function embedVerticalSeparationPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 7; $y++) { + if (-1 !== $matrix->get($xStart, $yStart + $y)) { + throw new RuntimeException('Byte already set'); + } + + $matrix->set($xStart, $yStart + $y, 0); + } + } + + /** + * Embeds a dot at the left bottom corner. + * + * @throws RuntimeException if a byte was already set to 0 + */ + private static function embedDarkDotAtLeftBottomCorner(ByteMatrix $matrix) : void + { + if (0 === $matrix->get(8, $matrix->getHeight() - 8)) { + throw new RuntimeException('Byte already set to 0'); + } + + $matrix->set(8, $matrix->getHeight() - 8, 1); + } + + /** + * Embeds position adjustment patterns if required. + */ + private static function maybeEmbedPositionAdjustmentPatterns(Version $version, ByteMatrix $matrix) : void + { + if ($version->getVersionNumber() < 2) { + return; + } + + $index = $version->getVersionNumber() - 1; + + $coordinates = self::POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[$index]; + $numCoordinates = count($coordinates); + + for ($i = 0; $i < $numCoordinates; ++$i) { + for ($j = 0; $j < $numCoordinates; ++$j) { + $y = $coordinates[$i]; + $x = $coordinates[$j]; + + if (null === $x || null === $y) { + continue; + } + + if (-1 === $matrix->get($x, $y)) { + self::embedPositionAdjustmentPattern($x - 2, $y - 2, $matrix); + } + } + } + } + + /** + * Embeds a single position adjustment pattern. + */ + private static function embedPositionAdjustmentPattern(int $xStart, int $yStart, ByteMatrix $matrix) : void + { + for ($y = 0; $y < 5; $y++) { + for ($x = 0; $x < 5; $x++) { + $matrix->set($xStart + $x, $yStart + $y, self::POSITION_ADJUSTMENT_PATTERN[$y][$x]); + } + } + } + + /** + * Embeds timing patterns into a matrix. + */ + private static function embedTimingPatterns(ByteMatrix $matrix) : void + { + $matrixWidth = $matrix->getWidth(); + + for ($i = 8; $i < $matrixWidth - 8; ++$i) { + $bit = ($i + 1) % 2; + + if (-1 === $matrix->get($i, 6)) { + $matrix->set($i, 6, $bit); + } + + if (-1 === $matrix->get(6, $i)) { + $matrix->set(6, $i, $bit); + } + } + } + + /** + * Embeds "dataBits" using "getMaskPattern". + * + * For debugging purposes, it skips masking process if "getMaskPattern" is -1. See 8.7 of JISX0510:2004 (p.38) for + * how to embed data bits. + * + * @throws WriterException if not all bits could be consumed + */ + private static function embedDataBits(BitArray $dataBits, int $maskPattern, ByteMatrix $matrix) : void + { + $bitIndex = 0; + $direction = -1; + + // Start from the right bottom cell. + $x = $matrix->getWidth() - 1; + $y = $matrix->getHeight() - 1; + + while ($x > 0) { + // Skip vertical timing pattern. + if (6 === $x) { + --$x; + } + + while ($y >= 0 && $y < $matrix->getHeight()) { + for ($i = 0; $i < 2; $i++) { + $xx = $x - $i; + + // Skip the cell if it's not empty. + if (-1 !== $matrix->get($xx, $y)) { + continue; + } + + if ($bitIndex < $dataBits->getSize()) { + $bit = $dataBits->get($bitIndex); + ++$bitIndex; + } else { + // Padding bit. If there is no bit left, we'll fill the + // left cells with 0, as described in 8.4.9 of + // JISX0510:2004 (p. 24). + $bit = false; + } + + // Skip masking if maskPattern is -1. + if (-1 !== $maskPattern && MaskUtil::getDataMaskBit($maskPattern, $xx, $y)) { + $bit = ! $bit; + } + + $matrix->set($xx, $y, (int) $bit); + } + + $y += $direction; + } + + $direction = -$direction; + $y += $direction; + $x -= 2; + } + + // All bits should be consumed + if ($dataBits->getSize() !== $bitIndex) { + throw new WriterException('Not all bits consumed (' . $bitIndex . ' out of ' . $dataBits->getSize() .')'); + } + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php b/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php new file mode 100644 index 0000000..f568e88 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php @@ -0,0 +1,141 @@ +mode = $mode; + $this->errorCorrectionLevel = $errorCorrectionLevel; + $this->version = $version; + $this->maskPattern = $maskPattern; + $this->matrix = $matrix; + } + + /** + * Gets the mode. + */ + public function getMode() : Mode + { + return $this->mode; + } + + /** + * Gets the EC level. + */ + public function getErrorCorrectionLevel() : ErrorCorrectionLevel + { + return $this->errorCorrectionLevel; + } + + /** + * Gets the version. + */ + public function getVersion() : Version + { + return $this->version; + } + + /** + * Gets the mask pattern. + */ + public function getMaskPattern() : int + { + return $this->maskPattern; + } + + /** + * Gets the matrix. + * + * @return ByteMatrix + */ + public function getMatrix() + { + return $this->matrix; + } + + /** + * Validates whether a mask pattern is valid. + */ + public static function isValidMaskPattern(int $maskPattern) : bool + { + return $maskPattern > 0 && $maskPattern < self::NUM_MASK_PATTERNS; + } + + /** + * Returns a string representation of the QR code. + */ + public function __toString() : string + { + $result = "<<\n" + . ' mode: ' . $this->mode . "\n" + . ' ecLevel: ' . $this->errorCorrectionLevel . "\n" + . ' version: ' . $this->version . "\n" + . ' maskPattern: ' . $this->maskPattern . "\n"; + + if ($this->matrix === null) { + $result .= " matrix: null\n"; + } else { + $result .= " matrix:\n"; + $result .= $this->matrix; + } + + $result .= ">>\n"; + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php b/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php new file mode 100644 index 0000000..6f70c20 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php @@ -0,0 +1,10 @@ + 100) { + throw new Exception\InvalidArgumentException('Alpha must be between 0 and 100'); + } + + $this->alpha = $alpha; + $this->baseColor = $baseColor; + } + + public function getAlpha() : int + { + return $this->alpha; + } + + public function getBaseColor() : ColorInterface + { + return $this->baseColor; + } + + public function toRgb() : Rgb + { + return $this->baseColor->toRgb(); + } + + public function toCmyk() : Cmyk + { + return $this->baseColor->toCmyk(); + } + + public function toGray() : Gray + { + return $this->baseColor->toGray(); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php b/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php new file mode 100644 index 0000000..d6de390 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php @@ -0,0 +1,103 @@ + 100) { + throw new Exception\InvalidArgumentException('Cyan must be between 0 and 100'); + } + + if ($magenta < 0 || $magenta > 100) { + throw new Exception\InvalidArgumentException('Magenta must be between 0 and 100'); + } + + if ($yellow < 0 || $yellow > 100) { + throw new Exception\InvalidArgumentException('Yellow must be between 0 and 100'); + } + + if ($black < 0 || $black > 100) { + throw new Exception\InvalidArgumentException('Black must be between 0 and 100'); + } + + $this->cyan = $cyan; + $this->magenta = $magenta; + $this->yellow = $yellow; + $this->black = $black; + } + + public function getCyan() : int + { + return $this->cyan; + } + + public function getMagenta() : int + { + return $this->magenta; + } + + public function getYellow() : int + { + return $this->yellow; + } + + public function getBlack() : int + { + return $this->black; + } + + public function toRgb() : Rgb + { + $k = $this->black / 100; + $c = (-$k * $this->cyan + $k * 100 + $this->cyan) / 100; + $m = (-$k * $this->magenta + $k * 100 + $this->magenta) / 100; + $y = (-$k * $this->yellow + $k * 100 + $this->yellow) / 100; + + return new Rgb( + (int) (-$c * 255 + 255), + (int) (-$m * 255 + 255), + (int) (-$y * 255 + 255) + ); + } + + public function toCmyk() : Cmyk + { + return $this; + } + + public function toGray() : Gray + { + return $this->toRgb()->toGray(); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php b/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php new file mode 100644 index 0000000..b50d1ca --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php @@ -0,0 +1,22 @@ + 100) { + throw new Exception\InvalidArgumentException('Gray must be between 0 and 100'); + } + + $this->gray = (int) $gray; + } + + public function getGray() : int + { + return $this->gray; + } + + public function toRgb() : Rgb + { + return new Rgb((int) ($this->gray * 2.55), (int) ($this->gray * 2.55), (int) ($this->gray * 2.55)); + } + + public function toCmyk() : Cmyk + { + return new Cmyk(0, 0, 0, 100 - $this->gray); + } + + public function toGray() : Gray + { + return $this; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php b/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php new file mode 100644 index 0000000..7935406 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php @@ -0,0 +1,88 @@ + 255) { + throw new Exception\InvalidArgumentException('Red must be between 0 and 255'); + } + + if ($green < 0 || $green > 255) { + throw new Exception\InvalidArgumentException('Green must be between 0 and 255'); + } + + if ($blue < 0 || $blue > 255) { + throw new Exception\InvalidArgumentException('Blue must be between 0 and 255'); + } + + $this->red = $red; + $this->green = $green; + $this->blue = $blue; + } + + public function getRed() : int + { + return $this->red; + } + + public function getGreen() : int + { + return $this->green; + } + + public function getBlue() : int + { + return $this->blue; + } + + public function toRgb() : Rgb + { + return $this; + } + + public function toCmyk() : Cmyk + { + $c = 1 - ($this->red / 255); + $m = 1 - ($this->green / 255); + $y = 1 - ($this->blue / 255); + $k = min($c, $m, $y); + + return new Cmyk( + (int) (100 * ($c - $k) / (1 - $k)), + (int) (100 * ($m - $k) / (1 - $k)), + (int) (100 * ($y - $k) / (1 - $k)), + (int) (100 * $k) + ); + } + + public function toGray() : Gray + { + return new Gray((int) (($this->red * 0.21 + $this->green * 0.71 + $this->blue * 0.07) / 2.55)); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php new file mode 100644 index 0000000..0d03125 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php @@ -0,0 +1,38 @@ +externalEye = $externalEye; + $this->internalEye = $internalEye; + } + + public function getExternalPath() : Path + { + return $this->externalEye->getExternalPath(); + } + + public function getInternalPath() : Path + { + return $this->internalEye->getInternalPath(); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php new file mode 100644 index 0000000..ab68f3c --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php @@ -0,0 +1,26 @@ +module = $module; + } + + public function getExternalPath() : Path + { + $matrix = new ByteMatrix(7, 7); + + for ($x = 0; $x < 7; ++$x) { + $matrix->set($x, 0, 1); + $matrix->set($x, 6, 1); + } + + for ($y = 1; $y < 6; ++$y) { + $matrix->set(0, $y, 1); + $matrix->set(6, $y, 1); + } + + return $this->module->createPath($matrix)->translate(-3.5, -3.5); + } + + public function getInternalPath() : Path + { + $matrix = new ByteMatrix(3, 3); + + for ($x = 0; $x < 3; ++$x) { + for ($y = 0; $y < 3; ++$y) { + $matrix->set($x, $y, 1); + } + } + + return $this->module->createPath($matrix)->translate(-1.5, -1.5); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php new file mode 100644 index 0000000..64d54ee --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php @@ -0,0 +1,54 @@ +move(-3.5, -3.5) + ->line(3.5, -3.5) + ->line(3.5, 3.5) + ->line(-3.5, 3.5) + ->close() + ->move(-2.5, -2.5) + ->line(-2.5, 2.5) + ->line(2.5, 2.5) + ->line(2.5, -2.5) + ->close() + ; + } + + public function getInternalPath() : Path + { + return (new Path()) + ->move(1.5, 0) + ->ellipticArc(1.5, 1.5, 0., false, true, 0., 1.5) + ->ellipticArc(1.5, 1.5, 0., false, true, -1.5, 0.) + ->ellipticArc(1.5, 1.5, 0., false, true, 0., -1.5) + ->ellipticArc(1.5, 1.5, 0., false, true, 1.5, 0.) + ->close() + ; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php new file mode 100644 index 0000000..a3892b4 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php @@ -0,0 +1,53 @@ +move(-3.5, -3.5) + ->line(3.5, -3.5) + ->line(3.5, 3.5) + ->line(-3.5, 3.5) + ->close() + ->move(-2.5, -2.5) + ->line(-2.5, 2.5) + ->line(2.5, 2.5) + ->line(2.5, -2.5) + ->close() + ; + } + + public function getInternalPath() : Path + { + return (new Path()) + ->move(-1.5, -1.5) + ->line(1.5, -1.5) + ->line(1.5, 1.5) + ->line(-1.5, 1.5) + ->close() + ; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php b/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php new file mode 100644 index 0000000..b581b54 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php @@ -0,0 +1,376 @@ +eps = "%!PS-Adobe-3.0 EPSF-3.0\n" + . "%%Creator: BaconQrCode\n" + . sprintf("%%%%BoundingBox: 0 0 %d %d \n", $size, $size) + . "%%BeginProlog\n" + . "save\n" + . "50 dict begin\n" + . "/q { gsave } bind def\n" + . "/Q { grestore } bind def\n" + . "/s { scale } bind def\n" + . "/t { translate } bind def\n" + . "/r { rotate } bind def\n" + . "/n { newpath } bind def\n" + . "/m { moveto } bind def\n" + . "/l { lineto } bind def\n" + . "/c { curveto } bind def\n" + . "/z { closepath } bind def\n" + . "/f { eofill } bind def\n" + . "/rgb { setrgbcolor } bind def\n" + . "/cmyk { setcmykcolor } bind def\n" + . "/gray { setgray } bind def\n" + . "%%EndProlog\n" + . "1 -1 s\n" + . sprintf("0 -%d t\n", $size); + + if ($backgroundColor instanceof Alpha && 0 === $backgroundColor->getAlpha()) { + return; + } + + $this->eps .= wordwrap( + '0 0 m' + . sprintf(' %s 0 l', (string) $size) + . sprintf(' %s %s l', (string) $size, (string) $size) + . sprintf(' 0 %s l', (string) $size) + . ' z' + . ' ' .$this->getColorSetString($backgroundColor) . " f\n", + 75, + "\n " + ); + } + + public function scale(float $size) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%1\$s %1\$s s\n", round($size, self::PRECISION)); + } + + public function translate(float $x, float $y) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%s %s t\n", round($x, self::PRECISION), round($y, self::PRECISION)); + } + + public function rotate(int $degrees) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= sprintf("%d r\n", $degrees); + } + + public function push() : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "q\n"; + } + + public function pop() : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "Q\n"; + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $fromX = 0; + $fromY = 0; + $this->eps .= wordwrap( + 'n ' + . $this->drawPathOperations($path, $fromX, $fromY) + . ' ' . $this->getColorSetString($color) . " f\n", + 75, + "\n " + ); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $fromX = 0; + $fromY = 0; + $this->eps .= wordwrap( + 'q n ' . $this->drawPathOperations($path, $fromX, $fromY) . "\n", + 75, + "\n " + ); + + $this->createGradientFill($gradient, $x, $y, $width, $height); + } + + public function done() : string + { + if (null === $this->eps) { + throw new RuntimeException('No image has been started'); + } + + $this->eps .= "%%TRAILER\nend restore\n%%EOF"; + $blob = $this->eps; + $this->eps = null; + + return $blob; + } + + private function drawPathOperations(Iterable $ops, &$fromX, &$fromY) : string + { + $pathData = []; + + foreach ($ops as $op) { + switch (true) { + case $op instanceof Move: + $fromX = $toX = round($op->getX(), self::PRECISION); + $fromY = $toY = round($op->getY(), self::PRECISION); + $pathData[] = sprintf('%s %s m', $toX, $toY); + break; + + case $op instanceof Line: + $fromX = $toX = round($op->getX(), self::PRECISION); + $fromY = $toY = round($op->getY(), self::PRECISION); + $pathData[] = sprintf('%s %s l', $toX, $toY); + break; + + case $op instanceof EllipticArc: + $pathData[] = $this->drawPathOperations($op->toCurves($fromX, $fromY), $fromX, $fromY); + break; + + case $op instanceof Curve: + $x1 = round($op->getX1(), self::PRECISION); + $y1 = round($op->getY1(), self::PRECISION); + $x2 = round($op->getX2(), self::PRECISION); + $y2 = round($op->getY2(), self::PRECISION); + $fromX = $x3 = round($op->getX3(), self::PRECISION); + $fromY = $y3 = round($op->getY3(), self::PRECISION); + $pathData[] = sprintf('%s %s %s %s %s %s c', $x1, $y1, $x2, $y2, $x3, $y3); + break; + + case $op instanceof Close: + $pathData[] = 'z'; + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + return implode(' ', $pathData); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : void + { + $startColor = $gradient->getStartColor(); + $endColor = $gradient->getEndColor(); + + if ($startColor instanceof Alpha) { + $startColor = $startColor->getBaseColor(); + } + + $startColorType = get_class($startColor); + + if (! in_array($startColorType, [Rgb::class, Cmyk::class, Gray::class])) { + $startColorType = Cmyk::class; + $startColor = $startColor->toCmyk(); + } + + if (get_class($endColor) !== $startColorType) { + switch ($startColorType) { + case Cmyk::class: + $endColor = $endColor->toCmyk(); + break; + + case Rgb::class: + $endColor = $endColor->toRgb(); + break; + + case Gray::class: + $endColor = $endColor->toGray(); + break; + } + } + + $this->eps .= "eoclip\n<<\n"; + + if ($gradient->getType() === GradientType::RADIAL()) { + $this->eps .= " /ShadingType 3\n"; + } else { + $this->eps .= " /ShadingType 2\n"; + } + + $this->eps .= " /Extend [ true true ]\n" + . " /AntiAlias true\n"; + + switch ($startColorType) { + case Cmyk::class: + $this->eps .= " /ColorSpace /DeviceCMYK\n"; + break; + + case Rgb::class: + $this->eps .= " /ColorSpace /DeviceRGB\n"; + break; + + case Gray::class: + $this->eps .= " /ColorSpace /DeviceGray\n"; + break; + } + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x + $width, self::PRECISION), + round($y, self::PRECISION) + ); + break; + + case GradientType::VERTICAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x, self::PRECISION), + round($y + $height, self::PRECISION) + ); + break; + + case GradientType::DIAGONAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y, self::PRECISION), + round($x + $width, self::PRECISION), + round($y + $height, self::PRECISION) + ); + break; + + case GradientType::INVERSE_DIAGONAL(): + $this->eps .= sprintf( + " /Coords [ %s %s %s %s ]\n", + round($x, self::PRECISION), + round($y + $height, self::PRECISION), + round($x + $width, self::PRECISION), + round($y, self::PRECISION) + ); + break; + + case GradientType::RADIAL(): + $centerX = ($x + $width) / 2; + $centerY = ($y + $height) / 2; + + $this->eps .= sprintf( + " /Coords [ %s %s 0 %s %s %s ]\n", + round($centerX, self::PRECISION), + round($centerY, self::PRECISION), + round($centerX, self::PRECISION), + round($centerY, self::PRECISION), + round(max($width, $height) / 2, self::PRECISION) + ); + break; + } + + $this->eps .= " /Function\n" + . " <<\n" + . " /FunctionType 2\n" + . " /Domain [ 0 1 ]\n" + . sprintf(" /C0 [ %s ]\n", $this->getColorString($startColor)) + . sprintf(" /C1 [ %s ]\n", $this->getColorString($endColor)) + . " /N 1\n" + . " >>\n>>\nshfill\nQ\n"; + } + + private function getColorSetString(ColorInterface $color) : string + { + if ($color instanceof Rgb) { + return $this->getColorString($color) . ' rgb'; + } + + if ($color instanceof Cmyk) { + return $this->getColorString($color) . ' cmyk'; + } + + if ($color instanceof Gray) { + return $this->getColorString($color) . ' gray'; + } + + return $this->getColorSetString($color->toCmyk()); + } + + private function getColorString(ColorInterface $color) : string + { + if ($color instanceof Rgb) { + return sprintf('%s %s %s', $color->getRed() / 255, $color->getGreen() / 255, $color->getBlue() / 255); + } + + if ($color instanceof Cmyk) { + return sprintf( + '%s %s %s %s', + $color->getCyan() / 100, + $color->getMagenta() / 100, + $color->getYellow() / 100, + $color->getBlack() / 100 + ); + } + + if ($color instanceof Gray) { + return sprintf('%s', $color->getGray() / 100); + } + + return $this->getColorString($color->toCmyk()); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php b/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php new file mode 100644 index 0000000..0935819 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php @@ -0,0 +1,87 @@ +imageFormat = $imageFormat; + $this->compressionQuality = $compressionQuality; + } + + public function new(int $size, ColorInterface $backgroundColor) : void + { + $this->image = new Imagick(); + $this->image->newImage($size, $size, $this->getColorPixel($backgroundColor)); + $this->image->setImageFormat($this->imageFormat); + $this->image->setCompressionQuality($this->compressionQuality); + $this->draw = new ImagickDraw(); + $this->gradientCount = 0; + $this->matrices = [new TransformationMatrix()]; + $this->matrixIndex = 0; + } + + public function scale(float $size) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->scale($size, $size); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::scale($size)); + } + + public function translate(float $x, float $y) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->translate($x, $y); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::translate($x, $y)); + } + + public function rotate(int $degrees) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->rotate($degrees); + $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex] + ->multiply(TransformationMatrix::rotate($degrees)); + } + + public function push() : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->push(); + $this->matrices[++$this->matrixIndex] = $this->matrices[$this->matrixIndex - 1]; + } + + public function pop() : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->pop(); + unset($this->matrices[$this->matrixIndex--]); + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->setFillColor($this->getColorPixel($color)); + $this->drawPath($path); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->draw->setFillPatternURL('#' . $this->createGradientFill($gradient, $x, $y, $width, $height)); + $this->drawPath($path); + } + + public function done() : string + { + if (null === $this->draw) { + throw new RuntimeException('No image has been started'); + } + + $this->image->drawImage($this->draw); + $blob = $this->image->getImageBlob(); + $this->draw->clear(); + $this->image->clear(); + $this->draw = null; + $this->image = null; + $this->gradientCount = null; + + return $blob; + } + + private function drawPath(Path $path) : void + { + $this->draw->pathStart(); + + foreach ($path as $op) { + switch (true) { + case $op instanceof Move: + $this->draw->pathMoveToAbsolute($op->getX(), $op->getY()); + break; + + case $op instanceof Line: + $this->draw->pathLineToAbsolute($op->getX(), $op->getY()); + break; + + case $op instanceof EllipticArc: + $this->draw->pathEllipticArcAbsolute( + $op->getXRadius(), + $op->getYRadius(), + $op->getXAxisAngle(), + $op->isLargeArc(), + $op->isSweep(), + $op->getX(), + $op->getY() + ); + break; + + case $op instanceof Curve: + $this->draw->pathCurveToAbsolute( + $op->getX1(), + $op->getY1(), + $op->getX2(), + $op->getY2(), + $op->getX3(), + $op->getY3() + ); + break; + + case $op instanceof Close: + $this->draw->pathClose(); + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + $this->draw->pathFinish(); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string + { + list($width, $height) = $this->matrices[$this->matrixIndex]->apply($width, $height); + + $startColor = $this->getColorPixel($gradient->getStartColor())->getColorAsString(); + $endColor = $this->getColorPixel($gradient->getEndColor())->getColorAsString(); + $gradientImage = new Imagick(); + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $gradientImage->newPseudoImage((int) $height, (int) $width, sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + $gradientImage->rotateImage('transparent', -90); + break; + + case GradientType::VERTICAL(): + $gradientImage->newPseudoImage((int) $width, (int) $height, sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + break; + + case GradientType::DIAGONAL(): + case GradientType::INVERSE_DIAGONAL(): + $gradientImage->newPseudoImage((int) ($width * sqrt(2)), (int) ($height * sqrt(2)), sprintf( + 'gradient:%s-%s', + $startColor, + $endColor + )); + + if (GradientType::DIAGONAL() === $gradient->getType()) { + $gradientImage->rotateImage('transparent', -45); + } else { + $gradientImage->rotateImage('transparent', -135); + } + + $rotatedWidth = $gradientImage->getImageWidth(); + $rotatedHeight = $gradientImage->getImageHeight(); + + $gradientImage->setImagePage($rotatedWidth, $rotatedHeight, 0, 0); + $gradientImage->cropImage( + intdiv($rotatedWidth, 2) - 2, + intdiv($rotatedHeight, 2) - 2, + intdiv($rotatedWidth, 4) + 1, + intdiv($rotatedWidth, 4) + 1 + ); + break; + + case GradientType::RADIAL(): + $gradientImage->newPseudoImage((int) $width, (int) $height, sprintf( + 'radial-gradient:%s-%s', + $startColor, + $endColor + )); + break; + } + + $id = sprintf('g%d', ++$this->gradientCount); + $this->draw->pushPattern($id, 0, 0, $width, $height); + $this->draw->composite(Imagick::COMPOSITE_COPY, 0, 0, $width, $height, $gradientImage); + $this->draw->popPattern(); + return $id; + } + + private function getColorPixel(ColorInterface $color) : ImagickPixel + { + $alpha = 100; + + if ($color instanceof Alpha) { + $alpha = $color->getAlpha(); + $color = $color->getBaseColor(); + } + + if ($color instanceof Rgb) { + return new ImagickPixel(sprintf( + 'rgba(%d, %d, %d, %F)', + $color->getRed(), + $color->getGreen(), + $color->getBlue(), + $alpha / 100 + )); + } + + if ($color instanceof Cmyk) { + return new ImagickPixel(sprintf( + 'cmyka(%d, %d, %d, %d, %F)', + $color->getCyan(), + $color->getMagenta(), + $color->getYellow(), + $color->getBlack(), + $alpha / 100 + )); + } + + if ($color instanceof Gray) { + return new ImagickPixel(sprintf( + 'graya(%d%%, %F)', + $color->getGray(), + $alpha / 100 + )); + } + + return $this->getColorPixel(new Alpha($alpha, $color->toRgb())); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php b/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php new file mode 100644 index 0000000..cb37a9f --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php @@ -0,0 +1,369 @@ +xmlWriter = new XMLWriter(); + $this->xmlWriter->openMemory(); + + $this->xmlWriter->startDocument('1.0', 'UTF-8'); + $this->xmlWriter->startElement('svg'); + $this->xmlWriter->writeAttribute('xmlns', 'http://www.w3.org/2000/svg'); + $this->xmlWriter->writeAttribute('version', '1.1'); + $this->xmlWriter->writeAttribute('width', (string) $size); + $this->xmlWriter->writeAttribute('height', (string) $size); + $this->xmlWriter->writeAttribute('viewBox', '0 0 '. $size . ' ' . $size); + + $this->gradientCount = 0; + $this->currentStack = 0; + $this->stack[0] = 0; + + $alpha = 1; + + if ($backgroundColor instanceof Alpha) { + $alpha = $backgroundColor->getAlpha() / 100; + } + + if (0 === $alpha) { + return; + } + + $this->xmlWriter->startElement('rect'); + $this->xmlWriter->writeAttribute('x', '0'); + $this->xmlWriter->writeAttribute('y', '0'); + $this->xmlWriter->writeAttribute('width', (string) $size); + $this->xmlWriter->writeAttribute('height', (string) $size); + $this->xmlWriter->writeAttribute('fill', $this->getColorString($backgroundColor)); + + if ($alpha < 1) { + $this->xmlWriter->writeAttribute('fill-opacity', (string) $alpha); + } + + $this->xmlWriter->endElement(); + } + + public function scale(float $size) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute( + 'transform', + sprintf('scale(%s)', round($size, self::PRECISION)) + ); + ++$this->stack[$this->currentStack]; + } + + public function translate(float $x, float $y) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute( + 'transform', + sprintf('translate(%s,%s)', round($x, self::PRECISION), round($y, self::PRECISION)) + ); + ++$this->stack[$this->currentStack]; + } + + public function rotate(int $degrees) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->xmlWriter->writeAttribute('transform', sprintf('rotate(%d)', $degrees)); + ++$this->stack[$this->currentStack]; + } + + public function push() : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $this->xmlWriter->startElement('g'); + $this->stack[] = 1; + ++$this->currentStack; + } + + public function pop() : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + for ($i = 0; $i < $this->stack[$this->currentStack]; ++$i) { + $this->xmlWriter->endElement(); + } + + array_pop($this->stack); + --$this->currentStack; + } + + public function drawPathWithColor(Path $path, ColorInterface $color) : void + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $alpha = 1; + + if ($color instanceof Alpha) { + $alpha = $color->getAlpha() / 100; + } + + $this->startPathElement($path); + $this->xmlWriter->writeAttribute('fill', $this->getColorString($color)); + + if ($alpha < 1) { + $this->xmlWriter->writeAttribute('fill-opacity', (string) $alpha); + } + + $this->xmlWriter->endElement(); + } + + public function drawPathWithGradient( + Path $path, + Gradient $gradient, + float $x, + float $y, + float $width, + float $height + ) : void { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + $gradientId = $this->createGradientFill($gradient, $x, $y, $width, $height); + $this->startPathElement($path); + $this->xmlWriter->writeAttribute('fill', 'url(#' . $gradientId . ')'); + $this->xmlWriter->endElement(); + } + + public function done() : string + { + if (null === $this->xmlWriter) { + throw new RuntimeException('No image has been started'); + } + + foreach ($this->stack as $openElements) { + for ($i = $openElements; $i > 0; --$i) { + $this->xmlWriter->endElement(); + } + } + + $this->xmlWriter->endDocument(); + $blob = $this->xmlWriter->outputMemory(true); + $this->xmlWriter = null; + $this->stack = null; + $this->currentStack = null; + $this->gradientCount = null; + + return $blob; + } + + private function startPathElement(Path $path) : void + { + $pathData = []; + + foreach ($path as $op) { + switch (true) { + case $op instanceof Move: + $pathData[] = sprintf( + 'M%s %s', + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof Line: + $pathData[] = sprintf( + 'L%s %s', + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof EllipticArc: + $pathData[] = sprintf( + 'A%s %s %s %u %u %s %s', + round($op->getXRadius(), self::PRECISION), + round($op->getYRadius(), self::PRECISION), + round($op->getXAxisAngle(), self::PRECISION), + $op->isLargeArc(), + $op->isSweep(), + round($op->getX(), self::PRECISION), + round($op->getY(), self::PRECISION) + ); + break; + + case $op instanceof Curve: + $pathData[] = sprintf( + 'C%s %s %s %s %s %s', + round($op->getX1(), self::PRECISION), + round($op->getY1(), self::PRECISION), + round($op->getX2(), self::PRECISION), + round($op->getY2(), self::PRECISION), + round($op->getX3(), self::PRECISION), + round($op->getY3(), self::PRECISION) + ); + break; + + case $op instanceof Close: + $pathData[] = 'Z'; + break; + + default: + throw new RuntimeException('Unexpected draw operation: ' . get_class($op)); + } + } + + $this->xmlWriter->startElement('path'); + $this->xmlWriter->writeAttribute('fill-rule', 'evenodd'); + $this->xmlWriter->writeAttribute('d', implode('', $pathData)); + } + + private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string + { + $this->xmlWriter->startElement('defs'); + + $startColor = $gradient->getStartColor(); + $endColor = $gradient->getEndColor(); + + if ($gradient->getType() === GradientType::RADIAL()) { + $this->xmlWriter->startElement('radialGradient'); + } else { + $this->xmlWriter->startElement('linearGradient'); + } + + $this->xmlWriter->writeAttribute('gradientUnits', 'userSpaceOnUse'); + + switch ($gradient->getType()) { + case GradientType::HORIZONTAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y, self::PRECISION)); + break; + + case GradientType::VERTICAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y + $height, self::PRECISION)); + break; + + case GradientType::DIAGONAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y + $height, self::PRECISION)); + break; + + case GradientType::INVERSE_DIAGONAL(): + $this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION)); + $this->xmlWriter->writeAttribute('y1', (string) round($y + $height, self::PRECISION)); + $this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION)); + $this->xmlWriter->writeAttribute('y2', (string) round($y, self::PRECISION)); + break; + + case GradientType::RADIAL(): + $this->xmlWriter->writeAttribute('cx', (string) round(($x + $width) / 2, self::PRECISION)); + $this->xmlWriter->writeAttribute('cy', (string) round(($y + $height) / 2, self::PRECISION)); + $this->xmlWriter->writeAttribute('r', (string) round(max($width, $height) / 2, self::PRECISION)); + break; + } + + $id = sprintf('g%d', ++$this->gradientCount); + $this->xmlWriter->writeAttribute('id', $id); + + $this->xmlWriter->startElement('stop'); + $this->xmlWriter->writeAttribute('offset', '0%'); + $this->xmlWriter->writeAttribute('stop-color', $this->getColorString($startColor)); + + if ($startColor instanceof Alpha) { + $this->xmlWriter->writeAttribute('stop-opacity', (string) $startColor->getAlpha()); + } + + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('stop'); + $this->xmlWriter->writeAttribute('offset', '100%'); + $this->xmlWriter->writeAttribute('stop-color', $this->getColorString($endColor)); + + if ($endColor instanceof Alpha) { + $this->xmlWriter->writeAttribute('stop-opacity', (string) $endColor->getAlpha()); + } + + $this->xmlWriter->endElement(); + + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + return $id; + } + + private function getColorString(ColorInterface $color) : string + { + $color = $color->toRgb(); + + return sprintf( + '#%02x%02x%02x', + $color->getRed(), + $color->getGreen(), + $color->getBlue() + ); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php b/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php new file mode 100644 index 0000000..7e88da6 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php @@ -0,0 +1,68 @@ +values = [1, 0, 0, 1, 0, 0]; + } + + public function multiply(self $other) : self + { + $matrix = new self(); + $matrix->values[0] = $this->values[0] * $other->values[0] + $this->values[2] * $other->values[1]; + $matrix->values[1] = $this->values[1] * $other->values[0] + $this->values[3] * $other->values[1]; + $matrix->values[2] = $this->values[0] * $other->values[2] + $this->values[2] * $other->values[3]; + $matrix->values[3] = $this->values[1] * $other->values[2] + $this->values[3] * $other->values[3]; + $matrix->values[4] = $this->values[0] * $other->values[4] + $this->values[2] * $other->values[5] + + $this->values[4]; + $matrix->values[5] = $this->values[1] * $other->values[4] + $this->values[3] * $other->values[5] + + $this->values[5]; + + return $matrix; + } + + public static function scale(float $size) : self + { + $matrix = new self(); + $matrix->values = [$size, 0, 0, $size, 0, 0]; + return $matrix; + } + + public static function translate(float $x, float $y) : self + { + $matrix = new self(); + $matrix->values = [1, 0, 0, 1, $x, $y]; + return $matrix; + } + + public static function rotate(int $degrees) : self + { + $matrix = new self(); + $rad = deg2rad($degrees); + $matrix->values = [cos($rad), sin($rad), -sin($rad), cos($rad), 0, 0]; + return $matrix; + } + + + /** + * Applies this matrix onto a point and returns the resulting viewport point. + * + * @return float[] + */ + public function apply(float $x, float $y) : array + { + return [ + $x * $this->values[0] + $y * $this->values[2] + $this->values[4], + $x * $this->values[1] + $y * $this->values[3] + $this->values[5], + ]; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php b/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php new file mode 100644 index 0000000..ab16276 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php @@ -0,0 +1,152 @@ +rendererStyle = $rendererStyle; + $this->imageBackEnd = $imageBackEnd; + } + + /** + * @throws InvalidArgumentException if matrix width doesn't match height + */ + public function render(QrCode $qrCode) : string + { + $size = $this->rendererStyle->getSize(); + $margin = $this->rendererStyle->getMargin(); + $matrix = $qrCode->getMatrix(); + $matrixSize = $matrix->getWidth(); + + if ($matrixSize !== $matrix->getHeight()) { + throw new InvalidArgumentException('Matrix must have the same width and height'); + } + + $totalSize = $matrixSize + ($margin * 2); + $moduleSize = $size / $totalSize; + $fill = $this->rendererStyle->getFill(); + + $this->imageBackEnd->new($size, $fill->getBackgroundColor()); + $this->imageBackEnd->scale((float) $moduleSize); + $this->imageBackEnd->translate((float) $margin, (float) $margin); + + $module = $this->rendererStyle->getModule(); + $moduleMatrix = clone $matrix; + MatrixUtil::removePositionDetectionPatterns($moduleMatrix); + $modulePath = $this->drawEyes($matrixSize, $module->createPath($moduleMatrix)); + + if ($fill->hasGradientFill()) { + $this->imageBackEnd->drawPathWithGradient( + $modulePath, + $fill->getForegroundGradient(), + 0, + 0, + $matrixSize, + $matrixSize + ); + } else { + $this->imageBackEnd->drawPathWithColor($modulePath, $fill->getForegroundColor()); + } + + return $this->imageBackEnd->done(); + } + + private function drawEyes(int $matrixSize, Path $modulePath) : Path + { + $fill = $this->rendererStyle->getFill(); + + $eye = $this->rendererStyle->getEye(); + $externalPath = $eye->getExternalPath(); + $internalPath = $eye->getInternalPath(); + + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getTopLeftEyeFill(), + 3.5, + 3.5, + 0, + $modulePath + ); + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getTopRightEyeFill(), + $matrixSize - 3.5, + 3.5, + 90, + $modulePath + ); + $modulePath = $this->drawEye( + $externalPath, + $internalPath, + $fill->getBottomLeftEyeFill(), + 3.5, + $matrixSize - 3.5, + -90, + $modulePath + ); + + return $modulePath; + } + + private function drawEye( + Path $externalPath, + Path $internalPath, + EyeFill $fill, + float $xTranslation, + float $yTranslation, + int $rotation, + Path $modulePath + ) : Path { + if ($fill->inheritsBothColors()) { + return $modulePath + ->append($externalPath->translate($xTranslation, $yTranslation)) + ->append($internalPath->translate($xTranslation, $yTranslation)); + } + + $this->imageBackEnd->push(); + $this->imageBackEnd->translate($xTranslation, $yTranslation); + + if (0 !== $rotation) { + $this->imageBackEnd->rotate($rotation); + } + + if ($fill->inheritsExternalColor()) { + $modulePath = $modulePath->append($externalPath->translate($xTranslation, $yTranslation)); + } else { + $this->imageBackEnd->drawPathWithColor($externalPath, $fill->getExternalColor()); + } + + if ($fill->inheritsInternalColor()) { + $modulePath = $modulePath->append($internalPath->translate($xTranslation, $yTranslation)); + } else { + $this->imageBackEnd->drawPathWithColor($internalPath, $fill->getInternalColor()); + } + + $this->imageBackEnd->pop(); + + return $modulePath; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php b/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php new file mode 100644 index 0000000..f536e5a --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php @@ -0,0 +1,63 @@ + 1) { + throw new InvalidArgumentException('Size must between 0 (exclusive) and 1 (inclusive)'); + } + + $this->size = $size; + } + + public function createPath(ByteMatrix $matrix) : Path + { + $width = $matrix->getWidth(); + $height = $matrix->getHeight(); + $path = new Path(); + $halfSize = $this->size / 2; + $margin = (1 - $this->size) / 2; + + for ($y = 0; $y < $height; ++$y) { + for ($x = 0; $x < $width; ++$x) { + if (! $matrix->get($x, $y)) { + continue; + } + + $pathX = $x + $margin; + $pathY = $y + $margin; + + $path = $path + ->move($pathX + $this->size, $pathY + $halfSize) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $halfSize, $pathY + $this->size) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX, $pathY + $halfSize) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $halfSize, $pathY) + ->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $this->size, $pathY + $halfSize) + ->close() + ; + } + } + + return $path; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php b/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php new file mode 100644 index 0000000..90482f2 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php @@ -0,0 +1,100 @@ + + */ + private $points = []; + + /** + * @var array|null + */ + private $simplifiedPoints; + + /** + * @var int + */ + private $minX = PHP_INT_MAX; + + /** + * @var int + */ + private $minY = PHP_INT_MAX; + + /** + * @var int + */ + private $maxX = -1; + + /** + * @var int + */ + private $maxY = -1; + + public function __construct(bool $positive) + { + $this->positive = $positive; + } + + public function addPoint(int $x, int $y) : void + { + $this->points[] = [$x, $y]; + $this->minX = min($this->minX, $x); + $this->minY = min($this->minY, $y); + $this->maxX = max($this->maxX, $x); + $this->maxY = max($this->maxY, $y); + } + + public function isPositive() : bool + { + return $this->positive; + } + + /** + * @return array + */ + public function getPoints() : array + { + return $this->points; + } + + public function getMaxX() : int + { + return $this->maxX; + } + + public function getSimplifiedPoints() : array + { + if (null !== $this->simplifiedPoints) { + return $this->simplifiedPoints; + } + + $points = []; + $length = count($this->points); + + for ($i = 0; $i < $length; ++$i) { + $previousPoint = $this->points[(0 === $i ? $length : $i) - 1]; + $nextPoint = $this->points[($length - 1 === $i ? -1 : $i) + 1]; + $currentPoint = $this->points[$i]; + + if (($previousPoint[0] === $currentPoint[0] && $currentPoint[0] === $nextPoint[0]) + || ($previousPoint[1] === $currentPoint[1] && $currentPoint[1] === $nextPoint[1]) + ) { + continue; + } + + $points[] = $currentPoint; + } + + return $this->simplifiedPoints = $points; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php b/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php new file mode 100644 index 0000000..eb29dc6 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php @@ -0,0 +1,169 @@ +bytes = iterator_to_array($matrix->getBytes()); + $this->size = count($this->bytes); + $this->width = $matrix->getWidth(); + $this->height = $matrix->getHeight(); + } + + /** + * @return Traversable + */ + public function getIterator() : Traversable + { + $originalBytes = $this->bytes; + $point = $this->findNext(0, 0); + + while (null !== $point) { + $edge = $this->findEdge($point[0], $point[1]); + $this->xorEdge($edge); + + yield $edge; + + $point = $this->findNext($point[0], $point[1]); + } + + $this->bytes = $originalBytes; + } + + /** + * @return int[]|null + */ + private function findNext(int $x, int $y) : ?array + { + $i = $this->width * $y + $x; + + while ($i < $this->size && 1 !== $this->bytes[$i]) { + ++$i; + } + + if ($i < $this->size) { + return $this->pointOf($i); + } + + return null; + } + + private function findEdge(int $x, int $y) : Edge + { + $edge = new Edge($this->isSet($x, $y)); + $startX = $x; + $startY = $y; + $dirX = 0; + $dirY = 1; + + while (true) { + $edge->addPoint($x, $y); + $x += $dirX; + $y += $dirY; + + if ($x === $startX && $y === $startY) { + break; + } + + $left = $this->isSet($x + ($dirX + $dirY - 1 ) / 2, $y + ($dirY - $dirX - 1) / 2); + $right = $this->isSet($x + ($dirX - $dirY - 1) / 2, $y + ($dirY + $dirX - 1) / 2); + + if ($right && ! $left) { + $tmp = $dirX; + $dirX = -$dirY; + $dirY = $tmp; + } elseif ($right) { + $tmp = $dirX; + $dirX = -$dirY; + $dirY = $tmp; + } elseif (! $left) { + $tmp = $dirX; + $dirX = $dirY; + $dirY = -$tmp; + } + } + + return $edge; + } + + private function xorEdge(Edge $path) : void + { + $points = $path->getPoints(); + $y1 = $points[0][1]; + $length = count($points); + $maxX = $path->getMaxX(); + + for ($i = 1; $i < $length; ++$i) { + $y = $points[$i][1]; + + if ($y === $y1) { + continue; + } + + $x = $points[$i][0]; + $minY = min($y1, $y); + + for ($j = $x; $j < $maxX; ++$j) { + $this->flip($j, $minY); + } + + $y1 = $y; + } + } + + private function isSet(int $x, int $y) : bool + { + return ( + $x >= 0 + && $x < $this->width + && $y >= 0 + && $y < $this->height + ) && 1 === $this->bytes[$this->width * $y + $x]; + } + + /** + * @return int[] + */ + private function pointOf(int $i) : array + { + $y = intdiv($i, $this->width); + return [$i - $y * $this->width, $y]; + } + + private function flip(int $x, int $y) : void + { + $this->bytes[$this->width * $y + $x] = ( + $this->isSet($x, $y) ? 0 : 1 + ); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php b/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php new file mode 100644 index 0000000..0ccb0e0 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php @@ -0,0 +1,18 @@ + 1) { + throw new InvalidArgumentException('Intensity must between 0 (exclusive) and 1 (inclusive)'); + } + + $this->intensity = $intensity / 2; + } + + public function createPath(ByteMatrix $matrix) : Path + { + $path = new Path(); + + foreach (new EdgeIterator($matrix) as $edge) { + $points = $edge->getSimplifiedPoints(); + $length = count($points); + + $currentPoint = $points[0]; + $nextPoint = $points[1]; + $horizontal = ($currentPoint[1] === $nextPoint[1]); + + if ($horizontal) { + $right = $nextPoint[0] > $currentPoint[0]; + $path = $path->move( + $currentPoint[0] + ($right ? $this->intensity : -$this->intensity), + $currentPoint[1] + ); + } else { + $up = $nextPoint[0] < $currentPoint[0]; + $path = $path->move( + $currentPoint[0], + $currentPoint[1] + ($up ? -$this->intensity : $this->intensity) + ); + } + + for ($i = 1; $i <= $length; ++$i) { + if ($i === $length) { + $previousPoint = $points[$length - 1]; + $currentPoint = $points[0]; + $nextPoint = $points[1]; + } else { + $previousPoint = $points[(0 === $i ? $length : $i) - 1]; + $currentPoint = $points[$i]; + $nextPoint = $points[($length - 1 === $i ? -1 : $i) + 1]; + } + + $horizontal = ($previousPoint[1] === $currentPoint[1]); + + if ($horizontal) { + $right = $previousPoint[0] < $currentPoint[0]; + $up = $nextPoint[1] < $currentPoint[1]; + $sweep = ($up xor $right); + + if ($this->intensity < 0.5 + || ($right && $previousPoint[0] !== $currentPoint[0] - 1) + || (! $right && $previousPoint[0] - 1 !== $currentPoint[0]) + ) { + $path = $path->line( + $currentPoint[0] + ($right ? -$this->intensity : $this->intensity), + $currentPoint[1] + ); + } + + $path = $path->ellipticArc( + $this->intensity, + $this->intensity, + 0, + false, + $sweep, + $currentPoint[0], + $currentPoint[1] + ($up ? -$this->intensity : $this->intensity) + ); + } else { + $up = $previousPoint[1] > $currentPoint[1]; + $right = $nextPoint[0] > $currentPoint[0]; + $sweep = ! ($up xor $right); + + if ($this->intensity < 0.5 + || ($up && $previousPoint[1] !== $currentPoint[1] + 1) + || (! $up && $previousPoint[0] + 1 !== $currentPoint[0]) + ) { + $path = $path->line( + $currentPoint[0], + $currentPoint[1] + ($up ? $this->intensity : -$this->intensity) + ); + } + + $path = $path->ellipticArc( + $this->intensity, + $this->intensity, + 0, + false, + $sweep, + $currentPoint[0] + ($right ? $this->intensity : -$this->intensity), + $currentPoint[1] + ); + } + } + + $path = $path->close(); + } + + return $path; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php b/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php new file mode 100644 index 0000000..9ab4607 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php @@ -0,0 +1,47 @@ +getSimplifiedPoints(); + $length = count($points); + $path = $path->move($points[0][0], $points[0][1]); + + for ($i = 1; $i < $length; ++$i) { + $path = $path->line($points[$i][0], $points[$i][1]); + } + + $path = $path->close(); + } + + return $path; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php new file mode 100644 index 0000000..b07feb0 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php @@ -0,0 +1,29 @@ +x1 = $x1; + $this->y1 = $y1; + $this->x2 = $x2; + $this->y2 = $y2; + $this->x3 = $x3; + $this->y3 = $y3; + } + + public function getX1() : float + { + return $this->x1; + } + + public function getY1() : float + { + return $this->y1; + } + + public function getX2() : float + { + return $this->x2; + } + + public function getY2() : float + { + return $this->y2; + } + + public function getX3() : float + { + return $this->x3; + } + + public function getY3() : float + { + return $this->y3; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self( + $this->x1 + $x, + $this->y1 + $y, + $this->x2 + $x, + $this->y2 + $y, + $this->x3 + $x, + $this->y3 + $y + ); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php b/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php new file mode 100644 index 0000000..9f2385a --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php @@ -0,0 +1,278 @@ +xRadius = abs($xRadius); + $this->yRadius = abs($yRadius); + $this->xAxisAngle = $xAxisAngle % 360; + $this->largeArc = $largeArc; + $this->sweep = $sweep; + $this->x = $x; + $this->y = $y; + } + + public function getXRadius() : float + { + return $this->xRadius; + } + + public function getYRadius() : float + { + return $this->yRadius; + } + + public function getXAxisAngle() : float + { + return $this->xAxisAngle; + } + + public function isLargeArc() : bool + { + return $this->largeArc; + } + + public function isSweep() : bool + { + return $this->sweep; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self( + $this->xRadius, + $this->yRadius, + $this->xAxisAngle, + $this->largeArc, + $this->sweep, + $this->x + $x, + $this->y + $y + ); + } + + /** + * Converts the elliptic arc to multiple curves. + * + * Since not all image back ends support elliptic arcs, this method allows to convert the arc into multiple curves + * resembling the same result. + * + * @see https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/ + * @return array + */ + public function toCurves(float $fromX, float $fromY) : array + { + if (sqrt(($fromX - $this->x) ** 2 + ($fromY - $this->y) ** 2) < self::ZERO_TOLERANCE) { + return []; + } + + if ($this->xRadius < self::ZERO_TOLERANCE || $this->yRadius < self::ZERO_TOLERANCE) { + return [new Line($this->x, $this->y)]; + } + + return $this->createCurves($fromX, $fromY); + } + + /** + * @return Curve[] + */ + private function createCurves(float $fromX, float $fromY) : array + { + $xAngle = deg2rad($this->xAxisAngle); + list($centerX, $centerY, $radiusX, $radiusY, $startAngle, $deltaAngle) = + $this->calculateCenterPointParameters($fromX, $fromY, $xAngle); + + $s = $startAngle; + $e = $s + $deltaAngle; + $sign = ($e < $s) ? -1 : 1; + $remain = abs($e - $s); + $p1 = self::point($centerX, $centerY, $radiusX, $radiusY, $xAngle, $s); + $curves = []; + + while ($remain > self::ZERO_TOLERANCE) { + $step = min($remain, pi() / 2); + $signStep = $step * $sign; + $p2 = self::point($centerX, $centerY, $radiusX, $radiusY, $xAngle, $s + $signStep); + + $alphaT = tan($signStep / 2); + $alpha = sin($signStep) * (sqrt(4 + 3 * $alphaT ** 2) - 1) / 3; + $d1 = self::derivative($radiusX, $radiusY, $xAngle, $s); + $d2 = self::derivative($radiusX, $radiusY, $xAngle, $s + $signStep); + + $curves[] = new Curve( + $p1[0] + $alpha * $d1[0], + $p1[1] + $alpha * $d1[1], + $p2[0] - $alpha * $d2[0], + $p2[1] - $alpha * $d2[1], + $p2[0], + $p2[1] + ); + + $s += $signStep; + $remain -= $step; + $p1 = $p2; + } + + return $curves; + } + + /** + * @return float[] + */ + private function calculateCenterPointParameters(float $fromX, float $fromY, float $xAngle) + { + $rX = $this->xRadius; + $rY = $this->yRadius; + + // F.6.5.1 + $dx2 = ($fromX - $this->x) / 2; + $dy2 = ($fromY - $this->y) / 2; + $x1p = cos($xAngle) * $dx2 + sin($xAngle) * $dy2; + $y1p = -sin($xAngle) * $dx2 + cos($xAngle) * $dy2; + + // F.6.5.2 + $rxs = $rX ** 2; + $rys = $rY ** 2; + $x1ps = $x1p ** 2; + $y1ps = $y1p ** 2; + $cr = $x1ps / $rxs + $y1ps / $rys; + + if ($cr > 1) { + $s = sqrt($cr); + $rX *= $s; + $rY *= $s; + $rxs = $rX ** 2; + $rys = $rY ** 2; + } + + $dq = ($rxs * $y1ps + $rys * $x1ps); + $pq = ($rxs * $rys - $dq) / $dq; + $q = sqrt(max(0, $pq)); + + if ($this->largeArc === $this->sweep) { + $q = -$q; + } + + $cxp = $q * $rX * $y1p / $rY; + $cyp = -$q * $rY * $x1p / $rX; + + // F.6.5.3 + $cx = cos($xAngle) * $cxp - sin($xAngle) * $cyp + ($fromX + $this->x) / 2; + $cy = sin($xAngle) * $cxp + cos($xAngle) * $cyp + ($fromY + $this->y) / 2; + + // F.6.5.5 + $theta = self::angle(1, 0, ($x1p - $cxp) / $rX, ($y1p - $cyp) / $rY); + + // F.6.5.6 + $delta = self::angle(($x1p - $cxp) / $rX, ($y1p - $cyp) / $rY, (-$x1p - $cxp) / $rX, (-$y1p - $cyp) / $rY); + $delta = fmod($delta, pi() * 2); + + if (! $this->sweep) { + $delta -= 2 * pi(); + } + + return [$cx, $cy, $rX, $rY, $theta, $delta]; + } + + private static function angle(float $ux, float $uy, float $vx, float $vy) : float + { + // F.6.5.4 + $dot = $ux * $vx + $uy * $vy; + $length = sqrt($ux ** 2 + $uy ** 2) * sqrt($vx ** 2 + $vy ** 2); + $angle = acos(min(1, max(-1, $dot / $length))); + + if (($ux * $vy - $uy * $vx) < 0) { + return -$angle; + } + + return $angle; + } + + /** + * @return float[] + */ + private static function point( + float $centerX, + float $centerY, + float $radiusX, + float $radiusY, + float $xAngle, + float $angle + ) : array { + return [ + $centerX + $radiusX * cos($xAngle) * cos($angle) - $radiusY * sin($xAngle) * sin($angle), + $centerY + $radiusX * sin($xAngle) * cos($angle) + $radiusY * cos($xAngle) * sin($angle), + ]; + } + + /** + * @return float[] + */ + private static function derivative(float $radiusX, float $radiusY, float $xAngle, float $angle) : array + { + return [ + -$radiusX * cos($xAngle) * sin($angle) - $radiusY * sin($xAngle) * cos($angle), + -$radiusX * sin($xAngle) * sin($angle) + $radiusY * cos($xAngle) * cos($angle), + ]; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php new file mode 100644 index 0000000..3149a39 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php @@ -0,0 +1,41 @@ +x = $x; + $this->y = $y; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self($this->x + $x, $this->y + $y); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php new file mode 100644 index 0000000..481d0dd --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php @@ -0,0 +1,41 @@ +x = $x; + $this->y = $y; + } + + public function getX() : float + { + return $this->x; + } + + public function getY() : float + { + return $this->y; + } + + /** + * @return self + */ + public function translate(float $x, float $y) : OperationInterface + { + return new self($this->x + $x, $this->y + $y); + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php b/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php new file mode 100644 index 0000000..a5fa0ed --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php @@ -0,0 +1,12 @@ +operations[] = new Move($x, $y); + return $path; + } + + /** + * Draws a line from the current position to another position. + */ + public function line(float $x, float $y) : self + { + $path = clone $this; + $path->operations[] = new Line($x, $y); + return $path; + } + + /** + * Draws an elliptic arc from the current position to another position. + */ + public function ellipticArc( + float $xRadius, + float $yRadius, + float $xAxisRotation, + bool $largeArc, + bool $sweep, + float $x, + float $y + ) : self { + $path = clone $this; + $path->operations[] = new EllipticArc($xRadius, $yRadius, $xAxisRotation, $largeArc, $sweep, $x, $y); + return $path; + } + + /** + * Draws a curve from the current position to another position. + */ + public function curve(float $x1, float $y1, float $x2, float $y2, float $x3, float $y3) : self + { + $path = clone $this; + $path->operations[] = new Curve($x1, $y1, $x2, $y2, $x3, $y3); + return $path; + } + + /** + * Closes a sub-path. + */ + public function close() : self + { + $path = clone $this; + $path->operations[] = Close::instance(); + return $path; + } + + /** + * Appends another path to this one. + */ + public function append(self $other) : self + { + $path = clone $this; + $path->operations = array_merge($this->operations, $other->operations); + return $path; + } + + public function translate(float $x, float $y) : self + { + $path = new self(); + + foreach ($this->operations as $operation) { + $path->operations[] = $operation->translate($x, $y); + } + + return $path; + } + + /** + * @return OperationInterface[]|Traversable + */ + public function getIterator() : Traversable + { + foreach ($this->operations as $operation) { + yield $operation; + } + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php b/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php new file mode 100644 index 0000000..8aa7652 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php @@ -0,0 +1,86 @@ +margin = $margin; + } + + /** + * @throws InvalidArgumentException if matrix width doesn't match height + */ + public function render(QrCode $qrCode) : string + { + $matrix = $qrCode->getMatrix(); + $matrixSize = $matrix->getWidth(); + + if ($matrixSize !== $matrix->getHeight()) { + throw new InvalidArgumentException('Matrix must have the same width and height'); + } + + $rows = $matrix->getArray()->toArray(); + + if (0 !== $matrixSize % 2) { + $rows[] = array_fill(0, $matrixSize, 0); + } + + $horizontalMargin = str_repeat(self::EMPTY_BLOCK, $this->margin); + $result = str_repeat("\n", (int) ceil($this->margin / 2)); + + for ($i = 0; $i < $matrixSize; $i += 2) { + $result .= $horizontalMargin; + + $upperRow = $rows[$i]; + $lowerRow = $rows[$i + 1]; + + for ($j = 0; $j < $matrixSize; ++$j) { + $upperBit = $upperRow[$j]; + $lowerBit = $lowerRow[$j]; + + if ($upperBit) { + $result .= $lowerBit ? self::FULL_BLOCK : self::UPPER_HALF_BLOCK; + } else { + $result .= $lowerBit ? self::LOWER_HALF_BLOCK : self::EMPTY_BLOCK; + } + } + + $result .= $horizontalMargin . "\n"; + } + + $result .= str_repeat("\n", (int) ceil($this->margin / 2)); + + return $result; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php b/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php new file mode 100644 index 0000000..b0aae39 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php @@ -0,0 +1,11 @@ +externalColor = $externalColor; + $this->internalColor = $internalColor; + } + + public static function uniform(ColorInterface $color) : self + { + return new self($color, $color); + } + + public static function inherit() : self + { + return self::$inherit ?: self::$inherit = new self(null, null); + } + + public function inheritsBothColors() : bool + { + return null === $this->externalColor && null === $this->internalColor; + } + + public function inheritsExternalColor() : bool + { + return null === $this->externalColor; + } + + public function inheritsInternalColor() : bool + { + return null === $this->internalColor; + } + + public function getExternalColor() : ColorInterface + { + if (null === $this->externalColor) { + throw new RuntimeException('External eye color inherits foreground color'); + } + + return $this->externalColor; + } + + public function getInternalColor() : ColorInterface + { + if (null === $this->internalColor) { + throw new RuntimeException('Internal eye color inherits foreground color'); + } + + return $this->internalColor; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php b/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php new file mode 100644 index 0000000..d54268e --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php @@ -0,0 +1,168 @@ +backgroundColor = $backgroundColor; + $this->foregroundColor = $foregroundColor; + $this->foregroundGradient = $foregroundGradient; + $this->topLeftEyeFill = $topLeftEyeFill; + $this->topRightEyeFill = $topRightEyeFill; + $this->bottomLeftEyeFill = $bottomLeftEyeFill; + } + + public static function default() : self + { + return self::$default ?: self::$default = self::uniformColor(new Gray(100), new Gray(0)); + } + + public static function withForegroundColor( + ColorInterface $backgroundColor, + ColorInterface $foregroundColor, + EyeFill $topLeftEyeFill, + EyeFill $topRightEyeFill, + EyeFill $bottomLeftEyeFill + ) : self { + return new self( + $backgroundColor, + $foregroundColor, + null, + $topLeftEyeFill, + $topRightEyeFill, + $bottomLeftEyeFill + ); + } + + public static function withForegroundGradient( + ColorInterface $backgroundColor, + Gradient $foregroundGradient, + EyeFill $topLeftEyeFill, + EyeFill $topRightEyeFill, + EyeFill $bottomLeftEyeFill + ) : self { + return new self( + $backgroundColor, + null, + $foregroundGradient, + $topLeftEyeFill, + $topRightEyeFill, + $bottomLeftEyeFill + ); + } + + public static function uniformColor(ColorInterface $backgroundColor, ColorInterface $foregroundColor) : self + { + return new self( + $backgroundColor, + $foregroundColor, + null, + EyeFill::inherit(), + EyeFill::inherit(), + EyeFill::inherit() + ); + } + + public static function uniformGradient(ColorInterface $backgroundColor, Gradient $foregroundGradient) : self + { + return new self( + $backgroundColor, + null, + $foregroundGradient, + EyeFill::inherit(), + EyeFill::inherit(), + EyeFill::inherit() + ); + } + + public function hasGradientFill() : bool + { + return null !== $this->foregroundGradient; + } + + public function getBackgroundColor() : ColorInterface + { + return $this->backgroundColor; + } + + public function getForegroundColor() : ColorInterface + { + if (null === $this->foregroundColor) { + throw new RuntimeException('Fill uses a gradient, thus no foreground color is available'); + } + + return $this->foregroundColor; + } + + public function getForegroundGradient() : Gradient + { + if (null === $this->foregroundGradient) { + throw new RuntimeException('Fill uses a single color, thus no foreground gradient is available'); + } + + return $this->foregroundGradient; + } + + public function getTopLeftEyeFill() : EyeFill + { + return $this->topLeftEyeFill; + } + + public function getTopRightEyeFill() : EyeFill + { + return $this->topRightEyeFill; + } + + public function getBottomLeftEyeFill() : EyeFill + { + return $this->bottomLeftEyeFill; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php b/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php new file mode 100644 index 0000000..3813dfd --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php @@ -0,0 +1,46 @@ +startColor = $startColor; + $this->endColor = $endColor; + $this->type = $type; + } + + public function getStartColor() : ColorInterface + { + return $this->startColor; + } + + public function getEndColor() : ColorInterface + { + return $this->endColor; + } + + public function getType() : GradientType + { + return $this->type; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php b/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php new file mode 100644 index 0000000..c1ca754 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php @@ -0,0 +1,22 @@ +margin = $margin; + $this->size = $size; + $this->module = $module ?: SquareModule::instance(); + $this->eye = $eye ?: new ModuleEye($this->module); + $this->fill = $fill ?: Fill::default(); + } + + public function withSize(int $size) : self + { + $style = clone $this; + $style->size = $size; + return $style; + } + + public function withMargin(int $margin) : self + { + $style = clone $this; + $style->margin = $margin; + return $style; + } + + public function getSize() : int + { + return $this->size; + } + + public function getMargin() : int + { + return $this->margin; + } + + public function getModule() : ModuleInterface + { + return $this->module; + } + + public function getEye() : EyeInterface + { + return $this->eye; + } + + public function getFill() : Fill + { + return $this->fill; + } +} diff --git a/vendor/bacon/bacon-qr-code/src/Writer.php b/vendor/bacon/bacon-qr-code/src/Writer.php new file mode 100644 index 0000000..d5bdc5c --- /dev/null +++ b/vendor/bacon/bacon-qr-code/src/Writer.php @@ -0,0 +1,71 @@ +renderer = $renderer; + } + + /** + * Writes QR code and returns it as string. + * + * Content is a string which *should* be encoded in UTF-8, in case there are + * non ASCII-characters present. + * + * @throws InvalidArgumentException if the content is empty + */ + public function writeString( + string $content, + string $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + ?ErrorCorrectionLevel $ecLevel = null, + ?Version $forcedVersion = null + ) : string { + if (strlen($content) === 0) { + throw new InvalidArgumentException('Found empty contents'); + } + + if (null === $ecLevel) { + $ecLevel = ErrorCorrectionLevel::L(); + } + + return $this->renderer->render(Encoder::encode($content, $ecLevel, $encoding, $forcedVersion)); + } + + /** + * Writes QR code to a file. + * + * @see Writer::writeString() + */ + public function writeFile( + string $content, + string $filename, + string $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING, + ?ErrorCorrectionLevel $ecLevel = null, + ?Version $forcedVersion = null + ) : void { + file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel, $forcedVersion)); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php b/vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php new file mode 100644 index 0000000..add798b --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php @@ -0,0 +1,222 @@ +assertFalse($array->get($i)); + $array->set($i); + $this->assertTrue($array->get($i)); + } + } + + public function testGetNextSet1() : void + { + $array = new BitArray(32); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, 32, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, 32, $array->getNextSet($i)); + } + } + + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, 33, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, 33, $array->getNextSet($i)); + } + } + } + + public function testGetNextSet2() : void + { + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, $i <= 31 ? 31 : 33, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, $i <= 31 ? 31 : 33, $array->getNextSet($i)); + } + } + + $array = new BitArray(33); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, 32, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, 32, $array->getNextSet($i)); + } + } + } + + public function testGetNextSet3() : void + { + $array = new BitArray(63); + $array->set(31); + $array->set(32); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($i <= 31) { + $expected = 31; + } elseif ($i <= 32) { + $expected = 32; + } else { + $expected = 63; + } + + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, $expected, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, $expected, $array->getNextSet($i)); + } + } + } + + public function testGetNextSet4() : void + { + $array = new BitArray(63); + $array->set(33); + $array->set(40); + + for ($i = 0; $i < $array->getSize(); ++$i) { + if ($i <= 33) { + $expected = 33; + } elseif ($i <= 40) { + $expected = 40; + } else { + $expected = 63; + } + + if ($this->getPhpUnitMajorVersion() === 7) { + $this->assertEquals($i, $expected, '', $array->getNextSet($i)); + } else { + $this->assertEqualsWithDelta($i, $expected, $array->getNextSet($i)); + } + } + } + + public function testGetNextSet5() : void + { + mt_srand(0xdeadbeef, MT_RAND_PHP); + + for ($i = 0; $i < 10; ++$i) { + $array = new BitArray(mt_rand(1, 100)); + $numSet = mt_rand(0, 19); + + for ($j = 0; $j < $numSet; ++$j) { + $array->set(mt_rand(0, $array->getSize() - 1)); + } + + $numQueries = mt_rand(0, 19); + + for ($j = 0; $j < $numQueries; ++$j) { + $query = mt_rand(0, $array->getSize() - 1); + $expected = $query; + + while ($expected < $array->getSize() && ! $array->get($expected)) { + ++$expected; + } + + $actual = $array->getNextSet($query); + + if ($actual !== $expected) { + $array->getNextSet($query); + } + + $this->assertEquals($expected, $actual); + } + } + } + + public function testSetBulk() : void + { + $array = new BitArray(64); + $array->setBulk(32, 0xFFFF0000); + + for ($i = 0; $i < 48; ++$i) { + $this->assertFalse($array->get($i)); + } + + for ($i = 48; $i < 64; ++$i) { + $this->assertTrue($array->get($i)); + } + } + + public function testClear() : void + { + $array = new BitArray(32); + + for ($i = 0; $i < 32; ++$i) { + $array->set($i); + } + + $array->clear(); + + for ($i = 0; $i < 32; ++$i) { + $this->assertFalse($array->get($i)); + } + } + + public function testGetArray() : void + { + $array = new BitArray(64); + $array->set(0); + $array->set(63); + + $ints = $array->getBitArray(); + + $this->assertSame(1, $ints[0]); + $this->assertSame(0x80000000, $ints[1]); + } + + public function testIsRange() : void + { + $array = new BitArray(64); + $this->assertTrue($array->isRange(0, 64, false)); + $this->assertFalse($array->isRange(0, 64, true)); + + $array->set(32); + $this->assertTrue($array->isRange(32, 33, true)); + + $array->set(31); + $this->assertTrue($array->isRange(31, 33, true)); + + $array->set(34); + $this->assertFalse($array->isRange(31, 35, true)); + + for ($i = 0; $i < 31; ++$i) { + $array->set($i); + } + + $this->assertTrue($array->isRange(0, 33, true)); + + for ($i = 33; $i < 64; ++$i) { + $array->set($i); + } + + $this->assertTrue($array->isRange(0, 64, true)); + $this->assertFalse($array->isRange(0, 64, false)); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php b/vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php new file mode 100644 index 0000000..8ad86d4 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php @@ -0,0 +1,115 @@ +assertEquals(33, $matrix->getHeight()); + + for ($y = 0; $y < 33; ++$y) { + for ($x = 0; $x < 33; ++$x) { + if ($y * $x % 3 === 0) { + $matrix->set($x, $y); + } + } + } + + for ($y = 0; $y < 33; $y++) { + for ($x = 0; $x < 33; ++$x) { + $this->assertSame(0 === $x * $y % 3, $matrix->get($x, $y)); + } + } + } + + public function testSetRegion() : void + { + $matrix = new BitMatrix(5); + $matrix->setRegion(1, 1, 3, 3); + + for ($y = 0; $y < 5; ++$y) { + for ($x = 0; $x < 5; ++$x) { + $this->assertSame($y >= 1 && $y <= 3 && $x >= 1 && $x <= 3, $matrix->get($x, $y)); + } + } + } + + public function testRectangularMatrix() : void + { + $matrix = new BitMatrix(75, 20); + $this->assertSame(75, $matrix->getWidth()); + $this->assertSame(20, $matrix->getHeight()); + + $matrix->set(10, 0); + $matrix->set(11, 1); + $matrix->set(50, 2); + $matrix->set(51, 3); + $matrix->flip(74, 4); + $matrix->flip(0, 5); + + $this->assertTrue($matrix->get(10, 0)); + $this->assertTrue($matrix->get(11, 1)); + $this->assertTrue($matrix->get(50, 2)); + $this->assertTrue($matrix->get(51, 3)); + $this->assertTrue($matrix->get(74, 4)); + $this->assertTrue($matrix->get(0, 5)); + + $matrix->flip(50, 2); + $matrix->flip(51, 3); + + $this->assertFalse($matrix->get(50, 2)); + $this->assertFalse($matrix->get(51, 3)); + } + + public function testRectangularSetRegion() : void + { + $matrix = new BitMatrix(320, 240); + $this->assertSame(320, $matrix->getWidth()); + $this->assertSame(240, $matrix->getHeight()); + + $matrix->setRegion(105, 22, 80, 12); + + for ($y = 0; $y < 240; ++$y) { + for ($x = 0; $x < 320; ++$x) { + $this->assertEquals($y >= 22 && $y < 34 && $x >= 105 && $x < 185, $matrix->get($x, $y)); + } + } + } + + public function testGetRow() : void + { + $matrix = new BitMatrix(102, 5); + + for ($x = 0; $x < 102; ++$x) { + if (0 === ($x & 3)) { + $matrix->set($x, 2); + } + } + + $array1 = $matrix->getRow(2, null); + $this->assertSame(102, $array1->getSize()); + + $array2 = new BitArray(60); + $array2 = $matrix->getRow(2, $array2); + $this->assertSame(102, $array2->getSize()); + + $array3 = new BitArray(200); + $array3 = $matrix->getRow(2, $array3); + $this->assertSame(200, $array3->getSize()); + + for ($x = 0; $x < 102; ++$x) { + $on = (0 === ($x & 3)); + + $this->assertSame($on, $array1->get($x)); + $this->assertSame($on, $array2->get($x)); + $this->assertSame($on, $array3->get($x)); + } + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php b/vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php new file mode 100644 index 0000000..2904d31 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php @@ -0,0 +1,25 @@ +assertSame(1, BitUtils::unsignedRightShift(1, 0)); + $this->assertSame(1, BitUtils::unsignedRightShift(10, 3)); + $this->assertSame(536870910, BitUtils::unsignedRightShift(-10, 3)); + } + + public function testNumberOfTrailingZeros() : void + { + $this->assertSame(32, BitUtils::numberOfTrailingZeros(0)); + $this->assertSame(1, BitUtils::numberOfTrailingZeros(10)); + $this->assertSame(0, BitUtils::numberOfTrailingZeros(15)); + $this->assertSame(2, BitUtils::numberOfTrailingZeros(20)); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php b/vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php new file mode 100644 index 0000000..369b5d9 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php @@ -0,0 +1,25 @@ +assertSame(0x0, ErrorCorrectionLevel::M()->getBits()); + $this->assertSame(0x1, ErrorCorrectionLevel::L()->getBits()); + $this->assertSame(0x2, ErrorCorrectionLevel::H()->getBits()); + $this->assertSame(0x3, ErrorCorrectionLevel::Q()->getBits()); + } + + public function testInvalidErrorCorrectionLevelThrowsException() : void + { + $this->expectException(OutOfBoundsException::class); + ErrorCorrectionLevel::forBits(4); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php b/vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php new file mode 100644 index 0000000..39534a2 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php @@ -0,0 +1,94 @@ +assertSame(0, FormatInformation::numBitsDiffering(1, 1)); + $this->assertSame(1, FormatInformation::numBitsDiffering(0, 2)); + $this->assertSame(2, FormatInformation::numBitsDiffering(1, 2)); + $this->assertEquals(32, FormatInformation::numBitsDiffering(-1, 0)); + } + + public function testDecode() : void + { + $expected = FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO, + self::MASKED_TEST_FORMAT_INFO + ); + + $this->assertNotNull($expected); + $this->assertSame(7, $expected->getDataMask()); + $this->assertSame(ErrorCorrectionLevel::Q(), $expected->getErrorCorrectionLevel()); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::UNMAKSED_TEST_FORMAT_INFO, + self::MASKED_TEST_FORMAT_INFO + ) + ); + } + + public function testDecodeWithBitDifference() : void + { + $expected = FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO, + self::MASKED_TEST_FORMAT_INFO + ); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0x1, + self::MASKED_TEST_FORMAT_INFO ^ 0x1 + ) + ); + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0x3, + self::MASKED_TEST_FORMAT_INFO ^ 0x3 + ) + ); + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0x7, + self::MASKED_TEST_FORMAT_INFO ^ 0x7 + ) + ); + $this->assertNull( + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0xf, + self::MASKED_TEST_FORMAT_INFO ^ 0xf + ) + ); + } + + public function testDecodeWithMisRead() : void + { + $expected = FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO, + self::MASKED_TEST_FORMAT_INFO + ); + + $this->assertEquals( + $expected, + FormatInformation::decodeFormatInformation( + self::MASKED_TEST_FORMAT_INFO ^ 0x3, + self::MASKED_TEST_FORMAT_INFO ^ 0xf + ) + ); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Common/ModeTest.php b/vendor/bacon/bacon-qr-code/test/Common/ModeTest.php new file mode 100644 index 0000000..51fcb3e --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Common/ModeTest.php @@ -0,0 +1,19 @@ +assertSame(0x0, Mode::TERMINATOR()->getBits()); + $this->assertSame(0x1, Mode::NUMERIC()->getBits()); + $this->assertSame(0x2, Mode::ALPHANUMERIC()->getBits()); + $this->assertSame(0x4, Mode::BYTE()->getBits()); + $this->assertSame(0x8, Mode::KANJI()->getBits()); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php b/vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php new file mode 100644 index 0000000..47975b5 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php @@ -0,0 +1,96 @@ +encode($block, $parity); + + // Copy parity into test blocks + for ($i = 0; $i < $numRoots; ++$i) { + $block[$i + $dataSize] = $parity[$i]; + $tBlock[$i + $dataSize] = $parity[$i]; + } + + // Seed with errors + for ($i = 0; $i < $errors; ++$i) { + $errorValue = mt_rand(1, $blockSize); + + do { + $errorLocation = mt_rand(0, $blockSize); + } while (0 !== $errorLocations[$errorLocation]); + + $errorLocations[$errorLocation] = 1; + + if (mt_rand(0, 1)) { + $erasures[] = $errorLocation; + } + + $tBlock[$errorLocation] ^= $errorValue; + } + + $erasures = SplFixedArray::fromArray($erasures, false); + + // Decode the errored block + $foundErrors = $codec->decode($tBlock, $erasures); + + if ($errors > 0 && null === $foundErrors) { + $this->assertSame($block, $tBlock, 'Decoder failed to correct errors'); + } + + $this->assertSame($errors, $foundErrors, 'Found errors do not equal expected errors'); + + for ($i = 0; $i < $foundErrors; ++$i) { + if (0 === $errorLocations[$erasures[$i]]) { + $this->fail(sprintf('Decoder indicates error in location %d without error', $erasures[$i])); + } + } + + $this->assertEquals($block, $tBlock, 'Decoder did not correct errors'); + } + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Common/VersionTest.php b/vendor/bacon/bacon-qr-code/test/Common/VersionTest.php new file mode 100644 index 0000000..f6f038b --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Common/VersionTest.php @@ -0,0 +1,78 @@ +assertNotNull($version); + $this->assertEquals($versionNumber, $version->getVersionNumber()); + $this->assertNotNull($version->getAlignmentPatternCenters()); + + if ($versionNumber > 1) { + $this->assertTrue(count($version->getAlignmentPatternCenters()) > 0); + } + + $this->assertEquals($dimension, $version->getDimensionForVersion()); + $this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::H())); + $this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::L())); + $this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::M())); + $this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::Q())); + $this->assertNotNull($version->buildFunctionPattern()); + } + + /** + * @dataProvider versions + */ + public function testGetProvisionalVersionForDimension(int $versionNumber, int $dimension) : void + { + $this->assertSame( + $versionNumber, + Version::getProvisionalVersionForDimension($dimension)->getVersionNumber() + ); + } + + /** + * @dataProvider decodeInformation + */ + public function testDecodeVersionInformation(int $expectedVersion, int $mask) : void + { + $version = Version::decodeVersionInformation($mask); + $this->assertNotNull($version); + $this->assertSame($expectedVersion, $version->getVersionNumber()); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php b/vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php new file mode 100644 index 0000000..9baa66b --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php @@ -0,0 +1,487 @@ +getMethods(ReflectionMethod::IS_STATIC) as $method) { + $method->setAccessible(true); + $this->methods[$method->getName()] = $method; + } + } + + public function testGetAlphanumericCode() : void + { + // The first ten code points are numbers. + for ($i = 0; $i < 10; ++$i) { + $this->assertSame($i, $this->methods['getAlphanumericCode']->invoke(null, ord('0') + $i)); + } + + // The next 26 code points are capital alphabet letters. + for ($i = 10; $i < 36; ++$i) { + // The first ten code points are numbers + $this->assertSame($i, $this->methods['getAlphanumericCode']->invoke(null, ord('A') + $i - 10)); + } + + // Others are symbol letters. + $this->assertSame(36, $this->methods['getAlphanumericCode']->invoke(null, ord(' '))); + $this->assertSame(37, $this->methods['getAlphanumericCode']->invoke(null, ord('$'))); + $this->assertSame(38, $this->methods['getAlphanumericCode']->invoke(null, ord('%'))); + $this->assertSame(39, $this->methods['getAlphanumericCode']->invoke(null, ord('*'))); + $this->assertSame(40, $this->methods['getAlphanumericCode']->invoke(null, ord('+'))); + $this->assertSame(41, $this->methods['getAlphanumericCode']->invoke(null, ord('-'))); + $this->assertSame(42, $this->methods['getAlphanumericCode']->invoke(null, ord('.'))); + $this->assertSame(43, $this->methods['getAlphanumericCode']->invoke(null, ord('/'))); + $this->assertSame(44, $this->methods['getAlphanumericCode']->invoke(null, ord(':'))); + + // Should return -1 for other letters. + $this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord('a'))); + $this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord('#'))); + $this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord("\0"))); + } + + public function testChooseMode() : void + { + // Numeric mode + $this->assertSame(Mode::NUMERIC(), $this->methods['chooseMode']->invoke(null, '0')); + $this->assertSame(Mode::NUMERIC(), $this->methods['chooseMode']->invoke(null, '0123456789')); + + // Alphanumeric mode + $this->assertSame(Mode::ALPHANUMERIC(), $this->methods['chooseMode']->invoke(null, 'A')); + $this->assertSame( + Mode::ALPHANUMERIC(), + $this->methods['chooseMode']->invoke(null, '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:') + ); + + // 8-bit byte mode + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, 'a')); + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '#')); + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '')); + + // AIUE in Hiragana in SHIFT-JIS + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\x8\xa\x8\xa\x8\xa\x8\xa6")); + + // Nihon in Kanji in SHIFT-JIS + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\x9\xf\x9\x7b")); + + // Sou-Utso-Byou in Kanji in SHIFT-JIS + $this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\xe\x4\x9\x5\x9\x61")); + } + + public function testEncode() : void + { + $qrCode = Encoder::encode('ABCDEF', ErrorCorrectionLevel::H()); + $expected = "<<\n" + . " mode: ALPHANUMERIC\n" + . " ecLevel: H\n" + . " version: 1\n" + . " maskPattern: 0\n" + . " matrix:\n" + . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" + . " 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" + . " 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" + . " 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" + . " 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" + . " 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" + . " 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" + . " 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" + . ">>\n"; + + $this->assertSame($expected, (string) $qrCode); + } + + public function testSimpleUtf8Eci() : void + { + $qrCode = Encoder::encode('hello', ErrorCorrectionLevel::H(), 'utf-8'); + $expected = "<<\n" + . " mode: BYTE\n" + . " ecLevel: H\n" + . " version: 1\n" + . " maskPattern: 3\n" + . " matrix:\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 0 0 0 0\n" + . " 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0\n" + . " 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 1 1 1\n" + . " 1 1 0 0 1 0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 0\n" + . " 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 1 0 0\n" + . " 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0\n" + . " 1 0 1 1 1 0 1 0 1 1 0 0 0 1 0 0 1 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 1 1 0\n" + . " 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 1 1 0 0 0 0\n" + . ">>\n"; + + $this->assertSame($expected, (string) $qrCode); + } + + public function testAppendModeInfo() : void + { + $bits = new BitArray(); + $this->methods['appendModeInfo']->invoke(null, Mode::NUMERIC(), $bits); + $this->assertSame(' ...X', (string) $bits); + } + + public function testAppendLengthInfo() : void + { + // 1 letter (1/1), 10 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 1, + Version::getVersionForNumber(1), + Mode::NUMERIC(), + $bits + ); + $this->assertSame(' ........ .X', (string) $bits); + + // 2 letters (2/1), 11 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 2, + Version::getVersionForNumber(10), + Mode::ALPHANUMERIC(), + $bits + ); + $this->assertSame(' ........ .X.', (string) $bits); + + // 255 letters (255/1), 16 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 255, + Version::getVersionForNumber(27), + Mode::BYTE(), + $bits + ); + $this->assertSame(' ........ XXXXXXXX', (string) $bits); + + // 512 letters (1024/2), 12 bits. + $bits = new BitArray(); + $this->methods['appendLengthInfo']->invoke( + null, + 512, + Version::getVersionForNumber(40), + Mode::KANJI(), + $bits + ); + $this->assertSame(' ..X..... ....', (string) $bits); + } + + public function testAppendBytes() : void + { + // Should use appendNumericBytes. + // 1 = 01 = 0001 in 4 bits. + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + '1', + Mode::NUMERIC(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertSame(' ...X', (string) $bits); + + // Should use appendAlphaNumericBytes. + // A = 10 = 0xa = 001010 in 6 bits. + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + 'A', + Mode::ALPHANUMERIC(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertSame(' ..X.X.', (string) $bits); + + // Should use append8BitBytes. + // 0x61, 0x62, 0x63 + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + 'abc', + Mode::BYTE(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertSame(' .XX....X .XX...X. .XX...XX', (string) $bits); + + // Should use appendKanjiBytes. + // 0x93, 0x5f + $bits = new BitArray(); + $this->methods['appendBytes']->invoke( + null, + "\x93\x5f", + Mode::KANJI(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + $this->assertSame(' .XX.XX.. XXXXX', (string) $bits); + + // Lower letters such as 'a' cannot be encoded in alphanumeric mode. + $this->expectException(WriterException::class); + $this->methods['appendBytes']->invoke( + null, + 'a', + Mode::ALPHANUMERIC(), + $bits, + Encoder::DEFAULT_BYTE_MODE_ECODING + ); + } + + public function testTerminateBits() : void + { + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 0, $bits); + $this->assertSame('', (string) $bits); + + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertSame(' ........', (string) $bits); + + $bits = new BitArray(); + $bits->appendBits(0, 3); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertSame(' ........', (string) $bits); + + $bits = new BitArray(); + $bits->appendBits(0, 5); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertSame(' ........', (string) $bits); + + $bits = new BitArray(); + $bits->appendBits(0, 8); + $this->methods['terminateBits']->invoke(null, 1, $bits); + $this->assertSame(' ........', (string) $bits); + + $bits = new BitArray(); + $this->methods['terminateBits']->invoke(null, 2, $bits); + $this->assertSame(' ........ XXX.XX..', (string) $bits); + + $bits = new BitArray(); + $bits->appendBits(0, 1); + $this->methods['terminateBits']->invoke(null, 3, $bits); + $this->assertSame(' ........ XXX.XX.. ...X...X', (string) $bits); + } + + public function testGetNumDataBytesAndNumEcBytesForBlockId() : void + { + // Version 1-H. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 26, 9, 1, 0); + $this->assertSame(9, $numDataBytes); + $this->assertSame(17, $numEcBytes); + + // Version 3-H. 2 blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 70, 26, 2, 0); + $this->assertSame(13, $numDataBytes); + $this->assertSame(22, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 70, 26, 2, 1); + $this->assertSame(13, $numDataBytes); + $this->assertSame(22, $numEcBytes); + + // Version 7-H. (4 + 1) blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 196, 66, 5, 0); + $this->assertSame(13, $numDataBytes); + $this->assertSame(26, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 196, 66, 5, 4); + $this->assertSame(14, $numDataBytes); + $this->assertSame(26, $numEcBytes); + + // Version 40-H. (20 + 61) blocks. + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 3706, 1276, 81, 0); + $this->assertSame(15, $numDataBytes); + $this->assertSame(30, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 3706, 1276, 81, 20); + $this->assertSame(16, $numDataBytes); + $this->assertSame(30, $numEcBytes); + list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId'] + ->invoke(null, 3706, 1276, 81, 80); + $this->assertSame(16, $numDataBytes); + $this->assertSame(30, $numEcBytes); + } + + public function testInterleaveWithEcBytes() : void + { + $dataBytes = SplFixedArray::fromArray([32, 65, 205, 69, 41, 220, 46, 128, 236], false); + $in = new BitArray(); + + foreach ($dataBytes as $dataByte) { + $in->appendBits($dataByte, 8); + } + + $outBits = $this->methods['interleaveWithEcBytes']->invoke(null, $in, 26, 9, 1); + $expected = SplFixedArray::fromArray([ + // Data bytes. + 32, 65, 205, 69, 41, 220, 46, 128, 236, + // Error correction bytes. + 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61, + ], false); + + $out = $outBits->toBytes(0, count($expected)); + + $this->assertEquals($expected, $out); + } + + public function testAppendNumericBytes() : void + { + // 1 = 01 = 0001 in 4 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '1', $bits); + $this->assertSame(' ...X', (string) $bits); + + // 12 = 0xc = 0001100 in 7 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '12', $bits); + $this->assertSame(' ...XX..', (string) $bits); + + // 123 = 0x7b = 0001111011 in 10 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '123', $bits); + $this->assertSame(' ...XXXX. XX', (string) $bits); + + // 1234 = "123" + "4" = 0001111011 + 0100 in 14 bits. + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '1234', $bits); + $this->assertSame(' ...XXXX. XX.X..', (string) $bits); + + // Empty + $bits = new BitArray(); + $this->methods['appendNumericBytes']->invoke(null, '', $bits); + $this->assertSame('', (string) $bits); + } + + public function testAppendAlphanumericBytes() : void + { + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'A', $bits); + $this->assertSame(' ..X.X.', (string) $bits); + + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'AB', $bits); + $this->assertSame(' ..XXX..X X.X', (string) $bits); + + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'ABC', $bits); + $this->assertSame(' ..XXX..X X.X..XX. .', (string) $bits); + + // Empty + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, '', $bits); + $this->assertSame('', (string) $bits); + + // Invalid data + $this->expectException(WriterException::class); + $bits = new BitArray(); + $this->methods['appendAlphanumericBytes']->invoke(null, 'abc', $bits); + } + + public function testAppend8BitBytes() : void + { + // 0x61, 0x62, 0x63 + $bits = new BitArray(); + $this->methods['append8BitBytes']->invoke(null, 'abc', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING); + $this->assertSame(' .XX....X .XX...X. .XX...XX', (string) $bits); + + // Empty + $bits = new BitArray(); + $this->methods['append8BitBytes']->invoke(null, '', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING); + $this->assertSame('', (string) $bits); + } + + public function testAppendKanjiBytes() : void + { + // Numbers are from page 21 of JISX0510:2004 + $bits = new BitArray(); + $this->methods['appendKanjiBytes']->invoke(null, "\x93\x5f", $bits); + $this->assertSame(' .XX.XX.. XXXXX', (string) $bits); + + $this->methods['appendKanjiBytes']->invoke(null, "\xe4\xaa", $bits); + $this->assertSame(' .XX.XX.. XXXXXXX. X.X.X.X. X.', (string) $bits); + } + + public function testGenerateEcBytes() : void + { + // Numbers are from http://www.swetake.com/qr/qr3.html and + // http://www.swetake.com/qr/qr9.html + $dataBytes = SplFixedArray::fromArray([32, 65, 205, 69, 41, 220, 46, 128, 236], false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17); + $expected = SplFixedArray::fromArray( + [42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61], + false + ); + $this->assertEquals($expected, $ecBytes); + + $dataBytes = SplFixedArray::fromArray( + [67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214], + false + ); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 18); + $expected = SplFixedArray::fromArray( + [175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187], + false + ); + $this->assertEquals($expected, $ecBytes); + + // High-order zero coefficient case. + $dataBytes = SplFixedArray::fromArray([32, 49, 205, 69, 42, 20, 0, 236, 17], false); + $ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17); + $expected = SplFixedArray::fromArray( + [0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213], + false + ); + $this->assertEquals($expected, $ecBytes); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php b/vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php new file mode 100644 index 0000000..46670fc --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php @@ -0,0 +1,251 @@ +assertSame( + 1 === $expected[$y][$x], + MaskUtil::getDataMaskBit($maskPattern, $x, $y) + ); + } + } + } + + public function testApplyMaskPenaltyRule1() : void + { + $matrix = new ByteMatrix(4, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + + $this->assertSame(0, MaskUtil::applyMaskPenaltyRule1($matrix)); + + // Horizontal + $matrix = new ByteMatrix(6, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + $matrix->set(4, 0, 0); + $matrix->set(5, 0, 1); + $this->assertSame(3, MaskUtil::applyMaskPenaltyRule1($matrix)); + $matrix->set(5, 0, 0); + $this->assertSame(4, MaskUtil::applyMaskPenaltyRule1($matrix)); + + // Vertical + $matrix = new ByteMatrix(1, 6); + $matrix->set(0, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(0, 3, 0); + $matrix->set(0, 4, 0); + $matrix->set(0, 5, 1); + $this->assertSame(3, MaskUtil::applyMaskPenaltyRule1($matrix)); + $matrix->set(0, 5, 0); + $this->assertSame(4, MaskUtil::applyMaskPenaltyRule1($matrix)); + } + + public function testApplyMaskPenaltyRule2() : void + { + $matrix = new ByteMatrix(1, 1); + $matrix->set(0, 0, 0); + $this->assertSame(0, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(2, 2); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 1); + $this->assertSame(0, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(2, 2); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 0); + $this->assertSame(3, MaskUtil::applyMaskPenaltyRule2($matrix)); + + $matrix = new ByteMatrix(3, 3); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(1, 1, 0); + $matrix->set(2, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(1, 2, 0); + $matrix->set(2, 2, 0); + $this->assertSame(3 * 4, MaskUtil::applyMaskPenaltyRule2($matrix)); + } + + public function testApplyMaskPenalty3() : void + { + // Horizontal 00001011101 + $matrix = new ByteMatrix(11, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 0); + $matrix->set(3, 0, 0); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $matrix->set(6, 0, 1); + $matrix->set(7, 0, 1); + $matrix->set(8, 0, 1); + $matrix->set(9, 0, 0); + $matrix->set(10, 0, 1); + $this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Horizontal 10111010000 + $matrix = new ByteMatrix(11, 1); + $matrix->set(0, 0, 1); + $matrix->set(1, 0, 0); + $matrix->set(2, 0, 1); + $matrix->set(3, 0, 1); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $matrix->set(6, 0, 1); + $matrix->set(7, 0, 0); + $matrix->set(8, 0, 0); + $matrix->set(9, 0, 0); + $matrix->set(10, 0, 0); + $this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Vertical 00001011101 + $matrix = new ByteMatrix(1, 11); + $matrix->set(0, 0, 0); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 0); + $matrix->set(0, 3, 0); + $matrix->set(0, 4, 1); + $matrix->set(0, 5, 0); + $matrix->set(0, 6, 1); + $matrix->set(0, 7, 1); + $matrix->set(0, 8, 1); + $matrix->set(0, 9, 0); + $matrix->set(0, 10, 1); + $this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + + // Vertical 10111010000 + $matrix = new ByteMatrix(1, 11); + $matrix->set(0, 0, 1); + $matrix->set(0, 1, 0); + $matrix->set(0, 2, 1); + $matrix->set(0, 3, 1); + $matrix->set(0, 4, 1); + $matrix->set(0, 5, 0); + $matrix->set(0, 6, 1); + $matrix->set(0, 7, 0); + $matrix->set(0, 8, 0); + $matrix->set(0, 9, 0); + $matrix->set(0, 10, 0); + $this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix)); + } + + public function testApplyMaskPenaltyRule4() : void + { + // Dark cell ratio = 0% + $matrix = new ByteMatrix(1, 1); + $matrix->set(0, 0, 0); + $this->assertSame(100, MaskUtil::applyMaskPenaltyRule4($matrix)); + + // Dark cell ratio = 5% + $matrix = new ByteMatrix(2, 1); + $matrix->set(0, 0, 0); + $matrix->set(0, 0, 1); + $this->assertSame(0, MaskUtil::applyMaskPenaltyRule4($matrix)); + + // Dark cell ratio = 66.67% + $matrix = new ByteMatrix(6, 1); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 1); + $matrix->set(2, 0, 1); + $matrix->set(3, 0, 1); + $matrix->set(4, 0, 1); + $matrix->set(5, 0, 0); + $this->assertSame(30, MaskUtil::applyMaskPenaltyRule4($matrix)); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php b/vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php new file mode 100644 index 0000000..106ceaa --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php @@ -0,0 +1,335 @@ +getMethods(ReflectionMethod::IS_STATIC) as $method) { + $method->setAccessible(true); + $this->methods[$method->getName()] = $method; + } + } + + public function testToString() : void + { + $matrix = new ByteMatrix(3, 3); + $matrix->set(0, 0, 0); + $matrix->set(1, 0, 1); + $matrix->set(2, 0, 0); + $matrix->set(0, 1, 1); + $matrix->set(1, 1, 0); + $matrix->set(2, 1, 1); + $matrix->set(0, 2, -1); + $matrix->set(1, 2, -1); + $matrix->set(2, 2, -1); + + $expected = " 0 1 0\n 1 0 1\n \n"; + $this->assertSame($expected, (string) $matrix); + } + + public function testClearMatrix() : void + { + $matrix = new ByteMatrix(2, 2); + MatrixUtil::clearMatrix($matrix); + + $this->assertSame(-1, $matrix->get(0, 0)); + $this->assertSame(-1, $matrix->get(1, 0)); + $this->assertSame(-1, $matrix->get(0, 1)); + $this->assertSame(-1, $matrix->get(1, 1)); + } + + public function testEmbedBasicPatterns1() : void + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(1), + $matrix + ); + $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 0 0 0 0 0 0 0 1 \n" + . " 1 1 1 1 1 1 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 1 1 1 1 1 1 0 \n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testEmbedBasicPatterns2() : void + { + $matrix = new ByteMatrix(25, 25); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(2), + $matrix + ); + $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 \n" + . " 0 \n" + . " 1 1 1 1 1 1 \n" + . " 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 \n" + . " 1 0 0 0 0 0 1 0 1 0 0 0 1 \n" + . " 1 0 1 1 1 0 1 0 1 1 1 1 1 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 1 1 1 0 1 0 \n" + . " 1 0 0 0 0 0 1 0 \n" + . " 1 1 1 1 1 1 1 0 \n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testEmbedTypeInfo() : void + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedTypeInfo']->invoke( + null, + ErrorCorrectionLevel::M(), + 5, + $matrix + ); + $expected = " 0 \n" + . " 1 \n" + . " 1 \n" + . " 1 \n" + . " 0 \n" + . " 0 \n" + . " \n" + . " 1 \n" + . " 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 0 \n" + . " 1 \n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testEmbedVersionInfo() : void + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['maybeEmbedVersionInfo']->invoke( + null, + Version::getVersionForNumber(7), + $matrix + ); + $expected = " 0 0 1 \n" + . " 0 1 0 \n" + . " 0 1 0 \n" + . " 0 1 1 \n" + . " 1 1 1 \n" + . " 0 0 0 \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " 0 0 0 0 1 0 \n" + . " 0 1 1 1 1 0 \n" + . " 1 0 0 1 1 0 \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n" + . " \n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testEmbedDataBits() : void + { + $matrix = new ByteMatrix(21, 21); + MatrixUtil::clearMatrix($matrix); + $this->methods['embedBasicPatterns']->invoke( + null, + Version::getVersionForNumber(1), + $matrix + ); + + $bits = new BitArray(); + $this->methods['embedDataBits']->invoke( + null, + $bits, + -1, + $matrix + ); + + $expected = " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testBuildMatrix() : void + { + $bytes = [ + 32, 65, 205, 69, 41, 220, 46, 128, 236, 42, 159, 74, 221, 244, 169, + 239, 150, 138, 70, 237, 85, 224, 96, 74, 219 , 61 + ]; + $bits = new BitArray(); + + foreach ($bytes as $byte) { + $bits->appendBits($byte, 8); + } + + $matrix = new ByteMatrix(21, 21); + MatrixUtil::buildMatrix( + $bits, + ErrorCorrectionLevel::H(), + Version::getVersionForNumber(1), + 3, + $matrix + ); + + $expected = " 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" + . " 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n" + . " 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n" + . " 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n" + . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n" + . " 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n" + . " 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n" + . " 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n" + . " 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n" + . " 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n" + . " 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n" + . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n" + . " 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n" + . " 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n" + . " 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n" + . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n" + . " 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n"; + + $this->assertSame($expected, (string) $matrix); + } + + public function testFindMsbSet() : void + { + $this->assertSame(0, $this->methods['findMsbSet']->invoke(null, 0)); + $this->assertSame(1, $this->methods['findMsbSet']->invoke(null, 1)); + $this->assertSame(8, $this->methods['findMsbSet']->invoke(null, 0x80)); + $this->assertSame(32, $this->methods['findMsbSet']->invoke(null, 0x80000000)); + } + + public function testCalculateBchCode() : void + { + // Encoding of type information. + // From Appendix C in JISX0510:2004 (p 65) + $this->assertSame(0xdc, $this->methods['calculateBchCode']->invoke(null, 5, 0x537)); + // From http://www.swetake.com/qr/qr6.html + $this->assertSame(0x1c2, $this->methods['calculateBchCode']->invoke(null, 0x13, 0x537)); + // From http://www.swetake.com/qr/qr11.html + $this->assertSame(0x214, $this->methods['calculateBchCode']->invoke(null, 0x1b, 0x537)); + + // Encoding of version information. + // From Appendix D in JISX0510:2004 (p 68) + $this->assertSame(0xc94, $this->methods['calculateBchCode']->invoke(null, 7, 0x1f25)); + $this->assertSame(0x5bc, $this->methods['calculateBchCode']->invoke(null, 8, 0x1f25)); + $this->assertSame(0xa99, $this->methods['calculateBchCode']->invoke(null, 9, 0x1f25)); + $this->assertSame(0x4d3, $this->methods['calculateBchCode']->invoke(null, 10, 0x1f25)); + $this->assertSame(0x9a6, $this->methods['calculateBchCode']->invoke(null, 20, 0x1f25)); + $this->assertSame(0xd75, $this->methods['calculateBchCode']->invoke(null, 30, 0x1f25)); + $this->assertSame(0xc69, $this->methods['calculateBchCode']->invoke(null, 40, 0x1f25)); + } + + public function testMakeVersionInfoBits() : void + { + // From Appendix D in JISX0510:2004 (p 68) + $bits = new BitArray(); + $this->methods['makeVersionInfoBits']->invoke(null, Version::getVersionForNumber(7), $bits); + $this->assertSame(' ...XXXXX ..X..X.X ..', (string) $bits); + } + + public function testMakeTypeInfoBits() : void + { + // From Appendix D in JISX0510:2004 (p 68) + $bits = new BitArray(); + $this->methods['makeTypeInfoBits']->invoke(null, ErrorCorrectionLevel::M(), 5, $bits); + $this->assertSame(' X......X X..XXX.', (string) $bits); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Integration/ImagickRenderingTest.php b/vendor/bacon/bacon-qr-code/test/Integration/ImagickRenderingTest.php new file mode 100644 index 0000000..3df8687 --- /dev/null +++ b/vendor/bacon/bacon-qr-code/test/Integration/ImagickRenderingTest.php @@ -0,0 +1,72 @@ +writeFile('Hello World!', $tempName); + + $this->assertMatchesFileSnapshot($tempName); + unlink($tempName); + } + + /** + * @requires extension imagick + */ + public function testIssue79() : void + { + $eye = SquareEye::instance(); + $squareModule = SquareModule::instance(); + + $eyeFill = new EyeFill(new Rgb(100, 100, 55), new Rgb(100, 100, 255)); + $gradient = new Gradient(new Rgb(100, 100, 55), new Rgb(100, 100, 255), GradientType::HORIZONTAL()); + + $renderer = new ImageRenderer( + new RendererStyle( + 400, + 2, + $squareModule, + $eye, + Fill::withForegroundGradient(new Rgb(255, 255, 255), $gradient, $eyeFill, $eyeFill, $eyeFill) + ), + new ImagickImageBackEnd() + ); + $writer = new Writer($renderer); + $tempName = tempnam(sys_get_temp_dir(), 'test') . '.png'; + $writer->writeFile('https://apiroad.net/very-long-url', $tempName); + + $this->assertMatchesFileSnapshot($tempName); + unlink($tempName); + } +} diff --git a/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png b/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png new file mode 100644 index 0000000..9a429ed Binary files /dev/null and b/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png differ diff --git a/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png b/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png new file mode 100644 index 0000000..47e3b1a Binary files /dev/null and b/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png differ diff --git a/vendor/dasprid/enum/LICENSE b/vendor/dasprid/enum/LICENSE new file mode 100644 index 0000000..d45a356 --- /dev/null +++ b/vendor/dasprid/enum/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2017, Ben Scholzen 'DASPRiD' +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/dasprid/enum/README.md b/vendor/dasprid/enum/README.md new file mode 100644 index 0000000..da37045 --- /dev/null +++ b/vendor/dasprid/enum/README.md @@ -0,0 +1,164 @@ +# PHP 7.1 enums + +[![Build Status](https://github.com/DASPRiD/Enum/actions/workflows/tests.yml/badge.svg)](https://github.com/DASPRiD/Enum/actions?query=workflow%3Atests) +[![Coverage Status](https://coveralls.io/repos/github/DASPRiD/Enum/badge.svg?branch=master)](https://coveralls.io/github/DASPRiD/Enum?branch=master) +[![Latest Stable Version](https://poser.pugx.org/dasprid/enum/v/stable)](https://packagist.org/packages/dasprid/enum) +[![Total Downloads](https://poser.pugx.org/dasprid/enum/downloads)](https://packagist.org/packages/dasprid/enum) +[![License](https://poser.pugx.org/dasprid/enum/license)](https://packagist.org/packages/dasprid/enum) + +It is a well known fact that PHP is missing a basic enum type, ignoring the rather incomplete `SplEnum` implementation +which is only available as a PECL extension. There are also quite a few other userland enum implementations around, +but all of them have one or another compromise. This library tries to close that gap as far as PHP allows it to. + +## Usage + +### Basics + +At its core, there is the `DASPRiD\Enum\AbstractEnum` class, which by default will work with constants like any other +enum implementation you might know. The first clear difference is that you should define all the constants as protected +(so nobody outside your class can read them but the `AbstractEnum` can still do so). The other even mightier difference +is that, for simple enums, the value of the constant doesn't matter at all. Let's have a look at a simple example: + +```php +use DASPRiD\Enum\AbstractEnum; + +/** + * @method static self MONDAY() + * @method static self TUESDAY() + * @method static self WEDNESDAY() + * @method static self THURSDAY() + * @method static self FRIDAY() + * @method static self SATURDAY() + * @method static self SUNDAY() + */ +final class WeekDay extends AbstractEnum +{ + protected const MONDAY = null; + protected const TUESDAY = null; + protected const WEDNESDAY = null; + protected const THURSDAY = null; + protected const FRIDAY = null; + protected const SATURDAY = null; + protected const SUNDAY = null; +} +``` + +If you need to provide constants for either internal use or public use, you can mark them as either private or public, +in which case they will be ignored by the enum, which only considers protected constants as valid values. As you can +see, we specifically defined the generated magic methods in a class level doc block, so anyone using this class will +automatically have proper auto-completion in their IDE. Now since you have defined the enum, you can simply use it like +that: + +```php +function tellItLikeItIs(WeekDay $weekDay) +{ + switch ($weekDay) { + case WeekDay::MONDAY(): + echo 'Mondays are bad.'; + break; + + case WeekDay::FRIDAY(): + echo 'Fridays are better.'; + break; + + case WeekDay::SATURDAY(): + case WeekDay::SUNDAY(): + echo 'Weekends are best.'; + break; + + default: + echo 'Midweek days are so-so.'; + } +} + +tellItLikeItIs(WeekDay::MONDAY()); +tellItLikeItIs(WeekDay::WEDNESDAY()); +tellItLikeItIs(WeekDay::FRIDAY()); +tellItLikeItIs(WeekDay::SATURDAY()); +tellItLikeItIs(WeekDay::SUNDAY()); +``` + +### More complex example + +Of course, all enums are singletons, which are not cloneable or serializable. Thus you can be sure that there is always +just one instance of the same type. Of course, the values of constants are not completely useless, let's have a look at +a more complex example: + +```php +use DASPRiD\Enum\AbstractEnum; + +/** + * @method static self MERCURY() + * @method static self VENUS() + * @method static self EARTH() + * @method static self MARS() + * @method static self JUPITER() + * @method static self SATURN() + * @method static self URANUS() + * @method static self NEPTUNE() + */ +final class Planet extends AbstractEnum +{ + protected const MERCURY = [3.303e+23, 2.4397e6]; + protected const VENUS = [4.869e+24, 6.0518e6]; + protected const EARTH = [5.976e+24, 6.37814e6]; + protected const MARS = [6.421e+23, 3.3972e6]; + protected const JUPITER = [1.9e+27, 7.1492e7]; + protected const SATURN = [5.688e+26, 6.0268e7]; + protected const URANUS = [8.686e+25, 2.5559e7]; + protected const NEPTUNE = [1.024e+26, 2.4746e7]; + + /** + * Universal gravitational constant. + * + * @var float + */ + private const G = 6.67300E-11; + + /** + * Mass in kilograms. + * + * @var float + */ + private $mass; + + /** + * Radius in meters. + * + * @var float + */ + private $radius; + + protected function __construct(float $mass, float $radius) + { + $this->mass = $mass; + $this->radius = $radius; + } + + public function mass() : float + { + return $this->mass; + } + + public function radius() : float + { + return $this->radius; + } + + public function surfaceGravity() : float + { + return self::G * $this->mass / ($this->radius * $this->radius); + } + + public function surfaceWeight(float $otherMass) : float + { + return $otherMass * $this->surfaceGravity(); + } +} + +$myMass = 80; + +foreach (Planet::values() as $planet) { + printf("Your weight on %s is %f\n", $planet, $planet->surfaceWeight($myMass)); +} +``` diff --git a/vendor/dasprid/enum/composer.json b/vendor/dasprid/enum/composer.json new file mode 100644 index 0000000..a099aba --- /dev/null +++ b/vendor/dasprid/enum/composer.json @@ -0,0 +1,34 @@ +{ + "name": "dasprid/enum", + "description": "PHP 7.1 enum implementation", + "license": "BSD-2-Clause", + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "keywords": [ + "enum", + "map" + ], + "require": { + "php": ">=7.1 <9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "*" + }, + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "DASPRiD\\EnumTest\\": "test/" + } + } +} diff --git a/vendor/dasprid/enum/src/AbstractEnum.php b/vendor/dasprid/enum/src/AbstractEnum.php new file mode 100644 index 0000000..79fe81c --- /dev/null +++ b/vendor/dasprid/enum/src/AbstractEnum.php @@ -0,0 +1,241 @@ +> + */ + private static $values = []; + + /** + * @var array + */ + private static $allValuesLoaded = []; + + /** + * @var array + */ + private static $constants = []; + + /** + * The constructor is private by default to avoid arbitrary enum creation. + * + * When creating your own constructor for a parameterized enum, make sure to declare it as protected, so that + * the static methods are able to construct it. Avoid making it public, as that would allow creation of + * non-singleton enum instances. + */ + private function __construct() + { + } + + /** + * Magic getter which forwards all calls to {@see self::valueOf()}. + * + * @return static + */ + final public static function __callStatic(string $name, array $arguments) : self + { + return static::valueOf($name); + } + + /** + * Returns an enum with the specified name. + * + * The name must match exactly an identifier used to declare an enum in this type (extraneous whitespace characters + * are not permitted). + * + * @return static + * @throws IllegalArgumentException if the enum has no constant with the specified name + */ + final public static function valueOf(string $name) : self + { + if (isset(self::$values[static::class][$name])) { + return self::$values[static::class][$name]; + } + + $constants = self::constants(); + + if (array_key_exists($name, $constants)) { + return self::createValue($name, $constants[$name][0], $constants[$name][1]); + } + + throw new IllegalArgumentException(sprintf('No enum constant %s::%s', static::class, $name)); + } + + /** + * @return static + */ + private static function createValue(string $name, int $ordinal, array $arguments) : self + { + $instance = new static(...$arguments); + $instance->name = $name; + $instance->ordinal = $ordinal; + self::$values[static::class][$name] = $instance; + return $instance; + } + + /** + * Obtains all possible types defined by this enum. + * + * @return static[] + */ + final public static function values() : array + { + if (isset(self::$allValuesLoaded[static::class])) { + return self::$values[static::class]; + } + + if (! isset(self::$values[static::class])) { + self::$values[static::class] = []; + } + + foreach (self::constants() as $name => $constant) { + if (array_key_exists($name, self::$values[static::class])) { + continue; + } + + static::createValue($name, $constant[0], $constant[1]); + } + + uasort(self::$values[static::class], function (self $a, self $b) { + return $a->ordinal() <=> $b->ordinal(); + }); + + self::$allValuesLoaded[static::class] = true; + return self::$values[static::class]; + } + + private static function constants() : array + { + if (isset(self::$constants[static::class])) { + return self::$constants[static::class]; + } + + self::$constants[static::class] = []; + $reflectionClass = new ReflectionClass(static::class); + $ordinal = -1; + + foreach ($reflectionClass->getReflectionConstants() as $reflectionConstant) { + if (! $reflectionConstant->isProtected()) { + continue; + } + + $value = $reflectionConstant->getValue(); + + self::$constants[static::class][$reflectionConstant->name] = [ + ++$ordinal, + is_array($value) ? $value : [] + ]; + } + + return self::$constants[static::class]; + } + + /** + * Returns the name of this enum constant, exactly as declared in its enum declaration. + * + * Most programmers should use the {@see self::__toString()} method in preference to this one, as the toString + * method may return a more user-friendly name. This method is designed primarily for use in specialized situations + * where correctness depends on getting the exact name, which will not vary from release to release. + */ + final public function name() : string + { + return $this->name; + } + + /** + * Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial + * constant is assigned an ordinal of zero). + * + * Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data + * structures. + */ + final public function ordinal() : int + { + return $this->ordinal; + } + + /** + * Compares this enum with the specified object for order. + * + * Returns negative integer, zero or positive integer as this object is less than, equal to or greater than the + * specified object. + * + * Enums are only comparable to other enums of the same type. The natural order implemented by this method is the + * order in which the constants are declared. + * + * @throws MismatchException if the passed enum is not of the same type + */ + final public function compareTo(self $other) : int + { + if (! $other instanceof static) { + throw new MismatchException(sprintf( + 'The passed enum %s is not of the same type as %s', + get_class($other), + static::class + )); + } + + return $this->ordinal - $other->ordinal; + } + + /** + * Forbid cloning enums. + * + * @throws CloneNotSupportedException + */ + final public function __clone() + { + throw new CloneNotSupportedException(); + } + + /** + * Forbid serializing enums. + * + * @throws SerializeNotSupportedException + */ + final public function __sleep() : array + { + throw new SerializeNotSupportedException(); + } + + /** + * Forbid unserializing enums. + * + * @throws UnserializeNotSupportedException + */ + final public function __wakeup() : void + { + throw new UnserializeNotSupportedException(); + } + + /** + * Turns the enum into a string representation. + * + * You may override this method to give a more user-friendly version. + */ + public function __toString() : string + { + return $this->name; + } +} diff --git a/vendor/dasprid/enum/src/EnumMap.php b/vendor/dasprid/enum/src/EnumMap.php new file mode 100644 index 0000000..95b8856 --- /dev/null +++ b/vendor/dasprid/enum/src/EnumMap.php @@ -0,0 +1,385 @@ + + */ + private $keyUniverse; + + /** + * Array representation of this map. The ith element is the value to which universe[i] is currently mapped, or null + * if it isn't mapped to anything, or NullValue if it's mapped to null. + * + * @var array + */ + private $values; + + /** + * @var int + */ + private $size = 0; + + /** + * Creates a new enum map. + * + * @param string $keyType the type of the keys, must extend AbstractEnum + * @param string $valueType the type of the values + * @param bool $allowNullValues whether to allow null values + * @throws IllegalArgumentException when key type does not extend AbstractEnum + */ + public function __construct(string $keyType, string $valueType, bool $allowNullValues) + { + if (! is_subclass_of($keyType, AbstractEnum::class)) { + throw new IllegalArgumentException(sprintf( + 'Class %s does not extend %s', + $keyType, + AbstractEnum::class + )); + } + + $this->keyType = $keyType; + $this->valueType = $valueType; + $this->allowNullValues = $allowNullValues; + $this->keyUniverse = $keyType::values(); + $this->values = array_fill(0, count($this->keyUniverse), null); + } + + public function __serialize(): array + { + $values = []; + + foreach ($this->values as $ordinal => $value) { + if (null === $value) { + continue; + } + + $values[$ordinal] = $this->unmaskNull($value); + } + + return [ + 'keyType' => $this->keyType, + 'valueType' => $this->valueType, + 'allowNullValues' => $this->allowNullValues, + 'values' => $values, + ]; + } + + public function __unserialize(array $data): void + { + $this->unserialize(serialize($data)); + } + + /** + * Checks whether the map types match the supplied ones. + * + * You should call this method when an EnumMap is passed to you and you want to ensure that it's made up of the + * correct types. + * + * @throws ExpectationException when supplied key type mismatches local key type + * @throws ExpectationException when supplied value type mismatches local value type + * @throws ExpectationException when the supplied map allows null values, abut should not + */ + public function expect(string $keyType, string $valueType, bool $allowNullValues) : void + { + if ($keyType !== $this->keyType) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with key type %s, but got %s', + $keyType, + $this->keyType + )); + } + + if ($valueType !== $this->valueType) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with value type %s, but got %s', + $keyType, + $this->keyType + )); + } + + if ($allowNullValues !== $this->allowNullValues) { + throw new ExpectationException(sprintf( + 'Callee expected an EnumMap with nullable flag %s, but got %s', + ($allowNullValues ? 'true' : 'false'), + ($this->allowNullValues ? 'true' : 'false') + )); + } + } + + /** + * Returns the number of key-value mappings in this map. + */ + public function size() : int + { + return $this->size; + } + + /** + * Returns true if this map maps one or more keys to the specified value. + */ + public function containsValue($value) : bool + { + return in_array($this->maskNull($value), $this->values, true); + } + + /** + * Returns true if this map contains a mapping for the specified key. + */ + public function containsKey(AbstractEnum $key) : bool + { + $this->checkKeyType($key); + return null !== $this->values[$key->ordinal()]; + } + + /** + * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. + * + * More formally, if this map contains a mapping from a key to a value, then this method returns the value; + * otherwise it returns null (there can be at most one such mapping). + * + * A return value of null does not necessarily indicate that the map contains no mapping for the key; it's also + * possible that hte map explicitly maps the key to null. The {@see self::containsKey()} operation may be used to + * distinguish these two cases. + * + * @return mixed + */ + public function get(AbstractEnum $key) + { + $this->checkKeyType($key); + return $this->unmaskNull($this->values[$key->ordinal()]); + } + + /** + * Associates the specified value with the specified key in this map. + * + * If the map previously contained a mapping for this key, the old value is replaced. + * + * @return mixed the previous value associated with the specified key, or null if there was no mapping for the key. + * (a null return can also indicate that the map previously associated null with the specified key.) + * @throws IllegalArgumentException when the passed values does not match the internal value type + */ + public function put(AbstractEnum $key, $value) + { + $this->checkKeyType($key); + + if (! $this->isValidValue($value)) { + throw new IllegalArgumentException(sprintf('Value is not of type %s', $this->valueType)); + } + + $index = $key->ordinal(); + $oldValue = $this->values[$index]; + $this->values[$index] = $this->maskNull($value); + + if (null === $oldValue) { + ++$this->size; + } + + return $this->unmaskNull($oldValue); + } + + /** + * Removes the mapping for this key frm this map if present. + * + * @return mixed the previous value associated with the specified key, or null if there was no mapping for the key. + * (a null return can also indicate that the map previously associated null with the specified key.) + */ + public function remove(AbstractEnum $key) + { + $this->checkKeyType($key); + + $index = $key->ordinal(); + $oldValue = $this->values[$index]; + $this->values[$index] = null; + + if (null !== $oldValue) { + --$this->size; + } + + return $this->unmaskNull($oldValue); + } + + /** + * Removes all mappings from this map. + */ + public function clear() : void + { + $this->values = array_fill(0, count($this->keyUniverse), null); + $this->size = 0; + } + + /** + * Compares the specified map with this map for quality. + * + * Returns true if the two maps represent the same mappings. + */ + public function equals(self $other) : bool + { + if ($this === $other) { + return true; + } + + if ($this->size !== $other->size) { + return false; + } + + return $this->values === $other->values; + } + + /** + * Returns the values contained in this map. + * + * The array will contain the values in the order their corresponding keys appear in the map, which is their natural + * order (the order in which the num constants are declared). + */ + public function values() : array + { + return array_values(array_map(function ($value) { + return $this->unmaskNull($value); + }, array_filter($this->values, function ($value) : bool { + return null !== $value; + }))); + } + + public function serialize() : string + { + return serialize($this->__serialize()); + } + + public function unserialize($serialized) : void + { + $data = unserialize($serialized); + $this->__construct($data['keyType'], $data['valueType'], $data['allowNullValues']); + + foreach ($this->keyUniverse as $key) { + if (array_key_exists($key->ordinal(), $data['values'])) { + $this->put($key, $data['values'][$key->ordinal()]); + } + } + } + + public function getIterator() : Traversable + { + foreach ($this->keyUniverse as $key) { + if (null === $this->values[$key->ordinal()]) { + continue; + } + + yield $key => $this->unmaskNull($this->values[$key->ordinal()]); + } + } + + private function maskNull($value) + { + if (null === $value) { + return NullValue::instance(); + } + + return $value; + } + + private function unmaskNull($value) + { + if ($value instanceof NullValue) { + return null; + } + + return $value; + } + + /** + * @throws IllegalArgumentException when the passed key does not match the internal key type + */ + private function checkKeyType(AbstractEnum $key) : void + { + if (get_class($key) !== $this->keyType) { + throw new IllegalArgumentException(sprintf( + 'Object of type %s is not the same type as %s', + get_class($key), + $this->keyType + )); + } + } + + private function isValidValue($value) : bool + { + if (null === $value) { + if ($this->allowNullValues) { + return true; + } + + return false; + } + + switch ($this->valueType) { + case 'mixed': + return true; + + case 'bool': + case 'boolean': + return is_bool($value); + + case 'int': + case 'integer': + return is_int($value); + + case 'float': + case 'double': + return is_float($value); + + case 'string': + return is_string($value); + + case 'object': + return is_object($value); + + case 'array': + return is_array($value); + } + + return $value instanceof $this->valueType; + } +} diff --git a/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php b/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php new file mode 100644 index 0000000..4b37dbe --- /dev/null +++ b/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php @@ -0,0 +1,10 @@ +getErrorCorrectionLevel()); + $baconMatrix = Encoder::encode($qrCode->getData(), $baconErrorCorrectionLevel, strval($qrCode->getEncoding()))->getMatrix(); + + $blockValues = []; + $columnCount = $baconMatrix->getWidth(); + $rowCount = $baconMatrix->getHeight(); + for ($rowIndex = 0; $rowIndex < $rowCount; ++$rowIndex) { + $blockValues[$rowIndex] = []; + for ($columnIndex = 0; $columnIndex < $columnCount; ++$columnIndex) { + $blockValues[$rowIndex][$columnIndex] = $baconMatrix->get($columnIndex, $rowIndex); + } + } + + return new Matrix($blockValues, $qrCode->getSize(), $qrCode->getMargin(), $qrCode->getRoundBlockSizeMode()); + } +} diff --git a/vendor/endroid/qr-code/src/Builder/Builder.php b/vendor/endroid/qr-code/src/Builder/Builder.php new file mode 100644 index 0000000..6e5ab03 --- /dev/null +++ b/vendor/endroid/qr-code/src/Builder/Builder.php @@ -0,0 +1,255 @@ + */ + private $options; + + public function __construct() + { + $this->options = [ + 'writer' => new PngWriter(), + 'writerOptions' => [], + 'qrCodeClass' => QrCode::class, + 'logoClass' => Logo::class, + 'labelClass' => Label::class, + 'validateResult' => false, + ]; + } + + public static function create(): BuilderInterface + { + return new self(); + } + + public function writer(WriterInterface $writer): BuilderInterface + { + $this->options['writer'] = $writer; + + return $this; + } + + /** @param array $writerOptions */ + public function writerOptions(array $writerOptions): BuilderInterface + { + $this->options['writerOptions'] = $writerOptions; + + return $this; + } + + public function data(string $data): BuilderInterface + { + $this->options['data'] = $data; + + return $this; + } + + public function encoding(EncodingInterface $encoding): BuilderInterface + { + $this->options['encoding'] = $encoding; + + return $this; + } + + public function errorCorrectionLevel(ErrorCorrectionLevelInterface $errorCorrectionLevel): BuilderInterface + { + $this->options['errorCorrectionLevel'] = $errorCorrectionLevel; + + return $this; + } + + public function size(int $size): BuilderInterface + { + $this->options['size'] = $size; + + return $this; + } + + public function margin(int $margin): BuilderInterface + { + $this->options['margin'] = $margin; + + return $this; + } + + public function roundBlockSizeMode(RoundBlockSizeModeInterface $roundBlockSizeMode): BuilderInterface + { + $this->options['roundBlockSizeMode'] = $roundBlockSizeMode; + + return $this; + } + + public function foregroundColor(ColorInterface $foregroundColor): BuilderInterface + { + $this->options['foregroundColor'] = $foregroundColor; + + return $this; + } + + public function backgroundColor(ColorInterface $backgroundColor): BuilderInterface + { + $this->options['backgroundColor'] = $backgroundColor; + + return $this; + } + + public function logoPath(string $logoPath): BuilderInterface + { + $this->options['logoPath'] = $logoPath; + + return $this; + } + + public function logoResizeToWidth(int $logoResizeToWidth): BuilderInterface + { + $this->options['logoResizeToWidth'] = $logoResizeToWidth; + + return $this; + } + + public function logoResizeToHeight(int $logoResizeToHeight): BuilderInterface + { + $this->options['logoResizeToHeight'] = $logoResizeToHeight; + + return $this; + } + + public function logoPunchoutBackground(bool $logoPunchoutBackground): BuilderInterface + { + $this->options['logoPunchoutBackground'] = $logoPunchoutBackground; + + return $this; + } + + public function labelText(string $labelText): BuilderInterface + { + $this->options['labelText'] = $labelText; + + return $this; + } + + public function labelFont(FontInterface $labelFont): BuilderInterface + { + $this->options['labelFont'] = $labelFont; + + return $this; + } + + public function labelAlignment(LabelAlignmentInterface $labelAlignment): BuilderInterface + { + $this->options['labelAlignment'] = $labelAlignment; + + return $this; + } + + public function labelMargin(MarginInterface $labelMargin): BuilderInterface + { + $this->options['labelMargin'] = $labelMargin; + + return $this; + } + + public function labelTextColor(ColorInterface $labelTextColor): BuilderInterface + { + $this->options['labelTextColor'] = $labelTextColor; + + return $this; + } + + public function validateResult(bool $validateResult): BuilderInterface + { + $this->options['validateResult'] = $validateResult; + + return $this; + } + + public function build(): ResultInterface + { + if (!isset($this->options['writer']) || !$this->options['writer'] instanceof WriterInterface) { + throw new \Exception('Pass a valid writer via $builder->writer()'); + } + + $writer = $this->options['writer']; + + if ($this->options['validateResult'] && !$writer instanceof ValidatingWriterInterface) { + throw new \Exception('Unable to validate result with '.get_class($writer)); + } + + /** @var QrCode $qrCode */ + $qrCode = $this->buildObject($this->options['qrCodeClass']); + + /** @var LogoInterface|null $logo */ + $logo = $this->buildObject($this->options['logoClass'], 'logo'); + + /** @var LabelInterface|null $label */ + $label = $this->buildObject($this->options['labelClass'], 'label'); + + $result = $writer->write($qrCode, $logo, $label, $this->options['writerOptions']); + + if ($this->options['validateResult'] && $writer instanceof ValidatingWriterInterface) { + $writer->validateResult($result, $qrCode->getData()); + } + + return $result; + } + + /** + * @param class-string $class + * + * @return mixed + */ + private function buildObject(string $class, string $optionsPrefix = null) + { + /** @var \ReflectionClass $reflectionClass */ + $reflectionClass = new \ReflectionClass($class); + + $arguments = []; + $hasBuilderOptions = false; + $missingRequiredArguments = []; + /** @var \ReflectionMethod $constructor */ + $constructor = $reflectionClass->getConstructor(); + $constructorParameters = $constructor->getParameters(); + foreach ($constructorParameters as $parameter) { + $optionName = null === $optionsPrefix ? $parameter->getName() : $optionsPrefix.ucfirst($parameter->getName()); + if (isset($this->options[$optionName])) { + $hasBuilderOptions = true; + $arguments[] = $this->options[$optionName]; + } elseif ($parameter->isDefaultValueAvailable()) { + $arguments[] = $parameter->getDefaultValue(); + } else { + $missingRequiredArguments[] = $optionName; + } + } + + if (!$hasBuilderOptions) { + return null; + } + + if (count($missingRequiredArguments) > 0) { + throw new \Exception(sprintf('Missing required arguments: %s', implode(', ', $missingRequiredArguments))); + } + + return $reflectionClass->newInstanceArgs($arguments); + } +} diff --git a/vendor/endroid/qr-code/src/Builder/BuilderInterface.php b/vendor/endroid/qr-code/src/Builder/BuilderInterface.php new file mode 100644 index 0000000..5e69bc2 --- /dev/null +++ b/vendor/endroid/qr-code/src/Builder/BuilderInterface.php @@ -0,0 +1,63 @@ + $writerOptions */ + public function writerOptions(array $writerOptions): BuilderInterface; + + public function data(string $data): BuilderInterface; + + public function encoding(EncodingInterface $encoding): BuilderInterface; + + public function errorCorrectionLevel(ErrorCorrectionLevelInterface $errorCorrectionLevel): BuilderInterface; + + public function size(int $size): BuilderInterface; + + public function margin(int $margin): BuilderInterface; + + public function roundBlockSizeMode(RoundBlockSizeModeInterface $roundBlockSizeMode): BuilderInterface; + + public function foregroundColor(ColorInterface $foregroundColor): BuilderInterface; + + public function backgroundColor(ColorInterface $backgroundColor): BuilderInterface; + + public function logoPath(string $logoPath): BuilderInterface; + + public function logoResizeToWidth(int $logoResizeToWidth): BuilderInterface; + + public function logoResizeToHeight(int $logoResizeToHeight): BuilderInterface; + + public function logoPunchoutBackground(bool $logoPunchoutBackground): BuilderInterface; + + public function labelText(string $labelText): BuilderInterface; + + public function labelFont(FontInterface $labelFont): BuilderInterface; + + public function labelAlignment(LabelAlignmentInterface $labelAlignment): BuilderInterface; + + public function labelMargin(MarginInterface $labelMargin): BuilderInterface; + + public function labelTextColor(ColorInterface $labelTextColor): BuilderInterface; + + public function validateResult(bool $validateResult): BuilderInterface; + + public function build(): ResultInterface; +} diff --git a/vendor/endroid/qr-code/src/Builder/BuilderRegistry.php b/vendor/endroid/qr-code/src/Builder/BuilderRegistry.php new file mode 100644 index 0000000..eb9666a --- /dev/null +++ b/vendor/endroid/qr-code/src/Builder/BuilderRegistry.php @@ -0,0 +1,25 @@ + */ + private $builders = []; + + public function getBuilder(string $name): BuilderInterface + { + if (!isset($this->builders[$name])) { + throw new \Exception(sprintf('Builder with name "%s" not available from registry', $name)); + } + + return $this->builders[$name]; + } + + public function addBuilder(string $name, BuilderInterface $builder): void + { + $this->builders[$name] = $builder; + } +} diff --git a/vendor/endroid/qr-code/src/Builder/BuilderRegistryInterface.php b/vendor/endroid/qr-code/src/Builder/BuilderRegistryInterface.php new file mode 100644 index 0000000..048d649 --- /dev/null +++ b/vendor/endroid/qr-code/src/Builder/BuilderRegistryInterface.php @@ -0,0 +1,12 @@ +red = $red; + $this->green = $green; + $this->blue = $blue; + $this->alpha = $alpha; + } + + public function getRed(): int + { + return $this->red; + } + + public function getGreen(): int + { + return $this->green; + } + + public function getBlue(): int + { + return $this->blue; + } + + public function getAlpha(): int + { + return $this->alpha; + } + + public function getOpacity(): float + { + return 1 - $this->alpha / 127; + } + + public function toArray(): array + { + return [ + 'red' => $this->red, + 'green' => $this->green, + 'blue' => $this->blue, + 'alpha' => $this->alpha, + ]; + } +} diff --git a/vendor/endroid/qr-code/src/Color/ColorInterface.php b/vendor/endroid/qr-code/src/Color/ColorInterface.php new file mode 100644 index 0000000..91d3818 --- /dev/null +++ b/vendor/endroid/qr-code/src/Color/ColorInterface.php @@ -0,0 +1,21 @@ + */ + public function toArray(): array; +} diff --git a/vendor/endroid/qr-code/src/Encoding/Encoding.php b/vendor/endroid/qr-code/src/Encoding/Encoding.php new file mode 100644 index 0000000..7586e6f --- /dev/null +++ b/vendor/endroid/qr-code/src/Encoding/Encoding.php @@ -0,0 +1,25 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } +} diff --git a/vendor/endroid/qr-code/src/Encoding/EncodingInterface.php b/vendor/endroid/qr-code/src/Encoding/EncodingInterface.php new file mode 100644 index 0000000..f57001b --- /dev/null +++ b/vendor/endroid/qr-code/src/Encoding/EncodingInterface.php @@ -0,0 +1,10 @@ +width = $width; + $this->height = $height; + } + + public static function createForLabel(LabelInterface $label): self + { + if (false !== strpos($label->getText(), "\n")) { + throw new \Exception('Label does not support line breaks'); + } + + if (!function_exists('imagettfbbox')) { + throw new \Exception('Function "imagettfbbox" does not exist: check your FreeType installation'); + } + + $labelBox = imagettfbbox($label->getFont()->getSize(), 0, $label->getFont()->getPath(), $label->getText()); + + if (!is_array($labelBox)) { + throw new \Exception('Unable to generate label image box: check your FreeType installation'); + } + + return new self( + intval($labelBox[2] - $labelBox[0]), + intval($labelBox[0] - $labelBox[7]) + ); + } + + public function getWidth(): int + { + return $this->width; + } + + public function getHeight(): int + { + return $this->height; + } +} diff --git a/vendor/endroid/qr-code/src/ImageData/LogoImageData.php b/vendor/endroid/qr-code/src/ImageData/LogoImageData.php new file mode 100644 index 0000000..41fcc1c --- /dev/null +++ b/vendor/endroid/qr-code/src/ImageData/LogoImageData.php @@ -0,0 +1,168 @@ +data = $data; + $this->image = $image; + $this->mimeType = $mimeType; + $this->width = $width; + $this->height = $height; + $this->punchoutBackground = $punchoutBackground; + } + + public static function createForLogo(LogoInterface $logo): self + { + $data = @file_get_contents($logo->getPath()); + + if (!is_string($data)) { + throw new \Exception(sprintf('Invalid data at path "%s"', $logo->getPath())); + } + + if (false !== filter_var($logo->getPath(), FILTER_VALIDATE_URL)) { + $mimeType = self::detectMimeTypeFromUrl($logo->getPath()); + } else { + $mimeType = self::detectMimeTypeFromPath($logo->getPath()); + } + + $width = $logo->getResizeToWidth(); + $height = $logo->getResizeToHeight(); + + if ('image/svg+xml' === $mimeType) { + if (null === $width || null === $height) { + throw new \Exception('SVG Logos require an explicitly set resize width and height'); + } + + return new self($data, null, $mimeType, $width, $height, $logo->getPunchoutBackground()); + } + + $image = imagecreatefromstring($data); + + if (!$image) { + throw new \Exception(sprintf('Unable to parse image data at path "%s"', $logo->getPath())); + } + + // No target width and height specified: use from original image + if (null !== $width && null !== $height) { + return new self($data, $image, $mimeType, $width, $height, $logo->getPunchoutBackground()); + } + + // Only target width specified: calculate height + if (null !== $width && null === $height) { + return new self($data, $image, $mimeType, $width, intval(imagesy($image) * $width / imagesx($image)), $logo->getPunchoutBackground()); + } + + // Only target height specified: calculate width + if (null === $width && null !== $height) { + return new self($data, $image, $mimeType, intval(imagesx($image) * $height / imagesy($image)), $height, $logo->getPunchoutBackground()); + } + + return new self($data, $image, $mimeType, imagesx($image), imagesy($image), $logo->getPunchoutBackground()); + } + + public function getData(): string + { + return $this->data; + } + + /** @return mixed */ + public function getImage() + { + return $this->image; + } + + public function getMimeType(): string + { + return $this->mimeType; + } + + public function getWidth(): int + { + return $this->width; + } + + public function getHeight(): int + { + return $this->height; + } + + public function getPunchoutBackground(): bool + { + return $this->punchoutBackground; + } + + public function createDataUri(): string + { + return 'data:'.$this->mimeType.';base64,'.base64_encode($this->data); + } + + private static function detectMimeTypeFromUrl(string $url): string + { + /** @var mixed $format */ + $format = PHP_VERSION_ID >= 80000 ? true : 1; + + $headers = get_headers($url, $format); + + if (!is_array($headers) || !isset($headers['Content-Type'])) { + throw new \Exception(sprintf('Content type could not be determined for logo URL "%s"', $url)); + } + + return is_array($headers['Content-Type']) ? $headers['Content-Type'][1] : $headers['Content-Type']; + } + + private static function detectMimeTypeFromPath(string $path): string + { + if (!function_exists('mime_content_type')) { + throw new \Exception('You need the ext-fileinfo extension to determine logo mime type'); + } + + $mimeType = @mime_content_type($path); + + if (!is_string($mimeType)) { + throw new \Exception('Could not determine mime type'); + } + + if (!preg_match('#^image/#', $mimeType)) { + throw new \Exception('Logo path is not an image'); + } + + // Passing mime type image/svg results in invisible images + if ('image/svg' === $mimeType) { + return 'image/svg+xml'; + } + + return $mimeType; + } +} diff --git a/vendor/endroid/qr-code/src/Label/Alignment/LabelAlignmentCenter.php b/vendor/endroid/qr-code/src/Label/Alignment/LabelAlignmentCenter.php new file mode 100644 index 0000000..c13e287 --- /dev/null +++ b/vendor/endroid/qr-code/src/Label/Alignment/LabelAlignmentCenter.php @@ -0,0 +1,9 @@ +validatePath($path); + + $this->path = $path; + $this->size = $size; + } + + private function validatePath(string $path): void + { + if (!file_exists($path)) { + throw new \Exception(sprintf('Invalid font path "%s"', $path)); + } + } + + public function getPath(): string + { + return $this->path; + } + + public function getSize(): int + { + return $this->size; + } +} diff --git a/vendor/endroid/qr-code/src/Label/Font/FontInterface.php b/vendor/endroid/qr-code/src/Label/Font/FontInterface.php new file mode 100644 index 0000000..1c0de9a --- /dev/null +++ b/vendor/endroid/qr-code/src/Label/Font/FontInterface.php @@ -0,0 +1,12 @@ +size = $size; + } + + public function getPath(): string + { + return __DIR__.'/../../../assets/noto_sans.otf'; + } + + public function getSize(): int + { + return $this->size; + } +} diff --git a/vendor/endroid/qr-code/src/Label/Font/OpenSans.php b/vendor/endroid/qr-code/src/Label/Font/OpenSans.php new file mode 100644 index 0000000..76c95b0 --- /dev/null +++ b/vendor/endroid/qr-code/src/Label/Font/OpenSans.php @@ -0,0 +1,26 @@ +size = $size; + } + + public function getPath(): string + { + return __DIR__.'/../../../assets/open_sans.ttf'; + } + + public function getSize(): int + { + return $this->size; + } +} diff --git a/vendor/endroid/qr-code/src/Label/Label.php b/vendor/endroid/qr-code/src/Label/Label.php new file mode 100644 index 0000000..b15ef76 --- /dev/null +++ b/vendor/endroid/qr-code/src/Label/Label.php @@ -0,0 +1,111 @@ +text = $text; + $this->font = isset($font) ? $font : new Font(__DIR__.'/../../assets/noto_sans.otf', 16); + $this->alignment = isset($alignment) ? $alignment : new LabelAlignmentCenter(); + $this->margin = isset($margin) ? $margin : new Margin(0, 10, 10, 10); + $this->textColor = isset($textColor) ? $textColor : new Color(0, 0, 0); + } + + public static function create(string $text): self + { + return new self($text); + } + + public function getText(): string + { + return $this->text; + } + + public function setText(string $text): self + { + $this->text = $text; + + return $this; + } + + public function getFont(): FontInterface + { + return $this->font; + } + + public function setFont(FontInterface $font): self + { + $this->font = $font; + + return $this; + } + + public function getAlignment(): LabelAlignmentInterface + { + return $this->alignment; + } + + public function setAlignment(LabelAlignmentInterface $alignment): self + { + $this->alignment = $alignment; + + return $this; + } + + public function getMargin(): MarginInterface + { + return $this->margin; + } + + public function setMargin(MarginInterface $margin): self + { + $this->margin = $margin; + + return $this; + } + + public function getTextColor(): ColorInterface + { + return $this->textColor; + } + + public function setTextColor(ColorInterface $textColor): self + { + $this->textColor = $textColor; + + return $this; + } +} diff --git a/vendor/endroid/qr-code/src/Label/LabelInterface.php b/vendor/endroid/qr-code/src/Label/LabelInterface.php new file mode 100644 index 0000000..a7d2ed6 --- /dev/null +++ b/vendor/endroid/qr-code/src/Label/LabelInterface.php @@ -0,0 +1,23 @@ +top = $top; + $this->right = $right; + $this->bottom = $bottom; + $this->left = $left; + } + + public function getTop(): int + { + return $this->top; + } + + public function getRight(): int + { + return $this->right; + } + + public function getBottom(): int + { + return $this->bottom; + } + + public function getLeft(): int + { + return $this->left; + } + + /** @return array */ + public function toArray(): array + { + return [ + 'top' => $this->top, + 'right' => $this->right, + 'bottom' => $this->bottom, + 'left' => $this->left, + ]; + } +} diff --git a/vendor/endroid/qr-code/src/Label/Margin/MarginInterface.php b/vendor/endroid/qr-code/src/Label/Margin/MarginInterface.php new file mode 100644 index 0000000..bc428bd --- /dev/null +++ b/vendor/endroid/qr-code/src/Label/Margin/MarginInterface.php @@ -0,0 +1,19 @@ + */ + public function toArray(): array; +} diff --git a/vendor/endroid/qr-code/src/Logo/Logo.php b/vendor/endroid/qr-code/src/Logo/Logo.php new file mode 100644 index 0000000..f9bb38f --- /dev/null +++ b/vendor/endroid/qr-code/src/Logo/Logo.php @@ -0,0 +1,81 @@ +path = $path; + $this->resizeToWidth = $resizeToWidth; + $this->resizeToHeight = $resizeToHeight; + $this->punchoutBackground = $punchoutBackground; + } + + public static function create(string $path): self + { + return new self($path); + } + + public function getPath(): string + { + return $this->path; + } + + public function setPath(string $path): self + { + $this->path = $path; + + return $this; + } + + public function getResizeToWidth(): ?int + { + return $this->resizeToWidth; + } + + public function setResizeToWidth(?int $resizeToWidth): self + { + $this->resizeToWidth = $resizeToWidth; + + return $this; + } + + public function getResizeToHeight(): ?int + { + return $this->resizeToHeight; + } + + public function setResizeToHeight(?int $resizeToHeight): self + { + $this->resizeToHeight = $resizeToHeight; + + return $this; + } + + public function getPunchoutBackground(): bool + { + return $this->punchoutBackground; + } + + public function setPunchoutBackground(bool $punchoutBackground): self + { + $this->punchoutBackground = $punchoutBackground; + + return $this; + } +} diff --git a/vendor/endroid/qr-code/src/Logo/LogoInterface.php b/vendor/endroid/qr-code/src/Logo/LogoInterface.php new file mode 100644 index 0000000..13d940c --- /dev/null +++ b/vendor/endroid/qr-code/src/Logo/LogoInterface.php @@ -0,0 +1,16 @@ +> */ + private $blockValues = []; + + /** @var float */ + private $blockSize; + + /** @var int */ + private $innerSize; + + /** @var int */ + private $outerSize; + + /** @var int */ + private $marginLeft; + + /** @var int */ + private $marginRight; + + /** @param array> $blockValues */ + public function __construct(array $blockValues, int $size, int $margin, RoundBlockSizeModeInterface $roundBlockSizeMode) + { + $this->blockValues = $blockValues; + + $this->blockSize = $size / $this->getBlockCount(); + $this->innerSize = $size; + $this->outerSize = $size + 2 * $margin; + + if ($roundBlockSizeMode instanceof RoundBlockSizeModeEnlarge) { + $this->blockSize = intval(ceil($this->blockSize)); + $this->innerSize = $this->blockSize * $this->getBlockCount(); + $this->outerSize = $this->innerSize + 2 * $margin; + } elseif ($roundBlockSizeMode instanceof RoundBlockSizeModeShrink) { + $this->blockSize = intval(floor($this->blockSize)); + $this->innerSize = $this->blockSize * $this->getBlockCount(); + $this->outerSize = $this->innerSize + 2 * $margin; + } elseif ($roundBlockSizeMode instanceof RoundBlockSizeModeMargin) { + $this->blockSize = intval(floor($this->blockSize)); + $this->innerSize = $this->blockSize * $this->getBlockCount(); + } + + if ($this->blockSize < 1) { + throw new \Exception('Too much data: increase image dimensions or lower error correction level'); + } + + $this->marginLeft = intval(($this->outerSize - $this->innerSize) / 2); + $this->marginRight = $this->outerSize - $this->innerSize - $this->marginLeft; + } + + public function getBlockValue(int $rowIndex, int $columnIndex): int + { + return $this->blockValues[$rowIndex][$columnIndex]; + } + + public function getBlockCount(): int + { + return count($this->blockValues[0]); + } + + public function getBlockSize(): float + { + return $this->blockSize; + } + + public function getInnerSize(): int + { + return $this->innerSize; + } + + public function getOuterSize(): int + { + return $this->outerSize; + } + + public function getMarginLeft(): int + { + return $this->marginLeft; + } + + public function getMarginRight(): int + { + return $this->marginRight; + } +} diff --git a/vendor/endroid/qr-code/src/Matrix/MatrixFactoryInterface.php b/vendor/endroid/qr-code/src/Matrix/MatrixFactoryInterface.php new file mode 100644 index 0000000..be501f1 --- /dev/null +++ b/vendor/endroid/qr-code/src/Matrix/MatrixFactoryInterface.php @@ -0,0 +1,12 @@ +data = $data; + $this->encoding = isset($encoding) ? $encoding : new Encoding('UTF-8'); + $this->errorCorrectionLevel = isset($errorCorrectionLevel) ? $errorCorrectionLevel : new ErrorCorrectionLevelLow(); + $this->size = $size; + $this->margin = $margin; + $this->roundBlockSizeMode = isset($roundBlockSizeMode) ? $roundBlockSizeMode : new RoundBlockSizeModeMargin(); + $this->foregroundColor = isset($foregroundColor) ? $foregroundColor : new Color(0, 0, 0); + $this->backgroundColor = isset($backgroundColor) ? $backgroundColor : new Color(255, 255, 255); + } + + public static function create(string $data): self + { + return new self($data); + } + + public function getData(): string + { + return $this->data; + } + + public function setData(string $data): self + { + $this->data = $data; + + return $this; + } + + public function getEncoding(): EncodingInterface + { + return $this->encoding; + } + + public function setEncoding(Encoding $encoding): self + { + $this->encoding = $encoding; + + return $this; + } + + public function getErrorCorrectionLevel(): ErrorCorrectionLevelInterface + { + return $this->errorCorrectionLevel; + } + + public function setErrorCorrectionLevel(ErrorCorrectionLevelInterface $errorCorrectionLevel): self + { + $this->errorCorrectionLevel = $errorCorrectionLevel; + + return $this; + } + + public function getSize(): int + { + return $this->size; + } + + public function setSize(int $size): self + { + $this->size = $size; + + return $this; + } + + public function getMargin(): int + { + return $this->margin; + } + + public function setMargin(int $margin): self + { + $this->margin = $margin; + + return $this; + } + + public function getRoundBlockSizeMode(): RoundBlockSizeModeInterface + { + return $this->roundBlockSizeMode; + } + + public function setRoundBlockSizeMode(RoundBlockSizeModeInterface $roundBlockSizeMode): self + { + $this->roundBlockSizeMode = $roundBlockSizeMode; + + return $this; + } + + public function getForegroundColor(): ColorInterface + { + return $this->foregroundColor; + } + + public function setForegroundColor(ColorInterface $foregroundColor): self + { + $this->foregroundColor = $foregroundColor; + + return $this; + } + + public function getBackgroundColor(): ColorInterface + { + return $this->backgroundColor; + } + + public function setBackgroundColor(ColorInterface $backgroundColor): self + { + $this->backgroundColor = $backgroundColor; + + return $this; + } +} diff --git a/vendor/endroid/qr-code/src/QrCodeInterface.php b/vendor/endroid/qr-code/src/QrCodeInterface.php new file mode 100644 index 0000000..2c96984 --- /dev/null +++ b/vendor/endroid/qr-code/src/QrCodeInterface.php @@ -0,0 +1,29 @@ +create($qrCode); + + return new BinaryResult($matrix); + } +} diff --git a/vendor/endroid/qr-code/src/Writer/DebugWriter.php b/vendor/endroid/qr-code/src/Writer/DebugWriter.php new file mode 100644 index 0000000..3e89515 --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/DebugWriter.php @@ -0,0 +1,28 @@ +setValidateResult(true); + } +} diff --git a/vendor/endroid/qr-code/src/Writer/EpsWriter.php b/vendor/endroid/qr-code/src/Writer/EpsWriter.php new file mode 100644 index 0000000..2ffd219 --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/EpsWriter.php @@ -0,0 +1,44 @@ +create($qrCode); + + $lines = [ + '%!PS-Adobe-3.0 EPSF-3.0', + '%%BoundingBox: 0 0 '.$matrix->getOuterSize().' '.$matrix->getOuterSize(), + '/F { rectfill } def', + number_format($qrCode->getBackgroundColor()->getRed() / 100, 2, '.', ',').' '.number_format($qrCode->getBackgroundColor()->getGreen() / 100, 2, '.', ',').' '.number_format($qrCode->getBackgroundColor()->getBlue() / 100, 2, '.', ',').' setrgbcolor', + '0 0 '.$matrix->getOuterSize().' '.$matrix->getOuterSize().' F', + number_format($qrCode->getForegroundColor()->getRed() / 100, 2, '.', ',').' '.number_format($qrCode->getForegroundColor()->getGreen() / 100, 2, '.', ',').' '.number_format($qrCode->getForegroundColor()->getBlue() / 100, 2, '.', ',').' setrgbcolor', + ]; + + for ($rowIndex = 0; $rowIndex < $matrix->getBlockCount(); ++$rowIndex) { + for ($columnIndex = 0; $columnIndex < $matrix->getBlockCount(); ++$columnIndex) { + if (1 === $matrix->getBlockValue($matrix->getBlockCount() - 1 - $rowIndex, $columnIndex)) { + $x = $matrix->getMarginLeft() + $matrix->getBlockSize() * $columnIndex; + $y = $matrix->getMarginLeft() + $matrix->getBlockSize() * $rowIndex; + $lines[] = number_format($x, self::DECIMAL_PRECISION, '.', '').' '.number_format($y, self::DECIMAL_PRECISION, '.', '').' '.number_format($matrix->getBlockSize(), self::DECIMAL_PRECISION, '.', '').' '.number_format($matrix->getBlockSize(), self::DECIMAL_PRECISION, '.', '').' F'; + } + } + } + + return new EpsResult($lines); + } +} diff --git a/vendor/endroid/qr-code/src/Writer/PdfWriter.php b/vendor/endroid/qr-code/src/Writer/PdfWriter.php new file mode 100644 index 0000000..1ecdb97 --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/PdfWriter.php @@ -0,0 +1,129 @@ +create($qrCode); + + $unit = 'mm'; + if (isset($options[self::WRITER_OPTION_UNIT])) { + $unit = $options[self::WRITER_OPTION_UNIT]; + } + + $allowedUnits = ['mm', 'pt', 'cm', 'in']; + if (!in_array($unit, $allowedUnits)) { + throw new \Exception(sprintf('PDF Measure unit should be one of [%s]', implode(', ', $allowedUnits))); + } + + $labelSpace = 0; + if ($label instanceof LabelInterface) { + $labelSpace = 30; + } + + if (!class_exists(\FPDF::class)) { + throw new \Exception('Unable to find FPDF: check your installation'); + } + + $foregroundColor = $qrCode->getForegroundColor(); + if ($foregroundColor->getAlpha() > 0) { + throw new \Exception('PDF Writer does not support alpha channels'); + } + $backgroundColor = $qrCode->getBackgroundColor(); + if ($backgroundColor->getAlpha() > 0) { + throw new \Exception('PDF Writer does not support alpha channels'); + } + + if (isset($options[self::WRITER_OPTION_PDF])) { + $fpdf = $options[self::WRITER_OPTION_PDF]; + if (!$fpdf instanceof \FPDF) { + throw new \Exception('pdf option must be an instance of FPDF'); + } + } else { + // @todo Check how to add label height later + $fpdf = new \FPDF('P', $unit, [$matrix->getOuterSize(), $matrix->getOuterSize() + $labelSpace]); + $fpdf->AddPage(); + } + + $x = 0; + if (isset($options[self::WRITER_OPTION_X])) { + $x = $options[self::WRITER_OPTION_X]; + } + $y = 0; + if (isset($options[self::WRITER_OPTION_Y])) { + $y = $options[self::WRITER_OPTION_Y]; + } + + $fpdf->SetFillColor($backgroundColor->getRed(), $backgroundColor->getGreen(), $backgroundColor->getBlue()); + $fpdf->Rect($x, $y, $matrix->getOuterSize(), $matrix->getOuterSize(), 'F'); + $fpdf->SetFillColor($foregroundColor->getRed(), $foregroundColor->getGreen(), $foregroundColor->getBlue()); + + for ($rowIndex = 0; $rowIndex < $matrix->getBlockCount(); ++$rowIndex) { + for ($columnIndex = 0; $columnIndex < $matrix->getBlockCount(); ++$columnIndex) { + if (1 === $matrix->getBlockValue($rowIndex, $columnIndex)) { + $fpdf->Rect( + $x + $matrix->getMarginLeft() + ($columnIndex * $matrix->getBlockSize()), + $y + $matrix->getMarginLeft() + ($rowIndex * $matrix->getBlockSize()), + $matrix->getBlockSize(), + $matrix->getBlockSize(), + 'F' + ); + } + } + } + + if ($logo instanceof LogoInterface) { + $this->addLogo($logo, $fpdf, $x, $y, $matrix->getOuterSize()); + } + + if ($label instanceof LabelInterface) { + $fpdf->SetXY($x, $y + $matrix->getOuterSize() + $labelSpace - 25); + $fpdf->SetFont('Helvetica', null, $label->getFont()->getSize()); + $fpdf->Cell($matrix->getOuterSize(), 0, $label->getText(), 0, 0, 'C'); + } + + return new PdfResult($fpdf); + } + + private function addLogo(LogoInterface $logo, \FPDF $fpdf, float $x, float $y, float $size): void + { + $logoPath = $logo->getPath(); + $logoHeight = $logo->getResizeToHeight(); + $logoWidth = $logo->getResizeToWidth(); + + if (null === $logoHeight || null === $logoWidth) { + [$logoSourceWidth, $logoSourceHeight] = \getimagesize($logoPath); + + if (null === $logoWidth) { + $logoWidth = (int) $logoSourceWidth; + } + + if (null === $logoHeight) { + $aspectRatio = $logoWidth / $logoSourceWidth; + $logoHeight = (int) ($logoSourceHeight * $aspectRatio); + } + } + + $logoX = $x + $size / 2 - (int) $logoWidth / 2; + $logoY = $y + $size / 2 - (int) $logoHeight / 2; + + $fpdf->Image($logoPath, $logoX, $logoY, $logoWidth, $logoHeight); + } +} diff --git a/vendor/endroid/qr-code/src/Writer/PngWriter.php b/vendor/endroid/qr-code/src/Writer/PngWriter.php new file mode 100644 index 0000000..209d69e --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/PngWriter.php @@ -0,0 +1,232 @@ +create($qrCode); + + $baseBlockSize = 50; + $baseImage = imagecreatetruecolor($matrix->getBlockCount() * $baseBlockSize, $matrix->getBlockCount() * $baseBlockSize); + + if (!$baseImage) { + throw new \Exception('Unable to generate image: check your GD installation'); + } + + /** @var int $foregroundColor */ + $foregroundColor = imagecolorallocatealpha( + $baseImage, + $qrCode->getForegroundColor()->getRed(), + $qrCode->getForegroundColor()->getGreen(), + $qrCode->getForegroundColor()->getBlue(), + $qrCode->getForegroundColor()->getAlpha() + ); + + /** @var int $backgroundColor */ + $backgroundColor = imagecolorallocatealpha( + $baseImage, + $qrCode->getBackgroundColor()->getRed(), + $qrCode->getBackgroundColor()->getGreen(), + $qrCode->getBackgroundColor()->getBlue(), + $qrCode->getBackgroundColor()->getAlpha() + ); + + imagefill($baseImage, 0, 0, $backgroundColor); + + for ($rowIndex = 0; $rowIndex < $matrix->getBlockCount(); ++$rowIndex) { + for ($columnIndex = 0; $columnIndex < $matrix->getBlockCount(); ++$columnIndex) { + if (1 === $matrix->getBlockValue($rowIndex, $columnIndex)) { + imagefilledrectangle( + $baseImage, + $columnIndex * $baseBlockSize, + $rowIndex * $baseBlockSize, + ($columnIndex + 1) * $baseBlockSize, + ($rowIndex + 1) * $baseBlockSize, + $foregroundColor + ); + } + } + } + + $targetWidth = $matrix->getOuterSize(); + $targetHeight = $matrix->getOuterSize(); + + if ($label instanceof LabelInterface) { + $labelImageData = LabelImageData::createForLabel($label); + $targetHeight += $labelImageData->getHeight() + $label->getMargin()->getTop() + $label->getMargin()->getBottom(); + } + + $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); + + if (!$targetImage) { + throw new \Exception('Unable to generate image: check your GD installation'); + } + + /** @var int $backgroundColor */ + $backgroundColor = imagecolorallocatealpha( + $targetImage, + $qrCode->getBackgroundColor()->getRed(), + $qrCode->getBackgroundColor()->getGreen(), + $qrCode->getBackgroundColor()->getBlue(), + $qrCode->getBackgroundColor()->getAlpha() + ); + + imagefill($targetImage, 0, 0, $backgroundColor); + + imagecopyresampled( + $targetImage, + $baseImage, + $matrix->getMarginLeft(), + $matrix->getMarginLeft(), + 0, + 0, + $matrix->getInnerSize(), + $matrix->getInnerSize(), + imagesx($baseImage), + imagesy($baseImage) + ); + + if (PHP_VERSION_ID < 80000) { + imagedestroy($baseImage); + } + + if ($qrCode->getBackgroundColor()->getAlpha() > 0) { + imagesavealpha($targetImage, true); + } + + $result = new PngResult($targetImage); + + if ($logo instanceof LogoInterface) { + $result = $this->addLogo($logo, $result); + } + + if ($label instanceof LabelInterface) { + $result = $this->addLabel($label, $result); + } + + return $result; + } + + private function addLogo(LogoInterface $logo, PngResult $result): PngResult + { + $logoImageData = LogoImageData::createForLogo($logo); + + if ('image/svg+xml' === $logoImageData->getMimeType()) { + throw new \Exception('PNG Writer does not support SVG logo'); + } + + $targetImage = $result->getImage(); + + if ($logoImageData->getPunchoutBackground()) { + /** @var int $transparent */ + $transparent = imagecolorallocatealpha($targetImage, 255, 255, 255, 127); + imagealphablending($targetImage, false); + for ( + $x_offset = intval(imagesx($targetImage) / 2 - $logoImageData->getWidth() / 2); + $x_offset < intval(imagesx($targetImage) / 2 - $logoImageData->getWidth() / 2) + $logoImageData->getWidth(); + ++$x_offset + ) { + for ( + $y_offset = intval(imagesy($targetImage) / 2 - $logoImageData->getHeight() / 2); + $y_offset < intval(imagesy($targetImage) / 2 - $logoImageData->getHeight() / 2) + $logoImageData->getHeight(); + ++$y_offset + ) { + imagesetpixel( + $targetImage, + $x_offset, + $y_offset, + $transparent + ); + } + } + } + + imagecopyresampled( + $targetImage, + $logoImageData->getImage(), + intval(imagesx($targetImage) / 2 - $logoImageData->getWidth() / 2), + intval(imagesx($targetImage) / 2 - $logoImageData->getHeight() / 2), + 0, + 0, + $logoImageData->getWidth(), + $logoImageData->getHeight(), + imagesx($logoImageData->getImage()), + imagesy($logoImageData->getImage()) + ); + + if (PHP_VERSION_ID < 80000) { + imagedestroy($logoImageData->getImage()); + } + + return new PngResult($targetImage); + } + + private function addLabel(LabelInterface $label, PngResult $result): PngResult + { + $targetImage = $result->getImage(); + + $labelImageData = LabelImageData::createForLabel($label); + + /** @var int $textColor */ + $textColor = imagecolorallocatealpha( + $targetImage, + $label->getTextColor()->getRed(), + $label->getTextColor()->getGreen(), + $label->getTextColor()->getBlue(), + $label->getTextColor()->getAlpha() + ); + + $x = intval(imagesx($targetImage) / 2 - $labelImageData->getWidth() / 2); + $y = imagesy($targetImage) - $label->getMargin()->getBottom(); + + if ($label->getAlignment() instanceof LabelAlignmentLeft) { + $x = $label->getMargin()->getLeft(); + } elseif ($label->getAlignment() instanceof LabelAlignmentRight) { + $x = imagesx($targetImage) - $labelImageData->getWidth() - $label->getMargin()->getRight(); + } + + imagettftext($targetImage, $label->getFont()->getSize(), 0, $x, $y, $textColor, $label->getFont()->getPath(), $label->getText()); + + return new PngResult($targetImage); + } + + public function validateResult(ResultInterface $result, string $expectedData): void + { + $string = $result->getString(); + + if (!class_exists(QrReader::class)) { + throw new \Exception('Please install khanamiryan/qrcode-detector-decoder or disable image validation'); + } + + if (PHP_VERSION_ID >= 80000) { + throw new \Exception('The validator is not compatible with PHP 8 yet, see https://github.com/khanamiryan/php-qrcode-detector-decoder/pull/103'); + } + + $reader = new QrReader($string, QrReader::SOURCE_TYPE_BLOB); + if ($reader->text() !== $expectedData) { + throw new \Exception('Built-in validation reader read "'.$reader->text().'" instead of "'.$expectedData.'". + Adjust your parameters to increase readability or disable built-in validation.'); + } + } +} diff --git a/vendor/endroid/qr-code/src/Writer/Result/AbstractResult.php b/vendor/endroid/qr-code/src/Writer/Result/AbstractResult.php new file mode 100644 index 0000000..43b680b --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/Result/AbstractResult.php @@ -0,0 +1,19 @@ +getMimeType().';base64,'.base64_encode($this->getString()); + } + + public function saveToFile(string $path): void + { + $string = $this->getString(); + file_put_contents($path, $string); + } +} diff --git a/vendor/endroid/qr-code/src/Writer/Result/BinaryResult.php b/vendor/endroid/qr-code/src/Writer/Result/BinaryResult.php new file mode 100644 index 0000000..7466759 --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/Result/BinaryResult.php @@ -0,0 +1,35 @@ +matrix = $matrix; + } + + public function getString(): string + { + $binaryString = ''; + for ($rowIndex = 0; $rowIndex < $this->matrix->getBlockCount(); ++$rowIndex) { + for ($columnIndex = 0; $columnIndex < $this->matrix->getBlockCount(); ++$columnIndex) { + $binaryString .= $this->matrix->getBlockValue($rowIndex, $columnIndex); + } + $binaryString .= "\n"; + } + + return $binaryString; + } + + public function getMimeType(): string + { + return 'text/plain'; + } +} diff --git a/vendor/endroid/qr-code/src/Writer/Result/DebugResult.php b/vendor/endroid/qr-code/src/Writer/Result/DebugResult.php new file mode 100644 index 0000000..ce9a28c --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/Result/DebugResult.php @@ -0,0 +1,83 @@ + */ + private $options; + + /** @var bool */ + private $validateResult = false; + + /** @param array $options */ + public function __construct(QrCodeInterface $qrCode, LogoInterface $logo = null, LabelInterface $label = null, array $options = []) + { + $this->qrCode = $qrCode; + $this->logo = $logo; + $this->label = $label; + $this->options = $options; + } + + public function setValidateResult(bool $validateResult): void + { + $this->validateResult = $validateResult; + } + + public function getString(): string + { + $debugLines = []; + + $debugLines[] = 'Data: '.$this->qrCode->getData(); + $debugLines[] = 'Encoding: '.$this->qrCode->getEncoding(); + $debugLines[] = 'Error Correction Level: '.get_class($this->qrCode->getErrorCorrectionLevel()); + $debugLines[] = 'Size: '.$this->qrCode->getSize(); + $debugLines[] = 'Margin: '.$this->qrCode->getMargin(); + $debugLines[] = 'Round block size mode: '.get_class($this->qrCode->getRoundBlockSizeMode()); + $debugLines[] = 'Foreground color: ['.implode(', ', $this->qrCode->getForegroundColor()->toArray()).']'; + $debugLines[] = 'Background color: ['.implode(', ', $this->qrCode->getBackgroundColor()->toArray()).']'; + + foreach ($this->options as $key => $value) { + $debugLines[] = 'Writer option: '.$key.': '.$value; + } + + if (isset($this->logo)) { + $debugLines[] = 'Logo path: '.$this->logo->getPath(); + $debugLines[] = 'Logo resize to width: '.$this->logo->getResizeToWidth(); + $debugLines[] = 'Logo resize to height: '.$this->logo->getResizeToHeight(); + } + + if (isset($this->label)) { + $debugLines[] = 'Label text: '.$this->label->getText(); + $debugLines[] = 'Label font path: '.$this->label->getFont()->getPath(); + $debugLines[] = 'Label font size: '.$this->label->getFont()->getSize(); + $debugLines[] = 'Label alignment: '.get_class($this->label->getAlignment()); + $debugLines[] = 'Label margin: ['.implode(', ', $this->label->getMargin()->toArray()).']'; + $debugLines[] = 'Label text color: ['.implode(', ', $this->label->getTextColor()->toArray()).']'; + } + + $debugLines[] = 'Validate result: '.($this->validateResult ? 'true' : 'false'); + + return implode("\n", $debugLines); + } + + public function getMimeType(): string + { + return 'text/plain'; + } +} diff --git a/vendor/endroid/qr-code/src/Writer/Result/EpsResult.php b/vendor/endroid/qr-code/src/Writer/Result/EpsResult.php new file mode 100644 index 0000000..31d56a1 --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/Result/EpsResult.php @@ -0,0 +1,27 @@ + */ + private $lines; + + /** @param array $lines */ + public function __construct(array $lines) + { + $this->lines = $lines; + } + + public function getString(): string + { + return implode("\n", $this->lines); + } + + public function getMimeType(): string + { + return 'image/eps'; + } +} diff --git a/vendor/endroid/qr-code/src/Writer/Result/PdfResult.php b/vendor/endroid/qr-code/src/Writer/Result/PdfResult.php new file mode 100644 index 0000000..936219e --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/Result/PdfResult.php @@ -0,0 +1,31 @@ +fpdf = $fpdf; + } + + public function getPdf(): \FPDF + { + return $this->fpdf; + } + + public function getString(): string + { + return $this->fpdf->Output('S'); + } + + public function getMimeType(): string + { + return 'application/pdf'; + } +} diff --git a/vendor/endroid/qr-code/src/Writer/Result/PngResult.php b/vendor/endroid/qr-code/src/Writer/Result/PngResult.php new file mode 100644 index 0000000..efa26c5 --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/Result/PngResult.php @@ -0,0 +1,36 @@ +image = $image; + } + + /** @return mixed */ + public function getImage() + { + return $this->image; + } + + public function getString(): string + { + ob_start(); + imagepng($this->image); + + return strval(ob_get_clean()); + } + + public function getMimeType(): string + { + return 'image/png'; + } +} diff --git a/vendor/endroid/qr-code/src/Writer/Result/ResultInterface.php b/vendor/endroid/qr-code/src/Writer/Result/ResultInterface.php new file mode 100644 index 0000000..a255605 --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/Result/ResultInterface.php @@ -0,0 +1,16 @@ +xml = $xml; + $this->excludeXmlDeclaration = $excludeXmlDeclaration; + } + + public function getXml(): \SimpleXMLElement + { + return $this->xml; + } + + public function getString(): string + { + $string = $this->xml->asXML(); + + if (!is_string($string)) { + throw new \Exception('Could not save SVG XML to string'); + } + + if ($this->excludeXmlDeclaration) { + $string = str_replace("\n", '', $string); + } + + return $string; + } + + public function getMimeType(): string + { + return 'image/svg+xml'; + } +} diff --git a/vendor/endroid/qr-code/src/Writer/SvgWriter.php b/vendor/endroid/qr-code/src/Writer/SvgWriter.php new file mode 100644 index 0000000..88665af --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/SvgWriter.php @@ -0,0 +1,109 @@ +create($qrCode); + + $xml = new \SimpleXMLElement(''); + $xml->addAttribute('version', '1.1'); + $xml->addAttribute('width', $matrix->getOuterSize().'px'); + $xml->addAttribute('height', $matrix->getOuterSize().'px'); + $xml->addAttribute('viewBox', '0 0 '.$matrix->getOuterSize().' '.$matrix->getOuterSize()); + $xml->addChild('defs'); + + $blockDefinition = $xml->defs->addChild('rect'); + $blockDefinition->addAttribute('id', $options[self::WRITER_OPTION_BLOCK_ID]); + $blockDefinition->addAttribute('width', number_format($matrix->getBlockSize(), self::DECIMAL_PRECISION, '.', '')); + $blockDefinition->addAttribute('height', number_format($matrix->getBlockSize(), self::DECIMAL_PRECISION, '.', '')); + $blockDefinition->addAttribute('fill', '#'.sprintf('%02x%02x%02x', $qrCode->getForegroundColor()->getRed(), $qrCode->getForegroundColor()->getGreen(), $qrCode->getForegroundColor()->getBlue())); + $blockDefinition->addAttribute('fill-opacity', strval($qrCode->getForegroundColor()->getOpacity())); + + $background = $xml->addChild('rect'); + $background->addAttribute('x', '0'); + $background->addAttribute('y', '0'); + $background->addAttribute('width', strval($matrix->getOuterSize())); + $background->addAttribute('height', strval($matrix->getOuterSize())); + $background->addAttribute('fill', '#'.sprintf('%02x%02x%02x', $qrCode->getBackgroundColor()->getRed(), $qrCode->getBackgroundColor()->getGreen(), $qrCode->getBackgroundColor()->getBlue())); + $background->addAttribute('fill-opacity', strval($qrCode->getBackgroundColor()->getOpacity())); + + for ($rowIndex = 0; $rowIndex < $matrix->getBlockCount(); ++$rowIndex) { + for ($columnIndex = 0; $columnIndex < $matrix->getBlockCount(); ++$columnIndex) { + if (1 === $matrix->getBlockValue($rowIndex, $columnIndex)) { + $block = $xml->addChild('use'); + $block->addAttribute('x', number_format($matrix->getMarginLeft() + $matrix->getBlockSize() * $columnIndex, self::DECIMAL_PRECISION, '.', '')); + $block->addAttribute('y', number_format($matrix->getMarginLeft() + $matrix->getBlockSize() * $rowIndex, self::DECIMAL_PRECISION, '.', '')); + $block->addAttribute('xlink:href', '#'.$options[self::WRITER_OPTION_BLOCK_ID], 'http://www.w3.org/1999/xlink'); + } + } + } + + $result = new SvgResult($xml, $options[self::WRITER_OPTION_EXCLUDE_XML_DECLARATION]); + + if ($logo instanceof LogoInterface) { + $this->addLogo($logo, $result, $options); + } + + return $result; + } + + /** @param array $options */ + private function addLogo(LogoInterface $logo, SvgResult $result, array $options): void + { + $logoImageData = LogoImageData::createForLogo($logo); + + if (!isset($options[self::WRITER_OPTION_FORCE_XLINK_HREF])) { + $options[self::WRITER_OPTION_FORCE_XLINK_HREF] = false; + } + + $xml = $result->getXml(); + + /** @var \SimpleXMLElement $xmlAttributes */ + $xmlAttributes = $xml->attributes(); + + $x = intval($xmlAttributes->width) / 2 - $logoImageData->getWidth() / 2; + $y = intval($xmlAttributes->height) / 2 - $logoImageData->getHeight() / 2; + + $imageDefinition = $xml->addChild('image'); + $imageDefinition->addAttribute('x', strval($x)); + $imageDefinition->addAttribute('y', strval($y)); + $imageDefinition->addAttribute('width', strval($logoImageData->getWidth())); + $imageDefinition->addAttribute('height', strval($logoImageData->getHeight())); + $imageDefinition->addAttribute('preserveAspectRatio', 'none'); + + // xlink:href is actually deprecated, but still required when placing the qr code in a pdf. + // SimpleXML strips out the xlink part by using addAttribute(), so it must be set directly. + if ($options[self::WRITER_OPTION_FORCE_XLINK_HREF]) { + $imageDefinition['xlink:href'] = $logoImageData->createDataUri(); + } else { + $imageDefinition->addAttribute('href', $logoImageData->createDataUri()); + } + } +} diff --git a/vendor/endroid/qr-code/src/Writer/ValidatingWriterInterface.php b/vendor/endroid/qr-code/src/Writer/ValidatingWriterInterface.php new file mode 100644 index 0000000..4f40048 --- /dev/null +++ b/vendor/endroid/qr-code/src/Writer/ValidatingWriterInterface.php @@ -0,0 +1,12 @@ + $options */ + public function write(QrCodeInterface $qrCode, LogoInterface $logo = null, LabelInterface $label = null, array $options = []): ResultInterface; +} diff --git a/vendor/phpmailer/phpmailer/SMTPUTF8.md b/vendor/phpmailer/phpmailer/SMTPUTF8.md new file mode 100644 index 0000000..ca284ee --- /dev/null +++ b/vendor/phpmailer/phpmailer/SMTPUTF8.md @@ -0,0 +1,48 @@ +# A short history of UTF-8 in email + +## Background + +For most of its existence, SMTP has been a 7-bit channel, only supporting US-ASCII characters. This has been a problem for many languages, especially those that use non-Latin scripts, and has led to the development of various workarounds. + +The first major improvement, introduced in 1994 in [RFC 1652](https://www.rfc-editor.org/rfc/rfc1652) and extended in 2011 in [RFC 6152](https://www.rfc-editor.org/rfc/rfc6152), was the addition of the `8BITMIME` SMTP extension, which allowed raw 8-bit data to be included in message bodies sent over SMTP. +This allowed the message *contents* to contain 8-bit data, including things like UTF-8 text, even though the SMTP protocol itself was still firmly 7-bit. This worked by having the server switch to 8-bit after the headers, and then back to 7-bit after the completion of a `DATA` command. + +From 1996, messages could support [RFC 2047 encoding](https://www.rfc-editor.org/rfc/rfc2047), which permitted inserting characters from any character set into header *values* (but not names), but only by encoding them in somewhat unreadable ways to allow them to survive passage through a 7-bit channel. An example with a subject of "Schrödinger's cat" would be: + +``` +Subject: =?utf-8?Q=Schr=C3=B6dinger=92s_Cat?= +``` + +Here the accented `ö` is encoded as `=C3=B6`, which is the UTF-8 encoding of the 2-byte character, and the whole thing is wrapped in `=?utf-8?Q?` to indicate that it uses the UTF-8 charset and `quoted-printable` encoding. This is a bit of a hack, and not very human-friendly, but it works. + +Similarly, 8-bit message bodies could be encoded using the same `quoted-printable` and `base64` content transfer encoding (CTE) schemes, which preserved the 8-bit content while encoding it in a format that could survive transmission through a 7-bit channel. + +Domain names were originally also stuck in a 7-bit world, actually even more constrained to only a subset of the US-ASCII character set. But of course, many people want to have domains in their own language/script. Internationalized domain name (IDN) permitted this, using yet another complex encoding scheme called punycode, defined for domain names in 2003 in [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492). This finally allowed the domain part (after the `@`) of email addresses to contain UTF-8, though it was actually an illusion preserved by email client applications. For example, an address of +`user@café.example.com` translates to +`user@xn--caf-dma.example.com` in punycode, rendering it mostly unreadable, but 7-bit friendly, and remaining compatible with email clients that don't know about IDN. + +The one remaining part of email that could not handle UTF-8 is the local part of email addresses (the part before the `@`). + +I've only mentioned UTF-8 here, but most of these approaches also allowed other character sets that were popular, such as [the ISO-8859 family](https://en.wikipedia.org/wiki/ISO/IEC_8859). However, UTF-8 solves so many problems that these other character sets are gradually falling out of favour, as UTF-8 can support all languages. + +This patchwork of overlapping approaches has served us well, but we have to admit that it's a mess. + +## SMTPUTF8 + +`SMTPUTF8` is another SMTP extension, defined in [RFC 6531](https://www.rfc-editor.org/rfc/rfc6531) in 2012. This essentially solves the whole problem, allowing the entire SMTP conversation — commands, headers, and message bodies — to be sent in raw, unencoded UTF-8. + +But there's a problem with this approach: adoption. If you send a UTF-8 message to a recipient whose mail server doesn't support this format, the sender has to somehow downgrade the message to make it survive a transition to 7-bit. This is a hard problem to solve, especially since there is no way to make a 7-bit system support UTF-8 in the local parts of addresses. This downgrade problem is what held up the adoption of `SMTPUTF8` in PHPMailer for many years, but in that time the *de facto* approach has become to simply fail in that situation, and tell the recipient it's time they upgraded their mail server 😅. + +The vast majority of large email providers (gmail, Yahoo, Microsoft, etc), mail servers (postfix, exim, IIS, etc), and mail clients (Apple Mail, Outlook, Thunderbird, etc) now all support SMTPUTF8, so the need for backward compatibility is no longer what it was. + +## SMTPUTF8 in PHPMailer + +Several other PHP email libraries have implemented a halfway solution to `SMTPUTF8`, adding only the ability to support UTF-8 in email addresses, not elsewhere in the protocol. I wanted PHPMailer to do it "the right way", and this has taken much longer. PHPMailer now supports UTF-8 everywhere, and does not need to use transfer or header encodings for UTF-8 text when connecting to an `SMTPUTF8`-capable mail server. + +This support is handled automatically: if you add an email address that requires UTF-8, PHPMailer will use UTF-8 for everything. If not, it will fall back to 7-bit and encode the message as necessary. + +The one place you will need to be careful is in the selection of the address validator. By default, PHPMailer uses PHP's built-in `filter_var` validator, which does not allow UTF-8 email addresses. When PHPMailer spots that you have submitted a UTF-8 address, but have not altered the default validator, it will automatically switch to using a UTF-8-compatible validator. As soon as you do this, any SMTP connection you make will *require* that the server you connect to supports `SMTPUTF8`. You can select this validator explicitly by setting `PHPMailer::$validator = 'eai'` (an acronym for Email Address Internationalization). + +### Postfix gotcha + +Postfix has supported `SMTPUTF8` for a long time, but it has a peculiarity that it does not always advertise that it does so. However, rather surprisingly, if you use UTF-8 in the conversation, it will work anyway. diff --git a/vendor/picqer/php-barcode-generator/.github/FUNDING.yml b/vendor/picqer/php-barcode-generator/.github/FUNDING.yml new file mode 100644 index 0000000..a8ff52a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/.github/FUNDING.yml @@ -0,0 +1 @@ +github: casperbakker diff --git a/vendor/picqer/php-barcode-generator/.github/workflows/phpstan.yml b/vendor/picqer/php-barcode-generator/.github/workflows/phpstan.yml new file mode 100644 index 0000000..7528e81 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/.github/workflows/phpstan.yml @@ -0,0 +1,29 @@ +name: Static analysis (phpstan) + +on: + push: + branches: + - main + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + extensions: mbstring, gd, bcmath, imagick + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-interaction + + - name: Run analysis + run: vendor/bin/phpstan --error-format=github --no-progress diff --git a/vendor/picqer/php-barcode-generator/.github/workflows/phpunit.yml b/vendor/picqer/php-barcode-generator/.github/workflows/phpunit.yml new file mode 100644 index 0000000..cfd73af --- /dev/null +++ b/vendor/picqer/php-barcode-generator/.github/workflows/phpunit.yml @@ -0,0 +1,36 @@ +name: Unit tests (phpunit) + +on: + push: + branches: + - main + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + php-versions: ['7.3', '7.4', '8.0', '8.1', '8.2'] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, gd, bcmath, imagick + + - name: Validate composer.json + run: composer validate + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-interaction + + - name: Run test suite + run: composer run-script test diff --git a/vendor/picqer/php-barcode-generator/.gitignore b/vendor/picqer/php-barcode-generator/.gitignore new file mode 100644 index 0000000..71981a6 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/.gitignore @@ -0,0 +1,5 @@ +vendor +composer.lock +composer.phar +.phpunit.result.cache +.DS_Store diff --git a/vendor/picqer/php-barcode-generator/LICENSE.md b/vendor/picqer/php-barcode-generator/LICENSE.md new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/LICENSE.md @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/vendor/picqer/php-barcode-generator/Readme.md b/vendor/picqer/php-barcode-generator/Readme.md new file mode 100644 index 0000000..dfdfea2 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/Readme.md @@ -0,0 +1,129 @@ +# PHP Barcode Generator +Build Status +Total Downloads +Latest Stable Version + +This is an easy to use, non-bloated, framework independent, barcode generator in PHP. It uses zero(!) composer dependencies and is only a handful of files. Probably the reason that this is the most downloaded barcode generator for PHP on Packagist. ;) + +It creates SVG, PNG, JPG and HTML images, from the most used 1D barcode standards. + +*The codebase is based on the [TCPDF barcode generator](https://github.com/tecnickcom/TCPDF) by Nicola Asuni. This code is therefor licensed under LGPLv3.* + +## No support for... +- No support for any **2D** barcodes, like QR codes. +- We only generate the 'bars' part of a barcode, without text below the barcode. If you want text of the code below the barcode, you could add it later to the output of this package. + +## Installation +Install through [composer](https://getcomposer.org/doc/00-intro.md): + +``` +composer require picqer/php-barcode-generator +``` + +If you want to generate PNG or JPG images, you need the GD library or Imagick installed on your system as well. + +## Usage +Initiate the barcode generator for the output you want, then call the ->getBarcode() routine as many times as you want. + +```php +getBarcode('081231723897', $generator::TYPE_CODE_128); +``` + +Will result in this beauty:
+![Barcode 081231723897 as Code 128](tests/verified-files/081231723897-ean13.svg) + +The `getBarcode()` method accepts the following parameters: +- `$barcode` String needed to encode in the barcode +- `$type` Type of barcode, use the constants defined in the class +- `$widthFactor` Width is based on the length of the data, with this factor you can make the barcode bars wider than default +- `$height` The total height of the barcode in pixels +- `$foregroundColor` Hex code as string, or array of RGB, of the colors of the bars (the foreground color) + +Example of usage of all parameters: + +```php +getBarcode('081231723897', $generator::TYPE_CODE_128, 3, 50, $redColor)); +``` + +## Image types +```php +$generatorSVG = new Picqer\Barcode\BarcodeGeneratorSVG(); // Vector based SVG +$generatorPNG = new Picqer\Barcode\BarcodeGeneratorPNG(); // Pixel based PNG +$generatorJPG = new Picqer\Barcode\BarcodeGeneratorJPG(); // Pixel based JPG +$generatorHTML = new Picqer\Barcode\BarcodeGeneratorHTML(); // Pixel based HTML +$generatorHTML = new Picqer\Barcode\BarcodeGeneratorDynamicHTML(); // Vector based HTML +``` + +## Accepted barcode types +These barcode types are supported. All types support different character sets or have mandatory lengths. Please see wikipedia for supported chars and lengths per type. + +Most used types are TYPE_CODE_128 and TYPE_CODE_39. Because of the best scanner support, variable length and most chars supported. + +- TYPE_CODE_32 (italian pharmaceutical code 'MINSAN') +- TYPE_CODE_39 +- TYPE_CODE_39_CHECKSUM +- TYPE_CODE_39E +- TYPE_CODE_39E_CHECKSUM +- TYPE_CODE_93 +- TYPE_STANDARD_2_5 +- TYPE_STANDARD_2_5_CHECKSUM +- TYPE_INTERLEAVED_2_5 +- TYPE_INTERLEAVED_2_5_CHECKSUM +- TYPE_CODE_128 +- TYPE_CODE_128_A +- TYPE_CODE_128_B +- TYPE_CODE_128_C +- TYPE_EAN_2 +- TYPE_EAN_5 +- TYPE_EAN_8 +- TYPE_EAN_13 +- TYPE_ITF14 (Also known as GTIN-14) +- TYPE_UPC_A +- TYPE_UPC_E +- TYPE_MSI +- TYPE_MSI_CHECKSUM +- TYPE_POSTNET +- TYPE_PLANET +- TYPE_RMS4CC +- TYPE_KIX +- TYPE_IMB +- TYPE_CODABAR +- TYPE_CODE_11 +- TYPE_PHARMA_CODE +- TYPE_PHARMA_CODE_TWO_TRACKS + +[See example images for all supported barcode types](examples.md) + +## A note about PNG and JPG images +If you want to use PNG or JPG images, you need to install [Imagick](https://www.php.net/manual/en/intro.imagick.php) or the [GD library](https://www.php.net/manual/en/intro.image.php). This package will use Imagick if that is installed, or fall back to GD. If you have both installed but you want a specific method, you can use `$generator->useGd()` or `$generator->useImagick()` to force your preference. + +## Examples + +### Embedded PNG image in HTML +```php +$generator = new Picqer\Barcode\BarcodeGeneratorPNG(); +echo ''; +``` + +### Save JPG barcode to disk +```php +$generator = new Picqer\Barcode\BarcodeGeneratorJPG(); +file_put_contents('barcode.jpg', $generator->getBarcode('081231723897', $generator::TYPE_CODABAR)); +``` + +### Oneliner SVG output to disk +```php +file_put_contents('barcode.svg', (new Picqer\Barcode\BarcodeGeneratorSVG())->getBarcode('6825ME601', Picqer\Barcode\BarcodeGeneratorSVG::TYPE_KIX)); +``` diff --git a/vendor/picqer/php-barcode-generator/composer.json b/vendor/picqer/php-barcode-generator/composer.json new file mode 100644 index 0000000..3328695 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/composer.json @@ -0,0 +1,41 @@ +{ + "name": "picqer/php-barcode-generator", + "type": "library", + "description": "An easy to use, non-bloated, barcode generator in PHP. Creates SVG, PNG, JPG and HTML images from the most used 1D barcode standards.", + "keywords": [ "php", "barcode", "barcode generator", "EAN", "EAN13", "UPC", "Code39", "Code128", "Code93", "Standard 2 of 5", "MSI", "POSTNET", "KIX", "KIXCODE", "CODABAR", "PHARMA", "Code11", "SVG", "PNG", "HTML", "JPG", "JPEG" ], + "homepage": "https://github.com/picqer/php-barcode-generator", + "license": "LGPL-3.0-or-later", + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "homepage": "http://nicolaasuni.tecnick.com" + }, + { + "name": "Casper Bakker", + "email": "info@picqer.com", + "homepage": "https://picqer.com" + } + ], + "require": { + "php": "^7.3|^8.0", + "ext-mbstring": "*" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "phpstan/phpstan": "^1.10" + }, + "suggest": { + "ext-bcmath": "Barcode IMB (Intelligent Mail Barcode) needs bcmath extension", + "ext-gd": "For JPG and PNG generators, GD or Imagick is required", + "ext-imagick": "For JPG and PNG generators, GD or Imagick is required" + }, + "autoload": { + "psr-4": { + "Picqer\\Barcode\\": "src" + } + }, + "scripts": { + "test": "vendor/bin/phpunit" + } +} diff --git a/vendor/picqer/php-barcode-generator/examples.md b/vendor/picqer/php-barcode-generator/examples.md new file mode 100644 index 0000000..00329a5 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/examples.md @@ -0,0 +1,139 @@ +# Examples of supported barcodes + +These are examples of supported barcodes with this library. + + + +### C39 + +![Barcode 1234567890ABC as C39](tests/verified-files/C39-1234567890ABC.svg) + +### C39+ + +![Barcode 1234567890ABC as C39+](tests/verified-files/C39+-1234567890ABC.svg) + +### C39E + +![Barcode 1234567890abcABC as C39E](tests/verified-files/C39E-1234567890abcABC.svg) + +### C39E+ + +![Barcode 1234567890abcABC as C39E+](tests/verified-files/C39E+-1234567890abcABC.svg) + +### C93 + +![Barcode 1234567890abcABC as C93](tests/verified-files/C93-1234567890abcABC.svg) + +### S25 + +![Barcode 1234567890 as S25](tests/verified-files/S25-1234567890.svg) + +### S25+ + +![Barcode 1234567890 as S25+](tests/verified-files/S25+-1234567890.svg) + +### I25 + +![Barcode 1234567890 as I25](tests/verified-files/I25-1234567890.svg) + +### I25+ + +![Barcode 1234567890 as I25+](tests/verified-files/I25+-1234567890.svg) + +### EAN13 + +![Barcode 081231723897 as EAN13](tests/verified-files/EAN13-081231723897.svg) + +![Barcode 0049000004632 as EAN13](tests/verified-files/EAN13-0049000004632.svg) + +![Barcode 004900000463 as EAN13](tests/verified-files/EAN13-004900000463.svg) + +### ITF14 + +![Barcode 00012345600012 as ITF14](tests/verified-files/ITF14-00012345600012.svg) + +![Barcode 05400141288766 as ITF14](tests/verified-files/ITF14-05400141288766.svg) + +### C128 + +![Barcode 081231723897 as C128](tests/verified-files/C128-081231723897.svg) + +![Barcode 1234567890abcABC-283*33 as C128](tests/verified-files/C128-1234567890abcABC-283-33.svg) + +### C128A + +![Barcode 1234567890 as C128A](tests/verified-files/C128A-1234567890.svg) + +### C128B + +![Barcode 081231723897 as C128B](tests/verified-files/C128B-081231723897.svg) + +![Barcode 1234567890abcABC-283*33 as C128B](tests/verified-files/C128B-1234567890abcABC-283-33.svg) + +### EAN2 + +![Barcode 22 as EAN2](tests/verified-files/EAN2-22.svg) + +### EAN5 + +![Barcode 1234567890abcABC-283*33 as EAN5](tests/verified-files/EAN5-1234567890abcABC-283-33.svg) + +### EAN8 + +![Barcode 1234568 as EAN8](tests/verified-files/EAN8-1234568.svg) + +### UPCA + +![Barcode 123456789 as UPCA](tests/verified-files/UPCA-123456789.svg) + +### UPCE + +![Barcode 123456789 as UPCE](tests/verified-files/UPCE-123456789.svg) + +### MSI + +![Barcode 123456789 as MSI](tests/verified-files/MSI-123456789.svg) + +### MSI+ + +![Barcode 123456789 as MSI+](tests/verified-files/MSI+-123456789.svg) + +### POSTNET + +![Barcode 123456789 as POSTNET](tests/verified-files/POSTNET-123456789.svg) + +### PLANET + +![Barcode 123456789 as PLANET](tests/verified-files/PLANET-123456789.svg) + +### RMS4CC + +![Barcode 123456789 as RMS4CC](tests/verified-files/RMS4CC-123456789.svg) + +### KIX + +![Barcode 123456789 as KIX](tests/verified-files/KIX-123456789.svg) + +### IMB + +![Barcode 123456789 as IMB](tests/verified-files/IMB-123456789.svg) + +### CODABAR + +![Barcode 123456789 as CODABAR](tests/verified-files/CODABAR-123456789.svg) + +### CODE11 + +![Barcode 123456789 as CODE11](tests/verified-files/CODE11-123456789.svg) + +### PHARMA + +![Barcode 123456789 as PHARMA](tests/verified-files/PHARMA-123456789.svg) + +### PHARMA2T + +![Barcode 123456789 as PHARMA2T](tests/verified-files/PHARMA2T-123456789.svg) + + + +*This file is generated by generate-examples.php* \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/generate-examples.php b/vendor/picqer/php-barcode-generator/generate-examples.php new file mode 100644 index 0000000..5929908 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/generate-examples.php @@ -0,0 +1,26 @@ +getBarcode('081231723897', $generatorSVG::TYPE_EAN_13)); +file_put_contents('tests/verified-files/081231723897-ean13-fractional-width.svg', $generatorSVG->getBarcode('081231723897', $generatorSVG::TYPE_EAN_13, 0.25, 25.75)); + +$generatorHTML = new Picqer\Barcode\BarcodeGeneratorHTML(); +file_put_contents('tests/verified-files/081231723897-code128.html', $generatorHTML->getBarcode('081231723897', $generatorHTML::TYPE_CODE_128)); + +file_put_contents('tests/verified-files/12345678903-imb.html', $generatorHTML->getBarcode('12345678903', $generatorHTML::TYPE_IMB)); + +$generatorDynamicHTML = new Picqer\Barcode\BarcodeGeneratorDynamicHTML(); +file_put_contents('tests/verified-files/081231723897-dynamic-code128.html', $generatorDynamicHTML->getBarcode('081231723897', $generatorDynamicHTML::TYPE_CODE_128)); + +file_put_contents('tests/verified-files/12345678903-dynamic-imb.html', $generatorDynamicHTML->getBarcode('12345678903', $generatorDynamicHTML::TYPE_IMB)); + +$generatorSVG = new Picqer\Barcode\BarcodeGeneratorSVG(); +file_put_contents('tests/verified-files/0049000004632-ean13.svg', $generatorSVG->getBarcode('0049000004632', $generatorSVG::TYPE_EAN_13)); + + +// New style of verified files +require(__DIR__ . '/tests/VerifiedBarcodeTest.php'); +$verifiedFiles = VerifiedBarcodeTest::$supportedBarcodes; + +$generatorSVG = new Picqer\Barcode\BarcodeGeneratorSVG(); +foreach ($verifiedFiles as $verifiedFile) { + foreach ($verifiedFile['barcodes'] as $barcode) { + file_put_contents('tests/verified-files/' . getSaveFilename($verifiedFile['type'] . '-' . $barcode) . '.svg', $generatorSVG->getBarcode($barcode, $verifiedFile['type'])); + } +} diff --git a/vendor/picqer/php-barcode-generator/phpstan.neon.dist b/vendor/picqer/php-barcode-generator/phpstan.neon.dist new file mode 100644 index 0000000..0405354 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/phpstan.neon.dist @@ -0,0 +1,4 @@ +parameters: + paths: + - src + level: 4 diff --git a/vendor/picqer/php-barcode-generator/phpunit.xml b/vendor/picqer/php-barcode-generator/phpunit.xml new file mode 100644 index 0000000..9f49e2c --- /dev/null +++ b/vendor/picqer/php-barcode-generator/phpunit.xml @@ -0,0 +1,13 @@ + + + + + ./src + + + + + ./tests/ + + + diff --git a/vendor/picqer/php-barcode-generator/src/Barcode.php b/vendor/picqer/php-barcode-generator/src/Barcode.php new file mode 100644 index 0000000..4ab9f20 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Barcode.php @@ -0,0 +1,43 @@ +barcode = $barcode; + } + + public function addBar(BarcodeBar $bar) + { + $this->bars[] = $bar; + $this->width += $bar->getWidth(); + $this->height = max($this->height, $bar->getHeight()); + } + + public function getBarcode(): string + { + return $this->barcode; + } + + public function getWidth(): int + { + return $this->width; + } + + public function getHeight(): int + { + return $this->height; + } + + public function getBars(): array + { + return $this->bars; + } +} \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeBar.php b/vendor/picqer/php-barcode-generator/src/BarcodeBar.php new file mode 100644 index 0000000..332a661 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeBar.php @@ -0,0 +1,42 @@ +width = $width; + $this->height = $height; + $this->positionVertical = $positionVertical; + $this->type = $drawBar ? self::TYPE_BAR : self::TYPE_SPACING; + } + + public function getWidth(): int + { + return $this->width; + } + + public function getHeight(): int + { + return $this->height; + } + + public function getPositionVertical(): int + { + return $this->positionVertical; + } + + public function isBar(): bool + { + return $this->type === self::TYPE_BAR; + } +} \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGenerator.php b/vendor/picqer/php-barcode-generator/src/BarcodeGenerator.php new file mode 100644 index 0000000..d7c1b2e --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGenerator.php @@ -0,0 +1,220 @@ +. +// +// See LICENSE.TXT file for more information. + +namespace Picqer\Barcode; + +use Picqer\Barcode\Exceptions\UnknownTypeException; +use Picqer\Barcode\Types\TypeCodabar; +use Picqer\Barcode\Types\TypeCode11; +use Picqer\Barcode\Types\TypeCode128; +use Picqer\Barcode\Types\TypeCode128A; +use Picqer\Barcode\Types\TypeCode128B; +use Picqer\Barcode\Types\TypeCode128C; +use Picqer\Barcode\Types\TypeCode32; +use Picqer\Barcode\Types\TypeCode39; +use Picqer\Barcode\Types\TypeCode39Checksum; +use Picqer\Barcode\Types\TypeCode39Extended; +use Picqer\Barcode\Types\TypeCode39ExtendedChecksum; +use Picqer\Barcode\Types\TypeCode93; +use Picqer\Barcode\Types\TypeEan13; +use Picqer\Barcode\Types\TypeEan8; +use Picqer\Barcode\Types\TypeIntelligentMailBarcode; +use Picqer\Barcode\Types\TypeInterleaved25; +use Picqer\Barcode\Types\TypeInterleaved25Checksum; +use Picqer\Barcode\Types\TypeITF14; +use Picqer\Barcode\Types\TypeKix; +use Picqer\Barcode\Types\TypeMsi; +use Picqer\Barcode\Types\TypeMsiChecksum; +use Picqer\Barcode\Types\TypePharmacode; +use Picqer\Barcode\Types\TypePharmacodeTwoCode; +use Picqer\Barcode\Types\TypePlanet; +use Picqer\Barcode\Types\TypePostnet; +use Picqer\Barcode\Types\TypeRms4cc; +use Picqer\Barcode\Types\TypeStandard2of5; +use Picqer\Barcode\Types\TypeStandard2of5Checksum; +use Picqer\Barcode\Types\TypeTelepen; +use Picqer\Barcode\Types\TypeUpcA; +use Picqer\Barcode\Types\TypeUpcE; +use Picqer\Barcode\Types\TypeUpcExtension2; +use Picqer\Barcode\Types\TypeUpcExtension5; + +abstract class BarcodeGenerator +{ + const TYPE_CODE_32 = 'C32'; + const TYPE_CODE_39 = 'C39'; + const TYPE_CODE_39_CHECKSUM = 'C39+'; + const TYPE_CODE_39E = 'C39E'; // CODE 39 EXTENDED + const TYPE_CODE_39E_CHECKSUM = 'C39E+'; // CODE 39 EXTENDED + CHECKSUM + const TYPE_CODE_93 = 'C93'; + const TYPE_STANDARD_2_5 = 'S25'; + const TYPE_STANDARD_2_5_CHECKSUM = 'S25+'; + const TYPE_INTERLEAVED_2_5 = 'I25'; + const TYPE_INTERLEAVED_2_5_CHECKSUM = 'I25+'; + const TYPE_ITF_14 = 'ITF14'; + const TYPE_CODE_128 = 'C128'; + const TYPE_CODE_128_A = 'C128A'; + const TYPE_CODE_128_B = 'C128B'; + const TYPE_CODE_128_C = 'C128C'; + const TYPE_EAN_2 = 'EAN2'; // 2-Digits UPC-Based Extention + const TYPE_EAN_5 = 'EAN5'; // 5-Digits UPC-Based Extention + const TYPE_EAN_8 = 'EAN8'; + const TYPE_EAN_13 = 'EAN13'; + const TYPE_UPC_A = 'UPCA'; + const TYPE_UPC_E = 'UPCE'; + const TYPE_MSI = 'MSI'; // MSI (Variation of Plessey code) + const TYPE_MSI_CHECKSUM = 'MSI+'; // MSI + CHECKSUM (modulo 11) + const TYPE_POSTNET = 'POSTNET'; + const TYPE_PLANET = 'PLANET'; + const TYPE_TELEPEN_ALPHA = 'TELEPENALPHA'; + const TYPE_TELEPEN_NUMERIC = 'TELEPENNUMERIC'; + const TYPE_RMS4CC = 'RMS4CC'; // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) + const TYPE_KIX = 'KIX'; // KIX (Klant index - Customer index) + const TYPE_IMB = 'IMB'; // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 + const TYPE_CODABAR = 'CODABAR'; + const TYPE_CODE_11 = 'CODE11'; + const TYPE_PHARMA_CODE = 'PHARMA'; + const TYPE_PHARMA_CODE_TWO_TRACKS = 'PHARMA2T'; + + protected function getBarcodeData(string $code, string $type): Barcode + { + $barcodeDataBuilder = $this->createDataBuilderForType($type); + + return $barcodeDataBuilder->getBarcodeData($code); + } + + protected function createDataBuilderForType(string $type) + { + switch (strtoupper($type)) { + case self::TYPE_CODE_32: + return new TypeCode32(); + + case self::TYPE_CODE_39: + return new TypeCode39(); + + case self::TYPE_CODE_39_CHECKSUM: + return new TypeCode39Checksum(); + + case self::TYPE_CODE_39E: + return new TypeCode39Extended(); + + case self::TYPE_CODE_39E_CHECKSUM: + return new TypeCode39ExtendedChecksum(); + + case self::TYPE_CODE_93: + return new TypeCode93(); + + case self::TYPE_STANDARD_2_5: + return new TypeStandard2of5(); + + case self::TYPE_STANDARD_2_5_CHECKSUM: + return new TypeStandard2of5Checksum(); + + case self::TYPE_INTERLEAVED_2_5: + return new TypeInterleaved25(); + + case self::TYPE_INTERLEAVED_2_5_CHECKSUM: + return new TypeInterleaved25Checksum(); + + case self::TYPE_ITF_14: + return new TypeITF14(); + + case self::TYPE_CODE_128: + return new TypeCode128(); + + case self::TYPE_CODE_128_A: + return new TypeCode128A(); + + case self::TYPE_CODE_128_B: + return new TypeCode128B(); + + case self::TYPE_CODE_128_C: + return new TypeCode128C(); + + case self::TYPE_EAN_2: + return new TypeUpcExtension2(); + + case self::TYPE_EAN_5: + return new TypeUpcExtension5(); + + case self::TYPE_EAN_8: + return new TypeEan8(); + + case self::TYPE_EAN_13: + return new TypeEan13(); + + case self::TYPE_UPC_A: + return new TypeUpcA(); + + case self::TYPE_UPC_E: + return new TypeUpcE(); + + case self::TYPE_MSI: + return new TypeMsi(); + + case self::TYPE_MSI_CHECKSUM: + return new TypeMsiChecksum(); + + case self::TYPE_POSTNET: + return new TypePostnet(); + + case self::TYPE_PLANET: + return new TypePlanet(); + + case self::TYPE_RMS4CC: + return new TypeRms4cc(); + + case self::TYPE_KIX: + return new TypeKix(); + + case self::TYPE_IMB: + return new TypeIntelligentMailBarcode(); + + case self::TYPE_CODABAR: + return new TypeCodabar(); + + case self::TYPE_CODE_11: + return new TypeCode11(); + + case self::TYPE_PHARMA_CODE: + return new TypePharmacode(); + + case self::TYPE_PHARMA_CODE_TWO_TRACKS: + return new TypePharmacodeTwoCode(); + + case self::TYPE_TELEPEN_ALPHA: + return new TypeTelepen(); + + case self::TYPE_TELEPEN_NUMERIC: + return new TypeTelepen('numeric'); + + } + + throw new UnknownTypeException(); + } +} diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorDynamicHTML.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorDynamicHTML.php new file mode 100644 index 0000000..57ce23e --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorDynamicHTML.php @@ -0,0 +1,44 @@ +getBarcodeData($barcode, $type); + + $html = '
' . PHP_EOL; + + $positionHorizontal = 0; + /** @var BarcodeBar $bar */ + foreach ($barcodeData->getBars() as $bar) { + $barWidth = $bar->getWidth() / $barcodeData->getWidth() * 100; + $barHeight = round(($bar->getHeight() / $barcodeData->getHeight() * 100), 3); + + if ($bar->isBar() && $barWidth > 0) { + $positionVertical = round(($bar->getPositionVertical() / $barcodeData->getHeight() * 100), 3); + + // draw a vertical bar + $html .= '
 
' . PHP_EOL; + } + + $positionHorizontal += $barWidth; + } + + $html .= '
' . PHP_EOL; + + return $html; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorHTML.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorHTML.php new file mode 100644 index 0000000..75a98fe --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorHTML.php @@ -0,0 +1,44 @@ +getBarcodeData($barcode, $type); + + $html = '
' . PHP_EOL; + + $positionHorizontal = 0; + /** @var BarcodeBar $bar */ + foreach ($barcodeData->getBars() as $bar) { + $barWidth = round(($bar->getWidth() * $widthFactor), 3); + $barHeight = round(($bar->getHeight() * $height / $barcodeData->getHeight()), 3); + + if ($bar->isBar() && $barWidth > 0) { + $positionVertical = round(($bar->getPositionVertical() * $height / $barcodeData->getHeight()), 3); + + // draw a vertical bar + $html .= '
 
' . PHP_EOL; + } + + $positionHorizontal += $barWidth; + } + + $html .= '
' . PHP_EOL; + + return $html; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorJPG.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorJPG.php new file mode 100644 index 0000000..0e33d70 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorJPG.php @@ -0,0 +1,22 @@ +newImage($width, $height, 'white', 'JPG'); + + return $image; + } + + protected function generateGdImage($image) + { + imagejpeg($image); + imagedestroy($image); + } +} diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorPNG.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorPNG.php new file mode 100644 index 0000000..150e1e4 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorPNG.php @@ -0,0 +1,121 @@ +useImagick = true; + } elseif (function_exists('imagecreate')) { + $this->useImagick = false; + } else { + throw new BarcodeException('Neither gd-lib or imagick are installed!'); + } + } + + /** + * Force the use of Imagick image extension + */ + public function useImagick() + { + $this->useImagick = true; + } + + /** + * Force the use of the GD image library + */ + public function useGd() + { + $this->useImagick = false; + } + + /** + * Return a PNG image representation of barcode (requires GD or Imagick library). + * + * @param string $barcode code to print + * @param BarcodeGenerator::TYPE_* $type (string) type of barcode + * @param int $widthFactor Width of a single bar element in pixels. + * @param int $height Height of a single bar element in pixels. + * @param array $foregroundColor RGB (0-255) foreground color for bar elements (background is transparent). + * @return string image data or false in case of error. + */ + public function getBarcode(string $barcode, $type, int $widthFactor = 2, int $height = 30, array $foregroundColor = [0, 0, 0]): string + { + $barcodeData = $this->getBarcodeData($barcode, $type); + $width = round($barcodeData->getWidth() * $widthFactor); + + if ($this->useImagick) { + $imagickBarsShape = new imagickdraw(); + $imagickBarsShape->setFillColor(new imagickpixel('rgb(' . implode(',', $foregroundColor) .')')); + } else { + $image = $this->createGdImageObject($width, $height); + $gdForegroundColor = imagecolorallocate($image, $foregroundColor[0], $foregroundColor[1], $foregroundColor[2]); + } + + // print bars + $positionHorizontal = 0; + /** @var BarcodeBar $bar */ + foreach ($barcodeData->getBars() as $bar) { + $barWidth = round(($bar->getWidth() * $widthFactor), 3); + + if ($bar->isBar() && $barWidth > 0) { + $y = round(($bar->getPositionVertical() * $height / $barcodeData->getHeight()), 3); + $barHeight = round(($bar->getHeight() * $height / $barcodeData->getHeight()), 3); + + // draw a vertical bar + if ($this->useImagick) { + $imagickBarsShape->rectangle($positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight)); + } else { + imagefilledrectangle($image, $positionHorizontal, $y, ($positionHorizontal + $barWidth - 1), ($y + $barHeight), $gdForegroundColor); + } + } + $positionHorizontal += $barWidth; + } + + if ($this->useImagick) { + $image = $this->createImagickImageObject($width, $height); + $image->drawImage($imagickBarsShape); + return $image->getImageBlob(); + } + + ob_start(); + $this->generateGdImage($image); + return ob_get_clean(); + } + + protected function createGdImageObject(int $width, int $height) + { + $image = imagecreate($width, $height); + $colorBackground = imagecolorallocate($image, 255, 255, 255); + imagecolortransparent($image, $colorBackground); + + return $image; + } + + protected function createImagickImageObject(int $width, int $height): Imagick + { + $image = new Imagick(); + $image->newImage($width, $height, 'none', 'PNG'); + + return $image; + } + + protected function generateGdImage($image) + { + imagepng($image); + imagedestroy($image); + } +} diff --git a/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorSVG.php b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorSVG.php new file mode 100644 index 0000000..4d0d477 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/BarcodeGeneratorSVG.php @@ -0,0 +1,59 @@ +getBarcodeData($barcode, $type); + + // replace table for special characters + $repstr = [ + "\0" => '', + '&' => '&', + '<' => '<', + '>' => '>', + ]; + + $width = round(($barcodeData->getWidth() * $widthFactor), 3); + + $svg = '' . PHP_EOL; + $svg .= '' . PHP_EOL; + $svg .= '' . PHP_EOL; + $svg .= "\t" . '' . strtr($barcodeData->getBarcode(), $repstr) . '' . PHP_EOL; + $svg .= "\t" . '' . PHP_EOL; + + // print bars + $positionHorizontal = 0; + /** @var BarcodeBar $bar */ + foreach ($barcodeData->getBars() as $bar) { + $barWidth = round(($bar->getWidth() * $widthFactor), 3); + $barHeight = round(($bar->getHeight() * $height / $barcodeData->getHeight()), 3); + + if ($bar->isBar() && $barWidth > 0) { + $positionVertical = round(($bar->getPositionVertical() * $height / $barcodeData->getHeight()), 3); + // draw a vertical bar + $svg .= "\t\t" . '' . PHP_EOL; + } + + $positionHorizontal += $barWidth; + } + + $svg .= "\t" . PHP_EOL; + $svg .= '' . PHP_EOL; + + return $svg; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Exceptions/BarcodeException.php b/vendor/picqer/php-barcode-generator/src/Exceptions/BarcodeException.php new file mode 100644 index 0000000..9ee1ad4 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Exceptions/BarcodeException.php @@ -0,0 +1,5 @@ +addBar(new BarcodeBar($barWidth, 1, $drawBar)); + $barWidth = 0; + } + } + + return $barcode; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeCodabar.php b/vendor/picqer/php-barcode-generator/src/Types/TypeCodabar.php new file mode 100644 index 0000000..0bf40e1 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeCodabar.php @@ -0,0 +1,64 @@ + '11111221', + '1' => '11112211', + '2' => '11121121', + '3' => '22111111', + '4' => '11211211', + '5' => '21111211', + '6' => '12111121', + '7' => '12112111', + '8' => '12211111', + '9' => '21121111', + '-' => '11122111', + '$' => '11221111', + ':' => '21112121', + '/' => '21211121', + '.' => '21212111', + '+' => '11222221', + 'A' => '11221211', + 'B' => '12121121', + 'C' => '11121221', + 'D' => '11122211' + ]; + + public function getBarcodeData(string $code): Barcode + { + $barcode = new Barcode($code); + + $code = 'A' . strtoupper($code) . 'A'; + + for ($i = 0; $i < strlen($code); ++$i) { + if (! isset($this->conversionTable[(string)$code[$i]])) { + throw new InvalidCharacterException('Char ' . $code[$i] . ' is unsupported'); + } + + $seq = $this->conversionTable[(string)$code[$i]]; + for ($j = 0; $j < 8; ++$j) { + if (($j % 2) == 0) { + $drawBar = true; + } else { + $drawBar = false; + } + $barWidth = $seq[$j]; + $barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar)); + } + } + + return $barcode; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeCode11.php b/vendor/picqer/php-barcode-generator/src/Types/TypeCode11.php new file mode 100644 index 0000000..2857cb3 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeCode11.php @@ -0,0 +1,111 @@ + '111121', + '1' => '211121', + '2' => '121121', + '3' => '221111', + '4' => '112121', + '5' => '212111', + '6' => '122111', + '7' => '111221', + '8' => '211211', + '9' => '211111', + '-' => '112111', + 'S' => '112211', + ]; + + public function getBarcodeData(string $code): Barcode + { + $barcode = new Barcode($code); + + $code .= $this->getCheckDigitC($code); + $code .= $this->getCheckDigitK($code); + + $code = 'S' . $code . 'S'; + + for ($i = 0; $i < strlen($code); ++$i) { + if (! isset($this->conversionTable[$code[$i]])) { + throw new InvalidCharacterException('Char ' . $code[$i] . ' is unsupported'); + } + + $seq = $this->conversionTable[$code[$i]]; + for ($j = 0; $j < strlen($seq); ++$j) { + if (($j % 2) == 0) { + $drawBar = true; + } else { + $drawBar = false; + } + $barWidth = $seq[$j]; + + $barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar)); + } + } + + return $barcode; + } + + private function getCheckDigitC(string $code): string + { + $p = 1; + $check = 0; + for ($i = (strlen($code) - 1); $i >= 0; --$i) { + $digit = $code[$i]; + if ($digit == '-') { + $dval = 10; + } else { + $dval = intval($digit); + } + $check += ($dval * $p); + ++$p; + if ($p > 10) { + $p = 1; + } + } + $check %= 11; + if ($check == 10) { + $check = '-'; + } + + return $check; + } + + private function getCheckDigitK(string $code): string + { + if (strlen($code) <= 10) { + return ''; + } + + $p = 1; + $check = 0; + for ($i = (strlen($code) - 1); $i >= 0; --$i) { + $digit = $code[$i]; + if ($digit == '-') { + $dval = 10; + } else { + $dval = intval($digit); + } + $check += ($dval * $p); + ++$p; + if ($p > 9) { + $p = 1; + } + } + $check %= 11; + + return (string)$check; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeCode128.php b/vendor/picqer/php-barcode-generator/src/Types/TypeCode128.php new file mode 100644 index 0000000..38fc618 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeCode128.php @@ -0,0 +1,420 @@ +?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; + $keys_a .= chr(0) . chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8) . chr(9); + $keys_a .= chr(10) . chr(11) . chr(12) . chr(13) . chr(14) . chr(15) . chr(16) . chr(17) . chr(18) . chr(19); + $keys_a .= chr(20) . chr(21) . chr(22) . chr(23) . chr(24) . chr(25) . chr(26) . chr(27) . chr(28) . chr(29); + $keys_a .= chr(30) . chr(31); + + // ASCII characters for code B (ASCII 32 - 127) + $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' . chr(127); + + // special codes + $fnc_a = [241 => 102, 242 => 97, 243 => 96, 244 => 101]; + $fnc_b = [241 => 102, 242 => 97, 243 => 96, 244 => 100]; + + // array of symbols + $code_data = []; + + // length of the code + $len = strlen($code); + + switch (strtoupper($this->type ?? "")) { + case 'A': + $startid = 103; + for ($i = 0; $i < $len; ++$i) { + $char = $code[$i]; + $char_id = ord($char); + if (($char_id >= 241) AND ($char_id <= 244)) { + $code_data[] = $fnc_a[$char_id]; + } elseif ($char_id <= 95) { + $code_data[] = strpos($keys_a, $char); + } else { + throw new InvalidCharacterException('Char ' . $char . ' is unsupported'); + } + } + break; + + case 'B': + $startid = 104; + for ($i = 0; $i < $len; ++$i) { + $char = $code[$i]; + $char_id = ord($char); + if (($char_id >= 241) AND ($char_id <= 244)) { + $code_data[] = $fnc_b[$char_id]; + } elseif (($char_id >= 32) AND ($char_id <= 127)) { + $code_data[] = strpos($keys_b, $char); + } else { + throw new InvalidCharacterException('Char ' . $char . ' is unsupported'); + } + } + break; + + case 'C': + $startid = 105; + if (ord($code[0]) == 241) { + $code_data[] = 102; + $code = substr($code, 1); + --$len; + } + if (($len % 2) != 0) { + throw new InvalidLengthException('Length must be even'); + } + for ($i = 0; $i < $len; $i += 2) { + $chrnum = $code[$i] . $code[$i + 1]; + if (preg_match('/([0-9]{2})/', $chrnum) > 0) { + $code_data[] = intval($chrnum); + } else { + throw new InvalidCharacterException(); + } + } + break; + + default: + // split code into sequences + $sequence = []; + // get numeric sequences (if any) + $numseq = []; + preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE); + if (isset($numseq[1]) AND ! empty($numseq[1])) { + $end_offset = 0; + foreach ($numseq[1] as $val) { + $offset = $val[1]; + + // numeric sequence + $slen = strlen($val[0]); + if (($slen % 2) != 0) { + // the length must be even + ++$offset; + $val[0] = substr($val[0], 1); + } + + if ($offset > $end_offset) { + // non numeric sequence + $sequence = array_merge($sequence, + $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset)))); + } + // numeric sequence fallback + $slen = strlen($val[0]); + if (($slen % 2) != 0) { + // the length must be even + --$slen; + } + $sequence[] = ['C', substr($code, $offset, $slen), $slen]; + $end_offset = $offset + $slen; + } + if ($end_offset < $len) { + $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset))); + } + } else { + // text code (non C mode) + $sequence = array_merge($sequence, $this->get128ABsequence($code)); + } + + // process the sequence + foreach ($sequence as $key => $seq) { + switch ($seq[0]) { + case 'A': + if ($key == 0) { + $startid = 103; + } elseif ($sequence[($key - 1)][0] != 'A') { + if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'B') AND (! isset($sequence[($key - 1)][3]))) { + // single character shift + $code_data[] = 98; + // mark shift + $sequence[$key][3] = true; + } elseif (! isset($sequence[($key - 1)][3])) { + $code_data[] = 101; + } + } + for ($i = 0; $i < $seq[2]; ++$i) { + $char = $seq[1][$i]; + $char_id = ord($char); + if (($char_id >= 241) AND ($char_id <= 244)) { + $code_data[] = $fnc_a[$char_id]; + } else { + $code_data[] = strpos($keys_a, $char); + } + } + break; + + case 'B': + if ($key == 0) { + $tmpchr = ord($seq[1][0]); + if (($seq[2] == 1) AND ($tmpchr >= 241) AND ($tmpchr <= 244) AND isset($sequence[($key + 1)]) AND ($sequence[($key + 1)][0] != 'B')) { + switch ($sequence[($key + 1)][0]) { + case 'A': + { + $startid = 103; + $sequence[$key][0] = 'A'; + $code_data[] = $fnc_a[$tmpchr]; + break; + } + case 'C': + { + $startid = 105; + $sequence[$key][0] = 'C'; + $code_data[] = $fnc_a[$tmpchr]; + break; + } + } + break; + } else { + $startid = 104; + } + } elseif ($sequence[($key - 1)][0] != 'B') { + if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'A') AND (! isset($sequence[($key - 1)][3]))) { + // single character shift + $code_data[] = 98; + // mark shift + $sequence[$key][3] = true; + } elseif (! isset($sequence[($key - 1)][3])) { + $code_data[] = 100; + } + } + for ($i = 0; $i < $seq[2]; ++$i) { + $char = $seq[1][$i]; + $char_id = ord($char); + if (($char_id >= 241) AND ($char_id <= 244)) { + $code_data[] = $fnc_b[$char_id]; + } else { + $code_data[] = strpos($keys_b, $char); + } + } + break; + + case 'C': + if ($key == 0) { + $startid = 105; + } elseif ($sequence[($key - 1)][0] != 'C') { + $code_data[] = 99; + } + for ($i = 0; $i < $seq[2]; $i += 2) { + $chrnum = $seq[1][$i] . $seq[1][$i + 1]; + $code_data[] = intval($chrnum); + } + break; + + default: + throw new InvalidCharacterException('Do not support different mode then A, B or C.'); + } + } + } + + // calculate check character + if (! isset($startid)) { + throw new BarcodeException('Could not determine start char for barcode.'); + } + + $sum = $startid; + foreach ($code_data as $key => $val) { + $sum += ($val * ($key + 1)); + } + // add check character + $code_data[] = ($sum % 103); + // add stop sequence + $code_data[] = 106; + $code_data[] = 107; + // add start code at the beginning + array_unshift($code_data, $startid); + + // build barcode array + $barcode = new Barcode($code); + foreach ($code_data as $val) { + $seq = $this->conversionTable[$val]; + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq[$j]; + + $barcode->addBar(new BarcodeBar($w, 1, $t)); + } + } + + return $barcode; + } + + + /** + * Split text code in A/B sequence for 128 code + * + * @param $code (string) code to split. + * @return array sequence + * @protected + */ + protected function get128ABsequence($code) + { + $len = strlen($code); + $sequence = []; + // get A sequences (if any) + $numseq = []; + preg_match_all('/([\x00-\x1f])/', $code, $numseq, PREG_OFFSET_CAPTURE); + if (isset($numseq[1]) AND ! empty($numseq[1])) { + $end_offset = 0; + foreach ($numseq[1] as $val) { + $offset = $val[1]; + if ($offset > $end_offset) { + // B sequence + $sequence[] = [ + 'B', + substr($code, $end_offset, ($offset - $end_offset)), + ($offset - $end_offset) + ]; + } + // A sequence + $slen = strlen($val[0]); + $sequence[] = ['A', substr($code, $offset, $slen), $slen]; + $end_offset = $offset + $slen; + } + if ($end_offset < $len) { + $sequence[] = ['B', substr($code, $end_offset), ($len - $end_offset)]; + } + } else { + // only B sequence + $sequence[] = ['B', $code, $len]; + } + + return $sequence; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeCode128A.php b/vendor/picqer/php-barcode-generator/src/Types/TypeCode128A.php new file mode 100644 index 0000000..ff2fe0c --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeCode128A.php @@ -0,0 +1,16 @@ + '0', + '1' => '1', + '2' => '2', + '3' => '3', + '4' => '4', + '5' => '5', + '6' => '6', + '7' => '7', + '8' => '8', + '9' => '9', + '10' => 'B', + '11' => 'C', + '12' => 'D', + '13' => 'F', + '14' => 'G', + '15' => 'H', + '16' => 'J', + '17' => 'K', + '18' => 'L', + '19' => 'M', + '20' => 'N', + '21' => 'P', + '22' => 'Q', + '23' => 'R', + '24' => 'S', + '25' => 'T', + '26' => 'U', + '27' => 'V', + '28' => 'W', + '29' => 'X', + '30' => 'Y', + '31' => 'Z' + ]; + + public function getBarcodeData(string $code): Barcode + { + // Validate code 32. + $stringLength = strlen($code); + + for ($i = 0; $i < $stringLength; ++$i) { + if (!is_numeric($code[$i])) { + throw new InvalidCharacterException('Character "' . $code[$i] . '" is not supported.'); + } + } + + // Prepare code 32. + $code = str_pad($code, 8, '0', STR_PAD_LEFT); + $checksumDigit = $this->checksum_code32(substr($code, 0, 8)); + $stringLength = max($stringLength, 8); + + if ($stringLength === 8) { + $code .= $checksumDigit; + ++$stringLength; + } + if ($stringLength !== 9) { + throw new InvalidLengthException('Only a code consisting of no more than 9 numbers is supported.'); + } + if ($code[8] !== $checksumDigit) { + throw new InvalidCheckDigitException('Provided checksum digit is wrong for provided code.'); + } + + // Convert code 32 into code 39. + $code39 = ''; + $codeElab = $code; + + for ($e = 5; $e >= 0; --$e) { + $code39 .= $this->conversionTable32[intval($codeElab / pow(32, $e))]; + $codeElab = $codeElab % pow(32, $e); + } + + // Return barcode data for code 39. + return parent::getBarcodeData($code39); + } + + + /** + * Calculate CODE 32 checksum (modulo 10). + * + * @param string $code code to represent. + * @return string char checksum. + * @protected + */ + protected function checksum_code32(string $code): string + { + $s = 0; + + foreach (str_split($code) as $i => $c) { + if (0 === $i % 2) { + $s += (int)$c; + } else { + $c = 2 * (int)$c; + $s += (int)floor($c / 10) + ($c % 10); + } + } + + return (string)($s % 10); + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeCode39.php b/vendor/picqer/php-barcode-generator/src/Types/TypeCode39.php new file mode 100644 index 0000000..5a4a2d2 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeCode39.php @@ -0,0 +1,329 @@ + '111331311', + '1' => '311311113', + '2' => '113311113', + '3' => '313311111', + '4' => '111331113', + '5' => '311331111', + '6' => '113331111', + '7' => '111311313', + '8' => '311311311', + '9' => '113311311', + 'A' => '311113113', + 'B' => '113113113', + 'C' => '313113111', + 'D' => '111133113', + 'E' => '311133111', + 'F' => '113133111', + 'G' => '111113313', + 'H' => '311113311', + 'I' => '113113311', + 'J' => '111133311', + 'K' => '311111133', + 'L' => '113111133', + 'M' => '313111131', + 'N' => '111131133', + 'O' => '311131131', + 'P' => '113131131', + 'Q' => '111111333', + 'R' => '311111331', + 'S' => '113111331', + 'T' => '111131331', + 'U' => '331111113', + 'V' => '133111113', + 'W' => '333111111', + 'X' => '131131113', + 'Y' => '331131111', + 'Z' => '133131111', + '-' => '131111313', + '.' => '331111311', + ' ' => '133111311', + '$' => '131313111', + '/' => '131311131', + '+' => '131113131', + '%' => '111313131', + '*' => '131131311', + ]; + + public function getBarcodeData(string $code): Barcode + { + if (strlen(trim($code)) === 0) { + throw new InvalidLengthException('You should provide a barcode string.'); + } + + if ($this->extended) { + // extended mode + $code = $this->encode_code39_ext($code); + } + + if ($this->checksum) { + // checksum + $code .= $this->checksum_code39($code); + } + + // add start and stop codes + $code = '*' . $code . '*'; + + $barcode = new Barcode($code); + + for ($i = 0; $i < strlen($code); ++$i) { + $char = $code[$i]; + if (! isset($this->conversionTable[$char])) { + throw new InvalidCharacterException('Char ' . $char . ' is unsupported'); + } + + for ($j = 0; $j < 9; ++$j) { + if (($j % 2) == 0) { + $drawBar = true; + } else { + $drawBar = false; + } + $barWidth = $this->conversionTable[$char][$j]; + $barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar)); + } + + // inter character gap + $barcode->addBar(new BarcodeBar(1, 1, false)); + } + + return $barcode; + } + + + /** + * Encode a string to be used for CODE 39 Extended mode. + * + * @param string $code code to represent. + * @return bool|string encoded string. + * @protected + */ + protected function encode_code39_ext($code) + { + $encode = [ + chr(0) => '%U', + chr(1) => '$A', + chr(2) => '$B', + chr(3) => '$C', + chr(4) => '$D', + chr(5) => '$E', + chr(6) => '$F', + chr(7) => '$G', + chr(8) => '$H', + chr(9) => '$I', + chr(10) => '$J', + chr(11) => '$K', + chr(12) => '$L', + chr(13) => '$M', + chr(14) => '$N', + chr(15) => '$O', + chr(16) => '$P', + chr(17) => '$Q', + chr(18) => '$R', + chr(19) => '$S', + chr(20) => '$T', + chr(21) => '$U', + chr(22) => '$V', + chr(23) => '$W', + chr(24) => '$X', + chr(25) => '$Y', + chr(26) => '$Z', + chr(27) => '%A', + chr(28) => '%B', + chr(29) => '%C', + chr(30) => '%D', + chr(31) => '%E', + chr(32) => ' ', + chr(33) => '/A', + chr(34) => '/B', + chr(35) => '/C', + chr(36) => '/D', + chr(37) => '/E', + chr(38) => '/F', + chr(39) => '/G', + chr(40) => '/H', + chr(41) => '/I', + chr(42) => '/J', + chr(43) => '/K', + chr(44) => '/L', + chr(45) => '-', + chr(46) => '.', + chr(47) => '/O', + chr(48) => '0', + chr(49) => '1', + chr(50) => '2', + chr(51) => '3', + chr(52) => '4', + chr(53) => '5', + chr(54) => '6', + chr(55) => '7', + chr(56) => '8', + chr(57) => '9', + chr(58) => '/Z', + chr(59) => '%F', + chr(60) => '%G', + chr(61) => '%H', + chr(62) => '%I', + chr(63) => '%J', + chr(64) => '%V', + chr(65) => 'A', + chr(66) => 'B', + chr(67) => 'C', + chr(68) => 'D', + chr(69) => 'E', + chr(70) => 'F', + chr(71) => 'G', + chr(72) => 'H', + chr(73) => 'I', + chr(74) => 'J', + chr(75) => 'K', + chr(76) => 'L', + chr(77) => 'M', + chr(78) => 'N', + chr(79) => 'O', + chr(80) => 'P', + chr(81) => 'Q', + chr(82) => 'R', + chr(83) => 'S', + chr(84) => 'T', + chr(85) => 'U', + chr(86) => 'V', + chr(87) => 'W', + chr(88) => 'X', + chr(89) => 'Y', + chr(90) => 'Z', + chr(91) => '%K', + chr(92) => '%L', + chr(93) => '%M', + chr(94) => '%N', + chr(95) => '%O', + chr(96) => '%W', + chr(97) => '+A', + chr(98) => '+B', + chr(99) => '+C', + chr(100) => '+D', + chr(101) => '+E', + chr(102) => '+F', + chr(103) => '+G', + chr(104) => '+H', + chr(105) => '+I', + chr(106) => '+J', + chr(107) => '+K', + chr(108) => '+L', + chr(109) => '+M', + chr(110) => '+N', + chr(111) => '+O', + chr(112) => '+P', + chr(113) => '+Q', + chr(114) => '+R', + chr(115) => '+S', + chr(116) => '+T', + chr(117) => '+U', + chr(118) => '+V', + chr(119) => '+W', + chr(120) => '+X', + chr(121) => '+Y', + chr(122) => '+Z', + chr(123) => '%P', + chr(124) => '%Q', + chr(125) => '%R', + chr(126) => '%S', + chr(127) => '%T' + ]; + + $code_ext = ''; + for ($i = 0; $i < strlen($code); ++$i) { + if (ord($code[$i]) > 127) { + throw new InvalidCharacterException('Only supports till char 127'); + } + + $code_ext .= $encode[$code[$i]]; + } + + return $code_ext; + } + + + /** + * Calculate CODE 39 checksum (modulo 43). + * + * @param string $code code to represent. + * @return string char checksum. + * @protected + */ + protected function checksum_code39($code) + { + $chars = [ + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '-', + '.', + ' ', + '$', + '/', + '+', + '%' + ]; + + $sum = 0; + for ($i = 0; $i < strlen($code); ++$i) { + $k = array_keys($chars, $code[$i]); + $sum += $k[0]; + } + $j = ($sum % 43); + + return $chars[$j]; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeCode39Checksum.php b/vendor/picqer/php-barcode-generator/src/Types/TypeCode39Checksum.php new file mode 100644 index 0000000..b129f28 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeCode39Checksum.php @@ -0,0 +1,14 @@ + '131112', // 0 + 49 => '111213', // 1 + 50 => '111312', // 2 + 51 => '111411', // 3 + 52 => '121113', // 4 + 53 => '121212', // 5 + 54 => '121311', // 6 + 55 => '111114', // 7 + 56 => '131211', // 8 + 57 => '141111', // 9 + 65 => '211113', // A + 66 => '211212', // B + 67 => '211311', // C + 68 => '221112', // D + 69 => '221211', // E + 70 => '231111', // F + 71 => '112113', // G + 72 => '112212', // H + 73 => '112311', // I + 74 => '122112', // J + 75 => '132111', // K + 76 => '111123', // L + 77 => '111222', // M + 78 => '111321', // N + 79 => '121122', // O + 80 => '131121', // P + 81 => '212112', // Q + 82 => '212211', // R + 83 => '211122', // S + 84 => '211221', // T + 85 => '221121', // U + 86 => '222111', // V + 87 => '112122', // W + 88 => '112221', // X + 89 => '122121', // Y + 90 => '123111', // Z + 45 => '121131', // - + 46 => '311112', // . + 32 => '311211', // + 36 => '321111', // $ + 47 => '112131', // / + 43 => '113121', // + + 37 => '211131', // % + 97 => '121221', // ($) + 98 => '312111', // (%) + 99 => '311121', // (/) + 100 => '122211', // (+) + 42 => '111141', // start-stop + ]; + + public function getBarcodeData(string $code): Barcode + { + $encode = [ + chr(0) => 'bU', + chr(1) => 'aA', + chr(2) => 'aB', + chr(3) => 'aC', + chr(4) => 'aD', + chr(5) => 'aE', + chr(6) => 'aF', + chr(7) => 'aG', + chr(8) => 'aH', + chr(9) => 'aI', + chr(10) => 'aJ', + chr(11) => 'aK', + chr(12) => 'aL', + chr(13) => 'aM', + chr(14) => 'aN', + chr(15) => 'aO', + chr(16) => 'aP', + chr(17) => 'aQ', + chr(18) => 'aR', + chr(19) => 'aS', + chr(20) => 'aT', + chr(21) => 'aU', + chr(22) => 'aV', + chr(23) => 'aW', + chr(24) => 'aX', + chr(25) => 'aY', + chr(26) => 'aZ', + chr(27) => 'bA', + chr(28) => 'bB', + chr(29) => 'bC', + chr(30) => 'bD', + chr(31) => 'bE', + chr(32) => ' ', + chr(33) => 'cA', + chr(34) => 'cB', + chr(35) => 'cC', + chr(36) => '$', + chr(37) => '%', + chr(38) => 'cF', + chr(39) => 'cG', + chr(40) => 'cH', + chr(41) => 'cI', + chr(42) => 'cJ', + chr(43) => '+', + chr(44) => 'cL', + chr(45) => '-', + chr(46) => '.', + chr(47) => '/', + chr(48) => '0', + chr(49) => '1', + chr(50) => '2', + chr(51) => '3', + chr(52) => '4', + chr(53) => '5', + chr(54) => '6', + chr(55) => '7', + chr(56) => '8', + chr(57) => '9', + chr(58) => 'cZ', + chr(59) => 'bF', + chr(60) => 'bG', + chr(61) => 'bH', + chr(62) => 'bI', + chr(63) => 'bJ', + chr(64) => 'bV', + chr(65) => 'A', + chr(66) => 'B', + chr(67) => 'C', + chr(68) => 'D', + chr(69) => 'E', + chr(70) => 'F', + chr(71) => 'G', + chr(72) => 'H', + chr(73) => 'I', + chr(74) => 'J', + chr(75) => 'K', + chr(76) => 'L', + chr(77) => 'M', + chr(78) => 'N', + chr(79) => 'O', + chr(80) => 'P', + chr(81) => 'Q', + chr(82) => 'R', + chr(83) => 'S', + chr(84) => 'T', + chr(85) => 'U', + chr(86) => 'V', + chr(87) => 'W', + chr(88) => 'X', + chr(89) => 'Y', + chr(90) => 'Z', + chr(91) => 'bK', + chr(92) => 'bL', + chr(93) => 'bM', + chr(94) => 'bN', + chr(95) => 'bO', + chr(96) => 'bW', + chr(97) => 'dA', + chr(98) => 'dB', + chr(99) => 'dC', + chr(100) => 'dD', + chr(101) => 'dE', + chr(102) => 'dF', + chr(103) => 'dG', + chr(104) => 'dH', + chr(105) => 'dI', + chr(106) => 'dJ', + chr(107) => 'dK', + chr(108) => 'dL', + chr(109) => 'dM', + chr(110) => 'dN', + chr(111) => 'dO', + chr(112) => 'dP', + chr(113) => 'dQ', + chr(114) => 'dR', + chr(115) => 'dS', + chr(116) => 'dT', + chr(117) => 'dU', + chr(118) => 'dV', + chr(119) => 'dW', + chr(120) => 'dX', + chr(121) => 'dY', + chr(122) => 'dZ', + chr(123) => 'bP', + chr(124) => 'bQ', + chr(125) => 'bR', + chr(126) => 'bS', + chr(127) => 'bT', + ]; + + $code_ext = ''; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + if (ord($code[$i]) > 127) { + throw new InvalidCharacterException('Only supports till char 127'); + } + $code_ext .= $encode[$code[$i]]; + } + + // checksum + $code_ext .= $this->checksum_code93($code_ext); + + // add start and stop codes + $code = '*' . $code_ext . '*'; + + $barcode = new Barcode($code); + + for ($i = 0; $i < strlen($code); ++$i) { + $char = ord($code[$i]); + if (! isset($this->conversionTable[$char])) { + throw new InvalidCharacterException('Char ' . $char . ' is unsupported'); + } + + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $drawBar = true; + } else { + $drawBar = false; + } + $barWidth = $this->conversionTable[$char][$j]; + + $barcode->addBar(new BarcodeBar($barWidth, 1, $drawBar)); + } + } + + $barcode->addBar(new BarcodeBar(1, 1, true)); + + return $barcode; + } + + /** + * Calculate CODE 93 checksum (modulo 47). + * + * @param $code (string) code to represent. + * @return string checksum code. + * @protected + */ + protected function checksum_code93($code) + { + $chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', 'a', 'b', 'c', 'd']; + + // calculate check digit C + $len = strlen($code); + $p = 1; + $check = 0; + for ($i = ($len - 1); $i >= 0; --$i) { + $k = array_keys($chars, $code[$i]); + $check += ($k[0] * $p); + ++$p; + if ($p > 20) { + $p = 1; + } + } + $check %= 47; + $c = $chars[$check]; + $code .= $c; + + // calculate check digit K + $p = 1; + $check = 0; + for ($i = $len; $i >= 0; --$i) { + $k = array_keys($chars, $code[$i]); + $check += ($k[0] * $p); + ++$p; + if ($p > 15) { + $p = 1; + } + } + $check %= 47; + $k = $chars[$check]; + + $checksum = $c . $k; + + return $checksum; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeEan13.php b/vendor/picqer/php-barcode-generator/src/Types/TypeEan13.php new file mode 100644 index 0000000..194d3ee --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeEan13.php @@ -0,0 +1,20 @@ +length; + + $dataLength = $length - 1; + + // Add zero padding in front + $code = str_pad($code, $dataLength, '0', STR_PAD_LEFT); + + $checksumDigit = $this->calculateChecksumDigit($code); + + if (strlen($code) == $dataLength) { + $code .= $checksumDigit; + } elseif ($checksumDigit !== intval($code[$dataLength])) { + // If length of given barcode is same as final length, barcode is including checksum + // Make sure that checksum is the same as we calculated + throw new InvalidCheckDigitException(); + } + + if ($this->upca || $this->upce) { + $code = '0' . $code; + ++$length; + } + + if ($this->upce) { + // convert UPC-A to UPC-E + $tmp = substr($code, 4, 3); + if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) { + // manufacturer code ends in 000, 100, or 200 + $upce_code = substr($code, 2, 2) . substr($code, 9, 3) . substr($code, 4, 1); + } else { + $tmp = substr($code, 5, 2); + if ($tmp == '00') { + // manufacturer code ends in 00 + $upce_code = substr($code, 2, 3) . substr($code, 10, 2) . '3'; + } else { + $tmp = substr($code, 6, 1); + if ($tmp == '0') { + // manufacturer code ends in 0 + $upce_code = substr($code, 2, 4) . substr($code, 11, 1) . '4'; + } else { + // manufacturer code does not end in zero + $upce_code = substr($code, 2, 5) . substr($code, 11, 1); + } + } + } + } + + // Convert digits to bars + $codes = [ + 'A' => [ // left odd parity + '0' => '0001101', + '1' => '0011001', + '2' => '0010011', + '3' => '0111101', + '4' => '0100011', + '5' => '0110001', + '6' => '0101111', + '7' => '0111011', + '8' => '0110111', + '9' => '0001011' + ], + 'B' => [ // left even parity + '0' => '0100111', + '1' => '0110011', + '2' => '0011011', + '3' => '0100001', + '4' => '0011101', + '5' => '0111001', + '6' => '0000101', + '7' => '0010001', + '8' => '0001001', + '9' => '0010111' + ], + 'C' => [ // right + '0' => '1110010', + '1' => '1100110', + '2' => '1101100', + '3' => '1000010', + '4' => '1011100', + '5' => '1001110', + '6' => '1010000', + '7' => '1000100', + '8' => '1001000', + '9' => '1110100' + ] + ]; + + $parities = [ + '0' => ['A', 'A', 'A', 'A', 'A', 'A'], + '1' => ['A', 'A', 'B', 'A', 'B', 'B'], + '2' => ['A', 'A', 'B', 'B', 'A', 'B'], + '3' => ['A', 'A', 'B', 'B', 'B', 'A'], + '4' => ['A', 'B', 'A', 'A', 'B', 'B'], + '5' => ['A', 'B', 'B', 'A', 'A', 'B'], + '6' => ['A', 'B', 'B', 'B', 'A', 'A'], + '7' => ['A', 'B', 'A', 'B', 'A', 'B'], + '8' => ['A', 'B', 'A', 'B', 'B', 'A'], + '9' => ['A', 'B', 'B', 'A', 'B', 'A'], + ]; + + $upce_parities = [ + [ + '0' => ['B', 'B', 'B', 'A', 'A', 'A'], + '1' => ['B', 'B', 'A', 'B', 'A', 'A'], + '2' => ['B', 'B', 'A', 'A', 'B', 'A'], + '3' => ['B', 'B', 'A', 'A', 'A', 'B'], + '4' => ['B', 'A', 'B', 'B', 'A', 'A'], + '5' => ['B', 'A', 'A', 'B', 'B', 'A'], + '6' => ['B', 'A', 'A', 'A', 'B', 'B'], + '7' => ['B', 'A', 'B', 'A', 'B', 'A'], + '8' => ['B', 'A', 'B', 'A', 'A', 'B'], + '9' => ['B', 'A', 'A', 'B', 'A', 'B'], + ], + [ + '0' => ['A', 'A', 'A', 'B', 'B', 'B'], + '1' => ['A', 'A', 'B', 'A', 'B', 'B'], + '2' => ['A', 'A', 'B', 'B', 'A', 'B'], + '3' => ['A', 'A', 'B', 'B', 'B', 'A'], + '4' => ['A', 'B', 'A', 'A', 'B', 'B'], + '5' => ['A', 'B', 'B', 'A', 'A', 'B'], + '6' => ['A', 'B', 'B', 'B', 'A', 'A'], + '7' => ['A', 'B', 'A', 'B', 'A', 'B'], + '8' => ['A', 'B', 'A', 'B', 'B', 'A'], + '9' => ['A', 'B', 'B', 'A', 'B', 'A'], + ], + ]; + + $seq = '101'; // left guard bar + if ($this->upce) { + $barcode = new Barcode($upce_code); + $p = $upce_parities[$code[1]][$checksumDigit]; + for ($i = 0; $i < 6; ++$i) { + $seq .= $codes[$p[$i]][$upce_code[$i]]; + } + $seq .= '010101'; // right guard bar + } else { + $barcode = new Barcode($code); + $half_len = intval(ceil($length / 2)); + if ($length == 8) { + for ($i = 0; $i < $half_len; ++$i) { + $seq .= $codes['A'][$code[$i]]; + } + } else { + $p = $parities[$code[0]]; + for ($i = 1; $i < $half_len; ++$i) { + $seq .= $codes[$p[$i - 1]][$code[$i]]; + } + } + $seq .= '01010'; // center guard bar + for ($i = $half_len; $i < $length; ++$i) { + if (! isset($codes['C'][$code[$i]])) { + throw new InvalidCharacterException('Char ' . $code[$i] . ' not allowed'); + } + $seq .= $codes['C'][$code[$i]]; + } + $seq .= '101'; // right guard bar + } + + $clen = strlen($seq); + $w = 0; + for ($i = 0; $i < $clen; ++$i) { + $w += 1; + if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq[$i] != $seq[($i + 1)]))) { + if ($seq[$i] == '1') { + $t = true; // bar + } else { + $t = false; // space + } + + $barcode->addBar(new BarcodeBar($w, 1, $t)); + $w = 0; + } + } + + return $barcode; + } + + protected function calculateChecksumDigit(string $code) + { + // calculate check digit + $sum_a = 0; + for ($i = 1; $i < $this->length - 1; $i += 2) { + $sum_a += $code[$i]; + } + if ($this->length > 12) { + $sum_a *= 3; + } + $sum_b = 0; + for ($i = 0; $i < $this->length - 1; $i += 2) { + $sum_b += intval(($code[$i])); + } + if ($this->length < 13) { + $sum_b *= 3; + } + $checksumDigit = ($sum_a + $sum_b) % 10; + if ($checksumDigit > 0) { + $checksumDigit = (10 - $checksumDigit); + } + + return $checksumDigit; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeITF14.php b/vendor/picqer/php-barcode-generator/src/Types/TypeITF14.php new file mode 100644 index 0000000..ff395d9 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeITF14.php @@ -0,0 +1,87 @@ + 14) { + throw new InvalidLengthException(); + } + + if (strlen($code) === 13) { + $code .= $this->getChecksum($code); + } + + $barcode = new Barcode($code); + + // Add start and stop codes + $code = 'AA' . strtolower($code) . 'ZA'; + + // Loop through 2 chars at once + for ($charIndex = 0; $charIndex < strlen($code); $charIndex += 2) { + if (! isset($chr[$code[$charIndex]]) || ! isset($chr[$code[$charIndex + 1]])) { + throw new InvalidCharacterException(); + } + + $drawBar = true; + $pbars = $chr[$code[$charIndex]]; + $pspaces = $chr[$code[$charIndex + 1]]; + $pmixed = ''; + + while (strlen($pbars) > 0) { + $pmixed .= $pbars[0] . $pspaces[0]; + $pbars = substr($pbars, 1); + $pspaces = substr($pspaces, 1); + } + + foreach (str_split($pmixed) as $width) { + $barcode->addBar(new BarcodeBar($width, 1, $drawBar)); + $drawBar = ! $drawBar; + } + } + + return $barcode; + } + + private function getChecksum(string $code): string + { + $total = 0; + + for ($charIndex = 0; $charIndex <= (strlen($code) - 1); $charIndex++) { + $integerOfChar = intval($code . substr($charIndex, 1)); + $total += $integerOfChar * (($charIndex === 0 || $charIndex % 2 === 0) ? 3 : 1); + } + + $checksum = 10 - ($total % 10); + if ($checksum === 10) { + $checksum = 0; + } + + return (string)$checksum; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeIntelligentMailBarcode.php b/vendor/picqer/php-barcode-generator/src/Types/TypeIntelligentMailBarcode.php new file mode 100644 index 0000000..e574cf7 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeIntelligentMailBarcode.php @@ -0,0 +1,571 @@ +
  • The Barcode Identifier shall be assigned by USPS to encode the + * presort identification that is currently printed in human readable form on the optional endorsement line (OEL) + * as well as for future USPS use. This shall be two digits, with the second digit in the range of 0–4. The + * allowable encoding ranges shall be 00–04, 10–14, 20–24, 30–34, 40–44, 50–54, 60–64, 70–74, 80–84, and + * 90–94.
  • The Service Type Identifier shall be assigned by USPS for any combination of services requested + * on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php–999. + * Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each + * service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier + * values.
  • The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digit number + * that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000- + * 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.
  • The + * Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The + * allowable encoding range shall be 000000000–999999999 when used with a 6 digit Mailer ID and 000000-999999 when + * used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the + * mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be + * 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000–99999, 000000000–999999999, + * and 00000000000–99999999999.
  • + * + * code to print, separate the ZIP (routing code) from the rest using a minus char '-' + * (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode) + */ + +class TypeIntelligentMailBarcode implements TypeInterface +{ + public function getBarcodeData(string $code): Barcode + { + $asc_chr = [ + 4, + 0, + 2, + 6, + 3, + 5, + 1, + 9, + 8, + 7, + 1, + 2, + 0, + 6, + 4, + 8, + 2, + 9, + 5, + 3, + 0, + 1, + 3, + 7, + 4, + 6, + 8, + 9, + 2, + 0, + 5, + 1, + 9, + 4, + 3, + 8, + 6, + 7, + 1, + 2, + 4, + 3, + 9, + 5, + 7, + 8, + 3, + 0, + 2, + 1, + 4, + 0, + 9, + 1, + 7, + 0, + 2, + 4, + 6, + 3, + 7, + 1, + 9, + 5, + 8 + ]; + $dsc_chr = [ + 7, + 1, + 9, + 5, + 8, + 0, + 2, + 4, + 6, + 3, + 5, + 8, + 9, + 7, + 3, + 0, + 6, + 1, + 7, + 4, + 6, + 8, + 9, + 2, + 5, + 1, + 7, + 5, + 4, + 3, + 8, + 7, + 6, + 0, + 2, + 5, + 4, + 9, + 3, + 0, + 1, + 6, + 8, + 2, + 0, + 4, + 5, + 9, + 6, + 7, + 5, + 2, + 6, + 3, + 8, + 5, + 1, + 9, + 8, + 7, + 4, + 0, + 2, + 6, + 3 + ]; + $asc_pos = [ + 3, + 0, + 8, + 11, + 1, + 12, + 8, + 11, + 10, + 6, + 4, + 12, + 2, + 7, + 9, + 6, + 7, + 9, + 2, + 8, + 4, + 0, + 12, + 7, + 10, + 9, + 0, + 7, + 10, + 5, + 7, + 9, + 6, + 8, + 2, + 12, + 1, + 4, + 2, + 0, + 1, + 5, + 4, + 6, + 12, + 1, + 0, + 9, + 4, + 7, + 5, + 10, + 2, + 6, + 9, + 11, + 2, + 12, + 6, + 7, + 5, + 11, + 0, + 3, + 2 + ]; + $dsc_pos = [ + 2, + 10, + 12, + 5, + 9, + 1, + 5, + 4, + 3, + 9, + 11, + 5, + 10, + 1, + 6, + 3, + 4, + 1, + 10, + 0, + 2, + 11, + 8, + 6, + 1, + 12, + 3, + 8, + 6, + 4, + 4, + 11, + 0, + 6, + 1, + 9, + 11, + 5, + 3, + 7, + 3, + 10, + 7, + 11, + 8, + 2, + 10, + 3, + 5, + 8, + 0, + 3, + 12, + 11, + 8, + 4, + 5, + 1, + 3, + 0, + 7, + 12, + 9, + 8, + 10 + ]; + $code_arr = explode('-', $code); + $tracking_number = $code_arr[0]; + if (isset($code_arr[1])) { + $routing_code = $code_arr[1]; + } else { + $routing_code = ''; + } + // Conversion of Routing Code + switch (strlen($routing_code)) { + case 0: + $binary_code = 0; + break; + + case 5: + $binary_code = bcadd($routing_code, '1'); + break; + + case 9: + $binary_code = bcadd($routing_code, '100001'); + break; + + case 11: + $binary_code = bcadd($routing_code, '1000100001'); + break; + + default: + throw new BarcodeException('Routing code unknown'); + } + + $binary_code = bcmul($binary_code, 10); + $binary_code = bcadd($binary_code, $tracking_number[0]); + $binary_code = bcmul($binary_code, 5); + $binary_code = bcadd($binary_code, $tracking_number[1]); + $binary_code .= substr($tracking_number, 2, 18); + + // convert to hexadecimal + $binary_code = $this->dec_to_hex($binary_code); + + // pad to get 13 bytes + $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT); + + // convert string to array of bytes + $binary_code_arr = chunk_split($binary_code, 2, "\r"); + $binary_code_arr = substr($binary_code_arr, 0, -1); + $binary_code_arr = explode("\r", $binary_code_arr); + + // calculate frame check sequence + $fcs = $this->imb_crc11fcs($binary_code_arr); + + // exclude first 2 bits from first byte + $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2)); + $binary_code_102bit = $first_byte . substr($binary_code, 2); + + // convert binary data to codewords + $codewords = []; + $data = $this->hex_to_dec($binary_code_102bit); + $codewords[0] = bcmod($data, 636) * 2; + $data = bcdiv($data, 636); + for ($i = 1; $i < 9; ++$i) { + $codewords[$i] = bcmod($data, 1365); + $data = bcdiv($data, 1365); + } + $codewords[9] = $data; + if (($fcs >> 10) == 1) { + $codewords[9] += 659; + } + + // generate lookup tables + $table2of13 = $this->imb_tables(2, 78); + $table5of13 = $this->imb_tables(5, 1287); + + // convert codewords to characters + $characters = []; + $bitmask = 512; + foreach ($codewords as $val) { + if ($val <= 1286) { + $chrcode = (int)$table5of13[$val]; + } else { + $chrcode = (int)$table2of13[($val - 1287)]; + } + if (($fcs & $bitmask) > 0) { + // bitwise invert + $chrcode = ((~$chrcode) & 8191); + } + $characters[] = $chrcode; + $bitmask /= 2; + } + $characters = array_reverse($characters); + + // build bars + $barcode = new Barcode($code); + for ($i = 0; $i < 65; ++$i) { + $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0); + $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0); + if ($asc AND $dsc) { + // full bar (F) + $p = 0; + $h = 3; + } elseif ($asc) { + // ascender (A) + $p = 0; + $h = 2; + } elseif ($dsc) { + // descender (D) + $p = 1; + $h = 2; + } else { + // tracker (T) + $p = 1; + $h = 1; + } + $barcode->addBar(new BarcodeBar(1, $h, true, $p)); + if ($i < 64) { + $barcode->addBar(new BarcodeBar(1, 2, false, 0)); + } + } + + return $barcode; + } + + /** + * Convert large integer number to hexadecimal representation. + * (requires PHP bcmath extension) + * + * @param $number (string) number to convert specified as a string + * @return string hexadecimal representation + */ + protected function dec_to_hex($number) + { + if ($number == 0) { + return '00'; + } + + $hex = []; + + while ($number > 0) { + array_push($hex, strtoupper(dechex(bcmod($number, '16')))); + $number = bcdiv($number, '16', 0); + } + $hex = array_reverse($hex); + + return implode($hex); + } + + + /** + * Intelligent Mail Barcode calculation of Frame Check Sequence + * + * @param $code_arr (string) array of hexadecimal values (13 bytes holding 102 bits right justified). + * @return int 11 bit Frame Check Sequence as integer (decimal base) + * @protected + */ + protected function imb_crc11fcs($code_arr) + { + $genpoly = 0x0F35; // generator polynomial + $fcs = 0x07FF; // Frame Check Sequence + // do most significant byte skipping the 2 most significant bits + $data = hexdec($code_arr[0]) << 5; + for ($bit = 2; $bit < 8; ++$bit) { + if (($fcs ^ $data) & 0x400) { + $fcs = ($fcs << 1) ^ $genpoly; + } else { + $fcs = ($fcs << 1); + } + $fcs &= 0x7FF; + $data <<= 1; + } + // do rest of bytes + for ($byte = 1; $byte < 13; ++$byte) { + $data = hexdec($code_arr[$byte]) << 3; + for ($bit = 0; $bit < 8; ++$bit) { + if (($fcs ^ $data) & 0x400) { + $fcs = ($fcs << 1) ^ $genpoly; + } else { + $fcs = ($fcs << 1); + } + $fcs &= 0x7FF; + $data <<= 1; + } + } + + return $fcs; + } + + /** + * Convert large hexadecimal number to decimal representation (string). + * (requires PHP bcmath extension) + * + * @param $hex (string) hexadecimal number to convert specified as a string + * @return string hexadecimal representation + */ + protected function hex_to_dec($hex) + { + $dec = 0; + $bitval = 1; + $len = strlen($hex); + for ($pos = ($len - 1); $pos >= 0; --$pos) { + $dec = bcadd($dec, bcmul(hexdec($hex[$pos]), $bitval)); + $bitval = bcmul($bitval, 16); + } + + return $dec; + } + + + /** + * generate Nof13 tables used for Intelligent Mail Barcode + * + * @param $n (int) is the type of table: 2 for 2of13 table, 5 for 5of13table + * @param $size (int) size of table (78 for n=2 and 1287 for n=5) + * @return array requested table + * @protected + */ + protected function imb_tables(int $n, int $size): array + { + $table = []; + $lli = 0; // LUT lower index + $lui = $size - 1; // LUT upper index + for ($count = 0; $count < 8192; ++$count) { + $bit_count = 0; + for ($bit_index = 0; $bit_index < 13; ++$bit_index) { + $bit_count += intval(($count & (1 << $bit_index)) != 0); + } + // if we don't have the right number of bits on, go on to the next value + if ($bit_count == $n) { + $reverse = ($this->imb_reverse_us($count) >> 3); + // if the reverse is less than count, we have already visited this pair before + if ($reverse >= $count) { + // If count is symmetric, place it at the first free slot from the end of the list. + // Otherwise, place it at the first free slot from the beginning of the list AND place $reverse ath the next free slot from the beginning of the list + if ($reverse == $count) { + $table[$lui] = $count; + --$lui; + } else { + $table[$lli] = $count; + ++$lli; + $table[$lli] = $reverse; + ++$lli; + } + } + } + } + + return $table; + } + + /** + * Reverse unsigned short value + * + * @param $num (int) value to reversr + * @return int reversed value + * @protected + */ + protected function imb_reverse_us($num) + { + $rev = 0; + for ($i = 0; $i < 16; ++$i) { + $rev <<= 1; + $rev |= ($num & 1); + $num >>= 1; + } + + return $rev; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeInterface.php b/vendor/picqer/php-barcode-generator/src/Types/TypeInterface.php new file mode 100644 index 0000000..f380c38 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeInterface.php @@ -0,0 +1,10 @@ +getChecksum($code); + + if ((strlen($code) % 2) != 0) { + // add leading zero if code-length is odd + $code = '0' . $code; + } + + // add start and stop codes + $code = 'AA' . strtolower($code) . 'ZA'; + + $barcode = new Barcode($code); + for ($i = 0; $i < strlen($code); $i = ($i + 2)) { + $char_bar = $code[$i]; + $char_space = $code[$i + 1]; + if (! isset($chr[$char_bar]) || ! isset($chr[$char_space])) { + throw new InvalidCharacterException(); + } + + // create a bar-space sequence + $seq = ''; + $chrlen = strlen($chr[$char_bar]); + for ($s = 0; $s < $chrlen; $s++) { + $seq .= $chr[$char_bar][$s] . $chr[$char_space][$s]; + } + + for ($j = 0; $j < strlen($seq); ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq[$j]; + $barcode->addBar(new BarcodeBar($w, 1, $t)); + } + } + + return $barcode; + } + + protected function getChecksum(string $code): string + { + $len = strlen($code); + $sum = 0; + for ($i = 0; $i < $len; $i += 2) { + $sum += $code[$i]; + } + $sum *= 3; + for ($i = 1; $i < $len; $i += 2) { + $sum += ($code[$i]); + } + $r = $sum % 10; + if ($r > 0) { + $r = (10 - $r); + } + + return (string)$r; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeKix.php b/vendor/picqer/php-barcode-generator/src/Types/TypeKix.php new file mode 100644 index 0000000..08595a5 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeKix.php @@ -0,0 +1,16 @@ +checksum) { + // add checksum + $clen = strlen($code); + $p = 2; + $check = 0; + for ($i = ($clen - 1); $i >= 0; --$i) { + $check += (hexdec($code[$i]) * $p); + ++$p; + if ($p > 7) { + $p = 2; + } + } + $check %= 11; + if ($check > 0) { + $check = 11 - $check; + } + $code .= $check; + } + $seq = '110'; // left guard + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $digit = $code[$i]; + if (! isset($chr[$digit])) { + throw new InvalidCharacterException('Char ' . $digit . ' is unsupported'); + } + $seq .= $chr[$digit]; + } + $seq .= '1001'; // right guard + + return BinarySequenceConverter::convert($code, $seq); + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypePharmacode.php b/vendor/picqer/php-barcode-generator/src/Types/TypePharmacode.php new file mode 100644 index 0000000..5f1f128 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypePharmacode.php @@ -0,0 +1,36 @@ + 0) { + if (($code % 2) == 0) { + $seq .= '11100'; + $code -= 2; + } else { + $seq .= '100'; + $code -= 1; + } + $code /= 2; + } + + $seq = substr($seq, 0, -2); + $seq = strrev($seq); + + return BinarySequenceConverter::convert($code, $seq); + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypePharmacodeTwoCode.php b/vendor/picqer/php-barcode-generator/src/Types/TypePharmacodeTwoCode.php new file mode 100644 index 0000000..3d7c2fa --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypePharmacodeTwoCode.php @@ -0,0 +1,80 @@ +addBar(new BarcodeBar(1, $h, 1, $p)); + if ($i < (strlen($seq) - 1)) { + $barcode->addBar(new BarcodeBar(1, 2, 0, 0)); + } + } + + return $barcode; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypePlanet.php b/vendor/picqer/php-barcode-generator/src/Types/TypePlanet.php new file mode 100644 index 0000000..0752386 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypePlanet.php @@ -0,0 +1,28 @@ + [1, 1, 2, 2, 2], + 1 => [2, 2, 2, 1, 1], + 2 => [2, 2, 1, 2, 1], + 3 => [2, 2, 1, 1, 2], + 4 => [2, 1, 2, 2, 1], + 5 => [2, 1, 2, 1, 2], + 6 => [2, 1, 1, 2, 2], + 7 => [1, 2, 2, 2, 1], + 8 => [1, 2, 2, 1, 2], + 9 => [1, 2, 1, 2, 2] + ]; +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypePostnet.php b/vendor/picqer/php-barcode-generator/src/Types/TypePostnet.php new file mode 100644 index 0000000..1f99ae2 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypePostnet.php @@ -0,0 +1,69 @@ + [2, 2, 1, 1, 1], + 1 => [1, 1, 1, 2, 2], + 2 => [1, 1, 2, 1, 2], + 3 => [1, 1, 2, 2, 1], + 4 => [1, 2, 1, 1, 2], + 5 => [1, 2, 1, 2, 1], + 6 => [1, 2, 2, 1, 1], + 7 => [2, 1, 1, 1, 2], + 8 => [2, 1, 1, 2, 1], + 9 => [2, 1, 2, 1, 1] + ]; + + public function getBarcodeData(string $code): Barcode + { + $code = str_replace(['-', ' '], '', $code); + $len = strlen($code); + + $barcode = new Barcode($code); + + // calculate checksum + $sum = 0; + for ($i = 0; $i < $len; ++$i) { + $sum += intval($code[$i]); + } + $chkd = ($sum % 10); + if ($chkd > 0) { + $chkd = (10 - $chkd); + } + $code .= $chkd; + $len = strlen($code); + + // start bar + $barcode->addBar(new BarcodeBar(1, 2, 1)); + $barcode->addBar(new BarcodeBar(1, 2, 0)); + + for ($i = 0; $i < $len; ++$i) { + for ($j = 0; $j < 5; ++$j) { + $h = $this->barlen[$code[$i]][$j]; + $p = floor(1 / $h); + $barcode->addBar(new BarcodeBar(1, $h, 1, $p)); + $barcode->addBar(new BarcodeBar(1, 2, 0)); + } + } + + // end bar + $barcode->addBar(new BarcodeBar(1, 2, 1)); + + return $barcode; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeRms4cc.php b/vendor/picqer/php-barcode-generator/src/Types/TypeRms4cc.php new file mode 100644 index 0000000..c728bcb --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeRms4cc.php @@ -0,0 +1,165 @@ + [3, 3, 2, 2], + '1' => [3, 4, 1, 2], + '2' => [3, 4, 2, 1], + '3' => [4, 3, 1, 2], + '4' => [4, 3, 2, 1], + '5' => [4, 4, 1, 1], + '6' => [3, 1, 4, 2], + '7' => [3, 2, 3, 2], + '8' => [3, 2, 4, 1], + '9' => [4, 1, 3, 2], + 'A' => [4, 1, 4, 1], + 'B' => [4, 2, 3, 1], + 'C' => [3, 1, 2, 4], + 'D' => [3, 2, 1, 4], + 'E' => [3, 2, 2, 3], + 'F' => [4, 1, 1, 4], + 'G' => [4, 1, 2, 3], + 'H' => [4, 2, 1, 3], + 'I' => [1, 3, 4, 2], + 'J' => [1, 4, 3, 2], + 'K' => [1, 4, 4, 1], + 'L' => [2, 3, 3, 2], + 'M' => [2, 3, 4, 1], + 'N' => [2, 4, 3, 1], + 'O' => [1, 3, 2, 4], + 'P' => [1, 4, 1, 4], + 'Q' => [1, 4, 2, 3], + 'R' => [2, 3, 1, 4], + 'S' => [2, 3, 2, 3], + 'T' => [2, 4, 1, 3], + 'U' => [1, 1, 4, 4], + 'V' => [1, 2, 3, 4], + 'W' => [1, 2, 4, 3], + 'X' => [2, 1, 3, 4], + 'Y' => [2, 1, 4, 3], + 'Z' => [2, 2, 3, 3] + ]; + + $code = strtoupper($code); + $len = strlen($code); + + $barcode = new Barcode($code); + + if (! $this->kix) { + // table for checksum calculation (row,col) + $checktable = [ + '0' => [1, 1], + '1' => [1, 2], + '2' => [1, 3], + '3' => [1, 4], + '4' => [1, 5], + '5' => [1, 0], + '6' => [2, 1], + '7' => [2, 2], + '8' => [2, 3], + '9' => [2, 4], + 'A' => [2, 5], + 'B' => [2, 0], + 'C' => [3, 1], + 'D' => [3, 2], + 'E' => [3, 3], + 'F' => [3, 4], + 'G' => [3, 5], + 'H' => [3, 0], + 'I' => [4, 1], + 'J' => [4, 2], + 'K' => [4, 3], + 'L' => [4, 4], + 'M' => [4, 5], + 'N' => [4, 0], + 'O' => [5, 1], + 'P' => [5, 2], + 'Q' => [5, 3], + 'R' => [5, 4], + 'S' => [5, 5], + 'T' => [5, 0], + 'U' => [0, 1], + 'V' => [0, 2], + 'W' => [0, 3], + 'X' => [0, 4], + 'Y' => [0, 5], + 'Z' => [0, 0] + ]; + + $row = 0; + $col = 0; + for ($i = 0; $i < $len; ++$i) { + $row += $checktable[$code[$i]][0]; + $col += $checktable[$code[$i]][1]; + } + $row %= 6; + $col %= 6; + $chk = array_keys($checktable, [$row, $col]); + $code .= $chk[0]; + ++$len; + + // start bar + $barcode->addBar(new BarcodeBar(1, 2, 1)); + $barcode->addBar(new BarcodeBar(1, 2, 0)); + } + + for ($i = 0; $i < $len; ++$i) { + for ($j = 0; $j < 4; ++$j) { + switch ($barmode[$code[$i]][$j]) { + case 1: + $p = 0; + $h = 2; + break; + + case 2: + $p = 0; + $h = 3; + break; + + case 3: + $p = 1; + $h = 1; + break; + + case 4: + $p = 1; + $h = 2; + break; + } + + $barcode->addBar(new BarcodeBar(1, $h, 1, $p)); + $barcode->addBar(new BarcodeBar(1, 2, 0)); + } + } + + if (! $this->kix) { + // stop bar + $barcode->addBar(new BarcodeBar(1, 3, 1)); + } + + return $barcode; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeStandard2of5.php b/vendor/picqer/php-barcode-generator/src/Types/TypeStandard2of5.php new file mode 100644 index 0000000..592f59a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeStandard2of5.php @@ -0,0 +1,74 @@ +checksum) { + // add checksum + $code .= $this->checksum_s25($code); + } + $seq = '11011010'; + + for ($i = 0; $i < strlen($code); ++$i) { + $digit = $code[$i]; + if (! isset($chr[$digit])) { + throw new InvalidCharacterException('Char ' . $digit . ' is unsupported'); + } + $seq .= $chr[$digit]; + } + $seq .= '1101011'; + + return BinarySequenceConverter::convert($code, $seq); + } + + /** + * Checksum for standard 2 of 5 barcodes. + * + * @param $code (string) code to process. + * @return int checksum. + * @protected + */ + protected function checksum_s25($code) + { + $len = strlen($code); + $sum = 0; + for ($i = 0; $i < $len; $i += 2) { + $sum += $code[$i]; + } + $sum *= 3; + for ($i = 1; $i < $len; $i += 2) { + $sum += ($code[$i]); + } + $r = $sum % 10; + if ($r > 0) { + $r = (10 - $r); + } + + return $r; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeStandard2of5Checksum.php b/vendor/picqer/php-barcode-generator/src/Types/TypeStandard2of5Checksum.php new file mode 100644 index 0000000..25bc4a0 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeStandard2of5Checksum.php @@ -0,0 +1,14 @@ + + * from Java implementation of Telepen by Robin Stuart + * at https://github.com/woo-j/OkapiBarcode which uses the + * Apache License 2.0 http://www.apache.org/licenses/LICENSE-2.0 + * + * Implements Telepen (also known as Telepen Alpha), and Telepen Numeric. + * + * Telepen can encode ASCII text input and includes a modulo-127 check digit. + * Telepen Numeric allows compression of numeric data into a Telepen symbol. Data + * can consist of pairs of numbers or pairs consisting of a numerical digit followed + * by an X character. Telepen Numeric also includes a mod-127 check digit. + */ + +namespace Picqer\Barcode\Types; + +use Picqer\Barcode\Barcode; +use Picqer\Barcode\BarcodeBar; +use Picqer\Barcode\Exceptions\InvalidFormatException; + +class TypeTelepen implements TypeInterface +{ + private const TELEPEN_START_CHAR = '_'; + private const TELEPEN_STOP_CHAR = 'z'; + private const TELEPEN_ALPHA = 'alpha'; + private const TELEPEN_NUMERIC = 'numeric'; + + private $telepen_lookup_table; + private $mode; + + public function __construct($m = 'alpha') + { + $this->mode = self::TELEPEN_ALPHA; + if (strtolower($m) == 'numeric') { + $this->mode = self::TELEPEN_NUMERIC; + } + $this->createTelepenConversionTable(); + } + + public function getBarcodeData(string $code): Barcode + { + /* The stream we get from the telepen output gives us the + * width of alternating black/white stripes + */ + + $encoded = $this->encode($code); //binary string + $barcode = new Barcode($code); + + $drawBar = true; + for ($i = 0; $i < strlen($encoded); ++$i) { + $barWidth = $encoded[$i]; + $barcode->addBar(new BarcodeBar($barWidth, 250, $drawBar)); + $drawBar = !$drawBar; //flip to other colour + } + + return $barcode; + } + + protected function encode($code) : string + { + $result = null; + if ($this->mode == self::TELEPEN_ALPHA) { + $result = $this->encodeAlpha($code); + } else { + $result = $this->encodeNumeric($code); + } + + return $result; + } + + protected function encodeAlpha($code) : string + { + // We aren't interested in the non-printable parts of the ASCII set + if ( + !preg_match('/[ -~]+/', $code) + ) { // everything from ASCII32-ASCII127 + throw new InvalidFormatException("Invalid characters in data"); + } + + $count = 0; + + /* other implementations use the byte-chr-int type equivalence to work + * with array indices in the conversion/lookup table. It's probably + * better to be more explicit with php, hence the use of ord and chr here. + */ + + // begin with start char + $dest = $this->telepen_lookup_table[ord(self::TELEPEN_START_CHAR)]; + + for ($i = 0; $i < strlen($code); $i++) { + //$ascii_code = ord(substr($code, $i, 1)); + $ascii_code = ord($code[$i]); + $dest .= ($this->telepen_lookup_table[$ascii_code]); + $count += $ascii_code; + } + + // Now add check and terminator + $check_digit = 127 - ($count % 127); + if ($check_digit == 127) { + $check_digit = 0; + } + + $dest .= $this->telepen_lookup_table[ord($check_digit)]; + $dest .= $this->telepen_lookup_table[ord(self::TELEPEN_STOP_CHAR)]; // Stop + + return $dest; + } + + private function encodeNumeric(string $code) : string + { + + /* If input contains non-numeric or X, exit */ + if (!preg_match('/^[0-9X]+$/', $code)) { + throw new InvalidFormatException("Invalid characters in data"); + } + + /* If input is an odd length, exit */ + $t = ''; + if (strlen($code) % 2 > 0) { + throw new InvalidFormatException("There must be an even number of digits"); + } + + $count = 0; + $dest = $this->telepen_lookup_table[ord(self::TELEPEN_START_CHAR)]; // begin with the start character _ + + for ($i = 0; $i < strlen($code); $i += 2) { + $c1 = $code[$i]; + $c2 = $code[$i+1]; + /* Input nX is allowed, but Xn is not */ + if ($c1 == 'X') { + throw new InvalidFormatException("Invalid position of X in data"); + } + $glyph = null; + if ($c2 == 'X') { + $glyph = (ord($c1) - ord('0')) + 17; + } else { + $glyph = ((10 * (ord($c1) - ord('0'))) + (ord($c2) - ord('0'))) + 27; + } + $count += $glyph; + $dest .= $this->telepen_lookup_table[$glyph]; + } + + $check_digit = 127 - ($count % 127); + if ($check_digit == 127) { + $check_digit = 0; + } + + $dest .= $this->telepen_lookup_table[$check_digit]; + $dest .= $this->telepen_lookup_table[ord(self::TELEPEN_STOP_CHAR)]; // Stop + + return $dest; + } + + /** + * The table provides a representation of barcode patterns + * for each character in the ASCII set. from ASCII0-127 + * Each barcode starts with "_" - ASCII95 0x5F, + * and ends with "z" - ASCII122 0xFA. + * More information about Telepen symbology is available from + * https://v4l237.n3cdn1.secureserver.net/wp-content/uploads/2022/05/Barcode-Symbology-information-and-History.pdf + */ + private function createTelepenConversionTable() + { + $this->telepen_lookup_table = [ + "1111111111111111", "1131313111", "33313111", "1111313131", + "3111313111", "11333131", "13133131", "111111313111", + "31333111", "1131113131", "33113131", "1111333111", + "3111113131", "1113133111", "1311133111", "111111113131", + "3131113111", "11313331", "333331", "111131113111", + "31113331", "1133113111", "1313113111", "1111113331", + "31131331", "113111113111", "3311113111", "1111131331", + "311111113111", "1113111331", "1311111331", "11111111113111", + "31313311", "1131311131", "33311131", "1111313311", + "3111311131", "11333311", "13133311", "111111311131", + "31331131", "1131113311", "33113311", "1111331131", + "3111113311", "1113131131", "1311131131", "111111113311", + "3131111131", "1131131311", "33131311", "111131111131", + "3111131311", "1133111131", "1313111131", "111111131311", + "3113111311", "113111111131", "3311111131", "111113111311", + "311111111131", "111311111311", "131111111311", "11111111111131", + "3131311111", "11313133", "333133", "111131311111", + "31113133", "1133311111", "1313311111", "1111113133", + "313333", "113111311111", "3311311111", "11113333", + "311111311111", "11131333", "13111333", "11111111311111", + "31311133", "1131331111", "33331111", "1111311133", + "3111331111", "11331133", "13131133", "111111331111", + "3113131111", "1131111133", "33111133", "111113131111", + "3111111133", "111311131111", "131111131111", "111111111133", + "31311313", "113131111111", "3331111111", "1111311313", + "311131111111", "11331313", "13131313", "11111131111111", + "3133111111", "1131111313", "33111313", "111133111111", + "3111111313", "111313111111", "131113111111", "111111111313", + "313111111111", "1131131113", "33131113", "11113111111111", + "3111131113", "113311111111", "131311111111", "111111131113", + "3113111113", "11311111111111", "331111111111", "111113111113", + "31111111111111", "111311111113", "131111111113" + ]; + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeUpcA.php b/vendor/picqer/php-barcode-generator/src/Types/TypeUpcA.php new file mode 100644 index 0000000..11d45b9 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeUpcA.php @@ -0,0 +1,20 @@ +length; + + // Padding + $code = str_pad($code, $len, '0', STR_PAD_LEFT); + + // Calculate check digit + if ($len == 2) { + $r = $code % 4; + } elseif ($len == 5) { + $r = (3 * intval($code[0] . $code[2] . $code[4])) + (9 * intval($code[1] . $code[3])); + $r %= 10; + } else { + throw new InvalidCheckDigitException(); + } + + // Convert digits to bars + $codes = [ + 'A' => [ // left odd parity + '0' => '0001101', + '1' => '0011001', + '2' => '0010011', + '3' => '0111101', + '4' => '0100011', + '5' => '0110001', + '6' => '0101111', + '7' => '0111011', + '8' => '0110111', + '9' => '0001011' + ], + 'B' => [ // left even parity + '0' => '0100111', + '1' => '0110011', + '2' => '0011011', + '3' => '0100001', + '4' => '0011101', + '5' => '0111001', + '6' => '0000101', + '7' => '0010001', + '8' => '0001001', + '9' => '0010111' + ] + ]; + + $parities = [ + 2 =>[ + '0' => ['A', 'A'], + '1' => ['A', 'B'], + '2' => ['B', 'A'], + '3' => ['B', 'B'] + ], + 5 => [ + '0' => ['B', 'B', 'A', 'A', 'A'], + '1' => ['B', 'A', 'B', 'A', 'A'], + '2' => ['B', 'A', 'A', 'B', 'A'], + '3' => ['B', 'A', 'A', 'A', 'B'], + '4' => ['A', 'B', 'B', 'A', 'A'], + '5' => ['A', 'A', 'B', 'B', 'A'], + '6' => ['A', 'A', 'A', 'B', 'B'], + '7' => ['A', 'B', 'A', 'B', 'A'], + '8' => ['A', 'B', 'A', 'A', 'B'], + '9' => ['A', 'A', 'B', 'A', 'B'] + ] + ]; + + $p = $parities[$len][$r]; + $seq = '1011'; // left guard bar + $seq .= $codes[$p[0]][$code[0]]; + for ($i = 1; $i < $len; ++$i) { + $seq .= '01'; // separator + $seq .= $codes[$p[$i]][$code[$i]]; + } + + return BinarySequenceConverter::convert($code, $seq); + } +} diff --git a/vendor/picqer/php-barcode-generator/src/Types/TypeUpcExtension5.php b/vendor/picqer/php-barcode-generator/src/Types/TypeUpcExtension5.php new file mode 100644 index 0000000..b1d3424 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/src/Types/TypeUpcExtension5.php @@ -0,0 +1,14 @@ +getBarcode('081231723897', $generator::TYPE_CODE_128); + + $this->assertStringEqualsFile('tests/verified-files/081231723897-dynamic-code128.html', $generated); + } + + public function test_dynamic_html_barcode_generator_can_generate_imb_barcode_to_test_heights() + { + $generator = new Picqer\Barcode\BarcodeGeneratorDynamicHTML(); + $generated = $generator->getBarcode('12345678903', $generator::TYPE_IMB); + + $this->assertStringEqualsFile('tests/verified-files/12345678903-dynamic-imb.html', $generated); + } +} diff --git a/vendor/picqer/php-barcode-generator/tests/BarcodeHtmlTest.php b/vendor/picqer/php-barcode-generator/tests/BarcodeHtmlTest.php new file mode 100644 index 0000000..ecdf617 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/BarcodeHtmlTest.php @@ -0,0 +1,22 @@ +getBarcode('081231723897', $generator::TYPE_CODE_128); + + $this->assertStringEqualsFile('tests/verified-files/081231723897-code128.html', $generated); + } + + public function test_html_barcode_generator_can_generate_imb_barcode_to_test_heights() + { + $generator = new Picqer\Barcode\BarcodeGeneratorHTML(); + $generated = $generator->getBarcode('12345678903', $generator::TYPE_IMB); + + $this->assertStringEqualsFile('tests/verified-files/12345678903-imb.html', $generated); + } +} diff --git a/vendor/picqer/php-barcode-generator/tests/BarcodeJpgTest.php b/vendor/picqer/php-barcode-generator/tests/BarcodeJpgTest.php new file mode 100644 index 0000000..d597f4a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/BarcodeJpgTest.php @@ -0,0 +1,135 @@ +useGd(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(202, $imageInfo[0]); // Image width + $this->assertEquals(30, $imageInfo[1]); // Image height + $this->assertEquals('image/jpeg', $imageInfo['mime']); + } + + public function test_jpg_barcode_generator_can_generate_code_39_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorJPG(); + $generator->useGd(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_39, 1); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(224, $imageInfo[0]); // Image width + $this->assertEquals(30, $imageInfo[1]); // Image height + $this->assertEquals('image/jpeg', $imageInfo['mime']); + } + + public function test_jpg_barcode_generator_can_use_different_height() + { + $generator = new Picqer\Barcode\BarcodeGeneratorJPG(); + $generator->useGd(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128, 2, 45); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(202, $imageInfo[0]); // Image width + $this->assertEquals(45, $imageInfo[1]); // Image height + $this->assertEquals('image/jpeg', $imageInfo['mime']); + } + + public function test_jpg_barcode_generator_can_use_different_width_factor() + { + $generator = new Picqer\Barcode\BarcodeGeneratorJPG(); + $generator->useGd(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128, 5); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(505, $imageInfo[0]); // Image width + $this->assertEquals('image/jpeg', $imageInfo['mime']); + } + + + // Copied as Imagick + + public function test_jpg_barcode_generator_can_generate_code_128_barcode_imagick() + { + if (! extension_loaded('imagick')) { + $this->markTestSkipped(); + } + + $generator = new Picqer\Barcode\BarcodeGeneratorJPG(); + $generator->useImagick(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(202, $imageInfo[0]); // Image width + $this->assertEquals(30, $imageInfo[1]); // Image height + $this->assertEquals('image/jpeg', $imageInfo['mime']); + } + + public function test_jpg_barcode_generator_can_generate_code_39_barcode_imagick() + { + if (! extension_loaded('imagick')) { + $this->markTestSkipped(); + } + + $generator = new Picqer\Barcode\BarcodeGeneratorJPG(); + $generator->useImagick(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_39, 1); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(224, $imageInfo[0]); // Image width + $this->assertEquals(30, $imageInfo[1]); // Image height + $this->assertEquals('image/jpeg', $imageInfo['mime']); + } + + public function test_jpg_barcode_generator_can_use_different_height_imagick() + { + if (! extension_loaded('imagick')) { + $this->markTestSkipped(); + } + + $generator = new Picqer\Barcode\BarcodeGeneratorJPG(); + $generator->useImagick(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128, 2, 45); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(202, $imageInfo[0]); // Image width + $this->assertEquals(45, $imageInfo[1]); // Image height + $this->assertEquals('image/jpeg', $imageInfo['mime']); + } + + public function test_jpg_barcode_generator_can_use_different_width_factor_imagick() + { + if (! extension_loaded('imagick')) { + $this->markTestSkipped(); + } + + $generator = new Picqer\Barcode\BarcodeGeneratorJPG(); + $generator->useImagick(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128, 5); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(505, $imageInfo[0]); // Image width + $this->assertEquals('image/jpeg', $imageInfo['mime']); + } +} diff --git a/vendor/picqer/php-barcode-generator/tests/BarcodePngTest.php b/vendor/picqer/php-barcode-generator/tests/BarcodePngTest.php new file mode 100644 index 0000000..700baa2 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/BarcodePngTest.php @@ -0,0 +1,125 @@ +useGd(); + $generated = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128); + + $this->assertEquals('PNG', substr($generated, 1, 3)); + } + + public function test_png_barcode_generator_can_generate_code_39_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorPNG(); + $generator->useGd(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_39, 1); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(224, $imageInfo[0]); // Image width + $this->assertEquals(30, $imageInfo[1]); // Image height + $this->assertEquals('image/png', $imageInfo['mime']); + } + + public function test_png_barcode_generator_can_use_different_height() + { + $generator = new Picqer\Barcode\BarcodeGeneratorPNG(); + $generator->useGd(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128, 2, 45); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(202, $imageInfo[0]); // Image width + $this->assertEquals(45, $imageInfo[1]); // Image height + $this->assertEquals('image/png', $imageInfo['mime']); + } + + public function test_png_barcode_generator_can_use_different_width_factor() + { + $generator = new Picqer\Barcode\BarcodeGeneratorPNG(); + $generator->useGd(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128, 5); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(505, $imageInfo[0]); // Image width + $this->assertEquals('image/png', $imageInfo['mime']); + } + + + // Copied as Imagick + + public function test_png_barcode_generator_can_generate_code_128_barcode_imagick() + { + if (! extension_loaded('imagick')) { + $this->markTestSkipped(); + } + + $generator = new Picqer\Barcode\BarcodeGeneratorPNG(); + $generator->useImagick(); + $generated = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128); + + $this->assertEquals('PNG', substr($generated, 1, 3)); + } + + public function test_png_barcode_generator_can_generate_code_39_barcode_imagick() + { + if (! extension_loaded('imagick')) { + $this->markTestSkipped(); + } + + $generator = new Picqer\Barcode\BarcodeGeneratorPNG(); + $generator->useImagick(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_39, 1); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(224, $imageInfo[0]); // Image width + $this->assertEquals(30, $imageInfo[1]); // Image height + $this->assertEquals('image/png', $imageInfo['mime']); + } + + public function test_png_barcode_generator_can_use_different_height_imagick() + { + if (! extension_loaded('imagick')) { + $this->markTestSkipped(); + } + + $generator = new Picqer\Barcode\BarcodeGeneratorPNG(); + $generator->useImagick(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128, 2, 45); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(202, $imageInfo[0]); // Image width + $this->assertEquals(45, $imageInfo[1]); // Image height + $this->assertEquals('image/png', $imageInfo['mime']); + } + + public function test_png_barcode_generator_can_use_different_width_factor_imagick() + { + if (! extension_loaded('imagick')) { + $this->markTestSkipped(); + } + + $generator = new Picqer\Barcode\BarcodeGeneratorPNG(); + $generator->useImagick(); + $result = $generator->getBarcode('081231723897', $generator::TYPE_CODE_128, 5); + + $imageInfo = getimagesizefromstring($result); + + $this->assertGreaterThan(100, strlen($result)); + $this->assertEquals(505, $imageInfo[0]); // Image width + $this->assertEquals('image/png', $imageInfo['mime']); + } +} diff --git a/vendor/picqer/php-barcode-generator/tests/BarcodeSvgTest.php b/vendor/picqer/php-barcode-generator/tests/BarcodeSvgTest.php new file mode 100644 index 0000000..5a080ff --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/BarcodeSvgTest.php @@ -0,0 +1,22 @@ +getBarcode('081231723897', $generator::TYPE_EAN_13); + + $this->assertStringEqualsFile('tests/verified-files/081231723897-ean13.svg', $generated); + } + + public function test_svg_barcode_generator_can_generate_ean_13_barcode_with_fractional_width() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generated = $generator->getBarcode('081231723897', $generator::TYPE_EAN_13, 0.25, 25.75); + + $this->assertStringEqualsFile('tests/verified-files/081231723897-ean13-fractional-width.svg', $generated); + } +} diff --git a/vendor/picqer/php-barcode-generator/tests/GeneratorTest.php b/vendor/picqer/php-barcode-generator/tests/GeneratorTest.php new file mode 100644 index 0000000..293efc0 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/GeneratorTest.php @@ -0,0 +1,70 @@ +expectException(Picqer\Barcode\Exceptions\InvalidLengthException::class); + + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generator->getBarcode('', $generator::TYPE_EAN_13); + } + + public function test_throws_exception_if_empty_barcode_is_used_in_code128() + { + $this->expectException(Picqer\Barcode\Exceptions\InvalidLengthException::class); + + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generator->getBarcode('', $generator::TYPE_CODE_128); + } + + public function test_ean13_generator_throws_exception_if_invalid_chars_are_used() + { + $this->expectException(Picqer\Barcode\Exceptions\InvalidCharacterException::class); + + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generator->getBarcode('A123', $generator::TYPE_EAN_13); + } + + public function test_ean13_generator_accepting_13_chars() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generated = $generator->getBarcode('0049000004632', $generator::TYPE_EAN_13); + + $this->assertStringEqualsFile('tests/verified-files/0049000004632-ean13.svg', $generated); + } + + public function test_ean13_generator_accepting_12_chars_and_generates_13th_check_digit() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generated = $generator->getBarcode('004900000463', $generator::TYPE_EAN_13); + + $this->assertStringEqualsFile('tests/verified-files/0049000004632-ean13.svg', $generated); + } + + public function test_ean13_generator_accepting_11_chars_and_generates_13th_check_digit_and_adds_leading_zero() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generated = $generator->getBarcode('04900000463', $generator::TYPE_EAN_13); + + $this->assertStringEqualsFile('tests/verified-files/0049000004632-ean13.svg', $generated); + } + + public function test_ean13_generator_throws_exception_when_wrong_check_digit_is_given() + { + $this->expectException(Picqer\Barcode\Exceptions\InvalidCheckDigitException::class); + + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generator->getBarcode('0049000004633', $generator::TYPE_EAN_13); + } + + public function test_generator_throws_unknown_type_exceptions() + { + $this->expectException(Picqer\Barcode\Exceptions\UnknownTypeException::class); + + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $generator->getBarcode('0049000004633', 'vladimir'); + } +} \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/tests/PharmacodeTest.php b/vendor/picqer/php-barcode-generator/tests/PharmacodeTest.php new file mode 100644 index 0000000..c068ffb --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/PharmacodeTest.php @@ -0,0 +1,15 @@ +expectException(Picqer\Barcode\Exceptions\InvalidLengthException::class); + + $pharmacode->getBarcodeData('0'); + } +} diff --git a/vendor/picqer/php-barcode-generator/tests/TypesTest.php b/vendor/picqer/php-barcode-generator/tests/TypesTest.php new file mode 100644 index 0000000..aaca1ad --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/TypesTest.php @@ -0,0 +1,254 @@ +getBarcode('1234567890ABC', $generator::TYPE_CODE_39); + + $this->assertStringEqualsFile('tests/verified-files/C39-1234567890ABC.svg', $result); + } + + public function test_generator_can_generate_code_39_checksum_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890ABC', $generator::TYPE_CODE_39_CHECKSUM); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_code_39_extended_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890abcABC', $generator::TYPE_CODE_39E); + + $this->assertStringEqualsFile('tests/verified-files/C39E-1234567890abcABC.svg', $result); + } + + public function test_generator_can_generate_code_39_extended_checksum_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890abcABC', $generator::TYPE_CODE_39E_CHECKSUM); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_code_93_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890abcABC', $generator::TYPE_CODE_93); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_standard_2_5_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890', $generator::TYPE_STANDARD_2_5); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_standard_2_5_checksum_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890', $generator::TYPE_STANDARD_2_5_CHECKSUM); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_interleaved_2_5_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890', $generator::TYPE_INTERLEAVED_2_5); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_interleaved_2_5_checksum_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890', $generator::TYPE_INTERLEAVED_2_5_CHECKSUM); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_code_128_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890abcABC-283*33', $generator::TYPE_CODE_128); + + $this->assertStringEqualsFile('tests/verified-files/C128-1234567890abcABC-283-33.svg', $result); + } + + public function test_generator_can_generate_code_128_a_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890', $generator::TYPE_CODE_128_A); + + $this->assertStringEqualsFile('tests/verified-files/C128A-1234567890.svg', $result); + } + + public function test_generator_can_generate_code_128_b_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890abcABC-283*33', $generator::TYPE_CODE_128_B); + + $this->assertStringEqualsFile('tests/verified-files/C128B-1234567890abcABC-283-33.svg', $result); + } + + public function test_generator_can_generate_ean_2_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('22', $generator::TYPE_EAN_2); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_ean_5_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890abcABC-283*33', $generator::TYPE_EAN_5); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_ean_8_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234568', $generator::TYPE_EAN_8); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_ean_13_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890', $generator::TYPE_EAN_13); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_upc_a_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_UPC_A); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_upc_e_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_UPC_E); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_msi_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_MSI); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_msi_checksum_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_MSI_CHECKSUM); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_postnet_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_POSTNET); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_planet_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_PLANET); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_rms4cc_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_RMS4CC); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_kix_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_KIX); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_imb_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_IMB); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_codabar_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_CODABAR); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_code_11_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_CODE_11); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_pharma_code_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_PHARMA_CODE); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_pharma_code_2_tracks_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('123456789', $generator::TYPE_PHARMA_CODE_TWO_TRACKS); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_telepen_alpha_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890ASCD', $generator::TYPE_TELEPEN_ALPHA); + + $this->assertGreaterThan(100, strlen($result)); + } + + public function test_generator_can_generate_telepen_numeric_barcode() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + $result = $generator->getBarcode('1234567890', $generator::TYPE_TELEPEN_NUMERIC); + + $this->assertGreaterThan(100, strlen($result)); + } +} \ No newline at end of file diff --git a/vendor/picqer/php-barcode-generator/tests/VerifiedBarcodeTest.php b/vendor/picqer/php-barcode-generator/tests/VerifiedBarcodeTest.php new file mode 100644 index 0000000..bc7f9f4 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/VerifiedBarcodeTest.php @@ -0,0 +1,72 @@ + BarcodeGenerator::TYPE_CODE_39, 'barcodes' => ['1234567890ABC']], + ['type' => BarcodeGenerator::TYPE_CODE_39_CHECKSUM, 'barcodes' => ['1234567890ABC']], + ['type' => BarcodeGenerator::TYPE_CODE_39E, 'barcodes' => ['1234567890abcABC']], + ['type' => BarcodeGenerator::TYPE_CODE_39E_CHECKSUM, 'barcodes' => ['1234567890abcABC']], + ['type' => BarcodeGenerator::TYPE_CODE_93, 'barcodes' => ['1234567890abcABC']], + ['type' => BarcodeGenerator::TYPE_STANDARD_2_5, 'barcodes' => ['1234567890']], + ['type' => BarcodeGenerator::TYPE_STANDARD_2_5_CHECKSUM, 'barcodes' => ['1234567890']], + ['type' => BarcodeGenerator::TYPE_INTERLEAVED_2_5, 'barcodes' => ['1234567890']], + ['type' => BarcodeGenerator::TYPE_INTERLEAVED_2_5_CHECKSUM, 'barcodes' => ['1234567890']], + ['type' => BarcodeGenerator::TYPE_EAN_13, 'barcodes' => ['081231723897', '0049000004632', '004900000463']], + ['type' => BarcodeGenerator::TYPE_ITF_14, 'barcodes' => ['00012345600012', '05400141288766']], + ['type' => BarcodeGenerator::TYPE_CODE_128, 'barcodes' => ['081231723897', '1234567890abcABC-283*33']], + ['type' => BarcodeGenerator::TYPE_CODE_128_A, 'barcodes' => ['1234567890']], + ['type' => BarcodeGenerator::TYPE_CODE_128_B, 'barcodes' => ['081231723897', '1234567890abcABC-283*33']], + ['type' => BarcodeGenerator::TYPE_EAN_2, 'barcodes' => ['22']], + ['type' => BarcodeGenerator::TYPE_EAN_5, 'barcodes' => ['1234567890abcABC-283*33']], + ['type' => BarcodeGenerator::TYPE_EAN_8, 'barcodes' => ['1234568']], + ['type' => BarcodeGenerator::TYPE_UPC_A, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_UPC_E, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_MSI, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_MSI_CHECKSUM, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_POSTNET, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_PLANET, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_RMS4CC, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_KIX, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_IMB, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_CODABAR, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_CODE_11, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_PHARMA_CODE, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_PHARMA_CODE_TWO_TRACKS, 'barcodes' => ['123456789']], + ['type' => BarcodeGenerator::TYPE_TELEPEN_ALPHA, 'barcodes' => ['1234567890ASCD']], + ['type' => BarcodeGenerator::TYPE_TELEPEN_NUMERIC, 'barcodes' => ['1234567890']] + ]; + + public function testAllSupportedBarcodeTypes() + { + $generator = new Picqer\Barcode\BarcodeGeneratorSVG(); + + foreach ($this::$supportedBarcodes as $barcodeTestSet) { + foreach ($barcodeTestSet['barcodes'] as $barcode) { + $result = $generator->getBarcode($barcode, $barcodeTestSet['type']); + + $this->assertStringEqualsFile( + sprintf('tests/verified-files/%s.svg', $this->getSaveFilename($barcodeTestSet['type'] . '-' . $barcode)), + $result, + sprintf('%s x %s dynamic test failed', $barcodeTestSet['type'], $barcode) + ); + } + } + } + + protected function getSaveFilename($value) + { + return preg_replace('/[^a-zA-Z0-9_ \-+]/s', '-', $value); + } +} diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/0049000004632-ean13.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/0049000004632-ean13.svg new file mode 100644 index 0000000..427ff40 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/0049000004632-ean13.svg @@ -0,0 +1,37 @@ + + + + 0049000004632 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-code128.html b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-code128.html new file mode 100644 index 0000000..e9cf37a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-code128.html @@ -0,0 +1,30 @@ +
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
    diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-dynamic-code128.html b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-dynamic-code128.html new file mode 100644 index 0000000..cdf2d94 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-dynamic-code128.html @@ -0,0 +1,30 @@ +
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
    diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13-fractional-width.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13-fractional-width.svg new file mode 100644 index 0000000..d616490 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13-fractional-width.svg @@ -0,0 +1,37 @@ + + + + 0812317238973 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13.svg new file mode 100644 index 0000000..96e1619 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/081231723897-ean13.svg @@ -0,0 +1,37 @@ + + + + 0812317238973 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/12345678903-dynamic-imb.html b/vendor/picqer/php-barcode-generator/tests/verified-files/12345678903-dynamic-imb.html new file mode 100644 index 0000000..c06f1fb --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/12345678903-dynamic-imb.html @@ -0,0 +1,67 @@ +
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
    diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/12345678903-imb.html b/vendor/picqer/php-barcode-generator/tests/verified-files/12345678903-imb.html new file mode 100644 index 0000000..eba3400 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/12345678903-imb.html @@ -0,0 +1,67 @@ +
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
     
    +
    diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C128-081231723897.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C128-081231723897.svg new file mode 100644 index 0000000..64b544f --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C128-081231723897.svg @@ -0,0 +1,35 @@ + + + + 081231723897 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C128-1234567890abcABC-283-33.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C128-1234567890abcABC-283-33.svg new file mode 100644 index 0000000..4a3708a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C128-1234567890abcABC-283-33.svg @@ -0,0 +1,74 @@ + + + + 1234567890abcABC-283*33 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C128A-1234567890.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C128A-1234567890.svg new file mode 100644 index 0000000..22d2cf4 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C128A-1234567890.svg @@ -0,0 +1,47 @@ + + + + 1234567890 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C128B-081231723897.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C128B-081231723897.svg new file mode 100644 index 0000000..f3ee4e0 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C128B-081231723897.svg @@ -0,0 +1,53 @@ + + + + 081231723897 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C128B-1234567890abcABC-283-33.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C128B-1234567890abcABC-283-33.svg new file mode 100644 index 0000000..ec25033 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C128B-1234567890abcABC-283-33.svg @@ -0,0 +1,86 @@ + + + + 1234567890abcABC-283*33 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C39+-1234567890ABC.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C39+-1234567890ABC.svg new file mode 100644 index 0000000..280551a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C39+-1234567890ABC.svg @@ -0,0 +1,87 @@ + + + + *1234567890ABCZ* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C39-1234567890ABC.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C39-1234567890ABC.svg new file mode 100644 index 0000000..448792d --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C39-1234567890ABC.svg @@ -0,0 +1,82 @@ + + + + *1234567890ABC* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C39E+-1234567890abcABC.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C39E+-1234567890abcABC.svg new file mode 100644 index 0000000..a1a87c5 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C39E+-1234567890abcABC.svg @@ -0,0 +1,117 @@ + + + + *1234567890+A+B+CABCJ* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C39E-1234567890abcABC.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C39E-1234567890abcABC.svg new file mode 100644 index 0000000..d85cc71 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C39E-1234567890abcABC.svg @@ -0,0 +1,112 @@ + + + + *1234567890+A+B+CABC* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/C93-1234567890abcABC.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/C93-1234567890abcABC.svg new file mode 100644 index 0000000..120c36f --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/C93-1234567890abcABC.svg @@ -0,0 +1,77 @@ + + + + *1234567890dAdBdCABC6-* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/CODABAR-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/CODABAR-123456789.svg new file mode 100644 index 0000000..0d9606a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/CODABAR-123456789.svg @@ -0,0 +1,51 @@ + + + + 123456789 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/CODE11-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/CODE11-123456789.svg new file mode 100644 index 0000000..f30d919 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/CODE11-123456789.svg @@ -0,0 +1,43 @@ + + + + 123456789 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-004900000463.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-004900000463.svg new file mode 100644 index 0000000..427ff40 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-004900000463.svg @@ -0,0 +1,37 @@ + + + + 0049000004632 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-0049000004632.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-0049000004632.svg new file mode 100644 index 0000000..427ff40 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-0049000004632.svg @@ -0,0 +1,37 @@ + + + + 0049000004632 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-081231723897.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-081231723897.svg new file mode 100644 index 0000000..96e1619 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN13-081231723897.svg @@ -0,0 +1,37 @@ + + + + 0812317238973 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/EAN2-22.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN2-22.svg new file mode 100644 index 0000000..d7f285d --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN2-22.svg @@ -0,0 +1,14 @@ + + + + 22 + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/EAN5-1234567890abcABC-283-33.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN5-1234567890abcABC-283-33.svg new file mode 100644 index 0000000..df18eae --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN5-1234567890abcABC-283-33.svg @@ -0,0 +1,23 @@ + + + + 1234567890abcABC-283*33 + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/EAN8-1234568.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN8-1234568.svg new file mode 100644 index 0000000..9c4e210 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/EAN8-1234568.svg @@ -0,0 +1,29 @@ + + + + 12345687 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/I25+-1234567890.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/I25+-1234567890.svg new file mode 100644 index 0000000..55f32b0 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/I25+-1234567890.svg @@ -0,0 +1,41 @@ + + + + AA012345678905ZA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/I25-1234567890.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/I25-1234567890.svg new file mode 100644 index 0000000..77af1b4 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/I25-1234567890.svg @@ -0,0 +1,36 @@ + + + + AA1234567890ZA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/IMB-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/IMB-123456789.svg new file mode 100644 index 0000000..a82dcd9 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/IMB-123456789.svg @@ -0,0 +1,72 @@ + + + + 123456789 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/ITF14-00012345600012.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/ITF14-00012345600012.svg new file mode 100644 index 0000000..25553f0 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/ITF14-00012345600012.svg @@ -0,0 +1,46 @@ + + + + 00012345600012 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/ITF14-05400141288766.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/ITF14-05400141288766.svg new file mode 100644 index 0000000..ece67b7 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/ITF14-05400141288766.svg @@ -0,0 +1,46 @@ + + + + 05400141288766 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/KIX-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/KIX-123456789.svg new file mode 100644 index 0000000..0c05177 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/KIX-123456789.svg @@ -0,0 +1,43 @@ + + + + 123456789 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/MSI+-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/MSI+-123456789.svg new file mode 100644 index 0000000..de5eae8 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/MSI+-123456789.svg @@ -0,0 +1,50 @@ + + + + 1234567892 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/MSI-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/MSI-123456789.svg new file mode 100644 index 0000000..89c0090 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/MSI-123456789.svg @@ -0,0 +1,46 @@ + + + + 123456789 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/PHARMA-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/PHARMA-123456789.svg new file mode 100644 index 0000000..f3561bb --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/PHARMA-123456789.svg @@ -0,0 +1,33 @@ + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/PHARMA2T-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/PHARMA2T-123456789.svg new file mode 100644 index 0000000..6f9368f --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/PHARMA2T-123456789.svg @@ -0,0 +1,24 @@ + + + + 0 + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/PLANET-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/PLANET-123456789.svg new file mode 100644 index 0000000..51de3aa --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/PLANET-123456789.svg @@ -0,0 +1,59 @@ + + + + 123456789 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/POSTNET-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/POSTNET-123456789.svg new file mode 100644 index 0000000..ca895ec --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/POSTNET-123456789.svg @@ -0,0 +1,59 @@ + + + + 123456789 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/RMS4CC-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/RMS4CC-123456789.svg new file mode 100644 index 0000000..ee91be7 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/RMS4CC-123456789.svg @@ -0,0 +1,49 @@ + + + + 123456789 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/S25+-1234567890.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/S25+-1234567890.svg new file mode 100644 index 0000000..dcdc32a --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/S25+-1234567890.svg @@ -0,0 +1,68 @@ + + + + 12345678905 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/S25-1234567890.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/S25-1234567890.svg new file mode 100644 index 0000000..26d48c5 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/S25-1234567890.svg @@ -0,0 +1,63 @@ + + + + 1234567890 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/TELEPENALPHA-1234567890ASCD.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/TELEPENALPHA-1234567890ASCD.svg new file mode 100644 index 0000000..d44f436 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/TELEPENALPHA-1234567890ASCD.svg @@ -0,0 +1,95 @@ + + + + 1234567890ASCD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/TELEPENNUMERIC-1234567890.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/TELEPENNUMERIC-1234567890.svg new file mode 100644 index 0000000..079766b --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/TELEPENNUMERIC-1234567890.svg @@ -0,0 +1,54 @@ + + + + 1234567890 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/UPCA-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/UPCA-123456789.svg new file mode 100644 index 0000000..d7ed6dc --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/UPCA-123456789.svg @@ -0,0 +1,37 @@ + + + + 0001234567895 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/picqer/php-barcode-generator/tests/verified-files/UPCE-123456789.svg b/vendor/picqer/php-barcode-generator/tests/verified-files/UPCE-123456789.svg new file mode 100644 index 0000000..4347e92 --- /dev/null +++ b/vendor/picqer/php-barcode-generator/tests/verified-files/UPCE-123456789.svg @@ -0,0 +1,24 @@ + + + + 012349 + + + + + + + + + + + + + + + + + + + +