Batch 4a: vendor base packages

This commit is contained in:
sas.fajri
2026-04-15 15:15:07 +07:00
parent b8c0d83453
commit 5c1958aa04
739 changed files with 84446 additions and 0 deletions

7
vendor/autoload.php vendored Executable file
View File

@@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit801fbe69b9c17eeb5f87ba0125931956::getLoader();

9
vendor/bacon/bacon-qr-code/.gitignore vendored Executable file
View File

@@ -0,0 +1,9 @@
composer.lock
vendor
nbproject
.idea
.buildpath
.project
.DS_Store
.*.sw*
.*.un~

14
vendor/bacon/bacon-qr-code/.travis.yml vendored Executable file
View File

@@ -0,0 +1,14 @@
language: php
php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- hhvm
install:
- travis_retry composer install --no-interaction
- composer info -i
script: vendor/bin/phpunit --bootstrap tests/bootstrap.php --configuration tests/phpunit.xml tests

22
vendor/bacon/bacon-qr-code/LICENSE vendored Executable file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2013, Ben 'DASPRiD' Scholzen
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.

37
vendor/bacon/bacon-qr-code/Module.php vendored Executable file
View File

@@ -0,0 +1,37 @@
<?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;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
/**
* Module for generating QR codes.
*/
class Module implements AutoloaderProviderInterface
{
/**
* Get autoloader config.
*
* @return array
*/
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}

24
vendor/bacon/bacon-qr-code/README.md vendored Executable file
View File

@@ -0,0 +1,24 @@
QR Code generator
=================
Master: [![Build Status](https://api.travis-ci.org/Bacon/BaconQrCode.png?branch=master)](http://travis-ci.org/Bacon/BaconQrCode)
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
$renderer = new \BaconQrCode\Renderer\Image\Png();
$renderer->setHeight(256);
$renderer->setWidth(256);
$writer = new \BaconQrCode\Writer($renderer);
$writer->writeFile('Hello World!', 'qrcode.png');
```

View File

@@ -0,0 +1,43 @@
<?php
// Generated by ZF2's ./bin/classmap_generator.php
return array(
'BaconQrCode\Common\AbstractEnum' => __DIR__ . '/src/BaconQrCode/Common/AbstractEnum.php',
'BaconQrCode\Common\BitArray' => __DIR__ . '/src/BaconQrCode/Common/BitArray.php',
'BaconQrCode\Common\BitMatrix' => __DIR__ . '/src/BaconQrCode/Common/BitMatrix.php',
'BaconQrCode\Common\BitUtils' => __DIR__ . '/src/BaconQrCode/Common/BitUtils.php',
'BaconQrCode\Common\CharacterSetEci' => __DIR__ . '/src/BaconQrCode/Common/CharacterSetEci.php',
'BaconQrCode\Common\EcBlock' => __DIR__ . '/src/BaconQrCode/Common/EcBlock.php',
'BaconQrCode\Common\EcBlocks' => __DIR__ . '/src/BaconQrCode/Common/EcBlocks.php',
'BaconQrCode\Common\ErrorCorrectionLevel' => __DIR__ . '/src/BaconQrCode/Common/ErrorCorrectionLevel.php',
'BaconQrCode\Common\FormatInformation' => __DIR__ . '/src/BaconQrCode/Common/FormatInformation.php',
'BaconQrCode\Common\Mode' => __DIR__ . '/src/BaconQrCode/Common/Mode.php',
'BaconQrCode\Common\ReedSolomonCodec' => __DIR__ . '/src/BaconQrCode/Common/ReedSolomonCodec.php',
'BaconQrCode\Common\Version' => __DIR__ . '/src/BaconQrCode/Common/Version.php',
'BaconQrCode\Encoder\BlockPair' => __DIR__ . '/src/BaconQrCode/Encoder/BlockPair.php',
'BaconQrCode\Encoder\ByteMatrix' => __DIR__ . '/src/BaconQrCode/Encoder/ByteMatrix.php',
'BaconQrCode\Encoder\Encoder' => __DIR__ . '/src/BaconQrCode/Encoder/Encoder.php',
'BaconQrCode\Encoder\MaskUtil' => __DIR__ . '/src/BaconQrCode/Encoder/MaskUtil.php',
'BaconQrCode\Encoder\MatrixUtil' => __DIR__ . '/src/BaconQrCode/Encoder/MatrixUtil.php',
'BaconQrCode\Encoder\QrCode' => __DIR__ . '/src/BaconQrCode/Encoder/QrCode.php',
'BaconQrCode\Exception\ExceptionInterface' => __DIR__ . '/src/BaconQrCode/Exception/ExceptionInterface.php',
'BaconQrCode\Exception\InvalidArgumentException' => __DIR__ . '/src/BaconQrCode/Exception/InvalidArgumentException.php',
'BaconQrCode\Exception\OutOfBoundsException' => __DIR__ . '/src/BaconQrCode/Exception/OutOfBoundsException.php',
'BaconQrCode\Exception\RuntimeException' => __DIR__ . '/src/BaconQrCode/Exception/RuntimeException.php',
'BaconQrCode\Exception\UnexpectedValueException' => __DIR__ . '/src/BaconQrCode/Exception/UnexpectedValueException.php',
'BaconQrCode\Exception\WriterException' => __DIR__ . '/src/BaconQrCode/Exception/WriterException.php',
'BaconQrCode\Renderer\Color\Cmyk' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Cmyk.php',
'BaconQrCode\Renderer\Color\ColorInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Color/ColorInterface.php',
'BaconQrCode\Renderer\Color\Gray' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Gray.php',
'BaconQrCode\Renderer\Color\Rgb' => __DIR__ . '/src/BaconQrCode/Renderer/Color/Rgb.php',
'BaconQrCode\Renderer\Image\AbstractRenderer' => __DIR__ . '/src/BaconQrCode/Renderer/Image/AbstractRenderer.php',
'BaconQrCode\Renderer\Image\Decorator\DecoratorInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php',
'BaconQrCode\Renderer\Image\Decorator\FinderPattern' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php',
'BaconQrCode\Renderer\Image\Eps' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Eps.php',
'BaconQrCode\Renderer\Image\Png' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Png.php',
'BaconQrCode\Renderer\Image\RendererInterface' => __DIR__ . '/src/BaconQrCode/Renderer/Image/RendererInterface.php',
'BaconQrCode\Renderer\Image\Svg' => __DIR__ . '/src/BaconQrCode/Renderer/Image/Svg.php',
'BaconQrCode\Renderer\RendererInterface' => __DIR__ . '/src/BaconQrCode/Renderer/RendererInterface.php',
'BaconQrCode\Renderer\Text\Plain' => __DIR__ . '/src/BaconQrCode/Renderer/Text/Plain.php',
'BaconQrCode\Renderer\Text\Html' => __DIR__ . '/src/BaconQrCode/Renderer/Text/Html.php',
'BaconQrCode\Writer' => __DIR__ . '/src/BaconQrCode/Writer.php',
);

View File

@@ -0,0 +1,12 @@
<?php
return function ($class) {
static $map;
if (!$map) {
$map = include __DIR__ . '/autoload_classmap.php';
}
if (!isset($map[$class])) {
return false;
}
return include $map[$class];
};

View File

@@ -0,0 +1,2 @@
<?php
spl_autoload_register(include __DIR__ . '/autoload_function.php');

29
vendor/bacon/bacon-qr-code/composer.json vendored Executable file
View File

@@ -0,0 +1,29 @@
{
"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": "^5.4|^7.0",
"ext-iconv": "*"
},
"suggest": {
"ext-gd": "to generate QR code images"
},
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "http://www.dasprids.de",
"role": "Developer"
}
],
"autoload": {
"psr-0": {
"BaconQrCode": "src/"
}
},
"require-dev": {
"phpunit/phpunit": "^4.8"
}
}

View File

@@ -0,0 +1,115 @@
<?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;
use BaconQrCode\Exception;
use ReflectionClass;
/**
* A general enum implementation until we got SplEnum.
*/
abstract class AbstractEnum
{
/**
* Default value.
*/
const __default = null;
/**
* Current value.
*
* @var mixed
*/
protected $value;
/**
* Cache of constants.
*
* @var array
*/
protected $constants;
/**
* Whether to handle values strict or not.
*
* @var boolean
*/
protected $strict;
/**
* Creates a new enum.
*
* @param mixed $initialValue
* @param boolean $strict
*/
public function __construct($initialValue = null, $strict = false)
{
$this->strict = $strict;
$this->change($initialValue);
}
/**
* Changes the value of the enum.
*
* @param mixed $value
* @return void
*/
public function change($value)
{
if (!in_array($value, $this->getConstList(), $this->strict)) {
throw new Exception\UnexpectedValueException('Value not a const in enum ' . get_class($this));
}
$this->value = $value;
}
/**
* Gets current value.
*
* @return mixed
*/
public function get()
{
return $this->value;
}
/**
* Gets all constants (possible values) as an array.
*
* @param boolean $includeDefault
* @return array
*/
public function getConstList($includeDefault = true)
{
if ($this->constants === null) {
$reflection = new ReflectionClass($this);
$this->constants = $reflection->getConstants();
}
if ($includeDefault) {
return $this->constants;
}
$constants = $this->constants;
unset($constants['__default']);
return $constants;
}
/**
* Gets the name of the enum.
*
* @return string
*/
public function __toString()
{
return array_search($this->value, $this->getConstList());
}
}

View File

@@ -0,0 +1,435 @@
<?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;
use SplFixedArray;
/**
* A simple, fast array of bits.
*/
class BitArray
{
/**
* Bits represented as an array of integers.
*
* @var SplFixedArray
*/
protected $bits;
/**
* Size of the bit array in bits.
*
* @var integer
*/
protected $size;
/**
* Creates a new bit array with a given size.
*
* @param integer $size
*/
public function __construct($size = 0)
{
$this->size = $size;
$this->bits = new SplFixedArray(($this->size + 31) >> 3);
}
/**
* Gets the size in bits.
*
* @return integer
*/
public function getSize()
{
return $this->size;
}
/**
* Gets the size in bytes.
*
* @return integer
*/
public function getSizeInBytes()
{
return ($this->size + 7) >> 3;
}
/**
* Ensures that the array has a minimum capacity.
*
* @param integer $size
* @return void
*/
public function ensureCapacity($size)
{
if ($size > count($this->bits) << 5) {
$this->bits->setSize(($size + 31) >> 5);
}
}
/**
* Gets a specific bit.
*
* @param integer $i
* @return boolean
*/
public function get($i)
{
return ($this->bits[$i >> 5] & (1 << ($i & 0x1f))) !== 0;
}
/**
* Sets a specific bit.
*
* @param integer $i
* @return void
*/
public function set($i)
{
$this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f);
}
/**
* Flips a specific bit.
*
* @param integer $i
* @return void
*/
public function flip($i)
{
$this->bits[$i >> 5] ^= 1 << ($i & 0x1f);
}
/**
* Gets the next set bit position from a given position.
*
* @param integer $from
* @return integer
*/
public function getNextSet($from)
{
if ($from >= $this->size) {
return $this->size;
}
$bitsOffset = $from >> 5;
$currentBits = $this->bits[$bitsOffset];
$bitsLength = count($this->bits);
$currentBits &= ~((1 << ($from & 0x1f)) - 1);
while ($currentBits === 0) {
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.
*
* @param integer $from
* @return integer
*/
public function getNextUnset($from)
{
if ($from >= $this->size) {
return $this->size;
}
$bitsOffset = $from >> 5;
$currentBits = ~$this->bits[$bitsOffset];
$bitsLength = count($this->bits);
$currentBits &= ~((1 << ($from & 0x1f)) - 1);
while ($currentBits === 0) {
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.
*
* @param integer $i
* @param integer $newBits
* @return void
*/
public function setBulk($i, $newBits)
{
$this->bits[$i >> 5] = $newBits;
}
/**
* Sets a range of bits.
*
* @param integer $start
* @param integer $end
* @return void
* @throws Exception\InvalidArgumentException
*/
public function setRange($start, $end)
{
if ($end < $start) {
throw new Exception\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 ($firstBit === 0 && $lastBit === 31) {
$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.
*
* @return void
*/
public function clear()
{
$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.
*
* @param integer $start
* @param integer $end
* @param integer $value
* @return boolean
* @throws Exception\InvalidArgumentException
*/
public function isRange($start, $end, $value)
{
if ($end < $start) {
throw new Exception\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 ($firstBit === 0 && $lastBit === 31) {
$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.
*
* @param boolean $bit
* @return void
*/
public function appendBit($bit)
{
$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.
*
* @param integer $value
* @param integer $numBits
* @return void
* @throws Exception\InvalidArgumentException
*/
public function appendBits($value, $numBits)
{
if ($numBits < 0 || $numBits > 32) {
throw new Exception\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.
*
* @param BitArray $other
* @return void
*/
public function appendBitArray(self $other)
{
$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.
*
* @param BitArray $other
* @return void
* @throws Exception\InvalidArgumentException
*/
public function xorBits(self $other)
{
$bitsLength = count($this->bits);
$otherBits = $other->getBitArray();
if ($bitsLength !== count($otherBits)) {
throw new Exception\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.
*
* @param integer $bitOffset
* @param integer $numBytes
* @return SplFixedArray
*/
public function toBytes($bitOffset, $numBytes)
{
$bytes = new SplFixedArray($numBytes);
for ($i = 0; $i < $numBytes; $i++) {
$byte = 0;
for ($j = 0; $j < 8; $j++) {
if ($this->get($bitOffset)) {
$byte |= 1 << (7 - $j);
}
$bitOffset++;
}
$bytes[$i] = $byte;
}
return $bytes;
}
/**
* Gets the internal bit array.
*
* @return SplFixedArray
*/
public function getBitArray()
{
return $this->bits;
}
/**
* Reverses the array.
*
* @return void
*/
public function reverse()
{
$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.
*
* @return string
*/
public function __toString()
{
$result = '';
for ($i = 0; $i < $this->size; $i++) {
if (($i & 0x07) === 0) {
$result .= ' ';
}
$result .= $this->get($i) ? 'X' : '.';
}
return $result;
}
}

View File

@@ -0,0 +1,350 @@
<?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;
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 integer
*/
protected $width;
/**
* Height of the bit matrix.
*
* @var integer
*/
protected $height;
/**
* Size in bits of each individual row.
*
* @var integer
*/
protected $rowSize;
/**
* Bits representation.
*
* @var SplFixedArray
*/
protected $bits;
/**
* Creates a new bit matrix with given dimensions.
*
* @param integer $width
* @param integer|null $height
* @throws Exception\InvalidArgumentException
*/
public function __construct($width, $height = null)
{
if ($height === null) {
$height = $width;
}
if ($width < 1 || $height < 1) {
throw new Exception\InvalidArgumentException('Both dimensions must be greater than zero');
}
$this->width = $width;
$this->height = $height;
$this->rowSize = ($width + 31) >> 5;
$this->bits = new SplFixedArray($this->rowSize * $height);
}
/**
* Gets the requested bit, where true means black.
*
* @param integer $x
* @param integer $y
* @return boolean
*/
public function get($x, $y)
{
$offset = $y * $this->rowSize + ($x >> 5);
return (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1) !== 0;
}
/**
* Sets the given bit to true.
*
* @param integer $x
* @param integer $y
* @return void
*/
public function set($x, $y)
{
$offset = $y * $this->rowSize + ($x >> 5);
$this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f));
}
/**
* Flips the given bit.
*
* @param integer $x
* @param integer $y
* @return void
*/
public function flip($x, $y)
{
$offset = $y * $this->rowSize + ($x >> 5);
$this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f));
}
/**
* Clears all bits (set to false).
*
* @return void
*/
public function clear()
{
$max = count($this->bits);
for ($i = 0; $i < $max; $i++) {
$this->bits[$i] = 0;
}
}
/**
* Sets a square region of the bit matrix to true.
*
* @param integer $left
* @param integer $top
* @param integer $width
* @param integer $height
* @return void
*/
public function setRegion($left, $top, $width, $height)
{
if ($top < 0 || $left < 0) {
throw new Exception\InvalidArgumentException('Left and top must be non-negative');
}
if ($height < 1 || $width < 1) {
throw new Exception\InvalidArgumentException('Width and height must be at least 1');
}
$right = $left + $width;
$bottom = $top + $height;
if ($bottom > $this->height || $right > $this->width) {
throw new Exception\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.
*
* @param integer $y
* @param BitArray $row
* @return BitArray
*/
public function getRow($y, BitArray $row = null)
{
if ($row === null || $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.
*
* @param integer $y
* @param BitArray $row
* @return void
*/
public function setRow($y, BitArray $row)
{
$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 SplFixedArray
*/
public function getEnclosingRectangle()
{
$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 ($bits !== 0) {
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 (BitUtils::unsignedRightShift($bits, $bit) === 0) {
$bit--;
}
if (($x32 * 32 + $bit) > $right) {
$right = $x32 * 32 + $bit;
}
}
}
}
$width = $right - $left;
$height = $bottom - $top;
if ($width < 0 || $height < 0) {
return null;
}
return SplFixedArray::fromArray(array($left, $top, $width, $height), false);
}
/**
* Gets the most top left set bit.
*
* This is useful in detecting a corner of a 'pure' barcode.
*
* @return SplFixedArray
*/
public function getTopLeftOnBit()
{
$bitsOffset = 0;
while ($bitsOffset < count($this->bits) && $this->bits[$bitsOffset] === 0) {
$bitsOffset++;
}
if ($bitsOffset === count($this->bits)) {
return null;
}
$x = intval($bitsOffset / $this->rowSize);
$y = ($bitsOffset % $this->rowSize) << 5;
$bits = $this->bits[$bitsOffset];
$bit = 0;
while (($bits << (31 - $bit)) === 0) {
$bit++;
}
$x += $bit;
return SplFixedArray::fromArray(array($x, $y), false);
}
/**
* Gets the most bottom right set bit.
*
* This is useful in detecting a corner of a 'pure' barcode.
*
* @return SplFixedArray
*/
public function getBottomRightOnBit()
{
$bitsOffset = count($this->bits) - 1;
while ($bitsOffset >= 0 && $this->bits[$bitsOffset] === 0) {
$bitsOffset--;
}
if ($bitsOffset < 0) {
return null;
}
$x = intval($bitsOffset / $this->rowSize);
$y = ($bitsOffset % $this->rowSize) << 5;
$bits = $this->bits[$bitsOffset];
$bit = 0;
while (BitUtils::unsignedRightShift($bits, $bit) === 0) {
$bit--;
}
$x += $bit;
return SplFixedArray::fromArray(array($x, $y), false);
}
/**
* Gets the width of the matrix,
*
* @return integer
*/
public function getWidth()
{
return $this->width;
}
/**
* Gets the height of the matrix.
*
* @return integer
*/
public function getHeight()
{
return $this->height;
}
}

View File

@@ -0,0 +1,51 @@
<?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;
/**
* General bit utilities.
*
* All utility methods are based on 32-bit integers and also work on 64-bit
* systems.
*/
class BitUtils
{
/**
* Performs an unsigned right shift.
*
* This is the same as the unsigned right shift operator ">>>" in other
* languages.
*
* @param integer $a
* @param integer $b
* @return integer
*/
public static function unsignedRightShift($a, $b)
{
return (
$a >= 0
? $a >> $b
: (($a & 0x7fffffff) >> $b) | (0x40000000 >> ($b - 1))
);
}
/**
* Gets the number of trailing zeros.
*
* @param integer $i
* @return integer
*/
public static function numberOfTrailingZeros($i)
{
$lastPos = strrpos(str_pad(decbin($i), 32, '0', STR_PAD_LEFT), '1');
return $lastPos === false ? 32 : 31 - $lastPos;
}
}

View File

@@ -0,0 +1,134 @@
<?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 Character Set ECI, according to "Extended Channel
* Interpretations" 5.3.1.1 of ISO 18004.
*/
class CharacterSetEci extends AbstractEnum
{
/**#@+
* Character set constants.
*/
const CP437 = 0;
const ISO8859_1 = 1;
const ISO8859_2 = 4;
const ISO8859_3 = 5;
const ISO8859_4 = 6;
const ISO8859_5 = 7;
const ISO8859_6 = 8;
const ISO8859_7 = 9;
const ISO8859_8 = 10;
const ISO8859_9 = 11;
const ISO8859_10 = 12;
const ISO8859_11 = 13;
const ISO8859_12 = 14;
const ISO8859_13 = 15;
const ISO8859_14 = 16;
const ISO8859_15 = 17;
const ISO8859_16 = 18;
const SJIS = 20;
const CP1250 = 21;
const CP1251 = 22;
const CP1252 = 23;
const CP1256 = 24;
const UNICODE_BIG_UNMARKED = 25;
const UTF8 = 26;
const ASCII = 27;
const BIG5 = 28;
const GB18030 = 29;
const EUC_KR = 30;
/**#@-*/
/**
* Map between character names and their ECI values.
*
* @var array
*/
protected static $nameToEci = array(
'ISO-8859-1' => self::ISO8859_1,
'ISO-8859-2' => self::ISO8859_2,
'ISO-8859-3' => self::ISO8859_3,
'ISO-8859-4' => self::ISO8859_4,
'ISO-8859-5' => self::ISO8859_5,
'ISO-8859-6' => self::ISO8859_6,
'ISO-8859-7' => self::ISO8859_7,
'ISO-8859-8' => self::ISO8859_8,
'ISO-8859-9' => self::ISO8859_9,
'ISO-8859-10' => self::ISO8859_10,
'ISO-8859-11' => self::ISO8859_11,
'ISO-8859-12' => self::ISO8859_12,
'ISO-8859-13' => self::ISO8859_13,
'ISO-8859-14' => self::ISO8859_14,
'ISO-8859-15' => self::ISO8859_15,
'ISO-8859-16' => self::ISO8859_16,
'SHIFT-JIS' => self::SJIS,
'WINDOWS-1250' => self::CP1250,
'WINDOWS-1251' => self::CP1251,
'WINDOWS-1252' => self::CP1252,
'WINDOWS-1256' => self::CP1256,
'UTF-16BE' => self::UNICODE_BIG_UNMARKED,
'UTF-8' => self::UTF8,
'ASCII' => self::ASCII,
'GBK' => self::GB18030,
'EUC-KR' => self::EUC_KR,
);
/**
* Additional possible values for character sets.
*
* @var array
*/
protected $additionalValues = array(
self::CP437 => 2,
self::ASCII => 170,
);
/**
* Gets character set ECI by value.
*
* @param string $name
* @return CharacterSetEci|null
*/
public static function getCharacterSetECIByValue($value)
{
if ($value < 0 || $value >= 900) {
throw new Exception\InvalidArgumentException('Value must be between 0 and 900');
}
if (false !== ($key = array_search($value, self::$additionalValues))) {
$value = $key;
}
try {
return new self($value);
} catch (Exception\UnexpectedValueException $e) {
return null;
}
}
/**
* Gets character set ECI by name.
*
* @param string $name
* @return CharacterSetEci|null
*/
public static function getCharacterSetECIByName($name)
{
$name = strtoupper($name);
if (isset(self::$nameToEci[$name])) {
return new self(self::$nameToEci[$name]);
}
return null;
}
}

View File

@@ -0,0 +1,65 @@
<?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;
/**
* Encapsualtes 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.
*/
class EcBlock
{
/**
* How many times the block is used.
*
* @var integer
*/
protected $count;
/**
* Number of data codewords.
*
* @var integer
*/
protected $dataCodewords;
/**
* Creates a new EC block.
*
* @param integer $count
* @param integer $dataCodewords
*/
public function __construct($count, $dataCodewords)
{
$this->count = $count;
$this->dataCodewords = $dataCodewords;
}
/**
* Returns how many times the block is used.
*
* @return integer
*/
public function getCount()
{
return $this->count;
}
/**
* Returns the number of data codewords.
*
* @return integer
*/
public function getDataCodewords()
{
return $this->dataCodewords;
}
}

View File

@@ -0,0 +1,101 @@
<?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;
use SplFixedArray;
/**
* 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.
*/
class EcBlocks
{
/**
* Number of EC codewords per block.
*
* @var integer
*/
protected $ecCodewordsPerBlock;
/**
* List of EC blocks.
*
* @var SplFixedArray
*/
protected $ecBlocks;
/**
* Creates a new EC blocks instance.
*
* @param integer $ecCodewordsPerBlock
* @param EcBlock $ecb1
* @param EcBlock|null $ecb2
*/
public function __construct($ecCodewordsPerBlock, EcBlock $ecb1, EcBlock $ecb2 = null)
{
$this->ecCodewordsPerBlock = $ecCodewordsPerBlock;
$this->ecBlocks = new SplFixedArray($ecb2 === null ? 1 : 2);
$this->ecBlocks[0] = $ecb1;
if ($ecb2 !== null) {
$this->ecBlocks[1] = $ecb2;
}
}
/**
* Gets the number of EC codewords per block.
*
* @return integer
*/
public function getEcCodewordsPerBlock()
{
return $this->ecCodewordsPerBlock;
}
/**
* Gets the total number of EC block appearances.
*
* @return integer
*/
public function getNumBlocks()
{
$total = 0;
foreach ($this->ecBlocks as $ecBlock) {
$total += $ecBlock->getCount();
}
return $total;
}
/**
* Gets the total count of EC codewords.
*
* @return integer
*/
public function getTotalEcCodewords()
{
return $this->ecCodewordsPerBlock * $this->getNumBlocks();
}
/**
* Gets the EC blocks included in this collection.
*
* @return SplFixedArray
*/
public function getEcBlocks()
{
return $this->ecBlocks;
}
}

View File

@@ -0,0 +1,62 @@
<?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;
/**
* Enum representing the four error correction levels.
*/
class ErrorCorrectionLevel extends AbstractEnum
{
/**
* Level L, ~7% correction.
*/
const L = 0x1;
/**
* Level M, ~15% correction.
*/
const M = 0x0;
/**
* Level Q, ~25% correction.
*/
const Q = 0x3;
/**
* Level H, ~30% correction.
*/
const H = 0x2;
/**
* Gets the ordinal of this enumeration constant.
*
* @return integer
*/
public function getOrdinal()
{
switch ($this->value) {
case self::L:
return 0;
break;
case self::M:
return 1;
break;
case self::Q:
return 2;
break;
case self::H:
return 3;
break;
}
}
}

View File

@@ -0,0 +1,236 @@
<?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.
*/
const FORMAT_INFO_MASK_QR = 0x5412;
/**
* Lookup table for decoding format information.
*
* See ISO 18004:2006, Annex C, Table C.1
*
* @var array
*/
protected static $formatInfoDecodeLookup = array(
array(0x5412, 0x00),
array(0x5125, 0x01),
array(0x5e7c, 0x02),
array(0x5b4b, 0x03),
array(0x45f9, 0x04),
array(0x40ce, 0x05),
array(0x4f97, 0x06),
array(0x4aa0, 0x07),
array(0x77c4, 0x08),
array(0x72f3, 0x09),
array(0x7daa, 0x0a),
array(0x789d, 0x0b),
array(0x662f, 0x0c),
array(0x6318, 0x0d),
array(0x6c41, 0x0e),
array(0x6976, 0x0f),
array(0x1689, 0x10),
array(0x13be, 0x11),
array(0x1ce7, 0x12),
array(0x19d0, 0x13),
array(0x0762, 0x14),
array(0x0255, 0x15),
array(0x0d0c, 0x16),
array(0x083b, 0x17),
array(0x355f, 0x18),
array(0x3068, 0x19),
array(0x3f31, 0x1a),
array(0x3a06, 0x1b),
array(0x24b4, 0x1c),
array(0x2183, 0x1d),
array(0x2eda, 0x1e),
array(0x2bed, 0x1f),
);
/**
* Offset i holds the number of 1 bits in the binary representation of i.
*
* @var array
*/
protected static $bitsSetInHalfByte = array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
/**
* Error correction level.
*
* @var ErrorCorrectionLevel
*/
protected $ecLevel;
/**
* Data mask.
*
* @var integer
*/
protected $dataMask;
/**
* Creates a new format information instance.
*
* @param integer $formatInfo
*/
protected function __construct($formatInfo)
{
$this->ecLevel = new ErrorCorrectionLevel(($formatInfo >> 3) & 0x3);
$this->dataMask = $formatInfo & 0x7;
}
/**
* Checks how many bits are different between two integers.
*
* @param integer $a
* @param integer $b
* @return integer
*/
public static function numBitsDiffering($a, $b)
{
$a ^= $b;
return (
self::$bitsSetInHalfByte[$a & 0xf]
+ self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 4) & 0xf)]
+ self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 8) & 0xf)]
+ self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 12) & 0xf)]
+ self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 16) & 0xf)]
+ self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 20) & 0xf)]
+ self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 24) & 0xf)]
+ self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 28) & 0xf)]
);
}
/**
* Decodes format information.
*
* @param integer $maskedFormatInfo1
* @param integer $maskedFormatInfo2
* @return FormatInformation|null
*/
public static function decodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2)
{
$formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2);
if ($formatInfo !== null) {
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.
*
* @param integer $maskedFormatInfo1
* @param integer $maskedFormatInfo2
* @return FormatInformation|null
*/
protected static function doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2)
{
$bestDifference = PHP_INT_MAX;
$bestFormatInfo = 0;
foreach (self::$formatInfoDecodeLookup 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;
}
/**
* Gets the error correction level.
*
* @return ErrorCorrectionLevel
*/
public function getErrorCorrectionLevel()
{
return $this->ecLevel;
}
/**
* Gets the data mask.
*
* @return integer
*/
public function getDataMask()
{
return $this->dataMask;
}
/**
* Hashes the code of the EC level.
*
* @return integer
*/
public function hashCode()
{
return ($this->ecLevel->get() << 3) | $this->dataMask;
}
/**
* Verifies if this instance equals another one.
*
* @param mixed $other
* @return boolean
*/
public function equals($other) {
if (!$other instanceof self) {
return false;
}
return (
$this->ecLevel->get() === $other->getErrorCorrectionLevel()->get()
&& $this->dataMask === $other->getDataMask()
);
}
}

View File

@@ -0,0 +1,70 @@
<?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;
/**
* Enum representing various modes in which data can be encoded to bits.
*/
class Mode extends AbstractEnum
{
/**#@+
* Mode constants.
*/
const TERMINATOR = 0x0;
const NUMERIC = 0x1;
const ALPHANUMERIC = 0x2;
const STRUCTURED_APPEND = 0x3;
const BYTE = 0x4;
const ECI = 0x7;
const KANJI = 0x8;
const FNC1_FIRST_POSITION = 0x5;
const FNC1_SECOND_POSITION = 0x9;
const HANZI = 0xd;
/**#@-*/
/**
* Character count bits for each version.
*
* @var array
*/
protected static $characterCountBitsForVersions = array(
self::TERMINATOR => array(0, 0, 0),
self::NUMERIC => array(10, 12, 14),
self::ALPHANUMERIC => array(9, 11, 13),
self::STRUCTURED_APPEND => array(0, 0, 0),
self::BYTE => array(8, 16, 16),
self::ECI => array(0, 0, 0),
self::KANJI => array(8, 10, 12),
self::FNC1_FIRST_POSITION => array(0, 0, 0),
self::FNC1_SECOND_POSITION => array(0, 0, 0),
self::HANZI => array(8, 10, 12),
);
/**
* Gets the number of bits used in a specific QR code version.
*
* @param Version $version
* @return integer
*/
public function getCharacterCountBits(Version $version)
{
$number = $version->getVersionNumber();
if ($number <= 9) {
$offset = 0;
} elseif ($number <= 26) {
$offset = 1;
} else {
$offset = 2;
}
return self::$characterCountBitsForVersions[$this->value][$offset];
}
}

View File

@@ -0,0 +1,476 @@
<?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;
use BaconQrCode\Exception;
use SplFixedArray;
/**
* Reed-Solomon codec for 8-bit characters.
*
* Based on libfec by Phil Karn, KA9Q.
*/
class ReedSolomonCodec
{
/**
* Symbol size in bits.
*
* @var integer
*/
protected $symbolSize;
/**
* Block size in symbols.
*
* @var integer
*/
protected $blockSize;
/**
* First root of RS code generator polynomial, index form.
*
* @var integer
*/
protected $firstRoot;
/**
* Primitive element to generate polynomial roots, index form.
*
* @var integer
*/
protected $primitive;
/**
* Prim-th root of 1, index form.
*
* @var integer
*/
protected $iPrimitive;
/**
* RS code generator polynomial degree (number of roots).
*
* @var integer
*/
protected $numRoots;
/**
* Padding bytes at front of shortened block.
*
* @var integer
*/
protected $padding;
/**
* Log lookup table.
*
* @var SplFixedArray
*/
protected $alphaTo;
/**
* Anti-Log lookup table.
*
* @var SplFixedArray
*/
protected $indexOf;
/**
* Generator polynomial.
*
* @var SplFixedArray
*/
protected $generatorPoly;
/**
* Creates a new reed solomon instance.
*
* @param integer $symbolSize
* @param integer $gfPoly
* @param integer $firstRoot
* @param integer $primitive
* @param integer $numRoots
* @param integer $padding
* @throws Exception\InvalidArgumentException
* @throws Exception\RuntimeException
*/
public function __construct($symbolSize, $gfPoly, $firstRoot, $primitive, $numRoots, $padding)
{
if ($symbolSize < 0 || $symbolSize > 8) {
throw new Exception\InvalidArgumentException('Symbol size must be between 0 and 8');
}
if ($firstRoot < 0 || $firstRoot >= (1 << $symbolSize)) {
throw new Exception\InvalidArgumentException('First root must be between 0 and ' . (1 << $symbolSize));
}
if ($numRoots < 0 || $numRoots >= (1 << $symbolSize)) {
throw new Exception\InvalidArgumentException('Num roots must be between 0 and ' . (1 << $symbolSize));
}
if ($padding < 0 || $padding >= ((1 << $symbolSize) - 1 - $numRoots)) {
throw new Exception\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 ($sr !== 1) {
throw new Exception\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 = intval($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.
*
* @param SplFixedArray $data
* @param SplFixedArray $parity
* @return void
*/
public function encode(SplFixedArray $data, SplFixedArray $parity)
{
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.
*
* @param SplFixedArray $data
* @param SplFixedArray|null $erasures
* @return null|integer
*/
public function decode(SplFixedArray $data, SplFixedArray $erasures = null)
{
// 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 = ($erasures !== null ? 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);
} else {
$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;
for ($i = 1, $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: uncorreactable 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 ($erasures !== null) {
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.
*
* @param itneger $x
* @return integer
*/
protected function modNn($x)
{
while ($x >= $this->blockSize) {
$x -= $this->blockSize;
$x = ($x >> $this->symbolSize) + ($x & $this->blockSize);
}
return $x;
}
}

View File

@@ -0,0 +1,687 @@
<?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;
use SplFixedArray;
/**
* Version representation.
*/
class Version
{
/**
* Version decode information.
*
* @var array
*/
protected static $versionDecodeInfo = array(
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
);
/**
* Cached version instances.
*
* @var array
*/
protected static $versions = array();
/**
* Version number of this version.
*
* @var integer
*/
protected $versionNumber;
/**
* Alignment pattern centers.
*
* @var SplFixedArray
*/
protected $alignmentPatternCenters;
/**
* Error correction blocks.
*
* @var SplFixedArray
*/
protected $errorCorrectionBlocks;
/**
* Total number of codewords.
*
* @var integer
*/
protected $totalCodewords;
/**
* Creates a new version.
*
* @param integer $versionNumber
* @param SplFixedArray $alignmentPatternCenters
* @param SplFixedArray $ecBlocks
*/
protected function __construct(
$versionNumber,
SplFixedArray $alignmentPatternCenters,
SplFixedArray $ecBlocks
) {
$this->versionNumber = $versionNumber;
$this->alignmentPatternCenters = $alignmentPatternCenters;
$this->errorCorrectionBlocks = $ecBlocks;
$totalCodewords = 0;
$ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock();
foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) {
$totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords);
}
$this->totalCodewords = $totalCodewords;
}
/**
* Gets the version number.
*
* @return integer
*/
public function getVersionNumber()
{
return $this->versionNumber;
}
/**
* Gets the alignment pattern centers.
*
* @return SplFixedArray
*/
public function getAlignmentPatternCenters()
{
return $this->alignmentPatternCenters;
}
/**
* Gets the total number of codewords.
*
* @return integer
*/
public function getTotalCodewords()
{
return $this->totalCodewords;
}
/**
* Gets the dimension for the current version.
*
* @return integer
*/
public function getDimensionForVersion()
{
return 17 + 4 * $this->versionNumber;
}
/**
* Gets the number of EC blocks for a specific EC level.
*
* @param ErrorCorrectionLevel $ecLevel
* @return integer
*/
public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel)
{
return $this->errorCorrectionBlocks[$ecLevel->getOrdinal()];
}
/**
* Gets a provisional version number for a specific dimension.
*
* @param integer $dimension
* @return Version
* @throws Exception\InvalidArgumentException
*/
public static function getProvisionalVersionForDimension($dimension)
{
if ($dimension % 4 !== 1) {
throw new Exception\InvalidArgumentException('Dimension is not 1 mod 4');
}
return self::getVersionForNumber(($dimension - 17) >> 2);
}
/**
* Gets a version instance for a specific version number.
*
* @param integer $versionNumber
* @return Version
* @throws Exception\InvalidArgumentException
*/
public static function getVersionForNumber($versionNumber)
{
if ($versionNumber < 1 || $versionNumber > 40) {
throw new Exception\InvalidArgumentException('Version number must be between 1 and 40');
}
if (!isset(self::$versions[$versionNumber])) {
self::buildVersion($versionNumber);
}
return self::$versions[$versionNumber - 1];
}
/**
* Decodes version information from an integer and returns the version.
*
* @param integer $versionBits
* @return Version|null
*/
public static function decodeVersionInformation($versionBits)
{
$bestDifference = PHP_INT_MAX;
$bestVersion = 0;
foreach (self::$versionDecodeInfo 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.
*
* @return BitMatrix
*/
public function buildFunctionPattern()
{
$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.
*
* @return string
*/
public function __toString()
{
return (string) $this->versionNumber;
}
/**
* Build and cache a specific version.
*
* See ISO 18004:2006 6.5.1 Table 9.
*
* @param integer $versionNumber
* @return void
*/
protected static function buildVersion($versionNumber)
{
switch ($versionNumber) {
case 1:
$patterns = array();
$ecBlocks = array(
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)),
);
break;
case 2:
$patterns = array(6, 18);
$ecBlocks = array(
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)),
);
break;
case 3:
$patterns = array(6, 22);
$ecBlocks = array(
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)),
);
break;
case 4:
$patterns = array(6, 26);
$ecBlocks = array(
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)),
);
break;
case 5:
$patterns = array(6, 30);
$ecBlocks = array(
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)),
);
break;
case 6:
$patterns = array(6, 34);
$ecBlocks = array(
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)),
);
break;
case 7:
$patterns = array(6, 22, 38);
$ecBlocks = array(
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)),
);
break;
case 8:
$patterns = array(6, 24, 42);
$ecBlocks = array(
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)),
);
break;
case 9:
$patterns = array(6, 26, 46);
$ecBlocks = array(
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)),
);
break;
case 10:
$patterns = array(6, 28, 50);
$ecBlocks = array(
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)),
);
break;
case 11:
$patterns = array(6, 30, 54);
$ecBlocks = array(
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)),
);
break;
case 12:
$patterns = array(6, 32, 58);
$ecBlocks = array(
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)),
);
break;
case 13:
$patterns = array(6, 34, 62);
$ecBlocks = array(
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)),
);
break;
case 14:
$patterns = array(6, 26, 46, 66);
$ecBlocks = array(
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)),
);
break;
case 15:
$patterns = array(6, 26, 48, 70);
$ecBlocks = array(
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)),
);
break;
case 16:
$patterns = array(6, 26, 50, 74);
$ecBlocks = array(
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)),
);
break;
case 17:
$patterns = array(6, 30, 54, 78);
$ecBlocks = array(
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)),
);
break;
case 18:
$patterns = array(6, 30, 56, 82);
$ecBlocks = array(
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)),
);
break;
case 19:
$patterns = array(6, 30, 58, 86);
$ecBlocks = array(
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)),
);
break;
case 20:
$patterns = array(6, 34, 62, 90);
$ecBlocks = array(
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)),
);
break;
case 21:
$patterns = array(6, 28, 50, 72, 94);
$ecBlocks = array(
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)),
);
break;
case 22:
$patterns = array(6, 26, 50, 74, 98);
$ecBlocks = array(
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)),
);
break;
case 23:
$patterns = array(6, 30, 54, 78, 102);
$ecBlocks = array(
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)),
);
break;
case 24:
$patterns = array(6, 28, 54, 80, 106);
$ecBlocks = array(
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)),
);
break;
case 25:
$patterns = array(6, 32, 58, 84, 110);
$ecBlocks = array(
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)),
);
break;
case 26:
$patterns = array(6, 30, 58, 86, 114);
$ecBlocks = array(
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)),
);
break;
case 27:
$patterns = array(6, 34, 62, 90, 118);
$ecBlocks = array(
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)),
);
break;
case 28:
$patterns = array(6, 26, 50, 74, 98, 122);
$ecBlocks = array(
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)),
);
break;
case 29:
$patterns = array(6, 30, 54, 78, 102, 126);
$ecBlocks = array(
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)),
);
break;
case 30:
$patterns = array(6, 26, 52, 78, 104, 130);
$ecBlocks = array(
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)),
);
break;
case 31:
$patterns = array(6, 30, 56, 82, 108, 134);
$ecBlocks = array(
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)),
);
break;
case 32:
$patterns = array(6, 34, 60, 86, 112, 138);
$ecBlocks = array(
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)),
);
break;
case 33:
$patterns = array(6, 30, 58, 86, 114, 142);
$ecBlocks = array(
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)),
);
break;
case 34:
$patterns = array(6, 34, 62, 90, 118, 146);
$ecBlocks = array(
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)),
);
break;
case 35:
$patterns = array(6, 30, 54, 78, 102, 126, 150);
$ecBlocks = array(
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)),
);
break;
case 36:
$patterns = array(6, 24, 50, 76, 102, 128, 154);
$ecBlocks = array(
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)),
);
break;
case 37:
$patterns = array(6, 28, 54, 80, 106, 132, 158);
$ecBlocks = array(
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)),
);
break;
case 38:
$patterns = array(6, 32, 58, 84, 110, 136, 162);
$ecBlocks = array(
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)),
);
break;
case 39:
$patterns = array(6, 26, 54, 82, 110, 138, 166);
$ecBlocks = array(
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)),
);
break;
case 40:
$patterns = array(6, 30, 58, 86, 114, 142, 170);
$ecBlocks = array(
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)),
);
break;
}
self::$versions[$versionNumber - 1] = new self(
$versionNumber,
SplFixedArray::fromArray($patterns, false),
SplFixedArray::fromArray($ecBlocks, false)
);
}
}

View File

@@ -0,0 +1,64 @@
<?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\Encoder;
use SplFixedArray;
/**
* Block pair.
*/
class BlockPair
{
/**
* Data bytes in the block.
*
* @var SplFixedArray
*/
protected $dataBytes;
/**
* Error correction bytes in the block.
*
* @var SplFixedArray
*/
protected $errorCorrectionBytes;
/**
* Creates a new block pair.
*
* @param SplFixedArray $data
* @param SplFixedArray $errorCorrection
*/
public function __construct(SplFixedArray $data, SplFixedArray $errorCorrection)
{
$this->dataBytes = $data;
$this->errorCorrectionBytes = $errorCorrection;
}
/**
* Gets the data bytes.
*
* @return SplFixedArray
*/
public function getDataBytes()
{
return $this->dataBytes;
}
/**
* Gets the error correction bytes.
*
* @return SplFixedArray
*/
public function getErrorCorrectionBytes()
{
return $this->errorCorrectionBytes;
}
}

View File

@@ -0,0 +1,158 @@
<?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\Encoder;
use SplFixedArray;
/**
* Byte matrix.
*/
class ByteMatrix
{
/**
* Bytes in the matrix, represented as array.
*
* @var SplFixedArray
*/
protected $bytes;
/**
* Width of the matrix.
*
* @var integer
*/
protected $width;
/**
* Height of the matrix.
*
* @var integer
*/
protected $height;
/**
* Creates a new byte matrix.
*
* @param integer $width
* @param integer $height
*/
public function __construct($width, $height)
{
$this->height = $height;
$this->width = $width;
$this->bytes = new SplFixedArray($height);
for ($y = 0; $y < $height; $y++) {
$this->bytes[$y] = new SplFixedArray($width);
}
}
/**
* Gets the width of the matrix.
*
* @return integer
*/
public function getWidth()
{
return $this->width;
}
/**
* Gets the height of the matrix.
*
* @return integer
*/
public function getHeight()
{
return $this->height;
}
/**
* Gets the internal representation of the matrix.
*
* @return SplFixedArray
*/
public function getArray()
{
return $this->bytes;
}
/**
* Gets the byte for a specific position.
*
* @param integer $x
* @param integer $y
* @return integer
*/
public function get($x, $y)
{
return $this->bytes[$y][$x];
}
/**
* Sets the byte for a specific position.
*
* @param integer $x
* @param integer $y
* @param integer $value
* @return void
*/
public function set($x, $y, $value)
{
$this->bytes[$y][$x] = (int) $value;
}
/**
* Clears the matrix with a specific value.
*
* @param integer $value
* @return void
*/
public function clear($value)
{
for ($y = 0; $y < $this->height; $y++) {
for ($x = 0; $x < $this->width; $x++) {
$this->bytes[$y][$x] = $value;
}
}
}
/**
* Returns a string representation of the matrix.
*
* @return string
*/
public function __toString()
{
$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;
}
}

View File

@@ -0,0 +1,687 @@
<?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\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;
use SplFixedArray;
/**
* Encoder.
*/
class Encoder
{
/**
* Default byte encoding.
*/
const DEFAULT_BYTE_MODE_ECODING = 'ISO-8859-1';
/**
* The original table is defined in the table 5 of JISX0510:2004 (p.19).
*
* @var array
*/
protected static $alphanumericTable = array(
-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
*/
protected static $codecs = array();
/**
* Encodes "content" with the error correction level "ecLevel".
*
* @param string $content
* @param ErrorCorrectionLevel $ecLevel
* @param ? $hints
* @return QrCode
*/
public static function encode($content, ErrorCorrectionLevel $ecLevel, $encoding = self::DEFAULT_BYTE_MODE_ECODING)
{
// 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->get() === Mode::BYTE && $encoding !== self::DEFAULT_BYTE_MODE_ECODING) {
$eci = CharacterSetEci::getCharacterSetEciByName($encoding);
if ($eci !== null) {
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);
$headerAndDataBits = new BitArray();
$headerAndDataBits->appendBitArray($headerBits);
// Find "length" of main segment and write it.
$numLetters = ($mode->get() === Mode::BYTE ? $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()
);
$qrCode = new QrCode();
$qrCode->setErrorCorrectionLevel($ecLevel);
$qrCode->setMode($mode);
$qrCode->setVersion($version);
// Choose the mask pattern and set to "qrCode".
$dimension = $version->getDimensionForVersion();
$matrix = new ByteMatrix($dimension, $dimension);
$maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix);
$qrCode->setMaskPattern($maskPattern);
// Build the matrix and set it to "qrCode".
MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix);
$qrCode->setMatrix($matrix);
return $qrCode;
}
/**
* Gets the alphanumeric code for a byte.
*
* @param string|integer $code
* @return integer
*/
protected static function getAlphanumericCode($code)
{
$code = (is_string($code) ? ord($code) : $code);
if (isset(self::$alphanumericTable[$code])) {
return self::$alphanumericTable[$code];
}
return -1;
}
/**
* Chooses the best mode for a given content.
*
* @param string $content
* @param string $encoding
* @return Mode
*/
protected static function chooseMode($content, $encoding = null)
{
if (strcasecmp($encoding, 'SHIFT-JIS') === 0) {
return self::isOnlyDoubleByteKanji($content) ? new Mode(Mode::KANJI) : new Mode(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 (self::getAlphanumericCode($char) !== -1) {
$hasAlphanumeric = true;
} else {
return new Mode(Mode::BYTE);
}
}
if ($hasAlphanumeric) {
return new Mode(Mode::ALPHANUMERIC);
} elseif ($hasNumeric) {
return new Mode(Mode::NUMERIC);
}
return new Mode(Mode::BYTE);
}
/**
* Calculates the mask penalty for a matrix.
*
* @param ByteMatrix $matrix
* @return integer
*/
protected static function calculateMaskPenalty(ByteMatrix $matrix)
{
return (
MaskUtil::applyMaskPenaltyRule1($matrix)
+ MaskUtil::applyMaskPenaltyRule2($matrix)
+ MaskUtil::applyMaskPenaltyRule3($matrix)
+ MaskUtil::applyMaskPenaltyRule4($matrix)
);
}
/**
* Chooses the best mask pattern for a matrix.
*
* @param BitArray $bits
* @param ErrorCorrectionLevel $ecLevel
* @param Version $version
* @param ByteMatrix $matrix
* @return integer
*/
protected static function chooseMaskPattern(
BitArray $bits,
ErrorCorrectionLevel $ecLevel,
Version $version,
ByteMatrix $matrix
) {
$minPenality = 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 < $minPenality) {
$minPenality = $penalty;
$bestMaskPattern = $maskPattern;
}
}
return $bestMaskPattern;
}
/**
* Chooses the best version for the input.
*
* @param integer $numInputBits
* @param ErrorCorrectionLevel $ecLevel
* @return Version
* @throws Exception\WriterException
*/
protected static function chooseVersion($numInputBits, ErrorCorrectionLevel $ecLevel)
{
for ($versionNum = 1; $versionNum <= 40; $versionNum++) {
$version = Version::getVersionForNumber($versionNum);
$numBytes = $version->getTotalCodewords();
$ecBlocks = $version->getEcBlocksForLevel($ecLevel);
$numEcBytes = $ecBlocks->getTotalEcCodewords();
$numDataBytes = $numBytes - $numEcBytes;
$totalInputBytes = intval(($numInputBits + 8) / 8);
if ($numDataBytes >= $totalInputBytes) {
return $version;
}
}
throw new Exception\WriterException('Data too big');
}
/**
* Terminates the bits in a bit array.
*
* @param integer $numDataBytes
* @param BitArray $bits
* @throws Exception\WriterException
*/
protected static function terminateBits($numDataBytes, BitArray $bits)
{
$capacity = $numDataBytes << 3;
if ($bits->getSize() > $capacity) {
throw new Exception\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(($i & 0x1) === 0 ? 0xec : 0x11, 8);
}
if ($bits->getSize() !== $capacity) {
throw new Exception\WriterException('Bits size does not equal capacity');
}
}
/**
* Gets number of data- and EC bytes for a block ID.
*
* @param integer $numTotalBytes
* @param integer $numDataBytes
* @param integer $numRsBlocks
* @param integer $blockId
* @return array
* @throws Exception\WriterException
*/
protected static function getNumDataBytesAndNumEcBytesForBlockId(
$numTotalBytes,
$numDataBytes,
$numRsBlocks,
$blockId
) {
if ($blockId >= $numRsBlocks) {
throw new Exception\WriterException('Block ID too large');
}
$numRsBlocksInGroup2 = $numTotalBytes % $numRsBlocks;
$numRsBlocksInGroup1 = $numRsBlocks - $numRsBlocksInGroup2;
$numTotalBytesInGroup1 = intval($numTotalBytes / $numRsBlocks);
$numTotalBytesInGroup2 = $numTotalBytesInGroup1 + 1;
$numDataBytesInGroup1 = intval($numDataBytes / $numRsBlocks);
$numDataBytesInGroup2 = $numDataBytesInGroup1 + 1;
$numEcBytesInGroup1 = $numTotalBytesInGroup1 - $numDataBytesInGroup1;
$numEcBytesInGroup2 = $numTotalBytesInGroup2 - $numDataBytesInGroup2;
if ($numEcBytesInGroup1 !== $numEcBytesInGroup2) {
throw new Exception\WriterException('EC bytes mismatch');
}
if ($numRsBlocks !== $numRsBlocksInGroup1 + $numRsBlocksInGroup2) {
throw new Exception\WriterException('RS blocks mismatch');
}
if ($numTotalBytes !==
(($numDataBytesInGroup1 + $numEcBytesInGroup1) * $numRsBlocksInGroup1)
+ (($numDataBytesInGroup2 + $numEcBytesInGroup2) * $numRsBlocksInGroup2)
) {
throw new Exception\WriterException('Total bytes mismatch');
}
if ($blockId < $numRsBlocksInGroup1) {
return array($numDataBytesInGroup1, $numEcBytesInGroup1);
} else {
return array($numDataBytesInGroup2, $numEcBytesInGroup2);
}
}
/**
* Interleaves data with EC bytes.
*
* @param BitArray $bits
* @param integer $numTotalBytes
* @param integer $numDataBytes
* @param integer $numRsBlocks
* @return BitArray
* @throws Exception\WriterException
*/
protected static function interleaveWithEcBytes(BitArray $bits, $numTotalBytes, $numDataBytes, $numRsBlocks)
{
if ($bits->getSizeInBytes() !== $numDataBytes) {
throw new Exception\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 Exception\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 Exception\WriterException('Interleaving error: ' . $numTotalBytes . ' and ' . $result->getSizeInBytes() . ' differ');
}
return $result;
}
/**
* Generates EC bytes for given data.
*
* @param SplFixedArray $dataBytes
* @param integer $numEcBytesInBlock
* @return SplFixedArray
*/
protected static function generateEcBytes(SplFixedArray $dataBytes, $numEcBytesInBlock)
{
$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.
*
* @param integer $numDataBytes
* @param integer $numEcBytesInBlock
* @return ReedSolomonCodec
*/
protected static function getCodec($numDataBytes, $numEcBytesInBlock)
{
$cacheId = $numDataBytes . '-' . $numEcBytesInBlock;
if (!isset(self::$codecs[$cacheId])) {
self::$codecs[$cacheId] = new ReedSolomonCodec(
8,
0x11d,
0,
1,
$numEcBytesInBlock,
255 - $numDataBytes - $numEcBytesInBlock
);
}
return self::$codecs[$cacheId];
}
/**
* Appends mode information to a bit array.
*
* @param Mode $mode
* @param BitArray $bits
* @return void
*/
protected static function appendModeInfo(Mode $mode, BitArray $bits)
{
$bits->appendBits($mode->get(), 4);
}
/**
* Appends length information to a bit array.
*
* @param integer $numLetters
* @param Version $version
* @param Mode $mode
* @param BitArray $bits
* @return void
* @throws Exception\WriterException
*/
protected static function appendLengthInfo($numLetters, Version $version, Mode $mode, BitArray $bits)
{
$numBits = $mode->getCharacterCountBits($version);
if ($numLetters >= (1 << $numBits)) {
throw new Exception\WriterException($numLetters . ' is bigger than ' . ((1 << $numBits) - 1));
}
$bits->appendBits($numLetters, $numBits);
}
/**
* Appends bytes to a bit array in a specific mode.
*
* @param stirng $content
* @param Mode $mode
* @param BitArray $bits
* @param string $encoding
* @return void
* @throws Exception\WriterException
*/
protected static function appendBytes($content, Mode $mode, BitArray $bits, $encoding)
{
switch ($mode->get()) {
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 Exception\WriterException('Invalid mode: ' . $mode->get());
}
}
/**
* Appends numeric bytes to a bit array.
*
* @param string $content
* @param BitArray $bits
* @return void
*/
protected static function appendNumericBytes($content, BitArray $bits)
{
$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.
*
* @param string $content
* @param BitArray $bits
* @return void
*/
protected static function appendAlphanumericBytes($content, BitArray $bits)
{
$length = strlen($content);
$i = 0;
while ($i < $length) {
if (-1 === ($code1 = self::getAlphanumericCode($content[$i]))) {
throw new Exception\WriterException('Invalid alphanumeric code');
}
if ($i + 1 < $length) {
if (-1 === ($code2 = self::getAlphanumericCode($content[$i + 1]))) {
throw new Exception\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.
*
* @param string $content
* @param BitArray $bits
* @return void
*/
protected static function append8BitBytes($content, BitArray $bits, $encoding)
{
if (false === ($bytes = @iconv('utf-8', $encoding, $content))) {
throw new Exception\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.
*
* @param string $content
* @param BitArray $bits
* @return void
*/
protected static function appendKanjiBytes($content, BitArray $bits)
{
if (strlen($content) % 2 > 0) {
// We just do a simple length check here. The for loop will check
// individual characters.
throw new Exception\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 Exception\WriterException('Invalid byte sequence');
}
$encoded = (($subtracted >> 8) * 0xc0) + ($subtracted & 0xff);
$bits->appendBits($encoded, 13);
}
}
/**
* Appends ECI information to a bit array.
*
* @param CharacterSetEci $eci
* @param BitArray $bits
* @return void
*/
protected static function appendEci(CharacterSetEci $eci, BitArray $bits)
{
$mode = new Mode(Mode::ECI);
$bits->appendBits($mode->get(), 4);
$bits->appendBits($eci->get(), 8);
}
}

View File

@@ -0,0 +1,291 @@
<?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\Encoder;
use BaconQrCode\Common\BitUtils;
/**
* Mask utility.
*/
class MaskUtil
{
/**#@+
* Penalty weights from section 6.8.2.1
*/
const N1 = 3;
const N2 = 3;
const N3 = 40;
const N4 = 10;
/**#@-*/
/**
* 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.
*
* @param ByteMatrix $matrix
* @return integer
*/
public static function applyMaskPenaltyRule1(ByteMatrix $matrix)
{
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.
*
* @param ByteMatrix $matrix
* @return integer
*/
public static function applyMaskPenaltyRule2(ByteMatrix $matrix)
{
$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).
*
* @param ByteMatrix $matrix
* @return integer
*/
public static function applyMaskPenaltyRule3(ByteMatrix $matrix)
{
$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
&& $array[$y][$x] === 1
&& $array[$y][$x + 1] === 0
&& $array[$y][$x + 2] === 1
&& $array[$y][$x + 3] === 1
&& $array[$y][$x + 4] === 1
&& $array[$y][$x + 5] === 0
&& $array[$y][$x + 6] === 1
&& (
(
$x + 10 < $width
&& $array[$y][$x + 7] === 0
&& $array[$y][$x + 8] === 0
&& $array[$y][$x + 9] === 0
&& $array[$y][$x + 10] === 0
)
|| (
$x - 4 >= 0
&& $array[$y][$x - 1] === 0
&& $array[$y][$x - 2] === 0
&& $array[$y][$x - 3] === 0
&& $array[$y][$x - 4] === 0
)
)
) {
$penalty += self::N3;
}
if (
$y + 6 < $height
&& $array[$y][$x] === 1
&& $array[$y + 1][$x] === 0
&& $array[$y + 2][$x] === 1
&& $array[$y + 3][$x] === 1
&& $array[$y + 4][$x] === 1
&& $array[$y + 5][$x] === 0
&& $array[$y + 6][$x] === 1
&& (
(
$y + 10 < $height
&& $array[$y + 7][$x] === 0
&& $array[$y + 8][$x] === 0
&& $array[$y + 9][$x] === 0
&& $array[$y + 10][$x] === 0
)
|| (
$y - 4 >= 0
&& $array[$y - 1][$x] === 0
&& $array[$y - 2][$x] === 0
&& $array[$y - 3][$x] === 0
&& $array[$y - 4][$x] === 0
)
)
) {
$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.
*
* @param ByteMatrix $matrix
* @return integer
*/
public static function applyMaskPenaltyRule4(ByteMatrix $matrix)
{
$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 ($arrayY[$x] === 1) {
$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.
*
* @param integer $maskPattern
* @param integer $x
* @param integer $y
* @return integer
* @throws Exception\InvalidArgumentException
*/
public static function getDataMaskBit($maskPattern, $x, $y)
{
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) + ($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 Exception\InvalidArgumentException('Invalid mask pattern: ' . $maskPattern);
}
return $intermediate === 0;
}
/**
* Helper function for applyMaskPenaltyRule1.
*
* We need this for doing this calculation in both vertical and horizontal
* orders respectively.
*
* @param ByteMatrix $matrix
* @param boolean $isHorizontal
* @return integer
*/
protected static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, $isHorizontal)
{
$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;
}
}

View File

@@ -0,0 +1,580 @@
<?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\Encoder;
use BaconQrCode\Common\BitArray;
use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Common\Version;
use BaconQrCode\Exception;
/**
* Matrix utility.
*/
class MatrixUtil
{
/**
* Position detection pattern.
*
* @var array
*/
protected static $positionDetectionPattern = array(
array(1, 1, 1, 1, 1, 1, 1),
array(1, 0, 0, 0, 0, 0, 1),
array(1, 0, 1, 1, 1, 0, 1),
array(1, 0, 1, 1, 1, 0, 1),
array(1, 0, 1, 1, 1, 0, 1),
array(1, 0, 0, 0, 0, 0, 1),
array(1, 1, 1, 1, 1, 1, 1),
);
/**
* Position adjustment pattern.
*
* @var array
*/
protected static $positionAdjustmentPattern = array(
array(1, 1, 1, 1, 1),
array(1, 0, 0, 0, 1),
array(1, 0, 1, 0, 1),
array(1, 0, 0, 0, 1),
array(1, 1, 1, 1, 1),
);
/**
* Coordinates for position adjustment patterns for each version.
*
* @var array
*/
protected static $positionAdjustmentPatternCoordinateTable = array(
array(null, null, null, null, null, null, null), // Version 1
array( 6, 18, null, null, null, null, null), // Version 2
array( 6, 22, null, null, null, null, null), // Version 3
array( 6, 26, null, null, null, null, null), // Version 4
array( 6, 30, null, null, null, null, null), // Version 5
array( 6, 34, null, null, null, null, null), // Version 6
array( 6, 22, 38, null, null, null, null), // Version 7
array( 6, 24, 42, null, null, null, null), // Version 8
array( 6, 26, 46, null, null, null, null), // Version 9
array( 6, 28, 50, null, null, null, null), // Version 10
array( 6, 30, 54, null, null, null, null), // Version 11
array( 6, 32, 58, null, null, null, null), // Version 12
array( 6, 34, 62, null, null, null, null), // Version 13
array( 6, 26, 46, 66, null, null, null), // Version 14
array( 6, 26, 48, 70, null, null, null), // Version 15
array( 6, 26, 50, 74, null, null, null), // Version 16
array( 6, 30, 54, 78, null, null, null), // Version 17
array( 6, 30, 56, 82, null, null, null), // Version 18
array( 6, 30, 58, 86, null, null, null), // Version 19
array( 6, 34, 62, 90, null, null, null), // Version 20
array( 6, 28, 50, 72, 94, null, null), // Version 21
array( 6, 26, 50, 74, 98, null, null), // Version 22
array( 6, 30, 54, 78, 102, null, null), // Version 23
array( 6, 28, 54, 80, 106, null, null), // Version 24
array( 6, 32, 58, 84, 110, null, null), // Version 25
array( 6, 30, 58, 86, 114, null, null), // Version 26
array( 6, 34, 62, 90, 118, null, null), // Version 27
array( 6, 26, 50, 74, 98, 122, null), // Version 28
array( 6, 30, 54, 78, 102, 126, null), // Version 29
array( 6, 26, 52, 78, 104, 130, null), // Version 30
array( 6, 30, 56, 82, 108, 134, null), // Version 31
array( 6, 34, 60, 86, 112, 138, null), // Version 32
array( 6, 30, 58, 86, 114, 142, null), // Version 33
array( 6, 34, 62, 90, 118, 146, null), // Version 34
array( 6, 30, 54, 78, 102, 126, 150), // Version 35
array( 6, 24, 50, 76, 102, 128, 154), // Version 36
array( 6, 28, 54, 80, 106, 132, 158), // Version 37
array( 6, 32, 58, 84, 110, 136, 162), // Version 38
array( 6, 26, 54, 82, 110, 138, 166), // Version 39
array( 6, 30, 58, 86, 114, 142, 170), // Version 40
);
/**
* Type information coordinates.
*
* @var array
*/
protected static $typeInfoCoordinates = array(
array(8, 0),
array(8, 1),
array(8, 2),
array(8, 3),
array(8, 4),
array(8, 5),
array(8, 7),
array(8, 8),
array(7, 8),
array(5, 8),
array(4, 8),
array(3, 8),
array(2, 8),
array(1, 8),
array(0, 8),
);
/**
* Version information polynomial.
*
* @var integer
*/
protected static $versionInfoPoly = 0x1f25;
/**
* Type information polynomial.
*
* @var integer
*/
protected static $typeInfoPoly = 0x537;
/**
* Type information mask pattern.
*
* @var integer
*/
protected static $typeInfoMaskPattern = 0x5412;
/**
* Clears a given matrix.
*
* @param ByteMatrix $matrix
* @return void
*/
public static function clearMatrix(ByteMatrix $matrix)
{
$matrix->clear(-1);
}
/**
* Builds a complete matrix.
*
* @param BitArray $dataBits
* @param ErrorCorrectionLevel $level
* @param Version $version
* @param integer $maskPattern
* @param ByteMatrix $matrix
* @return void
*/
public static function buildMatrix(
BitArray $dataBits,
ErrorCorrectionLevel $level,
Version $version,
$maskPattern,
ByteMatrix $matrix
) {
self::clearMatrix($matrix);
self::embedBasicPatterns($version, $matrix);
self::embedTypeInfo($level, $maskPattern, $matrix);
self::maybeEmbedVersionInfo($version, $matrix);
self::embedDataBits($dataBits, $maskPattern, $matrix);
}
/**
* Embeds type information into a matrix.
*
* @param ErrorCorrectionLevel $level
* @param integer $maskPattern
* @param ByteMatrix $matrix
* @return void
*/
protected static function embedTypeInfo(ErrorCorrectionLevel $level, $maskPattern, ByteMatrix $matrix)
{
$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::$typeInfoCoordinates[$i][0];
$y1 = self::$typeInfoCoordinates[$i][1];
$matrix->set($x1, $y1, $bit);
if ($i < 8) {
$x2 = $matrix->getWidth() - $i - 1;
$y2 = 8;
} else {
$x2 = 8;
$y2 = $matrix->getHeight() - 7 + ($i - 8);
}
$matrix->set($x2, $y2, $bit);
}
}
/**
* Generates type information bits and appends them to a bit array.
*
* @param ErrorCorrectionLevel $level
* @param integer $maskPattern
* @param BitArray $bits
* @return void
* @throws Exception\RuntimeException
*/
protected static function makeTypeInfoBits(ErrorCorrectionLevel $level, $maskPattern, BitArray $bits)
{
$typeInfo = ($level->get() << 3) | $maskPattern;
$bits->appendBits($typeInfo, 5);
$bchCode = self::calculateBchCode($typeInfo, self::$typeInfoPoly);
$bits->appendBits($bchCode, 10);
$maskBits = new BitArray();
$maskBits->appendBits(self::$typeInfoMaskPattern, 15);
$bits->xorBits($maskBits);
if ($bits->getSize() !== 15) {
throw new Exception\RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize());
}
}
/**
* Embeds version information if required.
*
* @param Version $version
* @param ByteMatrix $matrix
* @return void
*/
protected static function maybeEmbedVersionInfo(Version $version, ByteMatrix $matrix)
{
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, $bit);
$matrix->set($matrix->getHeight() - 11 + $j, $i, $bit);
}
}
}
/**
* Generates version information bits and appends them to a bit array.
*
* @param Version $version
* @param BitArray $bits
* @return void
* @throws Exception\RuntimeException
*/
protected static function makeVersionInfoBits(Version $version, BitArray $bits)
{
$bits->appendBits($version->getVersionNumber(), 6);
$bchCode = self::calculateBchCode($version->getVersionNumber(), self::$versionInfoPoly);
$bits->appendBits($bchCode, 12);
if ($bits->getSize() !== 18) {
throw new Exception\RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize());
}
}
/**
* Calculates the BHC code for a value and a polynomial.
*
* @param integer $value
* @param integer $poly
* @return integer
*/
protected static function calculateBchCode($value, $poly)
{
$msbSetInPoly = self::findMsbSet($poly);
$value <<= $msbSetInPoly - 1;
while (self::findMsbSet($value) >= $msbSetInPoly) {
$value ^= $poly << (self::findMsbSet($value) - $msbSetInPoly);
}
return $value;
}
/**
* Finds and MSB set.
*
* @param integer $value
* @return integer
*/
protected static function findMsbSet($value)
{
$numDigits = 0;
while ($value !== 0) {
$value >>= 1;
$numDigits++;
}
return $numDigits;
}
/**
* Embeds basic patterns into a matrix.
*
* @param Version $version
* @param ByteMatrix $matrix
* @return void
*/
protected static function embedBasicPatterns(Version $version, ByteMatrix $matrix)
{
self::embedPositionDetectionPatternsAndSeparators($matrix);
self::embedDarkDotAtLeftBottomCorner($matrix);
self::maybeEmbedPositionAdjustmentPatterns($version, $matrix);
self::embedTimingPatterns($matrix);
}
/**
* Embeds position detection patterns and separators into a byte matrix.
*
* @param ByteMatrix $matrix
* @return void
*/
protected static function embedPositionDetectionPatternsAndSeparators(ByteMatrix $matrix)
{
$pdpWidth = count(self::$positionDetectionPattern[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.
*
* @param integer $xStart
* @param integer $yStart
* @param ByteMatrix $matrix
* @return void
*/
protected static function embedPositionDetectionPattern($xStart, $yStart, ByteMatrix $matrix)
{
for ($y = 0; $y < 7; $y++) {
for ($x = 0; $x < 7; $x++) {
$matrix->set($xStart + $x, $yStart + $y, self::$positionDetectionPattern[$y][$x]);
}
}
}
/**
* Embeds a single horizontal separation pattern.
*
* @param integer $xStart
* @param integer $yStart
* @param ByteMatrix $matrix
* @return void
* @throws Exception\RuntimeException
*/
protected static function embedHorizontalSeparationPattern($xStart, $yStart, ByteMatrix $matrix)
{
for ($x = 0; $x < 8; $x++) {
if ($matrix->get($xStart + $x, $yStart) !== -1) {
throw new Exception\RuntimeException('Byte already set');
}
$matrix->set($xStart + $x, $yStart, 0);
}
}
/**
* Embeds a single vertical separation pattern.
*
* @param integer $xStart
* @param integer $yStart
* @param ByteMatrix $matrix
* @return void
* @throws Exception\RuntimeException
*/
protected static function embedVerticalSeparationPattern($xStart, $yStart, ByteMatrix $matrix)
{
for ($y = 0; $y < 7; $y++) {
if ($matrix->get($xStart, $yStart + $y) !== -1) {
throw new Exception\RuntimeException('Byte already set');
}
$matrix->set($xStart, $yStart + $y, 0);
}
}
/**
* Embeds a dot at the left bottom corner.
*
* @param ByteMatrix $matrix
* @return void
* @throws Exception\RuntimeException
*/
protected static function embedDarkDotAtLeftBottomCorner(ByteMatrix $matrix)
{
if ($matrix->get(8, $matrix->getHeight() - 8) === 0) {
throw new Exception\RuntimeException('Byte already set to 0');
}
$matrix->set(8, $matrix->getHeight() - 8, 1);
}
/**
* Embeds position adjustment patterns if required.
*
* @param Version $version
* @param ByteMatrix $matrix
* @return void
*/
protected static function maybeEmbedPositionAdjustmentPatterns(Version $version, ByteMatrix $matrix)
{
if ($version->getVersionNumber() < 2) {
return;
}
$index = $version->getVersionNumber() - 1;
$coordinates = self::$positionAdjustmentPatternCoordinateTable[$index];
$numCoordinates = count($coordinates);
for ($i = 0; $i < $numCoordinates; $i++) {
for ($j = 0; $j < $numCoordinates; $j++) {
$y = $coordinates[$i];
$x = $coordinates[$j];
if ($x === null || $y === null) {
continue;
}
if ($matrix->get($x, $y) === -1) {
self::embedPositionAdjustmentPattern($x - 2, $y - 2, $matrix);
}
}
}
}
/**
* Embeds a single position adjustment pattern.
*
* @param integer $xStart
* @param intger $yStart
* @param ByteMatrix $matrix
* @return void
*/
protected static function embedPositionAdjustmentPattern($xStart, $yStart, ByteMatrix $matrix)
{
for ($y = 0; $y < 5; $y++) {
for ($x = 0; $x < 5; $x++) {
$matrix->set($xStart + $x, $yStart + $y, self::$positionAdjustmentPattern[$y][$x]);
}
}
}
/**
* Embeds timing patterns into a matrix.
*
* @param ByteMatrix $matrix
* @return void
*/
protected static function embedTimingPatterns(ByteMatrix $matrix)
{
$matrixWidth = $matrix->getWidth();
for ($i = 8; $i < $matrixWidth - 8; $i++) {
$bit = ($i + 1) % 2;
if ($matrix->get($i, 6) === -1) {
$matrix->set($i, 6, $bit);
}
if ($matrix->get(6, $i) === -1) {
$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.
*
* @param BitArray $dataBits
* @param integer $maskPattern
* @param ByteMatrix $matrix
* @return void
* @throws Exception\WriterException
*/
protected static function embedDataBits(BitArray $dataBits, $maskPattern, ByteMatrix $matrix)
{
$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 ($x === 6) {
$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 ($matrix->get($xx, $y) !== -1) {
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 ($maskPattern !== -1 && MaskUtil::getDataMaskBit($maskPattern, $xx, $y)) {
$bit = !$bit;
}
$matrix->set($xx, $y, $bit);
}
$y += $direction;
}
$direction = -$direction;
$y += $direction;
$x -= 2;
}
// All bits should be consumed
if ($bitIndex !== $dataBits->getSize()) {
throw new Exception\WriterException('Not all bits consumed (' . $bitIndex . ' out of ' . $dataBits->getSize() .')');
}
}
}

View File

@@ -0,0 +1,201 @@
<?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\Encoder;
use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Common\Mode;
use BaconQrCode\Common\Version;
/**
* QR code.
*/
class QrCode
{
/**
* Number of possible mask patterns.
*/
const NUM_MASK_PATTERNS = 8;
/**
* Mode of the QR code.
*
* @var Mode
*/
protected $mode;
/**
* EC level of the QR code.
*
* @var ErrorCorrectionLevel
*/
protected $errorCorrectionLevel;
/**
* Version of the QR code.
*
* @var Version
*/
protected $version;
/**
* Mask pattern of the QR code.
*
* @var integer
*/
protected $maskPattern = -1;
/**
* Matrix of the QR code.
*
* @var ByteMatrix
*/
protected $matrix;
/**
* Gets the mode.
*
* @return Mode
*/
public function getMode()
{
return $this->mode;
}
/**
* Sets the mode.
*
* @param Mode $mode
* @return void
*/
public function setMode(Mode $mode)
{
$this->mode = $mode;
}
/**
* Gets the EC level.
*
* @return ErrorCorrectionLevel
*/
public function getErrorCorrectionLevel()
{
return $this->errorCorrectionLevel;
}
/**
* Sets the EC level.
*
* @param ErrorCorrectionLevel $errorCorrectionLevel
* @return void
*/
public function setErrorCorrectionLevel(ErrorCorrectionLevel $errorCorrectionLevel)
{
$this->errorCorrectionLevel = $errorCorrectionLevel;
}
/**
* Gets the version.
*
* @return Version
*/
public function getVersion()
{
return $this->version;
}
/**
* Sets the version.
*
* @param Version $version
* @return void
*/
public function setVersion(Version $version)
{
$this->version = $version;
}
/**
* Gets the mask pattern.
*
* @return integer
*/
public function getMaskPattern()
{
return $this->maskPattern;
}
/**
* Sets the mask pattern.
*
* @param integer $maskPattern
* @return void
*/
public function setMaskPattern($maskPattern)
{
$this->maskPattern = $maskPattern;
}
/**
* Gets the matrix.
*
* @return ByteMatrix
*/
public function getMatrix()
{
return $this->matrix;
}
/**
* Sets the matrix.
*
* @param ByteMatrix $matrix
* @return void
*/
public function setMatrix(ByteMatrix $matrix)
{
$this->matrix = $matrix;
}
/**
* Validates whether a mask pattern is valid.
*
* @param integer $maskPattern
* @return boolean
*/
public static function isValidMaskPattern($maskPattern)
{
return $maskPattern > 0 && $maskPattern < self::NUM_MASK_PATTERNS;
}
/**
* Returns a string representation of the QR code.
*
* @return string
*/
public function __toString()
{
$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;
}
}

View File

@@ -0,0 +1,14 @@
<?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\Exception;
interface ExceptionInterface
{
}

View File

@@ -0,0 +1,14 @@
<?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\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,14 @@
<?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\Exception;
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,14 @@
<?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\Exception;
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,14 @@
<?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\Exception;
class UnexpectedValueException extends \UnexpectedValueException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,14 @@
<?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\Exception;
class WriterException extends \RuntimeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,160 @@
<?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\Renderer\Color;
use BaconQrCode\Exception;
/**
* CMYK color.
*/
class Cmyk implements ColorInterface
{
/**
* Cyan value.
*
* @var integer
*/
protected $cyan;
/**
* Magenta value.
*
* @var integer
*/
protected $magenta;
/**
* Yellow value.
*
* @var integer
*/
protected $yellow;
/**
* Black value.
*
* @var integer
*/
protected $black;
/**
* Creates a new CMYK color.
*
* @param integer $cyan
* @param integer $magenta
* @param integer $yellow
* @param integer $black
*/
public function __construct($cyan, $magenta, $yellow, $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 = (int) $cyan;
$this->magenta = (int) $magenta;
$this->yellow = (int) $yellow;
$this->black = (int) $black;
}
/**
* Returns the cyan value.
*
* @return integer
*/
public function getCyan()
{
return $this->cyan;
}
/**
* Returns the magenta value.
*
* @return integer
*/
public function getMagenta()
{
return $this->magenta;
}
/**
* Returns the yellow value.
*
* @return integer
*/
public function getYellow()
{
return $this->yellow;
}
/**
* Returns the black value.
*
* @return integer
*/
public function getBlack()
{
return $this->black;
}
/**
* toRgb(): defined by ColorInterface.
*
* @see ColorInterface::toRgb()
* @return Rgb
*/
public function toRgb()
{
$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(
-$c * 255 + 255,
-$m * 255 + 255,
-$y * 255 + 255
);
}
/**
* toCmyk(): defined by ColorInterface.
*
* @see ColorInterface::toCmyk()
* @return Cmyk
*/
public function toCmyk()
{
return $this;
}
/**
* toGray(): defined by ColorInterface.
*
* @see ColorInterface::toGray()
* @return Gray
*/
public function toGray()
{
return $this->toRgb()->toGray();
}
}

View File

@@ -0,0 +1,37 @@
<?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\Renderer\Color;
/**
* Color interface.
*/
interface ColorInterface
{
/**
* Converts the color to RGB.
*
* @return Rgb
*/
public function toRgb();
/**
* Converts the color to CMYK.
*
* @return Cmyk
*/
public function toCmyk();
/**
* Converts the color to gray.
*
* @return Gray
*/
public function toGray();
}

View File

@@ -0,0 +1,84 @@
<?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\Renderer\Color;
use BaconQrCode\Exception;
/**
* Gray color.
*/
class Gray implements ColorInterface
{
/**
* Gray value.
*
* @var integer
*/
protected $gray;
/**
* Creates a new gray color.
*
* A low gray value means black, while a high value means white.
*
* @param integer $gray
*/
public function __construct($gray)
{
if ($gray < 0 || $gray > 100) {
throw new Exception\InvalidArgumentException('Gray must be between 0 and 100');
}
$this->gray = (int) $gray;
}
/**
* Returns the gray value.
*
* @return integer
*/
public function getGray()
{
return $this->gray;
}
/**
* toRgb(): defined by ColorInterface.
*
* @see ColorInterface::toRgb()
* @return Rgb
*/
public function toRgb()
{
return new Rgb($this->gray * 2.55, $this->gray * 2.55, $this->gray * 2.55);
}
/**
* toCmyk(): defined by ColorInterface.
*
* @see ColorInterface::toCmyk()
* @return Cmyk
*/
public function toCmyk()
{
return new Cmyk(0, 0, 0, 100 - $this->gray);
}
/**
* toGray(): defined by ColorInterface.
*
* @see ColorInterface::toGray()
* @return Gray
*/
public function toGray()
{
return $this;
}
}

View File

@@ -0,0 +1,148 @@
<?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\Renderer\Color;
use BaconQrCode\Exception;
/**
* RGB color.
*/
class Rgb implements ColorInterface
{
/**
* Red value.
*
* @var integer
*/
protected $red;
/**
* Green value.
*
* @var integer
*/
protected $green;
/**
* Blue value.
*
* @var integer
*/
protected $blue;
/**
* Creates a new RGB color.
*
* @param integer $red
* @param integer $green
* @param integer $blue
*/
public function __construct($red, $green, $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 = (int) $red;
$this->green = (int) $green;
$this->blue = (int) $blue;
}
/**
* Returns the red value.
*
* @return integer
*/
public function getRed()
{
return $this->red;
}
/**
* Returns the green value.
*
* @return integer
*/
public function getGreen()
{
return $this->green;
}
/**
* Returns the blue value.
*
* @return integer
*/
public function getBlue()
{
return $this->blue;
}
/**
* Returns a hexadecimal string representation of the RGB value.
*
* @return string
*/
public function __toString()
{
return sprintf('%02x%02x%02x', $this->red, $this->green, $this->blue);
}
/**
* toRgb(): defined by ColorInterface.
*
* @see ColorInterface::toRgb()
* @return Rgb
*/
public function toRgb()
{
return $this;
}
/**
* toCmyk(): defined by ColorInterface.
*
* @see ColorInterface::toCmyk()
* @return Cmyk
*/
public function toCmyk()
{
$c = 1 - ($this->red / 255);
$m = 1 - ($this->green / 255);
$y = 1 - ($this->blue / 255);
$k = min($c, $m, $y);
return new Cmyk(
100 * ($c - $k) / (1 - $k),
100 * ($m - $k) / (1 - $k),
100 * ($y - $k) / (1 - $k),
100 * $k
);
}
/**
* toGray(): defined by ColorInterface.
*
* @see ColorInterface::toGray()
* @return Gray
*/
public function toGray()
{
return new Gray(($this->red * 0.21 + $this->green * 0.71 + $this->blue * 0.07) / 2.55);
}
}

View File

@@ -0,0 +1,338 @@
<?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\Renderer\Image;
use BaconQrCode\Encoder\QrCode;
use BaconQrCode\Renderer\Color;
use BaconQrCode\Renderer\Image\Decorator\DecoratorInterface;
use BaconQrCode\Exception;
/**
* Image renderer, supporting multiple backends.
*/
abstract class AbstractRenderer implements RendererInterface
{
/**
* Margin around the QR code, also known as quiet zone.
*
* @var integer
*/
protected $margin = 4;
/**
* Requested width of the rendered image.
*
* @var integer
*/
protected $width = 0;
/**
* Requested height of the rendered image.
*
* @var integer
*/
protected $height = 0;
/**
* Whether dimensions should be rounded down.
*
* @var boolean
*/
protected $roundDimensions = true;
/**
* Final width of the image.
*
* @var integer
*/
protected $finalWidth;
/**
* Final height of the image.
*
* @var integer
*/
protected $finalHeight;
/**
* Size of each individual block.
*
* @var integer
*/
protected $blockSize;
/**
* Background color.
*
* @var Color\ColorInterface
*/
protected $backgroundColor;
/**
* Whether dimensions should be rounded down
*
* @var boolean
*/
protected $floorToClosestDimension;
/**
* Foreground color.
*
* @var Color\ColorInterface
*/
protected $foregroundColor;
/**
* Decorators used on QR codes.
*
* @var array
*/
protected $decorators = array();
/**
* Sets the margin around the QR code.
*
* @param integer $margin
* @return AbstractRenderer
* @throws Exception\InvalidArgumentException
*/
public function setMargin($margin)
{
if ($margin < 0) {
throw new Exception\InvalidArgumentException('Margin must be equal to greater than 0');
}
$this->margin = (int) $margin;
return $this;
}
/**
* Gets the margin around the QR code.
*
* @return integer
*/
public function getMargin()
{
return $this->margin;
}
/**
* Sets the height around the renderd image.
*
* If the width is smaller than the matrix width plus padding, the renderer
* will automatically use that as the width instead of the specified one.
*
* @param integer $width
* @return AbstractRenderer
*/
public function setWidth($width)
{
$this->width = (int) $width;
return $this;
}
/**
* Gets the width of the rendered image.
*
* @return integer
*/
public function getWidth()
{
return $this->width;
}
/**
* Sets the height around the renderd image.
*
* If the height is smaller than the matrix height plus padding, the
* renderer will automatically use that as the height instead of the
* specified one.
*
* @param integer $height
* @return AbstractRenderer
*/
public function setHeight($height)
{
$this->height = (int) $height;
return $this;
}
/**
* Gets the height around the rendered image.
*
* @return integer
*/
public function getHeight()
{
return $this->height;
}
/**
* Sets whether dimensions should be rounded down.
*
* @param boolean $flag
* @return AbstractRenderer
*/
public function setRoundDimensions($flag)
{
$this->floorToClosestDimension = $flag;
return $this;
}
/**
* Gets whether dimensions should be rounded down.
*
* @return boolean
*/
public function shouldRoundDimensions()
{
return $this->floorToClosestDimension;
}
/**
* Sets background color.
*
* @param Color\ColorInterface $color
* @return AbstractRenderer
*/
public function setBackgroundColor(Color\ColorInterface $color)
{
$this->backgroundColor = $color;
return $this;
}
/**
* Gets background color.
*
* @return Color\ColorInterface
*/
public function getBackgroundColor()
{
if ($this->backgroundColor === null) {
$this->backgroundColor = new Color\Gray(100);
}
return $this->backgroundColor;
}
/**
* Sets foreground color.
*
* @param Color\ColorInterface $color
* @return AbstractRenderer
*/
public function setForegroundColor(Color\ColorInterface $color)
{
$this->foregroundColor = $color;
return $this;
}
/**
* Gets foreground color.
*
* @return Color\ColorInterface
*/
public function getForegroundColor()
{
if ($this->foregroundColor === null) {
$this->foregroundColor = new Color\Gray(0);
}
return $this->foregroundColor;
}
/**
* Adds a decorator to the renderer.
*
* @param DecoratorInterface $decorator
* @return AbstractRenderer
*/
public function addDecorator(DecoratorInterface $decorator)
{
$this->decorators[] = $decorator;
return $this;
}
/**
* render(): defined by RendererInterface.
*
* @see RendererInterface::render()
* @param QrCode $qrCode
* @return string
*/
public function render(QrCode $qrCode)
{
$input = $qrCode->getMatrix();
$inputWidth = $input->getWidth();
$inputHeight = $input->getHeight();
$qrWidth = $inputWidth + ($this->getMargin() << 1);
$qrHeight = $inputHeight + ($this->getMargin() << 1);
$outputWidth = max($this->getWidth(), $qrWidth);
$outputHeight = max($this->getHeight(), $qrHeight);
$multiple = (int) min($outputWidth / $qrWidth, $outputHeight / $qrHeight);
if ($this->shouldRoundDimensions()) {
$outputWidth -= $outputWidth % $multiple;
$outputHeight -= $outputHeight % $multiple;
}
// Padding includes both the quiet zone and the extra white pixels to
// accommodate the requested dimensions. For example, if input is 25x25
// the QR will be 33x33 including the quiet zone. If the requested size
// is 200x160, the multiple will be 4, for a QR of 132x132. These will
// handle all the padding from 100x100 (the actual QR) up to 200x160.
$leftPadding = (int) (($outputWidth - ($inputWidth * $multiple)) / 2);
$topPadding = (int) (($outputHeight - ($inputHeight * $multiple)) / 2);
// Store calculated parameters
$this->finalWidth = $outputWidth;
$this->finalHeight = $outputHeight;
$this->blockSize = $multiple;
$this->init();
$this->addColor('background', $this->getBackgroundColor());
$this->addColor('foreground', $this->getForegroundColor());
$this->drawBackground('background');
foreach ($this->decorators as $decorator) {
$decorator->preProcess(
$qrCode,
$this,
$outputWidth,
$outputHeight,
$leftPadding,
$topPadding,
$multiple
);
}
for ($inputY = 0, $outputY = $topPadding; $inputY < $inputHeight; $inputY++, $outputY += $multiple) {
for ($inputX = 0, $outputX = $leftPadding; $inputX < $inputWidth; $inputX++, $outputX += $multiple) {
if ($input->get($inputX, $inputY) === 1) {
$this->drawBlock($outputX, $outputY, 'foreground');
}
}
}
foreach ($this->decorators as $decorator) {
$decorator->postProcess(
$qrCode,
$this,
$outputWidth,
$outputHeight,
$leftPadding,
$topPadding,
$multiple
);
}
return $this->getByteStream();
}
}

View File

@@ -0,0 +1,63 @@
<?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\Renderer\Image\Decorator;
use BaconQrCode\Encoder\QrCode;
use BaconQrCode\Renderer\Image\RendererInterface;
/**
* Decorator interface.
*/
interface DecoratorInterface
{
/**
* Pre-process a QR code.
*
* @param QrCode $qrCode
* @param RendererInterface $renderer
* @param integer $outputWidth
* @param integer $outputHeight
* @param integer $leftPadding
* @param integer $topPadding
* @param integer $multiple
* @return void
*/
public function preProcess(
QrCode $qrCode,
RendererInterface $renderer,
$outputWidth,
$outputHeight,
$leftPadding,
$topPadding,
$multiple
);
/**
* Post-process a QR code.
*
* @param QrCode $qrCode
* @param RendererInterface $renderer
* @param integer $outputWidth
* @param integer $outputHeight
* @param integer $leftPadding
* @param integer $topPadding
* @param integer $multiple
* @return void
*/
public function postProcess(
QrCode $qrCode,
RendererInterface $renderer,
$outputWidth,
$outputHeight,
$leftPadding,
$topPadding,
$multiple
);
}

View File

@@ -0,0 +1,210 @@
<?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\Renderer\Image\Decorator;
use BaconQrCode\Encoder\QrCode;
use BaconQrCode\Renderer\Image\RendererInterface;
use BaconQrCode\Renderer\Color;
/**
* Finder pattern decorator.
*/
class FinderPattern implements DecoratorInterface
{
/**
* @var Color\ColorInterface
*/
protected $innerColor;
/**
* @varColor\ColorInterface
*/
protected $outerColor;
/**
* Outer position detection pattern.
*
* @var array
*/
protected static $outerPositionDetectionPattern = array(
array(1, 1, 1, 1, 1, 1, 1),
array(1, 0, 0, 0, 0, 0, 1),
array(1, 0, 0, 0, 0, 0, 1),
array(1, 0, 0, 0, 0, 0, 1),
array(1, 0, 0, 0, 0, 0, 1),
array(1, 0, 0, 0, 0, 0, 1),
array(1, 1, 1, 1, 1, 1, 1),
);
/**
* Inner position detection pattern.
*
* @var array
*/
protected static $innerPositionDetectionPattern = array(
array(0, 0, 0, 0, 0, 0, 0),
array(0, 0, 0, 0, 0, 0, 0),
array(0, 0, 1, 1, 1, 0, 0),
array(0, 0, 1, 1, 1, 0, 0),
array(0, 0, 1, 1, 1, 0, 0),
array(0, 0, 0, 0, 0, 0, 0),
array(0, 0, 0, 0, 0, 0, 0),
);
/**
* Sets outer color.
*
* @param Color\ColorInterface $color
* @return FinderPattern
*/
public function setOuterColor(Color\ColorInterface $color)
{
$this->outerColor = $color;
return $this;
}
/**
* Gets outer color.
*
* @return Color\ColorInterface
*/
public function getOuterColor()
{
if ($this->outerColor === null) {
$this->outerColor = new Color\Gray(100);
}
return $this->outerColor;
}
/**
* Sets inner color.
*
* @param Color\ColorInterface $color
* @return FinderPattern
*/
public function setInnerColor(Color\ColorInterface $color)
{
$this->innerColor = $color;
return $this;
}
/**
* Gets inner color.
*
* @return Color\ColorInterface
*/
public function getInnerColor()
{
if ($this->innerColor === null) {
$this->innerColor = new Color\Gray(0);
}
return $this->innerColor;
}
/**
* preProcess(): defined by DecoratorInterface.
*
* @see DecoratorInterface::preProcess()
* @param QrCode $qrCode
* @param RendererInterface $renderer
* @param integer $outputWidth
* @param integer $outputHeight
* @param integer $leftPadding
* @param integer $topPadding
* @param integer $multiple
* @return void
*/
public function preProcess(
QrCode $qrCode,
RendererInterface $renderer,
$outputWidth,
$outputHeight,
$leftPadding,
$topPadding,
$multiple
) {
$matrix = $qrCode->getMatrix();
$positions = array(
array(0, 0),
array($matrix->getWidth() - 7, 0),
array(0, $matrix->getHeight() - 7),
);
foreach (self::$outerPositionDetectionPattern as $y => $row) {
foreach ($row as $x => $isSet) {
foreach ($positions as $position) {
$matrix->set($x + $position[0], $y + $position[1], 0);
}
}
}
}
/**
* postProcess(): defined by DecoratorInterface.
*
* @see DecoratorInterface::postProcess()
*
* @param QrCode $qrCode
* @param RendererInterface $renderer
* @param integer $outputWidth
* @param integer $outputHeight
* @param integer $leftPadding
* @param integer $topPadding
* @param integer $multiple
* @return void
*/
public function postProcess(
QrCode $qrCode,
RendererInterface $renderer,
$outputWidth,
$outputHeight,
$leftPadding,
$topPadding,
$multiple
) {
$matrix = $qrCode->getMatrix();
$positions = array(
array(0, 0),
array($matrix->getWidth() - 7, 0),
array(0, $matrix->getHeight() - 7),
);
$renderer->addColor('finder-outer', $this->getOuterColor());
$renderer->addColor('finder-inner', $this->getInnerColor());
foreach (self::$outerPositionDetectionPattern as $y => $row) {
foreach ($row as $x => $isOuterSet) {
$isInnerSet = self::$innerPositionDetectionPattern[$y][$x];
if ($isOuterSet) {
foreach ($positions as $position) {
$renderer->drawBlock(
$leftPadding + $x * $multiple + $position[0] * $multiple,
$topPadding + $y * $multiple + $position[1] * $multiple,
'finder-outer'
);
}
}
if ($isInnerSet) {
foreach ($positions as $position) {
$renderer->drawBlock(
$leftPadding + $x * $multiple + $position[0] * $multiple,
$topPadding + $y * $multiple + $position[1] * $multiple,
'finder-inner'
);
}
}
}
}
}
}

View File

@@ -0,0 +1,152 @@
<?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\Renderer\Image;
use BaconQrCode\Renderer\Color\ColorInterface;
use BaconQrCode\Renderer\Color\Rgb;
use BaconQrCode\Renderer\Color\Cmyk;
use BaconQrCode\Renderer\Color\Gray;
/**
* EPS backend.
*/
class Eps extends AbstractRenderer
{
/**
* EPS string.
*
* @var string
*/
protected $eps;
/**
* Colors used for drawing.
*
* @var array
*/
protected $colors = array();
/**
* Current color.
*
* @var string
*/
protected $currentColor;
/**
* init(): defined by RendererInterface.
*
* @see ImageRendererInterface::init()
* @return void
*/
public function init()
{
$this->eps = "%!PS-Adobe-3.0 EPSF-3.0\n"
. "%%BoundingBox: 0 0 " . $this->finalWidth . " " . $this->finalHeight . "\n"
. "/F { rectfill } def\n";
}
/**
* addColor(): defined by RendererInterface.
*
* @see ImageRendererInterface::addColor()
* @param string $id
* @param ColorInterface $color
* @return void
*/
public function addColor($id, ColorInterface $color)
{
if (
!$color instanceof Rgb
&& !$color instanceof Cmyk
&& !$color instanceof Gray
) {
$color = $color->toCmyk();
}
$this->colors[$id] = $color;
}
/**
* drawBackground(): defined by RendererInterface.
*
* @see ImageRendererInterface::drawBackground()
* @param string $colorId
* @return void
*/
public function drawBackground($colorId)
{
$this->setColor($colorId);
$this->eps .= "0 0 " . $this->finalWidth . " " . $this->finalHeight . " F\n";
}
/**
* drawBlock(): defined by RendererInterface.
*
* @see ImageRendererInterface::drawBlock()
* @param integer $x
* @param integer $y
* @param string $colorId
* @return void
*/
public function drawBlock($x, $y, $colorId)
{
$this->setColor($colorId);
$this->eps .= $x . " " . ($this->finalHeight - $y - $this->blockSize) . " " . $this->blockSize . " " . $this->blockSize . " F\n";
}
/**
* getByteStream(): defined by RendererInterface.
*
* @see ImageRendererInterface::getByteStream()
* @return string
*/
public function getByteStream()
{
return $this->eps;
}
/**
* Sets color to use.
*
* @param string $colorId
* @return void
*/
protected function setColor($colorId)
{
if ($colorId !== $this->currentColor) {
$color = $this->colors[$colorId];
if ($color instanceof Rgb) {
$this->eps .= sprintf(
"%F %F %F setrgbcolor\n",
$color->getRed() / 100,
$color->getGreen() / 100,
$color->getBlue() / 100
);
} elseif ($color instanceof Cmyk) {
$this->eps .= sprintf(
"%F %F %F %F setcmykcolor\n",
$color->getCyan() / 100,
$color->getMagenta() / 100,
$color->getYellow() / 100,
$color->getBlack() / 100
);
} elseif ($color instanceof Gray) {
$this->eps .= sprintf(
"%F setgray\n",
$color->getGray() / 100
);
}
$this->currentColor = $colorId;
}
}
}

View File

@@ -0,0 +1,115 @@
<?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\Renderer\Image;
use BaconQrCode\Exception;
use BaconQrCode\Renderer\Color\ColorInterface;
/**
* PNG backend.
*/
class Png extends AbstractRenderer
{
/**
* Image resource used when drawing.
*
* @var resource
*/
protected $image;
/**
* Colors used for drawing.
*
* @var array
*/
protected $colors = array();
/**
* init(): defined by RendererInterface.
*
* @see ImageRendererInterface::init()
* @return void
*/
public function init()
{
$this->image = imagecreatetruecolor($this->finalWidth, $this->finalHeight);
}
/**
* addColor(): defined by RendererInterface.
*
* @see ImageRendererInterface::addColor()
* @param string $id
* @param ColorInterface $color
* @return void
* @throws Exception\RuntimeException
*/
public function addColor($id, ColorInterface $color)
{
if ($this->image === null) {
throw new Exception\RuntimeException('Colors can only be added after init');
}
$color = $color->toRgb();
$this->colors[$id] = imagecolorallocate(
$this->image,
$color->getRed(),
$color->getGreen(),
$color->getBlue()
);
}
/**
* drawBackground(): defined by RendererInterface.
*
* @see ImageRendererInterface::drawBackground()
* @param string $colorId
* @return void
*/
public function drawBackground($colorId)
{
imagefill($this->image, 0, 0, $this->colors[$colorId]);
}
/**
* drawBlock(): defined by RendererInterface.
*
* @see ImageRendererInterface::drawBlock()
* @param integer $x
* @param integer $y
* @param string $colorId
* @return void
*/
public function drawBlock($x, $y, $colorId)
{
imagefilledrectangle(
$this->image,
$x,
$y,
$x + $this->blockSize - 1,
$y + $this->blockSize - 1,
$this->colors[$colorId]
);
}
/**
* getByteStream(): defined by RendererInterface.
*
* @see ImageRendererInterface::getByteStream()
* @return string
*/
public function getByteStream()
{
ob_start();
imagepng($this->image);
return ob_get_clean();
}
}

View File

@@ -0,0 +1,61 @@
<?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\Renderer\Image;
use BaconQrCode\Renderer\Color\ColorInterface;
use BaconQrCode\Renderer\RendererInterface as GeneralRendererInterface;
/**
* Renderer interface.
*/
interface RendererInterface extends GeneralRendererInterface
{
/**
* Initiates the drawing area.
*
* @return void
*/
public function init();
/**
* Adds a color to the drawing area.
*
* @param string $id
* @param ColorInterface $color
* @return void
*/
public function addColor($id, ColorInterface $color);
/**
* Draws the background.
*
* @param string $colorId
* @return void
*/
public function drawBackground($colorId);
/**
* Draws a block at a specified position.
*
* @param integer $x
* @param integer $y
* @param string $colorId
* @return void
*/
public function drawBlock($x, $y, $colorId);
/**
* Returns the byte stream representing the QR code.
*
* @return string
*/
public function getByteStream();
}

View File

@@ -0,0 +1,146 @@
<?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\Renderer\Image;
use BaconQrCode\Exception;
use BaconQrCode\Renderer\Color\ColorInterface;
use SimpleXMLElement;
/**
* SVG backend.
*/
class Svg extends AbstractRenderer
{
/**
* SVG resource.
*
* @var SimpleXMLElement
*/
protected $svg;
/**
* Colors used for drawing.
*
* @var array
*/
protected $colors = array();
/**
* Prototype IDs.
*
* @var array
*/
protected $prototypeIds = array();
/**
* init(): defined by RendererInterface.
*
* @see ImageRendererInterface::init()
* @return void
*/
public function init()
{
$this->svg = new SimpleXMLElement(
'<?xml version="1.0" encoding="UTF-8"?>'
. '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"/>'
);
$this->svg->addAttribute('version', '1.1');
$this->svg->addAttribute('width', $this->finalWidth . 'px');
$this->svg->addAttribute('height', $this->finalHeight . 'px');
$this->svg->addAttribute('viewBox', '0 0 ' . $this->finalWidth . ' ' . $this->finalHeight);
$this->svg->addChild('defs');
}
/**
* addColor(): defined by RendererInterface.
*
* @see ImageRendererInterface::addColor()
* @param string $id
* @param ColorInterface $color
* @return void
* @throws Exception\InvalidArgumentException
*/
public function addColor($id, ColorInterface $color)
{
$this->colors[$id] = (string) $color->toRgb();
}
/**
* drawBackground(): defined by RendererInterface.
*
* @see ImageRendererInterface::drawBackground()
* @param string $colorId
* @return void
*/
public function drawBackground($colorId)
{
$rect = $this->svg->addChild('rect');
$rect->addAttribute('x', 0);
$rect->addAttribute('y', 0);
$rect->addAttribute('width', $this->finalWidth);
$rect->addAttribute('height', $this->finalHeight);
$rect->addAttribute('fill', '#' . $this->colors[$colorId]);
}
/**
* drawBlock(): defined by RendererInterface.
*
* @see ImageRendererInterface::drawBlock()
* @param integer $x
* @param integer $y
* @param string $colorId
* @return void
*/
public function drawBlock($x, $y, $colorId)
{
$use = $this->svg->addChild('use');
$use->addAttribute('x', $x);
$use->addAttribute('y', $y);
$use->addAttribute(
'xlink:href',
$this->getRectPrototypeId($colorId),
'http://www.w3.org/1999/xlink'
);
}
/**
* getByteStream(): defined by RendererInterface.
*
* @see ImageRendererInterface::getByteStream()
* @return string
*/
public function getByteStream()
{
return $this->svg->asXML();
}
/**
* Get the prototype ID for a color.
*
* @param integer $colorId
* @return string
*/
protected function getRectPrototypeId($colorId)
{
if (!isset($this->prototypeIds[$colorId])) {
$id = 'r' . dechex(count($this->prototypeIds));
$rect = $this->svg->defs->addChild('rect');
$rect->addAttribute('id', $id);
$rect->addAttribute('width', $this->blockSize);
$rect->addAttribute('height', $this->blockSize);
$rect->addAttribute('fill', '#' . $this->colors[$colorId]);
$this->prototypeIds[$colorId] = '#' . $id;
}
return $this->prototypeIds[$colorId];
}
}

View File

@@ -0,0 +1,26 @@
<?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\Renderer;
use BaconQrCode\Encoder\QrCode;
/**
* Renderer interface.
*/
interface RendererInterface
{
/**
* Renders a QR code.
*
* @param QrCode $qrCode
* @return string
*/
public function render(QrCode $qrCode);
}

View File

@@ -0,0 +1,91 @@
<?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\Renderer\Text;
use BaconQrCode\Encoder\QrCode;
/**
* Html renderer.
*/
class Html extends Plain
{
/**
* HTML CSS class attribute value.
*
* @var string
*/
protected $class = '';
/**
* HTML CSS style definition for the code element.
*
* @var string
*/
protected $style = 'font-family: monospace; line-height: 0.65em; letter-spacing: -1px';
/**
* Set CSS class name.
*
* @param string $class
*/
public function setClass($class)
{
$this->class = $class;
}
/**
* Get CSS class name.
*
* @return string
*/
public function getClass()
{
return $this->class;
}
/**
* Set CSS style value.
*
* @param string $style
*/
public function setStyle($style)
{
$this->style = $style;
}
/**
* Get CSS style value.
*
* @return string
*/
public function getStyle()
{
return $this->style;
}
/**
* render(): defined by RendererInterface.
*
* @see RendererInterface::render()
* @param QrCode $qrCode
* @return string
*/
public function render(QrCode $qrCode)
{
$textCode = parent::render($qrCode);
$result = '<pre'
. ' style="' . htmlspecialchars($this->style, ENT_QUOTES, 'utf-8') . '"'
. ' class="' . htmlspecialchars($this->class, ENT_QUOTES, 'utf-8') . '"'
. '>' . $textCode . '</pre>';
return $result;
}
}

View File

@@ -0,0 +1,150 @@
<?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\Renderer\Text;
use BaconQrCode\Exception;
use BaconQrCode\Encoder\QrCode;
use BaconQrCode\Renderer\RendererInterface;
/**
* Plaintext renderer.
*/
class Plain implements RendererInterface
{
/**
* Margin around the QR code, also known as quiet zone.
*
* @var integer
*/
protected $margin = 1;
/**
* Char used for full block.
*
* UTF-8 FULL BLOCK (U+2588)
*
* @var string
* @link http://www.fileformat.info/info/unicode/char/2588/index.htm
*/
protected $fullBlock = "\xE2\x96\x88";
/**
* Char used for empty space
*
* @var string
*/
protected $emptyBlock = ' ';
/**
* Set char used as full block (occupied space, "black").
*
* @param string $fullBlock
*/
public function setFullBlock($fullBlock)
{
$this->fullBlock = $fullBlock;
}
/**
* Get char used as full block (occupied space, "black").
*
* @return string
*/
public function getFullBlock()
{
return $this->fullBlock;
}
/**
* Set char used as empty block (empty space, "white").
*
* @param string $emptyBlock
*/
public function setEmptyBlock($emptyBlock)
{
$this->emptyBlock = $emptyBlock;
}
/**
* Get char used as empty block (empty space, "white").
*
* @return string
*/
public function getEmptyBlock()
{
return $this->emptyBlock;
}
/**
* Sets the margin around the QR code.
*
* @param integer $margin
* @return AbstractRenderer
* @throws Exception\InvalidArgumentException
*/
public function setMargin($margin)
{
if ($margin < 0) {
throw new Exception\InvalidArgumentException('Margin must be equal to greater than 0');
}
$this->margin = (int) $margin;
return $this;
}
/**
* Gets the margin around the QR code.
*
* @return integer
*/
public function getMargin()
{
return $this->margin;
}
/**
* render(): defined by RendererInterface.
*
* @see RendererInterface::render()
* @param QrCode $qrCode
* @return string
*/
public function render(QrCode $qrCode)
{
$result = '';
$matrix = $qrCode->getMatrix();
$width = $matrix->getWidth();
// Top margin
for ($x = 0; $x < $this->margin; $x++) {
$result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin)."\n";
}
// Body
$array = $matrix->getArray();
foreach ($array as $row) {
$result .= str_repeat($this->emptyBlock, $this->margin); // left margin
foreach ($row as $byte) {
$result .= $byte ? $this->fullBlock : $this->emptyBlock;
}
$result .= str_repeat($this->emptyBlock, $this->margin); // right margin
$result .= "\n";
}
// Bottom margin
for ($x = 0; $x < $this->margin; $x++) {
$result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin)."\n";
}
return $result;
}
}

View File

@@ -0,0 +1,105 @@
<?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;
use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Encoder\Encoder;
use BaconQrCode\Exception;
use BaconQrCode\Renderer\RendererInterface;
/**
* QR code writer.
*/
class Writer
{
/**
* Renderer instance.
*
* @var RendererInterface
*/
protected $renderer;
/**
* Creates a new writer with a specific renderer.
*
* @param RendererInterface $renderer
*/
public function __construct(RendererInterface $renderer)
{
$this->renderer = $renderer;
}
/**
* Sets the renderer used to create a byte stream.
*
* @param RendererInterface $renderer
* @return Writer
*/
public function setRenderer(RendererInterface $renderer)
{
$this->renderer = $renderer;
return $this;
}
/**
* Gets the renderer used to create a byte stream.
*
* @return RendererInterface
*/
public function getRenderer()
{
return $this->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.
*
* @param string $content
* @param string $encoding
* @param integer $ecLevel
* @return string
* @throws Exception\InvalidArgumentException
*/
public function writeString(
$content,
$encoding = Encoder::DEFAULT_BYTE_MODE_ECODING,
$ecLevel = ErrorCorrectionLevel::L
) {
if (strlen($content) === 0) {
throw new Exception\InvalidArgumentException('Found empty contents');
}
$qrCode = Encoder::encode($content, new ErrorCorrectionLevel($ecLevel), $encoding);
return $this->getRenderer()->render($qrCode);
}
/**
* Writes QR code to a file.
*
* @see Writer::writeString()
* @param string $content
* @param string $filename
* @param string $encoding
* @param integer $ecLevel
* @return void
*/
public function writeFile(
$content,
$filename,
$encoding = Encoder::DEFAULT_BYTE_MODE_ECODING,
$ecLevel = ErrorCorrectionLevel::L
) {
file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel));
}
}

View File

@@ -0,0 +1,201 @@
<?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;
use PHPUnit_Framework_TestCase as TestCase;
class BitArrayTest extends TestCase
{
public function testGetSet()
{
$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()
{
$array = new BitArray(32);
for ($i = 0; $i < $array->getSize(); $i++) {
$this->assertEquals($i, 32, '', $array->getNextSet($i));
}
$array = new BitArray(33);
for ($i = 0; $i < $array->getSize(); $i++) {
$this->assertEquals($i, 33, '', $array->getNextSet($i));
}
}
public function testGetNextSet2()
{
$array = new BitArray(33);
for ($i = 0; $i < $array->getSize(); $i++) {
$this->assertEquals($i, $i <= 31 ? 31 : 33, '', $array->getNextSet($i));
}
$array = new BitArray(33);
for ($i = 0; $i < $array->getSize(); $i++) {
$this->assertEquals($i, 32, '', $array->getNextSet($i));
}
}
public function testGetNextSet3()
{
$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;
}
$this->assertEquals($i, $expected, '', $array->getNextSet($i));
}
}
public function testGetNextSet4()
{
$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;
}
$this->assertEquals($i, $expected, '', $array->getNextSet($i));
}
}
public function testGetNextSet5()
{
if (defined('MT_RAND_PHP')) {
mt_srand(0xdeadbeef, MT_RAND_PHP);
} else {
mt_srand(0xdeadbeef);
}
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()
{
$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()
{
$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()
{
$array = new BitArray(64);
$array->set(0);
$array->set(63);
$ints = $array->getBitArray();
$this->assertEquals(1, $ints[0]);
$this->assertEquals(0x80000000, $ints[1]);
}
public function testIsRange()
{
$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));
}
}

View File

@@ -0,0 +1,119 @@
<?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;
use PHPUnit_Framework_TestCase as TestCase;
class BitMatrixTest extends TestCase
{
public function testGetSet()
{
$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->assertEquals($x * $y % 3 === 0, $matrix->get($x, $y));
}
}
}
public function testSetRegion()
{
$matrix = new BitMatrix(5);
$matrix->setRegion(1, 1, 3, 3);
for ($y = 0; $y < 5; $y++) {
for ($x = 0; $x < 5; $x++) {
$this->assertEquals($y >= 1 && $y <= 3 && $x >= 1 && $x <= 3, $matrix->get($x, $y));
}
}
}
public function testRectangularMatrix()
{
$matrix = new BitMatrix(75, 20);
$this->assertEquals(75, $matrix->getWidth());
$this->assertEquals(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()
{
$matrix = new BitMatrix(320, 240);
$this->assertEquals(320, $matrix->getWidth());
$this->assertEquals(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()
{
$matrix = new BitMatrix(102, 5);
for ($x = 0; $x < 102; $x++) {
if ($x & 3 === 0) {
$matrix->set($x, 2);
}
}
$array1 = $matrix->getRow(2, null);
$this->assertEquals(102, $array1->getSize());
$array2 = new BitArray(60);
$array2 = $matrix->getRow(2, $array2);
$this->assertEquals(102, $array2->getSize());
$array3 = new BitArray(200);
$array3 = $matrix->getRow(2, $array3);
$this->assertEquals(200, $array3->getSize());
for ($x = 0; $x < 102; $x++) {
$on = ($x & 3 === 0);
$this->assertEquals($on, $array1->get($x));
$this->assertEquals($on, $array2->get($x));
$this->assertEquals($on, $array3->get($x));
}
}
}

View File

@@ -0,0 +1,30 @@
<?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;
use PHPUnit_Framework_TestCase as TestCase;
class BitUtilsTest extends TestCase
{
public function testUnsignedRightShift()
{
$this->assertEquals(1, BitUtils::unsignedRightShift(1, 0));
$this->assertEquals(1, BitUtils::unsignedRightShift(10, 3));
$this->assertEquals(536870910, BitUtils::unsignedRightShift(-10, 3));
}
public function testNumberOfTrailingZeros()
{
$this->assertEquals(32, BitUtils::numberOfTrailingZeros(0));
$this->assertEquals(1, BitUtils::numberOfTrailingZeros(10));
$this->assertEquals(0, BitUtils::numberOfTrailingZeros(15));
$this->assertEquals(2, BitUtils::numberOfTrailingZeros(20));
}
}

View File

@@ -0,0 +1,40 @@
<?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;
use PHPUnit_Framework_TestCase as TestCase;
class ErrorCorrectionLevelTest extends TestCase
{
public function testCreationThrowsNoException()
{
new ErrorCorrectionLevel(ErrorCorrectionLevel::M);
new ErrorCorrectionLevel(ErrorCorrectionLevel::L);
new ErrorCorrectionLevel(ErrorCorrectionLevel::H);
new ErrorCorrectionLevel(ErrorCorrectionLevel::Q);
}
public function testBitsMatchConstants()
{
$this->assertEquals(0x0, ErrorCorrectionLevel::M);
$this->assertEquals(0x1, ErrorCorrectionLevel::L);
$this->assertEquals(0x2, ErrorCorrectionLevel::H);
$this->assertEquals(0x3, ErrorCorrectionLevel::Q);
}
public function testInvalidErrorCorrectionLevelThrowsException()
{
$this->setExpectedException(
'BaconQrCode\Exception\UnexpectedValueException',
'Value not a const in enum BaconQrCode\Common\ErrorCorrectionLevel'
);
new ErrorCorrectionLevel(4);
}
}

View File

@@ -0,0 +1,104 @@
<?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;
use PHPUnit_Framework_TestCase as TestCase;
class FormatInformationTest extends TestCase
{
protected $maskedTestFormatInfo = 0x2bed;
protected $unmaskedTestFormatInfo;
public function setUp()
{
$this->unmaskedTestFormatInfo = $this->maskedTestFormatInfo ^ 0x5412;
}
public function testBitsDiffering()
{
$this->assertEquals(0, FormatInformation::numBitsDiffering(1, 1));
$this->assertEquals(1, FormatInformation::numBitsDiffering(0, 2));
$this->assertEquals(2, FormatInformation::numBitsDiffering(1, 2));
$this->assertEquals(32, FormatInformation::numBitsDiffering(-1, 0));
}
public function testDecode()
{
$expected = FormatInformation::decodeFormatInformation(
$this->maskedTestFormatInfo,
$this->maskedTestFormatInfo
);
$this->assertNotNull($expected);
$this->assertEquals(7, $expected->getDataMask());
$this->assertEquals(ErrorCorrectionLevel::Q, $expected->getErrorCorrectionLevel()->get());
$this->assertEquals(
$expected,
FormatInformation::decodeFormatInformation(
$this->unmaskedTestFormatInfo,
$this->maskedTestFormatInfo
)
);
}
public function testDecodeWithBitDifference()
{
$expected = FormatInformation::decodeFormatInformation(
$this->maskedTestFormatInfo,
$this->maskedTestFormatInfo
);
$this->assertEquals(
$expected,
FormatInformation::decodeFormatInformation(
$this->maskedTestFormatInfo ^ 0x1,
$this->maskedTestFormatInfo ^ 0x1
)
);
$this->assertEquals(
$expected,
FormatInformation::decodeFormatInformation(
$this->maskedTestFormatInfo ^ 0x3,
$this->maskedTestFormatInfo ^ 0x3
)
);
$this->assertEquals(
$expected,
FormatInformation::decodeFormatInformation(
$this->maskedTestFormatInfo ^ 0x7,
$this->maskedTestFormatInfo ^ 0x7
)
);
$this->assertNull(
FormatInformation::decodeFormatInformation(
$this->maskedTestFormatInfo ^ 0xf,
$this->maskedTestFormatInfo ^ 0xf
)
);
}
public function testDecodeWithMisRead()
{
$expected = FormatInformation::decodeFormatInformation(
$this->maskedTestFormatInfo,
$this->maskedTestFormatInfo
);
$this->assertEquals(
$expected,
FormatInformation::decodeFormatInformation(
$this->maskedTestFormatInfo ^ 0x3,
$this->maskedTestFormatInfo ^ 0xf
)
);
}
}

View File

@@ -0,0 +1,42 @@
<?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;
use PHPUnit_Framework_TestCase as TestCase;
class ModeTest extends TestCase
{
public function testCreationThrowsNoException()
{
new Mode(Mode::TERMINATOR);
new Mode(Mode::NUMERIC);
new Mode(Mode::ALPHANUMERIC);
new Mode(Mode::BYTE);
new Mode(Mode::KANJI);
}
public function testBitsMatchConstants()
{
$this->assertEquals(0x0, Mode::TERMINATOR);
$this->assertEquals(0x1, Mode::NUMERIC);
$this->assertEquals(0x2, Mode::ALPHANUMERIC);
$this->assertEquals(0x4, Mode::BYTE);
$this->assertEquals(0x8, Mode::KANJI);
}
public function testInvalidModeThrowsException()
{
$this->setExpectedException(
'BaconQrCode\Exception\UnexpectedValueException',
'Value not a const in enum BaconQrCode\Common\Mode'
);
new Mode(10);
}
}

View File

@@ -0,0 +1,111 @@
<?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;
use PHPUnit_Framework_TestCase as TestCase;
use SplFixedArray;
class ReedSolomonTest extends TestCase
{
public static function tabProvider()
{
return array(
array(2, 0x7, 1, 1, 1),
array(3, 0xb, 1, 1, 2),
array(4, 0x13, 1, 1, 4),
array(5, 0x25, 1, 1, 6),
array(6, 0x43, 1, 1, 8),
array(7, 0x89, 1, 1, 10),
array(8, 0x11d, 1, 1, 32),
);
}
/**
* @dataProvider tabProvider
* @param integer $symbolSize
* @param integer $generatorPoly
* @param integer $firstRoot
* @param integer $primitive
* @param integer $numRoots
* @return void
*/
public function testCodec($symbolSize, $generatorPoly, $firstRoot, $primitive, $numRoots)
{
if (defined('MT_RAND_PHP')) {
mt_srand(0xdeadbeef, MT_RAND_PHP);
} else {
mt_srand(0xdeadbeef);
}
$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 = array();
// 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 ($errorLocations[$errorLocation] !== 0);
$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 && $foundErrors === null) {
$this->assertEquals($block, $tBlock, 'Decoder failed to correct errors');
}
$this->assertEquals($errors, $foundErrors, 'Found errors do not equal expected errors');
for ($i = 0; $i < $foundErrors; $i++) {
if ($errorLocations[$erasures[$i]] === 0) {
$this->fail(sprintf('Decoder indicates error in location %d without error', $erasures[$i]));
}
}
$this->assertEquals($block, $tBlock, 'Decoder did not correct errors');
}
}
}

View File

@@ -0,0 +1,88 @@
<?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;
use PHPUnit_Framework_TestCase as TestCase;
class VersionTest extends TestCase
{
public static function versionProvider()
{
$array = array();
for ($i = 1; $i <= 40; $i++) {
$array[] = array($i, 4 * $i + 17);
}
return $array;
}
public static function decodeInformationProvider()
{
return array(
array(7, 0x07c94),
array(12, 0x0c762),
array(17, 0x1145d),
array(22, 0x168c9),
array(27, 0x1b08e),
array(32, 0x209d5),
);
}
/**
* @dataProvider versionProvider
* @param integer $versionNumber
* @param integer $dimension
*/
public function testVersionForNumber($versionNumber, $dimension)
{
$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(new ErrorCorrectionLevel(ErrorCorrectionLevel::H)));
$this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::L)));
$this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::M)));
$this->assertNotNull($version->getEcBlocksForLevel(new ErrorCorrectionLevel(ErrorCorrectionLevel::Q)));
$this->assertNotNull($version->buildFunctionPattern());
}
/**
* @dataProvider versionProvider
* @param integer $versionNumber
* @param integer $dimension
*/
public function testGetProvisionalVersionForDimension($versionNumber, $dimension)
{
$this->assertEquals(
$versionNumber,
Version::getProvisionalVersionForDimension($dimension)->getVersionNumber()
);
}
/**
* @dataProvider decodeInformationProvider
* @param integer $expectedVersion
* @param integer $mask
*/
public function testDecodeVersionInformation($expectedVersion, $mask)
{
$version = Version::decodeVersionInformation($mask);
$this->assertNotNull($version);
$this->assertEquals($expectedVersion, $version->getVersionNumber());
}
}

View File

@@ -0,0 +1,468 @@
<?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\Encoder;
use BaconQrCode\Common\BitArray;
use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Common\Mode;
use BaconQrCode\Common\Version;
use PHPUnit_Framework_TestCase as TestCase;
use ReflectionClass;
use ReflectionMethod;
use SplFixedArray;
class EncoderTest extends TestCase
{
protected $methods = array();
public function setUp()
{
// Hack to be able to test protected methods
$reflection = new ReflectionClass('BaconQrCode\Encoder\Encoder');
foreach ($reflection->getMethods(ReflectionMethod::IS_STATIC) as $method) {
$method->setAccessible(true);
$this->methods[$method->getName()] = $method;
}
}
public function testGetAlphanumericCode()
{
// The first ten code points are numbers.
for ($i = 0; $i < 10; $i++) {
$this->assertEquals($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->assertEquals($i, $this->methods['getAlphanumericCode']->invoke(null, ord('A') + $i - 10));
}
// Others are symbol letters.
$this->assertEquals(36, $this->methods['getAlphanumericCode']->invoke(null, ' '));
$this->assertEquals(37, $this->methods['getAlphanumericCode']->invoke(null, '$'));
$this->assertEquals(38, $this->methods['getAlphanumericCode']->invoke(null, '%'));
$this->assertEquals(39, $this->methods['getAlphanumericCode']->invoke(null, '*'));
$this->assertEquals(40, $this->methods['getAlphanumericCode']->invoke(null, '+'));
$this->assertEquals(41, $this->methods['getAlphanumericCode']->invoke(null, '-'));
$this->assertEquals(42, $this->methods['getAlphanumericCode']->invoke(null, '.'));
$this->assertEquals(43, $this->methods['getAlphanumericCode']->invoke(null, '/'));
$this->assertEquals(44, $this->methods['getAlphanumericCode']->invoke(null, ':'));
// Should return -1 for other letters.
$this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, 'a'));
$this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, '#'));
$this->assertEquals(-1, $this->methods['getAlphanumericCode']->invoke(null, "\0"));
}
public function testChooseMode()
{
// Numeric mode
$this->assertSame(Mode::NUMERIC, $this->methods['chooseMode']->invoke(null, '0')->get());
$this->assertSame(Mode::NUMERIC, $this->methods['chooseMode']->invoke(null, '0123456789')->get());
// Alphanumeric mode
$this->assertSame(Mode::ALPHANUMERIC, $this->methods['chooseMode']->invoke(null, 'A')->get());
$this->assertSame(Mode::ALPHANUMERIC, $this->methods['chooseMode']->invoke(null, '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:')->get());
// 8-bit byte mode
$this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, 'a')->get());
$this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, '#')->get());
$this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, '')->get());
// AIUE in Hiragana in SHIFT-JIS
$this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\x8\xa\x8\xa\x8\xa\x8\xa6")->get());
// Nihon in Kanji in SHIFT-JIS
$this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\x9\xf\x9\x7b")->get());
// Sou-Utso-Byou in Kanji in SHIFT-JIS
$this->assertSame(Mode::BYTE, $this->methods['chooseMode']->invoke(null, "\xe\x4\x9\x5\x9\x61")->get());
}
public function testEncode()
{
$qrCode = Encoder::encode('ABCDEF', new ErrorCorrectionLevel(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->assertEquals($expected, $qrCode->__toString());
}
public function testSimpleUtf8Eci()
{
$qrCode = Encoder::encode('hello', new ErrorCorrectionLevel(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->assertEquals($expected, $qrCode->__toString());
}
public function testAppendModeInfo()
{
$bits = new BitArray();
$this->methods['appendModeInfo']->invoke(null, new Mode(Mode::NUMERIC), $bits);
$this->assertEquals(' ...X', $bits->__toString());
}
public function testAppendLengthInfo()
{
// 1 letter (1/1), 10 bits.
$bits = new BitArray();
$this->methods['appendLengthInfo']->invoke(
null,
1,
Version::getVersionForNumber(1),
new Mode(Mode::NUMERIC),
$bits
);
$this->assertEquals(' ........ .X', $bits->__toString());
// 2 letters (2/1), 11 bits.
$bits = new BitArray();
$this->methods['appendLengthInfo']->invoke(
null,
2,
Version::getVersionForNumber(10),
new Mode(Mode::ALPHANUMERIC),
$bits
);
$this->assertEquals(' ........ .X.', $bits->__toString());
// 255 letters (255/1), 16 bits.
$bits = new BitArray();
$this->methods['appendLengthInfo']->invoke(
null,
255,
Version::getVersionForNumber(27),
new Mode(Mode::BYTE),
$bits
);
$this->assertEquals(' ........ XXXXXXXX', $bits->__toString());
// 512 letters (1024/2), 12 bits.
$bits = new BitArray();
$this->methods['appendLengthInfo']->invoke(
null,
512,
Version::getVersionForNumber(40),
new Mode(Mode::KANJI),
$bits
);
$this->assertEquals(' ..X..... ....', $bits->__toString());
}
public function testAppendBytes()
{
// Should use appendNumericBytes.
// 1 = 01 = 0001 in 4 bits.
$bits = new BitArray();
$this->methods['appendBytes']->invoke(
null,
'1',
new Mode(Mode::NUMERIC),
$bits,
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->assertEquals(' ...X', $bits->__toString());
// Should use appendAlphaNumericBytes.
// A = 10 = 0xa = 001010 in 6 bits.
$bits = new BitArray();
$this->methods['appendBytes']->invoke(
null,
'A',
new Mode(Mode::ALPHANUMERIC),
$bits,
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->assertEquals(' ..X.X.', $bits->__toString());
// Should use append8BitBytes.
// 0x61, 0x62, 0x63
$bits = new BitArray();
$this->methods['appendBytes']->invoke(
null,
'abc',
new Mode(Mode::BYTE),
$bits,
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->assertEquals(' .XX....X .XX...X. .XX...XX', $bits->__toString());
// Should use appendKanjiBytes.
// 0x93, 0x5f
$bits = new BitArray();
$this->methods['appendBytes']->invoke(
null,
"\x93\x5f",
new Mode(Mode::KANJI),
$bits,
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->assertEquals(' .XX.XX.. XXXXX', $bits->__toString());
// Lower letters such as 'a' cannot be encoded in alphanumeric mode.
$this->setExpectedException(
'BaconQrCode\Exception\WriterException',
'Invalid alphanumeric code'
);
$this->methods['appendBytes']->invoke(
null,
"a",
new Mode(Mode::ALPHANUMERIC),
$bits,
Encoder::DEFAULT_BYTE_MODE_ECODING
);
}
public function testTerminateBits()
{
$bits = new BitArray();
$this->methods['terminateBits']->invoke(null, 0, $bits);
$this->assertEquals('', $bits->__toString());
$bits = new BitArray();
$this->methods['terminateBits']->invoke(null, 1, $bits);
$this->assertEquals(' ........', $bits->__toString());
$bits = new BitArray();
$bits->appendBits(0, 3);
$this->methods['terminateBits']->invoke(null, 1, $bits);
$this->assertEquals(' ........', $bits->__toString());
$bits = new BitArray();
$bits->appendBits(0, 5);
$this->methods['terminateBits']->invoke(null, 1, $bits);
$this->assertEquals(' ........', $bits->__toString());
$bits = new BitArray();
$bits->appendBits(0, 8);
$this->methods['terminateBits']->invoke(null, 1, $bits);
$this->assertEquals(' ........', $bits->__toString());
$bits = new BitArray();
$this->methods['terminateBits']->invoke(null, 2, $bits);
$this->assertEquals(' ........ XXX.XX..', $bits->__toString());
$bits = new BitArray();
$bits->appendBits(0, 1);
$this->methods['terminateBits']->invoke(null, 3, $bits);
$this->assertEquals(' ........ XXX.XX.. ...X...X', $bits->__toString());
}
public function testGetNumDataBytesAndNumEcBytesForBlockId()
{
// Version 1-H.
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 26, 9, 1, 0);
$this->assertEquals(9, $numDataBytes);
$this->assertEquals(17, $numEcBytes);
// Version 3-H. 2 blocks.
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 70, 26, 2, 0);
$this->assertEquals(13, $numDataBytes);
$this->assertEquals(22, $numEcBytes);
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 70, 26, 2, 1);
$this->assertEquals(13, $numDataBytes);
$this->assertEquals(22, $numEcBytes);
// Version 7-H. (4 + 1) blocks.
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 196, 66, 5, 0);
$this->assertEquals(13, $numDataBytes);
$this->assertEquals(26, $numEcBytes);
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 196, 66, 5, 4);
$this->assertEquals(14, $numDataBytes);
$this->assertEquals(26, $numEcBytes);
// Version 40-H. (20 + 61) blocks.
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 0);
$this->assertEquals(15, $numDataBytes);
$this->assertEquals(30, $numEcBytes);
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 20);
$this->assertEquals(16, $numDataBytes);
$this->assertEquals(30, $numEcBytes);
list($numDataBytes, $numEcBytes) = $this->methods['getNumDataBytesAndNumEcBytesForBlockId']->invoke(null, 3706, 1276, 81, 80);
$this->assertEquals(16, $numDataBytes);
$this->assertEquals(30, $numEcBytes);
}
public function testInterleaveWithEcBytes()
{
$dataBytes = SplFixedArray::fromArray(array(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(array(
// 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()
{
// 1 = 01 = 0001 in 4 bits.
$bits = new BitArray();
$this->methods['appendNumericBytes']->invoke(null, '1', $bits);
$this->assertEquals(' ...X', $bits->__toString());
// 12 = 0xc = 0001100 in 7 bits.
$bits = new BitArray();
$this->methods['appendNumericBytes']->invoke(null, '12', $bits);
$this->assertEquals(' ...XX..', $bits->__toString());
// 123 = 0x7b = 0001111011 in 10 bits.
$bits = new BitArray();
$this->methods['appendNumericBytes']->invoke(null, '123', $bits);
$this->assertEquals(' ...XXXX. XX', $bits->__toString());
// 1234 = "123" + "4" = 0001111011 + 0100 in 14 bits.
$bits = new BitArray();
$this->methods['appendNumericBytes']->invoke(null, '1234', $bits);
$this->assertEquals(' ...XXXX. XX.X..', $bits->__toString());
// Empty
$bits = new BitArray();
$this->methods['appendNumericBytes']->invoke(null, '', $bits);
$this->assertEquals('', $bits->__toString());
}
public function testAppendAlphanumericBytes()
{
$bits = new BitArray();
$this->methods['appendAlphanumericBytes']->invoke(null, 'A', $bits);
$this->assertEquals(' ..X.X.', $bits->__toString());
$bits = new BitArray();
$this->methods['appendAlphanumericBytes']->invoke(null, 'AB', $bits);
$this->assertEquals(' ..XXX..X X.X', $bits->__toString());
$bits = new BitArray();
$this->methods['appendAlphanumericBytes']->invoke(null, 'ABC', $bits);
$this->assertEquals(' ..XXX..X X.X..XX. .', $bits->__toString());
// Empty
$bits = new BitArray();
$this->methods['appendAlphanumericBytes']->invoke(null, '', $bits);
$this->assertEquals('', $bits->__toString());
// Invalid data
$this->setExpectedException('BaconQrCode\Exception\WriterException', 'Invalid alphanumeric code');
$bits = new BitArray();
$this->methods['appendAlphanumericBytes']->invoke(null, 'abc', $bits);
}
public function testAppend8BitBytes()
{
// 0x61, 0x62, 0x63
$bits = new BitArray();
$this->methods['append8BitBytes']->invoke(null, 'abc', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING);
$this->assertEquals(' .XX....X .XX...X. .XX...XX', $bits->__toString());
// Empty
$bits = new BitArray();
$this->methods['append8BitBytes']->invoke(null, '', $bits, Encoder::DEFAULT_BYTE_MODE_ECODING);
$this->assertEquals('', $bits->__toString());
}
public function testAppendKanjiBytes()
{
// Numbers are from page 21 of JISX0510:2004
$bits = new BitArray();
$this->methods['appendKanjiBytes']->invoke(null, "\x93\x5f", $bits);
$this->assertEquals(' .XX.XX.. XXXXX', $bits->__toString());
$this->methods['appendKanjiBytes']->invoke(null, "\xe4\xaa", $bits);
$this->assertEquals(' .XX.XX.. XXXXXXX. X.X.X.X. X.', $bits->__toString());
}
public function testGenerateEcBytes()
{
// Numbers are from http://www.swetake.com/qr/qr3.html and
// http://www.swetake.com/qr/qr9.html
$dataBytes = SplFixedArray::fromArray(array(32, 65, 205, 69, 41, 220, 46, 128, 236), false);
$ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17);
$expected = SplFixedArray::fromArray(array(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(array(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(array(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(array(32, 49, 205, 69, 42, 20, 0, 236, 17), false);
$ecBytes = $this->methods['generateEcBytes']->invoke(null, $dataBytes, 17);
$expected = SplFixedArray::fromArray(array(0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213), false);
$this->assertEquals($expected, $ecBytes);
}
}

View File

@@ -0,0 +1,281 @@
<?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\Encoder;
use PHPUnit_Framework_TestCase as TestCase;
class MaskUtilTest extends TestCase
{
public static function dataMaskBitProvider()
{
return array(
array(
0,
array(
array(1, 0, 1, 0, 1, 0),
array(0, 1, 0, 1, 0, 1),
array(1, 0, 1, 0, 1, 0),
array(0, 1, 0, 1, 0, 1),
array(1, 0, 1, 0, 1, 0),
array(0, 1, 0, 1, 0, 1),
)
),
array(
1,
array(
array(1, 1, 1, 1, 1, 1),
array(0, 0, 0, 0, 0, 0),
array(1, 1, 1, 1, 1, 1),
array(0, 0, 0, 0, 0, 0),
array(1, 1, 1, 1, 1, 1),
array(0, 0, 0, 0, 0, 0),
)
),
array(
2,
array(
array(1, 0, 0, 1, 0, 0),
array(1, 0, 0, 1, 0, 0),
array(1, 0, 0, 1, 0, 0),
array(1, 0, 0, 1, 0, 0),
array(1, 0, 0, 1, 0, 0),
array(1, 0, 0, 1, 0, 0),
)
),
array(
3,
array(
array(1, 0, 0, 1, 0, 0),
array(0, 0, 1, 0, 0, 1),
array(0, 1, 0, 0, 1, 0),
array(1, 0, 0, 1, 0, 0),
array(0, 0, 1, 0, 0, 1),
array(0, 1, 0, 0, 1, 0),
)
),
array(
4,
array(
array(1, 1, 1, 0, 0, 0),
array(1, 1, 1, 0, 0, 0),
array(0, 0, 0, 1, 1, 1),
array(0, 0, 0, 1, 1, 1),
array(1, 1, 1, 0, 0, 0),
array(1, 1, 1, 0, 0, 0),
)
),
array(
5,
array(
array(1, 1, 1, 1, 1, 1),
array(1, 0, 0, 0, 0, 0),
array(1, 0, 0, 1, 0, 0),
array(1, 0, 1, 0, 1, 0),
array(1, 0, 0, 1, 0, 0),
array(1, 0, 0, 0, 0, 0),
)
),
array(
6,
array(
array(1, 1, 1, 1, 1, 1),
array(1, 1, 1, 0, 0, 0),
array(1, 1, 0, 1, 1, 0),
array(1, 0, 1, 0, 1, 0),
array(1, 0, 1, 1, 0, 1),
array(1, 0, 0, 0, 1, 1),
)
),
array(
7,
array(
array(1, 0, 1, 0, 1, 0),
array(0, 0, 0, 1, 1, 1),
array(1, 0, 0, 0, 1, 1),
array(0, 1, 0, 1, 0, 1),
array(1, 1, 1, 0, 0, 0),
array(0, 1, 1, 1, 0, 0),
)
),
);
}
/**
* @dataProvider dataMaskBitProvider
* @param integer $maskPattern
* @param array $expected
* @return void
*/
public function testGetDatMaskBit($maskPattern, array $expected)
{
for ($x = 0; $x < 6; $x++) {
for ($y = 0; $y < 6; $y++) {
if (($expected[$y][$x] === 1) !== MaskUtil::getDataMaskBit($maskPattern, $x, $y)) {
$this->fail('Data mask bit did not match');
}
}
}
}
public function testApplyMaskPenaltyRule1()
{
$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->assertEquals(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->assertEquals(3, MaskUtil::applyMaskPenaltyRule1($matrix));
$matrix->set(5, 0, 0);
$this->assertEquals(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->assertEquals(3, MaskUtil::applyMaskPenaltyRule1($matrix));
$matrix->set(0, 5, 0);
$this->assertEquals(4, MaskUtil::applyMaskPenaltyRule1($matrix));
}
public function testApplyMaskPenaltyRule2()
{
$matrix = new ByteMatrix(1, 1);
$matrix->set(0, 0, 0);
$this->assertEquals(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->assertEquals(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->assertEquals(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->assertEquals(3 * 4, MaskUtil::applyMaskPenaltyRule2($matrix));
}
public function testApplyMaskPenalty3()
{
// 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->assertEquals(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->assertEquals(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->assertEquals(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->assertEquals(40, MaskUtil::applyMaskPenaltyRule3($matrix));
}
public function testApplyMaskPenaltyRule4()
{
// Dark cell ratio = 0%
$matrix = new ByteMatrix(1, 1);
$matrix->set(0, 0, 0);
$this->assertEquals(100, MaskUtil::applyMaskPenaltyRule4($matrix));
// Dark cell ratio = 5%
$matrix = new ByteMatrix(2, 1);
$matrix->set(0, 0, 0);
$matrix->set(0, 0, 1);
$this->assertEquals(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->assertEquals(30, MaskUtil::applyMaskPenaltyRule4($matrix));
}
}

View File

@@ -0,0 +1,336 @@
<?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\Encoder;
use BaconQrCode\Common\BitArray;
use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Common\Version;
use PHPUnit_Framework_TestCase as TestCase;
use ReflectionClass;
use ReflectionMethod;
class MatrixUtilTest extends TestCase
{
protected $methods = array();
public function setUp()
{
// Hack to be able to test protected methods
$reflection = new ReflectionClass('BaconQrCode\Encoder\MatrixUtil');
foreach ($reflection->getMethods(ReflectionMethod::IS_STATIC) as $method) {
$method->setAccessible(true);
$this->methods[$method->getName()] = $method;
}
}
public function testToString()
{
$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->assertEquals($expected, $matrix->__toString());
}
public function testClearMatrix()
{
$matrix = new ByteMatrix(2, 2);
MatrixUtil::clearMatrix($matrix);
$this->assertEquals(-1, $matrix->get(0, 0));
$this->assertEquals(-1, $matrix->get(1, 0));
$this->assertEquals(-1, $matrix->get(0, 1));
$this->assertEquals(-1, $matrix->get(1, 1));
}
public function testEmbedBasicPatterns1()
{
$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->assertEquals($expected, $matrix->__toString());
}
public function testEmbedBasicPatterns2()
{
$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->assertEquals($expected, $matrix->__toString());
}
public function testEmbedTypeInfo()
{
$matrix = new ByteMatrix(21, 21);
MatrixUtil::clearMatrix($matrix);
$this->methods['embedTypeInfo']->invoke(
null,
new ErrorCorrectionLevel(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->assertEquals($expected, $matrix->__toString());
}
public function testEmbedVersionInfo()
{
$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->assertEquals($expected, $matrix->__toString());
}
public function testEmbedDataBits()
{
$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->assertEquals($expected, $matrix->__toString());
}
public function testBuildMatrix()
{
$bytes = array(
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,
new ErrorCorrectionLevel(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->assertEquals($expected, $matrix->__toString());
}
public function testFindMsbSet()
{
$this->assertEquals(0, $this->methods['findMsbSet']->invoke(null, 0));
$this->assertEquals(1, $this->methods['findMsbSet']->invoke(null, 1));
$this->assertEquals(8, $this->methods['findMsbSet']->invoke(null, 0x80));
$this->assertEquals(32, $this->methods['findMsbSet']->invoke(null, 0x80000000));
}
public function testCalculateBchCode()
{
// Encoding of type information.
// From Appendix C in JISX0510:2004 (p 65)
$this->assertEquals(0xdc, $this->methods['calculateBchCode']->invoke(null, 5, 0x537));
// From http://www.swetake.com/qr/qr6.html
$this->assertEquals(0x1c2, $this->methods['calculateBchCode']->invoke(null, 0x13, 0x537));
// From http://www.swetake.com/qr/qr11.html
$this->assertEquals(0x214, $this->methods['calculateBchCode']->invoke(null, 0x1b, 0x537));
// Encoding of version information.
// From Appendix D in JISX0510:2004 (p 68)
$this->assertEquals(0xc94, $this->methods['calculateBchCode']->invoke(null, 7, 0x1f25));
$this->assertEquals(0x5bc, $this->methods['calculateBchCode']->invoke(null, 8, 0x1f25));
$this->assertEquals(0xa99, $this->methods['calculateBchCode']->invoke(null, 9, 0x1f25));
$this->assertEquals(0x4d3, $this->methods['calculateBchCode']->invoke(null, 10, 0x1f25));
$this->assertEquals(0x9a6, $this->methods['calculateBchCode']->invoke(null, 20, 0x1f25));
$this->assertEquals(0xd75, $this->methods['calculateBchCode']->invoke(null, 30, 0x1f25));
$this->assertEquals(0xc69, $this->methods['calculateBchCode']->invoke(null, 40, 0x1f25));
}
public function testMakeVersionInfoBits()
{
// From Appendix D in JISX0510:2004 (p 68)
$bits = new BitArray();
$this->methods['makeVersionInfoBits']->invoke(null, Version::getVersionForNumber(7), $bits);
$this->assertEquals(' ...XXXXX ..X..X.X ..', $bits->__toString());
}
public function testMakeTypeInfoBits()
{
// From Appendix D in JISX0510:2004 (p 68)
$bits = new BitArray();
$this->methods['makeTypeInfoBits']->invoke(null, new ErrorCorrectionLevel(ErrorCorrectionLevel::M), 5, $bits);
$this->assertEquals(' X......X X..XXX.', $bits->__toString());
}
}

View File

@@ -0,0 +1,99 @@
<?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\Encoder;
use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Renderer\Text\Html;
use BaconQrCode\Writer;
use PHPUnit_Framework_TestCase as TestCase;
class HtmlTest extends TestCase
{
/**
* @var Html
*/
protected $renderer;
/**
* @var Writer
*/
protected $writer;
public function setUp()
{
$this->renderer = new Html();
$this->writer = new Writer($this->renderer);
}
public function testBasicRender()
{
$content = 'foobar';
$expected =
'<pre style="font-family: monospace; line-height: 0.65em; letter-spacing: -1px" class="">' .
" \n" .
" ███████ █████ ███████ \n" .
" █ █ █ █ █ █ \n" .
" █ ███ █ ██ █ ███ █ \n" .
" █ ███ █ ███ █ ███ █ \n" .
" █ ███ █ █ █ █ ███ █ \n" .
" █ █ ██ █ █ \n" .
" ███████ █ █ █ ███████ \n" .
" █████ \n" .
" ██ ██ █ ██ █ █ █ \n" .
" ██ ██ █ █ ██ \n" .
" ████████ █ ██ █ ██ \n" .
" ██ █ █ \n" .
" ██ ███ █ █ █ █ \n" .
" █ ███ █ █ \n" .
" ███████ ██ ██████ \n" .
" █ █ ████ ██ \n" .
" █ ███ █ ██ ██ ██ █ ██ \n" .
" █ ███ █ ██ ██ █ ██ \n" .
" █ ███ █ █ █ ██ ██ \n" .
" █ █ ███ ███ ████ \n" .
" ███████ ████ ██ \n" .
" \n" .
'</pre>'
;
$qrCode = Encoder::encode(
$content,
new ErrorCorrectionLevel(ErrorCorrectionLevel::L),
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->assertEquals($expected, $this->renderer->render($qrCode));
}
public function testSetStyle()
{
$content = 'foobar';
$qrCode = Encoder::encode(
$content,
new ErrorCorrectionLevel(ErrorCorrectionLevel::L),
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->renderer->setStyle('bar');
$this->assertEquals('bar', $this->renderer->getStyle());
$this->assertStringMatchesFormat('%astyle="bar"%a', $this->renderer->render($qrCode));
}
public function testSetClass()
{
$content = 'foobar';
$qrCode = Encoder::encode(
$content,
new ErrorCorrectionLevel(ErrorCorrectionLevel::L),
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->renderer->setClass('bar');
$this->assertEquals('bar', $this->renderer->getClass());
$this->assertStringMatchesFormat('%aclass="bar"%a', $this->renderer->render($qrCode));
}
}

View File

@@ -0,0 +1,149 @@
<?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\Encoder;
use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Renderer\Text\Plain;
use BaconQrCode\Writer;
use PHPUnit_Framework_TestCase as TestCase;
class PlainTest extends TestCase
{
/**
* @var Plain
*/
protected $renderer;
/**
* @var Writer
*/
protected $writer;
public function setUp()
{
$this->renderer = new Plain();
$this->writer = new Writer($this->renderer);
}
public function testBasicRender()
{
$content = 'foobar';
$expected =
" \n" .
" ███████ █████ ███████ \n" .
" █ █ █ █ █ █ \n" .
" █ ███ █ ██ █ ███ █ \n" .
" █ ███ █ ███ █ ███ █ \n" .
" █ ███ █ █ █ █ ███ █ \n" .
" █ █ ██ █ █ \n" .
" ███████ █ █ █ ███████ \n" .
" █████ \n" .
" ██ ██ █ ██ █ █ █ \n" .
" ██ ██ █ █ ██ \n" .
" ████████ █ ██ █ ██ \n" .
" ██ █ █ \n" .
" ██ ███ █ █ █ █ \n" .
" █ ███ █ █ \n" .
" ███████ ██ ██████ \n" .
" █ █ ████ ██ \n" .
" █ ███ █ ██ ██ ██ █ ██ \n" .
" █ ███ █ ██ ██ █ ██ \n" .
" █ ███ █ █ █ ██ ██ \n" .
" █ █ ███ ███ ████ \n" .
" ███████ ████ ██ \n" .
" \n"
;
$qrCode = Encoder::encode(
$content,
new ErrorCorrectionLevel(ErrorCorrectionLevel::L),
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->assertEquals($expected, $this->renderer->render($qrCode));
}
public function testBasicRenderNoMargins()
{
$content = 'foobar';
$expected =
"███████ █████ ███████\n" .
"█ █ █ █ █ █\n" .
"█ ███ █ ██ █ ███ █\n" .
"█ ███ █ ███ █ ███ █\n" .
"█ ███ █ █ █ █ ███ █\n" .
"█ █ ██ █ █\n" .
"███████ █ █ █ ███████\n" .
" █████ \n" .
"██ ██ █ ██ █ █ █\n" .
" ██ ██ █ █ ██ \n" .
" ████████ █ ██ █ ██\n" .
" ██ █ █\n" .
" ██ ███ █ █ █ █\n" .
" █ ███ █ █ \n" .
"███████ ██ ██████ \n" .
"█ █ ████ ██ \n" .
"█ ███ █ ██ ██ ██ █ ██\n" .
"█ ███ █ ██ ██ █ ██ \n" .
"█ ███ █ █ █ ██ ██\n" .
"█ █ ███ ███ ████\n" .
"███████ ████ ██ \n"
;
$qrCode = Encoder::encode(
$content,
new ErrorCorrectionLevel(ErrorCorrectionLevel::L),
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->renderer->setMargin(0);
$this->assertEquals(0, $this->renderer->getMargin());
$this->assertEquals($expected, $this->renderer->render($qrCode));
}
public function testBasicRenderCustomChar()
{
$content = 'foobar';
$expected =
"-----------------------\n" .
"-#######-#####-#######-\n" .
"-#-----#--#-#--#-----#-\n" .
"-#-###-#--##---#-###-#-\n" .
"-#-###-#--###--#-###-#-\n" .
"-#-###-#---#-#-#-###-#-\n" .
"-#-----#----##-#-----#-\n" .
"-#######-#-#-#-#######-\n" .
"---------#####---------\n" .
"-##-##-#--##-#-#-----#-\n" .
"----##----##-#-#-##----\n" .
"--########-#--##-#--##-\n" .
"-----------##------#-#-\n" .
"--##--###--#---#--#--#-\n" .
"---------#-###----#-#--\n" .
"-#######--##-######----\n" .
"-#-----#---####---##---\n" .
"-#-###-#-##-##-##-#-##-\n" .
"-#-###-#-##-##--#-##---\n" .
"-#-###-#---#---#-##-##-\n" .
"-#-----#-###--###-####-\n" .
"-#######-####---##-----\n" .
"-----------------------\n"
;
$qrCode = Encoder::encode(
$content,
new ErrorCorrectionLevel(ErrorCorrectionLevel::L),
Encoder::DEFAULT_BYTE_MODE_ECODING
);
$this->renderer->setFullBlock('#');
$this->renderer->setEmptyBlock('-');
$this->assertEquals('#', $this->renderer->getFullBlock());
$this->assertEquals('-', $this->renderer->getEmptyBlock());
$this->assertEquals($expected, $this->renderer->render($qrCode));
}
}

View File

@@ -0,0 +1,10 @@
<?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
*/
require_once __DIR__ . '/../autoload_register.php';

11
vendor/bacon/bacon-qr-code/tests/phpunit.xml vendored Executable file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./bootstrap.php" colors="true">
<testsuite name="BaconQrCode">
<directory>.</directory>
</testsuite>
<filter>
<whitelist>
<directory suffix=".php">../src/</directory>
</whitelist>
</filter>
</phpunit>

481
vendor/composer/ClassLoader.php vendored Executable file
View File

@@ -0,0 +1,481 @@
<?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
{
private $vendorDir;
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
private static $registeredLoaders = array();
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
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 array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
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 array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
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 array|string $paths The PSR-0 base directories
*/
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 array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
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
*/
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
*/
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
*/
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
*/
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.
*/
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;
}
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.
*/
function includeFile($file)
{
include $file;
}

337
vendor/composer/InstalledVersions.php vendored Normal file
View File

@@ -0,0 +1,337 @@
<?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 it's presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
private static $installed;
private static $canGetVendors;
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, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
*/
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, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: 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, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: 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, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: 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
View 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.

69
vendor/composer/autoload_classmap.php vendored Executable file
View File

@@ -0,0 +1,69 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'QrReader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/QrReader.php',
'Zxing\\Binarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php',
'Zxing\\BinaryBitmap' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php',
'Zxing\\ChecksumException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php',
'Zxing\\Common\\BitArray' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php',
'Zxing\\Common\\BitMatrix' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php',
'Zxing\\Common\\BitSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php',
'Zxing\\Common\\CharacterSetECI' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php',
'Zxing\\Common\\CharacterSetEci\\AbstractEnum\\AbstractEnum' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php',
'Zxing\\Common\\DecoderResult' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php',
'Zxing\\Common\\DefaultGridSampler' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php',
'Zxing\\Common\\DetectorResult' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php',
'Zxing\\Common\\Detector\\MathUtils' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php',
'Zxing\\Common\\Detector\\MonochromeRectangleDetector' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MonochromeRectangleDetector.php',
'Zxing\\Common\\GlobalHistogramBinarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php',
'Zxing\\Common\\GridSampler' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php',
'Zxing\\Common\\HybridBinarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php',
'Zxing\\Common\\PerspectiveTransform' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php',
'Zxing\\Common\\Reedsolomon\\GenericGF' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php',
'Zxing\\Common\\Reedsolomon\\GenericGFPoly' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php',
'Zxing\\Common\\Reedsolomon\\ReedSolomonDecoder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php',
'Zxing\\Common\\Reedsolomon\\ReedSolomonException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php',
'Zxing\\FormatException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/FormatException.php',
'Zxing\\GDLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/GDLuminanceSource.php',
'Zxing\\IMagickLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php',
'Zxing\\LuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php',
'Zxing\\NotFoundException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php',
'Zxing\\PlanarYUVLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/PlanarYUVLuminanceSource.php',
'Zxing\\Qrcode\\Decoder\\BitMatrixParser' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php',
'Zxing\\Qrcode\\Decoder\\DataBlock' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php',
'Zxing\\Qrcode\\Decoder\\DataMask' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask000' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask001' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask010' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask011' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask100' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask101' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask110' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask111' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DecodedBitStreamParser' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php',
'Zxing\\Qrcode\\Decoder\\Decoder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php',
'Zxing\\Qrcode\\Decoder\\ECB' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
'Zxing\\Qrcode\\Decoder\\ECBlocks' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
'Zxing\\Qrcode\\Decoder\\ErrorCorrectionLevel' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php',
'Zxing\\Qrcode\\Decoder\\FormatInformation' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php',
'Zxing\\Qrcode\\Decoder\\Mode' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php',
'Zxing\\Qrcode\\Decoder\\Version' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
'Zxing\\Qrcode\\Detector\\AlignmentPattern' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php',
'Zxing\\Qrcode\\Detector\\AlignmentPatternFinder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php',
'Zxing\\Qrcode\\Detector\\Detector' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php',
'Zxing\\Qrcode\\Detector\\FinderPattern' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php',
'Zxing\\Qrcode\\Detector\\FinderPatternFinder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php',
'Zxing\\Qrcode\\Detector\\FinderPatternInfo' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php',
'Zxing\\Qrcode\\QRCodeReader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php',
'Zxing\\RGBLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php',
'Zxing\\Reader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Reader.php',
'Zxing\\ReaderException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ReaderException.php',
'Zxing\\Result' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Result.php',
'Zxing\\ResultPoint' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php',
);

12
vendor/composer/autoload_files.php vendored Executable file
View File

@@ -0,0 +1,12 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'626dcc41390ebdaa619faa02d99943b0' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php',
'3a37ebac017bc098e9a86b35401e7a68' => $vendorDir . '/mongodb/mongodb/src/functions.php',
);

11
vendor/composer/autoload_namespaces.php vendored Executable file
View File

@@ -0,0 +1,11 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'org\\bovigo\\vfs' => array($vendorDir . '/mikey179/vfsStream/src/main/php'),
'BaconQrCode' => array($vendorDir . '/bacon/bacon-qr-code/src'),
);

16
vendor/composer/autoload_psr4.php vendored Executable file
View File

@@ -0,0 +1,16 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Component\\PropertyAccess\\' => array($vendorDir . '/symfony/property-access'),
'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
'Picqer\\Barcode\\' => array($vendorDir . '/picqer/php-barcode-generator/src'),
'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'),
'MongoDB\\' => array($vendorDir . '/mongodb/mongodb/src'),
'Endroid\\QrCode\\' => array($vendorDir . '/endroid/qrcode/src'),
);

75
vendor/composer/autoload_real.php vendored Executable file
View File

@@ -0,0 +1,75 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit801fbe69b9c17eeb5f87ba0125931956
{
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('ComposerAutoloaderInit801fbe69b9c17eeb5f87ba0125931956', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit801fbe69b9c17eeb5f87ba0125931956', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire801fbe69b9c17eeb5f87ba0125931956($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire801fbe69b9c17eeb5f87ba0125931956($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

158
vendor/composer/autoload_static.php vendored Normal file
View File

@@ -0,0 +1,158 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'626dcc41390ebdaa619faa02d99943b0' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php',
'3a37ebac017bc098e9a86b35401e7a68' => __DIR__ . '/..' . '/mongodb/mongodb/src/functions.php',
);
public static $prefixLengthsPsr4 = array (
'S' =>
array (
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Component\\PropertyAccess\\' => 33,
'Symfony\\Component\\OptionsResolver\\' => 34,
),
'P' =>
array (
'Picqer\\Barcode\\' => 15,
),
'M' =>
array (
'MyCLabs\\Enum\\' => 13,
'MongoDB\\' => 8,
),
'E' =>
array (
'Endroid\\QrCode\\' => 15,
),
);
public static $prefixDirsPsr4 = array (
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Component\\PropertyAccess\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/property-access',
),
'Symfony\\Component\\OptionsResolver\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/options-resolver',
),
'Picqer\\Barcode\\' =>
array (
0 => __DIR__ . '/..' . '/picqer/php-barcode-generator/src',
),
'MyCLabs\\Enum\\' =>
array (
0 => __DIR__ . '/..' . '/myclabs/php-enum/src',
),
'MongoDB\\' =>
array (
0 => __DIR__ . '/..' . '/mongodb/mongodb/src',
),
'Endroid\\QrCode\\' =>
array (
0 => __DIR__ . '/..' . '/endroid/qrcode/src',
),
);
public static $prefixesPsr0 = array (
'o' =>
array (
'org\\bovigo\\vfs' =>
array (
0 => __DIR__ . '/..' . '/mikey179/vfsStream/src/main/php',
),
),
'B' =>
array (
'BaconQrCode' =>
array (
0 => __DIR__ . '/..' . '/bacon/bacon-qr-code/src',
),
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'QrReader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/QrReader.php',
'Zxing\\Binarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php',
'Zxing\\BinaryBitmap' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php',
'Zxing\\ChecksumException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php',
'Zxing\\Common\\BitArray' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php',
'Zxing\\Common\\BitMatrix' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php',
'Zxing\\Common\\BitSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php',
'Zxing\\Common\\CharacterSetECI' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php',
'Zxing\\Common\\CharacterSetEci\\AbstractEnum\\AbstractEnum' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php',
'Zxing\\Common\\DecoderResult' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php',
'Zxing\\Common\\DefaultGridSampler' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php',
'Zxing\\Common\\DetectorResult' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php',
'Zxing\\Common\\Detector\\MathUtils' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php',
'Zxing\\Common\\Detector\\MonochromeRectangleDetector' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MonochromeRectangleDetector.php',
'Zxing\\Common\\GlobalHistogramBinarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php',
'Zxing\\Common\\GridSampler' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php',
'Zxing\\Common\\HybridBinarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php',
'Zxing\\Common\\PerspectiveTransform' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php',
'Zxing\\Common\\Reedsolomon\\GenericGF' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php',
'Zxing\\Common\\Reedsolomon\\GenericGFPoly' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php',
'Zxing\\Common\\Reedsolomon\\ReedSolomonDecoder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php',
'Zxing\\Common\\Reedsolomon\\ReedSolomonException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php',
'Zxing\\FormatException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/FormatException.php',
'Zxing\\GDLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/GDLuminanceSource.php',
'Zxing\\IMagickLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php',
'Zxing\\LuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php',
'Zxing\\NotFoundException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php',
'Zxing\\PlanarYUVLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/PlanarYUVLuminanceSource.php',
'Zxing\\Qrcode\\Decoder\\BitMatrixParser' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php',
'Zxing\\Qrcode\\Decoder\\DataBlock' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php',
'Zxing\\Qrcode\\Decoder\\DataMask' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask000' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask001' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask010' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask011' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask100' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask101' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask110' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DataMask111' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
'Zxing\\Qrcode\\Decoder\\DecodedBitStreamParser' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php',
'Zxing\\Qrcode\\Decoder\\Decoder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php',
'Zxing\\Qrcode\\Decoder\\ECB' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
'Zxing\\Qrcode\\Decoder\\ECBlocks' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
'Zxing\\Qrcode\\Decoder\\ErrorCorrectionLevel' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php',
'Zxing\\Qrcode\\Decoder\\FormatInformation' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php',
'Zxing\\Qrcode\\Decoder\\Mode' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php',
'Zxing\\Qrcode\\Decoder\\Version' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
'Zxing\\Qrcode\\Detector\\AlignmentPattern' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php',
'Zxing\\Qrcode\\Detector\\AlignmentPatternFinder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php',
'Zxing\\Qrcode\\Detector\\Detector' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php',
'Zxing\\Qrcode\\Detector\\FinderPattern' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php',
'Zxing\\Qrcode\\Detector\\FinderPatternFinder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php',
'Zxing\\Qrcode\\Detector\\FinderPatternInfo' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php',
'Zxing\\Qrcode\\QRCodeReader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php',
'Zxing\\RGBLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php',
'Zxing\\Reader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Reader.php',
'Zxing\\ReaderException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ReaderException.php',
'Zxing\\Result' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Result.php',
'Zxing\\ResultPoint' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$prefixesPsr0;
$loader->classMap = ComposerStaticInit801fbe69b9c17eeb5f87ba0125931956::$classMap;
}, null, ClassLoader::class);
}
}

585
vendor/composer/installed.json vendored Executable file
View File

@@ -0,0 +1,585 @@
{
"packages": [
{
"name": "bacon/bacon-qr-code",
"version": "1.0.3",
"version_normalized": "1.0.3.0",
"source": {
"type": "git",
"url": "https://github.com/Bacon/BaconQrCode.git",
"reference": "5a91b62b9d37cee635bbf8d553f4546057250bee"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/5a91b62b9d37cee635bbf8d553f4546057250bee",
"reference": "5a91b62b9d37cee635bbf8d553f4546057250bee",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": "^5.4|^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8"
},
"suggest": {
"ext-gd": "to generate QR code images"
},
"time": "2017-10-17T09:59:25+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"BaconQrCode": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "http://www.dasprids.de",
"role": "Developer"
}
],
"description": "BaconQrCode is a QR code generator for PHP.",
"homepage": "https://github.com/Bacon/BaconQrCode",
"install-path": "../bacon/bacon-qr-code"
},
{
"name": "endroid/qrcode",
"version": "2.5.1",
"version_normalized": "2.5.1.0",
"source": {
"type": "git",
"url": "https://github.com/endroid/qr-code.git",
"reference": "6062677d3404e0ded40647b8f62ec55ff9722eb7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/endroid/qr-code/zipball/6062677d3404e0ded40647b8f62ec55ff9722eb7",
"reference": "6062677d3404e0ded40647b8f62ec55ff9722eb7",
"shasum": ""
},
"require": {
"bacon/bacon-qr-code": "^1.0.3",
"ext-gd": "*",
"khanamiryan/qrcode-detector-decoder": "1",
"myclabs/php-enum": "^1.5",
"php": ">=5.6",
"symfony/options-resolver": "^2.7",
"symfony/property-access": "^2.7"
},
"require-dev": {
"phpunit/phpunit": "^5.7",
"symfony/asset": "^2.7",
"symfony/browser-kit": "^2.7",
"symfony/finder": "^2.7",
"symfony/framework-bundle": "^2.7",
"symfony/http-kernel": "^2.7",
"symfony/templating": "^2.7",
"symfony/twig-bundle": "^2.7",
"symfony/yaml": "^2.7"
},
"time": "2018-05-09T20:26:30+00:00",
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "2.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",
"homepage": "http://endroid.nl/"
}
],
"description": "Endroid QR Code",
"homepage": "https://github.com/endroid/QrCode",
"keywords": [
"bundle",
"code",
"endroid",
"flex",
"qr",
"qrcode",
"symfony"
],
"abandoned": "endroid/qr-code",
"install-path": "../endroid/qrcode"
},
{
"name": "khanamiryan/qrcode-detector-decoder",
"version": "1",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/khanamiryan/php-qrcode-detector-decoder.git",
"reference": "96d5f80680b04803c4f1b69d6e01735e876b80c7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/khanamiryan/php-qrcode-detector-decoder/zipball/96d5f80680b04803c4f1b69d6e01735e876b80c7",
"reference": "96d5f80680b04803c4f1b69d6e01735e876b80c7",
"shasum": ""
},
"require": {
"php": "^5.6|^7.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7"
},
"time": "2017-01-13T09:11:46+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"lib/"
],
"files": [
"lib/common/customFunctions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ashot Khanamiryan",
"email": "a.khanamiryan@gmail.com",
"homepage": "https://github.com/khanamiryan",
"role": "Developer"
}
],
"description": "QR code decoder / reader",
"homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder",
"keywords": [
"barcode",
"qr",
"zxing"
],
"install-path": "../khanamiryan/qrcode-detector-decoder"
},
{
"name": "mikey179/vfsStream",
"version": "v1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/bovigo/vfsStream.git",
"reference": "fc0fe8f4d0b527254a2dc45f0c265567c881d07e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bovigo/vfsStream/zipball/fc0fe8f4d0b527254a2dc45f0c265567c881d07e",
"reference": "fc0fe8f4d0b527254a2dc45f0c265567c881d07e",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2012-08-25T12:49:29+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"org\\bovigo\\vfs": "src/main/php"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD"
],
"homepage": "http://vfs.bovigo.org/",
"install-path": "../mikey179/vfsStream"
},
{
"name": "mongodb/mongodb",
"version": "1.2.0",
"version_normalized": "1.2.0.0",
"source": {
"type": "git",
"url": "https://github.com/mongodb/mongo-php-library.git",
"reference": "5cffeb33b893b6bb04195b99ddc3955a29252339"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/5cffeb33b893b6bb04195b99ddc3955a29252339",
"reference": "5cffeb33b893b6bb04195b99ddc3955a29252339",
"shasum": ""
},
"require": {
"ext-hash": "*",
"ext-json": "*",
"ext-mongodb": "^1.3.0",
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "^4.8"
},
"time": "2017-10-27T19:42:57+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"MongoDB\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Jeremy Mikola",
"email": "jmikola@gmail.com"
},
{
"name": "Hannes Magnusson",
"email": "bjori@mongodb.com"
},
{
"name": "Derick Rethans",
"email": "github@derickrethans.nl"
}
],
"description": "MongoDB driver library",
"homepage": "https://jira.mongodb.org/browse/PHPLIB",
"keywords": [
"database",
"driver",
"mongodb",
"persistence"
],
"support": {
"issues": "https://github.com/mongodb/mongo-php-library/issues",
"source": "https://github.com/mongodb/mongo-php-library/tree/master"
},
"install-path": "../mongodb/mongodb"
},
{
"name": "myclabs/php-enum",
"version": "1.6.6",
"version_normalized": "1.6.6.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/php-enum.git",
"reference": "32c4202886c51fbe5cc3a7c34ec5c9a4a790345e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/32c4202886c51fbe5cc3a7c34ec5c9a4a790345e",
"reference": "32c4202886c51fbe5cc3a7c34ec5c9a4a790345e",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=5.4"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.7|^6.0",
"squizlabs/php_codesniffer": "1.*"
},
"time": "2019-02-04T21:18:49+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"MyCLabs\\Enum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP Enum contributors",
"homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
}
],
"description": "PHP Enum implementation",
"homepage": "http://github.com/myclabs/php-enum",
"keywords": [
"enum"
],
"install-path": "../myclabs/php-enum"
},
{
"name": "picqer/php-barcode-generator",
"version": "v0.3",
"version_normalized": "0.3.0.0",
"source": {
"type": "git",
"url": "https://github.com/picqer/php-barcode-generator.git",
"reference": "2e4d5b1f7f04fdb348d0721ada65963dac6f0c0c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/picqer/php-barcode-generator/zipball/2e4d5b1f7f04fdb348d0721ada65963dac6f0c0c",
"reference": "2e4d5b1f7f04fdb348d0721ada65963dac6f0c0c",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^5.3"
},
"time": "2019-01-12T09:29:34+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Picqer\\Barcode\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPLv3"
],
"authors": [
{
"name": "Nicola Asuni",
"email": "info@tecnick.com",
"homepage": "http://nicolaasuni.tecnick.com"
},
{
"name": "Casper Bakker",
"email": "info@picqer.com"
}
],
"description": "An easy to use, non-bloated, barcode generator in PHP. Creates SVG, PNG, JPG and HTML images from the most used 1D barcode standards.",
"homepage": "http://github.com/picqer/php-barcode-generator",
"keywords": [
"CODABAR",
"Code11",
"Code93",
"EAN13",
"KIX",
"KIXCODE",
"MSI",
"POSTNET",
"Pharma",
"Standard 2 of 5",
"barcode",
"barcode generator",
"code128",
"code39",
"ean",
"html",
"jpeg",
"jpg",
"php",
"png",
"svg",
"upc"
],
"install-path": "../picqer/php-barcode-generator"
},
{
"name": "symfony/options-resolver",
"version": "v2.8.49",
"version_normalized": "2.8.49.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "7aaab725bb58f0e18aa12c61bdadd4793ab4c32b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/7aaab725bb58f0e18aa12c61bdadd4793ab4c32b",
"reference": "7aaab725bb58f0e18aa12c61bdadd4793ab4c32b",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"time": "2018-11-11T11:18:13+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\OptionsResolver\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony OptionsResolver Component",
"homepage": "https://symfony.com",
"keywords": [
"config",
"configuration",
"options"
],
"install-path": "../symfony/options-resolver"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.11.0",
"version_normalized": "1.11.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "82ebae02209c21113908c229e9883c419720738a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a",
"reference": "82ebae02209c21113908c229e9883c419720738a",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"time": "2019-02-06T07:57:58+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.11-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
},
{
"name": "Gert de Pagter",
"email": "backendtea@gmail.com"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"install-path": "../symfony/polyfill-ctype"
},
{
"name": "symfony/property-access",
"version": "v2.8.49",
"version_normalized": "2.8.49.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/property-access.git",
"reference": "c8f10191183be9bb0d5a1b8364d3891f1bde07b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/property-access/zipball/c8f10191183be9bb0d5a1b8364d3891f1bde07b6",
"reference": "c8f10191183be9bb0d5a1b8364d3891f1bde07b6",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/polyfill-ctype": "~1.8"
},
"time": "2018-11-11T11:18:13+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\PropertyAccess\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony PropertyAccess Component",
"homepage": "https://symfony.com",
"keywords": [
"access",
"array",
"extraction",
"index",
"injection",
"object",
"property",
"property path",
"reflection"
],
"install-path": "../symfony/property-access"
}
],
"dev": true,
"dev-package-names": [
"mikey179/vfsstream"
]
}

113
vendor/composer/installed.php vendored Normal file
View File

@@ -0,0 +1,113 @@
<?php return array(
'root' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => NULL,
'name' => 'codeigniter/framework',
'dev' => true,
),
'versions' => array(
'bacon/bacon-qr-code' => array(
'pretty_version' => '1.0.3',
'version' => '1.0.3.0',
'type' => 'library',
'install_path' => __DIR__ . '/../bacon/bacon-qr-code',
'aliases' => array(),
'reference' => '5a91b62b9d37cee635bbf8d553f4546057250bee',
'dev_requirement' => false,
),
'codeigniter/framework' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => NULL,
'dev_requirement' => false,
),
'endroid/qrcode' => array(
'pretty_version' => '2.5.1',
'version' => '2.5.1.0',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../endroid/qrcode',
'aliases' => array(),
'reference' => '6062677d3404e0ded40647b8f62ec55ff9722eb7',
'dev_requirement' => false,
),
'khanamiryan/qrcode-detector-decoder' => array(
'pretty_version' => '1',
'version' => '1.0.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../khanamiryan/qrcode-detector-decoder',
'aliases' => array(),
'reference' => '96d5f80680b04803c4f1b69d6e01735e876b80c7',
'dev_requirement' => false,
),
'mikey179/vfsstream' => array(
'pretty_version' => 'v1.1.0',
'version' => '1.1.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../mikey179/vfsStream',
'aliases' => array(),
'reference' => 'fc0fe8f4d0b527254a2dc45f0c265567c881d07e',
'dev_requirement' => true,
),
'mongodb/mongodb' => array(
'pretty_version' => '1.2.0',
'version' => '1.2.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../mongodb/mongodb',
'aliases' => array(),
'reference' => '5cffeb33b893b6bb04195b99ddc3955a29252339',
'dev_requirement' => false,
),
'myclabs/php-enum' => array(
'pretty_version' => '1.6.6',
'version' => '1.6.6.0',
'type' => 'library',
'install_path' => __DIR__ . '/../myclabs/php-enum',
'aliases' => array(),
'reference' => '32c4202886c51fbe5cc3a7c34ec5c9a4a790345e',
'dev_requirement' => false,
),
'picqer/php-barcode-generator' => array(
'pretty_version' => 'v0.3',
'version' => '0.3.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../picqer/php-barcode-generator',
'aliases' => array(),
'reference' => '2e4d5b1f7f04fdb348d0721ada65963dac6f0c0c',
'dev_requirement' => false,
),
'symfony/options-resolver' => array(
'pretty_version' => 'v2.8.49',
'version' => '2.8.49.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/options-resolver',
'aliases' => array(),
'reference' => '7aaab725bb58f0e18aa12c61bdadd4793ab4c32b',
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.11.0',
'version' => '1.11.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'reference' => '82ebae02209c21113908c229e9883c419720738a',
'dev_requirement' => false,
),
'symfony/property-access' => array(
'pretty_version' => 'v2.8.49',
'version' => '2.8.49.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/property-access',
'aliases' => array(),
'reference' => 'c8f10191183be9bb0d5a1b8364d3891f1bde07b6',
'dev_requirement' => false,
),
),
);

26
vendor/composer/platform_check.php vendored Normal file
View File

@@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 50600)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.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
);
}

View File

@@ -0,0 +1,2 @@
/composer.lock
/vendor

View File

@@ -0,0 +1,37 @@
# QR code decoder / reader for PHP
This is a PHP library to detect and decode QR-codes.<br />This is first and only QR code reader that works without extensions.<br />
Ported from [ZXing library](https://github.com/zxing/zxing)
## Installation
The recommended method of installing this library is via [Composer](https://getcomposer.org/).
Run the following command from your project root:
```bash
$ composer require khanamiryan/qrcode-detector-decoder
```
## Usage
```php
require __DIR__ . "/vendor/autoload.php";
$qrcode = new QrReader('path/to_image');
$text = $qrcode->text(); //return decoded text from QR Code
```
## Requirements
* PHP >= 5.6
* GD Library
## Contributing
You can help the project by adding features, cleaning the code, adding composer and other.
1. Fork it
2. Create your feature branch: `git checkout -b my-new-feature`
3. Commit your changes: `git commit -am 'Add some feature'`
4. Push to the branch: `git push origin my-new-feature`
5. Submit a pull request

View File

@@ -0,0 +1,24 @@
{
"name": "khanamiryan/qrcode-detector-decoder",
"type": "library",
"description": "QR code decoder / reader",
"keywords": ["qr", "zxing", "barcode"],
"homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder",
"license": "MIT",
"authors": [{
"name": "Ashot Khanamiryan",
"email": "a.khanamiryan@gmail.com",
"homepage": "https://github.com/khanamiryan",
"role": "Developer"
}],
"require": {
"php": "^5.6|^7.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7"
},
"autoload": {
"classmap": ["lib/"],
"files": ["lib/common/customFunctions.php"]
}
}

View File

@@ -0,0 +1,89 @@
<?php
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
use Zxing\Common\BitArray;
use Zxing\Common\BitMatrix;
/**
* This class hierarchy provides a set of methods to convert luminance data to 1 bit data.
* It allows the algorithm to vary polymorphically, for example allowing a very expensive
* thresholding technique for servers and a fast one for mobile. It also permits the implementation
* to vary, e.g. a JNI version for Android and a Java fallback version for other platforms.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
abstract class Binarizer {
private $source;
protected function __construct($source) {
$this->source = $source;
}
public final function getLuminanceSource() {
return $this->source;
}
/**
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
* cached data. Callers should assume this method is expensive and call it as seldom as possible.
* This method is intended for decoding 1D barcodes and may choose to apply sharpening.
* For callers which only examine one row of pixels at a time, the same BitArray should be reused
* and passed in with each call for performance. However it is legal to keep more than one row
* at a time if needed.
*
* @param y The row to fetch, which must be in [0, bitmap height)
* @param row An optional preallocated array. If null or too small, it will be ignored.
* If used, the Binarizer will call BitArray.clear(). Always use the returned object.
* @return The array of bits for this row (true means black).
* @throws NotFoundException if row can't be binarized
*/
public abstract function getBlackRow($y, $row);
/**
* Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
* may not apply sharpening. Therefore, a row from this matrix may not be identical to one
* fetched using getBlackRow(), so don't mix and match between them.
*
* @return The 2D array of bits for the image (true means black).
* @throws NotFoundException if image can't be binarized to make a matrix
*/
public abstract function getBlackMatrix();
/**
* Creates a new object with the same type as this Binarizer implementation, but with pristine
* state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
* of 1 bit data. See Effective Java for why we can't use Java's clone() method.
*
* @param source The LuminanceSource this Binarizer will operate on.
* @return A new concrete Binarizer implementation object.
*/
public abstract function createBinarizer($source);
public final function getWidth() {
return $this->source->getWidth();
}
public final function getHeight() {
return $this->source->getHeight();
}
}

View File

@@ -0,0 +1,152 @@
<?php
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
use Zxing\Common\BitArray;
use Zxing\Common\BitMatrix;
/**
* This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects
* accept a BinaryBitmap and attempt to decode it.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
final class BinaryBitmap {
private $binarizer;
private $matrix;
public function __construct($binarizer) {
if ($binarizer == null) {
throw new \InvalidArgumentException("Binarizer must be non-null.");
}
$this->binarizer = $binarizer;
}
/**
* @return The width of the bitmap.
*/
public function getWidth() {
return $this->binarizer->getWidth();
}
/**
* @return The height of the bitmap.
*/
public function getHeight() {
return $this->binarizer->getHeight();
}
/**
* Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
* cached data. Callers should assume this method is expensive and call it as seldom as possible.
* This method is intended for decoding 1D barcodes and may choose to apply sharpening.
*
* @param y The row to fetch, which must be in [0, bitmap height)
* @param row An optional preallocated array. If null or too small, it will be ignored.
* If used, the Binarizer will call BitArray.clear(). Always use the returned object.
* @return The array of bits for this row (true means black).
* @throws NotFoundException if row can't be binarized
*/
public function getBlackRow($y, $row) {
return $this->binarizer->getBlackRow($y, $row);
}
/**
* Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
* may not apply sharpening. Therefore, a row from this matrix may not be identical to one
* fetched using getBlackRow(), so don't mix and match between them.
*
* @return The 2D array of bits for the image (true means black).
* @throws NotFoundException if image can't be binarized to make a matrix
*/
public function getBlackMatrix(){
// The matrix is created on demand the first time it is requested, then cached. There are two
// reasons for this:
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
// 1D Reader finds a barcode before the 2D Readers run.
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
if ($this->matrix == null) {
$this->matrix = $this->binarizer->getBlackMatrix();
}
return $this->matrix;
}
/**
* @return Whether this bitmap can be cropped.
*/
public function isCropSupported() {
return $this->binarizer->getLuminanceSource()->isCropSupported();
}
/**
* Returns a new object with cropped image data. Implementations may keep a reference to the
* original data rather than a copy. Only callable if isCropSupported() is true.
*
* @param left The left coordinate, which must be in [0,getWidth())
* @param top The top coordinate, which must be in [0,getHeight())
* @param width The width of the rectangle to crop.
* @param height The height of the rectangle to crop.
* @return A cropped version of this object.
*/
public function crop($left, $top, $width, $height) {
$newSource = $this->binarizer->getLuminanceSource()->crop($left, $top, $width, $height);
return new BinaryBitmap($this->binarizer->createBinarizer($newSource));
}
/**
* @return Whether this bitmap supports counter-clockwise rotation.
*/
public function isRotateSupported() {
return $this->binarizer->getLuminanceSource()->isRotateSupported();
}
/**
* Returns a new object with rotated image data by 90 degrees counterclockwise.
* Only callable if {@link #isRotateSupported()} is true.
*
* @return A rotated version of this object.
*/
public function rotateCounterClockwise() {
$newSource = $this->binarizer->getLuminanceSource()->rotateCounterClockwise();
return new BinaryBitmap($this->binarizer->createBinarizer($newSource));
}
/**
* Returns a new object with rotated image data by 45 degrees counterclockwise.
* Only callable if {@link #isRotateSupported()} is true.
*
* @return A rotated version of this object.
*/
public function rotateCounterClockwise45() {
$newSource = $this->binarizer->getLuminanceSource()->rotateCounterClockwise45();
return new BinaryBitmap($this->binarizer->createBinarizer($newSource));
}
//@Override
public function toString() {
try {
return $this->getBlackMatrix()->toString();
} catch (NotFoundException $e) {
return "";
}
}
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
/**
* Thrown when a barcode was successfully detected and decoded, but
* was not returned because its checksum feature failed.
*
* @author Sean Owen
*/
final class ChecksumException extends ReaderException {
private static $instance;
public static function getChecksumInstance($cause=null) {
if (self::$isStackTrace) {
return new ChecksumException($cause);
} else {
if(!self::$instance){
self::$instance = new ChecksumException($cause);
}
return self::$instance;
}
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
/**
* Thrown when a barcode was successfully detected, but some aspect of
* the content did not conform to the barcode's format rules. This could have
* been due to a mis-detection.
*
* @author Sean Owen
*/
final class FormatException extends ReaderException {
private static $instance;
public function __construct($cause=null) {
if($cause){
parent::__construct($cause);
}
}
public static function getFormatInstance($cause=null) {
if(!self::$instance){
self::$instance = new FormatException();
}
if (self::$isStackTrace) {
return new FormatException($cause);
} else {
return self::$instance;
}
}
}

View File

@@ -0,0 +1,173 @@
<?php
namespace Zxing;
/**
* This class is used to help decode images from files which arrive as GD Resource
* It does not support rotation.
*
*
*
*/
final class GDLuminanceSource extends LuminanceSource {
public $luminances;
private $dataWidth;
private $dataHeight;
private $left;
private $top;
private $gdImage;
public function __construct($gdImage,
$dataWidth,
$dataHeight,
$left=null,
$top=null,
$width=null,
$height=null) {
if(!$left&&!$top&&!$width&&!$height){
$this->GDLuminanceSource($gdImage,$dataWidth,$dataHeight);
return;
}
parent::__construct($width, $height);
if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
throw new \InvalidArgumentException("Crop rectangle does not fit within image data.");
}
$this->luminances = $gdImage;
$this->dataWidth = $dataWidth;
$this->dataHeight = $dataHeight;
$this->left = $left;
$this->top = $top;
}
public function GDLuminanceSource($gdImage, $width, $height)
{
parent::__construct($width, $height);
$this->dataWidth = $width;
$this->dataHeight = $height;
$this->left = 0;
$this->top = 0;
$this->$gdImage = $gdImage;
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
$this->luminances = array();
//$this->luminances = $this->grayScaleToBitmap($this->grayscale());
$array = array();
$rgb = array();
for($j=0;$j<$height;$j++){
for($i=0;$i<$width;$i++){
$argb = imagecolorat($this->$gdImage, $i, $j);
$pixel = imagecolorsforindex($this->$gdImage, $argb);
$r = $pixel['red'];
$g = $pixel['green'];
$b = $pixel['blue'];
if ($r == $g && $g == $b) {
// Image is already greyscale, so pick any channel.
$this->luminances[] = $r;//(($r + 128) % 256) - 128;
} else {
// Calculate luminance cheaply, favoring green.
$this->luminances[] = ($r+2*$g+$b)/4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128;
}
}
}
/*
for ($y = 0; $y < $height; $y++) {
$offset = $y * $width;
for ($x = 0; $x < $width; $x++) {
$pixel = $pixels[$offset + $x];
$r = ($pixel >> 16) & 0xff;
$g = ($pixel >> 8) & 0xff;
$b = $pixel & 0xff;
if ($r == $g && $g == $b) {
// Image is already greyscale, so pick any channel.
$this->luminances[intval($offset + $x)] = (($r+128) % 256) - 128;
} else {
// Calculate luminance cheaply, favoring green.
$this->luminances[intval($offset + $x)] = (((($r + 2 * $g + $b) / 4)+128)%256) - 128;
}
}
*/
//}
// $this->luminances = $this->grayScaleToBitmap($this->luminances);
}
//@Override
public function getRow($y, $row=null) {
if ($y < 0 || $y >= $this->getHeight()) {
throw new \InvalidArgumentException("Requested row is outside the image: " + y);
}
$width = $this->getWidth();
if ($row == null || count($row) < $width) {
$row = array();
}
$offset = ($y + $this->top) * $this->dataWidth + $this->left;
$row = arraycopy($this->luminances,$offset, $row, 0, $width);
return $row;
}
//@Override
public function getMatrix() {
$width = $this->getWidth();
$height = $this->getHeight();
// If the caller asks for the entire underlying image, save the copy and give them the
// original data. The docs specifically warn that result.length must be ignored.
if ($width == $this->dataWidth && $height == $this->dataHeight) {
return $this->luminances;
}
$area = $width * $height;
$matrix = array();
$inputOffset = $this->top * $this->dataWidth + $this->left;
// If the width matches the full width of the underlying data, perform a single copy.
if ($width == $this->dataWidth) {
$matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area);
return $matrix;
}
// Otherwise copy one cropped row at a time.
$rgb = $this->luminances;
for ($y = 0; $y < $height; $y++) {
$outputOffset = $y * $width;
$matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width);
$inputOffset += $this->dataWidth;
}
return $matrix;
}
//@Override
public function isCropSupported() {
return true;
}
//@Override
public function crop($left, $top, $width, $height) {
return new GDLuminanceSource($this->luminances,
$this->dataWidth,
$this->dataHeight,
$this->left + $left,
$this->top + $top,
$width,
$height);
}
}

View File

@@ -0,0 +1,149 @@
<?php
namespace Zxing;
/**
* This class is used to help decode images from files which arrive as GD Resource
* It does not support rotation.
*
*
*
*/
final class IMagickLuminanceSource extends LuminanceSource {
public $luminances;
private $dataWidth;
private $dataHeight;
private $left;
private $top;
private $image;
public function __construct($image,
$dataWidth,
$dataHeight,
$left=null,
$top=null,
$width=null,
$height=null) {
if(!$left&&!$top&&!$width&&!$height){
$this->_IMagickLuminanceSource($image,$dataWidth,$dataHeight);
return;
}
parent::__construct($width, $height);
if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
throw new \InvalidArgumentException("Crop rectangle does not fit within image data.");
}
$this->luminances = $image;
$this->dataWidth = $dataWidth;
$this->dataHeight = $dataHeight;
$this->left = $left;
$this->top = $top;
}
public function _IMagickLuminanceSource($image, $width, $height)
{
parent::__construct($width, $height);
$this->dataWidth = $width;
$this->dataHeight = $height;
$this->left = 0;
$this->top = 0;
$this->image = $image;
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
$this->luminances = array();
$image->setImageColorspace (\Imagick::COLORSPACE_GRAY);
// $image->newPseudoImage(0, 0, "magick:rose");
$pixels = $image->exportImagePixels(1, 1, $width, $height, "RGB", \Imagick::COLORSPACE_RGB);
$array = array();
$rgb = array();
for($i=0;$i<count($pixels);$i+=3){
$r = $pixels[$i]& 0xff;
$g = $pixels[$i+1]& 0xff;
$b = $pixels[$i+2]& 0xff;
if ($r == $g && $g == $b) {
// Image is already greyscale, so pick any channel.
$this->luminances[] = $r;//(($r + 128) % 256) - 128;
} else {
// Calculate luminance cheaply, favoring green.
$this->luminances[] = ($r+2*$g+$b)/4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128;
}
}
}
//@Override
public function getRow($y, $row=null) {
if ($y < 0 || $y >= $this->getHeight()) {
throw new \InvalidArgumentException("Requested row is outside the image: " + y);
}
$width = $this->getWidth();
if ($row == null || count($row) < $width) {
$row = array();
}
$offset = ($y + $this->top) * $this->dataWidth + $this->left;
$row = arraycopy($this->luminances,$offset, $row, 0, $width);
return $row;
}
//@Override
public function getMatrix() {
$width = $this->getWidth();
$height = $this->getHeight();
// If the caller asks for the entire underlying image, save the copy and give them the
// original data. The docs specifically warn that result.length must be ignored.
if ($width == $this->dataWidth && $height == $this->dataHeight) {
return $this->luminances;
}
$area = $width * $height;
$matrix = array();
$inputOffset = $this->top * $this->dataWidth + $this->left;
// If the width matches the full width of the underlying data, perform a single copy.
if ($width == $this->dataWidth) {
$matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area);
return $matrix;
}
// Otherwise copy one cropped row at a time.
$rgb = $this->luminances;
for ($y = 0; $y < $height; $y++) {
$outputOffset = $y * $width;
$matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width);
$inputOffset += $this->dataWidth;
}
return $matrix;
}
//@Override
public function isCropSupported() {
return true;
}
//@Override
public function crop($left, $top, $width, $height) {
return new GDLuminanceSource($this->luminances,
$this->dataWidth,
$this->dataHeight,
$this->left + $left,
$this->top + $top,
$width,
$height);
}
}

View File

@@ -0,0 +1,159 @@
<?php
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
/**
* The purpose of this class hierarchy is to abstract different bitmap implementations across
* platforms into a standard interface for requesting greyscale luminance values. The interface
* only provides immutable methods; therefore crop and rotation create copies. This is to ensure
* that one Reader does not modify the original luminance source and leave it in an unknown state
* for other Readers in the chain.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
abstract class LuminanceSource {
private $width;
private $height;
function __construct($width, $height) {
$this->width = $width;
$this->height = $height;
}
/**
* Fetches one row of luminance data from the underlying platform's bitmap. Values range from
* 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
* to bitwise and with 0xff for each value. It is preferable for implementations of this method
* to only fetch this row rather than the whole image, since no 2D Readers may be installed and
* getMatrix() may never be called.
*
* @param $y; The row to fetch, which must be in [0,getHeight())
* @param $row; An optional preallocated array. If null or too small, it will be ignored.
* Always use the returned object, and ignore the .length of the array.
* @return array
* An array containing the luminance data.
*/
public abstract function getRow($y, $row);
/**
* Fetches luminance data for the underlying bitmap. Values should be fetched using:
* {@code int luminance = array[y * width + x] & 0xff}
*
* @return A row-major 2D array of luminance values. Do not use result.length as it may be
* larger than width * height bytes on some platforms. Do not modify the contents
* of the result.
*/
public abstract function getMatrix();
/**
* @return The width of the bitmap.
*/
public final function getWidth() {
return $this->width;
}
/**
* @return The height of the bitmap.
*/
public final function getHeight() {
return $this->height;
}
/**
* @return Whether this subclass supports cropping.
*/
public function isCropSupported() {
return false;
}
/**
* Returns a new object with cropped image data. Implementations may keep a reference to the
* original data rather than a copy. Only callable if isCropSupported() is true.
*
* @param left The left coordinate, which must be in [0,getWidth())
* @param top The top coordinate, which must be in [0,getHeight())
* @param width The width of the rectangle to crop.
* @param height The height of the rectangle to crop.
* @return A cropped version of this object.
*/
public function crop($left, $top, $width, $height) {
throw new \Exception("This luminance source does not support cropping.");
}
/**
* @return Whether this subclass supports counter-clockwise rotation.
*/
public function isRotateSupported() {
return false;
}
/**
* @return a wrapper of this {@code LuminanceSource} which inverts the luminances it returns -- black becomes
* white and vice versa, and each value becomes (255-value).
*/
public function invert() {
return new InvertedLuminanceSource($this);
}
/**
* Returns a new object with rotated image data by 90 degrees counterclockwise.
* Only callable if {@link #isRotateSupported()} is true.
*
* @return A rotated version of this object.
*/
public function rotateCounterClockwise() {
throw new \Exception("This luminance source does not support rotation by 90 degrees.");
}
/**
* Returns a new object with rotated image data by 45 degrees counterclockwise.
* Only callable if {@link #isRotateSupported()} is true.
*
* @return A rotated version of this object.
*/
public function rotateCounterClockwise45() {
throw new \Exception("This luminance source does not support rotation by 45 degrees.");
}
//@Override
public final function toString() {
$row = array();
$result = '';
for ($y = 0;$y < $this->height; $y++) {
$row = $this->getRow($y, $row);
for ($x = 0; $x < $this->width; $x++) {
$luminance = $row[$x] & 0xFF;
$c='';
if ($luminance < 0x40) {
$c = '#';
} else if ($luminance < 0x80) {
$c = '+';
} else if ($luminance < 0xC0) {
$c = '.';
} else {
$c = ' ';
}
$result.=($c);
}
$result.=('\n');
}
return $result;
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
/**
* Thrown when a barcode was not found in the image. It might have been
* partially detected but could not be confirmed.
*
* @author Sean Owen
*/
final class NotFoundException extends ReaderException {
private static $instance;
public static function getNotFoundInstance() {
if(!self::$instance ){
self::$instance = new NotFoundException();
}
return self::$instance;
}
}

View File

@@ -0,0 +1,172 @@
<?php
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
/**
* This object extends LuminanceSource around an array of YUV data returned from the camera driver,
* with the option to crop to a rectangle within the full data. This can be used to exclude
* superfluous pixels around the perimeter and speed up decoding.
*
* It works for any pixel format where the Y channel is planar and appears first, including
* YCbCr_420_SP and YCbCr_422_SP.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
final class PlanarYUVLuminanceSource extends LuminanceSource {
private static $THUMBNAIL_SCALE_FACTOR = 2;
private $yuvData;
private $dataWidth;
private $dataHeight;
private $left;
private $top;
public function __construct($yuvData,
$dataWidth,
$dataHeight,
$left,
$top,
$width,
$height,
$reverseHorizontal) {
parent::__construct($width, $height);
if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
$this->yuvData = $yuvData;
$this->dataWidth = $dataWidth;
$this->dataHeight = $dataHeight;
$this->left = $left;
$this->top = $top;
if ($reverseHorizontal) {
$this->reverseHorizontal($width, $height);
}
}
//@Override
public function getRow($y, $row=null) {
if ($y < 0 || $y >= getHeight()) {
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
$width = $this->getWidth();
if ($row == null || count($row) < $width) {
$row = array();//new byte[width];
}
$offset = ($y + $this->top) * $this->dataWidth + $this->left;
$row = arraycopy($this->yuvData, $offset, $row, 0, $width);
return $row;
}
//@Override
public function getMatrix() {
$width = $this->getWidth();
$height = $this->getHeight();
// If the caller asks for the entire underlying image, save the copy and give them the
// original data. The docs specifically warn that result.length must be ignored.
if ($width == $this->dataWidth && $height == $this->dataHeight) {
return $this->yuvData;
}
$area = $width * $height;
$matrix = array();//new byte[area];
$inputOffset = $this->top * $this->dataWidth + $this->left;
// If the width matches the full width of the underlying data, perform a single copy.
if ($width == $this->dataWidth) {
$matrix = arraycopy($this->yuvData, $inputOffset, $matrix, 0, $area);
return $matrix;
}
// Otherwise copy one cropped row at a time.
$yuv = $this->yuvData;
for ($y = 0; $y < $height; $y++) {
$outputOffset = $y * $width;
$matrix = arraycopy($this->yuvData, $inputOffset, $matrix, $outputOffset, $width);
$inputOffset += $this->dataWidth;
}
return $matrix;
}
// @Override
public function isCropSupported() {
return true;
}
// @Override
public function crop($left, $top, $width, $height) {
return new PlanarYUVLuminanceSource($this->yuvData,
$this->dataWidth,
$this->dataHeight,
$this->left + $left,
$this->top + $top,
$width,
$height,
false);
}
public function renderThumbnail() {
$width = intval($this->getWidth() / self::$THUMBNAIL_SCALE_FACTOR);
$height = intval($this->getHeight() / self::$THUMBNAIL_SCALE_FACTOR);
$pixels = array();//new int[width * height];
$yuv = $this->yuvData;
$inputOffset = $this->top * $this->dataWidth + $this->left;
for ($y = 0; $y < $height; $y++) {
$outputOffset = $y * $width;
for ($x = 0; $x < $width; $x++) {
$grey = intval32bits($yuv[$inputOffset + $x * self::$THUMBNAIL_SCALE_FACTOR] & 0xff);
$pixels[$outputOffset + $x] = intval32bits(0xFF000000 | ($grey * 0x00010101));
}
$inputOffset += $this->dataWidth * self::$THUMBNAIL_SCALE_FACTOR;
}
return $pixels;
}
/**
* @return width of image from {@link #renderThumbnail()}
*/
/*
public int getThumbnailWidth() {
return getWidth() / THUMBNAIL_SCALE_FACTOR;
}*/
/**
* @return height of image from {@link #renderThumbnail()}
*/
/*
public int getThumbnailHeight() {
return getHeight() / THUMBNAIL_SCALE_FACTOR;
}
private void reverseHorizontal(int width, int height) {
byte[] yuvData = this.yuvData;
for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth) {
int middle = rowStart + width / 2;
for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) {
byte temp = yuvData[x1];
yuvData[x1] = yuvData[x2];
yuvData[x2] = temp;
}
}
}
*/
}

View File

@@ -0,0 +1,84 @@
<?php
final class QrReader
{
const SOURCE_TYPE_FILE = 'file';
const SOURCE_TYPE_BLOB = 'blob';
const SOURCE_TYPE_RESOURCE = 'resource';
public $result;
function __construct($imgsource, $sourcetype = QrReader::SOURCE_TYPE_FILE, $isUseImagickIfAvailable = true)
{
try {
switch($sourcetype) {
case QrReader::SOURCE_TYPE_FILE:
if($isUseImagickIfAvailable && extension_loaded('imagick')) {
$im = new Imagick();
$im->readImage($imgsource);
}else {
$image = file_get_contents($imgsource);
$im = imagecreatefromstring($image);
}
break;
case QrReader::SOURCE_TYPE_BLOB:
if($isUseImagickIfAvailable && extension_loaded('imagick')) {
$im = new Imagick();
$im->readimageblob($imgsource);
}else {
$im = imagecreatefromstring($imgsource);
}
break;
case QrReader::SOURCE_TYPE_RESOURCE:
$im = $imgsource;
if($isUseImagickIfAvailable && extension_loaded('imagick')) {
$isUseImagickIfAvailable = true;
}else {
$isUseImagickIfAvailable = false;
}
break;
}
if($isUseImagickIfAvailable && extension_loaded('imagick')) {
$width = $im->getImageWidth();
$height = $im->getImageHeight();
$source = new \Zxing\IMagickLuminanceSource($im, $width, $height);
}else {
$width = imagesx($im);
$height = imagesy($im);
$source = new \Zxing\GDLuminanceSource($im, $width, $height);
}
$histo = new \Zxing\Common\HybridBinarizer($source);
$bitmap = new \Zxing\BinaryBitmap($histo);
$reader = new \Zxing\Qrcode\QRCodeReader();
$this->result = $reader->decode($bitmap);
}catch (\Zxing\NotFoundException $er){
$this->result = false;
}catch( \Zxing\FormatException $er){
$this->result = false;
}catch( \Zxing\ChecksumException $er){
$this->result = false;
}
}
public function text()
{
if(method_exists($this->result,'toString')) {
return ($this->result->toString());
}else{
return $this->result;
}
}
public function decode()
{
return $this->text();
}
}

View File

@@ -0,0 +1,310 @@
<?php
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
/**
* This class is used to help decode images from files which arrive as RGB data from
* an ARGB pixel array. It does not support rotation.
*
* @author dswitkin@google.com (Daniel Switkin)
* @author Betaminos
*/
final class RGBLuminanceSource extends LuminanceSource {
public $luminances;
private $dataWidth;
private $dataHeight;
private $left;
private $top;
private $pixels;
public function __construct($pixels,
$dataWidth,
$dataHeight,
$left=null,
$top=null,
$width=null,
$height=null) {
if(!$left&&!$top&&!$width&&!$height){
$this->RGBLuminanceSource_($pixels,$dataWidth,$dataHeight);
return;
}
parent::__construct($width, $height);
if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
throw new \InvalidArgumentException("Crop rectangle does not fit within image data.");
}
$this->luminances = $pixels;
$this->dataWidth = $dataWidth;
$this->dataHeight = $dataHeight;
$this->left = $left;
$this->top = $top;
}
public function RGBLuminanceSource_($width, $height, $pixels)
{
parent::__construct($width, $height);
$this->dataWidth = $width;
$this->dataHeight = $height;
$this->left = 0;
$this->top = 0;
$this->pixels = $pixels;
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
// up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
$this->luminances = array();
//$this->luminances = $this->grayScaleToBitmap($this->grayscale());
foreach ($pixels as $key => $pixel) {
$r = $pixel['red'];
$g = $pixel['green'];
$b = $pixel['blue'];
/* if (($pixel & 0xFF000000) == 0) {
$pixel = 0xFFFFFFFF; // = white
}
// .229R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC)
$this->luminances[$key] =
(306 * (($pixel >> 16) & 0xFF) +
601 * (($pixel >> 8) & 0xFF) +
117 * ($pixel & 0xFF) +
0x200) >> 10;
*/
//$r = ($pixel >> 16) & 0xff;
//$g = ($pixel >> 8) & 0xff;
//$b = $pixel & 0xff;
if ($r == $g && $g == $b) {
// Image is already greyscale, so pick any channel.
$this->luminances[$key] = $r;//(($r + 128) % 256) - 128;
} else {
// Calculate luminance cheaply, favoring green.
$this->luminances[$key] = ($r+2*$g+$b)/4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128;
}
}
/*
for ($y = 0; $y < $height; $y++) {
$offset = $y * $width;
for ($x = 0; $x < $width; $x++) {
$pixel = $pixels[$offset + $x];
$r = ($pixel >> 16) & 0xff;
$g = ($pixel >> 8) & 0xff;
$b = $pixel & 0xff;
if ($r == $g && $g == $b) {
// Image is already greyscale, so pick any channel.
$this->luminances[intval($offset + $x)] = (($r+128) % 256) - 128;
} else {
// Calculate luminance cheaply, favoring green.
$this->luminances[intval($offset + $x)] = (((($r + 2 * $g + $b) / 4)+128)%256) - 128;
}
}
*/
//}
// $this->luminances = $this->grayScaleToBitmap($this->luminances);
}
function grayscale(){
$width = $this->dataWidth;
$height = $this->dataHeight;
$ret = fill_array(0, $width*$height,0);
for ($y = 0; $y < $height; $y++)
{
for ($x = 0; $x < $width; $x++)
{
$gray = $this->getPixel($x, $y,$width,$height);
$ret[$x+$y*$width] = $gray;
}
}
return $ret;
}
function getPixel($x,$y,$width,$height){
$image = $this->pixels;
if ($width < $x) {
die('error');
}
if ($height < $y) {
die('error');
}
$point = ($x) + ($y * $width);
$r = $image[$point]['red'];//($image[$point] >> 16) & 0xff;
$g = $image[$point]['green'];//($image[$point] >> 8) & 0xff;
$b = $image[$point]['blue'];//$image[$point] & 0xff;
$p = intval(($r*33 +$g*34 + $b*33)/100);
return $p;
}
function getMiddleBrightnessPerArea($image)
{
$numSqrtArea = 4;
//obtain middle brightness((min + max) / 2) per area
$areaWidth = floor($this->dataWidth / $numSqrtArea);
$areaHeight = floor($this->dataHeight / $numSqrtArea);
$minmax = fill_array(0,$numSqrtArea,0);
for ($i = 0; $i < $numSqrtArea; $i++)
{
$minmax[$i] = fill_array(0,$numSqrtArea,0);
for ($i2 = 0; $i2 < $numSqrtArea; $i2++)
{
$minmax[$i][$i2] = array(0,0);
}
}
for ($ay = 0; $ay < $numSqrtArea; $ay++)
{
for ($ax = 0; $ax < $numSqrtArea; $ax++)
{
$minmax[$ax][$ay][0] = 0xFF;
for ($dy = 0; $dy < $areaHeight; $dy++)
{
for ($dx = 0; $dx < $areaWidth; $dx++)
{
$target = $image[intval($areaWidth * $ax + $dx+($areaHeight * $ay + $dy)*$this->dataWidth)];
if ($target < $minmax[$ax][$ay][0])
$minmax[$ax][$ay][0] = $target;
if ($target > $minmax[$ax][$ay][1])
$minmax[$ax][$ay][1] = $target;
}
}
//minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2;
}
}
$middle = array();
for ($i3 = 0; $i3 < $numSqrtArea; $i3++)
{
$middle[$i3] = array();
}
for ($ay = 0; $ay < $numSqrtArea; $ay++)
{
for ($ax = 0; $ax < $numSqrtArea; $ax++)
{
$middle[$ax][$ay] = floor(($minmax[$ax][$ay][0] + $minmax[$ax][$ay][1]) / 2);
//Console.out.print(middle[ax][ay] + ",");
}
//Console.out.println("");
}
//Console.out.println("");
return $middle;
}
function grayScaleToBitmap ($grayScale)
{
$middle = $this->getMiddleBrightnessPerArea($grayScale);
$sqrtNumArea = count($middle);
$areaWidth = floor($this->dataWidth/ $sqrtNumArea);
$areaHeight = floor($this->dataHeight / $sqrtNumArea);
$bitmap = fill_array(0,$this->dataWidth*$this->dataHeight,0);
for ($ay = 0; $ay < $sqrtNumArea; $ay++)
{
for ($ax = 0; $ax < $sqrtNumArea; $ax++)
{
for ($dy = 0; $dy < $areaHeight; $dy++)
{
for ($dx = 0; $dx < $areaWidth; $dx++)
{
$bitmap[intval($areaWidth * $ax + $dx+ ($areaHeight * $ay + $dy)*$this->dataWidth)] = ($grayScale[intval($areaWidth * $ax + $dx+ ($areaHeight * $ay + $dy)*$this->dataWidth)] < $middle[$ax][$ay])?0:255;
}
}
}
}
return $bitmap;
}
//@Override
public function getRow($y, $row=null) {
if ($y < 0 || $y >= $this->getHeight()) {
throw new \InvalidArgumentException("Requested row is outside the image: " + y);
}
$width = $this->getWidth();
if ($row == null || count($row) < $width) {
$row = array();
}
$offset = ($y + $this->top) * $this->dataWidth + $this->left;
$row = arraycopy($this->luminances,$offset, $row, 0, $width);
return $row;
}
//@Override
public function getMatrix() {
$width = $this->getWidth();
$height = $this->getHeight();
// If the caller asks for the entire underlying image, save the copy and give them the
// original data. The docs specifically warn that result.length must be ignored.
if ($width == $this->dataWidth && $height == $this->dataHeight) {
return $this->luminances;
}
$area = $width * $height;
$matrix = array();
$inputOffset = $this->top * $this->dataWidth + $this->left;
// If the width matches the full width of the underlying data, perform a single copy.
if ($width == $this->dataWidth) {
$matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area);
return $matrix;
}
// Otherwise copy one cropped row at a time.
$rgb = $this->luminances;
for ($y = 0; $y < $height; $y++) {
$outputOffset = $y * $width;
$matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width);
$inputOffset += $this->dataWidth;
}
return $matrix;
}
//@Override
public function isCropSupported() {
return true;
}
//@Override
public function crop($left, $top, $width, $height) {
return new RGBLuminanceSource($this->luminances,
$this->dataWidth,
$this->dataHeight,
$this->left + $left,
$this->top + $top,
$width,
$height);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Zxing;
interface Reader {
public function decode($image);
public function reset();
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
/**
* The general exception class throw when something goes wrong during decoding of a barcode.
* This includes, but is not limited to, failing checksums / error correction algorithms, being
* unable to locate finder timing patterns, and so on.
*
* @author Sean Owen
*/
abstract class ReaderException extends \Exception {
// disable stack traces when not running inside test units
//protected static $isStackTrace = System.getProperty("surefire.test.class.path") != null;
protected static $isStackTrace = false;
function ReaderException($cause=null) {
if($cause){
parent::__construct($cause);
}
}
// Prevent stack traces from being taken
// srowen says: huh, my IDE is saying this is not an override. native methods can't be overridden?
// This, at least, does not hurt. Because we use a singleton pattern here, it doesn't matter anyhow.
//@Override
public final function fillInStackTrace() {
return null;
}
}

View File

@@ -0,0 +1,128 @@
<?php
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
/**
* <p>Encapsulates the result of decoding a barcode within an image.</p>
*
* @author Sean Owen
*/
final class Result {
private $text;
private $rawBytes;
private $resultPoints;
private $format;
private $resultMetadata;
private $timestamp;
public function __construct($text,
$rawBytes,
$resultPoints,
$format,
$timestamp = '') {
$this->text = $text;
$this->rawBytes = $rawBytes;
$this->resultPoints = $resultPoints;
$this->format = $format;
$this->resultMetadata = null;
$this->timestamp = $timestamp?$timestamp:time();
}
/**
* @return raw text encoded by the barcode
*/
public function getText() {
return $this->text;
}
/**
* @return raw bytes encoded by the barcode, if applicable, otherwise {@code null}
*/
public function getRawBytes() {
return $this->rawBytes;
}
/**
* @return points related to the barcode in the image. These are typically points
* identifying finder patterns or the corners of the barcode. The exact meaning is
* specific to the type of barcode that was decoded.
*/
public function getResultPoints() {
return $this->resultPoints;
}
/**
* @return {@link BarcodeFormat} representing the format of the barcode that was decoded
*/
public function getBarcodeFormat() {
return $this->format;
}
/**
* @return {@link Map} mapping {@link ResultMetadataType} keys to values. May be
* {@code null}. This contains optional metadata about what was detected about the barcode,
* like orientation.
*/
public function getResultMetadata() {
return $this->resultMetadata;
}
public function putMetadata($type, $value) {
if ($this->resultMetadata == null) {
$this->resultMetadata = array();
}
$resultMetadata[$type] = $value;
}
public function putAllMetadata($metadata) {
if ($metadata != null) {
if ($this->resultMetadata == null) {
$this->resultMetadata = $metadata;
} else {
$this->resultMetadata = array_merge($this->resultMetadata, $metadata);
}
}
}
public function addResultPoints($newPoints) {
$oldPoints = $this->resultPoints;
if ($oldPoints == null) {
$this->resultPoints = $newPoints;
} else if ($newPoints != null && count($newPoints) > 0) {
$allPoints = fill_array(0,count($oldPoints)+count($newPoints),0);
$allPoints = arraycopy($oldPoints, 0, $allPoints, 0, count($oldPoints));
$allPoints = arraycopy($newPoints, 0, $allPoints, count($oldPoints), count($newPoints));
$this->resultPoints = $allPoints;
}
}
public function getTimestamp() {
return $this->timestamp;
}
//@Override
public function toString() {
return $this->text;
}
}

View File

@@ -0,0 +1,140 @@
<?php
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing;
use Zxing\Common\Detector\MathUtils;
/**
* <p>Encapsulates a point of interest in an image containing a barcode. Typically, this
* would be the location of a finder pattern or the corner of the barcode, for example.</p>
*
* @author Sean Owen
*/
class ResultPoint {
private $x;
private $y;
public function __construct($x, $y) {
$this->x = (float)($x);
$this->y = (float)($y);
}
public final function getX() {
return (float)($this->x);
}
public final function getY() {
return (float)($this->y);
}
//@Override
public final function equals($other) {
if ($other instanceof ResultPoint) {
$otherPoint = $other;
return $this->x == $otherPoint->x && $this->y == $otherPoint->y;
}
return false;
}
//@Override
public final function hashCode() {
return 31 * floatToIntBits($this->x) + floatToIntBits($this->y);
}
//@Override
public final function toString() {
$result = '';
$result.= ('(');
$result.=($this->x);
$result.=(',');
$result.=($this->y);
$result.=(')');
return $result;
}
/**
* Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC
* and BC is less than AC, and the angle between BC and BA is less than 180 degrees.
*
* @param patterns array of three {@code ResultPoint} to order
*/
public static function orderBestPatterns($patterns) {
// Find distances between pattern centers
$zeroOneDistance = self::distance($patterns[0], $patterns[1]);
$oneTwoDistance = self::distance($patterns[1], $patterns[2]);
$zeroTwoDistance = self::distance($patterns[0], $patterns[2]);
$pointA='';
$pointB='';
$pointC='';
// Assume one closest to other two is B; A and C will just be guesses at first
if ($oneTwoDistance >= $zeroOneDistance && $oneTwoDistance >= $zeroTwoDistance) {
$pointB = $patterns[0];
$pointA = $patterns[1];
$pointC = $patterns[2];
} else if ($zeroTwoDistance >= $oneTwoDistance && $zeroTwoDistance >= $zeroOneDistance) {
$pointB = $patterns[1];
$pointA = $patterns[0];
$pointC = $patterns[2];
} else {
$pointB = $patterns[2];
$pointA = $patterns[0];
$pointC = $patterns[1];
}
// Use cross product to figure out whether A and C are correct or flipped.
// This asks whether BC x BA has a positive z component, which is the arrangement
// we want for A, B, C. If it's negative, then we've got it flipped around and
// should swap A and C.
if (self::crossProductZ($pointA, $pointB, $pointC) < 0.0) {
$temp = $pointA;
$pointA = $pointC;
$pointC = $temp;
}
$patterns[0] = $pointA;
$patterns[1] = $pointB;
$patterns[2] = $pointC;
return $patterns;
}
/**
* @param pattern1 first pattern
* @param pattern2 second pattern
* @return distance between two points
*/
public static function distance($pattern1, $pattern2) {
return MathUtils::distance($pattern1->x, $pattern1->y, $pattern2->x, $pattern2->y);
}
/**
* Returns the z component of the cross product between vectors BC and BA.
*/
private static function crossProductZ($pointA,
$pointB,
$pointC) {
$bX = $pointB->x;
$bY = $pointB->y;
return (($pointC->x - $bX) * ($pointA->y - $bY)) - (($pointC->y - $bY) * ($pointA->x - $bX));
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace Zxing\Common\CharacterSetEci\AbstractEnum;
use \Zxing\NotFoundException;
use ReflectionClass;
/**
* A general enum implementation until we got SplEnum.
*/
final class AbstractEnum
{
/**
* Default value.
*/
const __default = null;
/**
* Current value.
*
* @var mixed
*/
protected $value;
/**
* Cache of constants.
*
* @var array
*/
protected $constants;
/**
* Whether to handle values strict or not.
*
* @var boolean
*/
protected $strict;
/**
* Creates a new enum.
*
* @param mixed $initialValue
* @param boolean $strict
*/
public function __construct($initialValue = null, $strict = false)
{
$this->strict = $strict;
$this->change($initialValue);
}
/**
* Changes the value of the enum.
*
* @param mixed $value
* @return void
*/
public function change($value)
{
if (!in_array($value, $this->getConstList(), $this->strict)) {
throw new Exception\UnexpectedValueException('Value not a const in enum ' . get_class($this));
}
$this->value = $value;
}
/**
* Gets current value.
*
* @return mixed
*/
public function get()
{
return $this->value;
}
/**
* Gets all constants (possible values) as an array.
*
* @param boolean $includeDefault
* @return array
*/
public function getConstList($includeDefault = true)
{
if ($this->constants === null) {
$reflection = new ReflectionClass($this);
$this->constants = $reflection->getConstants();
}
if ($includeDefault) {
return $this->constants;
}
$constants = $this->constants;
unset($constants['__default']);
return $constants;
}
/**
* Gets the name of the enum.
*
* @return string
*/
public function __toString()
{
return array_search($this->value, $this->getConstList());
}
}

View File

@@ -0,0 +1,394 @@
<?php
/**
* Created by PhpStorm.
* User: Ashot
* Date: 3/25/15
* Time: 11:51
*/
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing\Common;
/**
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
*
* @author Sean Owen
*/
final class BitArray {
private $bits;
private $size;
public function __construct($bits=array(),$size=0) {
if(!$bits&&!$size){
$this->$size = 0;
$this->bits = array();
}elseif($bits&&!$size){
$this->size = $bits;
$this->bits = $this->makeArray($bits);
}else{
$this->bits = $bits;
$this->size = $size;
}
}
public function getSize() {
return $this->size;
}
public function getSizeInBytes() {
return ($this->size + 7) / 8;
}
private function ensureCapacity($size) {
if ($size > count($this->bits) * 32) {
$newBits = $this->makeArray($size);
$newBits = arraycopy($this->bits, 0, $newBits, 0, count($this->bits));
$this->bits = $newBits;
}
}
/**
* @param $i; bit to get
* @return true iff bit i is set
*/
public function get($i) {
$key = intval($i / 32);
return intval32bits($this->bits[$key] & (1 << ($i & 0x1F))) != 0;
}
/**
* Sets bit i.
*
* @param i bit to set
*/
public function set($i) {
$this->bits[intval($i / 32)] |= 1 << ($i & 0x1F);
$this->bits[intval($i / 32)] = overflow($this->bits[intval($i / 32)]);
}
/**
* Flips bit i.
*
* @param i bit to set
*/
public function flip($i) {
$this->bits[intval($i / 32)] ^= 1 << ($i & 0x1F);
$this->bits[intval($i / 32)] = overflow32($this->bits[intval($i / 32)]);
}
/**
* @param from first bit to check
* @return index of first bit that is set, starting from the given index, or size if none are set
* at or beyond this given index
* @see #getNextUnset(int)
*/
public function getNextSet($from) {
if ($from >= $this->size) {
return $this->size;
}
$bitsOffset = intval($from / 32);
$currentBits = (int)$this->bits[$bitsOffset];
// mask off lesser bits first
$currentBits &= ~((1 << ($from & 0x1F)) - 1);
while ($currentBits == 0) {
if (++$bitsOffset == count($this->bits)) {
return $this->size;
}
$currentBits = $this->bits[$bitsOffset];
}
$result = ($bitsOffset * 32) + numberOfTrailingZeros($currentBits); //numberOfTrailingZeros
return $result > $this->size ? $this->size : $result;
}
/**
* @param from index to start looking for unset bit
* @return index of next unset bit, or {@code size} if none are unset until the end
* @see #getNextSet(int)
*/
public function getNextUnset($from) {
if ($from >= $this->size) {
return $this->size;
}
$bitsOffset = intval($from / 32);
$currentBits = ~$this->bits[$bitsOffset];
// mask off lesser bits first
$currentBits &= ~((1 << ($from & 0x1F)) - 1);
while ($currentBits == 0) {
if (++$bitsOffset == count($this->bits)) {
return $this->size;
}
$currentBits = overflow32(~$this->bits[$bitsOffset]);
}
$result = ($bitsOffset * 32) + numberOfTrailingZeros($currentBits);
return $result > $this->size ? $this->size : $result;
}
/**
* Sets a block of 32 bits, starting at bit i.
*
* @param i first bit to set
* @param newBits the new value of the next 32 bits. Note again that the least-significant bit
* corresponds to bit i, the next-least-significant to i+1, and so on.
*/
public function setBulk($i, $newBits) {
$this->bits[intval($i / 32)] = $newBits;
}
/**
* Sets a range of bits.
*
* @param start start of range, inclusive.
* @param end end of range, exclusive
*/
public function setRange($start, $end) {
if ($end < $start) {
throw new \InvalidArgumentException();
}
if ($end == $start) {
return;
}
$end--; // will be easier to treat this as the last actually set bit -- inclusive
$firstInt = intval($start / 32);
$lastInt = intval($end / 32);
for ($i = $firstInt; $i <= $lastInt; $i++) {
$firstBit = $i > $firstInt ? 0 : $start & 0x1F;
$lastBit = $i < $lastInt ? 31 : $end & 0x1F;
$mask = 0;
if ($firstBit == 0 && $lastBit == 31) {
$mask = -1;
} else {
$mask = 0;
for ($j = $firstBit; $j <= $lastBit; $j++) {
$mask |= 1 << $j;
}
}
$this->bits[$i] = overflow32($this->bits[$i]|$mask);
}
}
/**
* Clears all bits (sets to false).
*/
public function clear() {
$max = count($this->bits);
for ($i = 0; $i < $max; $i++) {
$this->bits[$i] = 0;
}
}
/**
* Efficient method to check if a range of bits is set, or not set.
*
* @param start start of range, inclusive.
* @param end end of range, exclusive
* @param value if true, checks that bits in range are set, otherwise checks that they are not set
* @return true iff all bits are set or not set in range, according to value argument
* @throws InvalidArgumentException if end is less than or equal to start
*/
public function isRange($start, $end, $value) {
if ($end < $start) {
throw new \InvalidArgumentException();
}
if ($end == $start) {
return true; // empty range matches
}
$end--; // will be easier to treat this as the last actually set bit -- inclusive
$firstInt = intval($start / 32);
$lastInt = intval($end / 32);
for ($i = $firstInt; $i <= $lastInt; $i++) {
$firstBit = $i > $firstInt ? 0 : $start & 0x1F;
$lastBit = $i < $lastInt ? 31 :$end & 0x1F;
$mask = 0;
if ($firstBit == 0 && $lastBit == 31) {
$mask = -1;
} else {
$mask = 0;
for ($j = $firstBit; $j <= $lastBit; $j++) {
$mask = overflow32($mask|(1 << $j));
}
}
// Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is,
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
if (($this->bits[$i] & $mask) != ($value ? $mask : 0)) {
return false;
}
}
return true;
}
public function appendBit($bit) {
$this->ensureCapacity($this->size + 1);
if ($bit) {
$this->bits[intval($this->size / 32)] |= 1 << ($this->size & 0x1F);
}
$this->size++;
}
/**
* Appends the least-significant bits, from value, in order from most-significant to
* least-significant. For example, appending 6 bits from 0x000001E will append the bits
* 0, 1, 1, 1, 1, 0 in that order.
*
* @param value {@code int} containing bits to append
* @param numBits bits from value to append
*/
public function appendBits($value, $numBits) {
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);
}
}
public function appendBitArray($other) {
$otherSize = $other->size;
$this->ensureCapacity($this->size + $otherSize);
for ($i = 0; $i < $otherSize; $i++) {
$this->appendBit($other->get($i));
}
}
public function _xor($other) {
if (count($this->bits) != count($other->bits)) {
throw new \InvalidArgumentException("Sizes don't match");
}
for ($i = 0; $i < count($this->bits); $i++) {
// The last byte could be incomplete (i.e. not have 8 bits in
// it) but there is no problem since 0 XOR 0 == 0.
$this->bits[$i] ^= $other->bits[$i];
}
}
/**
*
* @param bitOffset first bit to start writing
* @param array array to write into. Bytes are written most-significant byte first. This is the opposite
* of the internal representation, which is exposed by {@link #getBitArray()}
* @param offset position in array to start writing
* @param numBytes how many bytes to write
*/
public function toBytes($bitOffset, &$array, $offset, $numBytes) {
for ($i = 0; $i < $numBytes; $i++) {
$theByte = 0;
for ($j = 0; $j < 8; $j++) {
if ($this->get($bitOffset)) {
$theByte |= 1 << (7 - $j);
}
$bitOffset++;
}
$array[(int)($offset + $i)] = $theByte;
}
}
/**
* @return underlying array of ints. The first element holds the first 32 bits, and the least
* significant bit is bit 0.
*/
public function getBitArray() {
return $this->bits;
}
/**
* Reverses all bits in the array.
*/
public function reverse() {
$newBits = array();
// reverse all int's first
$len = (($this->size-1) / 32);
$oldBitsLen = $len + 1;
for ($i = 0; $i < $oldBitsLen; $i++) {
$x = $this->bits[$i];/*
$x = (($x >> 1) & 0x55555555L) | (($x & 0x55555555L) << 1);
$x = (($x >> 2) & 0x33333333L) | (($x & 0x33333333L) << 2);
$x = (($x >> 4) & 0x0f0f0f0fL) | (($x & 0x0f0f0f0fL) << 4);
$x = (($x >> 8) & 0x00ff00ffL) | (($x & 0x00ff00ffL) << 8);
$x = (($x >> 16) & 0x0000ffffL) | (($x & 0x0000ffffL) << 16);*/
$x = (($x >> 1) & 0x55555555) | (($x & 0x55555555) << 1);
$x = (($x >> 2) & 0x33333333) | (($x & 0x33333333) << 2);
$x = (($x >> 4) & 0x0f0f0f0f) | (($x & 0x0f0f0f0f) << 4);
$x = (($x >> 8) & 0x00ff00ff) | (($x & 0x00ff00ff) << 8);
$x = (($x >> 16) & 0x0000ffff) | (($x & 0x0000ffff) << 16);
$newBits[(int)$len - $i] = (int) $x;
}
// now correct the int's if the bit size isn't a multiple of 32
if ($this->size != $oldBitsLen * 32) {
$leftOffset = $oldBitsLen * 32 - $this->size;
$mask = 1;
for ($i = 0; $i < 31 - $leftOffset; $i++) {
$mask = ($mask << 1) | 1;
}
$currentInt = ($newBits[0] >> $leftOffset) & $mask;
for ($i = 1; $i < $oldBitsLen; $i++) {
$nextInt = $newBits[$i];
$currentInt |= $nextInt << (32 - $leftOffset);
$newBits[intval($i) - 1] = $currentInt;
$currentInt = ($nextInt >> $leftOffset) & $mask;
}
$newBits[intval($oldBitsLen) - 1] = $currentInt;
}
$bits = $newBits;
}
private static function makeArray($size) {
return array();
}
// @Override
public function equals($o) {
if (!($o instanceof BitArray)) {
return false;
}
$other = $o;
return $this->size == $other->size && $this->bits===$other->bits;
}
//@Override
public function hashCode() {
return 31 * $this->size +hashCode($this->bits);
}
// @Override
public function toString() {
$result = '';
for ($i = 0; $i < $this->size; $i++) {
if (($i & 0x07) == 0) {
$result.=' ';
}
$result.= ($this->get($i) ? 'X' : '.');
}
return (string) $result;
}
// @Override
public function _clone() {
return new BitArray($this->bits, $this->size);
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,112 @@
<?php
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing\Common;
/**
* <p>This provides an easy abstraction to read bits at a time from a sequence of bytes, where the
* number of bits read is not often a multiple of 8.</p>
*
* <p>This class is thread-safe but not reentrant -- unless the caller modifies the bytes array
* it passed in, in which case all bets are off.</p>
*
* @author Sean Owen
*/
final class BitSource {
private $bytes;
private $byteOffset = 0;
private $bitOffset = 0;
/**
* @param bytes bytes from which this will read bits. Bits will be read from the first byte first.
* Bits are read within a byte from most-significant to least-significant bit.
*/
public function __construct($bytes) {
$this->bytes = $bytes;
}
/**
* @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}.
*/
public function getBitOffset() {
return $this->bitOffset;
}
/**
* @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}.
*/
public function getByteOffset() {
return $this->byteOffset;
}
/**
* @param numBits number of bits to read
* @return int representing the bits read. The bits will appear as the least-significant
* bits of the int
* @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available
*/
public function readBits($numBits) {
if ($numBits < 1 || $numBits > 32 || $numBits > $this->available()) {
throw new \InvalidArgumentException(strval($numBits));
}
$result = 0;
// First, read remainder from current byte
if ($this->bitOffset > 0) {
$bitsLeft = 8 - $this->bitOffset;
$toRead = $numBits < $bitsLeft ? $numBits : $bitsLeft;
$bitsToNotRead = $bitsLeft - $toRead;
$mask = (0xFF >> (8 - $toRead)) << $bitsToNotRead;
$result = ($this->bytes[$this->byteOffset] & $mask) >> $bitsToNotRead;
$numBits -= $toRead;
$this->bitOffset += $toRead;
if ($this->bitOffset == 8) {
$this->bitOffset = 0;
$this->byteOffset++;
}
}
// Next read whole bytes
if ($numBits > 0) {
while ($numBits >= 8) {
$result = ($result << 8) | ($this->bytes[$this->byteOffset] & 0xFF);
$this->byteOffset++;
$numBits -= 8;
}
// Finally read a partial byte
if ($numBits > 0) {
$bitsToNotRead = 8 - $numBits;
$mask = (0xFF >> $bitsToNotRead) << $bitsToNotRead;
$result = ($result << $numBits) | (($this->bytes[$this->byteOffset] & $mask) >> $bitsToNotRead);
$this->bitOffset += $numBits;
}
}
return $result;
}
/**
* @return number of bits that can be read successfully
*/
public function available() {
return 8 * (count($this->bytes) - $this->byteOffset) - $this->bitOffset;
}
}

View File

@@ -0,0 +1,154 @@
<?php
namespace Zxing\Common;
use Zxing\Common\AbstractEnum;
/**
* Encapsulates a Character Set ECI, according to "Extended Channel
* Interpretations" 5.3.1.1 of ISO 18004.
*/
final class CharacterSetECI
{
private static $name = null;
/**#@+
* Character set constants.
*/
const CP437 = 0;
const ISO8859_1 = 1;
const ISO8859_2 = 4;
const ISO8859_3 = 5;
const ISO8859_4 = 6;
const ISO8859_5 = 7;
const ISO8859_6 = 8;
const ISO8859_7 = 9;
const ISO8859_8 = 10;
const ISO8859_9 = 11;
const ISO8859_10 = 12;
const ISO8859_11 = 13;
const ISO8859_12 = 14;
const ISO8859_13 = 15;
const ISO8859_14 = 16;
const ISO8859_15 = 17;
const ISO8859_16 = 18;
const SJIS = 20;
const CP1250 = 21;
const CP1251 = 22;
const CP1252 = 23;
const CP1256 = 24;
const UNICODE_BIG_UNMARKED = 25;
const UTF8 = 26;
const ASCII = 27;
const BIG5 = 28;
const GB18030 = 29;
const EUC_KR = 30;
/**#@-*/
/**
* Map between character names and their ECI values.
*
* @var array
*/
protected static $nameToEci = array(
'ISO-8859-1' => self::ISO8859_1,
'ISO-8859-2' => self::ISO8859_2,
'ISO-8859-3' => self::ISO8859_3,
'ISO-8859-4' => self::ISO8859_4,
'ISO-8859-5' => self::ISO8859_5,
'ISO-8859-6' => self::ISO8859_6,
'ISO-8859-7' => self::ISO8859_7,
'ISO-8859-8' => self::ISO8859_8,
'ISO-8859-9' => self::ISO8859_9,
'ISO-8859-10' => self::ISO8859_10,
'ISO-8859-11' => self::ISO8859_11,
'ISO-8859-12' => self::ISO8859_12,
'ISO-8859-13' => self::ISO8859_13,
'ISO-8859-14' => self::ISO8859_14,
'ISO-8859-15' => self::ISO8859_15,
'ISO-8859-16' => self::ISO8859_16,
'SHIFT-JIS' => self::SJIS,
'WINDOWS-1250' => self::CP1250,
'WINDOWS-1251' => self::CP1251,
'WINDOWS-1252' => self::CP1252,
'WINDOWS-1256' => self::CP1256,
'UTF-16BE' => self::UNICODE_BIG_UNMARKED,
'UTF-8' => self::UTF8,
'ASCII' => self::ASCII,
'GBK' => self::GB18030,
'EUC-KR' => self::EUC_KR,
);
/**
* Additional possible values for character sets.
*
* @var array
*/
protected static $additionalValues = array(
self::CP437 => 2,
self::ASCII => 170,
);
/**
* Gets character set ECI by value.
*
* @param string $name
* @return CharacterSetEci|null
*/
public static function getCharacterSetECIByValue($value)
{
if ($value < 0 || $value >= 900) {
throw new Exception\InvalidArgumentException('Value must be between 0 and 900');
}
if (false !== ($key = array_search($value, self::$additionalValues))) {
$value = $key;
}
array_search($value, self::$nameToEci);
try
{
self::setName($value);
return new self($value);
} catch (Exception\UnexpectedValueException $e) {
return null;
}
}
private static function setName($value)
{
foreach (self::$nameToEci as $name => $key) {
if($key == $value)
{
self::$name = $name;
return true;
}
}
if(self::$name == null)
{
foreach (self::$additionalValues as $name => $key) {
if($key == $value)
{
self::$name = $name;
return true;
}
}
}
}
/**
* Gets character set ECI name.
*
* @return character set ECI name|null
*/
public static function name()
{
return self::$name;
}
/**
* Gets character set ECI by name.
*
* @param string $name
* @return CharacterSetEci|null
*/
public static function getCharacterSetECIByName($name)
{
$name = strtoupper($name);
if (isset(self::$nameToEci[$name])) {
return new self(self::$nameToEci[$name]);
}
return null;
}
}

View File

@@ -0,0 +1,109 @@
<?php
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Zxing\Common;
/**
* <p>Encapsulates the result of decoding a matrix of bits. This typically
* applies to 2D barcode formats. For now it contains the raw bytes obtained,
* as well as a String interpretation of those bytes, if applicable.</p>
*
* @author Sean Owen
*/
final class DecoderResult {
private $rawBytes;
private $text;
private $byteSegments;
private $ecLevel;
private $errorsCorrected;
private $erasures;
private $other;
private $structuredAppendParity;
private $structuredAppendSequenceNumber;
public function __construct($rawBytes,
$text,
$byteSegments,
$ecLevel,
$saSequence = -1,
$saParity = -1) {
$this->rawBytes = $rawBytes;
$this->text = $text;
$this->byteSegments = $byteSegments;
$this->ecLevel = $ecLevel;
$this->structuredAppendParity = $saParity;
$this->structuredAppendSequenceNumber = $saSequence;
}
public function getRawBytes() {
return $this->rawBytes;
}
public function getText() {
return $this->text;
}
public function getByteSegments() {
return $this->byteSegments;
}
public function getECLevel() {
return $this->ecLevel;
}
public function getErrorsCorrected() {
return $this->errorsCorrected;
}
public function setErrorsCorrected($errorsCorrected) {
$this->errorsCorrected = $errorsCorrected;
}
public function getErasures() {
return $this->erasures;
}
public function setErasures($erasures) {
$this->erasures = $erasures;
}
public function getOther() {
return $this->other;
}
public function setOther($other) {
$this->other = $other;
}
public function hasStructuredAppend() {
return $this->structuredAppendParity >= 0 && $this->structuredAppendSequenceNumber >= 0;
}
public function getStructuredAppendParity() {
return $this->structuredAppendParity;
}
public function getStructuredAppendSequenceNumber() {
return $this->structuredAppendSequenceNumber;
}
}

Some files were not shown because too many files have changed in this diff Show More