diff --git a/pub/api/v1/user/mfa/index.php b/pub/api/v1/user/mfa/index.php
index d06029e..b99b3c3 100644
--- a/pub/api/v1/user/mfa/index.php
+++ b/pub/api/v1/user/mfa/index.php
@@ -1,13 +1,13 @@
request_method === 'POST') {
$this->apiOutput(400, ['error' => 'secret not found.']);
}
- $tfa = new TwoFactorAuth(new EndroidQrCodeWithLogoProvider());
+ $tfa = new TwoFactorAuth(new EndroidQrCodeProvider());
$API_mfa->postedData['user_uuid'] = $_SESSION['user']['user_uuid'];
$API_mfa->postedData['user_two_factor_secret'] = $_SESSION['mfasetup']['secret'];
diff --git a/pub/bin/pages/pageUserProfile_view.php b/pub/bin/pages/pageUserProfile_view.php
index 586ebff..f927c28 100644
--- a/pub/bin/pages/pageUserProfile_view.php
+++ b/pub/bin/pages/pageUserProfile_view.php
@@ -217,9 +217,9 @@ if ($user_data) { ?>
diff --git a/pub/login/php/mfaAuth.php b/pub/login/php/mfaAuth.php
index 2b4cfe1..b57a7b5 100644
--- a/pub/login/php/mfaAuth.php
+++ b/pub/login/php/mfaAuth.php
@@ -5,7 +5,7 @@ session_start();
require_once "{$_SERVER['DOCUMENT_ROOT']}/../vendor/autoload.php";
require_once "{$_SERVER['DOCUMENT_ROOT']}/login/php/authFunctions.php";
-use RobThree\Auth\Providers\Qr\EndroidQrCodeWithLogoProvider;
+use RobThree\Auth\Providers\Qr\EndroidQrCodeProvider;
use RobThree\Auth\TwoFactorAuth;
if (!isset($_POST['verification-1']) && !isset($_SESSION['mfa']['user_secret']) && !isset($_SESSION['mfa']['user_uuid'])) {
@@ -20,7 +20,7 @@ if (checkLoginAttempts() > 3) {
exit;
}
-$tfa = new TwoFactorAuth(new EndroidQrCodeWithLogoProvider());
+$tfa = new TwoFactorAuth(new EndroidQrCodeProvider());
$secret = $_SESSION['mfa']['user_secret'];
$postedCode = linkVerificationPosts();
diff --git a/vendor/bacon/bacon-qr-code/LICENSE b/vendor/bacon/bacon-qr-code/LICENSE
new file mode 100644
index 0000000..aa22018
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2017-present, 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..37d4336
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/README.md
@@ -0,0 +1,82 @@
+# QR Code generator
+
+[](https://github.com/Bacon/BaconQrCode/actions/workflows/ci.yml)
+[](https://codecov.io/gh/Bacon/BaconQrCode)
+[](https://packagist.org/packages/bacon/bacon-qr-code)
+[](https://packagist.org/packages/bacon/bacon-qr-code)
+[](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
+
+### GDLib Renderer
+GD library has so many limitations, that GD support is not added as backend, but as separated renderer.
+Use `GDLibRenderer` instead of `ImageRenderer`. These are the limitations:
+
+- Does not support gradient.
+- Does not support any curves, so you QR code is always squared.
+
+Example usage:
+
+```php
+use BaconQrCode\Renderer\GDLibRenderer;
+use BaconQrCode\Writer;
+
+$renderer = new GDLibRenderer(400);
+$writer = new Writer($renderer);
+$writer->writeFile('Hello World!', 'qrcode.png');
+```
+
+## Known issues
+
+### ImagickImageBackEnd: white pixel artifacts
+
+When using `ImagickImageBackEnd`, single white pixels may appear inside filled regions. This is
+most visible with margin 0 (where artifacts appear at the image edge), but can in theory occur at
+any position. The cause is a bug in ImageMagick's path fill rasterizer (`GetFillAlpha` in
+`MagickCore/draw.c`): an off-by-one error in the winding number calculation combined with an edge
+skipping bug in the scanline processing can incorrectly classify pixels as outside the polygon.
+
+The bug cannot be reliably worked around in this library:
+
+- **Canvas padding** (rendering on a larger canvas and cropping) does not work because the required
+ padding depends on the scale factor, path complexity, and ImageMagick's internal edge processing
+ state. No fixed padding value is safe for all inputs.
+- **Post-processing** (scanning for and fixing isolated white pixels) risks corrupting legitimate
+ rendering features such as curved module edges.
+
+For artifact-free output, use `SvgImageBackEnd` or `GDLibRenderer` instead.
+
+## Development
+
+To run unit tests, you need to have [Node.js](https://nodejs.org/en) and the pixelmatch library installed. Running
+`npm install` will install this for you.
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..9ec8629
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/BitArray.php
@@ -0,0 +1,364 @@
+
+ */
+ private SplFixedArray $bits;
+
+ /**
+ * Creates a new bit array with a given size.
+ */
+ public function __construct(private int $size = 0)
+ {
+ $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 min($result, $this->size);
+ }
+
+ /**
+ * 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 min($result, $this->size);
+ }
+
+ /**
+ * 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..294afb4
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php
@@ -0,0 +1,307 @@
+
+ */
+ private SplFixedArray $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..8b62b8c
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php
@@ -0,0 +1,177 @@
+|null
+ */
+ private static ?array $valueToEci;
+
+ /**
+ * @var array|null
+ */
+ private static ?array $nameToEci = null;
+
+ /**
+ * @param int[] $values
+ */
+ public function __construct(private readonly array $values, string ...$otherEncodingNames)
+ {
+ $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..bc9e865
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php
@@ -0,0 +1,33 @@
+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..63c52a9
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php
@@ -0,0 +1,66 @@
+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..ac84d66
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php
@@ -0,0 +1,57 @@
+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..6a5da0b
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php
@@ -0,0 +1,196 @@
+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..f5fb153
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/Mode.php
@@ -0,0 +1,69 @@
+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..d16a75e
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php
@@ -0,0 +1,454 @@
+ 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..68d3d16
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Common/Version.php
@@ -0,0 +1,592 @@
+|null
+ */
+ private static ?array $versions = null;
+
+ /**
+ * @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(2, 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..b1dc5c4
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php
@@ -0,0 +1,44 @@
+ $dataBytes Data bytes in the block.
+ * @param SplFixedArray $errorCorrectionBytes Error correction bytes in the block.
+ */
+ public function __construct(
+ private readonly SplFixedArray $dataBytes,
+ private readonly SplFixedArray $errorCorrectionBytes
+ ) {
+ }
+
+ /**
+ * 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..eefcf1c
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php
@@ -0,0 +1,134 @@
+>
+ */
+ private SplFixedArray $bytes;
+
+ public function __construct(private readonly int $width, private readonly int $height)
+ {
+ $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..a7e00ff
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php
@@ -0,0 +1,666 @@
+
+ */
+ private static array $codecs = [];
+
+ /**
+ * Encodes "content" with the error correction level "ecLevel".
+ */
+ public static function encode(
+ string $content,
+ ErrorCorrectionLevel $ecLevel,
+ string $encoding = self::DEFAULT_BYTE_MODE_ENCODING,
+ ?Version $forcedVersion = null,
+ // Barcode scanner might not be able to read the encoded message of the QR code with the prefix ECI of UTF-8
+ bool $prefixEci = true
+ ) : 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 ($prefixEci && Mode::BYTE() === $mode && self::DEFAULT_BYTE_MODE_ENCODING !== $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 = match ($mode) {
+ Mode::BYTE() => $dataBits->getSizeInBytes(),
+ Mode::NUMERIC(), Mode::ALPHANUMERIC() => strlen($content),
+ Mode::KANJI() => iconv_strlen($content, 'utf-8'),
+ };
+ 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 $byte) : int
+ {
+ return self::ALPHANUMERIC_TABLE[$byte] ?? -1;
+ }
+
+ /**
+ * Chooses the best mode for a given content.
+ */
+ private static function chooseMode(string $content, ?string $encoding = null) : Mode
+ {
+ if ('' === $content) {
+ return Mode::BYTE();
+ }
+
+ if (null !== $encoding && 0 === strcasecmp($encoding, 'SHIFT-JIS')) {
+ return self::isOnlyDoubleByteKanji($content) ? Mode::KANJI() : Mode::BYTE();
+ }
+
+ if (ctype_digit($content)) {
+ return Mode::NUMERIC();
+ }
+
+ if (self::isOnlyAlphanumeric($content)) {
+ return Mode::ALPHANUMERIC();
+ }
+
+ 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 (or is empty).
+ */
+ 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 = ord($bytes[$i]);
+
+ if (($byte < 0x81 || $byte > 0x9f) && $byte < 0xe0 || $byte > 0xeb) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if content only consists of alphanumeric characters (or is empty).
+ */
+ private static function isOnlyAlphanumeric(string $content) : bool
+ {
+ return strlen($content) === strspn($content, self::ALPHANUMERIC_CHARS);
+ }
+
+ /**
+ * 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];
+ }
+
+ $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.
+ */
+ private static function appendBytes(string $content, Mode $mode, BitArray $bits, string $encoding) : void
+ {
+ match ($mode) {
+ Mode::NUMERIC() => self::appendNumericBytes($content, $bits),
+ Mode::ALPHANUMERIC() => self::appendAlphanumericBytes($content, $bits),
+ Mode::BYTE() => self::append8BitBytes($content, $bits, $encoding),
+ Mode::KANJI() => self::appendKanjiBytes($content, $bits),
+ };
+ }
+
+ /**
+ * 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
+ {
+ $bytes = @iconv('utf-8', 'SHIFT-JIS', $content);
+
+ if (false === $bytes) {
+ throw new WriterException('Content could not be converted to SHIFT-JIS');
+ }
+
+ if (strlen($bytes) % 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($bytes);
+
+ for ($i = 0; $i < $length; $i += 2) {
+ $byte1 = ord($bytes[$i]);
+ $byte2 = ord($bytes[$i + 1]);
+ $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..cc85a40
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php
@@ -0,0 +1,235 @@
+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) floor(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.
+ */
+ public static function getDataMaskBit(int $maskPattern, int $x, int $y) : bool
+ {
+ return 0 === match ($maskPattern) {
+ 0 => ($x + $y) % 2,
+ 1 => $y % 2,
+ 2 => $x % 3,
+ 3 => ($x + $y) % 3,
+ 4 => (intdiv($y, 2) + intdiv($x, 3)) % 2,
+ 5 => (($x * $y) % 2) + (($x * $y) % 3),
+ 6 => ((($x * $y) % 2) + (($x * $y) % 3)) % 2,
+ 7 => ((($x + $y) % 2) + (($x * $y) % 3)) % 2,
+ };
+ }
+
+ /**
+ * 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..c3398f4
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php
@@ -0,0 +1,108 @@
+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;
+ }
+
+ public function getMatrix(): ByteMatrix
+ {
+ 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');
+ }
+ }
+
+ 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..eaf34f4
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php
@@ -0,0 +1,82 @@
+ 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');
+ }
+ }
+
+ 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
+ {
+ $c = $this->cyan / 100;
+ $m = $this->magenta / 100;
+ $y = $this->yellow / 100;
+ $k = $this->black / 100;
+
+ return new Rgb(
+ (int) round(255 * (1 - $c) * (1 - $k)),
+ (int) round(255 * (1 - $m) * (1 - $k)),
+ (int) round(255 * (1 - $y) * (1 - $k))
+ );
+ }
+
+ 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');
+ }
+ }
+
+ public function getGray() : int
+ {
+ return $this->gray;
+ }
+
+ public function toRgb() : Rgb
+ {
+ // use 255/100 instead of 2.55 to avoid floating-point precision loss (100 * 2.55 = 254.999...)
+ $value = (int) round($this->gray * 255 / 100);
+
+ return new Rgb($value, $value, $value);
+ }
+
+ 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..051c5be
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php
@@ -0,0 +1,75 @@
+ 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');
+ }
+ }
+
+ 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
+ {
+ // avoid division by zero with input rgb(0,0,0), by handling it as a specific case
+ if (0 === $this->red && 0 === $this->green && 0 === $this->blue) {
+ return new Cmyk(0, 0, 0, 100);
+ }
+
+ $c = 1 - ($this->red / 255);
+ $m = 1 - ($this->green / 255);
+ $y = 1 - ($this->blue / 255);
+ $k = min($c, $m, $y);
+
+ return new Cmyk(
+ (int) round(100 * ($c - $k) / (1 - $k)),
+ (int) round(100 * ($m - $k) / (1 - $k)),
+ (int) round(100 * ($y - $k) / (1 - $k)),
+ (int) round(100 * $k)
+ );
+ }
+
+ public function toGray() : Gray
+ {
+ // use integer-based calculation to avoid floating-point precision loss
+ return new Gray((int) round(($this->red * 2126 + $this->green * 7152 + $this->blue * 722) / 25500));
+ }
+}
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..379e5c7
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php
@@ -0,0 +1,26 @@
+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 @@
+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/PointyEye.php b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/PointyEye.php
new file mode 100644
index 0000000..39c7d23
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/PointyEye.php
@@ -0,0 +1,56 @@
+move(-3.5, 3.5)
+ ->line(-3.5, 0)
+ ->ellipticArc(3.5, 3.5, 0, false, true, 0, -3.5)
+ ->line(3.5, -3.5)
+ ->line(3.5, 3.5)
+ ->close()
+ ->move(2.5, 0)
+ ->ellipticArc(2.5, 2.5, 0, false, true, 0, 2.5)
+ ->ellipticArc(2.5, 2.5, 0, false, true, -2.5, 0)
+ ->ellipticArc(2.5, 2.5, 0, false, true, 0, -2.5)
+ ->ellipticArc(2.5, 2.5, 0, false, true, 2.5, 0)
+ ->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/SimpleCircleEye.php b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php
new file mode 100644
index 0000000..735d326
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php
@@ -0,0 +1,51 @@
+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..09bedfe
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php
@@ -0,0 +1,50 @@
+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/GDLibRenderer.php b/vendor/bacon/bacon-qr-code/src/Renderer/GDLibRenderer.php
new file mode 100644
index 0000000..7e6efc0
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/GDLibRenderer.php
@@ -0,0 +1,237 @@
+
+ */
+ private array $colors;
+
+ public function __construct(
+ private int $size,
+ private int $margin = 4,
+ private string $imageFormat = 'png',
+ private int $compressionQuality = 9,
+ private ?Fill $fill = null
+ ) {
+ if (! extension_loaded('gd') || ! function_exists('gd_info')) {
+ throw new RuntimeException('You need to install the GD extension to use this back end');
+ }
+
+ if ($this->fill === null) {
+ $this->fill = Fill::default();
+ }
+ if ($this->fill->hasGradientFill()) {
+ throw new InvalidArgumentException('GDLibRenderer does not support gradients');
+ }
+ }
+
+ /**
+ * @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');
+ }
+
+ MatrixUtil::removePositionDetectionPatterns($matrix);
+ $this->newImage();
+ $this->draw($matrix);
+
+ return $this->renderImage();
+ }
+
+ private function newImage(): void
+ {
+ $img = imagecreatetruecolor($this->size, $this->size);
+ if ($img === false) {
+ throw new RuntimeException('Failed to create image of that size');
+ }
+
+ $this->image = $img;
+ imagealphablending($this->image, false);
+ imagesavealpha($this->image, true);
+
+
+ $bg = $this->getColor($this->fill->getBackgroundColor());
+ imagefilledrectangle($this->image, 0, 0, $this->size, $this->size, $bg);
+ imagealphablending($this->image, true);
+ }
+
+ private function draw(ByteMatrix $matrix): void
+ {
+ $matrixSize = $matrix->getWidth();
+
+ $pointsOnSide = $matrix->getWidth() + $this->margin * 2;
+ $pointInPx = $this->size / $pointsOnSide;
+
+ $this->drawEye(0, 0, $pointInPx, $this->fill->getTopLeftEyeFill());
+ $this->drawEye($matrixSize - 7, 0, $pointInPx, $this->fill->getTopRightEyeFill());
+ $this->drawEye(0, $matrixSize - 7, $pointInPx, $this->fill->getBottomLeftEyeFill());
+
+ $rows = $matrix->getArray()->toArray();
+ $color = $this->getColor($this->fill->getForegroundColor());
+ for ($y = 0; $y < $matrixSize; $y += 1) {
+ for ($x = 0; $x < $matrixSize; $x += 1) {
+ if (! $rows[$y][$x]) {
+ continue;
+ }
+
+ $points = $this->normalizePoints([
+ ($this->margin + $x) * $pointInPx, ($this->margin + $y) * $pointInPx,
+ ($this->margin + $x + 1) * $pointInPx, ($this->margin + $y) * $pointInPx,
+ ($this->margin + $x + 1) * $pointInPx, ($this->margin + $y + 1) * $pointInPx,
+ ($this->margin + $x) * $pointInPx, ($this->margin + $y + 1) * $pointInPx,
+ ]);
+ imagefilledpolygon($this->image, $points, $color);
+ }
+ }
+ }
+
+ private function drawEye(int $xOffset, int $yOffset, float $pointInPx, EyeFill $eyeFill): void
+ {
+ $internalColor = $this->getColor($eyeFill->inheritsInternalColor()
+ ? $this->fill->getForegroundColor()
+ : $eyeFill->getInternalColor());
+
+ $externalColor = $this->getColor($eyeFill->inheritsExternalColor()
+ ? $this->fill->getForegroundColor()
+ : $eyeFill->getExternalColor());
+
+ for ($y = 0; $y < 7; $y += 1) {
+ for ($x = 0; $x < 7; $x += 1) {
+ if ((($y === 1 || $y === 5) && $x > 0 && $x < 6) || (($x === 1 || $x === 5) && $y > 0 && $y < 6)) {
+ continue;
+ }
+
+ $points = $this->normalizePoints([
+ ($this->margin + $x + $xOffset) * $pointInPx, ($this->margin + $y + $yOffset) * $pointInPx,
+ ($this->margin + $x + $xOffset + 1) * $pointInPx, ($this->margin + $y + $yOffset) * $pointInPx,
+ ($this->margin + $x + $xOffset + 1) * $pointInPx, ($this->margin + $y + $yOffset + 1) * $pointInPx,
+ ($this->margin + $x + $xOffset) * $pointInPx, ($this->margin + $y + $yOffset + 1) * $pointInPx,
+ ]);
+
+ if ($y > 1 && $y < 5 && $x > 1 && $x < 5) {
+ imagefilledpolygon($this->image, $points, $internalColor);
+ } else {
+ imagefilledpolygon($this->image, $points, $externalColor);
+ }
+ }
+ }
+ }
+
+ /**
+ * Normalize points will trim right and bottom line by 1 pixel.
+ * Otherwise pixels of neighbors are overlapping which leads to issue with transparency and small QR codes.
+ */
+ private function normalizePoints(array $points): array
+ {
+ $maxX = $maxY = 0;
+ for ($i = 0; $i < count($points); $i += 2) {
+ // Do manual round as GD just removes decimal part
+ $points[$i] = $newX = round($points[$i]);
+ $points[$i + 1] = $newY = round($points[$i + 1]);
+
+ $maxX = max($maxX, $newX);
+ $maxY = max($maxY, $newY);
+ }
+
+ // Do trimming only if there are 4 points (8 coordinates), assumes this is square.
+
+ for ($i = 0; $i < count($points); $i += 2) {
+ $points[$i] = min($points[$i], $maxX - 1);
+ $points[$i + 1] = min($points[$i + 1], $maxY - 1);
+ }
+
+ return $points;
+ }
+
+ private function renderImage(): string
+ {
+ ob_start();
+ $quality = $this->compressionQuality;
+ switch ($this->imageFormat) {
+ case 'png':
+ if ($quality > 9 || $quality < 0) {
+ $quality = 9;
+ }
+ imagepng($this->image, null, $quality);
+ break;
+
+ case 'gif':
+ imagegif($this->image, null);
+ break;
+
+ case 'jpeg':
+ case 'jpg':
+ if ($quality > 100 || $quality < 0) {
+ $quality = 85;
+ }
+ imagejpeg($this->image, null, $quality);
+ break;
+ default:
+ ob_end_clean();
+ throw new InvalidArgumentException(
+ 'Supported image formats are jpeg, png and gif, got: ' . $this->imageFormat
+ );
+ }
+
+ $this->colors = [];
+ $this->image = null;
+
+ return ob_get_clean();
+ }
+
+ private function getColor(ColorInterface $color): int
+ {
+ $alpha = 100;
+
+ if ($color instanceof Alpha) {
+ $alpha = $color->getAlpha();
+ $color = $color->getBaseColor();
+ }
+
+ $rgb = $color->toRgb();
+
+ $colorKey = sprintf('%02X%02X%02X%02X', $rgb->getRed(), $rgb->getGreen(), $rgb->getBlue(), $alpha);
+
+ if (! isset($this->colors[$colorKey])) {
+ $colorId = imagecolorallocatealpha(
+ $this->image,
+ $rgb->getRed(),
+ $rgb->getGreen(),
+ $rgb->getBlue(),
+ (int)((100 - $alpha) / 100 * 127) // Alpha for GD is in range 0 (opaque) - 127 (transparent)
+ );
+
+ if ($colorId === false) {
+ throw new RuntimeException('Failed to create color: #' . $colorKey);
+ }
+
+ $this->colors[$colorKey] = $colorId;
+ }
+
+ return $this->colors[$colorKey];
+ }
+}
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..4269456
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php
@@ -0,0 +1,373 @@
+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;
+ $this->antialias = $antialias;
+ }
+
+ 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();
+
+ if (! $this->antialias) {
+ $this->image->setAntiAlias(false);
+ $this->draw->setStrokeAntialias(false);
+ }
+
+ $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..5b6709a
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php
@@ -0,0 +1,363 @@
+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;
+ }
+
+ $toBeHashed = $this->getColorString($startColor) . $this->getColorString($endColor) . $gradient->getType();
+ if ($startColor instanceof Alpha) {
+ $toBeHashed .= (string) $startColor->getAlpha();
+ }
+ $id = sprintf('g%d-%s', ++$this->gradientCount, hash('xxh3', $toBeHashed));
+ $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..9b435a0
--- /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..0d33303
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php
@@ -0,0 +1,150 @@
+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->rotate($rotation)->translate($xTranslation, $yTranslation)
+ )
+ ->append(
+ $internalPath->rotate($rotation)->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->rotate($rotation)->translate($xTranslation, $yTranslation)
+ );
+ } else {
+ $this->imageBackEnd->drawPathWithColor($externalPath, $fill->getExternalColor());
+ }
+
+ if ($fill->inheritsInternalColor()) {
+ $modulePath = $modulePath->append(
+ $internalPath->rotate($rotation)->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..c5d5c6f
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php
@@ -0,0 +1,56 @@
+ 1) {
+ throw new InvalidArgumentException('Size must between 0 (exclusive) and 1 (inclusive)');
+ }
+ }
+
+ 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..141d66c
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php
@@ -0,0 +1,82 @@
+
+ */
+ private array $points = [];
+
+ /**
+ * @var array|null
+ */
+ private ?array $simplifiedPoints = null;
+
+ private int $minX = PHP_INT_MAX;
+
+ private int $minY = PHP_INT_MAX;
+
+ private int $maxX = -1;
+
+ private int $maxY = -1;
+
+ public function __construct(private readonly bool $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..01f692c
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php
@@ -0,0 +1,160 @@
+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..8cf1d0b
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php
@@ -0,0 +1,44 @@
+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..bddf2d0
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php
@@ -0,0 +1,34 @@
+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
+ );
+ }
+
+ /**
+ * @return self
+ */
+ public function rotate(int $degrees) : OperationInterface
+ {
+ $radians = deg2rad($degrees);
+ $sin = sin($radians);
+ $cos = cos($radians);
+ $x1r = $this->x1 * $cos - $this->y1 * $sin;
+ $y1r = $this->x1 * $sin + $this->y1 * $cos;
+ $x2r = $this->x2 * $cos - $this->y2 * $sin;
+ $y2r = $this->x2 * $sin + $this->y2 * $cos;
+ $x3r = $this->x3 * $cos - $this->y3 * $sin;
+ $y3r = $this->x3 * $sin + $this->y3 * $cos;
+ return new self(
+ $x1r,
+ $y1r,
+ $x2r,
+ $y2r,
+ $x3r,
+ $y3r
+ );
+ }
+}
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..800a032
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php
@@ -0,0 +1,266 @@
+xRadius = abs($xRadius);
+ $this->yRadius = abs($yRadius);
+ $this->xAxisAngle = $xAxisAngle % 360;
+ }
+
+ 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
+ );
+ }
+
+ /**
+ * @return self
+ */
+ public function rotate(int $degrees) : OperationInterface
+ {
+ $radians = deg2rad($degrees);
+ $sin = sin($radians);
+ $cos = cos($radians);
+ $xr = $this->x * $cos - $this->y * $sin;
+ $yr = $this->x * $sin + $this->y * $cos;
+ return new self(
+ $this->xRadius,
+ $this->yRadius,
+ $this->xAxisAngle,
+ $this->largeArc,
+ $this->sweep,
+ $xr,
+ $yr
+ );
+ }
+
+ /**
+ * 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): array
+ {
+ $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 > 0) {
+ $delta -= 2 * pi();
+ } elseif ($this->sweep && $delta < 0) {
+ $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..dec46fd
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php
@@ -0,0 +1,42 @@
+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);
+ }
+
+ /**
+ * @return self
+ */
+ public function rotate(int $degrees) : OperationInterface
+ {
+ $radians = deg2rad($degrees);
+ $sin = sin($radians);
+ $cos = cos($radians);
+ $xr = $this->x * $cos - $this->y * $sin;
+ $yr = $this->x * $sin + $this->y * $cos;
+ return new self($xr, $yr);
+ }
+}
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..c3c9a56
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php
@@ -0,0 +1,42 @@
+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);
+ }
+
+ /**
+ * @return self
+ */
+ public function rotate(int $degrees) : OperationInterface
+ {
+ $radians = deg2rad($degrees);
+ $sin = sin($radians);
+ $cos = cos($radians);
+ $xr = $this->x * $cos - $this->y * $sin;
+ $yr = $this->x * $sin + $this->y * $cos;
+ return new self($xr, $yr);
+ }
+}
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..9271555
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php
@@ -0,0 +1,17 @@
+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;
+ }
+
+ public function rotate(int $degrees) : self
+ {
+ $path = new self();
+
+ foreach ($this->operations as $operation) {
+ $path->operations[] = $operation->rotate($degrees);
+ }
+
+ return $path;
+ }
+
+ /**
+ * @return 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..219bbf3
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php
@@ -0,0 +1,80 @@
+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 && 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..19de25d
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php
@@ -0,0 +1,129 @@
+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..eea4031
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php
@@ -0,0 +1,31 @@
+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 @@
+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..d7f7ebb
--- /dev/null
+++ b/vendor/bacon/bacon-qr-code/src/Writer.php
@@ -0,0 +1,63 @@
+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_ENCODING,
+ ?ErrorCorrectionLevel $ecLevel = null,
+ ?Version $forcedVersion = null
+ ) : void {
+ file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel, $forcedVersion));
+ }
+}
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
index 4560be4..20d72d9 100644
--- a/vendor/composer/autoload_psr4.php
+++ b/vendor/composer/autoload_psr4.php
@@ -12,5 +12,8 @@ return array(
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
'Masterminds\\' => array($vendorDir . '/masterminds/html5/src'),
'FontLib\\' => array($vendorDir . '/dompdf/php-font-lib/src/FontLib'),
+ 'Endroid\\QrCode\\' => array($vendorDir . '/endroid/qr-code/src'),
'Dompdf\\' => array($vendorDir . '/dompdf/dompdf/src'),
+ 'DASPRiD\\Enum\\' => array($vendorDir . '/dasprid/enum/src'),
+ 'BaconQrCode\\' => array($vendorDir . '/bacon/bacon-qr-code/src'),
);
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
index b21dbfb..f9883fe 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -113,9 +113,18 @@ class ComposerStaticInit017c5201b421d99f90b020e446d1b958
array (
'FontLib\\' => 8,
),
+ 'E' =>
+ array (
+ 'Endroid\\QrCode\\' => 15,
+ ),
'D' =>
array (
'Dompdf\\' => 7,
+ 'DASPRiD\\Enum\\' => 13,
+ ),
+ 'B' =>
+ array (
+ 'BaconQrCode\\' => 12,
),
);
@@ -144,10 +153,22 @@ class ComposerStaticInit017c5201b421d99f90b020e446d1b958
array (
0 => __DIR__ . '/..' . '/dompdf/php-font-lib/src/FontLib',
),
+ 'Endroid\\QrCode\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/endroid/qr-code/src',
+ ),
'Dompdf\\' =>
array (
0 => __DIR__ . '/..' . '/dompdf/dompdf/src',
),
+ 'DASPRiD\\Enum\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/dasprid/enum/src',
+ ),
+ 'BaconQrCode\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/bacon/bacon-qr-code/src',
+ ),
);
public static $classMap = array (
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index bd759ef..9ffa56a 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1,5 +1,116 @@
{
"packages": [
+ {
+ "name": "bacon/bacon-qr-code",
+ "version": "v3.1.1",
+ "version_normalized": "3.1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Bacon/BaconQrCode.git",
+ "reference": "4da2233e72eeecd9be3b62e0dc2cc9ed8e2e31c2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/4da2233e72eeecd9be3b62e0dc2cc9ed8e2e31c2",
+ "reference": "4da2233e72eeecd9be3b62e0dc2cc9ed8e2e31c2",
+ "shasum": ""
+ },
+ "require": {
+ "dasprid/enum": "^1.0.3",
+ "ext-iconv": "*",
+ "php": "^8.1"
+ },
+ "require-dev": {
+ "phly/keep-a-changelog": "^2.12",
+ "phpunit/phpunit": "^10.5.11 || ^11.0.4",
+ "spatie/phpunit-snapshot-assertions": "^5.1.5",
+ "spatie/pixelmatch-php": "^1.2.0",
+ "squizlabs/php_codesniffer": "^3.9"
+ },
+ "suggest": {
+ "ext-imagick": "to generate QR code images"
+ },
+ "time": "2026-04-05T21:06:35+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "BaconQrCode\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Ben Scholzen 'DASPRiD'",
+ "email": "mail@dasprids.de",
+ "homepage": "https://dasprids.de/",
+ "role": "Developer"
+ }
+ ],
+ "description": "BaconQrCode is a QR code generator for PHP.",
+ "homepage": "https://github.com/Bacon/BaconQrCode",
+ "support": {
+ "issues": "https://github.com/Bacon/BaconQrCode/issues",
+ "source": "https://github.com/Bacon/BaconQrCode/tree/v3.1.1"
+ },
+ "install-path": "../bacon/bacon-qr-code"
+ },
+ {
+ "name": "dasprid/enum",
+ "version": "1.0.7",
+ "version_normalized": "1.0.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/DASPRiD/Enum.git",
+ "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/b5874fa9ed0043116c72162ec7f4fb50e02e7cce",
+ "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1 <9.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
+ "squizlabs/php_codesniffer": "*"
+ },
+ "time": "2025-09-16T12:23:56+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "DASPRiD\\Enum\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Ben Scholzen 'DASPRiD'",
+ "email": "mail@dasprids.de",
+ "homepage": "https://dasprids.de/",
+ "role": "Developer"
+ }
+ ],
+ "description": "PHP 7.1 enum implementation",
+ "keywords": [
+ "enum",
+ "map"
+ ],
+ "support": {
+ "issues": "https://github.com/DASPRiD/Enum/issues",
+ "source": "https://github.com/DASPRiD/Enum/tree/1.0.7"
+ },
+ "install-path": "../dasprid/enum"
+ },
{
"name": "dompdf/dompdf",
"version": "v3.1.5",
@@ -164,6 +275,81 @@
},
"install-path": "../dompdf/php-svg-lib"
},
+ {
+ "name": "endroid/qr-code",
+ "version": "6.1.3",
+ "version_normalized": "6.1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/endroid/qr-code.git",
+ "reference": "5fa534856ed95649d67c0eab0cabc03ab1d8e0e2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/endroid/qr-code/zipball/5fa534856ed95649d67c0eab0cabc03ab1d8e0e2",
+ "reference": "5fa534856ed95649d67c0eab0cabc03ab1d8e0e2",
+ "shasum": ""
+ },
+ "require": {
+ "bacon/bacon-qr-code": "^3.0",
+ "php": "^8.4"
+ },
+ "require-dev": {
+ "endroid/quality": "dev-main",
+ "ext-gd": "*",
+ "khanamiryan/qrcode-detector-decoder": "^2.0.3",
+ "setasign/fpdf": "^1.8.2"
+ },
+ "suggest": {
+ "ext-gd": "Enables you to write PNG images",
+ "khanamiryan/qrcode-detector-decoder": "Enables you to use the image validator",
+ "roave/security-advisories": "Makes sure package versions with known security issues are not installed",
+ "setasign/fpdf": "Enables you to use the PDF writer"
+ },
+ "time": "2026-02-05T07:01:58+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Endroid\\QrCode\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jeroen van den Enden",
+ "email": "info@endroid.nl"
+ }
+ ],
+ "description": "Endroid QR Code",
+ "homepage": "https://github.com/endroid/qr-code",
+ "keywords": [
+ "code",
+ "endroid",
+ "php",
+ "qr",
+ "qrcode"
+ ],
+ "support": {
+ "issues": "https://github.com/endroid/qr-code/issues",
+ "source": "https://github.com/endroid/qr-code/tree/6.1.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/endroid",
+ "type": "github"
+ }
+ ],
+ "install-path": "../endroid/qr-code"
+ },
{
"name": "masterminds/html5",
"version": "2.10.1",
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index 01c61e4..3c0bbce 100644
--- a/vendor/composer/installed.php
+++ b/vendor/composer/installed.php
@@ -19,6 +19,24 @@
'aliases' => array(),
'dev_requirement' => false,
),
+ 'bacon/bacon-qr-code' => array(
+ 'pretty_version' => 'v3.1.1',
+ 'version' => '3.1.1.0',
+ 'reference' => '4da2233e72eeecd9be3b62e0dc2cc9ed8e2e31c2',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../bacon/bacon-qr-code',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ 'dasprid/enum' => array(
+ 'pretty_version' => '1.0.7',
+ 'version' => '1.0.7.0',
+ 'reference' => 'b5874fa9ed0043116c72162ec7f4fb50e02e7cce',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../dasprid/enum',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
'dompdf/dompdf' => array(
'pretty_version' => 'v3.1.5',
'version' => '3.1.5.0',
@@ -46,6 +64,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
+ 'endroid/qr-code' => array(
+ 'pretty_version' => '6.1.3',
+ 'version' => '6.1.3.0',
+ 'reference' => '5fa534856ed95649d67c0eab0cabc03ab1d8e0e2',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../endroid/qr-code',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
'masterminds/html5' => array(
'pretty_version' => '2.10.1',
'version' => '2.10.1.0',
diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php
index 14bf88d..5ece5bc 100644
--- a/vendor/composer/platform_check.php
+++ b/vendor/composer/platform_check.php
@@ -4,8 +4,8 @@
$issues = array();
-if (!(PHP_VERSION_ID >= 80200)) {
- $issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.0". You are running ' . PHP_VERSION . '.';
+if (!(PHP_VERSION_ID >= 80400)) {
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 8.4.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
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
+
+[](https://github.com/DASPRiD/Enum/actions?query=workflow%3Atests)
+[](https://coveralls.io/github/DASPRiD/Enum?branch=master)
+[](https://packagist.org/packages/dasprid/enum)
+[](https://packagist.org/packages/dasprid/enum)
+[](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/src/AbstractEnum.php b/vendor/dasprid/enum/src/AbstractEnum.php
new file mode 100644
index 0000000..43006dc
--- /dev/null
+++ b/vendor/dasprid/enum/src/AbstractEnum.php
@@ -0,0 +1,261 @@
+>
+ */
+ 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 serializing enums.
+ *
+ * @throws SerializeNotSupportedException
+ */
+ final public function __serialize() : array
+ {
+ throw new SerializeNotSupportedException();
+ }
+
+ /**
+ * Forbid unserializing enums.
+ *
+ * @throws UnserializeNotSupportedException
+ */
+ final public function __wakeup() : void
+ {
+ throw new UnserializeNotSupportedException();
+ }
+
+ /**
+ * Forbid unserializing enums.
+ *
+ * @throws UnserializeNotSupportedException
+ */
+ final public function __unserialize($arg) : 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 @@
+build();
+```
+
+## Usage: without using the builder
+
+```php
+use Endroid\QrCode\Color\Color;
+use Endroid\QrCode\Encoding\Encoding;
+use Endroid\QrCode\ErrorCorrectionLevel;
+use Endroid\QrCode\QrCode;
+use Endroid\QrCode\Label\Label;
+use Endroid\QrCode\Logo\Logo;
+use Endroid\QrCode\RoundBlockSizeMode;
+use Endroid\QrCode\Writer\PngWriter;
+use Endroid\QrCode\Writer\ValidationException;
+
+$writer = new PngWriter();
+
+// Create QR code
+$qrCode = new QrCode(
+ data: 'Life is too short to be generating QR codes',
+ encoding: new Encoding('UTF-8'),
+ errorCorrectionLevel: ErrorCorrectionLevel::Low,
+ size: 300,
+ margin: 10,
+ roundBlockSizeMode: RoundBlockSizeMode::Margin,
+ foregroundColor: new Color(0, 0, 0),
+ backgroundColor: new Color(255, 255, 255)
+);
+
+// Create generic logo
+$logo = new Logo(
+ path: __DIR__.'/assets/bender.png',
+ resizeToWidth: 50,
+ punchoutBackground: true
+);
+
+// Create generic label
+$label = new Label(
+ text: 'Label',
+ textColor: new Color(255, 0, 0)
+);
+
+$result = $writer->write($qrCode, $logo, $label);
+
+// Validate the result
+$writer->validateResult($result, 'Life is too short to be generating QR codes');
+```
+
+## Usage: working with results
+
+```php
+
+// Directly output the QR code
+header('Content-Type: '.$result->getMimeType());
+echo $result->getString();
+
+// Save it to a file
+$result->saveToFile(__DIR__.'/qrcode.png');
+
+// Generate a data URI to include image data inline (i.e. inside an
tag)
+$dataUri = $result->getDataUri();
+```
+
+
+
+### Writer options
+
+Some writers provide writer options. Each available writer option is can be
+found as a constant prefixed with WRITER_OPTION_ in the writer class.
+
+* `PdfWriter`
+ * `unit`: unit of measurement (default: mm)
+ * `fpdf`: PDF to place the image in (default: new PDF)
+ * `x`: image offset (default: 0)
+ * `y`: image offset (default: 0)
+ * `link`: a URL or an identifier returned by `AddLink()`.
+* `PngWriter`
+ * `compression_level`: compression level (0-9, default: -1 = zlib default)
+ * `number_of_colors`: number of colors (1-256, null for true color and transparency)
+* `SvgWriter`
+ * `block_id`: id of the block element for external reference (default: block)
+ * `exclude_xml_declaration`: exclude XML declaration (default: false)
+ * `exclude_svg_width_and_height`: exclude width and height (default: false)
+ * `force_xlink_href`: forces xlink namespace in case of compatibility issues (default: false)
+ * `compact`: create using `path` element, otherwise use `defs` and `use` (default: true)
+* `WebPWriter`
+ * `quality`: image quality (0-100, default: 80)
+
+You can provide any writer options like this.
+
+```php
+use Endroid\QrCode\Writer\SvgWriter;
+
+$builder = new Builder(
+ writer: new SvgWriter(),
+ writerOptions: [
+ SvgWriter::WRITER_OPTION_EXCLUDE_XML_DECLARATION => true
+ ]
+);
+```
+
+### Encoding
+
+If you use a barcode scanner you can have some troubles while reading the
+generated QR codes. Depending on the encoding you chose you will have an extra
+amount of data corresponding to the ECI block. Some barcode scanner are not
+programmed to interpret this block of information. To ensure a maximum
+compatibility you can use the `ISO-8859-1` encoding that is the default
+encoding used by barcode scanners (if your character set supports it,
+i.e. no Chinese characters are present).
+
+### Round block size mode
+
+By default block sizes are rounded to guarantee sharp images and improve
+readability. However some other rounding variants are available.
+
+* `margin (default)`: the size of the QR code is shrunk if necessary but the size
+ of the final image remains unchanged due to additional margin being added.
+* `enlarge`: the size of the QR code and the final image are enlarged when
+ rounding differences occur.
+* `shrink`: the size of the QR code and the final image are
+ shrunk when rounding differences occur.
+* `none`: No rounding. This mode can be used when blocks don't need to be rounded
+ to pixels (for instance SVG).
+
+## Readability
+
+The readability of a QR code is primarily determined by the size, the input
+length, the error correction level and any possible logo over the image so you
+can tweak these parameters if you are looking for optimal results. You can also
+check $qrCode->getRoundBlockSize() value to see if block dimensions are rounded
+so that the image is more sharp and readable. Please note that rounding block
+size can result in additional padding to compensate for the rounding difference.
+And finally the encoding (default UTF-8 to support large character sets) can be
+set to `ISO-8859-1` if possible to improve readability.
+
+## Validating the generated QR code
+
+If you need to be extra sure the QR code you generated is readable and contains
+the exact data you requested you can enable the validation reader, which is
+disabled by default. You can do this either via the builder or directly on any
+writer that supports validation. See the examples above.
+
+Please note that validation affects performance so only use it in case of problems.
+
+## Symfony integration
+
+The [endroid/qr-code-bundle](https://github.com/endroid/qr-code-bundle)
+integrates the QR code library in Symfony for an even better experience.
+
+* Configure your defaults (like image size, default writer etc.)
+* Support for multiple configurations and injection via aliases
+* Generate QR codes for defined configurations via URL like /qr-code//Hello
+* Generate QR codes or URLs directly from Twig using dedicated functions
+
+Read the [bundle documentation](https://github.com/endroid/qr-code-bundle)
+for more information.
+
+## Versioning
+
+Version numbers follow the MAJOR.MINOR.PATCH scheme. Backwards compatibility
+breaking changes will be kept to a minimum but be aware that these can occur.
+Lock your dependencies for production and test your code when upgrading.
+
+## License
+
+This bundle is under the MIT license. For the full copyright and license
+information please view the LICENSE file that was distributed with this source code.
diff --git a/vendor/endroid/qr-code/assets/open_sans.ttf b/vendor/endroid/qr-code/assets/open_sans.ttf
new file mode 100644
index 0000000..db43334
Binary files /dev/null and b/vendor/endroid/qr-code/assets/open_sans.ttf differ
diff --git a/vendor/endroid/qr-code/src/Bacon/ErrorCorrectionLevelConverter.php b/vendor/endroid/qr-code/src/Bacon/ErrorCorrectionLevelConverter.php
new file mode 100644
index 0000000..ae2be59
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Bacon/ErrorCorrectionLevelConverter.php
@@ -0,0 +1,21 @@
+ BaconErrorCorrectionLevel::valueOf('L'),
+ ErrorCorrectionLevel::Medium => BaconErrorCorrectionLevel::valueOf('M'),
+ ErrorCorrectionLevel::Quartile => BaconErrorCorrectionLevel::valueOf('Q'),
+ ErrorCorrectionLevel::High => BaconErrorCorrectionLevel::valueOf('H'),
+ };
+ }
+}
diff --git a/vendor/endroid/qr-code/src/Bacon/MatrixFactory.php b/vendor/endroid/qr-code/src/Bacon/MatrixFactory.php
new file mode 100644
index 0000000..90fe295
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Bacon/MatrixFactory.php
@@ -0,0 +1,32 @@
+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] = 1 === $baconMatrix->get($columnIndex, $rowIndex) ? 1 : 0;
+ }
+ }
+
+ 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..89c6441
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Builder/Builder.php
@@ -0,0 +1,128 @@
+ */
+ private array $writerOptions = [],
+ private bool $validateResult = false,
+ // QrCode options
+ private string $data = '',
+ private EncodingInterface $encoding = new Encoding('UTF-8'),
+ private ErrorCorrectionLevel $errorCorrectionLevel = ErrorCorrectionLevel::Low,
+ private int $size = 300,
+ private int $margin = 10,
+ private RoundBlockSizeMode $roundBlockSizeMode = RoundBlockSizeMode::Margin,
+ private ColorInterface $foregroundColor = new Color(0, 0, 0),
+ private ColorInterface $backgroundColor = new Color(255, 255, 255),
+ // Label options
+ private string $labelText = '',
+ private FontInterface $labelFont = new Font(__DIR__.'/../../assets/open_sans.ttf', 16),
+ private LabelAlignment $labelAlignment = LabelAlignment::Center,
+ private MarginInterface $labelMargin = new Margin(0, 10, 10, 10),
+ private ColorInterface $labelTextColor = new Color(0, 0, 0),
+ // Logo options
+ private string $logoPath = '',
+ private ?int $logoResizeToWidth = null,
+ private ?int $logoResizeToHeight = null,
+ private bool $logoPunchoutBackground = false,
+ ) {
+ }
+
+ /** @param array|null $writerOptions */
+ public function build(
+ ?WriterInterface $writer = null,
+ ?array $writerOptions = null,
+ ?bool $validateResult = null,
+ // QrCode options
+ ?string $data = null,
+ ?EncodingInterface $encoding = null,
+ ?ErrorCorrectionLevel $errorCorrectionLevel = null,
+ ?int $size = null,
+ ?int $margin = null,
+ ?RoundBlockSizeMode $roundBlockSizeMode = null,
+ ?ColorInterface $foregroundColor = null,
+ ?ColorInterface $backgroundColor = null,
+ // Label options
+ ?string $labelText = null,
+ ?FontInterface $labelFont = null,
+ ?LabelAlignment $labelAlignment = null,
+ ?MarginInterface $labelMargin = null,
+ ?ColorInterface $labelTextColor = null,
+ // Logo options
+ ?string $logoPath = null,
+ ?int $logoResizeToWidth = null,
+ ?int $logoResizeToHeight = null,
+ ?bool $logoPunchoutBackground = null,
+ ): ResultInterface {
+ if ($this->validateResult && !$this->writer instanceof ValidatingWriterInterface) {
+ throw ValidationException::createForUnsupportedWriter(get_class($this->writer));
+ }
+
+ $writer = $writer ?? $this->writer;
+ $writerOptions = $writerOptions ?? $this->writerOptions;
+ $validateResult = $validateResult ?? $this->validateResult;
+
+ $createLabel = $this->labelText || $labelText;
+ $createLogo = $this->logoPath || $logoPath;
+
+ $qrCode = new QrCode(
+ data: $data ?? $this->data,
+ encoding: $encoding ?? $this->encoding,
+ errorCorrectionLevel: $errorCorrectionLevel ?? $this->errorCorrectionLevel,
+ size: $size ?? $this->size,
+ margin: $margin ?? $this->margin,
+ roundBlockSizeMode: $roundBlockSizeMode ?? $this->roundBlockSizeMode,
+ foregroundColor: $foregroundColor ?? $this->foregroundColor,
+ backgroundColor: $backgroundColor ?? $this->backgroundColor
+ );
+
+ $logo = $createLogo ? new Logo(
+ path: $logoPath ?? $this->logoPath,
+ resizeToWidth: $logoResizeToWidth ?? $this->logoResizeToWidth,
+ resizeToHeight: $logoResizeToHeight ?? $this->logoResizeToHeight,
+ punchoutBackground: $logoPunchoutBackground ?? $this->logoPunchoutBackground
+ ) : null;
+
+ $label = $createLabel ? new Label(
+ text: $labelText ?? $this->labelText,
+ font: $labelFont ?? $this->labelFont,
+ alignment: $labelAlignment ?? $this->labelAlignment,
+ margin: $labelMargin ?? $this->labelMargin,
+ textColor: $labelTextColor ?? $this->labelTextColor
+ ) : null;
+
+ $result = $writer->write($qrCode, $logo, $label, $writerOptions);
+
+ if ($validateResult && $writer instanceof ValidatingWriterInterface) {
+ $writer->validateResult($result, $qrCode->getData());
+ }
+
+ return $result;
+ }
+}
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..9a14dc0
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Builder/BuilderInterface.php
@@ -0,0 +1,45 @@
+|null $writerOptions */
+ public function build(
+ ?WriterInterface $writer = null,
+ ?array $writerOptions = null,
+ ?bool $validateResult = null,
+ // QrCode options
+ ?string $data = null,
+ ?EncodingInterface $encoding = null,
+ ?ErrorCorrectionLevel $errorCorrectionLevel = null,
+ ?int $size = null,
+ ?int $margin = null,
+ ?RoundBlockSizeMode $roundBlockSizeMode = null,
+ ?ColorInterface $foregroundColor = null,
+ ?ColorInterface $backgroundColor = null,
+ // Label options
+ ?string $labelText = null,
+ ?FontInterface $labelFont = null,
+ ?LabelAlignment $labelAlignment = null,
+ ?MarginInterface $labelMargin = null,
+ ?ColorInterface $labelTextColor = null,
+ // Logo options
+ ?string $logoPath = null,
+ ?int $logoResizeToWidth = null,
+ ?int $logoResizeToHeight = null,
+ ?bool $logoPunchoutBackground = null,
+ ): 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..13b9c96
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Builder/BuilderRegistry.php
@@ -0,0 +1,25 @@
+ */
+ private array $builders = [];
+
+ public function set(string $name, BuilderInterface $builder): void
+ {
+ $this->builders[$name] = $builder;
+ }
+
+ public function get(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];
+ }
+}
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..0d9fb37
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Builder/BuilderRegistryInterface.php
@@ -0,0 +1,12 @@
+ */
+ private int $red,
+ /** @var int<0, 255> */
+ private int $green,
+ /** @var int<0, 255> */
+ private int $blue,
+ /** @var int<0, 127> */
+ private int $alpha = 0,
+ ) {
+ }
+
+ 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 getHex(): string
+ {
+ return sprintf('#%02x%02x%02x', $this->red, $this->green, $this->blue);
+ }
+
+ 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..f009947
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Color/ColorInterface.php
@@ -0,0 +1,27 @@
+ */
+ public function getRed(): int;
+
+ /** @return int<0, 255> */
+ public function getGreen(): int;
+
+ /** @return int<0, 255> */
+ public function getBlue(): int;
+
+ /** @return int<0, 127> */
+ public function getAlpha(): int;
+
+ public function getOpacity(): float;
+
+ public function getHex(): string;
+
+ /** @return array */
+ 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..d6da27b
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Encoding/Encoding.php
@@ -0,0 +1,27 @@
+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..17748a4
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Encoding/EncodingInterface.php
@@ -0,0 +1,10 @@
+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..d4fd610
--- /dev/null
+++ b/vendor/endroid/qr-code/src/ImageData/LogoImageData.php
@@ -0,0 +1,159 @@
+getPath());
+
+ if (!is_string($data)) {
+ $errorDetails = error_get_last()['message'] ?? 'invalid data';
+ throw new \Exception(sprintf('Could not read logo image data from path "%s": %s', $logo->getPath(), $errorDetails));
+ }
+
+ 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());
+ }
+
+ if (!function_exists('imagecreatefromstring')) {
+ throw new \Exception('Function "imagecreatefromstring" does not exist: check your GD installation');
+ }
+
+ error_clear_last();
+ $image = @imagecreatefromstring($data);
+
+ if (!$image) {
+ $errorDetails = error_get_last()['message'] ?? 'invalid data';
+ throw new \Exception(sprintf('Unable to parse image data at path "%s": %s', $logo->getPath(), $errorDetails));
+ }
+
+ // 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) {
+ return new self($data, $image, $mimeType, $width, intval(imagesy($image) * $width / imagesx($image)), $logo->getPunchoutBackground());
+ }
+
+ // Only target height specified: calculate width
+ if (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;
+ }
+
+ public function getImage(): \GdImage
+ {
+ if (!$this->image instanceof \GdImage) {
+ throw new \Exception('SVG Images have no image resource');
+ }
+
+ 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
+ {
+ $headers = get_headers($url, true);
+
+ if (!is_array($headers)) {
+ throw new \Exception(sprintf('Could not retrieve headers to determine content type for logo URL "%s"', $url));
+ }
+
+ $headers = array_combine(array_map('strtolower', array_keys($headers)), $headers);
+
+ if (!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');
+ }
+
+ error_clear_last();
+ $mimeType = @mime_content_type($path);
+
+ if (!is_string($mimeType)) {
+ $errorDetails = error_get_last()['message'] ?? 'invalid data';
+ throw new \Exception(sprintf('Could not determine mime type: %s', $errorDetails));
+ }
+
+ 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/Font/Font.php b/vendor/endroid/qr-code/src/Label/Font/Font.php
new file mode 100644
index 0000000..e796c55
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Label/Font/Font.php
@@ -0,0 +1,32 @@
+assertValidPath($path);
+ }
+
+ private function assertValidPath(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;
+ }
+}
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..d7a7aba
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Label/Label.php
@@ -0,0 +1,49 @@
+text;
+ }
+
+ public function getFont(): FontInterface
+ {
+ return $this->font;
+ }
+
+ public function getAlignment(): LabelAlignment
+ {
+ return $this->alignment;
+ }
+
+ public function getMargin(): MarginInterface
+ {
+ return $this->margin;
+ }
+
+ public function getTextColor(): ColorInterface
+ {
+ return $this->textColor;
+ }
+}
diff --git a/vendor/endroid/qr-code/src/Label/LabelAlignment.php b/vendor/endroid/qr-code/src/Label/LabelAlignment.php
new file mode 100644
index 0000000..b609fe4
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Label/LabelAlignment.php
@@ -0,0 +1,12 @@
+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..bc4691f
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Logo/Logo.php
@@ -0,0 +1,36 @@
+path;
+ }
+
+ public function getResizeToWidth(): ?int
+ {
+ return $this->resizeToWidth;
+ }
+
+ public function getResizeToHeight(): ?int
+ {
+ return $this->resizeToHeight;
+ }
+
+ public function getPunchoutBackground(): bool
+ {
+ return $this->punchoutBackground;
+ }
+}
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 @@
+>> $blockValues */
+ public function __construct(
+ private array $blockValues,
+ int $size,
+ int $margin,
+ RoundBlockSizeMode $roundBlockSizeMode,
+ ) {
+ $blockSize = $size / $this->getBlockCount();
+ $innerSize = $size;
+ $outerSize = $size + 2 * $margin;
+
+ switch ($roundBlockSizeMode) {
+ case RoundBlockSizeMode::Enlarge:
+ $blockSize = intval(ceil($blockSize));
+ $innerSize = intval($blockSize * $this->getBlockCount());
+ $outerSize = $innerSize + 2 * $margin;
+ break;
+ case RoundBlockSizeMode::Shrink:
+ $blockSize = intval(floor($blockSize));
+ $innerSize = intval($blockSize * $this->getBlockCount());
+ $outerSize = $innerSize + 2 * $margin;
+ break;
+ case RoundBlockSizeMode::Margin:
+ $blockSize = intval(floor($blockSize));
+ $innerSize = intval($blockSize * $this->getBlockCount());
+ break;
+ }
+
+ if ($blockSize < 1) {
+ throw new BlockSizeTooSmallException('Too much data: increase image dimensions or lower error correction level');
+ }
+
+ $this->blockSize = $blockSize;
+ $this->innerSize = $innerSize;
+ $this->outerSize = $outerSize;
+ $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;
+ }
+
+ public function getEncoding(): EncodingInterface
+ {
+ return $this->encoding;
+ }
+
+ public function getErrorCorrectionLevel(): ErrorCorrectionLevel
+ {
+ return $this->errorCorrectionLevel;
+ }
+
+ public function getSize(): int
+ {
+ return $this->size;
+ }
+
+ public function getMargin(): int
+ {
+ return $this->margin;
+ }
+
+ public function getRoundBlockSizeMode(): RoundBlockSizeMode
+ {
+ return $this->roundBlockSizeMode;
+ }
+
+ public function getForegroundColor(): ColorInterface
+ {
+ return $this->foregroundColor;
+ }
+
+ public function getBackgroundColor(): ColorInterface
+ {
+ return $this->backgroundColor;
+ }
+}
diff --git a/vendor/endroid/qr-code/src/QrCodeInterface.php b/vendor/endroid/qr-code/src/QrCodeInterface.php
new file mode 100644
index 0000000..1a75726
--- /dev/null
+++ b/vendor/endroid/qr-code/src/QrCodeInterface.php
@@ -0,0 +1,27 @@
+create($qrCode);
+
+ return new BinaryResult($matrix);
+ }
+}
diff --git a/vendor/endroid/qr-code/src/Writer/ConsoleWriter.php b/vendor/endroid/qr-code/src/Writer/ConsoleWriter.php
new file mode 100644
index 0000000..e3bb7c3
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/ConsoleWriter.php
@@ -0,0 +1,23 @@
+create($qrCode);
+
+ return new ConsoleResult($matrix, $qrCode->getForegroundColor(), $qrCode->getBackgroundColor());
+ }
+}
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..8910a80
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/DebugWriter.php
@@ -0,0 +1,32 @@
+create($qrCode);
+
+ return new DebugResult($matrix, $qrCode, $logo, $label, $options);
+ }
+
+ public function validateResult(ResultInterface $result, string $expectedData): void
+ {
+ if (!$result instanceof DebugResult) {
+ throw new \Exception('Unable to write logo: instance of DebugResult expected');
+ }
+
+ $result->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..2f41967
--- /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($matrix, $lines);
+ }
+}
diff --git a/vendor/endroid/qr-code/src/Writer/GdTrait.php b/vendor/endroid/qr-code/src/Writer/GdTrait.php
new file mode 100644
index 0000000..a3069d6
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/GdTrait.php
@@ -0,0 +1,233 @@
+create($qrCode);
+ }
+
+ /** @param array $options */
+ public function writeGd(QrCodeInterface $qrCode, ?LogoInterface $logo = null, ?LabelInterface $label = null, array $options = []): GdResult
+ {
+ if (!extension_loaded('gd')) {
+ throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
+ }
+
+ $matrix = $this->getMatrix($qrCode);
+
+ $baseBlockSize = RoundBlockSizeMode::None === $qrCode->getRoundBlockSizeMode() ? 10 : intval($matrix->getBlockSize());
+ /** @var int<1, max> $baseImageSize */
+ $baseImageSize = $matrix->getBlockCount() * $baseBlockSize;
+ $baseImage = imagecreatetruecolor($baseImageSize, $baseImageSize);
+
+ if (!$baseImage) {
+ throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
+ }
+
+ $foregroundColor = imagecolorallocatealpha(
+ $baseImage,
+ $qrCode->getForegroundColor()->getRed(),
+ $qrCode->getForegroundColor()->getGreen(),
+ $qrCode->getForegroundColor()->getBlue(),
+ $qrCode->getForegroundColor()->getAlpha()
+ );
+
+ if (false === $foregroundColor) {
+ throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
+ }
+
+ $transparentColor = imagecolorallocatealpha($baseImage, 255, 255, 255, 127);
+
+ if (false === $transparentColor) {
+ throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
+ }
+
+ imagefill($baseImage, 0, 0, $transparentColor);
+
+ 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 - 1,
+ ($rowIndex + 1) * $baseBlockSize - 1,
+ $foregroundColor
+ );
+ }
+ }
+ }
+
+ /** @var int<1, max> $targetWidth */
+ $targetWidth = $matrix->getOuterSize();
+ /** @var int<1, max> $targetHeight */
+ $targetHeight = $matrix->getOuterSize();
+
+ if ($label instanceof LabelInterface) {
+ $labelImageData = LabelImageData::createForLabel($label);
+ $targetHeight += $labelImageData->getHeight() + $label->getMargin()->getTop() + $label->getMargin()->getBottom();
+ }
+
+ /** @var int<1, max> $targetHeight */
+ $targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
+
+ if (!$targetImage) {
+ throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
+ }
+
+ $backgroundColor = imagecolorallocatealpha(
+ $targetImage,
+ $qrCode->getBackgroundColor()->getRed(),
+ $qrCode->getBackgroundColor()->getGreen(),
+ $qrCode->getBackgroundColor()->getBlue(),
+ $qrCode->getBackgroundColor()->getAlpha()
+ );
+
+ if (false === $backgroundColor) {
+ throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly');
+ }
+
+ imagefill($targetImage, 0, 0, $backgroundColor);
+
+ imagecopyresampled(
+ $targetImage,
+ $baseImage,
+ $matrix->getMarginLeft(),
+ $matrix->getMarginLeft(),
+ 0,
+ 0,
+ $matrix->getInnerSize(),
+ $matrix->getInnerSize(),
+ imagesx($baseImage),
+ imagesy($baseImage)
+ );
+
+ if ($qrCode->getBackgroundColor()->getAlpha() > 0) {
+ imagesavealpha($targetImage, true);
+ }
+
+ $result = new GdResult($matrix, $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, GdResult $result): GdResult
+ {
+ $logoImageData = LogoImageData::createForLogo($logo);
+
+ if ('image/svg+xml' === $logoImageData->getMimeType()) {
+ throw new \Exception('GD Writer does not support SVG logo');
+ }
+
+ $targetImage = $result->getImage();
+ $matrix = $result->getMatrix();
+
+ if ($logoImageData->getPunchoutBackground()) {
+ $transparent = imagecolorallocatealpha($targetImage, 255, 255, 255, 127);
+
+ if (false === $transparent) {
+ throw new \Exception('Unable to allocate color: please check if the GD extension is enabled and configured correctly');
+ }
+
+ imagealphablending($targetImage, false);
+ $xOffsetStart = intval($matrix->getOuterSize() / 2 - $logoImageData->getWidth() / 2);
+ $yOffsetStart = intval($matrix->getOuterSize() / 2 - $logoImageData->getHeight() / 2);
+ for ($xOffset = $xOffsetStart; $xOffset < $xOffsetStart + $logoImageData->getWidth(); ++$xOffset) {
+ for ($yOffset = $yOffsetStart; $yOffset < $yOffsetStart + $logoImageData->getHeight(); ++$yOffset) {
+ imagesetpixel($targetImage, $xOffset, $yOffset, $transparent);
+ }
+ }
+ }
+
+ imagecopyresampled(
+ $targetImage,
+ $logoImageData->getImage(),
+ intval($matrix->getOuterSize() / 2 - $logoImageData->getWidth() / 2),
+ intval($matrix->getOuterSize() / 2 - $logoImageData->getHeight() / 2),
+ 0,
+ 0,
+ $logoImageData->getWidth(),
+ $logoImageData->getHeight(),
+ imagesx($logoImageData->getImage()),
+ imagesy($logoImageData->getImage())
+ );
+
+ return new GdResult($matrix, $targetImage);
+ }
+
+ private function addLabel(LabelInterface $label, GdResult $result): GdResult
+ {
+ $targetImage = $result->getImage();
+
+ $labelImageData = LabelImageData::createForLabel($label);
+
+ $textColor = imagecolorallocatealpha(
+ $targetImage,
+ $label->getTextColor()->getRed(),
+ $label->getTextColor()->getGreen(),
+ $label->getTextColor()->getBlue(),
+ $label->getTextColor()->getAlpha()
+ );
+
+ if (false === $textColor) {
+ throw new \Exception('Unable to allocate color: please check if the GD extension is enabled and configured correctly');
+ }
+
+ $x = intval(imagesx($targetImage) / 2 - $labelImageData->getWidth() / 2);
+ $y = imagesy($targetImage) - $label->getMargin()->getBottom();
+
+ if (LabelAlignment::Left === $label->getAlignment()) {
+ $x = $label->getMargin()->getLeft();
+ } elseif (LabelAlignment::Right === $label->getAlignment()) {
+ $x = imagesx($targetImage) - $labelImageData->getWidth() - $label->getMargin()->getRight();
+ }
+
+ imagettftext($targetImage, $label->getFont()->getSize(), 0, $x, $y, $textColor, $label->getFont()->getPath(), $label->getText());
+
+ return new GdResult($result->getMatrix(), $targetImage);
+ }
+
+ public function validateResult(ResultInterface $result, string $expectedData): void
+ {
+ $string = $result->getString();
+
+ if (!class_exists(QrReader::class)) {
+ throw ValidationException::createForMissingPackage('khanamiryan/qrcode-detector-decoder');
+ }
+
+ $reader = new QrReader($string, QrReader::SOURCE_TYPE_BLOB);
+ if ($reader->text() !== $expectedData) {
+ throw ValidationException::createForInvalidData($expectedData, strval($reader->text()));
+ }
+ }
+}
diff --git a/vendor/endroid/qr-code/src/Writer/GifWriter.php b/vendor/endroid/qr-code/src/Writer/GifWriter.php
new file mode 100644
index 0000000..52cc441
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/GifWriter.php
@@ -0,0 +1,23 @@
+writeGd($qrCode, $logo, $label, $options);
+
+ return new GifResult($gdResult->getMatrix(), $gdResult->getImage());
+ }
+}
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..3f0cd73
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/PdfWriter.php
@@ -0,0 +1,139 @@
+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', '', $label->getFont()->getSize());
+ $fpdf->Cell($matrix->getOuterSize(), 0, $label->getText(), 0, 0, 'C');
+ }
+
+ if (isset($options[self::WRITER_OPTION_LINK])) {
+ $link = $options[self::WRITER_OPTION_LINK];
+ $fpdf->Link($x, $y, $x + $matrix->getOuterSize(), $y + $matrix->getOuterSize(), $link);
+ }
+
+ return new PdfResult($matrix, $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) {
+ $imageSize = \getimagesize($logoPath);
+ if (!$imageSize) {
+ throw new \Exception(sprintf('Unable to read image size for logo "%s"', $logoPath));
+ }
+ [$logoSourceWidth, $logoSourceHeight] = $imageSize;
+
+ if (null === $logoWidth) {
+ $logoWidth = (int) $logoSourceWidth;
+ }
+
+ if (null === $logoHeight) {
+ $aspectRatio = $logoWidth / $logoSourceWidth;
+ $logoHeight = (int) ($logoSourceHeight * $aspectRatio);
+ }
+ }
+
+ $logoX = $x + $size / 2 - $logoWidth / 2;
+ $logoY = $y + $size / 2 - $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..1f6a51b
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/PngWriter.php
@@ -0,0 +1,43 @@
+getBackgroundColor()->getAlpha() > 0 || $qrCode->getForegroundColor()->getAlpha() > 0 => null,
+ $logo instanceof LogoInterface => null,
+ default => 16,
+ };
+ }
+
+ $gdResult = $this->writeGd($qrCode, $logo, $label, $options);
+
+ return new PngResult(
+ $gdResult->getMatrix(),
+ $gdResult->getImage(),
+ $options[self::WRITER_OPTION_COMPRESSION_LEVEL],
+ $options[self::WRITER_OPTION_NUMBER_OF_COLORS]
+ );
+ }
+}
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..b6547d2
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/AbstractResult.php
@@ -0,0 +1,31 @@
+matrix;
+ }
+
+ public function getDataUri(): string
+ {
+ return 'data:'.$this->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..386fb6a
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/BinaryResult.php
@@ -0,0 +1,35 @@
+getMatrix();
+
+ $binaryString = '';
+ for ($rowIndex = 0; $rowIndex < $matrix->getBlockCount(); ++$rowIndex) {
+ for ($columnIndex = 0; $columnIndex < $matrix->getBlockCount(); ++$columnIndex) {
+ $binaryString .= $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/ConsoleResult.php b/vendor/endroid/qr-code/src/Writer/Result/ConsoleResult.php
new file mode 100644
index 0000000..d3644db
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/ConsoleResult.php
@@ -0,0 +1,69 @@
+ ' ',
+ 1 => "\xe2\x96\x80",
+ 2 => "\xe2\x96\x84",
+ 3 => "\xe2\x96\x88",
+ ];
+
+ private string $colorEscapeCode;
+
+ public function __construct(
+ MatrixInterface $matrix,
+ ColorInterface $foreground,
+ ColorInterface $background,
+ ) {
+ parent::__construct($matrix);
+
+ $this->colorEscapeCode = sprintf(
+ "\e[38;2;%d;%d;%dm\e[48;2;%d;%d;%dm",
+ $foreground->getRed(),
+ $foreground->getGreen(),
+ $foreground->getBlue(),
+ $background->getRed(),
+ $background->getGreen(),
+ $background->getBlue()
+ );
+ }
+
+ public function getMimeType(): string
+ {
+ return 'text/plain';
+ }
+
+ public function getString(): string
+ {
+ $matrix = $this->getMatrix();
+
+ $side = $matrix->getBlockCount();
+ $marginLeft = $this->colorEscapeCode.self::TWO_BLOCKS[0].self::TWO_BLOCKS[0];
+ $marginRight = self::TWO_BLOCKS[0].self::TWO_BLOCKS[0]."\e[0m".PHP_EOL;
+ $marginVertical = $marginLeft.str_repeat(self::TWO_BLOCKS[0], $side).$marginRight;
+
+ $qrCodeString = $marginVertical;
+ for ($rowIndex = 0; $rowIndex < $side; $rowIndex += 2) {
+ $qrCodeString .= $marginLeft;
+ for ($columnIndex = 0; $columnIndex < $side; ++$columnIndex) {
+ $combined = $matrix->getBlockValue($rowIndex, $columnIndex);
+ if ($rowIndex + 1 < $side) {
+ $combined |= $matrix->getBlockValue($rowIndex + 1, $columnIndex) << 1;
+ }
+ $qrCodeString .= self::TWO_BLOCKS[$combined];
+ }
+ $qrCodeString .= $marginRight;
+ }
+ $qrCodeString .= $marginVertical;
+
+ return $qrCodeString;
+ }
+}
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..b632993
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/DebugResult.php
@@ -0,0 +1,74 @@
+ $options */
+ private readonly array $options = [],
+ ) {
+ parent::__construct($matrix);
+ }
+
+ 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();
+ $debugLines[] = 'Logo punchout background: '.($this->logo->getPunchoutBackground() ? 'true' : 'false');
+ }
+
+ 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..d801fd6
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/EpsResult.php
@@ -0,0 +1,28 @@
+ $lines */
+ private readonly array $lines,
+ ) {
+ parent::__construct($matrix);
+ }
+
+ 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/GdResult.php b/vendor/endroid/qr-code/src/Writer/Result/GdResult.php
new file mode 100644
index 0000000..a58c3e4
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/GdResult.php
@@ -0,0 +1,32 @@
+image;
+ }
+
+ public function getString(): string
+ {
+ throw new \Exception('You can only use this method in a concrete implementation');
+ }
+
+ public function getMimeType(): string
+ {
+ throw new \Exception('You can only use this method in a concrete implementation');
+ }
+}
diff --git a/vendor/endroid/qr-code/src/Writer/Result/GifResult.php b/vendor/endroid/qr-code/src/Writer/Result/GifResult.php
new file mode 100644
index 0000000..84b2497
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/GifResult.php
@@ -0,0 +1,21 @@
+image);
+
+ return strval(ob_get_clean());
+ }
+
+ public function getMimeType(): string
+ {
+ return 'image/gif';
+ }
+}
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..f7746a2
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/PdfResult.php
@@ -0,0 +1,32 @@
+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..8cdbc53
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/PngResult.php
@@ -0,0 +1,35 @@
+numberOfColors) {
+ imagetruecolortopalette($this->image, false, $this->numberOfColors);
+ }
+ imagepng($this->image, quality: $this->quality);
+
+ 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..2cd387e
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/ResultInterface.php
@@ -0,0 +1,20 @@
+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/Result/WebPResult.php b/vendor/endroid/qr-code/src/Writer/Result/WebPResult.php
new file mode 100644
index 0000000..735f128
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/Result/WebPResult.php
@@ -0,0 +1,35 @@
+image, quality: $this->quality);
+
+ return strval(ob_get_clean());
+ }
+
+ public function getMimeType(): string
+ {
+ return 'image/webp';
+ }
+}
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..9001279
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/SvgWriter.php
@@ -0,0 +1,174 @@
+create($qrCode);
+
+ $xml = new \SimpleXMLElement('');
+ $xml->addAttribute('version', '1.1');
+ if (!$options[self::WRITER_OPTION_EXCLUDE_SVG_WIDTH_AND_HEIGHT]) {
+ $xml->addAttribute('width', $matrix->getOuterSize().'px');
+ $xml->addAttribute('height', $matrix->getOuterSize().'px');
+ }
+ $xml->addAttribute('viewBox', '0 0 '.$matrix->getOuterSize().' '.$matrix->getOuterSize());
+
+ $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()));
+
+ if ($options[self::WRITER_OPTION_COMPACT]) {
+ $this->writePath($xml, $qrCode, $matrix);
+ } else {
+ $this->writeBlockDefinitions($xml, $qrCode, $matrix, $options);
+ }
+
+ $result = new SvgResult($matrix, $xml, boolval($options[self::WRITER_OPTION_EXCLUDE_XML_DECLARATION]));
+
+ if ($logo instanceof LogoInterface) {
+ $this->addLogo($logo, $result, $options);
+ }
+
+ return $result;
+ }
+
+ private function writePath(\SimpleXMLElement $xml, QrCodeInterface $qrCode, MatrixInterface $matrix): void
+ {
+ $path = '';
+ for ($rowIndex = 0; $rowIndex < $matrix->getBlockCount(); ++$rowIndex) {
+ $left = $matrix->getMarginLeft();
+ for ($columnIndex = 0; $columnIndex < $matrix->getBlockCount(); ++$columnIndex) {
+ if (1 === $matrix->getBlockValue($rowIndex, $columnIndex)) {
+ // When we are at the first column or when the previous column was 0 set new left
+ if (0 === $columnIndex || 0 === $matrix->getBlockValue($rowIndex, $columnIndex - 1)) {
+ $left = $matrix->getMarginLeft() + $matrix->getBlockSize() * $columnIndex;
+ }
+ // When we are at the
+ if ($columnIndex === $matrix->getBlockCount() - 1 || 0 === $matrix->getBlockValue($rowIndex, $columnIndex + 1)) {
+ $top = $matrix->getMarginLeft() + $matrix->getBlockSize() * $rowIndex;
+ $bottom = $matrix->getMarginLeft() + $matrix->getBlockSize() * ($rowIndex + 1);
+ $right = $matrix->getMarginLeft() + $matrix->getBlockSize() * ($columnIndex + 1);
+ $path .= 'M'.$this->formatNumber($left).','.$this->formatNumber($top);
+ $path .= 'L'.$this->formatNumber($right).','.$this->formatNumber($top);
+ $path .= 'L'.$this->formatNumber($right).','.$this->formatNumber($bottom);
+ $path .= 'L'.$this->formatNumber($left).','.$this->formatNumber($bottom).'Z';
+ }
+ }
+ }
+ }
+
+ $pathDefinition = $xml->addChild('path');
+ $pathDefinition->addAttribute('fill', '#'.sprintf('%02x%02x%02x', $qrCode->getForegroundColor()->getRed(), $qrCode->getForegroundColor()->getGreen(), $qrCode->getForegroundColor()->getBlue()));
+ $pathDefinition->addAttribute('fill-opacity', strval($qrCode->getForegroundColor()->getOpacity()));
+ $pathDefinition->addAttribute('d', $path);
+ }
+
+ /** @param array $options */
+ private function writeBlockDefinitions(\SimpleXMLElement $xml, QrCodeInterface $qrCode, MatrixInterface $matrix, array $options): void
+ {
+ $xml->addChild('defs');
+
+ $blockDefinition = $xml->defs->addChild('rect');
+ $blockDefinition->addAttribute('id', strval($options[self::WRITER_OPTION_BLOCK_ID]));
+ $blockDefinition->addAttribute('width', $this->formatNumber($matrix->getBlockSize()));
+ $blockDefinition->addAttribute('height', $this->formatNumber($matrix->getBlockSize()));
+ $blockDefinition->addAttribute('fill', '#'.sprintf('%02x%02x%02x', $qrCode->getForegroundColor()->getRed(), $qrCode->getForegroundColor()->getGreen(), $qrCode->getForegroundColor()->getBlue()));
+ $blockDefinition->addAttribute('fill-opacity', strval($qrCode->getForegroundColor()->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', $this->formatNumber($matrix->getMarginLeft() + $matrix->getBlockSize() * $columnIndex));
+ $block->addAttribute('y', $this->formatNumber($matrix->getMarginLeft() + $matrix->getBlockSize() * $rowIndex));
+ $block->addAttribute('xlink:href', '#'.$options[self::WRITER_OPTION_BLOCK_ID], 'http://www.w3.org/1999/xlink');
+ }
+ }
+ }
+ }
+
+ /** @param array $options */
+ private function addLogo(LogoInterface $logo, SvgResult $result, array $options): void
+ {
+ if ($logo->getPunchoutBackground()) {
+ throw new \Exception('The SVG writer does not support logo punchout background');
+ }
+
+ $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');
+
+ if ($options[self::WRITER_OPTION_FORCE_XLINK_HREF]) {
+ $imageDefinition->addAttribute('xlink:href', $logoImageData->createDataUri(), 'http://www.w3.org/1999/xlink');
+ } else {
+ $imageDefinition->addAttribute('href', $logoImageData->createDataUri());
+ }
+ }
+
+ private function formatNumber(float $number): string
+ {
+ $string = number_format($number, self::DECIMAL_PRECISION, '.', '');
+ $string = rtrim($string, '0');
+
+ return rtrim($string, '.');
+ }
+}
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 @@
+writeGd($qrCode, $logo, $label, $options);
+
+ return new WebPResult($gdResult->getMatrix(), $gdResult->getImage(), $options[self::WRITER_OPTION_QUALITY]);
+ }
+}
diff --git a/vendor/endroid/qr-code/src/Writer/WriterInterface.php b/vendor/endroid/qr-code/src/Writer/WriterInterface.php
new file mode 100644
index 0000000..66b233f
--- /dev/null
+++ b/vendor/endroid/qr-code/src/Writer/WriterInterface.php
@@ -0,0 +1,16 @@
+ $options */
+ public function write(QrCodeInterface $qrCode, ?LogoInterface $logo = null, ?LabelInterface $label = null, array $options = []): ResultInterface;
+}