branche initiale
This commit is contained in:
commit
a0b2c2a531
12
vendor/autoload.php
vendored
Executable file
12
vendor/autoload.php
vendored
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 50600) {
|
||||||
|
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInit6bb82695b2f28e8ee61f74ae2d5c5202::getLoader();
|
22
vendor/bacon/bacon-qr-code/LICENSE
vendored
Executable file
22
vendor/bacon/bacon-qr-code/LICENSE
vendored
Executable file
@ -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.
|
39
vendor/bacon/bacon-qr-code/README.md
vendored
Executable file
39
vendor/bacon/bacon-qr-code/README.md
vendored
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
# QR Code generator
|
||||||
|
|
||||||
|
[![PHP CI](https://github.com/Bacon/BaconQrCode/actions/workflows/ci.yml/badge.svg)](https://github.com/Bacon/BaconQrCode/actions/workflows/ci.yml)
|
||||||
|
[![codecov](https://codecov.io/gh/Bacon/BaconQrCode/branch/master/graph/badge.svg?token=rD0HcAiEEx)](https://codecov.io/gh/Bacon/BaconQrCode)
|
||||||
|
[![Latest Stable Version](https://poser.pugx.org/bacon/bacon-qr-code/v/stable)](https://packagist.org/packages/bacon/bacon-qr-code)
|
||||||
|
[![Total Downloads](https://poser.pugx.org/bacon/bacon-qr-code/downloads)](https://packagist.org/packages/bacon/bacon-qr-code)
|
||||||
|
[![License](https://poser.pugx.org/bacon/bacon-qr-code/license)](https://packagist.org/packages/bacon/bacon-qr-code)
|
||||||
|
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
BaconQrCode is a port of QR code portion of the ZXing library. It currently
|
||||||
|
only features the encoder part, but could later receive the decoder part as
|
||||||
|
well.
|
||||||
|
|
||||||
|
As the Reed Solomon codec implementation of the ZXing library performs quite
|
||||||
|
slow in PHP, it was exchanged with the implementation by Phil Karn.
|
||||||
|
|
||||||
|
|
||||||
|
## Example usage
|
||||||
|
```php
|
||||||
|
use BaconQrCode\Renderer\ImageRenderer;
|
||||||
|
use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
||||||
|
use BaconQrCode\Writer;
|
||||||
|
|
||||||
|
$renderer = new ImageRenderer(
|
||||||
|
new RendererStyle(400),
|
||||||
|
new ImagickImageBackEnd()
|
||||||
|
);
|
||||||
|
$writer = new Writer($renderer);
|
||||||
|
$writer->writeFile('Hello World!', 'qrcode.png');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available image renderer back ends
|
||||||
|
BaconQrCode comes with multiple back ends for rendering images. Currently included are the following:
|
||||||
|
|
||||||
|
- `ImagickImageBackEnd`: renders raster images using the Imagick library
|
||||||
|
- `SvgImageBackEnd`: renders SVG files using XMLWriter
|
||||||
|
- `EpsImageBackEnd`: renders EPS files
|
38
vendor/bacon/bacon-qr-code/composer.json
vendored
Executable file
38
vendor/bacon/bacon-qr-code/composer.json
vendored
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "bacon/bacon-qr-code",
|
||||||
|
"description": "BaconQrCode is a QR code generator for PHP.",
|
||||||
|
"license" : "BSD-2-Clause",
|
||||||
|
"homepage": "https://github.com/Bacon/BaconQrCode",
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"dasprid/enum": "^1.0.3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-imagick": "to generate QR code images"
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ben Scholzen 'DASPRiD'",
|
||||||
|
"email": "mail@dasprids.de",
|
||||||
|
"homepage": "https://dasprids.de/",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"BaconQrCode\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7 | ^8 | ^9",
|
||||||
|
"spatie/phpunit-snapshot-assertions": "^4.2.9",
|
||||||
|
"squizlabs/php_codesniffer": "^3.4",
|
||||||
|
"phly/keep-a-changelog": "^2.1"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"ocramius/package-versions": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
372
vendor/bacon/bacon-qr-code/src/Common/BitArray.php
vendored
Executable file
372
vendor/bacon/bacon-qr-code/src/Common/BitArray.php
vendored
Executable file
@ -0,0 +1,372 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use SplFixedArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple, fast array of bits.
|
||||||
|
*/
|
||||||
|
final class BitArray
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bits represented as an array of integers.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
private $bits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the bit array in bits.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new bit array with a given size.
|
||||||
|
*/
|
||||||
|
public function __construct(int $size = 0)
|
||||||
|
{
|
||||||
|
$this->size = $size;
|
||||||
|
$this->bits = SplFixedArray::fromArray(array_fill(0, ($this->size + 31) >> 3, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the size in bits.
|
||||||
|
*/
|
||||||
|
public function getSize() : int
|
||||||
|
{
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the size in bytes.
|
||||||
|
*/
|
||||||
|
public function getSizeInBytes() : int
|
||||||
|
{
|
||||||
|
return ($this->size + 7) >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the array has a minimum capacity.
|
||||||
|
*/
|
||||||
|
public function ensureCapacity(int $size) : void
|
||||||
|
{
|
||||||
|
if ($size > count($this->bits) << 5) {
|
||||||
|
$this->bits->setSize(($size + 31) >> 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a specific bit.
|
||||||
|
*/
|
||||||
|
public function get(int $i) : bool
|
||||||
|
{
|
||||||
|
return 0 !== ($this->bits[$i >> 5] & (1 << ($i & 0x1f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a specific bit.
|
||||||
|
*/
|
||||||
|
public function set(int $i) : void
|
||||||
|
{
|
||||||
|
$this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips a specific bit.
|
||||||
|
*/
|
||||||
|
public function flip(int $i) : void
|
||||||
|
{
|
||||||
|
$this->bits[$i >> 5] ^= 1 << ($i & 0x1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next set bit position from a given position.
|
||||||
|
*/
|
||||||
|
public function getNextSet(int $from) : int
|
||||||
|
{
|
||||||
|
if ($from >= $this->size) {
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bitsOffset = $from >> 5;
|
||||||
|
$currentBits = $this->bits[$bitsOffset];
|
||||||
|
$bitsLength = count($this->bits);
|
||||||
|
$currentBits &= ~((1 << ($from & 0x1f)) - 1);
|
||||||
|
|
||||||
|
while (0 === $currentBits) {
|
||||||
|
if (++$bitsOffset === $bitsLength) {
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentBits = $this->bits[$bitsOffset];
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits);
|
||||||
|
return $result > $this->size ? $this->size : $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next unset bit position from a given position.
|
||||||
|
*/
|
||||||
|
public function getNextUnset(int $from) : int
|
||||||
|
{
|
||||||
|
if ($from >= $this->size) {
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bitsOffset = $from >> 5;
|
||||||
|
$currentBits = ~$this->bits[$bitsOffset];
|
||||||
|
$bitsLength = count($this->bits);
|
||||||
|
$currentBits &= ~((1 << ($from & 0x1f)) - 1);
|
||||||
|
|
||||||
|
while (0 === $currentBits) {
|
||||||
|
if (++$bitsOffset === $bitsLength) {
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentBits = ~$this->bits[$bitsOffset];
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits);
|
||||||
|
return $result > $this->size ? $this->size : $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a bulk of bits.
|
||||||
|
*/
|
||||||
|
public function setBulk(int $i, int $newBits) : void
|
||||||
|
{
|
||||||
|
$this->bits[$i >> 5] = $newBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a range of bits.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if end is smaller than start
|
||||||
|
*/
|
||||||
|
public function setRange(int $start, int $end) : void
|
||||||
|
{
|
||||||
|
if ($end < $start) {
|
||||||
|
throw new InvalidArgumentException('End must be greater or equal to start');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($end === $start) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
--$end;
|
||||||
|
|
||||||
|
$firstInt = $start >> 5;
|
||||||
|
$lastInt = $end >> 5;
|
||||||
|
|
||||||
|
for ($i = $firstInt; $i <= $lastInt; ++$i) {
|
||||||
|
$firstBit = $i > $firstInt ? 0 : $start & 0x1f;
|
||||||
|
$lastBit = $i < $lastInt ? 31 : $end & 0x1f;
|
||||||
|
|
||||||
|
if (0 === $firstBit && 31 === $lastBit) {
|
||||||
|
$mask = 0x7fffffff;
|
||||||
|
} else {
|
||||||
|
$mask = 0;
|
||||||
|
|
||||||
|
for ($j = $firstBit; $j < $lastBit; ++$j) {
|
||||||
|
$mask |= 1 << $j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->bits[$i] = $this->bits[$i] | $mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the bit array, unsetting every bit.
|
||||||
|
*/
|
||||||
|
public function clear() : void
|
||||||
|
{
|
||||||
|
$bitsLength = count($this->bits);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $bitsLength; ++$i) {
|
||||||
|
$this->bits[$i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a range of bits is set or not set.
|
||||||
|
|
||||||
|
* @throws InvalidArgumentException if end is smaller than start
|
||||||
|
*/
|
||||||
|
public function isRange(int $start, int $end, bool $value) : bool
|
||||||
|
{
|
||||||
|
if ($end < $start) {
|
||||||
|
throw new InvalidArgumentException('End must be greater or equal to start');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($end === $start) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
--$end;
|
||||||
|
|
||||||
|
$firstInt = $start >> 5;
|
||||||
|
$lastInt = $end >> 5;
|
||||||
|
|
||||||
|
for ($i = $firstInt; $i <= $lastInt; ++$i) {
|
||||||
|
$firstBit = $i > $firstInt ? 0 : $start & 0x1f;
|
||||||
|
$lastBit = $i < $lastInt ? 31 : $end & 0x1f;
|
||||||
|
|
||||||
|
if (0 === $firstBit && 31 === $lastBit) {
|
||||||
|
$mask = 0x7fffffff;
|
||||||
|
} else {
|
||||||
|
$mask = 0;
|
||||||
|
|
||||||
|
for ($j = $firstBit; $j <= $lastBit; ++$j) {
|
||||||
|
$mask |= 1 << $j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($this->bits[$i] & $mask) !== ($value ? $mask : 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a bit to the array.
|
||||||
|
*/
|
||||||
|
public function appendBit(bool $bit) : void
|
||||||
|
{
|
||||||
|
$this->ensureCapacity($this->size + 1);
|
||||||
|
|
||||||
|
if ($bit) {
|
||||||
|
$this->bits[$this->size >> 5] = $this->bits[$this->size >> 5] | (1 << ($this->size & 0x1f));
|
||||||
|
}
|
||||||
|
|
||||||
|
++$this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a number of bits (up to 32) to the array.
|
||||||
|
|
||||||
|
* @throws InvalidArgumentException if num bits is not between 0 and 32
|
||||||
|
*/
|
||||||
|
public function appendBits(int $value, int $numBits) : void
|
||||||
|
{
|
||||||
|
if ($numBits < 0 || $numBits > 32) {
|
||||||
|
throw new InvalidArgumentException('Num bits must be between 0 and 32');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->ensureCapacity($this->size + $numBits);
|
||||||
|
|
||||||
|
for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) {
|
||||||
|
$this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) === 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends another bit array to this array.
|
||||||
|
*/
|
||||||
|
public function appendBitArray(self $other) : void
|
||||||
|
{
|
||||||
|
$otherSize = $other->getSize();
|
||||||
|
$this->ensureCapacity($this->size + $other->getSize());
|
||||||
|
|
||||||
|
for ($i = 0; $i < $otherSize; ++$i) {
|
||||||
|
$this->appendBit($other->get($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes an exclusive-or comparision on the current bit array.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if sizes don't match
|
||||||
|
*/
|
||||||
|
public function xorBits(self $other) : void
|
||||||
|
{
|
||||||
|
$bitsLength = count($this->bits);
|
||||||
|
$otherBits = $other->getBitArray();
|
||||||
|
|
||||||
|
if ($bitsLength !== count($otherBits)) {
|
||||||
|
throw new InvalidArgumentException('Sizes don\'t match');
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < $bitsLength; ++$i) {
|
||||||
|
$this->bits[$i] = $this->bits[$i] ^ $otherBits[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the bit array to a byte array.
|
||||||
|
*
|
||||||
|
* @return SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
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<int>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
313
vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php
vendored
Executable file
313
vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php
vendored
Executable file
@ -0,0 +1,313 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use SplFixedArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bit matrix.
|
||||||
|
*
|
||||||
|
* Represents a 2D matrix of bits. In function arguments below, and throughout
|
||||||
|
* the common module, x is the column position, and y is the row position. The
|
||||||
|
* ordering is always x, y. The origin is at the top-left.
|
||||||
|
*/
|
||||||
|
class BitMatrix
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Width of the bit matrix.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $width;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Height of the bit matrix.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size in bits of each individual row.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $rowSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bits representation.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
private $bits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException if a dimension is smaller than zero
|
||||||
|
*/
|
||||||
|
public function __construct(int $width, int $height = null)
|
||||||
|
{
|
||||||
|
if (null === $height) {
|
||||||
|
$height = $width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($width < 1 || $height < 1) {
|
||||||
|
throw new InvalidArgumentException('Both dimensions must be greater than zero');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->width = $width;
|
||||||
|
$this->height = $height;
|
||||||
|
$this->rowSize = ($width + 31) >> 5;
|
||||||
|
$this->bits = SplFixedArray::fromArray(array_fill(0, $this->rowSize * $height, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the requested bit, where true means black.
|
||||||
|
*/
|
||||||
|
public function get(int $x, int $y) : bool
|
||||||
|
{
|
||||||
|
$offset = $y * $this->rowSize + ($x >> 5);
|
||||||
|
return 0 !== (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the given bit to true.
|
||||||
|
*/
|
||||||
|
public function set(int $x, int $y) : void
|
||||||
|
{
|
||||||
|
$offset = $y * $this->rowSize + ($x >> 5);
|
||||||
|
$this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips the given bit.
|
||||||
|
*/
|
||||||
|
public function flip(int $x, int $y) : void
|
||||||
|
{
|
||||||
|
$offset = $y * $this->rowSize + ($x >> 5);
|
||||||
|
$this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all bits (set to false).
|
||||||
|
*/
|
||||||
|
public function clear() : void
|
||||||
|
{
|
||||||
|
$max = count($this->bits);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $max; ++$i) {
|
||||||
|
$this->bits[$i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a square region of the bit matrix to true.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if left or top are negative
|
||||||
|
* @throws InvalidArgumentException if width or height are smaller than 1
|
||||||
|
* @throws InvalidArgumentException if region does not fit into the matix
|
||||||
|
*/
|
||||||
|
public function setRegion(int $left, int $top, int $width, int $height) : void
|
||||||
|
{
|
||||||
|
if ($top < 0 || $left < 0) {
|
||||||
|
throw new InvalidArgumentException('Left and top must be non-negative');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($height < 1 || $width < 1) {
|
||||||
|
throw new InvalidArgumentException('Width and height must be at least 1');
|
||||||
|
}
|
||||||
|
|
||||||
|
$right = $left + $width;
|
||||||
|
$bottom = $top + $height;
|
||||||
|
|
||||||
|
if ($bottom > $this->height || $right > $this->width) {
|
||||||
|
throw new InvalidArgumentException('The region must fit inside the matrix');
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($y = $top; $y < $bottom; ++$y) {
|
||||||
|
$offset = $y * $this->rowSize;
|
||||||
|
|
||||||
|
for ($x = $left; $x < $right; ++$x) {
|
||||||
|
$index = $offset + ($x >> 5);
|
||||||
|
$this->bits[$index] = $this->bits[$index] | (1 << ($x & 0x1f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fast method to retrieve one row of data from the matrix as a BitArray.
|
||||||
|
*/
|
||||||
|
public function getRow(int $y, BitArray $row = null) : BitArray
|
||||||
|
{
|
||||||
|
if (null === $row || $row->getSize() < $this->width) {
|
||||||
|
$row = new BitArray($this->width);
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset = $y * $this->rowSize;
|
||||||
|
|
||||||
|
for ($x = 0; $x < $this->rowSize; ++$x) {
|
||||||
|
$row->setBulk($x << 5, $this->bits[$offset + $x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a row of data from a BitArray.
|
||||||
|
*/
|
||||||
|
public function setRow(int $y, BitArray $row) : void
|
||||||
|
{
|
||||||
|
$bits = $row->getBitArray();
|
||||||
|
|
||||||
|
for ($i = 0; $i < $this->rowSize; ++$i) {
|
||||||
|
$this->bits[$y * $this->rowSize + $i] = $bits[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is useful in detecting the enclosing rectangle of a 'pure' barcode.
|
||||||
|
*
|
||||||
|
* @return int[]|null
|
||||||
|
*/
|
||||||
|
public function getEnclosingRectangle() : ?array
|
||||||
|
{
|
||||||
|
$left = $this->width;
|
||||||
|
$top = $this->height;
|
||||||
|
$right = -1;
|
||||||
|
$bottom = -1;
|
||||||
|
|
||||||
|
for ($y = 0; $y < $this->height; ++$y) {
|
||||||
|
for ($x32 = 0; $x32 < $this->rowSize; ++$x32) {
|
||||||
|
$bits = $this->bits[$y * $this->rowSize + $x32];
|
||||||
|
|
||||||
|
if (0 !== $bits) {
|
||||||
|
if ($y < $top) {
|
||||||
|
$top = $y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($y > $bottom) {
|
||||||
|
$bottom = $y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($x32 * 32 < $left) {
|
||||||
|
$bit = 0;
|
||||||
|
|
||||||
|
while (($bits << (31 - $bit)) === 0) {
|
||||||
|
$bit++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($x32 * 32 + $bit) < $left) {
|
||||||
|
$left = $x32 * 32 + $bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($x32 * 32 + 31 > $right) {
|
||||||
|
$bit = 31;
|
||||||
|
|
||||||
|
while (0 === BitUtils::unsignedRightShift($bits, $bit)) {
|
||||||
|
--$bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($x32 * 32 + $bit) > $right) {
|
||||||
|
$right = $x32 * 32 + $bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$width = $right - $left;
|
||||||
|
$height = $bottom - $top;
|
||||||
|
|
||||||
|
if ($width < 0 || $height < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$left, $top, $width, $height];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the most top left set bit.
|
||||||
|
*
|
||||||
|
* This is useful in detecting a corner of a 'pure' barcode.
|
||||||
|
*
|
||||||
|
* @return int[]|null
|
||||||
|
*/
|
||||||
|
public function getTopLeftOnBit() : ?array
|
||||||
|
{
|
||||||
|
$bitsOffset = 0;
|
||||||
|
|
||||||
|
while ($bitsOffset < count($this->bits) && 0 === $this->bits[$bitsOffset]) {
|
||||||
|
++$bitsOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($this->bits) === $bitsOffset) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = intdiv($bitsOffset, $this->rowSize);
|
||||||
|
$y = ($bitsOffset % $this->rowSize) << 5;
|
||||||
|
|
||||||
|
$bits = $this->bits[$bitsOffset];
|
||||||
|
$bit = 0;
|
||||||
|
|
||||||
|
while (0 === ($bits << (31 - $bit))) {
|
||||||
|
++$bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x += $bit;
|
||||||
|
|
||||||
|
return [$x, $y];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the most bottom right set bit.
|
||||||
|
*
|
||||||
|
* This is useful in detecting a corner of a 'pure' barcode.
|
||||||
|
*
|
||||||
|
* @return int[]|null
|
||||||
|
*/
|
||||||
|
public function getBottomRightOnBit() : ?array
|
||||||
|
{
|
||||||
|
$bitsOffset = count($this->bits) - 1;
|
||||||
|
|
||||||
|
while ($bitsOffset >= 0 && 0 === $this->bits[$bitsOffset]) {
|
||||||
|
--$bitsOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bitsOffset < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = intdiv($bitsOffset, $this->rowSize);
|
||||||
|
$y = ($bitsOffset % $this->rowSize) << 5;
|
||||||
|
|
||||||
|
$bits = $this->bits[$bitsOffset];
|
||||||
|
$bit = 0;
|
||||||
|
|
||||||
|
while (0 === BitUtils::unsignedRightShift($bits, $bit)) {
|
||||||
|
--$bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x += $bit;
|
||||||
|
|
||||||
|
return [$x, $y];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the width of the matrix,
|
||||||
|
*/
|
||||||
|
public function getWidth() : int
|
||||||
|
{
|
||||||
|
return $this->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the height of the matrix.
|
||||||
|
*/
|
||||||
|
public function getHeight() : int
|
||||||
|
{
|
||||||
|
return $this->height;
|
||||||
|
}
|
||||||
|
}
|
41
vendor/bacon/bacon-qr-code/src/Common/BitUtils.php
vendored
Executable file
41
vendor/bacon/bacon-qr-code/src/Common/BitUtils.php
vendored
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General bit utilities.
|
||||||
|
*
|
||||||
|
* All utility methods are based on 32-bit integers and also work on 64-bit
|
||||||
|
* systems.
|
||||||
|
*/
|
||||||
|
final class BitUtils
|
||||||
|
{
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs an unsigned right shift.
|
||||||
|
*
|
||||||
|
* This is the same as the unsigned right shift operator ">>>" 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;
|
||||||
|
}
|
||||||
|
}
|
180
vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php
vendored
Executable file
180
vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php
vendored
Executable file
@ -0,0 +1,180 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use DASPRiD\Enum\AbstractEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 of ISO 18004.
|
||||||
|
*
|
||||||
|
* @method static self CP437()
|
||||||
|
* @method static self ISO8859_1()
|
||||||
|
* @method static self ISO8859_2()
|
||||||
|
* @method static self ISO8859_3()
|
||||||
|
* @method static self ISO8859_4()
|
||||||
|
* @method static self ISO8859_5()
|
||||||
|
* @method static self ISO8859_6()
|
||||||
|
* @method static self ISO8859_7()
|
||||||
|
* @method static self ISO8859_8()
|
||||||
|
* @method static self ISO8859_9()
|
||||||
|
* @method static self ISO8859_10()
|
||||||
|
* @method static self ISO8859_11()
|
||||||
|
* @method static self ISO8859_12()
|
||||||
|
* @method static self ISO8859_13()
|
||||||
|
* @method static self ISO8859_14()
|
||||||
|
* @method static self ISO8859_15()
|
||||||
|
* @method static self ISO8859_16()
|
||||||
|
* @method static self SJIS()
|
||||||
|
* @method static self CP1250()
|
||||||
|
* @method static self CP1251()
|
||||||
|
* @method static self CP1252()
|
||||||
|
* @method static self CP1256()
|
||||||
|
* @method static self UNICODE_BIG_UNMARKED()
|
||||||
|
* @method static self UTF8()
|
||||||
|
* @method static self ASCII()
|
||||||
|
* @method static self BIG5()
|
||||||
|
* @method static self GB18030()
|
||||||
|
* @method static self EUC_KR()
|
||||||
|
*/
|
||||||
|
final class CharacterSetEci extends AbstractEnum
|
||||||
|
{
|
||||||
|
protected const CP437 = [[0, 2]];
|
||||||
|
protected const ISO8859_1 = [[1, 3], 'ISO-8859-1'];
|
||||||
|
protected const ISO8859_2 = [[4], 'ISO-8859-2'];
|
||||||
|
protected const ISO8859_3 = [[5], 'ISO-8859-3'];
|
||||||
|
protected const ISO8859_4 = [[6], 'ISO-8859-4'];
|
||||||
|
protected const ISO8859_5 = [[7], 'ISO-8859-5'];
|
||||||
|
protected const ISO8859_6 = [[8], 'ISO-8859-6'];
|
||||||
|
protected const ISO8859_7 = [[9], 'ISO-8859-7'];
|
||||||
|
protected const ISO8859_8 = [[10], 'ISO-8859-8'];
|
||||||
|
protected const ISO8859_9 = [[11], 'ISO-8859-9'];
|
||||||
|
protected const ISO8859_10 = [[12], 'ISO-8859-10'];
|
||||||
|
protected const ISO8859_11 = [[13], 'ISO-8859-11'];
|
||||||
|
protected const ISO8859_12 = [[14], 'ISO-8859-12'];
|
||||||
|
protected const ISO8859_13 = [[15], 'ISO-8859-13'];
|
||||||
|
protected const ISO8859_14 = [[16], 'ISO-8859-14'];
|
||||||
|
protected const ISO8859_15 = [[17], 'ISO-8859-15'];
|
||||||
|
protected const ISO8859_16 = [[18], 'ISO-8859-16'];
|
||||||
|
protected const SJIS = [[20], 'Shift_JIS'];
|
||||||
|
protected const CP1250 = [[21], 'windows-1250'];
|
||||||
|
protected const CP1251 = [[22], 'windows-1251'];
|
||||||
|
protected const CP1252 = [[23], 'windows-1252'];
|
||||||
|
protected const CP1256 = [[24], 'windows-1256'];
|
||||||
|
protected const UNICODE_BIG_UNMARKED = [[25], 'UTF-16BE', 'UnicodeBig'];
|
||||||
|
protected const UTF8 = [[26], 'UTF-8'];
|
||||||
|
protected const ASCII = [[27, 170], 'US-ASCII'];
|
||||||
|
protected const BIG5 = [[28]];
|
||||||
|
protected const GB18030 = [[29], 'GB2312', 'EUC_CN', 'GBK'];
|
||||||
|
protected const EUC_KR = [[30], 'EUC-KR'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int[]
|
||||||
|
*/
|
||||||
|
private $values;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $otherEncodingNames;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<int, self>|null
|
||||||
|
*/
|
||||||
|
private static $valueToEci;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, self>|null
|
||||||
|
*/
|
||||||
|
private static $nameToEci;
|
||||||
|
|
||||||
|
public function __construct(array $values, string ...$otherEncodingNames)
|
||||||
|
{
|
||||||
|
$this->values = $values;
|
||||||
|
$this->otherEncodingNames = $otherEncodingNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the primary value.
|
||||||
|
*/
|
||||||
|
public function getValue() : int
|
||||||
|
{
|
||||||
|
return $this->values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets character set ECI by value.
|
||||||
|
*
|
||||||
|
* Returns the representing ECI of a given value, or null if it is legal but unsupported.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if value is not between 0 and 900
|
||||||
|
*/
|
||||||
|
public static function getCharacterSetEciByValue(int $value) : ?self
|
||||||
|
{
|
||||||
|
if ($value < 0 || $value >= 900) {
|
||||||
|
throw new InvalidArgumentException('Value must be between 0 and 900');
|
||||||
|
}
|
||||||
|
|
||||||
|
$valueToEci = self::valueToEci();
|
||||||
|
|
||||||
|
if (! array_key_exists($value, $valueToEci)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $valueToEci[$value];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns character set ECI by name.
|
||||||
|
*
|
||||||
|
* Returns the representing ECI of a given name, or null if it is legal but unsupported
|
||||||
|
*/
|
||||||
|
public static function getCharacterSetEciByName(string $name) : ?self
|
||||||
|
{
|
||||||
|
$nameToEci = self::nameToEci();
|
||||||
|
$name = strtolower($name);
|
||||||
|
|
||||||
|
if (! array_key_exists($name, $nameToEci)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nameToEci[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function valueToEci() : array
|
||||||
|
{
|
||||||
|
if (null !== self::$valueToEci) {
|
||||||
|
return self::$valueToEci;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$valueToEci = [];
|
||||||
|
|
||||||
|
foreach (self::values() as $eci) {
|
||||||
|
foreach ($eci->values as $value) {
|
||||||
|
self::$valueToEci[$value] = $eci;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$valueToEci;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function nameToEci() : array
|
||||||
|
{
|
||||||
|
if (null !== self::$nameToEci) {
|
||||||
|
return self::$nameToEci;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$nameToEci = [];
|
||||||
|
|
||||||
|
foreach (self::values() as $eci) {
|
||||||
|
self::$nameToEci[strtolower($eci->name())] = $eci;
|
||||||
|
|
||||||
|
foreach ($eci->otherEncodingNames as $name) {
|
||||||
|
self::$nameToEci[strtolower($name)] = $eci;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$nameToEci;
|
||||||
|
}
|
||||||
|
}
|
49
vendor/bacon/bacon-qr-code/src/Common/EcBlock.php
vendored
Executable file
49
vendor/bacon/bacon-qr-code/src/Common/EcBlock.php
vendored
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates the parameters for one error-correction block in one symbol version.
|
||||||
|
*
|
||||||
|
* This includes the number of data codewords, and the number of times a block with these parameters is used
|
||||||
|
* consecutively in the QR code version's format.
|
||||||
|
*/
|
||||||
|
final class EcBlock
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* How many times the block is used.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of data codewords.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $dataCodewords;
|
||||||
|
|
||||||
|
public function __construct(int $count, int $dataCodewords)
|
||||||
|
{
|
||||||
|
$this->count = $count;
|
||||||
|
$this->dataCodewords = $dataCodewords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns how many times the block is used.
|
||||||
|
*/
|
||||||
|
public function getCount() : int
|
||||||
|
{
|
||||||
|
return $this->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of data codewords.
|
||||||
|
*/
|
||||||
|
public function getDataCodewords() : int
|
||||||
|
{
|
||||||
|
return $this->dataCodewords;
|
||||||
|
}
|
||||||
|
}
|
74
vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php
vendored
Executable file
74
vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php
vendored
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a set of error-correction blocks in one symbol version.
|
||||||
|
*
|
||||||
|
* Most versions will use blocks of differing sizes within one version, so, this encapsulates the parameters for each
|
||||||
|
* set of blocks. It also holds the number of error-correction codewords per block since it will be the same across all
|
||||||
|
* blocks within one version.
|
||||||
|
*/
|
||||||
|
final class EcBlocks
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Number of EC codewords per block.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $ecCodewordsPerBlock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of EC blocks.
|
||||||
|
*
|
||||||
|
* @var EcBlock[]
|
||||||
|
*/
|
||||||
|
private $ecBlocks;
|
||||||
|
|
||||||
|
public function __construct(int $ecCodewordsPerBlock, EcBlock ...$ecBlocks)
|
||||||
|
{
|
||||||
|
$this->ecCodewordsPerBlock = $ecCodewordsPerBlock;
|
||||||
|
$this->ecBlocks = $ecBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of EC codewords per block.
|
||||||
|
*/
|
||||||
|
public function getEcCodewordsPerBlock() : int
|
||||||
|
{
|
||||||
|
return $this->ecCodewordsPerBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total number of EC block appearances.
|
||||||
|
*/
|
||||||
|
public function getNumBlocks() : int
|
||||||
|
{
|
||||||
|
$total = 0;
|
||||||
|
|
||||||
|
foreach ($this->ecBlocks as $ecBlock) {
|
||||||
|
$total += $ecBlock->getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total count of EC codewords.
|
||||||
|
*/
|
||||||
|
public function getTotalEcCodewords() : int
|
||||||
|
{
|
||||||
|
return $this->ecCodewordsPerBlock * $this->getNumBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the EC blocks included in this collection.
|
||||||
|
*
|
||||||
|
* @return EcBlock[]
|
||||||
|
*/
|
||||||
|
public function getEcBlocks() : array
|
||||||
|
{
|
||||||
|
return $this->ecBlocks;
|
||||||
|
}
|
||||||
|
}
|
63
vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php
vendored
Executable file
63
vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php
vendored
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\OutOfBoundsException;
|
||||||
|
use DASPRiD\Enum\AbstractEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing the four error correction levels.
|
||||||
|
*
|
||||||
|
* @method static self L() ~7% correction
|
||||||
|
* @method static self M() ~15% correction
|
||||||
|
* @method static self Q() ~25% correction
|
||||||
|
* @method static self H() ~30% correction
|
||||||
|
*/
|
||||||
|
final class ErrorCorrectionLevel extends AbstractEnum
|
||||||
|
{
|
||||||
|
protected const L = [0x01];
|
||||||
|
protected const M = [0x00];
|
||||||
|
protected const Q = [0x03];
|
||||||
|
protected const H = [0x02];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $bits;
|
||||||
|
|
||||||
|
protected function __construct(int $bits)
|
||||||
|
{
|
||||||
|
$this->bits = $bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws OutOfBoundsException if number of bits is invalid
|
||||||
|
*/
|
||||||
|
public static function forBits(int $bits) : self
|
||||||
|
{
|
||||||
|
switch ($bits) {
|
||||||
|
case 0:
|
||||||
|
return self::M();
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return self::L();
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return self::H();
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return self::Q();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new OutOfBoundsException('Invalid number of bits');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the two bits used to encode this error correction level.
|
||||||
|
*/
|
||||||
|
public function getBits() : int
|
||||||
|
{
|
||||||
|
return $this->bits;
|
||||||
|
}
|
||||||
|
}
|
203
vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php
vendored
Executable file
203
vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php
vendored
Executable file
@ -0,0 +1,203 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BaconQrCode
|
||||||
|
*
|
||||||
|
* @link http://github.com/Bacon/BaconQrCode For the canonical source repository
|
||||||
|
* @copyright 2013 Ben 'DASPRiD' Scholzen
|
||||||
|
* @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a QR Code's format information, including the data mask used and error correction level.
|
||||||
|
*/
|
||||||
|
class FormatInformation
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Mask for format information.
|
||||||
|
*/
|
||||||
|
private const FORMAT_INFO_MASK_QR = 0x5412;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup table for decoding format information.
|
||||||
|
*
|
||||||
|
* See ISO 18004:2006, Annex C, Table C.1
|
||||||
|
*/
|
||||||
|
private const FORMAT_INFO_DECODE_LOOKUP = [
|
||||||
|
[0x5412, 0x00],
|
||||||
|
[0x5125, 0x01],
|
||||||
|
[0x5e7c, 0x02],
|
||||||
|
[0x5b4b, 0x03],
|
||||||
|
[0x45f9, 0x04],
|
||||||
|
[0x40ce, 0x05],
|
||||||
|
[0x4f97, 0x06],
|
||||||
|
[0x4aa0, 0x07],
|
||||||
|
[0x77c4, 0x08],
|
||||||
|
[0x72f3, 0x09],
|
||||||
|
[0x7daa, 0x0a],
|
||||||
|
[0x789d, 0x0b],
|
||||||
|
[0x662f, 0x0c],
|
||||||
|
[0x6318, 0x0d],
|
||||||
|
[0x6c41, 0x0e],
|
||||||
|
[0x6976, 0x0f],
|
||||||
|
[0x1689, 0x10],
|
||||||
|
[0x13be, 0x11],
|
||||||
|
[0x1ce7, 0x12],
|
||||||
|
[0x19d0, 0x13],
|
||||||
|
[0x0762, 0x14],
|
||||||
|
[0x0255, 0x15],
|
||||||
|
[0x0d0c, 0x16],
|
||||||
|
[0x083b, 0x17],
|
||||||
|
[0x355f, 0x18],
|
||||||
|
[0x3068, 0x19],
|
||||||
|
[0x3f31, 0x1a],
|
||||||
|
[0x3a06, 0x1b],
|
||||||
|
[0x24b4, 0x1c],
|
||||||
|
[0x2183, 0x1d],
|
||||||
|
[0x2eda, 0x1e],
|
||||||
|
[0x2bed, 0x1f],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset i holds the number of 1 bits in the binary representation of i.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private const BITS_SET_IN_HALF_BYTE = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error correction level.
|
||||||
|
*
|
||||||
|
* @var ErrorCorrectionLevel
|
||||||
|
*/
|
||||||
|
private $ecLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data mask.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $dataMask;
|
||||||
|
|
||||||
|
protected function __construct(int $formatInfo)
|
||||||
|
{
|
||||||
|
$this->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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
76
vendor/bacon/bacon-qr-code/src/Common/Mode.php
vendored
Executable file
76
vendor/bacon/bacon-qr-code/src/Common/Mode.php
vendored
Executable file
@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
use DASPRiD\Enum\AbstractEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing various modes in which data can be encoded to bits.
|
||||||
|
*
|
||||||
|
* @method static self TERMINATOR()
|
||||||
|
* @method static self NUMERIC()
|
||||||
|
* @method static self ALPHANUMERIC()
|
||||||
|
* @method static self STRUCTURED_APPEND()
|
||||||
|
* @method static self BYTE()
|
||||||
|
* @method static self ECI()
|
||||||
|
* @method static self KANJI()
|
||||||
|
* @method static self FNC1_FIRST_POSITION()
|
||||||
|
* @method static self FNC1_SECOND_POSITION()
|
||||||
|
* @method static self HANZI()
|
||||||
|
*/
|
||||||
|
final class Mode extends AbstractEnum
|
||||||
|
{
|
||||||
|
protected const TERMINATOR = [[0, 0, 0], 0x00];
|
||||||
|
protected const NUMERIC = [[10, 12, 14], 0x01];
|
||||||
|
protected const ALPHANUMERIC = [[9, 11, 13], 0x02];
|
||||||
|
protected const STRUCTURED_APPEND = [[0, 0, 0], 0x03];
|
||||||
|
protected const BYTE = [[8, 16, 16], 0x04];
|
||||||
|
protected const ECI = [[0, 0, 0], 0x07];
|
||||||
|
protected const KANJI = [[8, 10, 12], 0x08];
|
||||||
|
protected const FNC1_FIRST_POSITION = [[0, 0, 0], 0x05];
|
||||||
|
protected const FNC1_SECOND_POSITION = [[0, 0, 0], 0x09];
|
||||||
|
protected const HANZI = [[8, 10, 12], 0x0d];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int[]
|
||||||
|
*/
|
||||||
|
private $characterCountBitsForVersions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $bits;
|
||||||
|
|
||||||
|
protected function __construct(array $characterCountBitsForVersions, int $bits)
|
||||||
|
{
|
||||||
|
$this->characterCountBitsForVersions = $characterCountBitsForVersions;
|
||||||
|
$this->bits = $bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bits used in a specific QR code version.
|
||||||
|
*/
|
||||||
|
public function getCharacterCountBits(Version $version) : int
|
||||||
|
{
|
||||||
|
$number = $version->getVersionNumber();
|
||||||
|
|
||||||
|
if ($number <= 9) {
|
||||||
|
$offset = 0;
|
||||||
|
} elseif ($number <= 26) {
|
||||||
|
$offset = 1;
|
||||||
|
} else {
|
||||||
|
$offset = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->characterCountBitsForVersions[$offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the four bits used to encode this mode.
|
||||||
|
*/
|
||||||
|
public function getBits() : int
|
||||||
|
{
|
||||||
|
return $this->bits;
|
||||||
|
}
|
||||||
|
}
|
468
vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php
vendored
Executable file
468
vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php
vendored
Executable file
@ -0,0 +1,468 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use BaconQrCode\Exception\RuntimeException;
|
||||||
|
use SplFixedArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reed-Solomon codec for 8-bit characters.
|
||||||
|
*
|
||||||
|
* Based on libfec by Phil Karn, KA9Q.
|
||||||
|
*/
|
||||||
|
final class ReedSolomonCodec
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Symbol size in bits.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $symbolSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block size in symbols.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $blockSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First root of RS code generator polynomial, index form.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $firstRoot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Primitive element to generate polynomial roots, index form.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $primitive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prim-th root of 1, index form.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $iPrimitive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RS code generator polynomial degree (number of roots).
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $numRoots;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Padding bytes at front of shortened block.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $padding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log lookup table.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray
|
||||||
|
*/
|
||||||
|
private $alphaTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anti-Log lookup table.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray
|
||||||
|
*/
|
||||||
|
private $indexOf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generator polynomial.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray
|
||||||
|
*/
|
||||||
|
private $generatorPoly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException if symbol size ist not between 0 and 8
|
||||||
|
* @throws InvalidArgumentException if first root is invalid
|
||||||
|
* @throws InvalidArgumentException if num roots is invalid
|
||||||
|
* @throws InvalidArgumentException if padding is invalid
|
||||||
|
* @throws RuntimeException if field generator polynomial is not primitive
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
int $symbolSize,
|
||||||
|
int $gfPoly,
|
||||||
|
int $firstRoot,
|
||||||
|
int $primitive,
|
||||||
|
int $numRoots,
|
||||||
|
int $padding
|
||||||
|
) {
|
||||||
|
if ($symbolSize < 0 || $symbolSize > 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;
|
||||||
|
}
|
||||||
|
}
|
596
vendor/bacon/bacon-qr-code/src/Common/Version.php
vendored
Executable file
596
vendor/bacon/bacon-qr-code/src/Common/Version.php
vendored
Executable file
@ -0,0 +1,596 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use SplFixedArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version representation.
|
||||||
|
*/
|
||||||
|
final class Version
|
||||||
|
{
|
||||||
|
private const VERSION_DECODE_INFO = [
|
||||||
|
0x07c94,
|
||||||
|
0x085bc,
|
||||||
|
0x09a99,
|
||||||
|
0x0a4d3,
|
||||||
|
0x0bbf6,
|
||||||
|
0x0c762,
|
||||||
|
0x0d847,
|
||||||
|
0x0e60d,
|
||||||
|
0x0f928,
|
||||||
|
0x10b78,
|
||||||
|
0x1145d,
|
||||||
|
0x12a17,
|
||||||
|
0x13532,
|
||||||
|
0x149a6,
|
||||||
|
0x15683,
|
||||||
|
0x168c9,
|
||||||
|
0x177ec,
|
||||||
|
0x18ec4,
|
||||||
|
0x191e1,
|
||||||
|
0x1afab,
|
||||||
|
0x1b08e,
|
||||||
|
0x1cc1a,
|
||||||
|
0x1d33f,
|
||||||
|
0x1ed75,
|
||||||
|
0x1f250,
|
||||||
|
0x209d5,
|
||||||
|
0x216f0,
|
||||||
|
0x228ba,
|
||||||
|
0x2379f,
|
||||||
|
0x24b0b,
|
||||||
|
0x2542e,
|
||||||
|
0x26a64,
|
||||||
|
0x27541,
|
||||||
|
0x28c69,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version number of this version.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $versionNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alignment pattern centers.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray
|
||||||
|
*/
|
||||||
|
private $alignmentPatternCenters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error correction blocks.
|
||||||
|
*
|
||||||
|
* @var EcBlocks[]
|
||||||
|
*/
|
||||||
|
private $ecBlocks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total number of codewords.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $totalCodewords;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached version instances.
|
||||||
|
*
|
||||||
|
* @var array<int, self>|null
|
||||||
|
*/
|
||||||
|
private static $versions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int[] $alignmentPatternCenters
|
||||||
|
*/
|
||||||
|
private function __construct(
|
||||||
|
int $versionNumber,
|
||||||
|
array $alignmentPatternCenters,
|
||||||
|
EcBlocks ...$ecBlocks
|
||||||
|
) {
|
||||||
|
$this->versionNumber = $versionNumber;
|
||||||
|
$this->alignmentPatternCenters = $alignmentPatternCenters;
|
||||||
|
$this->ecBlocks = $ecBlocks;
|
||||||
|
|
||||||
|
$totalCodewords = 0;
|
||||||
|
$ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock();
|
||||||
|
|
||||||
|
foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) {
|
||||||
|
$totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->totalCodewords = $totalCodewords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version number.
|
||||||
|
*/
|
||||||
|
public function getVersionNumber() : int
|
||||||
|
{
|
||||||
|
return $this->versionNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the alignment pattern centers.
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function getAlignmentPatternCenters() : array
|
||||||
|
{
|
||||||
|
return $this->alignmentPatternCenters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total number of codewords.
|
||||||
|
*/
|
||||||
|
public function getTotalCodewords() : int
|
||||||
|
{
|
||||||
|
return $this->totalCodewords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the dimension for the current version.
|
||||||
|
*/
|
||||||
|
public function getDimensionForVersion() : int
|
||||||
|
{
|
||||||
|
return 17 + 4 * $this->versionNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of EC blocks for a specific EC level.
|
||||||
|
*/
|
||||||
|
public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel) : EcBlocks
|
||||||
|
{
|
||||||
|
return $this->ecBlocks[$ecLevel->ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a provisional version number for a specific dimension.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if dimension is not 1 mod 4
|
||||||
|
*/
|
||||||
|
public static function getProvisionalVersionForDimension(int $dimension) : self
|
||||||
|
{
|
||||||
|
if (1 !== $dimension % 4) {
|
||||||
|
throw new InvalidArgumentException('Dimension is not 1 mod 4');
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::getVersionForNumber(intdiv($dimension - 17, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a version instance for a specific version number.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if version number is out of range
|
||||||
|
*/
|
||||||
|
public static function getVersionForNumber(int $versionNumber) : self
|
||||||
|
{
|
||||||
|
if ($versionNumber < 1 || $versionNumber > 40) {
|
||||||
|
throw new InvalidArgumentException('Version number must be between 1 and 40');
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::versions()[$versionNumber - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes version information from an integer and returns the version.
|
||||||
|
*/
|
||||||
|
public static function decodeVersionInformation(int $versionBits) : ?self
|
||||||
|
{
|
||||||
|
$bestDifference = PHP_INT_MAX;
|
||||||
|
$bestVersion = 0;
|
||||||
|
|
||||||
|
foreach (self::VERSION_DECODE_INFO as $i => $targetVersion) {
|
||||||
|
if ($targetVersion === $versionBits) {
|
||||||
|
return self::getVersionForNumber($i + 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
$bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion);
|
||||||
|
|
||||||
|
if ($bitsDifference < $bestDifference) {
|
||||||
|
$bestVersion = $i + 7;
|
||||||
|
$bestDifference = $bitsDifference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bestDifference <= 3) {
|
||||||
|
return self::getVersionForNumber($bestVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the function pattern for the current version.
|
||||||
|
*/
|
||||||
|
public function buildFunctionPattern() : BitMatrix
|
||||||
|
{
|
||||||
|
$dimension = $this->getDimensionForVersion();
|
||||||
|
$bitMatrix = new BitMatrix($dimension);
|
||||||
|
|
||||||
|
// Top left finder pattern + separator + format
|
||||||
|
$bitMatrix->setRegion(0, 0, 9, 9);
|
||||||
|
// Top right finder pattern + separator + format
|
||||||
|
$bitMatrix->setRegion($dimension - 8, 0, 8, 9);
|
||||||
|
// Bottom left finder pattern + separator + format
|
||||||
|
$bitMatrix->setRegion(0, $dimension - 8, 9, 8);
|
||||||
|
|
||||||
|
// Alignment patterns
|
||||||
|
$max = count($this->alignmentPatternCenters);
|
||||||
|
|
||||||
|
for ($x = 0; $x < $max; ++$x) {
|
||||||
|
$i = $this->alignmentPatternCenters[$x] - 2;
|
||||||
|
|
||||||
|
for ($y = 0; $y < $max; ++$y) {
|
||||||
|
if (($x === 0 && ($y === 0 || $y === $max - 1)) || ($x === $max - 1 && $y === 0)) {
|
||||||
|
// No alignment patterns near the three finder paterns
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertical timing pattern
|
||||||
|
$bitMatrix->setRegion(6, 9, 1, $dimension - 17);
|
||||||
|
// Horizontal timing pattern
|
||||||
|
$bitMatrix->setRegion(9, 6, $dimension - 17, 1);
|
||||||
|
|
||||||
|
if ($this->versionNumber > 6) {
|
||||||
|
// Version info, top right
|
||||||
|
$bitMatrix->setRegion($dimension - 11, 0, 3, 6);
|
||||||
|
// Version info, bottom left
|
||||||
|
$bitMatrix->setRegion(0, $dimension - 11, 6, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bitMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation for the version.
|
||||||
|
*/
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
return (string) $this->versionNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build and cache a specific version.
|
||||||
|
*
|
||||||
|
* See ISO 18004:2006 6.5.1 Table 9.
|
||||||
|
*
|
||||||
|
* @return array<int, self>
|
||||||
|
*/
|
||||||
|
private static function versions() : array
|
||||||
|
{
|
||||||
|
if (null !== self::$versions) {
|
||||||
|
return self::$versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$versions = [
|
||||||
|
new self(
|
||||||
|
1,
|
||||||
|
[],
|
||||||
|
new EcBlocks(7, new EcBlock(1, 19)),
|
||||||
|
new EcBlocks(10, new EcBlock(1, 16)),
|
||||||
|
new EcBlocks(13, new EcBlock(1, 13)),
|
||||||
|
new EcBlocks(17, new EcBlock(1, 9))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
2,
|
||||||
|
[6, 18],
|
||||||
|
new EcBlocks(10, new EcBlock(1, 34)),
|
||||||
|
new EcBlocks(16, new EcBlock(1, 28)),
|
||||||
|
new EcBlocks(22, new EcBlock(1, 22)),
|
||||||
|
new EcBlocks(28, new EcBlock(1, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
3,
|
||||||
|
[6, 22],
|
||||||
|
new EcBlocks(15, new EcBlock(1, 55)),
|
||||||
|
new EcBlocks(26, new EcBlock(1, 44)),
|
||||||
|
new EcBlocks(18, new EcBlock(2, 17)),
|
||||||
|
new EcBlocks(22, new EcBlock(2, 13))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
4,
|
||||||
|
[6, 26],
|
||||||
|
new EcBlocks(20, new EcBlock(1, 80)),
|
||||||
|
new EcBlocks(18, new EcBlock(2, 32)),
|
||||||
|
new EcBlocks(26, new EcBlock(3, 24)),
|
||||||
|
new EcBlocks(16, new EcBlock(4, 9))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
5,
|
||||||
|
[6, 30],
|
||||||
|
new EcBlocks(26, new EcBlock(1, 108)),
|
||||||
|
new EcBlocks(24, new EcBlock(2, 43)),
|
||||||
|
new EcBlocks(18, new EcBlock(2, 15), new EcBlock(2, 16)),
|
||||||
|
new EcBlocks(22, new EcBlock(2, 11), new EcBlock(2, 12))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
6,
|
||||||
|
[6, 34],
|
||||||
|
new EcBlocks(18, new EcBlock(2, 68)),
|
||||||
|
new EcBlocks(16, new EcBlock(4, 27)),
|
||||||
|
new EcBlocks(24, new EcBlock(4, 19)),
|
||||||
|
new EcBlocks(28, new EcBlock(4, 15))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
7,
|
||||||
|
[6, 22, 38],
|
||||||
|
new EcBlocks(20, new EcBlock(2, 78)),
|
||||||
|
new EcBlocks(18, new EcBlock(4, 31)),
|
||||||
|
new EcBlocks(18, new EcBlock(2, 14), new EcBlock(4, 15)),
|
||||||
|
new EcBlocks(26, new EcBlock(4, 13), new EcBlock(1, 14))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
8,
|
||||||
|
[6, 24, 42],
|
||||||
|
new EcBlocks(24, new EcBlock(2, 97)),
|
||||||
|
new EcBlocks(22, new EcBlock(2, 38), new EcBlock(2, 39)),
|
||||||
|
new EcBlocks(22, new EcBlock(4, 18), new EcBlock(2, 19)),
|
||||||
|
new EcBlocks(26, new EcBlock(4, 14), new EcBlock(2, 15))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
9,
|
||||||
|
[6, 26, 46],
|
||||||
|
new EcBlocks(30, new EcBlock(2, 116)),
|
||||||
|
new EcBlocks(22, new EcBlock(3, 36), new EcBlock(2, 37)),
|
||||||
|
new EcBlocks(20, new EcBlock(4, 16), new EcBlock(4, 17)),
|
||||||
|
new EcBlocks(24, new EcBlock(4, 12), new EcBlock(4, 13))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
10,
|
||||||
|
[6, 28, 50],
|
||||||
|
new EcBlocks(18, new EcBlock(2, 68), new EcBlock(2, 69)),
|
||||||
|
new EcBlocks(26, new EcBlock(4, 43), new EcBlock(1, 44)),
|
||||||
|
new EcBlocks(24, new EcBlock(6, 19), new EcBlock(2, 20)),
|
||||||
|
new EcBlocks(28, new EcBlock(6, 15), new EcBlock(2, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
11,
|
||||||
|
[6, 30, 54],
|
||||||
|
new EcBlocks(20, new EcBlock(4, 81)),
|
||||||
|
new EcBlocks(30, new EcBlock(1, 50), new EcBlock(4, 51)),
|
||||||
|
new EcBlocks(28, new EcBlock(4, 22), new EcBlock(4, 23)),
|
||||||
|
new EcBlocks(24, new EcBlock(3, 12), new EcBlock(8, 13))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
12,
|
||||||
|
[6, 32, 58],
|
||||||
|
new EcBlocks(24, new EcBlock(2, 92), new EcBlock(2, 93)),
|
||||||
|
new EcBlocks(22, new EcBlock(6, 36), new EcBlock(2, 37)),
|
||||||
|
new EcBlocks(26, new EcBlock(4, 20), new EcBlock(6, 21)),
|
||||||
|
new EcBlocks(28, new EcBlock(7, 14), new EcBlock(4, 15))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
13,
|
||||||
|
[6, 34, 62],
|
||||||
|
new EcBlocks(26, new EcBlock(4, 107)),
|
||||||
|
new EcBlocks(22, new EcBlock(8, 37), new EcBlock(1, 38)),
|
||||||
|
new EcBlocks(24, new EcBlock(8, 20), new EcBlock(4, 21)),
|
||||||
|
new EcBlocks(22, new EcBlock(12, 11), new EcBlock(4, 12))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
14,
|
||||||
|
[6, 26, 46, 66],
|
||||||
|
new EcBlocks(30, new EcBlock(3, 115), new EcBlock(1, 116)),
|
||||||
|
new EcBlocks(24, new EcBlock(4, 40), new EcBlock(5, 41)),
|
||||||
|
new EcBlocks(20, new EcBlock(11, 16), new EcBlock(5, 17)),
|
||||||
|
new EcBlocks(24, new EcBlock(11, 12), new EcBlock(5, 13))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
15,
|
||||||
|
[6, 26, 48, 70],
|
||||||
|
new EcBlocks(22, new EcBlock(5, 87), new EcBlock(1, 88)),
|
||||||
|
new EcBlocks(24, new EcBlock(5, 41), new EcBlock(5, 42)),
|
||||||
|
new EcBlocks(30, new EcBlock(5, 24), new EcBlock(7, 25)),
|
||||||
|
new EcBlocks(24, new EcBlock(11, 12), new EcBlock(7, 13))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
16,
|
||||||
|
[6, 26, 50, 74],
|
||||||
|
new EcBlocks(24, new EcBlock(5, 98), new EcBlock(1, 99)),
|
||||||
|
new EcBlocks(28, new EcBlock(7, 45), new EcBlock(3, 46)),
|
||||||
|
new EcBlocks(24, new EcBlock(15, 19), new EcBlock(2, 20)),
|
||||||
|
new EcBlocks(30, new EcBlock(3, 15), new EcBlock(13, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
17,
|
||||||
|
[6, 30, 54, 78],
|
||||||
|
new EcBlocks(28, new EcBlock(1, 107), new EcBlock(5, 108)),
|
||||||
|
new EcBlocks(28, new EcBlock(10, 46), new EcBlock(1, 47)),
|
||||||
|
new EcBlocks(28, new EcBlock(1, 22), new EcBlock(15, 23)),
|
||||||
|
new EcBlocks(28, new EcBlock(2, 14), new EcBlock(17, 15))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
18,
|
||||||
|
[6, 30, 56, 82],
|
||||||
|
new EcBlocks(30, new EcBlock(5, 120), new EcBlock(1, 121)),
|
||||||
|
new EcBlocks(26, new EcBlock(9, 43), new EcBlock(4, 44)),
|
||||||
|
new EcBlocks(28, new EcBlock(17, 22), new EcBlock(1, 23)),
|
||||||
|
new EcBlocks(28, new EcBlock(2, 14), new EcBlock(19, 15))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
19,
|
||||||
|
[6, 30, 58, 86],
|
||||||
|
new EcBlocks(28, new EcBlock(3, 113), new EcBlock(4, 114)),
|
||||||
|
new EcBlocks(26, new EcBlock(3, 44), new EcBlock(11, 45)),
|
||||||
|
new EcBlocks(26, new EcBlock(17, 21), new EcBlock(4, 22)),
|
||||||
|
new EcBlocks(26, new EcBlock(9, 13), new EcBlock(16, 14))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
20,
|
||||||
|
[6, 34, 62, 90],
|
||||||
|
new EcBlocks(28, new EcBlock(3, 107), new EcBlock(5, 108)),
|
||||||
|
new EcBlocks(26, new EcBlock(3, 41), new EcBlock(13, 42)),
|
||||||
|
new EcBlocks(30, new EcBlock(15, 24), new EcBlock(5, 25)),
|
||||||
|
new EcBlocks(28, new EcBlock(15, 15), new EcBlock(10, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
21,
|
||||||
|
[6, 28, 50, 72, 94],
|
||||||
|
new EcBlocks(28, new EcBlock(4, 116), new EcBlock(4, 117)),
|
||||||
|
new EcBlocks(26, new EcBlock(17, 42)),
|
||||||
|
new EcBlocks(28, new EcBlock(17, 22), new EcBlock(6, 23)),
|
||||||
|
new EcBlocks(30, new EcBlock(19, 16), new EcBlock(6, 17))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
22,
|
||||||
|
[6, 26, 50, 74, 98],
|
||||||
|
new EcBlocks(28, new EcBlock(2, 111), new EcBlock(7, 112)),
|
||||||
|
new EcBlocks(28, new EcBlock(17, 46)),
|
||||||
|
new EcBlocks(30, new EcBlock(7, 24), new EcBlock(16, 25)),
|
||||||
|
new EcBlocks(24, new EcBlock(34, 13))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
23,
|
||||||
|
[6, 30, 54, 78, 102],
|
||||||
|
new EcBlocks(30, new EcBlock(4, 121), new EcBlock(5, 122)),
|
||||||
|
new EcBlocks(28, new EcBlock(4, 47), new EcBlock(14, 48)),
|
||||||
|
new EcBlocks(30, new EcBlock(11, 24), new EcBlock(14, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(16, 15), new EcBlock(14, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
24,
|
||||||
|
[6, 28, 54, 80, 106],
|
||||||
|
new EcBlocks(30, new EcBlock(6, 117), new EcBlock(4, 118)),
|
||||||
|
new EcBlocks(28, new EcBlock(6, 45), new EcBlock(14, 46)),
|
||||||
|
new EcBlocks(30, new EcBlock(11, 24), new EcBlock(16, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(30, 16), new EcBlock(2, 17))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
25,
|
||||||
|
[6, 32, 58, 84, 110],
|
||||||
|
new EcBlocks(26, new EcBlock(8, 106), new EcBlock(4, 107)),
|
||||||
|
new EcBlocks(28, new EcBlock(8, 47), new EcBlock(13, 48)),
|
||||||
|
new EcBlocks(30, new EcBlock(7, 24), new EcBlock(22, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(22, 15), new EcBlock(13, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
26,
|
||||||
|
[6, 30, 58, 86, 114],
|
||||||
|
new EcBlocks(28, new EcBlock(10, 114), new EcBlock(2, 115)),
|
||||||
|
new EcBlocks(28, new EcBlock(19, 46), new EcBlock(4, 47)),
|
||||||
|
new EcBlocks(28, new EcBlock(28, 22), new EcBlock(6, 23)),
|
||||||
|
new EcBlocks(30, new EcBlock(33, 16), new EcBlock(4, 17))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
27,
|
||||||
|
[6, 34, 62, 90, 118],
|
||||||
|
new EcBlocks(30, new EcBlock(8, 122), new EcBlock(4, 123)),
|
||||||
|
new EcBlocks(28, new EcBlock(22, 45), new EcBlock(3, 46)),
|
||||||
|
new EcBlocks(30, new EcBlock(8, 23), new EcBlock(26, 24)),
|
||||||
|
new EcBlocks(30, new EcBlock(12, 15), new EcBlock(28, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
28,
|
||||||
|
[6, 26, 50, 74, 98, 122],
|
||||||
|
new EcBlocks(30, new EcBlock(3, 117), new EcBlock(10, 118)),
|
||||||
|
new EcBlocks(28, new EcBlock(3, 45), new EcBlock(23, 46)),
|
||||||
|
new EcBlocks(30, new EcBlock(4, 24), new EcBlock(31, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(11, 15), new EcBlock(31, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
29,
|
||||||
|
[6, 30, 54, 78, 102, 126],
|
||||||
|
new EcBlocks(30, new EcBlock(7, 116), new EcBlock(7, 117)),
|
||||||
|
new EcBlocks(28, new EcBlock(21, 45), new EcBlock(7, 46)),
|
||||||
|
new EcBlocks(30, new EcBlock(1, 23), new EcBlock(37, 24)),
|
||||||
|
new EcBlocks(30, new EcBlock(19, 15), new EcBlock(26, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
30,
|
||||||
|
[6, 26, 52, 78, 104, 130],
|
||||||
|
new EcBlocks(30, new EcBlock(5, 115), new EcBlock(10, 116)),
|
||||||
|
new EcBlocks(28, new EcBlock(19, 47), new EcBlock(10, 48)),
|
||||||
|
new EcBlocks(30, new EcBlock(15, 24), new EcBlock(25, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(23, 15), new EcBlock(25, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
31,
|
||||||
|
[6, 30, 56, 82, 108, 134],
|
||||||
|
new EcBlocks(30, new EcBlock(13, 115), new EcBlock(3, 116)),
|
||||||
|
new EcBlocks(28, new EcBlock(2, 46), new EcBlock(29, 47)),
|
||||||
|
new EcBlocks(30, new EcBlock(42, 24), new EcBlock(1, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(23, 15), new EcBlock(28, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
32,
|
||||||
|
[6, 34, 60, 86, 112, 138],
|
||||||
|
new EcBlocks(30, new EcBlock(17, 115)),
|
||||||
|
new EcBlocks(28, new EcBlock(10, 46), new EcBlock(23, 47)),
|
||||||
|
new EcBlocks(30, new EcBlock(10, 24), new EcBlock(35, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(19, 15), new EcBlock(35, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
33,
|
||||||
|
[6, 30, 58, 86, 114, 142],
|
||||||
|
new EcBlocks(30, new EcBlock(17, 115), new EcBlock(1, 116)),
|
||||||
|
new EcBlocks(28, new EcBlock(14, 46), new EcBlock(21, 47)),
|
||||||
|
new EcBlocks(30, new EcBlock(29, 24), new EcBlock(19, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(11, 15), new EcBlock(46, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
34,
|
||||||
|
[6, 34, 62, 90, 118, 146],
|
||||||
|
new EcBlocks(30, new EcBlock(13, 115), new EcBlock(6, 116)),
|
||||||
|
new EcBlocks(28, new EcBlock(14, 46), new EcBlock(23, 47)),
|
||||||
|
new EcBlocks(30, new EcBlock(44, 24), new EcBlock(7, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(59, 16), new EcBlock(1, 17))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
35,
|
||||||
|
[6, 30, 54, 78, 102, 126, 150],
|
||||||
|
new EcBlocks(30, new EcBlock(12, 121), new EcBlock(7, 122)),
|
||||||
|
new EcBlocks(28, new EcBlock(12, 47), new EcBlock(26, 48)),
|
||||||
|
new EcBlocks(30, new EcBlock(39, 24), new EcBlock(14, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(22, 15), new EcBlock(41, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
36,
|
||||||
|
[6, 24, 50, 76, 102, 128, 154],
|
||||||
|
new EcBlocks(30, new EcBlock(6, 121), new EcBlock(14, 122)),
|
||||||
|
new EcBlocks(28, new EcBlock(6, 47), new EcBlock(34, 48)),
|
||||||
|
new EcBlocks(30, new EcBlock(46, 24), new EcBlock(10, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(2, 15), new EcBlock(64, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
37,
|
||||||
|
[6, 28, 54, 80, 106, 132, 158],
|
||||||
|
new EcBlocks(30, new EcBlock(17, 122), new EcBlock(4, 123)),
|
||||||
|
new EcBlocks(28, new EcBlock(29, 46), new EcBlock(14, 47)),
|
||||||
|
new EcBlocks(30, new EcBlock(49, 24), new EcBlock(10, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(24, 15), new EcBlock(46, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
38,
|
||||||
|
[6, 32, 58, 84, 110, 136, 162],
|
||||||
|
new EcBlocks(30, new EcBlock(4, 122), new EcBlock(18, 123)),
|
||||||
|
new EcBlocks(28, new EcBlock(13, 46), new EcBlock(32, 47)),
|
||||||
|
new EcBlocks(30, new EcBlock(48, 24), new EcBlock(14, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(42, 15), new EcBlock(32, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
39,
|
||||||
|
[6, 26, 54, 82, 110, 138, 166],
|
||||||
|
new EcBlocks(30, new EcBlock(20, 117), new EcBlock(4, 118)),
|
||||||
|
new EcBlocks(28, new EcBlock(40, 47), new EcBlock(7, 48)),
|
||||||
|
new EcBlocks(30, new EcBlock(43, 24), new EcBlock(22, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(10, 15), new EcBlock(67, 16))
|
||||||
|
),
|
||||||
|
new self(
|
||||||
|
40,
|
||||||
|
[6, 30, 58, 86, 114, 142, 170],
|
||||||
|
new EcBlocks(30, new EcBlock(19, 118), new EcBlock(6, 119)),
|
||||||
|
new EcBlocks(28, new EcBlock(18, 47), new EcBlock(31, 48)),
|
||||||
|
new EcBlocks(30, new EcBlock(34, 24), new EcBlock(34, 25)),
|
||||||
|
new EcBlocks(30, new EcBlock(20, 15), new EcBlock(61, 16))
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
58
vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php
vendored
Executable file
58
vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php
vendored
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Encoder;
|
||||||
|
|
||||||
|
use SplFixedArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block pair.
|
||||||
|
*/
|
||||||
|
final class BlockPair
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Data bytes in the block.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
private $dataBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error correction bytes in the block.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
private $errorCorrectionBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new block pair.
|
||||||
|
*
|
||||||
|
* @param SplFixedArray<int> $data
|
||||||
|
* @param SplFixedArray<int> $errorCorrection
|
||||||
|
*/
|
||||||
|
public function __construct(SplFixedArray $data, SplFixedArray $errorCorrection)
|
||||||
|
{
|
||||||
|
$this->dataBytes = $data;
|
||||||
|
$this->errorCorrectionBytes = $errorCorrection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data bytes.
|
||||||
|
*
|
||||||
|
* @return SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
public function getDataBytes() : SplFixedArray
|
||||||
|
{
|
||||||
|
return $this->dataBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the error correction bytes.
|
||||||
|
*
|
||||||
|
* @return SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
public function getErrorCorrectionBytes() : SplFixedArray
|
||||||
|
{
|
||||||
|
return $this->errorCorrectionBytes;
|
||||||
|
}
|
||||||
|
}
|
150
vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php
vendored
Executable file
150
vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php
vendored
Executable file
@ -0,0 +1,150 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Encoder;
|
||||||
|
|
||||||
|
use SplFixedArray;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte matrix.
|
||||||
|
*/
|
||||||
|
final class ByteMatrix
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bytes in the matrix, represented as array.
|
||||||
|
*
|
||||||
|
* @var SplFixedArray<SplFixedArray<int>>
|
||||||
|
*/
|
||||||
|
private $bytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Width of the matrix.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $width;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Height of the matrix.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $height;
|
||||||
|
|
||||||
|
public function __construct(int $width, int $height)
|
||||||
|
{
|
||||||
|
$this->height = $height;
|
||||||
|
$this->width = $width;
|
||||||
|
$this->bytes = new SplFixedArray($height);
|
||||||
|
|
||||||
|
for ($y = 0; $y < $height; ++$y) {
|
||||||
|
$this->bytes[$y] = SplFixedArray::fromArray(array_fill(0, $width, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the width of the matrix.
|
||||||
|
*/
|
||||||
|
public function getWidth() : int
|
||||||
|
{
|
||||||
|
return $this->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the height of the matrix.
|
||||||
|
*/
|
||||||
|
public function getHeight() : int
|
||||||
|
{
|
||||||
|
return $this->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the internal representation of the matrix.
|
||||||
|
*
|
||||||
|
* @return SplFixedArray<SplFixedArray<int>>
|
||||||
|
*/
|
||||||
|
public function getArray() : SplFixedArray
|
||||||
|
{
|
||||||
|
return $this->bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Traversable<int>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
668
vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php
vendored
Executable file
668
vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php
vendored
Executable file
@ -0,0 +1,668 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Encoder;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\BitArray;
|
||||||
|
use BaconQrCode\Common\CharacterSetEci;
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Common\Mode;
|
||||||
|
use BaconQrCode\Common\ReedSolomonCodec;
|
||||||
|
use BaconQrCode\Common\Version;
|
||||||
|
use BaconQrCode\Exception\WriterException;
|
||||||
|
use SplFixedArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encoder.
|
||||||
|
*/
|
||||||
|
final class Encoder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Default byte encoding.
|
||||||
|
*/
|
||||||
|
public const DEFAULT_BYTE_MODE_ECODING = 'ISO-8859-1';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The original table is defined in the table 5 of JISX0510:2004 (p.19).
|
||||||
|
*/
|
||||||
|
private const ALPHANUMERIC_TABLE = [
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
|
||||||
|
36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
|
||||||
|
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
|
||||||
|
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Codec cache.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $codecs = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes "content" with the error correction level "ecLevel".
|
||||||
|
*/
|
||||||
|
public static function encode(
|
||||||
|
string $content,
|
||||||
|
ErrorCorrectionLevel $ecLevel,
|
||||||
|
string $encoding = self::DEFAULT_BYTE_MODE_ECODING,
|
||||||
|
?Version $forcedVersion = null
|
||||||
|
) : QrCode {
|
||||||
|
// Pick an encoding mode appropriate for the content. Note that this
|
||||||
|
// will not attempt to use multiple modes / segments even if that were
|
||||||
|
// more efficient. Would be nice.
|
||||||
|
$mode = self::chooseMode($content, $encoding);
|
||||||
|
|
||||||
|
// This will store the header information, like mode and length, as well
|
||||||
|
// as "header" segments like an ECI segment.
|
||||||
|
$headerBits = new BitArray();
|
||||||
|
|
||||||
|
// Append ECI segment if applicable
|
||||||
|
if (Mode::BYTE() === $mode && self::DEFAULT_BYTE_MODE_ECODING !== $encoding) {
|
||||||
|
$eci = CharacterSetEci::getCharacterSetEciByName($encoding);
|
||||||
|
|
||||||
|
if (null !== $eci) {
|
||||||
|
self::appendEci($eci, $headerBits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (With ECI in place,) Write the mode marker
|
||||||
|
self::appendModeInfo($mode, $headerBits);
|
||||||
|
|
||||||
|
// Collect data within the main segment, separately, to count its size
|
||||||
|
// if needed. Don't add it to main payload yet.
|
||||||
|
$dataBits = new BitArray();
|
||||||
|
self::appendBytes($content, $mode, $dataBits, $encoding);
|
||||||
|
|
||||||
|
// Hard part: need to know version to know how many bits length takes.
|
||||||
|
// But need to know how many bits it takes to know version. First we
|
||||||
|
// take a guess at version by assuming version will be the minimum, 1:
|
||||||
|
$provisionalBitsNeeded = $headerBits->getSize()
|
||||||
|
+ $mode->getCharacterCountBits(Version::getVersionForNumber(1))
|
||||||
|
+ $dataBits->getSize();
|
||||||
|
$provisionalVersion = self::chooseVersion($provisionalBitsNeeded, $ecLevel);
|
||||||
|
|
||||||
|
// Use that guess to calculate the right version. I am still not sure
|
||||||
|
// this works in 100% of cases.
|
||||||
|
$bitsNeeded = $headerBits->getSize()
|
||||||
|
+ $mode->getCharacterCountBits($provisionalVersion)
|
||||||
|
+ $dataBits->getSize();
|
||||||
|
$version = self::chooseVersion($bitsNeeded, $ecLevel);
|
||||||
|
|
||||||
|
if (null !== $forcedVersion) {
|
||||||
|
// Forced version check
|
||||||
|
if ($version->getVersionNumber() <= $forcedVersion->getVersionNumber()) {
|
||||||
|
// Calculated minimum version is same or equal as forced version
|
||||||
|
$version = $forcedVersion;
|
||||||
|
} else {
|
||||||
|
throw new WriterException(
|
||||||
|
'Invalid version! Calculated version: '
|
||||||
|
. $version->getVersionNumber()
|
||||||
|
. ', requested version: '
|
||||||
|
. $forcedVersion->getVersionNumber()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$headerAndDataBits = new BitArray();
|
||||||
|
$headerAndDataBits->appendBitArray($headerBits);
|
||||||
|
|
||||||
|
// Find "length" of main segment and write it.
|
||||||
|
$numLetters = (Mode::BYTE() === $mode ? $dataBits->getSizeInBytes() : strlen($content));
|
||||||
|
self::appendLengthInfo($numLetters, $version, $mode, $headerAndDataBits);
|
||||||
|
|
||||||
|
// Put data together into the overall payload.
|
||||||
|
$headerAndDataBits->appendBitArray($dataBits);
|
||||||
|
$ecBlocks = $version->getEcBlocksForLevel($ecLevel);
|
||||||
|
$numDataBytes = $version->getTotalCodewords() - $ecBlocks->getTotalEcCodewords();
|
||||||
|
|
||||||
|
// Terminate the bits properly.
|
||||||
|
self::terminateBits($numDataBytes, $headerAndDataBits);
|
||||||
|
|
||||||
|
// Interleave data bits with error correction code.
|
||||||
|
$finalBits = self::interleaveWithEcBytes(
|
||||||
|
$headerAndDataBits,
|
||||||
|
$version->getTotalCodewords(),
|
||||||
|
$numDataBytes,
|
||||||
|
$ecBlocks->getNumBlocks()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Choose the mask pattern.
|
||||||
|
$dimension = $version->getDimensionForVersion();
|
||||||
|
$matrix = new ByteMatrix($dimension, $dimension);
|
||||||
|
$maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix);
|
||||||
|
|
||||||
|
// Build the matrix.
|
||||||
|
MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix);
|
||||||
|
|
||||||
|
return new QrCode($mode, $ecLevel, $version, $maskPattern, $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the alphanumeric code for a byte.
|
||||||
|
*/
|
||||||
|
private static function getAlphanumericCode(int $code) : int
|
||||||
|
{
|
||||||
|
if (isset(self::ALPHANUMERIC_TABLE[$code])) {
|
||||||
|
return self::ALPHANUMERIC_TABLE[$code];
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chooses the best mode for a given content.
|
||||||
|
*/
|
||||||
|
private static function chooseMode(string $content, string $encoding = null) : Mode
|
||||||
|
{
|
||||||
|
if (null !== $encoding && 0 === strcasecmp($encoding, 'SHIFT-JIS')) {
|
||||||
|
return self::isOnlyDoubleByteKanji($content) ? Mode::KANJI() : Mode::BYTE();
|
||||||
|
}
|
||||||
|
|
||||||
|
$hasNumeric = false;
|
||||||
|
$hasAlphanumeric = false;
|
||||||
|
$contentLength = strlen($content);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $contentLength; ++$i) {
|
||||||
|
$char = $content[$i];
|
||||||
|
|
||||||
|
if (ctype_digit($char)) {
|
||||||
|
$hasNumeric = true;
|
||||||
|
} elseif (-1 !== self::getAlphanumericCode(ord($char))) {
|
||||||
|
$hasAlphanumeric = true;
|
||||||
|
} else {
|
||||||
|
return Mode::BYTE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hasAlphanumeric) {
|
||||||
|
return Mode::ALPHANUMERIC();
|
||||||
|
} elseif ($hasNumeric) {
|
||||||
|
return Mode::NUMERIC();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Mode::BYTE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the mask penalty for a matrix.
|
||||||
|
*/
|
||||||
|
private static function calculateMaskPenalty(ByteMatrix $matrix) : int
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
MaskUtil::applyMaskPenaltyRule1($matrix)
|
||||||
|
+ MaskUtil::applyMaskPenaltyRule2($matrix)
|
||||||
|
+ MaskUtil::applyMaskPenaltyRule3($matrix)
|
||||||
|
+ MaskUtil::applyMaskPenaltyRule4($matrix)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if content only consists of double-byte kanji characters.
|
||||||
|
*/
|
||||||
|
private static function isOnlyDoubleByteKanji(string $content) : bool
|
||||||
|
{
|
||||||
|
$bytes = @iconv('utf-8', 'SHIFT-JIS', $content);
|
||||||
|
|
||||||
|
if (false === $bytes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$length = strlen($bytes);
|
||||||
|
|
||||||
|
if (0 !== $length % 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < $length; $i += 2) {
|
||||||
|
$byte = $bytes[$i] & 0xff;
|
||||||
|
|
||||||
|
if (($byte < 0x81 || $byte > 0x9f) && $byte < 0xe0 || $byte > 0xeb) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chooses the best mask pattern for a matrix.
|
||||||
|
*/
|
||||||
|
private static function chooseMaskPattern(
|
||||||
|
BitArray $bits,
|
||||||
|
ErrorCorrectionLevel $ecLevel,
|
||||||
|
Version $version,
|
||||||
|
ByteMatrix $matrix
|
||||||
|
) : int {
|
||||||
|
$minPenalty = PHP_INT_MAX;
|
||||||
|
$bestMaskPattern = -1;
|
||||||
|
|
||||||
|
for ($maskPattern = 0; $maskPattern < QrCode::NUM_MASK_PATTERNS; ++$maskPattern) {
|
||||||
|
MatrixUtil::buildMatrix($bits, $ecLevel, $version, $maskPattern, $matrix);
|
||||||
|
$penalty = self::calculateMaskPenalty($matrix);
|
||||||
|
|
||||||
|
if ($penalty < $minPenalty) {
|
||||||
|
$minPenalty = $penalty;
|
||||||
|
$bestMaskPattern = $maskPattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bestMaskPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chooses the best version for the input.
|
||||||
|
*
|
||||||
|
* @throws WriterException if data is too big
|
||||||
|
*/
|
||||||
|
private static function chooseVersion(int $numInputBits, ErrorCorrectionLevel $ecLevel) : Version
|
||||||
|
{
|
||||||
|
for ($versionNum = 1; $versionNum <= 40; ++$versionNum) {
|
||||||
|
$version = Version::getVersionForNumber($versionNum);
|
||||||
|
$numBytes = $version->getTotalCodewords();
|
||||||
|
|
||||||
|
$ecBlocks = $version->getEcBlocksForLevel($ecLevel);
|
||||||
|
$numEcBytes = $ecBlocks->getTotalEcCodewords();
|
||||||
|
|
||||||
|
$numDataBytes = $numBytes - $numEcBytes;
|
||||||
|
$totalInputBytes = intdiv($numInputBits + 8, 8);
|
||||||
|
|
||||||
|
if ($numDataBytes >= $totalInputBytes) {
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new WriterException('Data too big');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminates the bits in a bit array.
|
||||||
|
*
|
||||||
|
* @throws WriterException if data bits cannot fit in the QR code
|
||||||
|
* @throws WriterException if bits size does not equal the capacity
|
||||||
|
*/
|
||||||
|
private static function terminateBits(int $numDataBytes, BitArray $bits) : void
|
||||||
|
{
|
||||||
|
$capacity = $numDataBytes << 3;
|
||||||
|
|
||||||
|
if ($bits->getSize() > $capacity) {
|
||||||
|
throw new WriterException('Data bits cannot fit in the QR code');
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < 4 && $bits->getSize() < $capacity; ++$i) {
|
||||||
|
$bits->appendBit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$numBitsInLastByte = $bits->getSize() & 0x7;
|
||||||
|
|
||||||
|
if ($numBitsInLastByte > 0) {
|
||||||
|
for ($i = $numBitsInLastByte; $i < 8; ++$i) {
|
||||||
|
$bits->appendBit(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$numPaddingBytes = $numDataBytes - $bits->getSizeInBytes();
|
||||||
|
|
||||||
|
for ($i = 0; $i < $numPaddingBytes; ++$i) {
|
||||||
|
$bits->appendBits(0 === ($i & 0x1) ? 0xec : 0x11, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bits->getSize() !== $capacity) {
|
||||||
|
throw new WriterException('Bits size does not equal capacity');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets number of data- and EC bytes for a block ID.
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
* @throws WriterException if block ID is too large
|
||||||
|
* @throws WriterException if EC bytes mismatch
|
||||||
|
* @throws WriterException if RS blocks mismatch
|
||||||
|
* @throws WriterException if total bytes mismatch
|
||||||
|
*/
|
||||||
|
private static function getNumDataBytesAndNumEcBytesForBlockId(
|
||||||
|
int $numTotalBytes,
|
||||||
|
int $numDataBytes,
|
||||||
|
int $numRsBlocks,
|
||||||
|
int $blockId
|
||||||
|
) : array {
|
||||||
|
if ($blockId >= $numRsBlocks) {
|
||||||
|
throw new WriterException('Block ID too large');
|
||||||
|
}
|
||||||
|
|
||||||
|
$numRsBlocksInGroup2 = $numTotalBytes % $numRsBlocks;
|
||||||
|
$numRsBlocksInGroup1 = $numRsBlocks - $numRsBlocksInGroup2;
|
||||||
|
$numTotalBytesInGroup1 = intdiv($numTotalBytes, $numRsBlocks);
|
||||||
|
$numTotalBytesInGroup2 = $numTotalBytesInGroup1 + 1;
|
||||||
|
$numDataBytesInGroup1 = intdiv($numDataBytes, $numRsBlocks);
|
||||||
|
$numDataBytesInGroup2 = $numDataBytesInGroup1 + 1;
|
||||||
|
$numEcBytesInGroup1 = $numTotalBytesInGroup1 - $numDataBytesInGroup1;
|
||||||
|
$numEcBytesInGroup2 = $numTotalBytesInGroup2 - $numDataBytesInGroup2;
|
||||||
|
|
||||||
|
if ($numEcBytesInGroup1 !== $numEcBytesInGroup2) {
|
||||||
|
throw new WriterException('EC bytes mismatch');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($numRsBlocks !== $numRsBlocksInGroup1 + $numRsBlocksInGroup2) {
|
||||||
|
throw new WriterException('RS blocks mismatch');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($numTotalBytes !==
|
||||||
|
(($numDataBytesInGroup1 + $numEcBytesInGroup1) * $numRsBlocksInGroup1)
|
||||||
|
+ (($numDataBytesInGroup2 + $numEcBytesInGroup2) * $numRsBlocksInGroup2)
|
||||||
|
) {
|
||||||
|
throw new WriterException('Total bytes mismatch');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($blockId < $numRsBlocksInGroup1) {
|
||||||
|
return [$numDataBytesInGroup1, $numEcBytesInGroup1];
|
||||||
|
} else {
|
||||||
|
return [$numDataBytesInGroup2, $numEcBytesInGroup2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interleaves data with EC bytes.
|
||||||
|
*
|
||||||
|
* @throws WriterException if number of bits and data bytes does not match
|
||||||
|
* @throws WriterException if data bytes does not match offset
|
||||||
|
* @throws WriterException if an interleaving error occurs
|
||||||
|
*/
|
||||||
|
private static function interleaveWithEcBytes(
|
||||||
|
BitArray $bits,
|
||||||
|
int $numTotalBytes,
|
||||||
|
int $numDataBytes,
|
||||||
|
int $numRsBlocks
|
||||||
|
) : BitArray {
|
||||||
|
if ($bits->getSizeInBytes() !== $numDataBytes) {
|
||||||
|
throw new WriterException('Number of bits and data bytes does not match');
|
||||||
|
}
|
||||||
|
|
||||||
|
$dataBytesOffset = 0;
|
||||||
|
$maxNumDataBytes = 0;
|
||||||
|
$maxNumEcBytes = 0;
|
||||||
|
|
||||||
|
$blocks = new SplFixedArray($numRsBlocks);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $numRsBlocks; ++$i) {
|
||||||
|
list($numDataBytesInBlock, $numEcBytesInBlock) = self::getNumDataBytesAndNumEcBytesForBlockId(
|
||||||
|
$numTotalBytes,
|
||||||
|
$numDataBytes,
|
||||||
|
$numRsBlocks,
|
||||||
|
$i
|
||||||
|
);
|
||||||
|
|
||||||
|
$size = $numDataBytesInBlock;
|
||||||
|
$dataBytes = $bits->toBytes(8 * $dataBytesOffset, $size);
|
||||||
|
$ecBytes = self::generateEcBytes($dataBytes, $numEcBytesInBlock);
|
||||||
|
$blocks[$i] = new BlockPair($dataBytes, $ecBytes);
|
||||||
|
|
||||||
|
$maxNumDataBytes = max($maxNumDataBytes, $size);
|
||||||
|
$maxNumEcBytes = max($maxNumEcBytes, count($ecBytes));
|
||||||
|
$dataBytesOffset += $numDataBytesInBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($numDataBytes !== $dataBytesOffset) {
|
||||||
|
throw new WriterException('Data bytes does not match offset');
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = new BitArray();
|
||||||
|
|
||||||
|
for ($i = 0; $i < $maxNumDataBytes; ++$i) {
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
$dataBytes = $block->getDataBytes();
|
||||||
|
|
||||||
|
if ($i < count($dataBytes)) {
|
||||||
|
$result->appendBits($dataBytes[$i], 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < $maxNumEcBytes; ++$i) {
|
||||||
|
foreach ($blocks as $block) {
|
||||||
|
$ecBytes = $block->getErrorCorrectionBytes();
|
||||||
|
|
||||||
|
if ($i < count($ecBytes)) {
|
||||||
|
$result->appendBits($ecBytes[$i], 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($numTotalBytes !== $result->getSizeInBytes()) {
|
||||||
|
throw new WriterException(
|
||||||
|
'Interleaving error: ' . $numTotalBytes . ' and ' . $result->getSizeInBytes() . ' differ'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates EC bytes for given data.
|
||||||
|
*
|
||||||
|
* @param SplFixedArray<int> $dataBytes
|
||||||
|
* @return SplFixedArray<int>
|
||||||
|
*/
|
||||||
|
private static function generateEcBytes(SplFixedArray $dataBytes, int $numEcBytesInBlock) : SplFixedArray
|
||||||
|
{
|
||||||
|
$numDataBytes = count($dataBytes);
|
||||||
|
$toEncode = new SplFixedArray($numDataBytes + $numEcBytesInBlock);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $numDataBytes; $i++) {
|
||||||
|
$toEncode[$i] = $dataBytes[$i] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ecBytes = new SplFixedArray($numEcBytesInBlock);
|
||||||
|
$codec = self::getCodec($numDataBytes, $numEcBytesInBlock);
|
||||||
|
$codec->encode($toEncode, $ecBytes);
|
||||||
|
|
||||||
|
return $ecBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an RS codec and caches it.
|
||||||
|
*/
|
||||||
|
private static function getCodec(int $numDataBytes, int $numEcBytesInBlock) : ReedSolomonCodec
|
||||||
|
{
|
||||||
|
$cacheId = $numDataBytes . '-' . $numEcBytesInBlock;
|
||||||
|
|
||||||
|
if (isset(self::$codecs[$cacheId])) {
|
||||||
|
return self::$codecs[$cacheId];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$codecs[$cacheId] = new ReedSolomonCodec(
|
||||||
|
8,
|
||||||
|
0x11d,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
$numEcBytesInBlock,
|
||||||
|
255 - $numDataBytes - $numEcBytesInBlock
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends mode information to a bit array.
|
||||||
|
*/
|
||||||
|
private static function appendModeInfo(Mode $mode, BitArray $bits) : void
|
||||||
|
{
|
||||||
|
$bits->appendBits($mode->getBits(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends length information to a bit array.
|
||||||
|
*
|
||||||
|
* @throws WriterException if num letters is bigger than expected
|
||||||
|
*/
|
||||||
|
private static function appendLengthInfo(int $numLetters, Version $version, Mode $mode, BitArray $bits) : void
|
||||||
|
{
|
||||||
|
$numBits = $mode->getCharacterCountBits($version);
|
||||||
|
|
||||||
|
if ($numLetters >= (1 << $numBits)) {
|
||||||
|
throw new WriterException($numLetters . ' is bigger than ' . ((1 << $numBits) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bits->appendBits($numLetters, $numBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends bytes to a bit array in a specific mode.
|
||||||
|
*
|
||||||
|
* @throws WriterException if an invalid mode was supplied
|
||||||
|
*/
|
||||||
|
private static function appendBytes(string $content, Mode $mode, BitArray $bits, string $encoding) : void
|
||||||
|
{
|
||||||
|
switch ($mode) {
|
||||||
|
case Mode::NUMERIC():
|
||||||
|
self::appendNumericBytes($content, $bits);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mode::ALPHANUMERIC():
|
||||||
|
self::appendAlphanumericBytes($content, $bits);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mode::BYTE():
|
||||||
|
self::append8BitBytes($content, $bits, $encoding);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mode::KANJI():
|
||||||
|
self::appendKanjiBytes($content, $bits);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new WriterException('Invalid mode: ' . $mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends numeric bytes to a bit array.
|
||||||
|
*/
|
||||||
|
private static function appendNumericBytes(string $content, BitArray $bits) : void
|
||||||
|
{
|
||||||
|
$length = strlen($content);
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
while ($i < $length) {
|
||||||
|
$num1 = (int) $content[$i];
|
||||||
|
|
||||||
|
if ($i + 2 < $length) {
|
||||||
|
// Encode three numeric letters in ten bits.
|
||||||
|
$num2 = (int) $content[$i + 1];
|
||||||
|
$num3 = (int) $content[$i + 2];
|
||||||
|
$bits->appendBits($num1 * 100 + $num2 * 10 + $num3, 10);
|
||||||
|
$i += 3;
|
||||||
|
} elseif ($i + 1 < $length) {
|
||||||
|
// Encode two numeric letters in seven bits.
|
||||||
|
$num2 = (int) $content[$i + 1];
|
||||||
|
$bits->appendBits($num1 * 10 + $num2, 7);
|
||||||
|
$i += 2;
|
||||||
|
} else {
|
||||||
|
// Encode one numeric letter in four bits.
|
||||||
|
$bits->appendBits($num1, 4);
|
||||||
|
++$i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends alpha-numeric bytes to a bit array.
|
||||||
|
*
|
||||||
|
* @throws WriterException if an invalid alphanumeric code was found
|
||||||
|
*/
|
||||||
|
private static function appendAlphanumericBytes(string $content, BitArray $bits) : void
|
||||||
|
{
|
||||||
|
$length = strlen($content);
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
while ($i < $length) {
|
||||||
|
$code1 = self::getAlphanumericCode(ord($content[$i]));
|
||||||
|
|
||||||
|
if (-1 === $code1) {
|
||||||
|
throw new WriterException('Invalid alphanumeric code');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i + 1 < $length) {
|
||||||
|
$code2 = self::getAlphanumericCode(ord($content[$i + 1]));
|
||||||
|
|
||||||
|
if (-1 === $code2) {
|
||||||
|
throw new WriterException('Invalid alphanumeric code');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode two alphanumeric letters in 11 bits.
|
||||||
|
$bits->appendBits($code1 * 45 + $code2, 11);
|
||||||
|
$i += 2;
|
||||||
|
} else {
|
||||||
|
// Encode one alphanumeric letter in six bits.
|
||||||
|
$bits->appendBits($code1, 6);
|
||||||
|
++$i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends regular 8-bit bytes to a bit array.
|
||||||
|
*
|
||||||
|
* @throws WriterException if content cannot be encoded to target encoding
|
||||||
|
*/
|
||||||
|
private static function append8BitBytes(string $content, BitArray $bits, string $encoding) : void
|
||||||
|
{
|
||||||
|
$bytes = @iconv('utf-8', $encoding, $content);
|
||||||
|
|
||||||
|
if (false === $bytes) {
|
||||||
|
throw new WriterException('Could not encode content to ' . $encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
$length = strlen($bytes);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $length; $i++) {
|
||||||
|
$bits->appendBits(ord($bytes[$i]), 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends KANJI bytes to a bit array.
|
||||||
|
*
|
||||||
|
* @throws WriterException if content does not seem to be encoded in SHIFT-JIS
|
||||||
|
* @throws WriterException if an invalid byte sequence occurs
|
||||||
|
*/
|
||||||
|
private static function appendKanjiBytes(string $content, BitArray $bits) : void
|
||||||
|
{
|
||||||
|
if (strlen($content) % 2 > 0) {
|
||||||
|
// We just do a simple length check here. The for loop will check
|
||||||
|
// individual characters.
|
||||||
|
throw new WriterException('Content does not seem to be encoded in SHIFT-JIS');
|
||||||
|
}
|
||||||
|
|
||||||
|
$length = strlen($content);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $length; $i += 2) {
|
||||||
|
$byte1 = ord($content[$i]) & 0xff;
|
||||||
|
$byte2 = ord($content[$i + 1]) & 0xff;
|
||||||
|
$code = ($byte1 << 8) | $byte2;
|
||||||
|
|
||||||
|
if ($code >= 0x8140 && $code <= 0x9ffc) {
|
||||||
|
$subtracted = $code - 0x8140;
|
||||||
|
} elseif ($code >= 0xe040 && $code <= 0xebbf) {
|
||||||
|
$subtracted = $code - 0xc140;
|
||||||
|
} else {
|
||||||
|
throw new WriterException('Invalid byte sequence');
|
||||||
|
}
|
||||||
|
|
||||||
|
$encoded = (($subtracted >> 8) * 0xc0) + ($subtracted & 0xff);
|
||||||
|
|
||||||
|
$bits->appendBits($encoded, 13);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends ECI information to a bit array.
|
||||||
|
*/
|
||||||
|
private static function appendEci(CharacterSetEci $eci, BitArray $bits) : void
|
||||||
|
{
|
||||||
|
$mode = Mode::ECI();
|
||||||
|
$bits->appendBits($mode->getBits(), 4);
|
||||||
|
$bits->appendBits($eci->getValue(), 8);
|
||||||
|
}
|
||||||
|
}
|
271
vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php
vendored
Executable file
271
vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php
vendored
Executable file
@ -0,0 +1,271 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Encoder;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\BitUtils;
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask utility.
|
||||||
|
*/
|
||||||
|
final class MaskUtil
|
||||||
|
{
|
||||||
|
/**#@+
|
||||||
|
* Penalty weights from section 6.8.2.1
|
||||||
|
*/
|
||||||
|
const N1 = 3;
|
||||||
|
const N2 = 3;
|
||||||
|
const N3 = 40;
|
||||||
|
const N4 = 10;
|
||||||
|
/**#@-*/
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies mask penalty rule 1 and returns the penalty.
|
||||||
|
*
|
||||||
|
* Finds repetitive cells with the same color and gives penalty to them.
|
||||||
|
* Example: 00000 or 11111.
|
||||||
|
*/
|
||||||
|
public static function applyMaskPenaltyRule1(ByteMatrix $matrix) : int
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
self::applyMaskPenaltyRule1Internal($matrix, true)
|
||||||
|
+ self::applyMaskPenaltyRule1Internal($matrix, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies mask penalty rule 2 and returns the penalty.
|
||||||
|
*
|
||||||
|
* Finds 2x2 blocks with the same color and gives penalty to them. This is
|
||||||
|
* actually equivalent to the spec's rule, which is to find MxN blocks and
|
||||||
|
* give a penalty proportional to (M-1)x(N-1), because this is the number of
|
||||||
|
* 2x2 blocks inside such a block.
|
||||||
|
*/
|
||||||
|
public static function applyMaskPenaltyRule2(ByteMatrix $matrix) : int
|
||||||
|
{
|
||||||
|
$penalty = 0;
|
||||||
|
$array = $matrix->getArray();
|
||||||
|
$width = $matrix->getWidth();
|
||||||
|
$height = $matrix->getHeight();
|
||||||
|
|
||||||
|
for ($y = 0; $y < $height - 1; ++$y) {
|
||||||
|
for ($x = 0; $x < $width - 1; ++$x) {
|
||||||
|
$value = $array[$y][$x];
|
||||||
|
|
||||||
|
if ($value === $array[$y][$x + 1]
|
||||||
|
&& $value === $array[$y + 1][$x]
|
||||||
|
&& $value === $array[$y + 1][$x + 1]
|
||||||
|
) {
|
||||||
|
++$penalty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::N2 * $penalty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies mask penalty rule 3 and returns the penalty.
|
||||||
|
*
|
||||||
|
* Finds consecutive cells of 00001011101 or 10111010000, and gives penalty
|
||||||
|
* to them. If we find patterns like 000010111010000, we give penalties
|
||||||
|
* twice (i.e. 40 * 2).
|
||||||
|
*/
|
||||||
|
public static function applyMaskPenaltyRule3(ByteMatrix $matrix) : int
|
||||||
|
{
|
||||||
|
$penalty = 0;
|
||||||
|
$array = $matrix->getArray();
|
||||||
|
$width = $matrix->getWidth();
|
||||||
|
$height = $matrix->getHeight();
|
||||||
|
|
||||||
|
for ($y = 0; $y < $height; ++$y) {
|
||||||
|
for ($x = 0; $x < $width; ++$x) {
|
||||||
|
if ($x + 6 < $width
|
||||||
|
&& 1 === $array[$y][$x]
|
||||||
|
&& 0 === $array[$y][$x + 1]
|
||||||
|
&& 1 === $array[$y][$x + 2]
|
||||||
|
&& 1 === $array[$y][$x + 3]
|
||||||
|
&& 1 === $array[$y][$x + 4]
|
||||||
|
&& 0 === $array[$y][$x + 5]
|
||||||
|
&& 1 === $array[$y][$x + 6]
|
||||||
|
&& (
|
||||||
|
(
|
||||||
|
$x + 10 < $width
|
||||||
|
&& 0 === $array[$y][$x + 7]
|
||||||
|
&& 0 === $array[$y][$x + 8]
|
||||||
|
&& 0 === $array[$y][$x + 9]
|
||||||
|
&& 0 === $array[$y][$x + 10]
|
||||||
|
)
|
||||||
|
|| (
|
||||||
|
$x - 4 >= 0
|
||||||
|
&& 0 === $array[$y][$x - 1]
|
||||||
|
&& 0 === $array[$y][$x - 2]
|
||||||
|
&& 0 === $array[$y][$x - 3]
|
||||||
|
&& 0 === $array[$y][$x - 4]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$penalty += self::N3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($y + 6 < $height
|
||||||
|
&& 1 === $array[$y][$x]
|
||||||
|
&& 0 === $array[$y + 1][$x]
|
||||||
|
&& 1 === $array[$y + 2][$x]
|
||||||
|
&& 1 === $array[$y + 3][$x]
|
||||||
|
&& 1 === $array[$y + 4][$x]
|
||||||
|
&& 0 === $array[$y + 5][$x]
|
||||||
|
&& 1 === $array[$y + 6][$x]
|
||||||
|
&& (
|
||||||
|
(
|
||||||
|
$y + 10 < $height
|
||||||
|
&& 0 === $array[$y + 7][$x]
|
||||||
|
&& 0 === $array[$y + 8][$x]
|
||||||
|
&& 0 === $array[$y + 9][$x]
|
||||||
|
&& 0 === $array[$y + 10][$x]
|
||||||
|
)
|
||||||
|
|| (
|
||||||
|
$y - 4 >= 0
|
||||||
|
&& 0 === $array[$y - 1][$x]
|
||||||
|
&& 0 === $array[$y - 2][$x]
|
||||||
|
&& 0 === $array[$y - 3][$x]
|
||||||
|
&& 0 === $array[$y - 4][$x]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$penalty += self::N3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $penalty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies mask penalty rule 4 and returns the penalty.
|
||||||
|
*
|
||||||
|
* Calculates the ratio of dark cells and gives penalty if the ratio is far
|
||||||
|
* from 50%. It gives 10 penalty for 5% distance.
|
||||||
|
*/
|
||||||
|
public static function applyMaskPenaltyRule4(ByteMatrix $matrix) : int
|
||||||
|
{
|
||||||
|
$numDarkCells = 0;
|
||||||
|
|
||||||
|
$array = $matrix->getArray();
|
||||||
|
$width = $matrix->getWidth();
|
||||||
|
$height = $matrix->getHeight();
|
||||||
|
|
||||||
|
for ($y = 0; $y < $height; ++$y) {
|
||||||
|
$arrayY = $array[$y];
|
||||||
|
|
||||||
|
for ($x = 0; $x < $width; ++$x) {
|
||||||
|
if (1 === $arrayY[$x]) {
|
||||||
|
++$numDarkCells;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$numTotalCells = $height * $width;
|
||||||
|
$darkRatio = $numDarkCells / $numTotalCells;
|
||||||
|
$fixedPercentVariances = (int) (abs($darkRatio - 0.5) * 20);
|
||||||
|
|
||||||
|
return $fixedPercentVariances * self::N4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mask bit for "getMaskPattern" at "x" and "y".
|
||||||
|
*
|
||||||
|
* See 8.8 of JISX0510:2004 for mask pattern conditions.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if an invalid mask pattern was supplied
|
||||||
|
*/
|
||||||
|
public static function getDataMaskBit(int $maskPattern, int $x, int $y) : bool
|
||||||
|
{
|
||||||
|
switch ($maskPattern) {
|
||||||
|
case 0:
|
||||||
|
$intermediate = ($y + $x) & 0x1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
$intermediate = $y & 0x1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
$intermediate = $x % 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
$intermediate = ($y + $x) % 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
$intermediate = (BitUtils::unsignedRightShift($y, 1) + (int) ($x / 3)) & 0x1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
$temp = $y * $x;
|
||||||
|
$intermediate = ($temp & 0x1) + ($temp % 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
$temp = $y * $x;
|
||||||
|
$intermediate = (($temp & 0x1) + ($temp % 3)) & 0x1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
$temp = $y * $x;
|
||||||
|
$intermediate = (($temp % 3) + (($y + $x) & 0x1)) & 0x1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new InvalidArgumentException('Invalid mask pattern: ' . $maskPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 == $intermediate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for applyMaskPenaltyRule1.
|
||||||
|
*
|
||||||
|
* We need this for doing this calculation in both vertical and horizontal
|
||||||
|
* orders respectively.
|
||||||
|
*/
|
||||||
|
private static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, bool $isHorizontal) : int
|
||||||
|
{
|
||||||
|
$penalty = 0;
|
||||||
|
$iLimit = $isHorizontal ? $matrix->getHeight() : $matrix->getWidth();
|
||||||
|
$jLimit = $isHorizontal ? $matrix->getWidth() : $matrix->getHeight();
|
||||||
|
$array = $matrix->getArray();
|
||||||
|
|
||||||
|
for ($i = 0; $i < $iLimit; ++$i) {
|
||||||
|
$numSameBitCells = 0;
|
||||||
|
$prevBit = -1;
|
||||||
|
|
||||||
|
for ($j = 0; $j < $jLimit; $j++) {
|
||||||
|
$bit = $isHorizontal ? $array[$i][$j] : $array[$j][$i];
|
||||||
|
|
||||||
|
if ($bit === $prevBit) {
|
||||||
|
++$numSameBitCells;
|
||||||
|
} else {
|
||||||
|
if ($numSameBitCells >= 5) {
|
||||||
|
$penalty += self::N1 + ($numSameBitCells - 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
$numSameBitCells = 1;
|
||||||
|
$prevBit = $bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($numSameBitCells >= 5) {
|
||||||
|
$penalty += self::N1 + ($numSameBitCells - 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $penalty;
|
||||||
|
}
|
||||||
|
}
|
513
vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php
vendored
Executable file
513
vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php
vendored
Executable file
@ -0,0 +1,513 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Encoder;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\BitArray;
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Common\Version;
|
||||||
|
use BaconQrCode\Exception\RuntimeException;
|
||||||
|
use BaconQrCode\Exception\WriterException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matrix utility.
|
||||||
|
*/
|
||||||
|
final class MatrixUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Position detection pattern.
|
||||||
|
*/
|
||||||
|
private const POSITION_DETECTION_PATTERN = [
|
||||||
|
[1, 1, 1, 1, 1, 1, 1],
|
||||||
|
[1, 0, 0, 0, 0, 0, 1],
|
||||||
|
[1, 0, 1, 1, 1, 0, 1],
|
||||||
|
[1, 0, 1, 1, 1, 0, 1],
|
||||||
|
[1, 0, 1, 1, 1, 0, 1],
|
||||||
|
[1, 0, 0, 0, 0, 0, 1],
|
||||||
|
[1, 1, 1, 1, 1, 1, 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position adjustment pattern.
|
||||||
|
*/
|
||||||
|
private const POSITION_ADJUSTMENT_PATTERN = [
|
||||||
|
[1, 1, 1, 1, 1],
|
||||||
|
[1, 0, 0, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 0, 0, 1],
|
||||||
|
[1, 1, 1, 1, 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordinates for position adjustment patterns for each version.
|
||||||
|
*/
|
||||||
|
private const POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = [
|
||||||
|
[null, null, null, null, null, null, null], // Version 1
|
||||||
|
[ 6, 18, null, null, null, null, null], // Version 2
|
||||||
|
[ 6, 22, null, null, null, null, null], // Version 3
|
||||||
|
[ 6, 26, null, null, null, null, null], // Version 4
|
||||||
|
[ 6, 30, null, null, null, null, null], // Version 5
|
||||||
|
[ 6, 34, null, null, null, null, null], // Version 6
|
||||||
|
[ 6, 22, 38, null, null, null, null], // Version 7
|
||||||
|
[ 6, 24, 42, null, null, null, null], // Version 8
|
||||||
|
[ 6, 26, 46, null, null, null, null], // Version 9
|
||||||
|
[ 6, 28, 50, null, null, null, null], // Version 10
|
||||||
|
[ 6, 30, 54, null, null, null, null], // Version 11
|
||||||
|
[ 6, 32, 58, null, null, null, null], // Version 12
|
||||||
|
[ 6, 34, 62, null, null, null, null], // Version 13
|
||||||
|
[ 6, 26, 46, 66, null, null, null], // Version 14
|
||||||
|
[ 6, 26, 48, 70, null, null, null], // Version 15
|
||||||
|
[ 6, 26, 50, 74, null, null, null], // Version 16
|
||||||
|
[ 6, 30, 54, 78, null, null, null], // Version 17
|
||||||
|
[ 6, 30, 56, 82, null, null, null], // Version 18
|
||||||
|
[ 6, 30, 58, 86, null, null, null], // Version 19
|
||||||
|
[ 6, 34, 62, 90, null, null, null], // Version 20
|
||||||
|
[ 6, 28, 50, 72, 94, null, null], // Version 21
|
||||||
|
[ 6, 26, 50, 74, 98, null, null], // Version 22
|
||||||
|
[ 6, 30, 54, 78, 102, null, null], // Version 23
|
||||||
|
[ 6, 28, 54, 80, 106, null, null], // Version 24
|
||||||
|
[ 6, 32, 58, 84, 110, null, null], // Version 25
|
||||||
|
[ 6, 30, 58, 86, 114, null, null], // Version 26
|
||||||
|
[ 6, 34, 62, 90, 118, null, null], // Version 27
|
||||||
|
[ 6, 26, 50, 74, 98, 122, null], // Version 28
|
||||||
|
[ 6, 30, 54, 78, 102, 126, null], // Version 29
|
||||||
|
[ 6, 26, 52, 78, 104, 130, null], // Version 30
|
||||||
|
[ 6, 30, 56, 82, 108, 134, null], // Version 31
|
||||||
|
[ 6, 34, 60, 86, 112, 138, null], // Version 32
|
||||||
|
[ 6, 30, 58, 86, 114, 142, null], // Version 33
|
||||||
|
[ 6, 34, 62, 90, 118, 146, null], // Version 34
|
||||||
|
[ 6, 30, 54, 78, 102, 126, 150], // Version 35
|
||||||
|
[ 6, 24, 50, 76, 102, 128, 154], // Version 36
|
||||||
|
[ 6, 28, 54, 80, 106, 132, 158], // Version 37
|
||||||
|
[ 6, 32, 58, 84, 110, 136, 162], // Version 38
|
||||||
|
[ 6, 26, 54, 82, 110, 138, 166], // Version 39
|
||||||
|
[ 6, 30, 58, 86, 114, 142, 170], // Version 40
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type information coordinates.
|
||||||
|
*/
|
||||||
|
private const TYPE_INFO_COORDINATES = [
|
||||||
|
[8, 0],
|
||||||
|
[8, 1],
|
||||||
|
[8, 2],
|
||||||
|
[8, 3],
|
||||||
|
[8, 4],
|
||||||
|
[8, 5],
|
||||||
|
[8, 7],
|
||||||
|
[8, 8],
|
||||||
|
[7, 8],
|
||||||
|
[5, 8],
|
||||||
|
[4, 8],
|
||||||
|
[3, 8],
|
||||||
|
[2, 8],
|
||||||
|
[1, 8],
|
||||||
|
[0, 8],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version information polynomial.
|
||||||
|
*/
|
||||||
|
private const VERSION_INFO_POLY = 0x1f25;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type information polynomial.
|
||||||
|
*/
|
||||||
|
private const TYPE_INFO_POLY = 0x537;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type information mask pattern.
|
||||||
|
*/
|
||||||
|
private const TYPE_INFO_MASK_PATTERN = 0x5412;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears a given matrix.
|
||||||
|
*/
|
||||||
|
public static function clearMatrix(ByteMatrix $matrix) : void
|
||||||
|
{
|
||||||
|
$matrix->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() .')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
141
vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php
vendored
Executable file
141
vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php
vendored
Executable file
@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Encoder;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Common\Mode;
|
||||||
|
use BaconQrCode\Common\Version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QR code.
|
||||||
|
*/
|
||||||
|
final class QrCode
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Number of possible mask patterns.
|
||||||
|
*/
|
||||||
|
public const NUM_MASK_PATTERNS = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mode of the QR code.
|
||||||
|
*
|
||||||
|
* @var Mode
|
||||||
|
*/
|
||||||
|
private $mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EC level of the QR code.
|
||||||
|
*
|
||||||
|
* @var ErrorCorrectionLevel
|
||||||
|
*/
|
||||||
|
private $errorCorrectionLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version of the QR code.
|
||||||
|
*
|
||||||
|
* @var Version
|
||||||
|
*/
|
||||||
|
private $version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask pattern of the QR code.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $maskPattern = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matrix of the QR code.
|
||||||
|
*
|
||||||
|
* @var ByteMatrix
|
||||||
|
*/
|
||||||
|
private $matrix;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
Mode $mode,
|
||||||
|
ErrorCorrectionLevel $errorCorrectionLevel,
|
||||||
|
Version $version,
|
||||||
|
int $maskPattern,
|
||||||
|
ByteMatrix $matrix
|
||||||
|
) {
|
||||||
|
$this->mode = $mode;
|
||||||
|
$this->errorCorrectionLevel = $errorCorrectionLevel;
|
||||||
|
$this->version = $version;
|
||||||
|
$this->maskPattern = $maskPattern;
|
||||||
|
$this->matrix = $matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the mode.
|
||||||
|
*/
|
||||||
|
public function getMode() : Mode
|
||||||
|
{
|
||||||
|
return $this->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the EC level.
|
||||||
|
*/
|
||||||
|
public function getErrorCorrectionLevel() : ErrorCorrectionLevel
|
||||||
|
{
|
||||||
|
return $this->errorCorrectionLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version.
|
||||||
|
*/
|
||||||
|
public function getVersion() : Version
|
||||||
|
{
|
||||||
|
return $this->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the mask pattern.
|
||||||
|
*/
|
||||||
|
public function getMaskPattern() : int
|
||||||
|
{
|
||||||
|
return $this->maskPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the matrix.
|
||||||
|
*
|
||||||
|
* @return ByteMatrix
|
||||||
|
*/
|
||||||
|
public function getMatrix()
|
||||||
|
{
|
||||||
|
return $this->matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates whether a mask pattern is valid.
|
||||||
|
*/
|
||||||
|
public static function isValidMaskPattern(int $maskPattern) : bool
|
||||||
|
{
|
||||||
|
return $maskPattern > 0 && $maskPattern < self::NUM_MASK_PATTERNS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the QR code.
|
||||||
|
*/
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
$result = "<<\n"
|
||||||
|
. ' mode: ' . $this->mode . "\n"
|
||||||
|
. ' ecLevel: ' . $this->errorCorrectionLevel . "\n"
|
||||||
|
. ' version: ' . $this->version . "\n"
|
||||||
|
. ' maskPattern: ' . $this->maskPattern . "\n";
|
||||||
|
|
||||||
|
if ($this->matrix === null) {
|
||||||
|
$result .= " matrix: null\n";
|
||||||
|
} else {
|
||||||
|
$result .= " matrix:\n";
|
||||||
|
$result .= $this->matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result .= ">>\n";
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
10
vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php
vendored
Executable file
10
vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Exception;
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
interface ExceptionInterface extends Throwable
|
||||||
|
{
|
||||||
|
}
|
8
vendor/bacon/bacon-qr-code/src/Exception/InvalidArgumentException.php
vendored
Executable file
8
vendor/bacon/bacon-qr-code/src/Exception/InvalidArgumentException.php
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
8
vendor/bacon/bacon-qr-code/src/Exception/OutOfBoundsException.php
vendored
Executable file
8
vendor/bacon/bacon-qr-code/src/Exception/OutOfBoundsException.php
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
8
vendor/bacon/bacon-qr-code/src/Exception/RuntimeException.php
vendored
Executable file
8
vendor/bacon/bacon-qr-code/src/Exception/RuntimeException.php
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
8
vendor/bacon/bacon-qr-code/src/Exception/UnexpectedValueException.php
vendored
Executable file
8
vendor/bacon/bacon-qr-code/src/Exception/UnexpectedValueException.php
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class UnexpectedValueException extends \UnexpectedValueException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
8
vendor/bacon/bacon-qr-code/src/Exception/WriterException.php
vendored
Executable file
8
vendor/bacon/bacon-qr-code/src/Exception/WriterException.php
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class WriterException extends \RuntimeException implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
57
vendor/bacon/bacon-qr-code/src/Renderer/Color/Alpha.php
vendored
Executable file
57
vendor/bacon/bacon-qr-code/src/Renderer/Color/Alpha.php
vendored
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Color;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class Alpha implements ColorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $alpha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ColorInterface
|
||||||
|
*/
|
||||||
|
private $baseColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $alpha the alpha value, 0 to 100
|
||||||
|
*/
|
||||||
|
public function __construct(int $alpha, ColorInterface $baseColor)
|
||||||
|
{
|
||||||
|
if ($alpha < 0 || $alpha > 100) {
|
||||||
|
throw new Exception\InvalidArgumentException('Alpha must be between 0 and 100');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->alpha = $alpha;
|
||||||
|
$this->baseColor = $baseColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAlpha() : int
|
||||||
|
{
|
||||||
|
return $this->alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseColor() : ColorInterface
|
||||||
|
{
|
||||||
|
return $this->baseColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toRgb() : Rgb
|
||||||
|
{
|
||||||
|
return $this->baseColor->toRgb();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toCmyk() : Cmyk
|
||||||
|
{
|
||||||
|
return $this->baseColor->toCmyk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toGray() : Gray
|
||||||
|
{
|
||||||
|
return $this->baseColor->toGray();
|
||||||
|
}
|
||||||
|
}
|
103
vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php
vendored
Executable file
103
vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php
vendored
Executable file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Color;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class Cmyk implements ColorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $cyan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $magenta;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $yellow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $black;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $cyan the cyan amount, 0 to 100
|
||||||
|
* @param int $magenta the magenta amount, 0 to 100
|
||||||
|
* @param int $yellow the yellow amount, 0 to 100
|
||||||
|
* @param int $black the black amount, 0 to 100
|
||||||
|
*/
|
||||||
|
public function __construct(int $cyan, int $magenta, int $yellow, int $black)
|
||||||
|
{
|
||||||
|
if ($cyan < 0 || $cyan > 100) {
|
||||||
|
throw new Exception\InvalidArgumentException('Cyan must be between 0 and 100');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($magenta < 0 || $magenta > 100) {
|
||||||
|
throw new Exception\InvalidArgumentException('Magenta must be between 0 and 100');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($yellow < 0 || $yellow > 100) {
|
||||||
|
throw new Exception\InvalidArgumentException('Yellow must be between 0 and 100');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($black < 0 || $black > 100) {
|
||||||
|
throw new Exception\InvalidArgumentException('Black must be between 0 and 100');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cyan = $cyan;
|
||||||
|
$this->magenta = $magenta;
|
||||||
|
$this->yellow = $yellow;
|
||||||
|
$this->black = $black;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCyan() : int
|
||||||
|
{
|
||||||
|
return $this->cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMagenta() : int
|
||||||
|
{
|
||||||
|
return $this->magenta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getYellow() : int
|
||||||
|
{
|
||||||
|
return $this->yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlack() : int
|
||||||
|
{
|
||||||
|
return $this->black;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toRgb() : Rgb
|
||||||
|
{
|
||||||
|
$k = $this->black / 100;
|
||||||
|
$c = (-$k * $this->cyan + $k * 100 + $this->cyan) / 100;
|
||||||
|
$m = (-$k * $this->magenta + $k * 100 + $this->magenta) / 100;
|
||||||
|
$y = (-$k * $this->yellow + $k * 100 + $this->yellow) / 100;
|
||||||
|
|
||||||
|
return new Rgb(
|
||||||
|
(int) (-$c * 255 + 255),
|
||||||
|
(int) (-$m * 255 + 255),
|
||||||
|
(int) (-$y * 255 + 255)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toCmyk() : Cmyk
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toGray() : Gray
|
||||||
|
{
|
||||||
|
return $this->toRgb()->toGray();
|
||||||
|
}
|
||||||
|
}
|
22
vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php
vendored
Executable file
22
vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php
vendored
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Color;
|
||||||
|
|
||||||
|
interface ColorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Converts the color to RGB.
|
||||||
|
*/
|
||||||
|
public function toRgb() : Rgb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the color to CMYK.
|
||||||
|
*/
|
||||||
|
public function toCmyk() : Cmyk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the color to gray.
|
||||||
|
*/
|
||||||
|
public function toGray() : Gray;
|
||||||
|
}
|
46
vendor/bacon/bacon-qr-code/src/Renderer/Color/Gray.php
vendored
Executable file
46
vendor/bacon/bacon-qr-code/src/Renderer/Color/Gray.php
vendored
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Color;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class Gray implements ColorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $gray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $gray the gray value between 0 (black) and 100 (white)
|
||||||
|
*/
|
||||||
|
public function __construct(int $gray)
|
||||||
|
{
|
||||||
|
if ($gray < 0 || $gray > 100) {
|
||||||
|
throw new Exception\InvalidArgumentException('Gray must be between 0 and 100');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->gray = (int) $gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGray() : int
|
||||||
|
{
|
||||||
|
return $this->gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toRgb() : Rgb
|
||||||
|
{
|
||||||
|
return new Rgb((int) ($this->gray * 2.55), (int) ($this->gray * 2.55), (int) ($this->gray * 2.55));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toCmyk() : Cmyk
|
||||||
|
{
|
||||||
|
return new Cmyk(0, 0, 0, 100 - $this->gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toGray() : Gray
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
88
vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php
vendored
Executable file
88
vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php
vendored
Executable file
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Color;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception;
|
||||||
|
|
||||||
|
final class Rgb implements ColorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $red;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $green;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $blue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $red the red amount of the color, 0 to 255
|
||||||
|
* @param int $green the green amount of the color, 0 to 255
|
||||||
|
* @param int $blue the blue amount of the color, 0 to 255
|
||||||
|
*/
|
||||||
|
public function __construct(int $red, int $green, int $blue)
|
||||||
|
{
|
||||||
|
if ($red < 0 || $red > 255) {
|
||||||
|
throw new Exception\InvalidArgumentException('Red must be between 0 and 255');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($green < 0 || $green > 255) {
|
||||||
|
throw new Exception\InvalidArgumentException('Green must be between 0 and 255');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($blue < 0 || $blue > 255) {
|
||||||
|
throw new Exception\InvalidArgumentException('Blue must be between 0 and 255');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->red = $red;
|
||||||
|
$this->green = $green;
|
||||||
|
$this->blue = $blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRed() : int
|
||||||
|
{
|
||||||
|
return $this->red;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGreen() : int
|
||||||
|
{
|
||||||
|
return $this->green;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlue() : int
|
||||||
|
{
|
||||||
|
return $this->blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toRgb() : Rgb
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toCmyk() : Cmyk
|
||||||
|
{
|
||||||
|
$c = 1 - ($this->red / 255);
|
||||||
|
$m = 1 - ($this->green / 255);
|
||||||
|
$y = 1 - ($this->blue / 255);
|
||||||
|
$k = min($c, $m, $y);
|
||||||
|
|
||||||
|
return new Cmyk(
|
||||||
|
(int) (100 * ($c - $k) / (1 - $k)),
|
||||||
|
(int) (100 * ($m - $k) / (1 - $k)),
|
||||||
|
(int) (100 * ($y - $k) / (1 - $k)),
|
||||||
|
(int) (100 * $k)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toGray() : Gray
|
||||||
|
{
|
||||||
|
return new Gray((int) (($this->red * 0.21 + $this->green * 0.71 + $this->blue * 0.07) / 2.55));
|
||||||
|
}
|
||||||
|
}
|
38
vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php
vendored
Executable file
38
vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php
vendored
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Eye;
|
||||||
|
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines the style of two different eyes.
|
||||||
|
*/
|
||||||
|
final class CompositeEye implements EyeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var EyeInterface
|
||||||
|
*/
|
||||||
|
private $externalEye;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var EyeInterface
|
||||||
|
*/
|
||||||
|
private $internalEye;
|
||||||
|
|
||||||
|
public function __construct(EyeInterface $externalEye, EyeInterface $internalEye)
|
||||||
|
{
|
||||||
|
$this->externalEye = $externalEye;
|
||||||
|
$this->internalEye = $internalEye;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExternalPath() : Path
|
||||||
|
{
|
||||||
|
return $this->externalEye->getExternalPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInternalPath() : Path
|
||||||
|
{
|
||||||
|
return $this->internalEye->getInternalPath();
|
||||||
|
}
|
||||||
|
}
|
26
vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php
vendored
Executable file
26
vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php
vendored
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Eye;
|
||||||
|
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for describing the look of an eye.
|
||||||
|
*/
|
||||||
|
interface EyeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the path of the external eye element.
|
||||||
|
*
|
||||||
|
* The path origin point (0, 0) must be anchored at the middle of the path.
|
||||||
|
*/
|
||||||
|
public function getExternalPath() : Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path of the internal eye element.
|
||||||
|
*
|
||||||
|
* The path origin point (0, 0) must be anchored at the middle of the path.
|
||||||
|
*/
|
||||||
|
public function getInternalPath() : Path;
|
||||||
|
}
|
54
vendor/bacon/bacon-qr-code/src/Renderer/Eye/ModuleEye.php
vendored
Executable file
54
vendor/bacon/bacon-qr-code/src/Renderer/Eye/ModuleEye.php
vendored
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Eye;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\ByteMatrix;
|
||||||
|
use BaconQrCode\Renderer\Module\ModuleInterface;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders an eye based on a module renderer.
|
||||||
|
*/
|
||||||
|
final class ModuleEye implements EyeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ModuleInterface
|
||||||
|
*/
|
||||||
|
private $module;
|
||||||
|
|
||||||
|
public function __construct(ModuleInterface $module)
|
||||||
|
{
|
||||||
|
$this->module = $module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExternalPath() : Path
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(7, 7);
|
||||||
|
|
||||||
|
for ($x = 0; $x < 7; ++$x) {
|
||||||
|
$matrix->set($x, 0, 1);
|
||||||
|
$matrix->set($x, 6, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($y = 1; $y < 6; ++$y) {
|
||||||
|
$matrix->set(0, $y, 1);
|
||||||
|
$matrix->set(6, $y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->module->createPath($matrix)->translate(-3.5, -3.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInternalPath() : Path
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(3, 3);
|
||||||
|
|
||||||
|
for ($x = 0; $x < 3; ++$x) {
|
||||||
|
for ($y = 0; $y < 3; ++$y) {
|
||||||
|
$matrix->set($x, $y, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->module->createPath($matrix)->translate(-1.5, -1.5);
|
||||||
|
}
|
||||||
|
}
|
54
vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php
vendored
Executable file
54
vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php
vendored
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Eye;
|
||||||
|
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the inner eye as a circle.
|
||||||
|
*/
|
||||||
|
final class SimpleCircleEye implements EyeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var self|null
|
||||||
|
*/
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function instance() : self
|
||||||
|
{
|
||||||
|
return self::$instance ?: self::$instance = new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExternalPath() : Path
|
||||||
|
{
|
||||||
|
return (new Path())
|
||||||
|
->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()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
53
vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php
vendored
Executable file
53
vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php
vendored
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Eye;
|
||||||
|
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the eyes in their default square shape.
|
||||||
|
*/
|
||||||
|
final class SquareEye implements EyeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var self|null
|
||||||
|
*/
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function instance() : self
|
||||||
|
{
|
||||||
|
return self::$instance ?: self::$instance = new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExternalPath() : Path
|
||||||
|
{
|
||||||
|
return (new Path())
|
||||||
|
->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()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
376
vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php
vendored
Executable file
376
vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php
vendored
Executable file
@ -0,0 +1,376 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Image;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\RuntimeException;
|
||||||
|
use BaconQrCode\Renderer\Color\Alpha;
|
||||||
|
use BaconQrCode\Renderer\Color\Cmyk;
|
||||||
|
use BaconQrCode\Renderer\Color\ColorInterface;
|
||||||
|
use BaconQrCode\Renderer\Color\Gray;
|
||||||
|
use BaconQrCode\Renderer\Color\Rgb;
|
||||||
|
use BaconQrCode\Renderer\Path\Close;
|
||||||
|
use BaconQrCode\Renderer\Path\Curve;
|
||||||
|
use BaconQrCode\Renderer\Path\EllipticArc;
|
||||||
|
use BaconQrCode\Renderer\Path\Line;
|
||||||
|
use BaconQrCode\Renderer\Path\Move;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\Gradient;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\GradientType;
|
||||||
|
|
||||||
|
final class EpsImageBackEnd implements ImageBackEndInterface
|
||||||
|
{
|
||||||
|
private const PRECISION = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
private $eps;
|
||||||
|
|
||||||
|
public function new(int $size, ColorInterface $backgroundColor) : void
|
||||||
|
{
|
||||||
|
$this->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());
|
||||||
|
}
|
||||||
|
}
|
87
vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php
vendored
Executable file
87
vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php
vendored
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Image;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\RuntimeException;
|
||||||
|
use BaconQrCode\Renderer\Color\ColorInterface;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\Gradient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for back ends able to to produce path based images.
|
||||||
|
*/
|
||||||
|
interface ImageBackEndInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Starts a new image.
|
||||||
|
*
|
||||||
|
* If a previous image was already started, previous data get erased.
|
||||||
|
*/
|
||||||
|
public function new(int $size, ColorInterface $backgroundColor) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms all following drawing operation coordinates by scaling them by a given factor.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if no image was started yet.
|
||||||
|
*/
|
||||||
|
public function scale(float $size) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms all following drawing operation coordinates by translating them by a given amount.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if no image was started yet.
|
||||||
|
*/
|
||||||
|
public function translate(float $x, float $y) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms all following drawing operation coordinates by rotating them by a given amount.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if no image was started yet.
|
||||||
|
*/
|
||||||
|
public function rotate(int $degrees) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes the current coordinate transformation onto a stack.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if no image was started yet.
|
||||||
|
*/
|
||||||
|
public function push() : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pops the last coordinate transformation from a stack.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if no image was started yet.
|
||||||
|
*/
|
||||||
|
public function pop() : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a path with a given color.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if no image was started yet.
|
||||||
|
*/
|
||||||
|
public function drawPathWithColor(Path $path, ColorInterface $color) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a path with a given gradient which spans the box described by the position and size.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if no image was started yet.
|
||||||
|
*/
|
||||||
|
public function drawPathWithGradient(
|
||||||
|
Path $path,
|
||||||
|
Gradient $gradient,
|
||||||
|
float $x,
|
||||||
|
float $y,
|
||||||
|
float $width,
|
||||||
|
float $height
|
||||||
|
) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends the image drawing operation and returns the resulting blob.
|
||||||
|
*
|
||||||
|
* This should reset the state of the back end and thus this method should only be callable once per image.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if no image was started yet.
|
||||||
|
*/
|
||||||
|
public function done() : string;
|
||||||
|
}
|
336
vendor/bacon/bacon-qr-code/src/Renderer/Image/ImagickImageBackEnd.php
vendored
Executable file
336
vendor/bacon/bacon-qr-code/src/Renderer/Image/ImagickImageBackEnd.php
vendored
Executable file
@ -0,0 +1,336 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Image;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\RuntimeException;
|
||||||
|
use BaconQrCode\Renderer\Color\Alpha;
|
||||||
|
use BaconQrCode\Renderer\Color\Cmyk;
|
||||||
|
use BaconQrCode\Renderer\Color\ColorInterface;
|
||||||
|
use BaconQrCode\Renderer\Color\Gray;
|
||||||
|
use BaconQrCode\Renderer\Color\Rgb;
|
||||||
|
use BaconQrCode\Renderer\Path\Close;
|
||||||
|
use BaconQrCode\Renderer\Path\Curve;
|
||||||
|
use BaconQrCode\Renderer\Path\EllipticArc;
|
||||||
|
use BaconQrCode\Renderer\Path\Line;
|
||||||
|
use BaconQrCode\Renderer\Path\Move;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\Gradient;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\GradientType;
|
||||||
|
use Imagick;
|
||||||
|
use ImagickDraw;
|
||||||
|
use ImagickPixel;
|
||||||
|
|
||||||
|
final class ImagickImageBackEnd implements ImageBackEndInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $imageFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $compressionQuality;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Imagick|null
|
||||||
|
*/
|
||||||
|
private $image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ImagickDraw|null
|
||||||
|
*/
|
||||||
|
private $draw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
private $gradientCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var TransformationMatrix[]|null
|
||||||
|
*/
|
||||||
|
private $matrices;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
private $matrixIndex;
|
||||||
|
|
||||||
|
public function __construct(string $imageFormat = 'png', int $compressionQuality = 100)
|
||||||
|
{
|
||||||
|
if (! class_exists(Imagick::class)) {
|
||||||
|
throw new RuntimeException('You need to install the imagick extension to use this back end');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->imageFormat = $imageFormat;
|
||||||
|
$this->compressionQuality = $compressionQuality;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function new(int $size, ColorInterface $backgroundColor) : void
|
||||||
|
{
|
||||||
|
$this->image = new Imagick();
|
||||||
|
$this->image->newImage($size, $size, $this->getColorPixel($backgroundColor));
|
||||||
|
$this->image->setImageFormat($this->imageFormat);
|
||||||
|
$this->image->setCompressionQuality($this->compressionQuality);
|
||||||
|
$this->draw = new ImagickDraw();
|
||||||
|
$this->gradientCount = 0;
|
||||||
|
$this->matrices = [new TransformationMatrix()];
|
||||||
|
$this->matrixIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scale(float $size) : void
|
||||||
|
{
|
||||||
|
if (null === $this->draw) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->draw->scale($size, $size);
|
||||||
|
$this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex]
|
||||||
|
->multiply(TransformationMatrix::scale($size));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function translate(float $x, float $y) : void
|
||||||
|
{
|
||||||
|
if (null === $this->draw) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->draw->translate($x, $y);
|
||||||
|
$this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex]
|
||||||
|
->multiply(TransformationMatrix::translate($x, $y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rotate(int $degrees) : void
|
||||||
|
{
|
||||||
|
if (null === $this->draw) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->draw->rotate($degrees);
|
||||||
|
$this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex]
|
||||||
|
->multiply(TransformationMatrix::rotate($degrees));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function push() : void
|
||||||
|
{
|
||||||
|
if (null === $this->draw) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->draw->push();
|
||||||
|
$this->matrices[++$this->matrixIndex] = $this->matrices[$this->matrixIndex - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pop() : void
|
||||||
|
{
|
||||||
|
if (null === $this->draw) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->draw->pop();
|
||||||
|
unset($this->matrices[$this->matrixIndex--]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function drawPathWithColor(Path $path, ColorInterface $color) : void
|
||||||
|
{
|
||||||
|
if (null === $this->draw) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->draw->setFillColor($this->getColorPixel($color));
|
||||||
|
$this->drawPath($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function drawPathWithGradient(
|
||||||
|
Path $path,
|
||||||
|
Gradient $gradient,
|
||||||
|
float $x,
|
||||||
|
float $y,
|
||||||
|
float $width,
|
||||||
|
float $height
|
||||||
|
) : void {
|
||||||
|
if (null === $this->draw) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->draw->setFillPatternURL('#' . $this->createGradientFill($gradient, $x, $y, $width, $height));
|
||||||
|
$this->drawPath($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function done() : string
|
||||||
|
{
|
||||||
|
if (null === $this->draw) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->image->drawImage($this->draw);
|
||||||
|
$blob = $this->image->getImageBlob();
|
||||||
|
$this->draw->clear();
|
||||||
|
$this->image->clear();
|
||||||
|
$this->draw = null;
|
||||||
|
$this->image = null;
|
||||||
|
$this->gradientCount = null;
|
||||||
|
|
||||||
|
return $blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function drawPath(Path $path) : void
|
||||||
|
{
|
||||||
|
$this->draw->pathStart();
|
||||||
|
|
||||||
|
foreach ($path as $op) {
|
||||||
|
switch (true) {
|
||||||
|
case $op instanceof Move:
|
||||||
|
$this->draw->pathMoveToAbsolute($op->getX(), $op->getY());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case $op instanceof Line:
|
||||||
|
$this->draw->pathLineToAbsolute($op->getX(), $op->getY());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case $op instanceof EllipticArc:
|
||||||
|
$this->draw->pathEllipticArcAbsolute(
|
||||||
|
$op->getXRadius(),
|
||||||
|
$op->getYRadius(),
|
||||||
|
$op->getXAxisAngle(),
|
||||||
|
$op->isLargeArc(),
|
||||||
|
$op->isSweep(),
|
||||||
|
$op->getX(),
|
||||||
|
$op->getY()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case $op instanceof Curve:
|
||||||
|
$this->draw->pathCurveToAbsolute(
|
||||||
|
$op->getX1(),
|
||||||
|
$op->getY1(),
|
||||||
|
$op->getX2(),
|
||||||
|
$op->getY2(),
|
||||||
|
$op->getX3(),
|
||||||
|
$op->getY3()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case $op instanceof Close:
|
||||||
|
$this->draw->pathClose();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new RuntimeException('Unexpected draw operation: ' . get_class($op));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->draw->pathFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string
|
||||||
|
{
|
||||||
|
list($width, $height) = $this->matrices[$this->matrixIndex]->apply($width, $height);
|
||||||
|
|
||||||
|
$startColor = $this->getColorPixel($gradient->getStartColor())->getColorAsString();
|
||||||
|
$endColor = $this->getColorPixel($gradient->getEndColor())->getColorAsString();
|
||||||
|
$gradientImage = new Imagick();
|
||||||
|
|
||||||
|
switch ($gradient->getType()) {
|
||||||
|
case GradientType::HORIZONTAL():
|
||||||
|
$gradientImage->newPseudoImage((int) $height, (int) $width, sprintf(
|
||||||
|
'gradient:%s-%s',
|
||||||
|
$startColor,
|
||||||
|
$endColor
|
||||||
|
));
|
||||||
|
$gradientImage->rotateImage('transparent', -90);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GradientType::VERTICAL():
|
||||||
|
$gradientImage->newPseudoImage((int) $width, (int) $height, sprintf(
|
||||||
|
'gradient:%s-%s',
|
||||||
|
$startColor,
|
||||||
|
$endColor
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GradientType::DIAGONAL():
|
||||||
|
case GradientType::INVERSE_DIAGONAL():
|
||||||
|
$gradientImage->newPseudoImage((int) ($width * sqrt(2)), (int) ($height * sqrt(2)), sprintf(
|
||||||
|
'gradient:%s-%s',
|
||||||
|
$startColor,
|
||||||
|
$endColor
|
||||||
|
));
|
||||||
|
|
||||||
|
if (GradientType::DIAGONAL() === $gradient->getType()) {
|
||||||
|
$gradientImage->rotateImage('transparent', -45);
|
||||||
|
} else {
|
||||||
|
$gradientImage->rotateImage('transparent', -135);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rotatedWidth = $gradientImage->getImageWidth();
|
||||||
|
$rotatedHeight = $gradientImage->getImageHeight();
|
||||||
|
|
||||||
|
$gradientImage->setImagePage($rotatedWidth, $rotatedHeight, 0, 0);
|
||||||
|
$gradientImage->cropImage(
|
||||||
|
intdiv($rotatedWidth, 2) - 2,
|
||||||
|
intdiv($rotatedHeight, 2) - 2,
|
||||||
|
intdiv($rotatedWidth, 4) + 1,
|
||||||
|
intdiv($rotatedWidth, 4) + 1
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GradientType::RADIAL():
|
||||||
|
$gradientImage->newPseudoImage((int) $width, (int) $height, sprintf(
|
||||||
|
'radial-gradient:%s-%s',
|
||||||
|
$startColor,
|
||||||
|
$endColor
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = sprintf('g%d', ++$this->gradientCount);
|
||||||
|
$this->draw->pushPattern($id, 0, 0, $width, $height);
|
||||||
|
$this->draw->composite(Imagick::COMPOSITE_COPY, 0, 0, $width, $height, $gradientImage);
|
||||||
|
$this->draw->popPattern();
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getColorPixel(ColorInterface $color) : ImagickPixel
|
||||||
|
{
|
||||||
|
$alpha = 100;
|
||||||
|
|
||||||
|
if ($color instanceof Alpha) {
|
||||||
|
$alpha = $color->getAlpha();
|
||||||
|
$color = $color->getBaseColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($color instanceof Rgb) {
|
||||||
|
return new ImagickPixel(sprintf(
|
||||||
|
'rgba(%d, %d, %d, %F)',
|
||||||
|
$color->getRed(),
|
||||||
|
$color->getGreen(),
|
||||||
|
$color->getBlue(),
|
||||||
|
$alpha / 100
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($color instanceof Cmyk) {
|
||||||
|
return new ImagickPixel(sprintf(
|
||||||
|
'cmyka(%d, %d, %d, %d, %F)',
|
||||||
|
$color->getCyan(),
|
||||||
|
$color->getMagenta(),
|
||||||
|
$color->getYellow(),
|
||||||
|
$color->getBlack(),
|
||||||
|
$alpha / 100
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($color instanceof Gray) {
|
||||||
|
return new ImagickPixel(sprintf(
|
||||||
|
'graya(%d%%, %F)',
|
||||||
|
$color->getGray(),
|
||||||
|
$alpha / 100
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getColorPixel(new Alpha($alpha, $color->toRgb()));
|
||||||
|
}
|
||||||
|
}
|
369
vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php
vendored
Executable file
369
vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php
vendored
Executable file
@ -0,0 +1,369 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Image;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\RuntimeException;
|
||||||
|
use BaconQrCode\Renderer\Color\Alpha;
|
||||||
|
use BaconQrCode\Renderer\Color\ColorInterface;
|
||||||
|
use BaconQrCode\Renderer\Path\Close;
|
||||||
|
use BaconQrCode\Renderer\Path\Curve;
|
||||||
|
use BaconQrCode\Renderer\Path\EllipticArc;
|
||||||
|
use BaconQrCode\Renderer\Path\Line;
|
||||||
|
use BaconQrCode\Renderer\Path\Move;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\Gradient;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\GradientType;
|
||||||
|
use XMLWriter;
|
||||||
|
|
||||||
|
final class SvgImageBackEnd implements ImageBackEndInterface
|
||||||
|
{
|
||||||
|
private const PRECISION = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var XMLWriter|null
|
||||||
|
*/
|
||||||
|
private $xmlWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int[]|null
|
||||||
|
*/
|
||||||
|
private $stack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
private $currentStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
private $gradientCount;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
if (! class_exists(XMLWriter::class)) {
|
||||||
|
throw new RuntimeException('You need to install the libxml extension to use this back end');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function new(int $size, ColorInterface $backgroundColor) : void
|
||||||
|
{
|
||||||
|
$this->xmlWriter = new XMLWriter();
|
||||||
|
$this->xmlWriter->openMemory();
|
||||||
|
|
||||||
|
$this->xmlWriter->startDocument('1.0', 'UTF-8');
|
||||||
|
$this->xmlWriter->startElement('svg');
|
||||||
|
$this->xmlWriter->writeAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
||||||
|
$this->xmlWriter->writeAttribute('version', '1.1');
|
||||||
|
$this->xmlWriter->writeAttribute('width', (string) $size);
|
||||||
|
$this->xmlWriter->writeAttribute('height', (string) $size);
|
||||||
|
$this->xmlWriter->writeAttribute('viewBox', '0 0 '. $size . ' ' . $size);
|
||||||
|
|
||||||
|
$this->gradientCount = 0;
|
||||||
|
$this->currentStack = 0;
|
||||||
|
$this->stack[0] = 0;
|
||||||
|
|
||||||
|
$alpha = 1;
|
||||||
|
|
||||||
|
if ($backgroundColor instanceof Alpha) {
|
||||||
|
$alpha = $backgroundColor->getAlpha() / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === $alpha) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->startElement('rect');
|
||||||
|
$this->xmlWriter->writeAttribute('x', '0');
|
||||||
|
$this->xmlWriter->writeAttribute('y', '0');
|
||||||
|
$this->xmlWriter->writeAttribute('width', (string) $size);
|
||||||
|
$this->xmlWriter->writeAttribute('height', (string) $size);
|
||||||
|
$this->xmlWriter->writeAttribute('fill', $this->getColorString($backgroundColor));
|
||||||
|
|
||||||
|
if ($alpha < 1) {
|
||||||
|
$this->xmlWriter->writeAttribute('fill-opacity', (string) $alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->endElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scale(float $size) : void
|
||||||
|
{
|
||||||
|
if (null === $this->xmlWriter) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->startElement('g');
|
||||||
|
$this->xmlWriter->writeAttribute(
|
||||||
|
'transform',
|
||||||
|
sprintf('scale(%s)', round($size, self::PRECISION))
|
||||||
|
);
|
||||||
|
++$this->stack[$this->currentStack];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function translate(float $x, float $y) : void
|
||||||
|
{
|
||||||
|
if (null === $this->xmlWriter) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->startElement('g');
|
||||||
|
$this->xmlWriter->writeAttribute(
|
||||||
|
'transform',
|
||||||
|
sprintf('translate(%s,%s)', round($x, self::PRECISION), round($y, self::PRECISION))
|
||||||
|
);
|
||||||
|
++$this->stack[$this->currentStack];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rotate(int $degrees) : void
|
||||||
|
{
|
||||||
|
if (null === $this->xmlWriter) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->startElement('g');
|
||||||
|
$this->xmlWriter->writeAttribute('transform', sprintf('rotate(%d)', $degrees));
|
||||||
|
++$this->stack[$this->currentStack];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function push() : void
|
||||||
|
{
|
||||||
|
if (null === $this->xmlWriter) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->startElement('g');
|
||||||
|
$this->stack[] = 1;
|
||||||
|
++$this->currentStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pop() : void
|
||||||
|
{
|
||||||
|
if (null === $this->xmlWriter) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < $this->stack[$this->currentStack]; ++$i) {
|
||||||
|
$this->xmlWriter->endElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
array_pop($this->stack);
|
||||||
|
--$this->currentStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function drawPathWithColor(Path $path, ColorInterface $color) : void
|
||||||
|
{
|
||||||
|
if (null === $this->xmlWriter) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$alpha = 1;
|
||||||
|
|
||||||
|
if ($color instanceof Alpha) {
|
||||||
|
$alpha = $color->getAlpha() / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->startPathElement($path);
|
||||||
|
$this->xmlWriter->writeAttribute('fill', $this->getColorString($color));
|
||||||
|
|
||||||
|
if ($alpha < 1) {
|
||||||
|
$this->xmlWriter->writeAttribute('fill-opacity', (string) $alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->endElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function drawPathWithGradient(
|
||||||
|
Path $path,
|
||||||
|
Gradient $gradient,
|
||||||
|
float $x,
|
||||||
|
float $y,
|
||||||
|
float $width,
|
||||||
|
float $height
|
||||||
|
) : void {
|
||||||
|
if (null === $this->xmlWriter) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
$gradientId = $this->createGradientFill($gradient, $x, $y, $width, $height);
|
||||||
|
$this->startPathElement($path);
|
||||||
|
$this->xmlWriter->writeAttribute('fill', 'url(#' . $gradientId . ')');
|
||||||
|
$this->xmlWriter->endElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function done() : string
|
||||||
|
{
|
||||||
|
if (null === $this->xmlWriter) {
|
||||||
|
throw new RuntimeException('No image has been started');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->stack as $openElements) {
|
||||||
|
for ($i = $openElements; $i > 0; --$i) {
|
||||||
|
$this->xmlWriter->endElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->endDocument();
|
||||||
|
$blob = $this->xmlWriter->outputMemory(true);
|
||||||
|
$this->xmlWriter = null;
|
||||||
|
$this->stack = null;
|
||||||
|
$this->currentStack = null;
|
||||||
|
$this->gradientCount = null;
|
||||||
|
|
||||||
|
return $blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function startPathElement(Path $path) : void
|
||||||
|
{
|
||||||
|
$pathData = [];
|
||||||
|
|
||||||
|
foreach ($path as $op) {
|
||||||
|
switch (true) {
|
||||||
|
case $op instanceof Move:
|
||||||
|
$pathData[] = sprintf(
|
||||||
|
'M%s %s',
|
||||||
|
round($op->getX(), self::PRECISION),
|
||||||
|
round($op->getY(), self::PRECISION)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case $op instanceof Line:
|
||||||
|
$pathData[] = sprintf(
|
||||||
|
'L%s %s',
|
||||||
|
round($op->getX(), self::PRECISION),
|
||||||
|
round($op->getY(), self::PRECISION)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case $op instanceof EllipticArc:
|
||||||
|
$pathData[] = sprintf(
|
||||||
|
'A%s %s %s %u %u %s %s',
|
||||||
|
round($op->getXRadius(), self::PRECISION),
|
||||||
|
round($op->getYRadius(), self::PRECISION),
|
||||||
|
round($op->getXAxisAngle(), self::PRECISION),
|
||||||
|
$op->isLargeArc(),
|
||||||
|
$op->isSweep(),
|
||||||
|
round($op->getX(), self::PRECISION),
|
||||||
|
round($op->getY(), self::PRECISION)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case $op instanceof Curve:
|
||||||
|
$pathData[] = sprintf(
|
||||||
|
'C%s %s %s %s %s %s',
|
||||||
|
round($op->getX1(), self::PRECISION),
|
||||||
|
round($op->getY1(), self::PRECISION),
|
||||||
|
round($op->getX2(), self::PRECISION),
|
||||||
|
round($op->getY2(), self::PRECISION),
|
||||||
|
round($op->getX3(), self::PRECISION),
|
||||||
|
round($op->getY3(), self::PRECISION)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case $op instanceof Close:
|
||||||
|
$pathData[] = 'Z';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new RuntimeException('Unexpected draw operation: ' . get_class($op));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->startElement('path');
|
||||||
|
$this->xmlWriter->writeAttribute('fill-rule', 'evenodd');
|
||||||
|
$this->xmlWriter->writeAttribute('d', implode('', $pathData));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string
|
||||||
|
{
|
||||||
|
$this->xmlWriter->startElement('defs');
|
||||||
|
|
||||||
|
$startColor = $gradient->getStartColor();
|
||||||
|
$endColor = $gradient->getEndColor();
|
||||||
|
|
||||||
|
if ($gradient->getType() === GradientType::RADIAL()) {
|
||||||
|
$this->xmlWriter->startElement('radialGradient');
|
||||||
|
} else {
|
||||||
|
$this->xmlWriter->startElement('linearGradient');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlWriter->writeAttribute('gradientUnits', 'userSpaceOnUse');
|
||||||
|
|
||||||
|
switch ($gradient->getType()) {
|
||||||
|
case GradientType::HORIZONTAL():
|
||||||
|
$this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('y2', (string) round($y, self::PRECISION));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GradientType::VERTICAL():
|
||||||
|
$this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('x2', (string) round($x, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('y2', (string) round($y + $height, self::PRECISION));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GradientType::DIAGONAL():
|
||||||
|
$this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('y1', (string) round($y, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('y2', (string) round($y + $height, self::PRECISION));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GradientType::INVERSE_DIAGONAL():
|
||||||
|
$this->xmlWriter->writeAttribute('x1', (string) round($x, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('y1', (string) round($y + $height, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('x2', (string) round($x + $width, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('y2', (string) round($y, self::PRECISION));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GradientType::RADIAL():
|
||||||
|
$this->xmlWriter->writeAttribute('cx', (string) round(($x + $width) / 2, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('cy', (string) round(($y + $height) / 2, self::PRECISION));
|
||||||
|
$this->xmlWriter->writeAttribute('r', (string) round(max($width, $height) / 2, self::PRECISION));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = sprintf('g%d', ++$this->gradientCount);
|
||||||
|
$this->xmlWriter->writeAttribute('id', $id);
|
||||||
|
|
||||||
|
$this->xmlWriter->startElement('stop');
|
||||||
|
$this->xmlWriter->writeAttribute('offset', '0%');
|
||||||
|
$this->xmlWriter->writeAttribute('stop-color', $this->getColorString($startColor));
|
||||||
|
|
||||||
|
if ($startColor instanceof Alpha) {
|
||||||
|
$this->xmlWriter->writeAttribute('stop-opacity', $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', $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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
68
vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php
vendored
Executable file
68
vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php
vendored
Executable file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Image;
|
||||||
|
|
||||||
|
final class TransformationMatrix
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var float[]
|
||||||
|
*/
|
||||||
|
private $values;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->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],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
152
vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php
vendored
Executable file
152
vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php
vendored
Executable file
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\MatrixUtil;
|
||||||
|
use BaconQrCode\Encoder\QrCode;
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use BaconQrCode\Renderer\Image\ImageBackEndInterface;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\EyeFill;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
||||||
|
|
||||||
|
final class ImageRenderer implements RendererInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var RendererStyle
|
||||||
|
*/
|
||||||
|
private $rendererStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ImageBackEndInterface
|
||||||
|
*/
|
||||||
|
private $imageBackEnd;
|
||||||
|
|
||||||
|
public function __construct(RendererStyle $rendererStyle, ImageBackEndInterface $imageBackEnd)
|
||||||
|
{
|
||||||
|
$this->rendererStyle = $rendererStyle;
|
||||||
|
$this->imageBackEnd = $imageBackEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException if matrix width doesn't match height
|
||||||
|
*/
|
||||||
|
public function render(QrCode $qrCode) : string
|
||||||
|
{
|
||||||
|
$size = $this->rendererStyle->getSize();
|
||||||
|
$margin = $this->rendererStyle->getMargin();
|
||||||
|
$matrix = $qrCode->getMatrix();
|
||||||
|
$matrixSize = $matrix->getWidth();
|
||||||
|
|
||||||
|
if ($matrixSize !== $matrix->getHeight()) {
|
||||||
|
throw new InvalidArgumentException('Matrix must have the same width and height');
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalSize = $matrixSize + ($margin * 2);
|
||||||
|
$moduleSize = $size / $totalSize;
|
||||||
|
$fill = $this->rendererStyle->getFill();
|
||||||
|
|
||||||
|
$this->imageBackEnd->new($size, $fill->getBackgroundColor());
|
||||||
|
$this->imageBackEnd->scale((float) $moduleSize);
|
||||||
|
$this->imageBackEnd->translate((float) $margin, (float) $margin);
|
||||||
|
|
||||||
|
$module = $this->rendererStyle->getModule();
|
||||||
|
$moduleMatrix = clone $matrix;
|
||||||
|
MatrixUtil::removePositionDetectionPatterns($moduleMatrix);
|
||||||
|
$modulePath = $this->drawEyes($matrixSize, $module->createPath($moduleMatrix));
|
||||||
|
|
||||||
|
if ($fill->hasGradientFill()) {
|
||||||
|
$this->imageBackEnd->drawPathWithGradient(
|
||||||
|
$modulePath,
|
||||||
|
$fill->getForegroundGradient(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
$matrixSize,
|
||||||
|
$matrixSize
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->imageBackEnd->drawPathWithColor($modulePath, $fill->getForegroundColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->imageBackEnd->done();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function drawEyes(int $matrixSize, Path $modulePath) : Path
|
||||||
|
{
|
||||||
|
$fill = $this->rendererStyle->getFill();
|
||||||
|
|
||||||
|
$eye = $this->rendererStyle->getEye();
|
||||||
|
$externalPath = $eye->getExternalPath();
|
||||||
|
$internalPath = $eye->getInternalPath();
|
||||||
|
|
||||||
|
$modulePath = $this->drawEye(
|
||||||
|
$externalPath,
|
||||||
|
$internalPath,
|
||||||
|
$fill->getTopLeftEyeFill(),
|
||||||
|
3.5,
|
||||||
|
3.5,
|
||||||
|
0,
|
||||||
|
$modulePath
|
||||||
|
);
|
||||||
|
$modulePath = $this->drawEye(
|
||||||
|
$externalPath,
|
||||||
|
$internalPath,
|
||||||
|
$fill->getTopRightEyeFill(),
|
||||||
|
$matrixSize - 3.5,
|
||||||
|
3.5,
|
||||||
|
90,
|
||||||
|
$modulePath
|
||||||
|
);
|
||||||
|
$modulePath = $this->drawEye(
|
||||||
|
$externalPath,
|
||||||
|
$internalPath,
|
||||||
|
$fill->getBottomLeftEyeFill(),
|
||||||
|
3.5,
|
||||||
|
$matrixSize - 3.5,
|
||||||
|
-90,
|
||||||
|
$modulePath
|
||||||
|
);
|
||||||
|
|
||||||
|
return $modulePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function drawEye(
|
||||||
|
Path $externalPath,
|
||||||
|
Path $internalPath,
|
||||||
|
EyeFill $fill,
|
||||||
|
float $xTranslation,
|
||||||
|
float $yTranslation,
|
||||||
|
int $rotation,
|
||||||
|
Path $modulePath
|
||||||
|
) : Path {
|
||||||
|
if ($fill->inheritsBothColors()) {
|
||||||
|
return $modulePath
|
||||||
|
->append($externalPath->translate($xTranslation, $yTranslation))
|
||||||
|
->append($internalPath->translate($xTranslation, $yTranslation));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->imageBackEnd->push();
|
||||||
|
$this->imageBackEnd->translate($xTranslation, $yTranslation);
|
||||||
|
|
||||||
|
if (0 !== $rotation) {
|
||||||
|
$this->imageBackEnd->rotate($rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fill->inheritsExternalColor()) {
|
||||||
|
$modulePath = $modulePath->append($externalPath->translate($xTranslation, $yTranslation));
|
||||||
|
} else {
|
||||||
|
$this->imageBackEnd->drawPathWithColor($externalPath, $fill->getExternalColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fill->inheritsInternalColor()) {
|
||||||
|
$modulePath = $modulePath->append($internalPath->translate($xTranslation, $yTranslation));
|
||||||
|
} else {
|
||||||
|
$this->imageBackEnd->drawPathWithColor($internalPath, $fill->getInternalColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->imageBackEnd->pop();
|
||||||
|
|
||||||
|
return $modulePath;
|
||||||
|
}
|
||||||
|
}
|
63
vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php
vendored
Executable file
63
vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php
vendored
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Module;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\ByteMatrix;
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders individual modules as dots.
|
||||||
|
*/
|
||||||
|
final class DotsModule implements ModuleInterface
|
||||||
|
{
|
||||||
|
public const LARGE = 1;
|
||||||
|
public const MEDIUM = .8;
|
||||||
|
public const SMALL = .6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $size;
|
||||||
|
|
||||||
|
public function __construct(float $size)
|
||||||
|
{
|
||||||
|
if ($size <= 0 || $size > 1) {
|
||||||
|
throw new InvalidArgumentException('Size must between 0 (exclusive) and 1 (inclusive)');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->size = $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createPath(ByteMatrix $matrix) : Path
|
||||||
|
{
|
||||||
|
$width = $matrix->getWidth();
|
||||||
|
$height = $matrix->getHeight();
|
||||||
|
$path = new Path();
|
||||||
|
$halfSize = $this->size / 2;
|
||||||
|
$margin = (1 - $this->size) / 2;
|
||||||
|
|
||||||
|
for ($y = 0; $y < $height; ++$y) {
|
||||||
|
for ($x = 0; $x < $width; ++$x) {
|
||||||
|
if (! $matrix->get($x, $y)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pathX = $x + $margin;
|
||||||
|
$pathY = $y + $margin;
|
||||||
|
|
||||||
|
$path = $path
|
||||||
|
->move($pathX + $this->size, $pathY + $halfSize)
|
||||||
|
->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $halfSize, $pathY + $this->size)
|
||||||
|
->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX, $pathY + $halfSize)
|
||||||
|
->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $halfSize, $pathY)
|
||||||
|
->ellipticArc($halfSize, $halfSize, 0, false, true, $pathX + $this->size, $pathY + $halfSize)
|
||||||
|
->close()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
}
|
100
vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php
vendored
Executable file
100
vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php
vendored
Executable file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Module\EdgeIterator;
|
||||||
|
|
||||||
|
final class Edge
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $positive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<int[]>
|
||||||
|
*/
|
||||||
|
private $points = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<int[]>|null
|
||||||
|
*/
|
||||||
|
private $simplifiedPoints;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $minX = PHP_INT_MAX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $minY = PHP_INT_MAX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $maxX = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $maxY = -1;
|
||||||
|
|
||||||
|
public function __construct(bool $positive)
|
||||||
|
{
|
||||||
|
$this->positive = $positive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addPoint(int $x, int $y) : void
|
||||||
|
{
|
||||||
|
$this->points[] = [$x, $y];
|
||||||
|
$this->minX = min($this->minX, $x);
|
||||||
|
$this->minY = min($this->minY, $y);
|
||||||
|
$this->maxX = max($this->maxX, $x);
|
||||||
|
$this->maxY = max($this->maxY, $y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isPositive() : bool
|
||||||
|
{
|
||||||
|
return $this->positive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int[]>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
169
vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php
vendored
Executable file
169
vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php
vendored
Executable file
@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Module\EdgeIterator;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\ByteMatrix;
|
||||||
|
use IteratorAggregate;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edge iterator based on potrace.
|
||||||
|
*/
|
||||||
|
final class EdgeIterator implements IteratorAggregate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int[]
|
||||||
|
*/
|
||||||
|
private $bytes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $width;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $height;
|
||||||
|
|
||||||
|
public function __construct(ByteMatrix $matrix)
|
||||||
|
{
|
||||||
|
$this->bytes = iterator_to_array($matrix->getBytes());
|
||||||
|
$this->size = count($this->bytes);
|
||||||
|
$this->width = $matrix->getWidth();
|
||||||
|
$this->height = $matrix->getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Edge[]
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
18
vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php
vendored
Executable file
18
vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php
vendored
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Module;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\ByteMatrix;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface describing how modules should be rendered.
|
||||||
|
*
|
||||||
|
* A module always receives a byte matrix (with values either being 1 or 0). It returns a path, where the origin
|
||||||
|
* coordinate (0, 0) equals the top left corner of the first matrix value.
|
||||||
|
*/
|
||||||
|
interface ModuleInterface
|
||||||
|
{
|
||||||
|
public function createPath(ByteMatrix $matrix) : Path;
|
||||||
|
}
|
129
vendor/bacon/bacon-qr-code/src/Renderer/Module/RoundnessModule.php
vendored
Executable file
129
vendor/bacon/bacon-qr-code/src/Renderer/Module/RoundnessModule.php
vendored
Executable file
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Module;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\ByteMatrix;
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use BaconQrCode\Renderer\Module\EdgeIterator\EdgeIterator;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds the corners of module groups.
|
||||||
|
*/
|
||||||
|
final class RoundnessModule implements ModuleInterface
|
||||||
|
{
|
||||||
|
public const STRONG = 1;
|
||||||
|
public const MEDIUM = .5;
|
||||||
|
public const SOFT = .25;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $intensity;
|
||||||
|
|
||||||
|
public function __construct(float $intensity)
|
||||||
|
{
|
||||||
|
if ($intensity <= 0 || $intensity > 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;
|
||||||
|
}
|
||||||
|
}
|
47
vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php
vendored
Executable file
47
vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php
vendored
Executable file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Module;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\ByteMatrix;
|
||||||
|
use BaconQrCode\Renderer\Module\EdgeIterator\EdgeIterator;
|
||||||
|
use BaconQrCode\Renderer\Path\Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Groups modules together to a single path.
|
||||||
|
*/
|
||||||
|
final class SquareModule implements ModuleInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var self|null
|
||||||
|
*/
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function instance() : self
|
||||||
|
{
|
||||||
|
return self::$instance ?: self::$instance = new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createPath(ByteMatrix $matrix) : Path
|
||||||
|
{
|
||||||
|
$path = new Path();
|
||||||
|
|
||||||
|
foreach (new EdgeIterator($matrix) as $edge) {
|
||||||
|
$points = $edge->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;
|
||||||
|
}
|
||||||
|
}
|
29
vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php
vendored
Executable file
29
vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php
vendored
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Path;
|
||||||
|
|
||||||
|
final class Close implements OperationInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var self|null
|
||||||
|
*/
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function instance() : self
|
||||||
|
{
|
||||||
|
return self::$instance ?: self::$instance = new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function translate(float $x, float $y) : OperationInterface
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
92
vendor/bacon/bacon-qr-code/src/Renderer/Path/Curve.php
vendored
Executable file
92
vendor/bacon/bacon-qr-code/src/Renderer/Path/Curve.php
vendored
Executable file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Path;
|
||||||
|
|
||||||
|
final class Curve implements OperationInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $x1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $y1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $x2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $y2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $x3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $y3;
|
||||||
|
|
||||||
|
public function __construct(float $x1, float $y1, float $x2, float $y2, float $x3, float $y3)
|
||||||
|
{
|
||||||
|
$this->x1 = $x1;
|
||||||
|
$this->y1 = $y1;
|
||||||
|
$this->x2 = $x2;
|
||||||
|
$this->y2 = $y2;
|
||||||
|
$this->x3 = $x3;
|
||||||
|
$this->y3 = $y3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getX1() : float
|
||||||
|
{
|
||||||
|
return $this->x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getY1() : float
|
||||||
|
{
|
||||||
|
return $this->y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getX2() : float
|
||||||
|
{
|
||||||
|
return $this->x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getY2() : float
|
||||||
|
{
|
||||||
|
return $this->y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getX3() : float
|
||||||
|
{
|
||||||
|
return $this->x3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getY3() : float
|
||||||
|
{
|
||||||
|
return $this->y3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function translate(float $x, float $y) : OperationInterface
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
$this->x1 + $x,
|
||||||
|
$this->y1 + $y,
|
||||||
|
$this->x2 + $x,
|
||||||
|
$this->y2 + $y,
|
||||||
|
$this->x3 + $x,
|
||||||
|
$this->y3 + $y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
278
vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php
vendored
Executable file
278
vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php
vendored
Executable file
@ -0,0 +1,278 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Path;
|
||||||
|
|
||||||
|
final class EllipticArc implements OperationInterface
|
||||||
|
{
|
||||||
|
private const ZERO_TOLERANCE = 1e-05;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $xRadius;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $yRadius;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $xAxisAngle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $largeArc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $sweep;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $y;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
float $xRadius,
|
||||||
|
float $yRadius,
|
||||||
|
float $xAxisAngle,
|
||||||
|
bool $largeArc,
|
||||||
|
bool $sweep,
|
||||||
|
float $x,
|
||||||
|
float $y
|
||||||
|
) {
|
||||||
|
$this->xRadius = abs($xRadius);
|
||||||
|
$this->yRadius = abs($yRadius);
|
||||||
|
$this->xAxisAngle = $xAxisAngle % 360;
|
||||||
|
$this->largeArc = $largeArc;
|
||||||
|
$this->sweep = $sweep;
|
||||||
|
$this->x = $x;
|
||||||
|
$this->y = $y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getXRadius() : float
|
||||||
|
{
|
||||||
|
return $this->xRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getYRadius() : float
|
||||||
|
{
|
||||||
|
return $this->yRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getXAxisAngle() : float
|
||||||
|
{
|
||||||
|
return $this->xAxisAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isLargeArc() : bool
|
||||||
|
{
|
||||||
|
return $this->largeArc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isSweep() : bool
|
||||||
|
{
|
||||||
|
return $this->sweep;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getX() : float
|
||||||
|
{
|
||||||
|
return $this->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getY() : float
|
||||||
|
{
|
||||||
|
return $this->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function translate(float $x, float $y) : OperationInterface
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
$this->xRadius,
|
||||||
|
$this->yRadius,
|
||||||
|
$this->xAxisAngle,
|
||||||
|
$this->largeArc,
|
||||||
|
$this->sweep,
|
||||||
|
$this->x + $x,
|
||||||
|
$this->y + $y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the elliptic arc to multiple curves.
|
||||||
|
*
|
||||||
|
* Since not all image back ends support elliptic arcs, this method allows to convert the arc into multiple curves
|
||||||
|
* resembling the same result.
|
||||||
|
*
|
||||||
|
* @see https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/
|
||||||
|
* @return array<Curve|Line>
|
||||||
|
*/
|
||||||
|
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, $fromY) : array
|
||||||
|
{
|
||||||
|
$xAngle = deg2rad($this->xAxisAngle);
|
||||||
|
list($centerX, $centerY, $radiusX, $radiusY, $startAngle, $deltaAngle) =
|
||||||
|
$this->calculateCenterPointParameters($fromX, $fromY, $xAngle);
|
||||||
|
|
||||||
|
$s = $startAngle;
|
||||||
|
$e = $s + $deltaAngle;
|
||||||
|
$sign = ($e < $s) ? -1 : 1;
|
||||||
|
$remain = abs($e - $s);
|
||||||
|
$p1 = self::point($centerX, $centerY, $radiusX, $radiusY, $xAngle, $s);
|
||||||
|
$curves = [];
|
||||||
|
|
||||||
|
while ($remain > self::ZERO_TOLERANCE) {
|
||||||
|
$step = min($remain, pi() / 2);
|
||||||
|
$signStep = $step * $sign;
|
||||||
|
$p2 = self::point($centerX, $centerY, $radiusX, $radiusY, $xAngle, $s + $signStep);
|
||||||
|
|
||||||
|
$alphaT = tan($signStep / 2);
|
||||||
|
$alpha = sin($signStep) * (sqrt(4 + 3 * $alphaT ** 2) - 1) / 3;
|
||||||
|
$d1 = self::derivative($radiusX, $radiusY, $xAngle, $s);
|
||||||
|
$d2 = self::derivative($radiusX, $radiusY, $xAngle, $s + $signStep);
|
||||||
|
|
||||||
|
$curves[] = new Curve(
|
||||||
|
$p1[0] + $alpha * $d1[0],
|
||||||
|
$p1[1] + $alpha * $d1[1],
|
||||||
|
$p2[0] - $alpha * $d2[0],
|
||||||
|
$p2[1] - $alpha * $d2[1],
|
||||||
|
$p2[0],
|
||||||
|
$p2[1]
|
||||||
|
);
|
||||||
|
|
||||||
|
$s += $signStep;
|
||||||
|
$remain -= $step;
|
||||||
|
$p1 = $p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $curves;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return float[]
|
||||||
|
*/
|
||||||
|
private function calculateCenterPointParameters(float $fromX, float $fromY, float $xAngle)
|
||||||
|
{
|
||||||
|
$rX = $this->xRadius;
|
||||||
|
$rY = $this->yRadius;
|
||||||
|
|
||||||
|
// F.6.5.1
|
||||||
|
$dx2 = ($fromX - $this->x) / 2;
|
||||||
|
$dy2 = ($fromY - $this->y) / 2;
|
||||||
|
$x1p = cos($xAngle) * $dx2 + sin($xAngle) * $dy2;
|
||||||
|
$y1p = -sin($xAngle) * $dx2 + cos($xAngle) * $dy2;
|
||||||
|
|
||||||
|
// F.6.5.2
|
||||||
|
$rxs = $rX ** 2;
|
||||||
|
$rys = $rY ** 2;
|
||||||
|
$x1ps = $x1p ** 2;
|
||||||
|
$y1ps = $y1p ** 2;
|
||||||
|
$cr = $x1ps / $rxs + $y1ps / $rys;
|
||||||
|
|
||||||
|
if ($cr > 1) {
|
||||||
|
$s = sqrt($cr);
|
||||||
|
$rX *= $s;
|
||||||
|
$rY *= $s;
|
||||||
|
$rxs = $rX ** 2;
|
||||||
|
$rys = $rY ** 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dq = ($rxs * $y1ps + $rys * $x1ps);
|
||||||
|
$pq = ($rxs * $rys - $dq) / $dq;
|
||||||
|
$q = sqrt(max(0, $pq));
|
||||||
|
|
||||||
|
if ($this->largeArc === $this->sweep) {
|
||||||
|
$q = -$q;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cxp = $q * $rX * $y1p / $rY;
|
||||||
|
$cyp = -$q * $rY * $x1p / $rX;
|
||||||
|
|
||||||
|
// F.6.5.3
|
||||||
|
$cx = cos($xAngle) * $cxp - sin($xAngle) * $cyp + ($fromX + $this->x) / 2;
|
||||||
|
$cy = sin($xAngle) * $cxp + cos($xAngle) * $cyp + ($fromY + $this->y) / 2;
|
||||||
|
|
||||||
|
// F.6.5.5
|
||||||
|
$theta = self::angle(1, 0, ($x1p - $cxp) / $rX, ($y1p - $cyp) / $rY);
|
||||||
|
|
||||||
|
// F.6.5.6
|
||||||
|
$delta = self::angle(($x1p - $cxp) / $rX, ($y1p - $cyp) / $rY, (-$x1p - $cxp) / $rX, (-$y1p - $cyp) / $rY);
|
||||||
|
$delta = fmod($delta, pi() * 2);
|
||||||
|
|
||||||
|
if (! $this->sweep) {
|
||||||
|
$delta -= 2 * pi();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$cx, $cy, $rX, $rY, $theta, $delta];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function angle(float $ux, float $uy, float $vx, float $vy) : float
|
||||||
|
{
|
||||||
|
// F.6.5.4
|
||||||
|
$dot = $ux * $vx + $uy * $vy;
|
||||||
|
$length = sqrt($ux ** 2 + $uy ** 2) * sqrt($vx ** 2 + $vy ** 2);
|
||||||
|
$angle = acos(min(1, max(-1, $dot / $length)));
|
||||||
|
|
||||||
|
if (($ux * $vy - $uy * $vx) < 0) {
|
||||||
|
return -$angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return float[]
|
||||||
|
*/
|
||||||
|
private static function point(
|
||||||
|
float $centerX,
|
||||||
|
float $centerY,
|
||||||
|
float $radiusX,
|
||||||
|
float $radiusY,
|
||||||
|
float $xAngle,
|
||||||
|
float $angle
|
||||||
|
) : array {
|
||||||
|
return [
|
||||||
|
$centerX + $radiusX * cos($xAngle) * cos($angle) - $radiusY * sin($xAngle) * sin($angle),
|
||||||
|
$centerY + $radiusX * sin($xAngle) * cos($angle) + $radiusY * cos($xAngle) * sin($angle),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return float[]
|
||||||
|
*/
|
||||||
|
private static function derivative(float $radiusX, float $radiusY, float $xAngle, float $angle) : array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
-$radiusX * cos($xAngle) * sin($angle) - $radiusY * sin($xAngle) * cos($angle),
|
||||||
|
-$radiusX * sin($xAngle) * sin($angle) + $radiusY * cos($xAngle) * cos($angle),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
41
vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php
vendored
Executable file
41
vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php
vendored
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Path;
|
||||||
|
|
||||||
|
final class Line implements OperationInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $y;
|
||||||
|
|
||||||
|
public function __construct(float $x, float $y)
|
||||||
|
{
|
||||||
|
$this->x = $x;
|
||||||
|
$this->y = $y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getX() : float
|
||||||
|
{
|
||||||
|
return $this->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getY() : float
|
||||||
|
{
|
||||||
|
return $this->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function translate(float $x, float $y) : OperationInterface
|
||||||
|
{
|
||||||
|
return new self($this->x + $x, $this->y + $y);
|
||||||
|
}
|
||||||
|
}
|
41
vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php
vendored
Executable file
41
vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php
vendored
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Path;
|
||||||
|
|
||||||
|
final class Move implements OperationInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $y;
|
||||||
|
|
||||||
|
public function __construct(float $x, float $y)
|
||||||
|
{
|
||||||
|
$this->x = $x;
|
||||||
|
$this->y = $y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getX() : float
|
||||||
|
{
|
||||||
|
return $this->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getY() : float
|
||||||
|
{
|
||||||
|
return $this->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function translate(float $x, float $y) : OperationInterface
|
||||||
|
{
|
||||||
|
return new self($this->x + $x, $this->y + $y);
|
||||||
|
}
|
||||||
|
}
|
12
vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php
vendored
Executable file
12
vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php
vendored
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Path;
|
||||||
|
|
||||||
|
interface OperationInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Translates the operation's coordinates.
|
||||||
|
*/
|
||||||
|
public function translate(float $x, float $y) : self;
|
||||||
|
}
|
106
vendor/bacon/bacon-qr-code/src/Renderer/Path/Path.php
vendored
Executable file
106
vendor/bacon/bacon-qr-code/src/Renderer/Path/Path.php
vendored
Executable file
@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\Path;
|
||||||
|
|
||||||
|
use IteratorAggregate;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal Representation of a vector path.
|
||||||
|
*/
|
||||||
|
final class Path implements IteratorAggregate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var OperationInterface[]
|
||||||
|
*/
|
||||||
|
private $operations = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the drawing operation to a certain position.
|
||||||
|
*/
|
||||||
|
public function move(float $x, float $y) : self
|
||||||
|
{
|
||||||
|
$path = clone $this;
|
||||||
|
$path->operations[] = new Move($x, $y);
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a line from the current position to another position.
|
||||||
|
*/
|
||||||
|
public function line(float $x, float $y) : self
|
||||||
|
{
|
||||||
|
$path = clone $this;
|
||||||
|
$path->operations[] = new Line($x, $y);
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws an elliptic arc from the current position to another position.
|
||||||
|
*/
|
||||||
|
public function ellipticArc(
|
||||||
|
float $xRadius,
|
||||||
|
float $yRadius,
|
||||||
|
float $xAxisRotation,
|
||||||
|
bool $largeArc,
|
||||||
|
bool $sweep,
|
||||||
|
float $x,
|
||||||
|
float $y
|
||||||
|
) : self {
|
||||||
|
$path = clone $this;
|
||||||
|
$path->operations[] = new EllipticArc($xRadius, $yRadius, $xAxisRotation, $largeArc, $sweep, $x, $y);
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a curve from the current position to another position.
|
||||||
|
*/
|
||||||
|
public function curve(float $x1, float $y1, float $x2, float $y2, float $x3, float $y3) : self
|
||||||
|
{
|
||||||
|
$path = clone $this;
|
||||||
|
$path->operations[] = new Curve($x1, $y1, $x2, $y2, $x3, $y3);
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes a sub-path.
|
||||||
|
*/
|
||||||
|
public function close() : self
|
||||||
|
{
|
||||||
|
$path = clone $this;
|
||||||
|
$path->operations[] = Close::instance();
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends another path to this one.
|
||||||
|
*/
|
||||||
|
public function append(self $other) : self
|
||||||
|
{
|
||||||
|
$path = clone $this;
|
||||||
|
$path->operations = array_merge($this->operations, $other->operations);
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function translate(float $x, float $y) : self
|
||||||
|
{
|
||||||
|
$path = new self();
|
||||||
|
|
||||||
|
foreach ($this->operations as $operation) {
|
||||||
|
$path->operations[] = $operation->translate($x, $y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return OperationInterface[]|Traversable
|
||||||
|
*/
|
||||||
|
public function getIterator() : Traversable
|
||||||
|
{
|
||||||
|
foreach ($this->operations as $operation) {
|
||||||
|
yield $operation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php
vendored
Executable file
86
vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php
vendored
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\QrCode;
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
|
||||||
|
final class PlainTextRenderer implements RendererInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* UTF-8 full block (U+2588)
|
||||||
|
*/
|
||||||
|
private const FULL_BLOCK = "\xe2\x96\x88";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UTF-8 upper half block (U+2580)
|
||||||
|
*/
|
||||||
|
private const UPPER_HALF_BLOCK = "\xe2\x96\x80";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UTF-8 lower half block (U+2584)
|
||||||
|
*/
|
||||||
|
private const LOWER_HALF_BLOCK = "\xe2\x96\x84";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UTF-8 no-break space (U+00A0)
|
||||||
|
*/
|
||||||
|
private const EMPTY_BLOCK = "\xc2\xa0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $margin;
|
||||||
|
|
||||||
|
public function __construct(int $margin = 2)
|
||||||
|
{
|
||||||
|
$this->margin = $margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException if matrix width doesn't match height
|
||||||
|
*/
|
||||||
|
public function render(QrCode $qrCode) : string
|
||||||
|
{
|
||||||
|
$matrix = $qrCode->getMatrix();
|
||||||
|
$matrixSize = $matrix->getWidth();
|
||||||
|
|
||||||
|
if ($matrixSize !== $matrix->getHeight()) {
|
||||||
|
throw new InvalidArgumentException('Matrix must have the same width and height');
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = $matrix->getArray()->toArray();
|
||||||
|
|
||||||
|
if (0 !== $matrixSize % 2) {
|
||||||
|
$rows[] = array_fill(0, $matrixSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$horizontalMargin = str_repeat(self::EMPTY_BLOCK, $this->margin);
|
||||||
|
$result = str_repeat("\n", (int) ceil($this->margin / 2));
|
||||||
|
|
||||||
|
for ($i = 0; $i < $matrixSize; $i += 2) {
|
||||||
|
$result .= $horizontalMargin;
|
||||||
|
|
||||||
|
$upperRow = $rows[$i];
|
||||||
|
$lowerRow = $rows[$i + 1];
|
||||||
|
|
||||||
|
for ($j = 0; $j < $matrixSize; ++$j) {
|
||||||
|
$upperBit = $upperRow[$j];
|
||||||
|
$lowerBit = $lowerRow[$j];
|
||||||
|
|
||||||
|
if ($upperBit) {
|
||||||
|
$result .= $lowerBit ? self::FULL_BLOCK : self::UPPER_HALF_BLOCK;
|
||||||
|
} else {
|
||||||
|
$result .= $lowerBit ? self::LOWER_HALF_BLOCK : self::EMPTY_BLOCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result .= $horizontalMargin . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$result .= str_repeat("\n", (int) ceil($this->margin / 2));
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
11
vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php
vendored
Executable file
11
vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php
vendored
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\QrCode;
|
||||||
|
|
||||||
|
interface RendererInterface
|
||||||
|
{
|
||||||
|
public function render(QrCode $qrCode) : string;
|
||||||
|
}
|
74
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/EyeFill.php
vendored
Executable file
74
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/EyeFill.php
vendored
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\RendererStyle;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\RuntimeException;
|
||||||
|
use BaconQrCode\Renderer\Color\ColorInterface;
|
||||||
|
|
||||||
|
final class EyeFill
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ColorInterface|null
|
||||||
|
*/
|
||||||
|
private $externalColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ColorInterface|null
|
||||||
|
*/
|
||||||
|
private $internalColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var self|null
|
||||||
|
*/
|
||||||
|
private static $inherit;
|
||||||
|
|
||||||
|
public function __construct(?ColorInterface $externalColor, ?ColorInterface $internalColor)
|
||||||
|
{
|
||||||
|
$this->externalColor = $externalColor;
|
||||||
|
$this->internalColor = $internalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function uniform(ColorInterface $color) : self
|
||||||
|
{
|
||||||
|
return new self($color, $color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function inherit() : self
|
||||||
|
{
|
||||||
|
return self::$inherit ?: self::$inherit = new self(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function inheritsBothColors() : bool
|
||||||
|
{
|
||||||
|
return null === $this->externalColor && null === $this->internalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function inheritsExternalColor() : bool
|
||||||
|
{
|
||||||
|
return null === $this->externalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function inheritsInternalColor() : bool
|
||||||
|
{
|
||||||
|
return null === $this->internalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExternalColor() : ColorInterface
|
||||||
|
{
|
||||||
|
if (null === $this->externalColor) {
|
||||||
|
throw new RuntimeException('External eye color inherits foreground color');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->externalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInternalColor() : ColorInterface
|
||||||
|
{
|
||||||
|
if (null === $this->internalColor) {
|
||||||
|
throw new RuntimeException('Internal eye color inherits foreground color');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->internalColor;
|
||||||
|
}
|
||||||
|
}
|
168
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php
vendored
Executable file
168
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php
vendored
Executable file
@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\RendererStyle;
|
||||||
|
|
||||||
|
use BaconQrCode\Exception\RuntimeException;
|
||||||
|
use BaconQrCode\Renderer\Color\ColorInterface;
|
||||||
|
use BaconQrCode\Renderer\Color\Gray;
|
||||||
|
|
||||||
|
final class Fill
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ColorInterface
|
||||||
|
*/
|
||||||
|
private $backgroundColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ColorInterface|null
|
||||||
|
*/
|
||||||
|
private $foregroundColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Gradient|null
|
||||||
|
*/
|
||||||
|
private $foregroundGradient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var EyeFill
|
||||||
|
*/
|
||||||
|
private $topLeftEyeFill;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var EyeFill
|
||||||
|
*/
|
||||||
|
private $topRightEyeFill;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var EyeFill
|
||||||
|
*/
|
||||||
|
private $bottomLeftEyeFill;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var self|null
|
||||||
|
*/
|
||||||
|
private static $default;
|
||||||
|
|
||||||
|
private function __construct(
|
||||||
|
ColorInterface $backgroundColor,
|
||||||
|
?ColorInterface $foregroundColor,
|
||||||
|
?Gradient $foregroundGradient,
|
||||||
|
EyeFill $topLeftEyeFill,
|
||||||
|
EyeFill $topRightEyeFill,
|
||||||
|
EyeFill $bottomLeftEyeFill
|
||||||
|
) {
|
||||||
|
$this->backgroundColor = $backgroundColor;
|
||||||
|
$this->foregroundColor = $foregroundColor;
|
||||||
|
$this->foregroundGradient = $foregroundGradient;
|
||||||
|
$this->topLeftEyeFill = $topLeftEyeFill;
|
||||||
|
$this->topRightEyeFill = $topRightEyeFill;
|
||||||
|
$this->bottomLeftEyeFill = $bottomLeftEyeFill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function default() : self
|
||||||
|
{
|
||||||
|
return self::$default ?: self::$default = self::uniformColor(new Gray(100), new Gray(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function withForegroundColor(
|
||||||
|
ColorInterface $backgroundColor,
|
||||||
|
ColorInterface $foregroundColor,
|
||||||
|
EyeFill $topLeftEyeFill,
|
||||||
|
EyeFill $topRightEyeFill,
|
||||||
|
EyeFill $bottomLeftEyeFill
|
||||||
|
) : self {
|
||||||
|
return new self(
|
||||||
|
$backgroundColor,
|
||||||
|
$foregroundColor,
|
||||||
|
null,
|
||||||
|
$topLeftEyeFill,
|
||||||
|
$topRightEyeFill,
|
||||||
|
$bottomLeftEyeFill
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function withForegroundGradient(
|
||||||
|
ColorInterface $backgroundColor,
|
||||||
|
Gradient $foregroundGradient,
|
||||||
|
EyeFill $topLeftEyeFill,
|
||||||
|
EyeFill $topRightEyeFill,
|
||||||
|
EyeFill $bottomLeftEyeFill
|
||||||
|
) : self {
|
||||||
|
return new self(
|
||||||
|
$backgroundColor,
|
||||||
|
null,
|
||||||
|
$foregroundGradient,
|
||||||
|
$topLeftEyeFill,
|
||||||
|
$topRightEyeFill,
|
||||||
|
$bottomLeftEyeFill
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function uniformColor(ColorInterface $backgroundColor, ColorInterface $foregroundColor) : self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
$backgroundColor,
|
||||||
|
$foregroundColor,
|
||||||
|
null,
|
||||||
|
EyeFill::inherit(),
|
||||||
|
EyeFill::inherit(),
|
||||||
|
EyeFill::inherit()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function uniformGradient(ColorInterface $backgroundColor, Gradient $foregroundGradient) : self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
$backgroundColor,
|
||||||
|
null,
|
||||||
|
$foregroundGradient,
|
||||||
|
EyeFill::inherit(),
|
||||||
|
EyeFill::inherit(),
|
||||||
|
EyeFill::inherit()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasGradientFill() : bool
|
||||||
|
{
|
||||||
|
return null !== $this->foregroundGradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBackgroundColor() : ColorInterface
|
||||||
|
{
|
||||||
|
return $this->backgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getForegroundColor() : ColorInterface
|
||||||
|
{
|
||||||
|
if (null === $this->foregroundColor) {
|
||||||
|
throw new RuntimeException('Fill uses a gradient, thus no foreground color is available');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->foregroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getForegroundGradient() : Gradient
|
||||||
|
{
|
||||||
|
if (null === $this->foregroundGradient) {
|
||||||
|
throw new RuntimeException('Fill uses a single color, thus no foreground gradient is available');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->foregroundGradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTopLeftEyeFill() : EyeFill
|
||||||
|
{
|
||||||
|
return $this->topLeftEyeFill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTopRightEyeFill() : EyeFill
|
||||||
|
{
|
||||||
|
return $this->topRightEyeFill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBottomLeftEyeFill() : EyeFill
|
||||||
|
{
|
||||||
|
return $this->bottomLeftEyeFill;
|
||||||
|
}
|
||||||
|
}
|
46
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php
vendored
Executable file
46
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php
vendored
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\RendererStyle;
|
||||||
|
|
||||||
|
use BaconQrCode\Renderer\Color\ColorInterface;
|
||||||
|
|
||||||
|
final class Gradient
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ColorInterface
|
||||||
|
*/
|
||||||
|
private $startColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ColorInterface
|
||||||
|
*/
|
||||||
|
private $endColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var GradientType
|
||||||
|
*/
|
||||||
|
private $type;
|
||||||
|
|
||||||
|
public function __construct(ColorInterface $startColor, ColorInterface $endColor, GradientType $type)
|
||||||
|
{
|
||||||
|
$this->startColor = $startColor;
|
||||||
|
$this->endColor = $endColor;
|
||||||
|
$this->type = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStartColor() : ColorInterface
|
||||||
|
{
|
||||||
|
return $this->startColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEndColor() : ColorInterface
|
||||||
|
{
|
||||||
|
return $this->endColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType() : GradientType
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
}
|
22
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php
vendored
Executable file
22
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php
vendored
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\RendererStyle;
|
||||||
|
|
||||||
|
use DASPRiD\Enum\AbstractEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method static self VERTICAL()
|
||||||
|
* @method static self HORIZONTAL()
|
||||||
|
* @method static self DIAGONAL()
|
||||||
|
* @method static self INVERSE_DIAGONAL()
|
||||||
|
* @method static self RADIAL()
|
||||||
|
*/
|
||||||
|
final class GradientType extends AbstractEnum
|
||||||
|
{
|
||||||
|
protected const VERTICAL = null;
|
||||||
|
protected const HORIZONTAL = null;
|
||||||
|
protected const DIAGONAL = null;
|
||||||
|
protected const INVERSE_DIAGONAL = null;
|
||||||
|
protected const RADIAL = null;
|
||||||
|
}
|
90
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/RendererStyle.php
vendored
Executable file
90
vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/RendererStyle.php
vendored
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode\Renderer\RendererStyle;
|
||||||
|
|
||||||
|
use BaconQrCode\Renderer\Eye\EyeInterface;
|
||||||
|
use BaconQrCode\Renderer\Eye\ModuleEye;
|
||||||
|
use BaconQrCode\Renderer\Module\ModuleInterface;
|
||||||
|
use BaconQrCode\Renderer\Module\SquareModule;
|
||||||
|
|
||||||
|
final class RendererStyle
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $margin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ModuleInterface
|
||||||
|
*/
|
||||||
|
private $module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var EyeInterface|null
|
||||||
|
*/
|
||||||
|
private $eye;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Fill
|
||||||
|
*/
|
||||||
|
private $fill;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
int $size,
|
||||||
|
int $margin = 4,
|
||||||
|
?ModuleInterface $module = null,
|
||||||
|
?EyeInterface $eye = null,
|
||||||
|
?Fill $fill = null
|
||||||
|
) {
|
||||||
|
$this->margin = $margin;
|
||||||
|
$this->size = $size;
|
||||||
|
$this->module = $module ?: SquareModule::instance();
|
||||||
|
$this->eye = $eye ?: new ModuleEye($this->module);
|
||||||
|
$this->fill = $fill ?: Fill::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withSize(int $size) : self
|
||||||
|
{
|
||||||
|
$style = clone $this;
|
||||||
|
$style->size = $size;
|
||||||
|
return $style;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withMargin(int $margin) : self
|
||||||
|
{
|
||||||
|
$style = clone $this;
|
||||||
|
$style->margin = $margin;
|
||||||
|
return $style;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSize() : int
|
||||||
|
{
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMargin() : int
|
||||||
|
{
|
||||||
|
return $this->margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getModule() : ModuleInterface
|
||||||
|
{
|
||||||
|
return $this->module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEye() : EyeInterface
|
||||||
|
{
|
||||||
|
return $this->eye;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFill() : Fill
|
||||||
|
{
|
||||||
|
return $this->fill;
|
||||||
|
}
|
||||||
|
}
|
71
vendor/bacon/bacon-qr-code/src/Writer.php
vendored
Executable file
71
vendor/bacon/bacon-qr-code/src/Writer.php
vendored
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCode;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Common\Version;
|
||||||
|
use BaconQrCode\Encoder\Encoder;
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
|
use BaconQrCode\Renderer\RendererInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QR code writer.
|
||||||
|
*/
|
||||||
|
final class Writer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Renderer instance.
|
||||||
|
*
|
||||||
|
* @var RendererInterface
|
||||||
|
*/
|
||||||
|
private $renderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new writer with a specific renderer.
|
||||||
|
*/
|
||||||
|
public function __construct(RendererInterface $renderer)
|
||||||
|
{
|
||||||
|
$this->renderer = $renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes QR code and returns it as string.
|
||||||
|
*
|
||||||
|
* Content is a string which *should* be encoded in UTF-8, in case there are
|
||||||
|
* non ASCII-characters present.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException if the content is empty
|
||||||
|
*/
|
||||||
|
public function writeString(
|
||||||
|
string $content,
|
||||||
|
string $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING,
|
||||||
|
?ErrorCorrectionLevel $ecLevel = null,
|
||||||
|
?Version $forcedVersion = null
|
||||||
|
) : string {
|
||||||
|
if (strlen($content) === 0) {
|
||||||
|
throw new InvalidArgumentException('Found empty contents');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $ecLevel) {
|
||||||
|
$ecLevel = ErrorCorrectionLevel::L();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderer->render(Encoder::encode($content, $ecLevel, $encoding, $forcedVersion));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes QR code to a file.
|
||||||
|
*
|
||||||
|
* @see Writer::writeString()
|
||||||
|
*/
|
||||||
|
public function writeFile(
|
||||||
|
string $content,
|
||||||
|
string $filename,
|
||||||
|
string $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING,
|
||||||
|
?ErrorCorrectionLevel $ecLevel = null,
|
||||||
|
?Version $forcedVersion = null
|
||||||
|
) : void {
|
||||||
|
file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel, $forcedVersion));
|
||||||
|
}
|
||||||
|
}
|
222
vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php
vendored
Executable file
222
vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php
vendored
Executable file
@ -0,0 +1,222 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\BitArray;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PHPUnit\Runner\Version as PHPUnitVersion;
|
||||||
|
|
||||||
|
final class BitArrayTest extends TestCase
|
||||||
|
{
|
||||||
|
private function getPhpUnitMajorVersion(): int
|
||||||
|
{
|
||||||
|
return (int) explode('.', PHPUnitVersion::id())[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetSet() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(33);
|
||||||
|
|
||||||
|
for ($i = 0; $i < 33; ++$i) {
|
||||||
|
$this->assertFalse($array->get($i));
|
||||||
|
$array->set($i);
|
||||||
|
$this->assertTrue($array->get($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNextSet1() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(32);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $array->getSize(); ++$i) {
|
||||||
|
if ($this->getPhpUnitMajorVersion() === 7) {
|
||||||
|
$this->assertEquals($i, 32, '', $array->getNextSet($i));
|
||||||
|
} else {
|
||||||
|
$this->assertEqualsWithDelta($i, 32, $array->getNextSet($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$array = new BitArray(33);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $array->getSize(); ++$i) {
|
||||||
|
if ($this->getPhpUnitMajorVersion() === 7) {
|
||||||
|
$this->assertEquals($i, 33, '', $array->getNextSet($i));
|
||||||
|
} else {
|
||||||
|
$this->assertEqualsWithDelta($i, 33, $array->getNextSet($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNextSet2() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(33);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $array->getSize(); ++$i) {
|
||||||
|
if ($this->getPhpUnitMajorVersion() === 7) {
|
||||||
|
$this->assertEquals($i, $i <= 31 ? 31 : 33, '', $array->getNextSet($i));
|
||||||
|
} else {
|
||||||
|
$this->assertEqualsWithDelta($i, $i <= 31 ? 31 : 33, $array->getNextSet($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$array = new BitArray(33);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $array->getSize(); ++$i) {
|
||||||
|
if ($this->getPhpUnitMajorVersion() === 7) {
|
||||||
|
$this->assertEquals($i, 32, '', $array->getNextSet($i));
|
||||||
|
} else {
|
||||||
|
$this->assertEqualsWithDelta($i, 32, $array->getNextSet($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNextSet3() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(63);
|
||||||
|
$array->set(31);
|
||||||
|
$array->set(32);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $array->getSize(); ++$i) {
|
||||||
|
if ($i <= 31) {
|
||||||
|
$expected = 31;
|
||||||
|
} elseif ($i <= 32) {
|
||||||
|
$expected = 32;
|
||||||
|
} else {
|
||||||
|
$expected = 63;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getPhpUnitMajorVersion() === 7) {
|
||||||
|
$this->assertEquals($i, $expected, '', $array->getNextSet($i));
|
||||||
|
} else {
|
||||||
|
$this->assertEqualsWithDelta($i, $expected, $array->getNextSet($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNextSet4() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(63);
|
||||||
|
$array->set(33);
|
||||||
|
$array->set(40);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $array->getSize(); ++$i) {
|
||||||
|
if ($i <= 33) {
|
||||||
|
$expected = 33;
|
||||||
|
} elseif ($i <= 40) {
|
||||||
|
$expected = 40;
|
||||||
|
} else {
|
||||||
|
$expected = 63;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getPhpUnitMajorVersion() === 7) {
|
||||||
|
$this->assertEquals($i, $expected, '', $array->getNextSet($i));
|
||||||
|
} else {
|
||||||
|
$this->assertEqualsWithDelta($i, $expected, $array->getNextSet($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNextSet5() : void
|
||||||
|
{
|
||||||
|
mt_srand(0xdeadbeef, MT_RAND_PHP);
|
||||||
|
|
||||||
|
for ($i = 0; $i < 10; ++$i) {
|
||||||
|
$array = new BitArray(mt_rand(1, 100));
|
||||||
|
$numSet = mt_rand(0, 19);
|
||||||
|
|
||||||
|
for ($j = 0; $j < $numSet; ++$j) {
|
||||||
|
$array->set(mt_rand(0, $array->getSize() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
$numQueries = mt_rand(0, 19);
|
||||||
|
|
||||||
|
for ($j = 0; $j < $numQueries; ++$j) {
|
||||||
|
$query = mt_rand(0, $array->getSize() - 1);
|
||||||
|
$expected = $query;
|
||||||
|
|
||||||
|
while ($expected < $array->getSize() && ! $array->get($expected)) {
|
||||||
|
++$expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
$actual = $array->getNextSet($query);
|
||||||
|
|
||||||
|
if ($actual !== $expected) {
|
||||||
|
$array->getNextSet($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetBulk() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(64);
|
||||||
|
$array->setBulk(32, 0xFFFF0000);
|
||||||
|
|
||||||
|
for ($i = 0; $i < 48; ++$i) {
|
||||||
|
$this->assertFalse($array->get($i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 48; $i < 64; ++$i) {
|
||||||
|
$this->assertTrue($array->get($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testClear() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(32);
|
||||||
|
|
||||||
|
for ($i = 0; $i < 32; ++$i) {
|
||||||
|
$array->set($i);
|
||||||
|
}
|
||||||
|
|
||||||
|
$array->clear();
|
||||||
|
|
||||||
|
for ($i = 0; $i < 32; ++$i) {
|
||||||
|
$this->assertFalse($array->get($i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetArray() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(64);
|
||||||
|
$array->set(0);
|
||||||
|
$array->set(63);
|
||||||
|
|
||||||
|
$ints = $array->getBitArray();
|
||||||
|
|
||||||
|
$this->assertSame(1, $ints[0]);
|
||||||
|
$this->assertSame(0x80000000, $ints[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsRange() : void
|
||||||
|
{
|
||||||
|
$array = new BitArray(64);
|
||||||
|
$this->assertTrue($array->isRange(0, 64, false));
|
||||||
|
$this->assertFalse($array->isRange(0, 64, true));
|
||||||
|
|
||||||
|
$array->set(32);
|
||||||
|
$this->assertTrue($array->isRange(32, 33, true));
|
||||||
|
|
||||||
|
$array->set(31);
|
||||||
|
$this->assertTrue($array->isRange(31, 33, true));
|
||||||
|
|
||||||
|
$array->set(34);
|
||||||
|
$this->assertFalse($array->isRange(31, 35, true));
|
||||||
|
|
||||||
|
for ($i = 0; $i < 31; ++$i) {
|
||||||
|
$array->set($i);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTrue($array->isRange(0, 33, true));
|
||||||
|
|
||||||
|
for ($i = 33; $i < 64; ++$i) {
|
||||||
|
$array->set($i);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTrue($array->isRange(0, 64, true));
|
||||||
|
$this->assertFalse($array->isRange(0, 64, false));
|
||||||
|
}
|
||||||
|
}
|
115
vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php
vendored
Executable file
115
vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php
vendored
Executable file
@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\BitArray;
|
||||||
|
use BaconQrCode\Common\BitMatrix;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class BitMatrixTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGetSet() : void
|
||||||
|
{
|
||||||
|
$matrix = new BitMatrix(33);
|
||||||
|
$this->assertEquals(33, $matrix->getHeight());
|
||||||
|
|
||||||
|
for ($y = 0; $y < 33; ++$y) {
|
||||||
|
for ($x = 0; $x < 33; ++$x) {
|
||||||
|
if ($y * $x % 3 === 0) {
|
||||||
|
$matrix->set($x, $y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($y = 0; $y < 33; $y++) {
|
||||||
|
for ($x = 0; $x < 33; ++$x) {
|
||||||
|
$this->assertSame(0 === $x * $y % 3, $matrix->get($x, $y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetRegion() : void
|
||||||
|
{
|
||||||
|
$matrix = new BitMatrix(5);
|
||||||
|
$matrix->setRegion(1, 1, 3, 3);
|
||||||
|
|
||||||
|
for ($y = 0; $y < 5; ++$y) {
|
||||||
|
for ($x = 0; $x < 5; ++$x) {
|
||||||
|
$this->assertSame($y >= 1 && $y <= 3 && $x >= 1 && $x <= 3, $matrix->get($x, $y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRectangularMatrix() : void
|
||||||
|
{
|
||||||
|
$matrix = new BitMatrix(75, 20);
|
||||||
|
$this->assertSame(75, $matrix->getWidth());
|
||||||
|
$this->assertSame(20, $matrix->getHeight());
|
||||||
|
|
||||||
|
$matrix->set(10, 0);
|
||||||
|
$matrix->set(11, 1);
|
||||||
|
$matrix->set(50, 2);
|
||||||
|
$matrix->set(51, 3);
|
||||||
|
$matrix->flip(74, 4);
|
||||||
|
$matrix->flip(0, 5);
|
||||||
|
|
||||||
|
$this->assertTrue($matrix->get(10, 0));
|
||||||
|
$this->assertTrue($matrix->get(11, 1));
|
||||||
|
$this->assertTrue($matrix->get(50, 2));
|
||||||
|
$this->assertTrue($matrix->get(51, 3));
|
||||||
|
$this->assertTrue($matrix->get(74, 4));
|
||||||
|
$this->assertTrue($matrix->get(0, 5));
|
||||||
|
|
||||||
|
$matrix->flip(50, 2);
|
||||||
|
$matrix->flip(51, 3);
|
||||||
|
|
||||||
|
$this->assertFalse($matrix->get(50, 2));
|
||||||
|
$this->assertFalse($matrix->get(51, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRectangularSetRegion() : void
|
||||||
|
{
|
||||||
|
$matrix = new BitMatrix(320, 240);
|
||||||
|
$this->assertSame(320, $matrix->getWidth());
|
||||||
|
$this->assertSame(240, $matrix->getHeight());
|
||||||
|
|
||||||
|
$matrix->setRegion(105, 22, 80, 12);
|
||||||
|
|
||||||
|
for ($y = 0; $y < 240; ++$y) {
|
||||||
|
for ($x = 0; $x < 320; ++$x) {
|
||||||
|
$this->assertEquals($y >= 22 && $y < 34 && $x >= 105 && $x < 185, $matrix->get($x, $y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetRow() : void
|
||||||
|
{
|
||||||
|
$matrix = new BitMatrix(102, 5);
|
||||||
|
|
||||||
|
for ($x = 0; $x < 102; ++$x) {
|
||||||
|
if (0 === ($x & 3)) {
|
||||||
|
$matrix->set($x, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$array1 = $matrix->getRow(2, null);
|
||||||
|
$this->assertSame(102, $array1->getSize());
|
||||||
|
|
||||||
|
$array2 = new BitArray(60);
|
||||||
|
$array2 = $matrix->getRow(2, $array2);
|
||||||
|
$this->assertSame(102, $array2->getSize());
|
||||||
|
|
||||||
|
$array3 = new BitArray(200);
|
||||||
|
$array3 = $matrix->getRow(2, $array3);
|
||||||
|
$this->assertSame(200, $array3->getSize());
|
||||||
|
|
||||||
|
for ($x = 0; $x < 102; ++$x) {
|
||||||
|
$on = (0 === ($x & 3));
|
||||||
|
|
||||||
|
$this->assertSame($on, $array1->get($x));
|
||||||
|
$this->assertSame($on, $array2->get($x));
|
||||||
|
$this->assertSame($on, $array3->get($x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php
vendored
Executable file
25
vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php
vendored
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\BitUtils;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class BitUtilsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testUnsignedRightShift() : void
|
||||||
|
{
|
||||||
|
$this->assertSame(1, BitUtils::unsignedRightShift(1, 0));
|
||||||
|
$this->assertSame(1, BitUtils::unsignedRightShift(10, 3));
|
||||||
|
$this->assertSame(536870910, BitUtils::unsignedRightShift(-10, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNumberOfTrailingZeros() : void
|
||||||
|
{
|
||||||
|
$this->assertSame(32, BitUtils::numberOfTrailingZeros(0));
|
||||||
|
$this->assertSame(1, BitUtils::numberOfTrailingZeros(10));
|
||||||
|
$this->assertSame(0, BitUtils::numberOfTrailingZeros(15));
|
||||||
|
$this->assertSame(2, BitUtils::numberOfTrailingZeros(20));
|
||||||
|
}
|
||||||
|
}
|
25
vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php
vendored
Executable file
25
vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php
vendored
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Exception\OutOfBoundsException;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ErrorCorrectionLevelTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testBitsMatchConstants() : void
|
||||||
|
{
|
||||||
|
$this->assertSame(0x0, ErrorCorrectionLevel::M()->getBits());
|
||||||
|
$this->assertSame(0x1, ErrorCorrectionLevel::L()->getBits());
|
||||||
|
$this->assertSame(0x2, ErrorCorrectionLevel::H()->getBits());
|
||||||
|
$this->assertSame(0x3, ErrorCorrectionLevel::Q()->getBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInvalidErrorCorrectionLevelThrowsException() : void
|
||||||
|
{
|
||||||
|
$this->expectException(OutOfBoundsException::class);
|
||||||
|
ErrorCorrectionLevel::forBits(4);
|
||||||
|
}
|
||||||
|
}
|
94
vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php
vendored
Executable file
94
vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php
vendored
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Common\FormatInformation;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class FormatInformationTest extends TestCase
|
||||||
|
{
|
||||||
|
private const MASKED_TEST_FORMAT_INFO = 0x2bed;
|
||||||
|
private const UNMAKSED_TEST_FORMAT_INFO = self::MASKED_TEST_FORMAT_INFO ^ 0x5412;
|
||||||
|
|
||||||
|
public function testBitsDiffering() : void
|
||||||
|
{
|
||||||
|
$this->assertSame(0, FormatInformation::numBitsDiffering(1, 1));
|
||||||
|
$this->assertSame(1, FormatInformation::numBitsDiffering(0, 2));
|
||||||
|
$this->assertSame(2, FormatInformation::numBitsDiffering(1, 2));
|
||||||
|
$this->assertEquals(32, FormatInformation::numBitsDiffering(-1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDecode() : void
|
||||||
|
{
|
||||||
|
$expected = FormatInformation::decodeFormatInformation(
|
||||||
|
self::MASKED_TEST_FORMAT_INFO,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertNotNull($expected);
|
||||||
|
$this->assertSame(7, $expected->getDataMask());
|
||||||
|
$this->assertSame(ErrorCorrectionLevel::Q(), $expected->getErrorCorrectionLevel());
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
FormatInformation::decodeFormatInformation(
|
||||||
|
self::UNMAKSED_TEST_FORMAT_INFO,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDecodeWithBitDifference() : void
|
||||||
|
{
|
||||||
|
$expected = FormatInformation::decodeFormatInformation(
|
||||||
|
self::MASKED_TEST_FORMAT_INFO,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
FormatInformation::decodeFormatInformation(
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0x1,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0x1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
FormatInformation::decodeFormatInformation(
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0x3,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0x3
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
FormatInformation::decodeFormatInformation(
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0x7,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0x7
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertNull(
|
||||||
|
FormatInformation::decodeFormatInformation(
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0xf,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0xf
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDecodeWithMisRead() : void
|
||||||
|
{
|
||||||
|
$expected = FormatInformation::decodeFormatInformation(
|
||||||
|
self::MASKED_TEST_FORMAT_INFO,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$expected,
|
||||||
|
FormatInformation::decodeFormatInformation(
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0x3,
|
||||||
|
self::MASKED_TEST_FORMAT_INFO ^ 0xf
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
19
vendor/bacon/bacon-qr-code/test/Common/ModeTest.php
vendored
Executable file
19
vendor/bacon/bacon-qr-code/test/Common/ModeTest.php
vendored
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\Mode;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ModeTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testBitsMatchConstants() : void
|
||||||
|
{
|
||||||
|
$this->assertSame(0x0, Mode::TERMINATOR()->getBits());
|
||||||
|
$this->assertSame(0x1, Mode::NUMERIC()->getBits());
|
||||||
|
$this->assertSame(0x2, Mode::ALPHANUMERIC()->getBits());
|
||||||
|
$this->assertSame(0x4, Mode::BYTE()->getBits());
|
||||||
|
$this->assertSame(0x8, Mode::KANJI()->getBits());
|
||||||
|
}
|
||||||
|
}
|
96
vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php
vendored
Executable file
96
vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php
vendored
Executable file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\ReedSolomonCodec;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SplFixedArray;
|
||||||
|
|
||||||
|
class ReedSolomonTest extends TestCase
|
||||||
|
{
|
||||||
|
public function tabs() : array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[2, 0x7, 1, 1, 1],
|
||||||
|
[3, 0xb, 1, 1, 2],
|
||||||
|
[4, 0x13, 1, 1, 4],
|
||||||
|
[5, 0x25, 1, 1, 6],
|
||||||
|
[6, 0x43, 1, 1, 8],
|
||||||
|
[7, 0x89, 1, 1, 10],
|
||||||
|
[8, 0x11d, 1, 1, 32],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider tabs
|
||||||
|
*/
|
||||||
|
public function testCodec(int $symbolSize, int $generatorPoly, int $firstRoot, int $primitive, int $numRoots) : void
|
||||||
|
{
|
||||||
|
mt_srand(0xdeadbeef, MT_RAND_PHP);
|
||||||
|
|
||||||
|
$blockSize = (1 << $symbolSize) - 1;
|
||||||
|
$dataSize = $blockSize - $numRoots;
|
||||||
|
$codec = new ReedSolomonCodec($symbolSize, $generatorPoly, $firstRoot, $primitive, $numRoots, 0);
|
||||||
|
|
||||||
|
for ($errors = 0; $errors <= $numRoots / 2; ++$errors) {
|
||||||
|
// Load block with random data and encode
|
||||||
|
$block = SplFixedArray::fromArray(array_fill(0, $blockSize, 0), false);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $dataSize; ++$i) {
|
||||||
|
$block[$i] = mt_rand(0, $blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make temporary copy
|
||||||
|
$tBlock = clone $block;
|
||||||
|
$parity = SplFixedArray::fromArray(array_fill(0, $numRoots, 0), false);
|
||||||
|
$errorLocations = SplFixedArray::fromArray(array_fill(0, $blockSize, 0), false);
|
||||||
|
$erasures = [];
|
||||||
|
|
||||||
|
// Create parity
|
||||||
|
$codec->encode($block, $parity);
|
||||||
|
|
||||||
|
// Copy parity into test blocks
|
||||||
|
for ($i = 0; $i < $numRoots; ++$i) {
|
||||||
|
$block[$i + $dataSize] = $parity[$i];
|
||||||
|
$tBlock[$i + $dataSize] = $parity[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seed with errors
|
||||||
|
for ($i = 0; $i < $errors; ++$i) {
|
||||||
|
$errorValue = mt_rand(1, $blockSize);
|
||||||
|
|
||||||
|
do {
|
||||||
|
$errorLocation = mt_rand(0, $blockSize);
|
||||||
|
} while (0 !== $errorLocations[$errorLocation]);
|
||||||
|
|
||||||
|
$errorLocations[$errorLocation] = 1;
|
||||||
|
|
||||||
|
if (mt_rand(0, 1)) {
|
||||||
|
$erasures[] = $errorLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tBlock[$errorLocation] ^= $errorValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$erasures = SplFixedArray::fromArray($erasures, false);
|
||||||
|
|
||||||
|
// Decode the errored block
|
||||||
|
$foundErrors = $codec->decode($tBlock, $erasures);
|
||||||
|
|
||||||
|
if ($errors > 0 && null === $foundErrors) {
|
||||||
|
$this->assertSame($block, $tBlock, 'Decoder failed to correct errors');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertSame($errors, $foundErrors, 'Found errors do not equal expected errors');
|
||||||
|
|
||||||
|
for ($i = 0; $i < $foundErrors; ++$i) {
|
||||||
|
if (0 === $errorLocations[$erasures[$i]]) {
|
||||||
|
$this->fail(sprintf('Decoder indicates error in location %d without error', $erasures[$i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals($block, $tBlock, 'Decoder did not correct errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
vendor/bacon/bacon-qr-code/test/Common/VersionTest.php
vendored
Executable file
78
vendor/bacon/bacon-qr-code/test/Common/VersionTest.php
vendored
Executable file
@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Common;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Common\Version;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class VersionTest extends TestCase
|
||||||
|
{
|
||||||
|
public function versions() : array
|
||||||
|
{
|
||||||
|
$array = [];
|
||||||
|
|
||||||
|
for ($i = 1; $i <= 40; ++$i) {
|
||||||
|
$array[] = [$i, 4 * $i + 17];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function decodeInformation() : array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[7, 0x07c94],
|
||||||
|
[12, 0x0c762],
|
||||||
|
[17, 0x1145d],
|
||||||
|
[22, 0x168c9],
|
||||||
|
[27, 0x1b08e],
|
||||||
|
[32, 0x209d5],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider versions
|
||||||
|
*/
|
||||||
|
public function testVersionForNumber(int $versionNumber, int $dimension) : void
|
||||||
|
{
|
||||||
|
$version = Version::getVersionForNumber($versionNumber);
|
||||||
|
|
||||||
|
$this->assertNotNull($version);
|
||||||
|
$this->assertEquals($versionNumber, $version->getVersionNumber());
|
||||||
|
$this->assertNotNull($version->getAlignmentPatternCenters());
|
||||||
|
|
||||||
|
if ($versionNumber > 1) {
|
||||||
|
$this->assertTrue(count($version->getAlignmentPatternCenters()) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals($dimension, $version->getDimensionForVersion());
|
||||||
|
$this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::H()));
|
||||||
|
$this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::L()));
|
||||||
|
$this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::M()));
|
||||||
|
$this->assertNotNull($version->getEcBlocksForLevel(ErrorCorrectionLevel::Q()));
|
||||||
|
$this->assertNotNull($version->buildFunctionPattern());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider versions
|
||||||
|
*/
|
||||||
|
public function testGetProvisionalVersionForDimension(int $versionNumber, int $dimension) : void
|
||||||
|
{
|
||||||
|
$this->assertSame(
|
||||||
|
$versionNumber,
|
||||||
|
Version::getProvisionalVersionForDimension($dimension)->getVersionNumber()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider decodeInformation
|
||||||
|
*/
|
||||||
|
public function testDecodeVersionInformation(int $expectedVersion, int $mask) : void
|
||||||
|
{
|
||||||
|
$version = Version::decodeVersionInformation($mask);
|
||||||
|
$this->assertNotNull($version);
|
||||||
|
$this->assertSame($expectedVersion, $version->getVersionNumber());
|
||||||
|
}
|
||||||
|
}
|
487
vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php
vendored
Executable file
487
vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php
vendored
Executable file
@ -0,0 +1,487 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Encoder;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\BitArray;
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Common\Mode;
|
||||||
|
use BaconQrCode\Common\Version;
|
||||||
|
use BaconQrCode\Encoder\Encoder;
|
||||||
|
use BaconQrCode\Exception\WriterException;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionMethod;
|
||||||
|
use SplFixedArray;
|
||||||
|
|
||||||
|
final class EncoderTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ReflectionMethod[]
|
||||||
|
*/
|
||||||
|
protected $methods = [];
|
||||||
|
|
||||||
|
public function setUp() : void
|
||||||
|
{
|
||||||
|
// Hack to be able to test protected methods
|
||||||
|
$reflection = new ReflectionClass(Encoder::class);
|
||||||
|
|
||||||
|
foreach ($reflection->getMethods(ReflectionMethod::IS_STATIC) as $method) {
|
||||||
|
$method->setAccessible(true);
|
||||||
|
$this->methods[$method->getName()] = $method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetAlphanumericCode() : void
|
||||||
|
{
|
||||||
|
// The first ten code points are numbers.
|
||||||
|
for ($i = 0; $i < 10; ++$i) {
|
||||||
|
$this->assertSame($i, $this->methods['getAlphanumericCode']->invoke(null, ord('0') + $i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The next 26 code points are capital alphabet letters.
|
||||||
|
for ($i = 10; $i < 36; ++$i) {
|
||||||
|
// The first ten code points are numbers
|
||||||
|
$this->assertSame($i, $this->methods['getAlphanumericCode']->invoke(null, ord('A') + $i - 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Others are symbol letters.
|
||||||
|
$this->assertSame(36, $this->methods['getAlphanumericCode']->invoke(null, ord(' ')));
|
||||||
|
$this->assertSame(37, $this->methods['getAlphanumericCode']->invoke(null, ord('$')));
|
||||||
|
$this->assertSame(38, $this->methods['getAlphanumericCode']->invoke(null, ord('%')));
|
||||||
|
$this->assertSame(39, $this->methods['getAlphanumericCode']->invoke(null, ord('*')));
|
||||||
|
$this->assertSame(40, $this->methods['getAlphanumericCode']->invoke(null, ord('+')));
|
||||||
|
$this->assertSame(41, $this->methods['getAlphanumericCode']->invoke(null, ord('-')));
|
||||||
|
$this->assertSame(42, $this->methods['getAlphanumericCode']->invoke(null, ord('.')));
|
||||||
|
$this->assertSame(43, $this->methods['getAlphanumericCode']->invoke(null, ord('/')));
|
||||||
|
$this->assertSame(44, $this->methods['getAlphanumericCode']->invoke(null, ord(':')));
|
||||||
|
|
||||||
|
// Should return -1 for other letters.
|
||||||
|
$this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord('a')));
|
||||||
|
$this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord('#')));
|
||||||
|
$this->assertSame(-1, $this->methods['getAlphanumericCode']->invoke(null, ord("\0")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testChooseMode() : void
|
||||||
|
{
|
||||||
|
// Numeric mode
|
||||||
|
$this->assertSame(Mode::NUMERIC(), $this->methods['chooseMode']->invoke(null, '0'));
|
||||||
|
$this->assertSame(Mode::NUMERIC(), $this->methods['chooseMode']->invoke(null, '0123456789'));
|
||||||
|
|
||||||
|
// Alphanumeric mode
|
||||||
|
$this->assertSame(Mode::ALPHANUMERIC(), $this->methods['chooseMode']->invoke(null, 'A'));
|
||||||
|
$this->assertSame(
|
||||||
|
Mode::ALPHANUMERIC(),
|
||||||
|
$this->methods['chooseMode']->invoke(null, '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:')
|
||||||
|
);
|
||||||
|
|
||||||
|
// 8-bit byte mode
|
||||||
|
$this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, 'a'));
|
||||||
|
$this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, '#'));
|
||||||
|
$this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, ''));
|
||||||
|
|
||||||
|
// AIUE in Hiragana in SHIFT-JIS
|
||||||
|
$this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\x8\xa\x8\xa\x8\xa\x8\xa6"));
|
||||||
|
|
||||||
|
// Nihon in Kanji in SHIFT-JIS
|
||||||
|
$this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\x9\xf\x9\x7b"));
|
||||||
|
|
||||||
|
// Sou-Utso-Byou in Kanji in SHIFT-JIS
|
||||||
|
$this->assertSame(Mode::BYTE(), $this->methods['chooseMode']->invoke(null, "\xe\x4\x9\x5\x9\x61"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEncode() : void
|
||||||
|
{
|
||||||
|
$qrCode = Encoder::encode('ABCDEF', ErrorCorrectionLevel::H());
|
||||||
|
$expected = "<<\n"
|
||||||
|
. " mode: ALPHANUMERIC\n"
|
||||||
|
. " ecLevel: H\n"
|
||||||
|
. " version: 1\n"
|
||||||
|
. " maskPattern: 0\n"
|
||||||
|
. " matrix:\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n"
|
||||||
|
. " 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n"
|
||||||
|
. " 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n"
|
||||||
|
. ">>\n";
|
||||||
|
|
||||||
|
$this->assertSame($expected, (string) $qrCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSimpleUtf8Eci() : void
|
||||||
|
{
|
||||||
|
$qrCode = Encoder::encode('hello', ErrorCorrectionLevel::H(), 'utf-8');
|
||||||
|
$expected = "<<\n"
|
||||||
|
. " mode: BYTE\n"
|
||||||
|
. " ecLevel: H\n"
|
||||||
|
. " version: 1\n"
|
||||||
|
. " maskPattern: 3\n"
|
||||||
|
. " matrix:\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 1 0 1 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 0 0 0 0\n"
|
||||||
|
. " 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0\n"
|
||||||
|
. " 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 1 1 1\n"
|
||||||
|
. " 1 1 0 0 1 0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 0\n"
|
||||||
|
. " 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 1 0 0\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 0 0 0 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 1 0 0 0 1 0 0 1 0 0 0 0\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 1 1 0\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 1 1 0 0 0 0\n"
|
||||||
|
. ">>\n";
|
||||||
|
|
||||||
|
$this->assertSame($expected, (string) $qrCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAppendModeInfo() : void
|
||||||
|
{
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendModeInfo']->invoke(null, Mode::NUMERIC(), $bits);
|
||||||
|
$this->assertSame(' ...X', (string) $bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAppendLengthInfo() : void
|
||||||
|
{
|
||||||
|
// 1 letter (1/1), 10 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendLengthInfo']->invoke(
|
||||||
|
null,
|
||||||
|
1,
|
||||||
|
Version::getVersionForNumber(1),
|
||||||
|
Mode::NUMERIC(),
|
||||||
|
$bits
|
||||||
|
);
|
||||||
|
$this->assertSame(' ........ .X', (string) $bits);
|
||||||
|
|
||||||
|
// 2 letters (2/1), 11 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendLengthInfo']->invoke(
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
Version::getVersionForNumber(10),
|
||||||
|
Mode::ALPHANUMERIC(),
|
||||||
|
$bits
|
||||||
|
);
|
||||||
|
$this->assertSame(' ........ .X.', (string) $bits);
|
||||||
|
|
||||||
|
// 255 letters (255/1), 16 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendLengthInfo']->invoke(
|
||||||
|
null,
|
||||||
|
255,
|
||||||
|
Version::getVersionForNumber(27),
|
||||||
|
Mode::BYTE(),
|
||||||
|
$bits
|
||||||
|
);
|
||||||
|
$this->assertSame(' ........ XXXXXXXX', (string) $bits);
|
||||||
|
|
||||||
|
// 512 letters (1024/2), 12 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendLengthInfo']->invoke(
|
||||||
|
null,
|
||||||
|
512,
|
||||||
|
Version::getVersionForNumber(40),
|
||||||
|
Mode::KANJI(),
|
||||||
|
$bits
|
||||||
|
);
|
||||||
|
$this->assertSame(' ..X..... ....', (string) $bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAppendBytes() : void
|
||||||
|
{
|
||||||
|
// Should use appendNumericBytes.
|
||||||
|
// 1 = 01 = 0001 in 4 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendBytes']->invoke(
|
||||||
|
null,
|
||||||
|
'1',
|
||||||
|
Mode::NUMERIC(),
|
||||||
|
$bits,
|
||||||
|
Encoder::DEFAULT_BYTE_MODE_ECODING
|
||||||
|
);
|
||||||
|
$this->assertSame(' ...X', (string) $bits);
|
||||||
|
|
||||||
|
// Should use appendAlphaNumericBytes.
|
||||||
|
// A = 10 = 0xa = 001010 in 6 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendBytes']->invoke(
|
||||||
|
null,
|
||||||
|
'A',
|
||||||
|
Mode::ALPHANUMERIC(),
|
||||||
|
$bits,
|
||||||
|
Encoder::DEFAULT_BYTE_MODE_ECODING
|
||||||
|
);
|
||||||
|
$this->assertSame(' ..X.X.', (string) $bits);
|
||||||
|
|
||||||
|
// Should use append8BitBytes.
|
||||||
|
// 0x61, 0x62, 0x63
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendBytes']->invoke(
|
||||||
|
null,
|
||||||
|
'abc',
|
||||||
|
Mode::BYTE(),
|
||||||
|
$bits,
|
||||||
|
Encoder::DEFAULT_BYTE_MODE_ECODING
|
||||||
|
);
|
||||||
|
$this->assertSame(' .XX....X .XX...X. .XX...XX', (string) $bits);
|
||||||
|
|
||||||
|
// Should use appendKanjiBytes.
|
||||||
|
// 0x93, 0x5f
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendBytes']->invoke(
|
||||||
|
null,
|
||||||
|
"\x93\x5f",
|
||||||
|
Mode::KANJI(),
|
||||||
|
$bits,
|
||||||
|
Encoder::DEFAULT_BYTE_MODE_ECODING
|
||||||
|
);
|
||||||
|
$this->assertSame(' .XX.XX.. XXXXX', (string) $bits);
|
||||||
|
|
||||||
|
// Lower letters such as 'a' cannot be encoded in alphanumeric mode.
|
||||||
|
$this->expectException(WriterException::class);
|
||||||
|
$this->methods['appendBytes']->invoke(
|
||||||
|
null,
|
||||||
|
'a',
|
||||||
|
Mode::ALPHANUMERIC(),
|
||||||
|
$bits,
|
||||||
|
Encoder::DEFAULT_BYTE_MODE_ECODING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTerminateBits() : void
|
||||||
|
{
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['terminateBits']->invoke(null, 0, $bits);
|
||||||
|
$this->assertSame('', (string) $bits);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['terminateBits']->invoke(null, 1, $bits);
|
||||||
|
$this->assertSame(' ........', (string) $bits);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$bits->appendBits(0, 3);
|
||||||
|
$this->methods['terminateBits']->invoke(null, 1, $bits);
|
||||||
|
$this->assertSame(' ........', (string) $bits);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$bits->appendBits(0, 5);
|
||||||
|
$this->methods['terminateBits']->invoke(null, 1, $bits);
|
||||||
|
$this->assertSame(' ........', (string) $bits);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$bits->appendBits(0, 8);
|
||||||
|
$this->methods['terminateBits']->invoke(null, 1, $bits);
|
||||||
|
$this->assertSame(' ........', (string) $bits);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['terminateBits']->invoke(null, 2, $bits);
|
||||||
|
$this->assertSame(' ........ XXX.XX..', (string) $bits);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$bits->appendBits(0, 1);
|
||||||
|
$this->methods['terminateBits']->invoke(null, 3, $bits);
|
||||||
|
$this->assertSame(' ........ XXX.XX.. ...X...X', (string) $bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetNumDataBytesAndNumEcBytesForBlockId() : void
|
||||||
|
{
|
||||||
|
// Version 1-H.
|
||||||
|
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']
|
||||||
|
->invoke(null, 26, 9, 1, 0);
|
||||||
|
$this->assertSame(9, $numDataBytes);
|
||||||
|
$this->assertSame(17, $numEcBytes);
|
||||||
|
|
||||||
|
// Version 3-H. 2 blocks.
|
||||||
|
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']
|
||||||
|
->invoke(null, 70, 26, 2, 0);
|
||||||
|
$this->assertSame(13, $numDataBytes);
|
||||||
|
$this->assertSame(22, $numEcBytes);
|
||||||
|
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']
|
||||||
|
->invoke(null, 70, 26, 2, 1);
|
||||||
|
$this->assertSame(13, $numDataBytes);
|
||||||
|
$this->assertSame(22, $numEcBytes);
|
||||||
|
|
||||||
|
// Version 7-H. (4 + 1) blocks.
|
||||||
|
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']
|
||||||
|
->invoke(null, 196, 66, 5, 0);
|
||||||
|
$this->assertSame(13, $numDataBytes);
|
||||||
|
$this->assertSame(26, $numEcBytes);
|
||||||
|
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']
|
||||||
|
->invoke(null, 196, 66, 5, 4);
|
||||||
|
$this->assertSame(14, $numDataBytes);
|
||||||
|
$this->assertSame(26, $numEcBytes);
|
||||||
|
|
||||||
|
// Version 40-H. (20 + 61) blocks.
|
||||||
|
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']
|
||||||
|
->invoke(null, 3706, 1276, 81, 0);
|
||||||
|
$this->assertSame(15, $numDataBytes);
|
||||||
|
$this->assertSame(30, $numEcBytes);
|
||||||
|
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']
|
||||||
|
->invoke(null, 3706, 1276, 81, 20);
|
||||||
|
$this->assertSame(16, $numDataBytes);
|
||||||
|
$this->assertSame(30, $numEcBytes);
|
||||||
|
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']
|
||||||
|
->invoke(null, 3706, 1276, 81, 80);
|
||||||
|
$this->assertSame(16, $numDataBytes);
|
||||||
|
$this->assertSame(30, $numEcBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInterleaveWithEcBytes() : void
|
||||||
|
{
|
||||||
|
$dataBytes = SplFixedArray::fromArray([32, 65, 205, 69, 41, 220, 46, 128, 236], false);
|
||||||
|
$in = new BitArray();
|
||||||
|
|
||||||
|
foreach ($dataBytes as $dataByte) {
|
||||||
|
$in->appendBits($dataByte, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
$outBits = $this->methods['interleaveWithEcBytes']->invoke(null, $in, 26, 9, 1);
|
||||||
|
$expected = SplFixedArray::fromArray([
|
||||||
|
// Data bytes.
|
||||||
|
32, 65, 205, 69, 41, 220, 46, 128, 236,
|
||||||
|
// Error correction bytes.
|
||||||
|
42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61,
|
||||||
|
], false);
|
||||||
|
|
||||||
|
$out = $outBits->toBytes(0, count($expected));
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAppendNumericBytes() : void
|
||||||
|
{
|
||||||
|
// 1 = 01 = 0001 in 4 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendNumericBytes']->invoke(null, '1', $bits);
|
||||||
|
$this->assertSame(' ...X', (string) $bits);
|
||||||
|
|
||||||
|
// 12 = 0xc = 0001100 in 7 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendNumericBytes']->invoke(null, '12', $bits);
|
||||||
|
$this->assertSame(' ...XX..', (string) $bits);
|
||||||
|
|
||||||
|
// 123 = 0x7b = 0001111011 in 10 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendNumericBytes']->invoke(null, '123', $bits);
|
||||||
|
$this->assertSame(' ...XXXX. XX', (string) $bits);
|
||||||
|
|
||||||
|
// 1234 = "123" + "4" = 0001111011 + 0100 in 14 bits.
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendNumericBytes']->invoke(null, '1234', $bits);
|
||||||
|
$this->assertSame(' ...XXXX. XX.X..', (string) $bits);
|
||||||
|
|
||||||
|
// Empty
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendNumericBytes']->invoke(null, '', $bits);
|
||||||
|
$this->assertSame('', (string) $bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAppendAlphanumericBytes() : void
|
||||||
|
{
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendAlphanumericBytes']->invoke(null, 'A', $bits);
|
||||||
|
$this->assertSame(' ..X.X.', (string) $bits);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendAlphanumericBytes']->invoke(null, 'AB', $bits);
|
||||||
|
$this->assertSame(' ..XXX..X X.X', (string) $bits);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendAlphanumericBytes']->invoke(null, 'ABC', $bits);
|
||||||
|
$this->assertSame(' ..XXX..X X.X..XX. .', (string) $bits);
|
||||||
|
|
||||||
|
// Empty
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendAlphanumericBytes']->invoke(null, '', $bits);
|
||||||
|
$this->assertSame('', (string) $bits);
|
||||||
|
|
||||||
|
// Invalid data
|
||||||
|
$this->expectException(WriterException::class);
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendAlphanumericBytes']->invoke(null, 'abc', $bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAppend8BitBytes() : void
|
||||||
|
{
|
||||||
|
// 0x61, 0x62, 0x63
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['append8BitBytes']->invoke(null, 'abc', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING);
|
||||||
|
$this->assertSame(' .XX....X .XX...X. .XX...XX', (string) $bits);
|
||||||
|
|
||||||
|
// Empty
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['append8BitBytes']->invoke(null, '', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING);
|
||||||
|
$this->assertSame('', (string) $bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAppendKanjiBytes() : void
|
||||||
|
{
|
||||||
|
// Numbers are from page 21 of JISX0510:2004
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['appendKanjiBytes']->invoke(null, "\x93\x5f", $bits);
|
||||||
|
$this->assertSame(' .XX.XX.. XXXXX', (string) $bits);
|
||||||
|
|
||||||
|
$this->methods['appendKanjiBytes']->invoke(null, "\xe4\xaa", $bits);
|
||||||
|
$this->assertSame(' .XX.XX.. XXXXXXX. X.X.X.X. X.', (string) $bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGenerateEcBytes() : void
|
||||||
|
{
|
||||||
|
// Numbers are from http://www.swetake.com/qr/qr3.html and
|
||||||
|
// http://www.swetake.com/qr/qr9.html
|
||||||
|
$dataBytes = SplFixedArray::fromArray([32, 65, 205, 69, 41, 220, 46, 128, 236], false);
|
||||||
|
$ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17);
|
||||||
|
$expected = SplFixedArray::fromArray(
|
||||||
|
[42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$this->assertEquals($expected, $ecBytes);
|
||||||
|
|
||||||
|
$dataBytes = SplFixedArray::fromArray(
|
||||||
|
[67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 18);
|
||||||
|
$expected = SplFixedArray::fromArray(
|
||||||
|
[175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$this->assertEquals($expected, $ecBytes);
|
||||||
|
|
||||||
|
// High-order zero coefficient case.
|
||||||
|
$dataBytes = SplFixedArray::fromArray([32, 49, 205, 69, 42, 20, 0, 236, 17], false);
|
||||||
|
$ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17);
|
||||||
|
$expected = SplFixedArray::fromArray(
|
||||||
|
[0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213],
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$this->assertEquals($expected, $ecBytes);
|
||||||
|
}
|
||||||
|
}
|
251
vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php
vendored
Executable file
251
vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php
vendored
Executable file
@ -0,0 +1,251 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Encoder;
|
||||||
|
|
||||||
|
use BaconQrCode\Encoder\ByteMatrix;
|
||||||
|
use BaconQrCode\Encoder\MaskUtil;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class MaskUtilTest extends TestCase
|
||||||
|
{
|
||||||
|
public function dataMaskBits() : array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[0, [
|
||||||
|
[1, 0, 1, 0, 1, 0],
|
||||||
|
[0, 1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1, 0],
|
||||||
|
[0, 1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1, 0],
|
||||||
|
[0, 1, 0, 1, 0, 1],
|
||||||
|
]],
|
||||||
|
[1, [
|
||||||
|
[1, 1, 1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 0, 0, 0],
|
||||||
|
]],
|
||||||
|
[2, [
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
]],
|
||||||
|
[3, [
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[0, 0, 1, 0, 0, 1],
|
||||||
|
[0, 1, 0, 0, 1, 0],
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[0, 0, 1, 0, 0, 1],
|
||||||
|
[0, 1, 0, 0, 1, 0],
|
||||||
|
]],
|
||||||
|
[4, [
|
||||||
|
[1, 1, 1, 0, 0, 0],
|
||||||
|
[1, 1, 1, 0, 0, 0],
|
||||||
|
[0, 0, 0, 1, 1, 1],
|
||||||
|
[0, 0, 0, 1, 1, 1],
|
||||||
|
[1, 1, 1, 0, 0, 0],
|
||||||
|
[1, 1, 1, 0, 0, 0],
|
||||||
|
]],
|
||||||
|
[5, [
|
||||||
|
[1, 1, 1, 1, 1, 1],
|
||||||
|
[1, 0, 0, 0, 0, 0],
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[1, 0, 1, 0, 1, 0],
|
||||||
|
[1, 0, 0, 1, 0, 0],
|
||||||
|
[1, 0, 0, 0, 0, 0],
|
||||||
|
]],
|
||||||
|
[6, [
|
||||||
|
[1, 1, 1, 1, 1, 1],
|
||||||
|
[1, 1, 1, 0, 0, 0],
|
||||||
|
[1, 1, 0, 1, 1, 0],
|
||||||
|
[1, 0, 1, 0, 1, 0],
|
||||||
|
[1, 0, 1, 1, 0, 1],
|
||||||
|
[1, 0, 0, 0, 1, 1],
|
||||||
|
]],
|
||||||
|
[7, [
|
||||||
|
[1, 0, 1, 0, 1, 0],
|
||||||
|
[0, 0, 0, 1, 1, 1],
|
||||||
|
[1, 0, 0, 0, 1, 1],
|
||||||
|
[0, 1, 0, 1, 0, 1],
|
||||||
|
[1, 1, 1, 0, 0, 0],
|
||||||
|
[0, 1, 1, 1, 0, 0],
|
||||||
|
]],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataMaskBits
|
||||||
|
*/
|
||||||
|
public function testGetDatMaskBit(int $maskPattern, array $expected) : void
|
||||||
|
{
|
||||||
|
for ($x = 0; $x < 6; ++$x) {
|
||||||
|
for ($y = 0; $y < 6; ++$y) {
|
||||||
|
$this->assertSame(
|
||||||
|
1 === $expected[$y][$x],
|
||||||
|
MaskUtil::getDataMaskBit($maskPattern, $x, $y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testApplyMaskPenaltyRule1() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(4, 1);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(1, 0, 0);
|
||||||
|
$matrix->set(2, 0, 0);
|
||||||
|
$matrix->set(3, 0, 0);
|
||||||
|
|
||||||
|
$this->assertSame(0, MaskUtil::applyMaskPenaltyRule1($matrix));
|
||||||
|
|
||||||
|
// Horizontal
|
||||||
|
$matrix = new ByteMatrix(6, 1);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(1, 0, 0);
|
||||||
|
$matrix->set(2, 0, 0);
|
||||||
|
$matrix->set(3, 0, 0);
|
||||||
|
$matrix->set(4, 0, 0);
|
||||||
|
$matrix->set(5, 0, 1);
|
||||||
|
$this->assertSame(3, MaskUtil::applyMaskPenaltyRule1($matrix));
|
||||||
|
$matrix->set(5, 0, 0);
|
||||||
|
$this->assertSame(4, MaskUtil::applyMaskPenaltyRule1($matrix));
|
||||||
|
|
||||||
|
// Vertical
|
||||||
|
$matrix = new ByteMatrix(1, 6);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(0, 1, 0);
|
||||||
|
$matrix->set(0, 2, 0);
|
||||||
|
$matrix->set(0, 3, 0);
|
||||||
|
$matrix->set(0, 4, 0);
|
||||||
|
$matrix->set(0, 5, 1);
|
||||||
|
$this->assertSame(3, MaskUtil::applyMaskPenaltyRule1($matrix));
|
||||||
|
$matrix->set(0, 5, 0);
|
||||||
|
$this->assertSame(4, MaskUtil::applyMaskPenaltyRule1($matrix));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testApplyMaskPenaltyRule2() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(1, 1);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$this->assertSame(0, MaskUtil::applyMaskPenaltyRule2($matrix));
|
||||||
|
|
||||||
|
$matrix = new ByteMatrix(2, 2);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(1, 0, 0);
|
||||||
|
$matrix->set(0, 1, 0);
|
||||||
|
$matrix->set(1, 1, 1);
|
||||||
|
$this->assertSame(0, MaskUtil::applyMaskPenaltyRule2($matrix));
|
||||||
|
|
||||||
|
$matrix = new ByteMatrix(2, 2);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(1, 0, 0);
|
||||||
|
$matrix->set(0, 1, 0);
|
||||||
|
$matrix->set(1, 1, 0);
|
||||||
|
$this->assertSame(3, MaskUtil::applyMaskPenaltyRule2($matrix));
|
||||||
|
|
||||||
|
$matrix = new ByteMatrix(3, 3);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(1, 0, 0);
|
||||||
|
$matrix->set(2, 0, 0);
|
||||||
|
$matrix->set(0, 1, 0);
|
||||||
|
$matrix->set(1, 1, 0);
|
||||||
|
$matrix->set(2, 1, 0);
|
||||||
|
$matrix->set(0, 2, 0);
|
||||||
|
$matrix->set(1, 2, 0);
|
||||||
|
$matrix->set(2, 2, 0);
|
||||||
|
$this->assertSame(3 * 4, MaskUtil::applyMaskPenaltyRule2($matrix));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testApplyMaskPenalty3() : void
|
||||||
|
{
|
||||||
|
// Horizontal 00001011101
|
||||||
|
$matrix = new ByteMatrix(11, 1);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(1, 0, 0);
|
||||||
|
$matrix->set(2, 0, 0);
|
||||||
|
$matrix->set(3, 0, 0);
|
||||||
|
$matrix->set(4, 0, 1);
|
||||||
|
$matrix->set(5, 0, 0);
|
||||||
|
$matrix->set(6, 0, 1);
|
||||||
|
$matrix->set(7, 0, 1);
|
||||||
|
$matrix->set(8, 0, 1);
|
||||||
|
$matrix->set(9, 0, 0);
|
||||||
|
$matrix->set(10, 0, 1);
|
||||||
|
$this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix));
|
||||||
|
|
||||||
|
// Horizontal 10111010000
|
||||||
|
$matrix = new ByteMatrix(11, 1);
|
||||||
|
$matrix->set(0, 0, 1);
|
||||||
|
$matrix->set(1, 0, 0);
|
||||||
|
$matrix->set(2, 0, 1);
|
||||||
|
$matrix->set(3, 0, 1);
|
||||||
|
$matrix->set(4, 0, 1);
|
||||||
|
$matrix->set(5, 0, 0);
|
||||||
|
$matrix->set(6, 0, 1);
|
||||||
|
$matrix->set(7, 0, 0);
|
||||||
|
$matrix->set(8, 0, 0);
|
||||||
|
$matrix->set(9, 0, 0);
|
||||||
|
$matrix->set(10, 0, 0);
|
||||||
|
$this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix));
|
||||||
|
|
||||||
|
// Vertical 00001011101
|
||||||
|
$matrix = new ByteMatrix(1, 11);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(0, 1, 0);
|
||||||
|
$matrix->set(0, 2, 0);
|
||||||
|
$matrix->set(0, 3, 0);
|
||||||
|
$matrix->set(0, 4, 1);
|
||||||
|
$matrix->set(0, 5, 0);
|
||||||
|
$matrix->set(0, 6, 1);
|
||||||
|
$matrix->set(0, 7, 1);
|
||||||
|
$matrix->set(0, 8, 1);
|
||||||
|
$matrix->set(0, 9, 0);
|
||||||
|
$matrix->set(0, 10, 1);
|
||||||
|
$this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix));
|
||||||
|
|
||||||
|
// Vertical 10111010000
|
||||||
|
$matrix = new ByteMatrix(1, 11);
|
||||||
|
$matrix->set(0, 0, 1);
|
||||||
|
$matrix->set(0, 1, 0);
|
||||||
|
$matrix->set(0, 2, 1);
|
||||||
|
$matrix->set(0, 3, 1);
|
||||||
|
$matrix->set(0, 4, 1);
|
||||||
|
$matrix->set(0, 5, 0);
|
||||||
|
$matrix->set(0, 6, 1);
|
||||||
|
$matrix->set(0, 7, 0);
|
||||||
|
$matrix->set(0, 8, 0);
|
||||||
|
$matrix->set(0, 9, 0);
|
||||||
|
$matrix->set(0, 10, 0);
|
||||||
|
$this->assertSame(40, MaskUtil::applyMaskPenaltyRule3($matrix));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testApplyMaskPenaltyRule4() : void
|
||||||
|
{
|
||||||
|
// Dark cell ratio = 0%
|
||||||
|
$matrix = new ByteMatrix(1, 1);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$this->assertSame(100, MaskUtil::applyMaskPenaltyRule4($matrix));
|
||||||
|
|
||||||
|
// Dark cell ratio = 5%
|
||||||
|
$matrix = new ByteMatrix(2, 1);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(0, 0, 1);
|
||||||
|
$this->assertSame(0, MaskUtil::applyMaskPenaltyRule4($matrix));
|
||||||
|
|
||||||
|
// Dark cell ratio = 66.67%
|
||||||
|
$matrix = new ByteMatrix(6, 1);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(1, 0, 1);
|
||||||
|
$matrix->set(2, 0, 1);
|
||||||
|
$matrix->set(3, 0, 1);
|
||||||
|
$matrix->set(4, 0, 1);
|
||||||
|
$matrix->set(5, 0, 0);
|
||||||
|
$this->assertSame(30, MaskUtil::applyMaskPenaltyRule4($matrix));
|
||||||
|
}
|
||||||
|
}
|
335
vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php
vendored
Executable file
335
vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php
vendored
Executable file
@ -0,0 +1,335 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Encoder;
|
||||||
|
|
||||||
|
use BaconQrCode\Common\BitArray;
|
||||||
|
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||||
|
use BaconQrCode\Common\Version;
|
||||||
|
use BaconQrCode\Encoder\ByteMatrix;
|
||||||
|
use BaconQrCode\Encoder\MatrixUtil;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionMethod;
|
||||||
|
|
||||||
|
class MatrixUtilTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ReflectionMethod[]
|
||||||
|
*/
|
||||||
|
protected $methods = [];
|
||||||
|
|
||||||
|
public function setUp() : void
|
||||||
|
{
|
||||||
|
// Hack to be able to test protected methods
|
||||||
|
$reflection = new ReflectionClass(MatrixUtil::class);
|
||||||
|
|
||||||
|
foreach ($reflection->getMethods(ReflectionMethod::IS_STATIC) as $method) {
|
||||||
|
$method->setAccessible(true);
|
||||||
|
$this->methods[$method->getName()] = $method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testToString() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(3, 3);
|
||||||
|
$matrix->set(0, 0, 0);
|
||||||
|
$matrix->set(1, 0, 1);
|
||||||
|
$matrix->set(2, 0, 0);
|
||||||
|
$matrix->set(0, 1, 1);
|
||||||
|
$matrix->set(1, 1, 0);
|
||||||
|
$matrix->set(2, 1, 1);
|
||||||
|
$matrix->set(0, 2, -1);
|
||||||
|
$matrix->set(1, 2, -1);
|
||||||
|
$matrix->set(2, 2, -1);
|
||||||
|
|
||||||
|
$expected = " 0 1 0\n 1 0 1\n \n";
|
||||||
|
$this->assertSame($expected, (string) $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testClearMatrix() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(2, 2);
|
||||||
|
MatrixUtil::clearMatrix($matrix);
|
||||||
|
|
||||||
|
$this->assertSame(-1, $matrix->get(0, 0));
|
||||||
|
$this->assertSame(-1, $matrix->get(1, 0));
|
||||||
|
$this->assertSame(-1, $matrix->get(0, 1));
|
||||||
|
$this->assertSame(-1, $matrix->get(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmbedBasicPatterns1() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(21, 21);
|
||||||
|
MatrixUtil::clearMatrix($matrix);
|
||||||
|
$this->methods['embedBasicPatterns']->invoke(
|
||||||
|
null,
|
||||||
|
Version::getVersionForNumber(1),
|
||||||
|
$matrix
|
||||||
|
);
|
||||||
|
$expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 1 \n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 \n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 \n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 \n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 \n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 \n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 \n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 \n";
|
||||||
|
|
||||||
|
$this->assertSame($expected, (string) $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmbedBasicPatterns2() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(25, 25);
|
||||||
|
MatrixUtil::clearMatrix($matrix);
|
||||||
|
$this->methods['embedBasicPatterns']->invoke(
|
||||||
|
null,
|
||||||
|
Version::getVersionForNumber(2),
|
||||||
|
$matrix
|
||||||
|
);
|
||||||
|
$expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 1 1 1 1 1 1 \n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 0 1 0 1 \n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 1 0 0 0 1 \n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 1 1 1 1 \n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 \n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 \n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 \n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 \n";
|
||||||
|
|
||||||
|
$this->assertSame($expected, (string) $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmbedTypeInfo() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(21, 21);
|
||||||
|
MatrixUtil::clearMatrix($matrix);
|
||||||
|
$this->methods['embedTypeInfo']->invoke(
|
||||||
|
null,
|
||||||
|
ErrorCorrectionLevel::M(),
|
||||||
|
5,
|
||||||
|
$matrix
|
||||||
|
);
|
||||||
|
$expected = " 0 \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " \n"
|
||||||
|
. " 1 \n"
|
||||||
|
. " 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 0 \n"
|
||||||
|
. " 1 \n";
|
||||||
|
|
||||||
|
$this->assertSame($expected, (string) $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmbedVersionInfo() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(21, 21);
|
||||||
|
MatrixUtil::clearMatrix($matrix);
|
||||||
|
$this->methods['maybeEmbedVersionInfo']->invoke(
|
||||||
|
null,
|
||||||
|
Version::getVersionForNumber(7),
|
||||||
|
$matrix
|
||||||
|
);
|
||||||
|
$expected = " 0 0 1 \n"
|
||||||
|
. " 0 1 0 \n"
|
||||||
|
. " 0 1 0 \n"
|
||||||
|
. " 0 1 1 \n"
|
||||||
|
. " 1 1 1 \n"
|
||||||
|
. " 0 0 0 \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " 0 0 0 0 1 0 \n"
|
||||||
|
. " 0 1 1 1 1 0 \n"
|
||||||
|
. " 1 0 0 1 1 0 \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n"
|
||||||
|
. " \n";
|
||||||
|
|
||||||
|
$this->assertSame($expected, (string) $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmbedDataBits() : void
|
||||||
|
{
|
||||||
|
$matrix = new ByteMatrix(21, 21);
|
||||||
|
MatrixUtil::clearMatrix($matrix);
|
||||||
|
$this->methods['embedBasicPatterns']->invoke(
|
||||||
|
null,
|
||||||
|
Version::getVersionForNumber(1),
|
||||||
|
$matrix
|
||||||
|
);
|
||||||
|
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['embedDataBits']->invoke(
|
||||||
|
null,
|
||||||
|
$bits,
|
||||||
|
-1,
|
||||||
|
$matrix
|
||||||
|
);
|
||||||
|
|
||||||
|
$expected = " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
|
||||||
|
|
||||||
|
$this->assertSame($expected, (string) $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildMatrix() : void
|
||||||
|
{
|
||||||
|
$bytes = [
|
||||||
|
32, 65, 205, 69, 41, 220, 46, 128, 236, 42, 159, 74, 221, 244, 169,
|
||||||
|
239, 150, 138, 70, 237, 85, 224, 96, 74, 219 , 61
|
||||||
|
];
|
||||||
|
$bits = new BitArray();
|
||||||
|
|
||||||
|
foreach ($bytes as $byte) {
|
||||||
|
$bits->appendBits($byte, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
$matrix = new ByteMatrix(21, 21);
|
||||||
|
MatrixUtil::buildMatrix(
|
||||||
|
$bits,
|
||||||
|
ErrorCorrectionLevel::H(),
|
||||||
|
Version::getVersionForNumber(1),
|
||||||
|
3,
|
||||||
|
$matrix
|
||||||
|
);
|
||||||
|
|
||||||
|
$expected = " 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n"
|
||||||
|
. " 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n"
|
||||||
|
. " 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n"
|
||||||
|
. " 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n"
|
||||||
|
. " 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n"
|
||||||
|
. " 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n"
|
||||||
|
. " 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n"
|
||||||
|
. " 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n"
|
||||||
|
. " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n"
|
||||||
|
. " 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n";
|
||||||
|
|
||||||
|
$this->assertSame($expected, (string) $matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindMsbSet() : void
|
||||||
|
{
|
||||||
|
$this->assertSame(0, $this->methods['findMsbSet']->invoke(null, 0));
|
||||||
|
$this->assertSame(1, $this->methods['findMsbSet']->invoke(null, 1));
|
||||||
|
$this->assertSame(8, $this->methods['findMsbSet']->invoke(null, 0x80));
|
||||||
|
$this->assertSame(32, $this->methods['findMsbSet']->invoke(null, 0x80000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCalculateBchCode() : void
|
||||||
|
{
|
||||||
|
// Encoding of type information.
|
||||||
|
// From Appendix C in JISX0510:2004 (p 65)
|
||||||
|
$this->assertSame(0xdc, $this->methods['calculateBchCode']->invoke(null, 5, 0x537));
|
||||||
|
// From http://www.swetake.com/qr/qr6.html
|
||||||
|
$this->assertSame(0x1c2, $this->methods['calculateBchCode']->invoke(null, 0x13, 0x537));
|
||||||
|
// From http://www.swetake.com/qr/qr11.html
|
||||||
|
$this->assertSame(0x214, $this->methods['calculateBchCode']->invoke(null, 0x1b, 0x537));
|
||||||
|
|
||||||
|
// Encoding of version information.
|
||||||
|
// From Appendix D in JISX0510:2004 (p 68)
|
||||||
|
$this->assertSame(0xc94, $this->methods['calculateBchCode']->invoke(null, 7, 0x1f25));
|
||||||
|
$this->assertSame(0x5bc, $this->methods['calculateBchCode']->invoke(null, 8, 0x1f25));
|
||||||
|
$this->assertSame(0xa99, $this->methods['calculateBchCode']->invoke(null, 9, 0x1f25));
|
||||||
|
$this->assertSame(0x4d3, $this->methods['calculateBchCode']->invoke(null, 10, 0x1f25));
|
||||||
|
$this->assertSame(0x9a6, $this->methods['calculateBchCode']->invoke(null, 20, 0x1f25));
|
||||||
|
$this->assertSame(0xd75, $this->methods['calculateBchCode']->invoke(null, 30, 0x1f25));
|
||||||
|
$this->assertSame(0xc69, $this->methods['calculateBchCode']->invoke(null, 40, 0x1f25));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMakeVersionInfoBits() : void
|
||||||
|
{
|
||||||
|
// From Appendix D in JISX0510:2004 (p 68)
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['makeVersionInfoBits']->invoke(null, Version::getVersionForNumber(7), $bits);
|
||||||
|
$this->assertSame(' ...XXXXX ..X..X.X ..', (string) $bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMakeTypeInfoBits() : void
|
||||||
|
{
|
||||||
|
// From Appendix D in JISX0510:2004 (p 68)
|
||||||
|
$bits = new BitArray();
|
||||||
|
$this->methods['makeTypeInfoBits']->invoke(null, ErrorCorrectionLevel::M(), 5, $bits);
|
||||||
|
$this->assertSame(' X......X X..XXX.', (string) $bits);
|
||||||
|
}
|
||||||
|
}
|
63
vendor/bacon/bacon-qr-code/test/Integration/ImagickRenderingTest.php
vendored
Executable file
63
vendor/bacon/bacon-qr-code/test/Integration/ImagickRenderingTest.php
vendored
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace BaconQrCodeTest\Integration;
|
||||||
|
|
||||||
|
use BaconQrCode\Renderer\Color\Rgb;
|
||||||
|
use BaconQrCode\Renderer\Eye\SquareEye;
|
||||||
|
use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
|
||||||
|
use BaconQrCode\Renderer\ImageRenderer;
|
||||||
|
use BaconQrCode\Renderer\Module\SquareModule;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\EyeFill;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\Fill;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\Gradient;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\GradientType;
|
||||||
|
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
||||||
|
use BaconQrCode\Writer;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Spatie\Snapshots\MatchesSnapshots;
|
||||||
|
|
||||||
|
final class ImagickRenderingTest extends TestCase
|
||||||
|
{
|
||||||
|
use MatchesSnapshots;
|
||||||
|
|
||||||
|
public function testGenericQrCode() : void
|
||||||
|
{
|
||||||
|
$renderer = new ImageRenderer(
|
||||||
|
new RendererStyle(400),
|
||||||
|
new ImagickImageBackEnd()
|
||||||
|
);
|
||||||
|
$writer = new Writer($renderer);
|
||||||
|
$tempName = tempnam(sys_get_temp_dir(), 'test') . '.png';
|
||||||
|
$writer->writeFile('Hello World!', $tempName);
|
||||||
|
|
||||||
|
$this->assertMatchesFileSnapshot($tempName);
|
||||||
|
unlink($tempName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIssue79() : void
|
||||||
|
{
|
||||||
|
$eye = SquareEye::instance();
|
||||||
|
$squareModule = SquareModule::instance();
|
||||||
|
|
||||||
|
$eyeFill = new EyeFill(new Rgb(100, 100, 55), new Rgb(100, 100, 255));
|
||||||
|
$gradient = new Gradient(new Rgb(100, 100, 55), new Rgb(100, 100, 255), GradientType::HORIZONTAL());
|
||||||
|
|
||||||
|
$renderer = new ImageRenderer(
|
||||||
|
new RendererStyle(
|
||||||
|
400,
|
||||||
|
2,
|
||||||
|
$squareModule,
|
||||||
|
$eye,
|
||||||
|
Fill::withForegroundGradient(new Rgb(255, 255, 255), $gradient, $eyeFill, $eyeFill, $eyeFill)
|
||||||
|
),
|
||||||
|
new ImagickImageBackEnd()
|
||||||
|
);
|
||||||
|
$writer = new Writer($renderer);
|
||||||
|
$tempName = tempnam(sys_get_temp_dir(), 'test') . '.png';
|
||||||
|
$writer->writeFile('https://apiroad.net/very-long-url', $tempName);
|
||||||
|
|
||||||
|
$this->assertMatchesFileSnapshot($tempName);
|
||||||
|
unlink($tempName);
|
||||||
|
}
|
||||||
|
}
|
BIN
vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png
vendored
Executable file
BIN
vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
BIN
vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png
vendored
Executable file
BIN
vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
117
vendor/bin/lessc
vendored
Executable file
117
vendor/bin/lessc
vendored
Executable file
@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy PHP file generated by Composer
|
||||||
|
*
|
||||||
|
* This file includes the referenced bin path (../wikimedia/less.php/bin/lessc)
|
||||||
|
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
||||||
|
*
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
||||||
|
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 80000) {
|
||||||
|
if (!class_exists('Composer\BinProxyWrapper')) {
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class BinProxyWrapper
|
||||||
|
{
|
||||||
|
private $handle;
|
||||||
|
private $position;
|
||||||
|
private $realpath;
|
||||||
|
|
||||||
|
public function stream_open($path, $mode, $options, &$opened_path)
|
||||||
|
{
|
||||||
|
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
||||||
|
$opened_path = substr($path, 17);
|
||||||
|
$this->realpath = realpath($opened_path) ?: $opened_path;
|
||||||
|
$opened_path = $this->realpath;
|
||||||
|
$this->handle = fopen($this->realpath, $mode);
|
||||||
|
$this->position = 0;
|
||||||
|
|
||||||
|
return (bool) $this->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_read($count)
|
||||||
|
{
|
||||||
|
$data = fread($this->handle, $count);
|
||||||
|
|
||||||
|
if ($this->position === 0) {
|
||||||
|
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->position += strlen($data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_cast($castAs)
|
||||||
|
{
|
||||||
|
return $this->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_close()
|
||||||
|
{
|
||||||
|
fclose($this->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_lock($operation)
|
||||||
|
{
|
||||||
|
return $operation ? flock($this->handle, $operation) : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_seek($offset, $whence)
|
||||||
|
{
|
||||||
|
if (0 === fseek($this->handle, $offset, $whence)) {
|
||||||
|
$this->position = ftell($this->handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_tell()
|
||||||
|
{
|
||||||
|
return $this->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_eof()
|
||||||
|
{
|
||||||
|
return feof($this->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_stat()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_set_option($option, $arg1, $arg2)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function url_stat($path, $flags)
|
||||||
|
{
|
||||||
|
$path = substr($path, 17);
|
||||||
|
if (file_exists($path)) {
|
||||||
|
return stat($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) {
|
||||||
|
include("phpvfscomposer://" . __DIR__ . '/..'.'/wikimedia/less.php/bin/lessc');
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include __DIR__ . '/..'.'/wikimedia/less.php/bin/lessc';
|
572
vendor/composer/ClassLoader.php
vendored
Executable file
572
vendor/composer/ClassLoader.php
vendored
Executable file
@ -0,0 +1,572 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see https://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see https://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
/** @var ?string */
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
|
// PSR-4
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, array<string, int>>
|
||||||
|
*/
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, array<int, string>>
|
||||||
|
*/
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, array<string, string[]>>
|
||||||
|
*/
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $useIncludePath = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
* @psalm-var array<string, string>
|
||||||
|
*/
|
||||||
|
private $classMap = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool[]
|
||||||
|
* @psalm-var array<string, bool>
|
||||||
|
*/
|
||||||
|
private $missingClasses = array();
|
||||||
|
|
||||||
|
/** @var ?string */
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var self[]
|
||||||
|
*/
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ?string $vendorDir
|
||||||
|
*/
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array<string, array<int, string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array<string, string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array<string, string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[] Array of classname => path
|
||||||
|
* @psalm-return array<string, string>
|
||||||
|
*/
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $classMap Class to filename map
|
||||||
|
* @psalm-param array<string, string> $classMap
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param string[]|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param string[]|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param string[]|string $paths The PSR-0 base directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param string[]|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return true|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return self[]
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @param string $ext
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
* @return void
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function includeFile($file)
|
||||||
|
{
|
||||||
|
include $file;
|
||||||
|
}
|
352
vendor/composer/InstalledVersions.php
vendored
Executable file
352
vendor/composer/InstalledVersions.php
vendored
Executable file
@ -0,0 +1,352 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
|
use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is copied in every Composer installed project and available to all
|
||||||
|
*
|
||||||
|
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||||
|
*
|
||||||
|
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||||
|
*
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class InstalledVersions
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var mixed[]|null
|
||||||
|
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||||
|
*/
|
||||||
|
private static $installed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
|
private static $canGetVendors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
$packages[] = array_keys($installed['versions']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 === \count($packages)) {
|
||||||
|
return $packages[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names with a specific type e.g. 'library'
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackagesByType($type)
|
||||||
|
{
|
||||||
|
$packagesByType = array();
|
||||||
|
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
foreach ($installed['versions'] as $name => $package) {
|
||||||
|
if (isset($package['type']) && $package['type'] === $type) {
|
||||||
|
$packagesByType[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packagesByType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package is installed
|
||||||
|
*
|
||||||
|
* This also returns true if the package name is provided or replaced by another package
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @param bool $includeDevRequirements
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (isset($installed['versions'][$packageName])) {
|
||||||
|
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package satisfies a version constraint
|
||||||
|
*
|
||||||
|
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||||
|
*
|
||||||
|
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||||
|
*
|
||||||
|
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||||
|
* @param string $packageName
|
||||||
|
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||||
|
{
|
||||||
|
$constraint = $parser->parseConstraints($constraint);
|
||||||
|
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||||
|
|
||||||
|
return $provided->matches($constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||||
|
*
|
||||||
|
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||||
|
* whether a given version of a package is installed, and not just whether it exists
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string Version constraint usable with composer/semver
|
||||||
|
*/
|
||||||
|
public static function getVersionRanges($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ranges = array();
|
||||||
|
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' || ', $ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getPrettyVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||||
|
*/
|
||||||
|
public static function getReference($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['reference'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||||
|
*/
|
||||||
|
public static function getInstallPath($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||||
|
*/
|
||||||
|
public static function getRootPackage()
|
||||||
|
{
|
||||||
|
$installed = self::getInstalled();
|
||||||
|
|
||||||
|
return $installed[0]['root'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw installed.php data for custom implementations
|
||||||
|
*
|
||||||
|
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||||
|
*/
|
||||||
|
public static function getRawData()
|
||||||
|
{
|
||||||
|
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
self::$installed = include __DIR__ . '/installed.php';
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||||
|
*
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
public static function getAllRawData()
|
||||||
|
{
|
||||||
|
return self::getInstalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets you reload the static array from another file
|
||||||
|
*
|
||||||
|
* This is only useful for complex integrations in which a project needs to use
|
||||||
|
* this class but then also needs to execute another project's autoloader in process,
|
||||||
|
* and wants to ensure both projects have access to their version of installed.php.
|
||||||
|
*
|
||||||
|
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||||
|
* the data it needs from this class, then call reload() with
|
||||||
|
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||||
|
* the project in which it runs can then also use this class safely, without
|
||||||
|
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||||
|
*
|
||||||
|
* @param array[] $data A vendor/composer/installed.php data set
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||||
|
*/
|
||||||
|
public static function reload($data)
|
||||||
|
{
|
||||||
|
self::$installed = $data;
|
||||||
|
self::$installedByVendor = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static function getInstalled()
|
||||||
|
{
|
||||||
|
if (null === self::$canGetVendors) {
|
||||||
|
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = array();
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
||||||
|
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||||
|
self::$installed = $installed[count($installed) - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
self::$installed = require __DIR__ . '/installed.php';
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$installed[] = self::$installed;
|
||||||
|
|
||||||
|
return $installed;
|
||||||
|
}
|
||||||
|
}
|
21
vendor/composer/LICENSE
vendored
Executable file
21
vendor/composer/LICENSE
vendored
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
11
vendor/composer/autoload_classmap.php
vendored
Executable file
11
vendor/composer/autoload_classmap.php
vendored
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
'lessc' => $vendorDir . '/wikimedia/less.php/lessc.inc.php',
|
||||||
|
);
|
10
vendor/composer/autoload_namespaces.php
vendored
Executable file
10
vendor/composer/autoload_namespaces.php
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Less' => array($vendorDir . '/wikimedia/less.php/lib'),
|
||||||
|
);
|
12
vendor/composer/autoload_psr4.php
vendored
Executable file
12
vendor/composer/autoload_psr4.php
vendored
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Endroid\\QrCode\\' => array($vendorDir . '/endroid/qr-code/src'),
|
||||||
|
'DASPRiD\\Enum\\' => array($vendorDir . '/dasprid/enum/src'),
|
||||||
|
'BaconQrCode\\' => array($vendorDir . '/bacon/bacon-qr-code/src'),
|
||||||
|
);
|
38
vendor/composer/autoload_real.php
vendored
Executable file
38
vendor/composer/autoload_real.php
vendored
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInit6bb82695b2f28e8ee61f74ae2d5c5202
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Composer\Autoload\ClassLoader
|
||||||
|
*/
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
require __DIR__ . '/platform_check.php';
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInit6bb82695b2f28e8ee61f74ae2d5c5202', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInit6bb82695b2f28e8ee61f74ae2d5c5202', 'loadClassLoader'));
|
||||||
|
|
||||||
|
require __DIR__ . '/autoload_static.php';
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInit6bb82695b2f28e8ee61f74ae2d5c5202::getInitializer($loader));
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
64
vendor/composer/autoload_static.php
vendored
Executable file
64
vendor/composer/autoload_static.php
vendored
Executable file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInit6bb82695b2f28e8ee61f74ae2d5c5202
|
||||||
|
{
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'E' =>
|
||||||
|
array (
|
||||||
|
'Endroid\\QrCode\\' => 15,
|
||||||
|
),
|
||||||
|
'D' =>
|
||||||
|
array (
|
||||||
|
'DASPRiD\\Enum\\' => 13,
|
||||||
|
),
|
||||||
|
'B' =>
|
||||||
|
array (
|
||||||
|
'BaconQrCode\\' => 12,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'Endroid\\QrCode\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/endroid/qr-code/src',
|
||||||
|
),
|
||||||
|
'DASPRiD\\Enum\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/dasprid/enum/src',
|
||||||
|
),
|
||||||
|
'BaconQrCode\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/bacon/bacon-qr-code/src',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixesPsr0 = array (
|
||||||
|
'L' =>
|
||||||
|
array (
|
||||||
|
'Less' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/wikimedia/less.php/lib',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $classMap = array (
|
||||||
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
'lessc' => __DIR__ . '/..' . '/wikimedia/less.php/lessc.inc.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInit6bb82695b2f28e8ee61f74ae2d5c5202::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInit6bb82695b2f28e8ee61f74ae2d5c5202::$prefixDirsPsr4;
|
||||||
|
$loader->prefixesPsr0 = ComposerStaticInit6bb82695b2f28e8ee61f74ae2d5c5202::$prefixesPsr0;
|
||||||
|
$loader->classMap = ComposerStaticInit6bb82695b2f28e8ee61f74ae2d5c5202::$classMap;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
260
vendor/composer/installed.json
vendored
Executable file
260
vendor/composer/installed.json
vendored
Executable file
@ -0,0 +1,260 @@
|
|||||||
|
{
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "bacon/bacon-qr-code",
|
||||||
|
"version": "2.0.7",
|
||||||
|
"version_normalized": "2.0.7.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Bacon/BaconQrCode.git",
|
||||||
|
"reference": "d70c840f68657ce49094b8d91f9ee0cc07fbf66c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/d70c840f68657ce49094b8d91f9ee0cc07fbf66c",
|
||||||
|
"reference": "d70c840f68657ce49094b8d91f9ee0cc07fbf66c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dasprid/enum": "^1.0.3",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phly/keep-a-changelog": "^2.1",
|
||||||
|
"phpunit/phpunit": "^7 | ^8 | ^9",
|
||||||
|
"spatie/phpunit-snapshot-assertions": "^4.2.9",
|
||||||
|
"squizlabs/php_codesniffer": "^3.4"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-imagick": "to generate QR code images"
|
||||||
|
},
|
||||||
|
"time": "2022-03-14T02:02:36+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/2.0.7"
|
||||||
|
},
|
||||||
|
"install-path": "../bacon/bacon-qr-code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dasprid/enum",
|
||||||
|
"version": "1.0.3",
|
||||||
|
"version_normalized": "1.0.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/DASPRiD/Enum.git",
|
||||||
|
"reference": "5abf82f213618696dda8e3bf6f64dd042d8542b2"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/DASPRiD/Enum/zipball/5abf82f213618696dda8e3bf6f64dd042d8542b2",
|
||||||
|
"reference": "5abf82f213618696dda8e3bf6f64dd042d8542b2",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7 | ^8 | ^9",
|
||||||
|
"squizlabs/php_codesniffer": "^3.4"
|
||||||
|
},
|
||||||
|
"time": "2020-10-02T16:03:48+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.3"
|
||||||
|
},
|
||||||
|
"install-path": "../dasprid/enum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "endroid/qr-code",
|
||||||
|
"version": "4.4.9",
|
||||||
|
"version_normalized": "4.4.9.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/endroid/qr-code.git",
|
||||||
|
"reference": "bf087fa1e93a1b7310e2d94d187e26ae51db199d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/endroid/qr-code/zipball/bf087fa1e93a1b7310e2d94d187e26ae51db199d",
|
||||||
|
"reference": "bf087fa1e93a1b7310e2d94d187e26ae51db199d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"bacon/bacon-qr-code": "^2.0.5",
|
||||||
|
"php": "^7.4||^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"endroid/quality": "dev-master",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"khanamiryan/qrcode-detector-decoder": "^1.0.4",
|
||||||
|
"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": "2022-05-10T07:25:08+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.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/4.4.9"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/endroid",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"install-path": "../endroid/qr-code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wikimedia/less.php",
|
||||||
|
"version": "v3.1.0",
|
||||||
|
"version_normalized": "3.1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/wikimedia/less.php.git",
|
||||||
|
"reference": "a486d78b9bd16b72f237fc6093aa56d69ce8bd13"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/wikimedia/less.php/zipball/a486d78b9bd16b72f237fc6093aa56d69ce8bd13",
|
||||||
|
"reference": "a486d78b9bd16b72f237fc6093aa56d69ce8bd13",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.9"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mediawiki/mediawiki-codesniffer": "34.0.0",
|
||||||
|
"mediawiki/minus-x": "1.0.0",
|
||||||
|
"php-parallel-lint/php-console-highlighter": "0.5.0",
|
||||||
|
"php-parallel-lint/php-parallel-lint": "1.2.0",
|
||||||
|
"phpunit/phpunit": "^8.5"
|
||||||
|
},
|
||||||
|
"time": "2020-12-11T19:33:31+00:00",
|
||||||
|
"bin": [
|
||||||
|
"bin/lessc"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"Less": "lib/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"lessc.inc.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Josh Schmidt",
|
||||||
|
"homepage": "https://github.com/oyejorge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Matt Agar",
|
||||||
|
"homepage": "https://github.com/agar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Martin Jantošovič",
|
||||||
|
"homepage": "https://github.com/Mordred"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP port of the Javascript version of LESS http://lesscss.org (Originally maintained by Josh Schmidt)",
|
||||||
|
"keywords": [
|
||||||
|
"css",
|
||||||
|
"less",
|
||||||
|
"less.js",
|
||||||
|
"lesscss",
|
||||||
|
"php",
|
||||||
|
"stylesheet"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/wikimedia/less.php/issues",
|
||||||
|
"source": "https://github.com/wikimedia/less.php/tree/v3.1.0"
|
||||||
|
},
|
||||||
|
"install-path": "../wikimedia/less.php"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"dev-package-names": []
|
||||||
|
}
|
59
vendor/composer/installed.php
vendored
Executable file
59
vendor/composer/installed.php
vendored
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
<?php return array(
|
||||||
|
'root' => array(
|
||||||
|
'name' => '__root__',
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '5e455c1499d4fba2d9bb825e4db8b58a3a6a595e',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev' => true,
|
||||||
|
),
|
||||||
|
'versions' => array(
|
||||||
|
'__root__' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '5e455c1499d4fba2d9bb825e4db8b58a3a6a595e',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'bacon/bacon-qr-code' => array(
|
||||||
|
'pretty_version' => '2.0.7',
|
||||||
|
'version' => '2.0.7.0',
|
||||||
|
'reference' => 'd70c840f68657ce49094b8d91f9ee0cc07fbf66c',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../bacon/bacon-qr-code',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'dasprid/enum' => array(
|
||||||
|
'pretty_version' => '1.0.3',
|
||||||
|
'version' => '1.0.3.0',
|
||||||
|
'reference' => '5abf82f213618696dda8e3bf6f64dd042d8542b2',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../dasprid/enum',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'endroid/qr-code' => array(
|
||||||
|
'pretty_version' => '4.4.9',
|
||||||
|
'version' => '4.4.9.0',
|
||||||
|
'reference' => 'bf087fa1e93a1b7310e2d94d187e26ae51db199d',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../endroid/qr-code',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'wikimedia/less.php' => array(
|
||||||
|
'pretty_version' => 'v3.1.0',
|
||||||
|
'version' => '3.1.0.0',
|
||||||
|
'reference' => 'a486d78b9bd16b72f237fc6093aa56d69ce8bd13',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../wikimedia/less.php',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
26
vendor/composer/platform_check.php
vendored
Executable file
26
vendor/composer/platform_check.php
vendored
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// platform_check.php @generated by Composer
|
||||||
|
|
||||||
|
$issues = array();
|
||||||
|
|
||||||
|
if (!(PHP_VERSION_ID >= 70400)) {
|
||||||
|
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($issues) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger_error(
|
||||||
|
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
22
vendor/dasprid/enum/LICENSE
vendored
Executable file
22
vendor/dasprid/enum/LICENSE
vendored
Executable file
@ -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.
|
164
vendor/dasprid/enum/README.md
vendored
Executable file
164
vendor/dasprid/enum/README.md
vendored
Executable file
@ -0,0 +1,164 @@
|
|||||||
|
# PHP 7.1 enums
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/DASPRiD/Enum.svg?branch=master)](https://travis-ci.org/DASPRiD/Enum)
|
||||||
|
[![Coverage Status](https://coveralls.io/repos/github/DASPRiD/Enum/badge.svg?branch=master)](https://coveralls.io/github/DASPRiD/Enum?branch=master)
|
||||||
|
[![Latest Stable Version](https://poser.pugx.org/dasprid/enum/v/stable)](https://packagist.org/packages/dasprid/enum)
|
||||||
|
[![Total Downloads](https://poser.pugx.org/dasprid/enum/downloads)](https://packagist.org/packages/dasprid/enum)
|
||||||
|
[![License](https://poser.pugx.org/dasprid/enum/license)](https://packagist.org/packages/dasprid/enum)
|
||||||
|
|
||||||
|
It is a well known fact that PHP is missing a basic enum type, ignoring the rather incomplete `SplEnum` implementation
|
||||||
|
which is only available as a PECL extension. There are also quite a few other userland enum implementations around,
|
||||||
|
but all of them have one or another compromise. This library tries to close that gap as far as PHP allows it to.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basics
|
||||||
|
|
||||||
|
At its core, there is the `DASPRiD\Enum\AbstractEnum` class, which by default will work with constants like any other
|
||||||
|
enum implementation you might know. The first clear difference is that you should define all the constants as protected
|
||||||
|
(so nobody outside your class can read them but the `AbstractEnum` can still do so). The other even mightier difference
|
||||||
|
is that, for simple enums, the value of the constant doesn't matter at all. Let's have a look at a simple example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DASPRiD\Enum\AbstractEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method static self MONDAY()
|
||||||
|
* @method static self TUESDAY()
|
||||||
|
* @method static self WEDNESDAY()
|
||||||
|
* @method static self THURSDAY()
|
||||||
|
* @method static self FRIDAY()
|
||||||
|
* @method static self SATURDAY()
|
||||||
|
* @method static self SUNDAY()
|
||||||
|
*/
|
||||||
|
final class WeekDay extends AbstractEnum
|
||||||
|
{
|
||||||
|
protected const MONDAY = null;
|
||||||
|
protected const TUESDAY = null;
|
||||||
|
protected const WEDNESDAY = null;
|
||||||
|
protected const THURSDAY = null;
|
||||||
|
protected const FRIDAY = null;
|
||||||
|
protected const SATURDAY = null;
|
||||||
|
protected const SUNDAY = null;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to provide constants for either internal use or public use, you can mark them as either private or public,
|
||||||
|
in which case they will be ignored by the enum, which only considers protected constants as valid values. As you can
|
||||||
|
see, we specifically defined the generated magic methods in a class level doc block, so anyone using this class will
|
||||||
|
automatically have proper auto-completion in their IDE. Now since you have defined the enum, you can simply use it like
|
||||||
|
that:
|
||||||
|
|
||||||
|
```php
|
||||||
|
function tellItLikeItIs(WeekDay $weekDay)
|
||||||
|
{
|
||||||
|
switch ($weekDay) {
|
||||||
|
case WeekDay::MONDAY():
|
||||||
|
echo 'Mondays are bad.';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WeekDay::FRIDAY():
|
||||||
|
echo 'Fridays are better.';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WeekDay::SATURDAY():
|
||||||
|
case WeekDay::SUNDAY():
|
||||||
|
echo 'Weekends are best.';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
echo 'Midweek days are so-so.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tellItLikeItIs(WeekDay::MONDAY());
|
||||||
|
tellItLikeItIs(WeekDay::WEDNESDAY());
|
||||||
|
tellItLikeItIs(WeekDay::FRIDAY());
|
||||||
|
tellItLikeItIs(WeekDay::SATURDAY());
|
||||||
|
tellItLikeItIs(WeekDay::SUNDAY());
|
||||||
|
```
|
||||||
|
|
||||||
|
### More complex example
|
||||||
|
|
||||||
|
Of course, all enums are singletons, which are not cloneable or serializable. Thus you can be sure that there is always
|
||||||
|
just one instance of the same type. Of course, the values of constants are not completely useless, let's have a look at
|
||||||
|
a more complex example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DASPRiD\Enum\AbstractEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method static self MERCURY()
|
||||||
|
* @method static self VENUS()
|
||||||
|
* @method static self EARTH()
|
||||||
|
* @method static self MARS()
|
||||||
|
* @method static self JUPITER()
|
||||||
|
* @method static self SATURN()
|
||||||
|
* @method static self URANUS()
|
||||||
|
* @method static self NEPTUNE()
|
||||||
|
*/
|
||||||
|
final class Planet extends AbstractEnum
|
||||||
|
{
|
||||||
|
protected const MERCURY = [3.303e+23, 2.4397e6];
|
||||||
|
protected const VENUS = [4.869e+24, 6.0518e6];
|
||||||
|
protected const EARTH = [5.976e+24, 6.37814e6];
|
||||||
|
protected const MARS = [6.421e+23, 3.3972e6];
|
||||||
|
protected const JUPITER = [1.9e+27, 7.1492e7];
|
||||||
|
protected const SATURN = [5.688e+26, 6.0268e7];
|
||||||
|
protected const URANUS = [8.686e+25, 2.5559e7];
|
||||||
|
protected const NEPTUNE = [1.024e+26, 2.4746e7];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Universal gravitational constant.
|
||||||
|
*
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private const G = 6.67300E-11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mass in kilograms.
|
||||||
|
*
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $mass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Radius in meters.
|
||||||
|
*
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $radius;
|
||||||
|
|
||||||
|
protected function __construct(float $mass, float $radius)
|
||||||
|
{
|
||||||
|
$this->mass = $mass;
|
||||||
|
$this->radius = $radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mass() : float
|
||||||
|
{
|
||||||
|
return $this->mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function radius() : float
|
||||||
|
{
|
||||||
|
return $this->radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function surfaceGravity() : float
|
||||||
|
{
|
||||||
|
return self::G * $this->mass / ($this->radius * $this->radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function surfaceWeight(float $otherMass) : float
|
||||||
|
{
|
||||||
|
return $otherMass * $this->surfaceGravity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$myMass = 80;
|
||||||
|
|
||||||
|
foreach (Planet::values() as $planet) {
|
||||||
|
printf("Your weight on %s is %f\n", $planet, $planet->surfaceWeight($myMass));
|
||||||
|
}
|
||||||
|
```
|
31
vendor/dasprid/enum/composer.json
vendored
Executable file
31
vendor/dasprid/enum/composer.json
vendored
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "dasprid/enum",
|
||||||
|
"description": "PHP 7.1 enum implementation",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ben Scholzen 'DASPRiD'",
|
||||||
|
"email": "mail@dasprids.de",
|
||||||
|
"homepage": "https://dasprids.de/",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"enum",
|
||||||
|
"map"
|
||||||
|
],
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7 | ^8 | ^9",
|
||||||
|
"squizlabs/php_codesniffer": "^3.4"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"DASPRiD\\Enum\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"DASPRiD\\EnumTest\\": "test/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
vendor/dasprid/enum/phpunit.xml.dist
vendored
Executable file
17
vendor/dasprid/enum/phpunit.xml.dist
vendored
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
colors="true">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="DASPRiD\\Enum Tests">
|
||||||
|
<directory>./test</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||||
|
<directory suffix=".php">src</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
241
vendor/dasprid/enum/src/AbstractEnum.php
vendored
Executable file
241
vendor/dasprid/enum/src/AbstractEnum.php
vendored
Executable file
@ -0,0 +1,241 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace DASPRiD\Enum;
|
||||||
|
|
||||||
|
use DASPRiD\Enum\Exception\CloneNotSupportedException;
|
||||||
|
use DASPRiD\Enum\Exception\IllegalArgumentException;
|
||||||
|
use DASPRiD\Enum\Exception\MismatchException;
|
||||||
|
use DASPRiD\Enum\Exception\SerializeNotSupportedException;
|
||||||
|
use DASPRiD\Enum\Exception\UnserializeNotSupportedException;
|
||||||
|
use ReflectionClass;
|
||||||
|
|
||||||
|
abstract class AbstractEnum
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $ordinal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, array<string, static>>
|
||||||
|
*/
|
||||||
|
private static $values = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, bool>
|
||||||
|
*/
|
||||||
|
private static $allValuesLoaded = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, array>
|
||||||
|
*/
|
||||||
|
private static $constants = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor is private by default to avoid arbitrary enum creation.
|
||||||
|
*
|
||||||
|
* When creating your own constructor for a parameterized enum, make sure to declare it as protected, so that
|
||||||
|
* the static methods are able to construct it. Avoid making it public, as that would allow creation of
|
||||||
|
* non-singleton enum instances.
|
||||||
|
*/
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic getter which forwards all calls to {@see self::valueOf()}.
|
||||||
|
*
|
||||||
|
* @return static
|
||||||
|
*/
|
||||||
|
final public static function __callStatic(string $name, array $arguments) : self
|
||||||
|
{
|
||||||
|
return static::valueOf($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an enum with the specified name.
|
||||||
|
*
|
||||||
|
* The name must match exactly an identifier used to declare an enum in this type (extraneous whitespace characters
|
||||||
|
* are not permitted).
|
||||||
|
*
|
||||||
|
* @return static
|
||||||
|
* @throws IllegalArgumentException if the enum has no constant with the specified name
|
||||||
|
*/
|
||||||
|
final public static function valueOf(string $name) : self
|
||||||
|
{
|
||||||
|
if (isset(self::$values[static::class][$name])) {
|
||||||
|
return self::$values[static::class][$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
$constants = self::constants();
|
||||||
|
|
||||||
|
if (array_key_exists($name, $constants)) {
|
||||||
|
return self::createValue($name, $constants[$name][0], $constants[$name][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(sprintf('No enum constant %s::%s', static::class, $name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return static
|
||||||
|
*/
|
||||||
|
private static function createValue(string $name, int $ordinal, array $arguments) : self
|
||||||
|
{
|
||||||
|
$instance = new static(...$arguments);
|
||||||
|
$instance->name = $name;
|
||||||
|
$instance->ordinal = $ordinal;
|
||||||
|
self::$values[static::class][$name] = $instance;
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains all possible types defined by this enum.
|
||||||
|
*
|
||||||
|
* @return static[]
|
||||||
|
*/
|
||||||
|
final public static function values() : array
|
||||||
|
{
|
||||||
|
if (isset(self::$allValuesLoaded[static::class])) {
|
||||||
|
return self::$values[static::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! isset(self::$values[static::class])) {
|
||||||
|
self::$values[static::class] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (self::constants() as $name => $constant) {
|
||||||
|
if (array_key_exists($name, self::$values[static::class])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static::createValue($name, $constant[0], $constant[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uasort(self::$values[static::class], function (self $a, self $b) {
|
||||||
|
return $a->ordinal() <=> $b->ordinal();
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$allValuesLoaded[static::class] = true;
|
||||||
|
return self::$values[static::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function constants() : array
|
||||||
|
{
|
||||||
|
if (isset(self::$constants[static::class])) {
|
||||||
|
return self::$constants[static::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$constants[static::class] = [];
|
||||||
|
$reflectionClass = new ReflectionClass(static::class);
|
||||||
|
$ordinal = -1;
|
||||||
|
|
||||||
|
foreach ($reflectionClass->getReflectionConstants() as $reflectionConstant) {
|
||||||
|
if (! $reflectionConstant->isProtected()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $reflectionConstant->getValue();
|
||||||
|
|
||||||
|
self::$constants[static::class][$reflectionConstant->name] = [
|
||||||
|
++$ordinal,
|
||||||
|
is_array($value) ? $value : []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$constants[static::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of this enum constant, exactly as declared in its enum declaration.
|
||||||
|
*
|
||||||
|
* Most programmers should use the {@see self::__toString()} method in preference to this one, as the toString
|
||||||
|
* method may return a more user-friendly name. This method is designed primarily for use in specialized situations
|
||||||
|
* where correctness depends on getting the exact name, which will not vary from release to release.
|
||||||
|
*/
|
||||||
|
final public function name() : string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial
|
||||||
|
* constant is assigned an ordinal of zero).
|
||||||
|
*
|
||||||
|
* Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data
|
||||||
|
* structures.
|
||||||
|
*/
|
||||||
|
final public function ordinal() : int
|
||||||
|
{
|
||||||
|
return $this->ordinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares this enum with the specified object for order.
|
||||||
|
*
|
||||||
|
* Returns negative integer, zero or positive integer as this object is less than, equal to or greater than the
|
||||||
|
* specified object.
|
||||||
|
*
|
||||||
|
* Enums are only comparable to other enums of the same type. The natural order implemented by this method is the
|
||||||
|
* order in which the constants are declared.
|
||||||
|
*
|
||||||
|
* @throws MismatchException if the passed enum is not of the same type
|
||||||
|
*/
|
||||||
|
final public function compareTo(self $other) : int
|
||||||
|
{
|
||||||
|
if (! $other instanceof static) {
|
||||||
|
throw new MismatchException(sprintf(
|
||||||
|
'The passed enum %s is not of the same type as %s',
|
||||||
|
get_class($other),
|
||||||
|
static::class
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->ordinal - $other->ordinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forbid cloning enums.
|
||||||
|
*
|
||||||
|
* @throws CloneNotSupportedException
|
||||||
|
*/
|
||||||
|
final public function __clone()
|
||||||
|
{
|
||||||
|
throw new CloneNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forbid serializing enums.
|
||||||
|
*
|
||||||
|
* @throws SerializeNotSupportedException
|
||||||
|
*/
|
||||||
|
final public function __sleep() : array
|
||||||
|
{
|
||||||
|
throw new SerializeNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forbid unserializing enums.
|
||||||
|
*
|
||||||
|
* @throws UnserializeNotSupportedException
|
||||||
|
*/
|
||||||
|
final public function __wakeup() : void
|
||||||
|
{
|
||||||
|
throw new UnserializeNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns the enum into a string representation.
|
||||||
|
*
|
||||||
|
* You may override this method to give a more user-friendly version.
|
||||||
|
*/
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
}
|
375
vendor/dasprid/enum/src/EnumMap.php
vendored
Executable file
375
vendor/dasprid/enum/src/EnumMap.php
vendored
Executable file
@ -0,0 +1,375 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace DASPRiD\Enum;
|
||||||
|
|
||||||
|
use DASPRiD\Enum\Exception\ExpectationException;
|
||||||
|
use DASPRiD\Enum\Exception\IllegalArgumentException;
|
||||||
|
use IteratorAggregate;
|
||||||
|
use Serializable;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specialized map implementation for use with enum type keys.
|
||||||
|
*
|
||||||
|
* All of the keys in an enum map must come from a single enum type that is specified, when the map is created. Enum
|
||||||
|
* maps are represented internally as arrays. This representation is extremely compact and efficient.
|
||||||
|
*
|
||||||
|
* Enum maps are maintained in the natural order of their keys (the order in which the enum constants are declared).
|
||||||
|
* This is reflected in the iterators returned by the collection views {@see self::getIterator()} and
|
||||||
|
* {@see self::values()}.
|
||||||
|
*
|
||||||
|
* Iterators returned by the collection views are not consistent: They may or may not show the effects of modifications
|
||||||
|
* to the map that occur while the iteration is in progress.
|
||||||
|
*/
|
||||||
|
final class EnumMap implements Serializable, IteratorAggregate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The class name of the key.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $keyType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the value.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $valueType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $allowNullValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All of the constants comprising the enum, cached for performance.
|
||||||
|
*
|
||||||
|
* @var array<int, AbstractEnum>
|
||||||
|
*/
|
||||||
|
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<int, mixed>
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
$values = [];
|
||||||
|
|
||||||
|
foreach ($this->values as $ordinal => $value) {
|
||||||
|
if (null === $value) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$values[$ordinal] = $this->unmaskNull($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serialize([
|
||||||
|
'keyType' => $this->keyType,
|
||||||
|
'valueType' => $this->valueType,
|
||||||
|
'allowNullValues' => $this->allowNullValues,
|
||||||
|
'values' => $values,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
10
vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php
vendored
Executable file
10
vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace DASPRiD\Enum\Exception;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
final class CloneNotSupportedException extends Exception implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
10
vendor/dasprid/enum/src/Exception/ExceptionInterface.php
vendored
Executable file
10
vendor/dasprid/enum/src/Exception/ExceptionInterface.php
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace DASPRiD\Enum\Exception;
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
interface ExceptionInterface extends Throwable
|
||||||
|
{
|
||||||
|
}
|
10
vendor/dasprid/enum/src/Exception/ExpectationException.php
vendored
Executable file
10
vendor/dasprid/enum/src/Exception/ExpectationException.php
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace DASPRiD\Enum\Exception;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
final class ExpectationException extends Exception implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
10
vendor/dasprid/enum/src/Exception/IllegalArgumentException.php
vendored
Executable file
10
vendor/dasprid/enum/src/Exception/IllegalArgumentException.php
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace DASPRiD\Enum\Exception;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
final class IllegalArgumentException extends Exception implements ExceptionInterface
|
||||||
|
{
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user