Add a BSD licensed QR code library
This commit is contained in:
parent
b42de823e8
commit
456789a024
Binary file not shown.
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import necessary dependencies
|
||||
*/
|
||||
require_once 'QRByte.php';
|
||||
require_once 'QRMode.php';
|
||||
|
||||
/**
|
||||
* This class provides the 8bit Byte implementaton of a QRByte
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QR8bitByte implements QRByte
|
||||
{
|
||||
/**
|
||||
* The data
|
||||
* @var array
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* The mode
|
||||
* @var unknown
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* Retrieve the mode
|
||||
*
|
||||
* @return int The mode
|
||||
* @see QRByte::getMode()
|
||||
*/
|
||||
public function getMode()
|
||||
{
|
||||
return $this->mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the length
|
||||
*
|
||||
* @return int The length
|
||||
* @see QRByte::getLength()
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
return strlen($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to byte
|
||||
*
|
||||
* @param QRBitBuffer $buffer The data to write into byte
|
||||
*
|
||||
* @see QRByte::write()
|
||||
*/
|
||||
public function write(QRBitBuffer $buffer)
|
||||
{
|
||||
for($i = 0; $i < strlen($this->data); $i++)
|
||||
{
|
||||
$buffer->put(ord($this->data[$i]), 8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of a QR8bitByte
|
||||
*
|
||||
* @param array $data The data for the Byte
|
||||
*/
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->mode = QRMode::MODE_8BIT_BYTE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* QRBitBuffer class
|
||||
*
|
||||
* The purpose of this class is to act as data holder for QRCode.
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRBitBuffer
|
||||
{
|
||||
/**
|
||||
* Array based buffer access
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $buffer;
|
||||
|
||||
/**
|
||||
* Length of array
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $length;
|
||||
|
||||
/**
|
||||
* Create a new instance of QRBitBuffer
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->buffer = array();
|
||||
$this->length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get particular bit given by index
|
||||
*
|
||||
* @param int $index The index of bit
|
||||
* @return boolean
|
||||
*/
|
||||
public function get($index)
|
||||
{
|
||||
$bufIndex = floor($index / 8);
|
||||
return ( ($this->buffer[$bufIndex] >> (7 - $index % 8) ) & 1) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the byte at particular index
|
||||
*
|
||||
* @param int $index The index of the byte
|
||||
* @return string
|
||||
*/
|
||||
public function getAt($index)
|
||||
{
|
||||
return $this->buffer[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Put amount of bits
|
||||
* @param int $num The data to put
|
||||
* @param int $length The length of data
|
||||
*/
|
||||
public function put($num, $length)
|
||||
{
|
||||
for($i = 0; $i < $length; $i++)
|
||||
{
|
||||
$this->putBit((($num >> ($length - $i - 1)) & 1) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current length in bits
|
||||
*
|
||||
* @return int The amount of bits
|
||||
*/
|
||||
public function getLengthInBits()
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put particular bit
|
||||
*
|
||||
* @param int $bit The bit to put
|
||||
*/
|
||||
public function putBit($bit)
|
||||
{
|
||||
$bufIndex = floor($this->length / 8);
|
||||
if(sizeof($this->buffer) <= $bufIndex)
|
||||
{
|
||||
array_push($this->buffer, 0);
|
||||
}
|
||||
|
||||
if($bit)
|
||||
{
|
||||
$this->buffer[$bufIndex] |= (0x80 >> ($this->length % 8));
|
||||
}
|
||||
|
||||
$this->length++;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import necessary dependencies
|
||||
*/
|
||||
require_once 'QRBitBuffer.php';
|
||||
|
||||
/**
|
||||
* This interface describes a QRByte implementation
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
interface QRByte
|
||||
{
|
||||
/**
|
||||
* Retrieve the mode
|
||||
*
|
||||
* @return int The mode
|
||||
*/
|
||||
public function getMode();
|
||||
|
||||
/**
|
||||
* Retrieve the length
|
||||
*
|
||||
* @return int The length
|
||||
*/
|
||||
public function getLength();
|
||||
|
||||
/**
|
||||
* Write data to byte
|
||||
*
|
||||
* @param QRBitBuffer $buffer The data to write into byte
|
||||
*/
|
||||
public function write(QRBitBuffer $buffer);
|
||||
}
|
||||
|
|
@ -0,0 +1,656 @@
|
|||
<?php
|
||||
/**
|
||||
* This file provides the main QRCode class.
|
||||
*
|
||||
* The project is a rewrite from jQuery extension available at
|
||||
* @link https://github.com/jeromeetienne/jquery-qrcode
|
||||
*
|
||||
* For a detailed description of QRCode and its features please check
|
||||
* @link http://www.qrcode.com/
|
||||
*
|
||||
* QR Code is registered trademark of
|
||||
* DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*
|
||||
* All files in the package have the same license:
|
||||
* http://opensource.org/licenses/BSD-2-Clause
|
||||
*
|
||||
* @copyright BSD2
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import necessary dependencies
|
||||
*/
|
||||
require_once 'QR8bitByte.php';
|
||||
require_once 'QRBitBuffer.php';
|
||||
require_once 'QRRSBlock.php';
|
||||
require_once 'QRUtil.php';
|
||||
require_once 'QRCodeException.php';
|
||||
|
||||
/**
|
||||
* This is the main class
|
||||
*
|
||||
* It provides the functionality to generate a QRCode bitmap
|
||||
* out of appended data elements.
|
||||
*
|
||||
* @package phpQr
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
*/
|
||||
class QRCode
|
||||
{
|
||||
/**
|
||||
* Needed for padding
|
||||
*
|
||||
* @final
|
||||
*
|
||||
*/
|
||||
const PAD0 = 0xec;
|
||||
|
||||
/**
|
||||
* Needed for padding
|
||||
*
|
||||
* @final
|
||||
*
|
||||
*/
|
||||
const PAD1 = 0x11;
|
||||
|
||||
/**
|
||||
* The type number of qrcode
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $typeNumber;
|
||||
|
||||
/**
|
||||
* Level of error correction
|
||||
*
|
||||
* @see QRErrorCorrectLevel
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $errorCorrectLevel;
|
||||
|
||||
/**
|
||||
* Bitmap
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $modules;
|
||||
|
||||
/**
|
||||
* Amount of modules in bitmap
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $moduleCount;
|
||||
|
||||
/**
|
||||
* The data as array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $dataCache;
|
||||
|
||||
/**
|
||||
* All append data elements
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $dataList;
|
||||
|
||||
/**
|
||||
* Create a new instance of QRCode
|
||||
*
|
||||
* @param int $typeNumber
|
||||
* The type of QRCode
|
||||
* @param int $errorCorrectLevel
|
||||
* The error correction level
|
||||
*/
|
||||
public function __construct($typeNumber, $errorCorrectLevel)
|
||||
{
|
||||
$this->typeNumber = $typeNumber;
|
||||
$this->errorCorrectLevel = $errorCorrectLevel;
|
||||
$this->modules = null;
|
||||
$this->moduleCount = 0;
|
||||
$this->dataCache = null;
|
||||
$this->dataList = array ();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is only needed for debugging purposes and returns the bitmap
|
||||
* DONT USE THIS TO MANIPULATE THE BITMAP!
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getModules()
|
||||
{
|
||||
return $this->modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new data element to the QRCode
|
||||
*
|
||||
* @param string $data
|
||||
*/
|
||||
public function addData($data)
|
||||
{
|
||||
$newData = new QR8bitByte ( $data );
|
||||
array_push ( $this->dataList, $newData );
|
||||
$this->dataCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a given bitmap entry is dark or not
|
||||
*
|
||||
* @param int $row
|
||||
* The row in bitmap
|
||||
* @param int $col
|
||||
* The column in bitmap
|
||||
*
|
||||
* @throws QRCodeException
|
||||
* @return true in case of its a dark bit, false otherwise
|
||||
*/
|
||||
public function isDark($row, $col)
|
||||
{
|
||||
if ($row < 0 || $this->moduleCount <= $row || $col < 0 || $this->moduleCount <= $col)
|
||||
{
|
||||
throw new QRCodeException ( "$row,$col" );
|
||||
}
|
||||
|
||||
return $this->modules [$row] [$col];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of modules in bitmap
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getModuleCount()
|
||||
{
|
||||
return $this->moduleCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the QRCode bitmap
|
||||
*/
|
||||
public function make()
|
||||
{
|
||||
if ($this->typeNumber < 1)
|
||||
{
|
||||
$typeNumber = 1;
|
||||
for($typeNumber = 1; $typeNumber < 40; $typeNumber ++)
|
||||
{
|
||||
$rsBlocks = QRRSBlock::getInstance ()->getRSBlocks ( $typeNumber, $this->errorCorrectLevel );
|
||||
|
||||
$buffer = new QRBitBuffer ();
|
||||
$totalDataCount = 0;
|
||||
for($i = 0; $i < sizeof ( $rsBlocks ); $i ++)
|
||||
{
|
||||
$totalDataCount += $rsBlocks [$i]->getDataCount ();
|
||||
}
|
||||
|
||||
for($i = 0; $i < sizeof ( $this->dataList ); $i ++)
|
||||
{
|
||||
$data = $this->dataList [$i];
|
||||
|
||||
assert ( $data instanceof QRByte );
|
||||
|
||||
$buffer->put ( $data->getMode (), 4 );
|
||||
$buffer->put ( $data->getLength (), QRUtil::getInstance ()->getLengthInBits ( $data->getMode (), $typeNumber ) );
|
||||
$data->write ( $buffer );
|
||||
}
|
||||
if ($buffer->getLengthInBits () <= $totalDataCount * 8)
|
||||
break;
|
||||
}
|
||||
$this->typeNumber = $typeNumber;
|
||||
}
|
||||
$this->makeImpl ( false, $this->getBestMaskPattern () );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the bitmap (really)
|
||||
*
|
||||
* @param boolean $test
|
||||
* @param int $maskPattern
|
||||
*/
|
||||
private function makeImpl($test, $maskPattern)
|
||||
{
|
||||
$this->moduleCount = $this->typeNumber * 4 + 17;
|
||||
$this->modules = QRUtil::getInstance ()->createEmptyArray ( $this->moduleCount );
|
||||
|
||||
for($row = 0; $row < $this->moduleCount; $row ++)
|
||||
{
|
||||
$this->modules [$row] = QRUtil::getInstance ()->createEmptyArray ( $this->moduleCount );
|
||||
|
||||
for($col = 0; $col < $this->moduleCount; $col ++)
|
||||
{
|
||||
$this->modules [$row] [$col] = null;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setupPositionProbePattern ( 0, 0 );
|
||||
$this->setupPositionProbePattern ( $this->moduleCount - 7, 0 );
|
||||
$this->setupPositionProbePattern ( 0, $this->moduleCount - 7 );
|
||||
$this->setupPositionAdjustPattern ();
|
||||
$this->setupTimingPattern ();
|
||||
$this->setupTypeInfo ( $test, $maskPattern );
|
||||
|
||||
if ($this->typeNumber >= 7)
|
||||
{
|
||||
$this->setTypeNumber ( $test );
|
||||
}
|
||||
|
||||
if ($this->dataCache == null)
|
||||
{
|
||||
$this->dataCache = self::createData ( $this->typeNumber, $this->errorCorrectLevel, $this->dataList );
|
||||
}
|
||||
|
||||
$this->mapData ( $this->dataCache, $maskPattern );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the position probes to the bitmap
|
||||
*
|
||||
* @param int $row
|
||||
* @param int $col
|
||||
*/
|
||||
private function setupPositionProbePattern($row, $col)
|
||||
{
|
||||
for($r = - 1; $r <= 7; $r ++)
|
||||
{
|
||||
if ($row + $r <= - 1 || $this->moduleCount <= $row + $r)
|
||||
continue;
|
||||
|
||||
for($c = - 1; $c <= 7; $c ++)
|
||||
{
|
||||
if ($col + $c <= - 1 || $this->moduleCount <= $col + $c)
|
||||
continue;
|
||||
|
||||
if ((0 <= $r && $r <= 6 && ($c == 0 || $c == 6)) || (0 <= $c && $c <= 6 && ($r == 0 || $r == 6)) || (2 <= $r && $r <= 4 && 2 <= $c && $c <= 4))
|
||||
{
|
||||
$this->modules [$row + $r] [$col + $c] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->modules [$row + $r] [$col + $c] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the best mask pattern for this QRCode
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getBestMaskPattern()
|
||||
{
|
||||
$minLostPoint = 0;
|
||||
$pattern = 0;
|
||||
|
||||
for($i = 0; $i < 8; $i ++)
|
||||
{
|
||||
$this->makeImpl ( true, $i );
|
||||
|
||||
$lostPoint = QRUtil::getInstance ()->getLostPoint ( $this );
|
||||
|
||||
if ($i == 0 || $minLostPoint > $lostPoint)
|
||||
{
|
||||
$minLostPoint = $lostPoint;
|
||||
$pattern = $i;
|
||||
}
|
||||
}
|
||||
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the timing pattern to bitmap
|
||||
*/
|
||||
private function setupTimingPattern()
|
||||
{
|
||||
for($r = 8; $r < $this->moduleCount - 8; $r ++)
|
||||
{
|
||||
if ($this->modules [$r] [6] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$this->modules [$r] [6] = ($r % 2 == 0);
|
||||
}
|
||||
|
||||
for($c = 8; $c < $this->moduleCount - 8; $c ++)
|
||||
{
|
||||
if ($this->modules [6] [$c] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$this->modules [6] [$c] = ($c % 2 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the position adjust pattern to bitmap
|
||||
*/
|
||||
private function setupPositionAdjustPattern()
|
||||
{
|
||||
$pos = QRUtil::getInstance ()->getPatternPosition ( $this->typeNumber );
|
||||
|
||||
for($i = 0; $i < sizeof ( $pos ); $i ++)
|
||||
{
|
||||
for($j = 0; $j < sizeof ( $pos ); $j ++)
|
||||
{
|
||||
$row = $pos [$i];
|
||||
$col = $pos [$j];
|
||||
|
||||
if ($this->modules [$row] [$col] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for($r = - 2; $r <= 2; $r ++)
|
||||
{
|
||||
for($c = - 2; $c <= 2; $c ++)
|
||||
{
|
||||
if ($r == - 2 || $r == 2 || $c == - 2 || $c == 2 || ($r == 0 && $c == 0))
|
||||
{
|
||||
$this->modules [$row + $r] [$col + $c] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->modules [$row + $r] [$col + $c] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the type number to bitmap
|
||||
*
|
||||
* @param boolean $test
|
||||
*/
|
||||
private function setTypeNumber($test)
|
||||
{
|
||||
$bits = QRUtil::getInstance ()->getBCHTypeNumber ( $this->typeNumber );
|
||||
|
||||
for($i = 0; $i < 18; $i ++)
|
||||
{
|
||||
$mod = (! $test && (($bits >> $i) & 1) == 1);
|
||||
$this->modules [floor ( $i / 3 )] [$i % 3 + $this->moduleCount - 8 - 3] = $mod;
|
||||
}
|
||||
|
||||
for($i = 0; $i < 18; $i ++)
|
||||
{
|
||||
$mod = (! $test && (($bits >> $i) & 1) == 1);
|
||||
$this->modules [$i % 3 + $this->moduleCount - 8 - 3] [floor ( $i / 3 )] = $mod;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the type info to bitmap
|
||||
*
|
||||
* @param boolean $test
|
||||
* @param int $maskPattern
|
||||
*/
|
||||
private function setupTypeInfo($test, $maskPattern)
|
||||
{
|
||||
$data = ($this->errorCorrectLevel << 3) | $maskPattern;
|
||||
$bits = QRUtil::getInstance ()->getBCHTypeInfo ( $data );
|
||||
|
||||
// vertical
|
||||
for($i = 0; $i < 15; $i ++)
|
||||
{
|
||||
$mod = (! $test && (($bits >> $i) & 1) == 1);
|
||||
if ($i < 6)
|
||||
{
|
||||
$this->modules [$i] [8] = $mod;
|
||||
}
|
||||
else if ($i < 8)
|
||||
{
|
||||
$this->modules [$i + 1] [8] = $mod;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->modules [$this->moduleCount - 15 + $i] [8] = $mod;
|
||||
}
|
||||
}
|
||||
|
||||
// horizontal
|
||||
for($i = 0; $i < 15; $i ++)
|
||||
{
|
||||
$mod = (! $test && (($bits >> $i) & 1) == 1);
|
||||
|
||||
if ($i < 8)
|
||||
{
|
||||
$this->modules [8] [$this->moduleCount - $i - 1] = $mod;
|
||||
}
|
||||
else if ($i < 9)
|
||||
{
|
||||
$this->modules [8] [15 - $i - 1 + 1] = $mod;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->modules [8] [15 - $i - 1] = $mod;
|
||||
}
|
||||
}
|
||||
|
||||
// fixed module
|
||||
$this->modules [$this->moduleCount - 8] [8] = (! $test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the data to bitmap
|
||||
*
|
||||
* @param array $data
|
||||
* @param int $maskPattern
|
||||
*/
|
||||
private function mapData($data, $maskPattern)
|
||||
{
|
||||
$inc = - 1;
|
||||
$row = $this->moduleCount - 1;
|
||||
$bitIndex = 7;
|
||||
$byteIndex = 0;
|
||||
|
||||
for($col = $this->moduleCount - 1; $col > 0; $col -= 2)
|
||||
{
|
||||
if ($col == 6)
|
||||
$col --;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
for($c = 0; $c < 2; $c ++)
|
||||
{
|
||||
if ($this->modules [$row] [$col - $c] === null)
|
||||
{
|
||||
$dark = false;
|
||||
|
||||
if ($byteIndex < sizeof ( $data ))
|
||||
{
|
||||
$dark = ((($data [$byteIndex] >> $bitIndex) & 1) == 1);
|
||||
}
|
||||
|
||||
$mask = QRUtil::getInstance ()->getMask ( $maskPattern, $row, $col - $c );
|
||||
|
||||
if ($mask)
|
||||
$dark = ! $dark;
|
||||
|
||||
$this->modules [$row] [$col - $c] = $dark;
|
||||
$bitIndex --;
|
||||
|
||||
if ($bitIndex == - 1)
|
||||
{
|
||||
$byteIndex ++;
|
||||
$bitIndex = 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$row += $inc;
|
||||
|
||||
if ($row < 0 || $this->moduleCount <= $row)
|
||||
{
|
||||
$row -= $inc;
|
||||
$inc = - $inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bitmap out of all append data elements
|
||||
*
|
||||
* @param int $typeNumber
|
||||
* @param int $errorCorrectLevel
|
||||
* @param array $dataList
|
||||
*
|
||||
* @throws QRCodeException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function createData($typeNumber, $errorCorrectLevel, $dataList)
|
||||
{
|
||||
$rsBlocks = QRRSBlock::getInstance ()->getRSBlocks ( $typeNumber, $errorCorrectLevel );
|
||||
|
||||
$buffer = new QRBitBuffer ();
|
||||
|
||||
for($i = 0; $i < sizeof ( $dataList ); $i ++)
|
||||
{
|
||||
$data = $dataList [$i];
|
||||
assert ( $data instanceof QRByte );
|
||||
|
||||
$buffer->put ( $data->getMode (), 4 );
|
||||
$buffer->put ( $data->getLength (), QRUtil::getInstance ()->getLengthInBits ( $data->getMode (), $typeNumber ) );
|
||||
$data->write ( $buffer );
|
||||
}
|
||||
|
||||
// calc num max data
|
||||
$totalDataCount = 0;
|
||||
for($i = 0; $i < sizeof ( $rsBlocks ); $i ++)
|
||||
{
|
||||
$totalDataCount += $rsBlocks [$i]->getDataCount ();
|
||||
}
|
||||
|
||||
if ($buffer->getLengthInBits () > $totalDataCount * 8)
|
||||
{
|
||||
throw new QRCodeException ( "code length overflow (" . $buffer->getLengthInBits () . " > " . ($totalDataCount * 8) . ")" );
|
||||
}
|
||||
|
||||
// end code
|
||||
if ($buffer->getLengthInBits () + 4 <= $totalDataCount * 8)
|
||||
{
|
||||
$buffer->put ( 0, 4 );
|
||||
}
|
||||
|
||||
// padding
|
||||
while ( $buffer->getLengthInBits () % 8 != 0 )
|
||||
{
|
||||
$buffer->putBit ( false );
|
||||
}
|
||||
|
||||
// padding
|
||||
while ( true )
|
||||
{
|
||||
if ($buffer->getLengthInBits () >= $totalDataCount * 8)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
$buffer->put ( QRCode::PAD0, 8 );
|
||||
|
||||
if ($buffer->getLengthInBits () >= $totalDataCount * 8)
|
||||
{
|
||||
break;
|
||||
}
|
||||
$buffer->put ( QRCode::PAD1, 8 );
|
||||
}
|
||||
|
||||
return $this->createBytes ( $buffer, $rsBlocks );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create bitmap out of the bit buffer using reed solomon blocks
|
||||
*
|
||||
* @param QRBitBuffer $buffer
|
||||
* @param array $rsBlocks
|
||||
* @return array
|
||||
*/
|
||||
public function createBytes(QRBitBuffer $buffer, $rsBlocks)
|
||||
{
|
||||
$offset = 0;
|
||||
$maxDcCount = 0;
|
||||
$maxEcCount = 0;
|
||||
|
||||
$dcdata = QRUtil::getInstance ()->createEmptyArray ( sizeof ( $rsBlocks ) );
|
||||
$ecdata = QRUtil::getInstance ()->createEmptyArray ( sizeof ( $rsBlocks ) );
|
||||
|
||||
for($r = 0; $r < sizeof ( $rsBlocks ); $r ++)
|
||||
{
|
||||
$dcCount = $rsBlocks [$r]->getDataCount ();
|
||||
$ecCount = $rsBlocks [$r]->getTotalCount () - $dcCount;
|
||||
|
||||
$maxDcCount = max ( array (
|
||||
$maxDcCount,
|
||||
$dcCount
|
||||
) );
|
||||
$maxEcCount = max ( array (
|
||||
$maxEcCount,
|
||||
$ecCount
|
||||
) );
|
||||
|
||||
$dcdata [$r] = QRUtil::getInstance ()->createEmptyArray ( $dcCount );
|
||||
|
||||
for($i = 0; $i < sizeof ( $dcdata [$r] ); $i ++)
|
||||
{
|
||||
$dcdata [$r] [$i] = 0xff & $buffer->getAt ( $i + $offset );
|
||||
}
|
||||
$offset += $dcCount;
|
||||
|
||||
$rsPoly = QRUtil::getInstance ()->getErrorCorrectPolynominal ( $ecCount );
|
||||
$rawPoly = new QRPolynominal ( $dcdata [$r], $rsPoly->getLength () - 1 );
|
||||
|
||||
$modPoly = $rawPoly->mod ( $rsPoly );
|
||||
$ecdata [$r] = QRUtil::getInstance ()->createEmptyArray ( $rsPoly->getLength () - 1 );
|
||||
for($i = 0; $i < sizeof ( $ecdata [$r] ); $i ++)
|
||||
{
|
||||
$modIndex = $i + $modPoly->getLength () - sizeof ( $ecdata [$r] );
|
||||
$ecdata [$r] [$i] = ($modIndex >= 0) ? $modPoly->get ( $modIndex ) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
$totalCodeCount = 0;
|
||||
for($i = 0; $i < sizeof ( $rsBlocks ); $i ++)
|
||||
{
|
||||
$totalCodeCount += $rsBlocks [$i]->getTotalCount ();
|
||||
}
|
||||
|
||||
$data = QRUtil::getInstance ()->createEmptyArray ( $totalCodeCount );
|
||||
$index = 0;
|
||||
|
||||
for($i = 0; $i < $maxDcCount; $i ++)
|
||||
{
|
||||
for($r = 0; $r < sizeof ( $rsBlocks ); $r ++)
|
||||
{
|
||||
if ($i < sizeof ( $dcdata [$r] ))
|
||||
{
|
||||
$data [$index ++] = $dcdata [$r] [$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for($i = 0; $i < $maxEcCount; $i ++)
|
||||
{
|
||||
for($r = 0; $r < sizeof ( $rsBlocks ); $r ++)
|
||||
{
|
||||
if ($i < sizeof ( $ecdata [$r] ))
|
||||
{
|
||||
$data [$index ++] = $ecdata [$r] [$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A derived exception
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRCodeException extends ErrorException {};
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import necessary dependencies
|
||||
*/
|
||||
require_once 'QRCodeException.php';
|
||||
|
||||
/**
|
||||
* Derived exception class
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRCodeImageException extends QRCodeException{};
|
||||
|
||||
/**
|
||||
* This class provides all needed functionality to create an image out of an QRCode bitmap
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRCodeImage
|
||||
{
|
||||
/**
|
||||
* The previously created QRCode
|
||||
*
|
||||
* @var QRCode
|
||||
*/
|
||||
private $qrcode;
|
||||
|
||||
/**
|
||||
* The desired width of the destination image
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $width;
|
||||
|
||||
/**
|
||||
* The desired height of the destination image
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $height;
|
||||
|
||||
/**
|
||||
* Quality of the destination image
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $quality;
|
||||
|
||||
/**
|
||||
* The image buffer provided by GD function imagecreate()
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $img;
|
||||
|
||||
/**
|
||||
* Create a new QRCodeImage instance
|
||||
*
|
||||
* @param QRCode $qrcode The previously created QRCode
|
||||
* @param int $width The desired width of the destination image
|
||||
* @param int $height The desired height of the destination image
|
||||
* @param int $quality The desired quality of the destination image
|
||||
*/
|
||||
public function __construct(QRCode $qrcode, $width, $height, $quality = 90)
|
||||
{
|
||||
$this->qrcode = $qrcode;
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
$this->quality = $quality;
|
||||
$this->img = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the image
|
||||
*/
|
||||
public function draw()
|
||||
{
|
||||
$moduleCount = $this->qrcode->getModuleCount();
|
||||
$tileWidth = $this->width / $moduleCount;
|
||||
$tileHeight = $this->height / $moduleCount;
|
||||
|
||||
$this->img = imagecreatetruecolor($this->width, $this->height);
|
||||
|
||||
if($this->img)
|
||||
{
|
||||
$fg = imagecolorallocate($this->img, 0, 0, 0);
|
||||
if($fg === false)
|
||||
{
|
||||
$this->finish();
|
||||
throw new QRCodeImageException('Could not allocate foreground color!');
|
||||
}
|
||||
$bg = imagecolorallocate($this->img, 255, 255, 255);
|
||||
if($bg === false)
|
||||
{
|
||||
$this->finish();
|
||||
throw new QRCodeImageException('Could not allocate background color!');
|
||||
}
|
||||
|
||||
for($row = 0; $row < $moduleCount; $row++)
|
||||
{
|
||||
for($col = 0; $col < $moduleCount; $col++)
|
||||
{
|
||||
$fillStyle = $this->qrcode->isDark($row, $col) ? $fg : $bg;
|
||||
|
||||
$x = round($col * $tileWidth);
|
||||
$y = round($row * $tileHeight);
|
||||
$w = (ceil(($col + 1) * $tileWidth) - floor($col * $tileWidth));
|
||||
if($x + $w > $this->width)
|
||||
{
|
||||
$w = $this->width - $x;
|
||||
}
|
||||
$h = (ceil(($row + 1) * $tileWidth) - floor($row * $tileWidth));
|
||||
if($y + $h > $this->height)
|
||||
{
|
||||
$h = $this->height - $y;
|
||||
}
|
||||
|
||||
if(!imagefilledrectangle($this->img, $x, $y, $x + $w, $y + $h, $fillStyle))
|
||||
{
|
||||
$this->finish();
|
||||
throw new QRCodeImageException(sprintf('Could not fill the rectangle using desired coordinates (x = %d, y = %d, w = %d, h = %d, c = %d)',
|
||||
$x, $y, $w, $h, $fillStyle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QRCodeImageException('Could not create true color image buffer!');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the image
|
||||
*
|
||||
* @param string $filename
|
||||
*/
|
||||
public function store($filename)
|
||||
{
|
||||
if($this->img)
|
||||
{
|
||||
if(!imagejpeg($this->img, $filename, $this->quality))
|
||||
{
|
||||
throw new QRCodeImageException(sprintf('Could not save image to file %s', $filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the image as string
|
||||
*/
|
||||
public function getImage()
|
||||
{
|
||||
if($this->img)
|
||||
{
|
||||
ob_start();
|
||||
if(!imagejpeg($this->img, null, $this->quality))
|
||||
{
|
||||
ob_end_flush();
|
||||
throw new QRCodeImageException('Could not create a jpeg out of the image buffer!');
|
||||
}
|
||||
$out = ob_get_clean();
|
||||
return $out;
|
||||
}
|
||||
throw new QRCodeImageException('No image data available!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the image buffer
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
if($this->img)
|
||||
{
|
||||
imagedestroy($this->img);
|
||||
$this->img = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Error correct level enumeration
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
abstract class QRErrorCorrectLevel
|
||||
{
|
||||
const L = 1;
|
||||
const M = 0;
|
||||
const Q = 3;
|
||||
const H = 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import necessary dependencies
|
||||
*/
|
||||
require_once 'QRCodeException.php';
|
||||
|
||||
/**
|
||||
* Derived exception
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRMathException extends QRCodeException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* QR Code math helper class
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
final class QRMath
|
||||
{
|
||||
/**
|
||||
* Exponent table
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $EXP_TABLE = null;
|
||||
|
||||
/**
|
||||
* Logarithm table
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $LOG_TABLE = null;
|
||||
|
||||
/**
|
||||
* Singleton pattern
|
||||
*
|
||||
* @var QRMath
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Singleton pattern
|
||||
*
|
||||
* @return QRMath Singleton
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (! self::$instance)
|
||||
{
|
||||
self::$instance = new self ();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of QRMath
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
$this->init ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the tables
|
||||
*/
|
||||
private function init()
|
||||
{
|
||||
$this->EXP_TABLE = array ();
|
||||
for($i = 0; $i < 8; $i ++)
|
||||
{
|
||||
$this->EXP_TABLE [$i] = 1 << $i;
|
||||
}
|
||||
|
||||
for($i = 8; $i < 256; $i ++)
|
||||
{
|
||||
$this->EXP_TABLE [$i] = $this->EXP_TABLE [$i - 4] ^ $this->EXP_TABLE [$i - 5] ^ $this->EXP_TABLE [$i - 6] ^ $this->EXP_TABLE [$i - 8];
|
||||
}
|
||||
|
||||
$this->LOG_TABLE = array ();
|
||||
for($i = 0; $i < 255; $i ++)
|
||||
{
|
||||
$this->LOG_TABLE [$this->EXP_TABLE [$i]] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get logarithm of n
|
||||
*
|
||||
* @param int $n
|
||||
* @throws QRMathException
|
||||
* @return int
|
||||
*/
|
||||
public function glog($n)
|
||||
{
|
||||
if ($n < 1)
|
||||
{
|
||||
throw new QRMathException ( "glog(" . $n . ")" );
|
||||
}
|
||||
|
||||
foreach ( $this->LOG_TABLE as $key => $value )
|
||||
{
|
||||
if ($key == $n)
|
||||
return $value;
|
||||
}
|
||||
|
||||
throw new QRMathException ( "glog($n)" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the exponent of n
|
||||
*
|
||||
* @param int $n
|
||||
* @return int
|
||||
*/
|
||||
public function gexp($n)
|
||||
{
|
||||
while ( $n < 0 )
|
||||
{
|
||||
$n += 255;
|
||||
}
|
||||
while ( $n >= 256 )
|
||||
{
|
||||
$n -= 255;
|
||||
}
|
||||
foreach ( $this->EXP_TABLE as $key => $value )
|
||||
{
|
||||
if ($key == $n)
|
||||
return $value;
|
||||
}
|
||||
|
||||
throw new QRMathException ( "gexp($n)" );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* QRCode mode enumeration
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
abstract class QRMode
|
||||
{
|
||||
const MODE_NUMBER = 1;
|
||||
const MODE_ALPHA_NUM = 2;
|
||||
const MODE_8BIT_BYTE = 4;
|
||||
const MODE_KANJI = 8;
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import necessary dependencies
|
||||
*/
|
||||
require_once 'QRUtil.php';
|
||||
require_once 'QRMath.php';
|
||||
require_once 'QRCodeException.php';
|
||||
|
||||
/**
|
||||
* Derived exception
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRPolynominalException extends QRCodeException{};
|
||||
|
||||
/**
|
||||
* The purpose of this class is to provide a polynominal implementation for the QRCode package
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRPolynominal
|
||||
{
|
||||
/**
|
||||
* Bitmap
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $num;
|
||||
|
||||
/**
|
||||
* Create a new QRPolynominal instance
|
||||
*
|
||||
* @param array $num
|
||||
* @param int $shift
|
||||
*
|
||||
* @throws QRPolynominalException
|
||||
*/
|
||||
public function __construct($num, $shift)
|
||||
{
|
||||
if(sizeof($num) == 0)
|
||||
{
|
||||
throw new QRPolynominalException("Invalid num size");
|
||||
}
|
||||
|
||||
$offset = 0;
|
||||
while($offset < sizeof($num) && $num[$offset] == 0)
|
||||
{
|
||||
$offset++;
|
||||
}
|
||||
|
||||
$this->num = QRUtil::getInstance()->createEmptyArray(sizeof($num) - $offset + $shift);
|
||||
for($i = 0; $i < sizeof($num) - $offset; $i++)
|
||||
{
|
||||
$this->num[$i] = $num[$i + $offset];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a particular bitmap index
|
||||
*
|
||||
* @param int $index
|
||||
* @return multitype:
|
||||
*/
|
||||
public function get($index)
|
||||
{
|
||||
return $this->num[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of bitmap
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
return sizeof($this->num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply another polynom against this
|
||||
*
|
||||
* @param QRPolynominal $e The other
|
||||
* @return QRPolynominal The multiplied result
|
||||
*/
|
||||
public function multiply(QRPolynominal $e)
|
||||
{
|
||||
$num = QRUtil::getInstance()->createEmptyArray($this->getLength() + $e->getLength() - 1);
|
||||
|
||||
for($i = 0; $i < $this->getLength(); $i++)
|
||||
{
|
||||
for($j = 0; $j < $e->getLength(); $j++)
|
||||
{
|
||||
$a = QRMath::getInstance()->glog($this->get($i));
|
||||
$b = QRMath::getInstance()->glog($e->get($j));
|
||||
|
||||
$base = 0;
|
||||
if(isset($num[$i + $j]))
|
||||
$base = $num[$i + $j];
|
||||
$num[$i + $j] = $base ^ QRMath::getInstance()->gexp( $a + $b );
|
||||
}
|
||||
}
|
||||
|
||||
return new QRPolynominal($num, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform modulus against another polynom
|
||||
*
|
||||
* @param QRPolynominal $e
|
||||
*
|
||||
* @return QRPolynominal
|
||||
*/
|
||||
public function mod(QRPolynominal $e)
|
||||
{
|
||||
if($this->getLength() - $e->getLength() < 0)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
$ratio = QRMath::getInstance()->glog($this->get(0)) - QRMath::getInstance()->glog($e->get(0));
|
||||
|
||||
$num = QRUtil::getInstance()->createEmptyArray($this->getLength());
|
||||
|
||||
for($i = 0; $i < $this->getLength(); $i++)
|
||||
{
|
||||
$num[$i] = $this->get($i);
|
||||
}
|
||||
|
||||
for($i = 0; $i < $e->getLength(); $i++)
|
||||
{
|
||||
$num[$i] ^= QRMath::getInstance()->gexp(QRMath::getInstance()->glog($e->get($i)) + $ratio);
|
||||
}
|
||||
|
||||
$result = new QRPolynominal($num, 0);
|
||||
$result = $result->mod($e);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,503 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import necessary dependencies
|
||||
*/
|
||||
require_once 'QRCodeException.php';
|
||||
require_once 'QRErrorCorrectLevel.php';
|
||||
|
||||
/**
|
||||
* Derived exception class
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRRSBlockException extends QRCodeException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is a Reed-Solomon implementation for the QRCode.
|
||||
* The purpose is to provide error correction and block information.
|
||||
*
|
||||
* Inspired by qrcode.js from https://github.com/jeromeetienne/jquery-qrcode
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
* @link http://www.thonky.com/qr-code-tutorial/error-correction-table/
|
||||
*/
|
||||
class QRRSBlock
|
||||
{
|
||||
/**
|
||||
* The total count of blocks
|
||||
*
|
||||
* @var int The total count of blocks
|
||||
*/
|
||||
private $totalCount;
|
||||
|
||||
/**
|
||||
* The data count of blocks
|
||||
*
|
||||
* @var int The data count of blocks
|
||||
*/
|
||||
private $dataCount;
|
||||
|
||||
/**
|
||||
* The block table
|
||||
* @var array The block table
|
||||
*/
|
||||
private $RS_BLOCK_TABLE;
|
||||
|
||||
/**
|
||||
* Singleton pattern
|
||||
*
|
||||
* @var QRRSBlock Singleton
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* The serialized block data for faster initialization
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $blockFileName = 'rsblock.dat';
|
||||
|
||||
/**
|
||||
* Singleton pattern
|
||||
*
|
||||
* @return QRRSBlock
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if(!self::$instance)
|
||||
{
|
||||
self::$instance = new self(0, 0);
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the data count
|
||||
*
|
||||
* @return int The data count
|
||||
*/
|
||||
public function getDataCount()
|
||||
{
|
||||
return $this->dataCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the total count
|
||||
*
|
||||
* @return int The total count
|
||||
*/
|
||||
public function getTotalCount()
|
||||
{
|
||||
return $this->totalCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new QR Reed-Solomon block instance
|
||||
*
|
||||
* @param int $totalCount The total count of blocks
|
||||
* @param int $dataCount The data count of blocks
|
||||
*/
|
||||
private function __construct($totalCount, $dataCount)
|
||||
{
|
||||
$this->initRsBlock();
|
||||
|
||||
$this->totalCount = $totalCount;
|
||||
$this->dataCount = $dataCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rs blocks of particular type and error correction level
|
||||
*
|
||||
* @param int $typeNumber
|
||||
* @param int $errorCorrectLevel
|
||||
* @throws QRRSBlockException
|
||||
* @return QRRSBlock
|
||||
*/
|
||||
public function getRSBlocks($typeNumber, $errorCorrectLevel)
|
||||
{
|
||||
$rsBlock = $this->getRsBlockTable($typeNumber, $errorCorrectLevel);
|
||||
|
||||
if(!$rsBlock)
|
||||
{
|
||||
throw new QRRSBlockException("Bad RS Block at type number " . $typeNumber . " / error correct level " . $errorCorrectLevel);
|
||||
}
|
||||
|
||||
$length = sizeof($rsBlock) / 3;
|
||||
|
||||
$list = array();
|
||||
|
||||
for($i = 0; $i < $length; $i++)
|
||||
{
|
||||
$count = $rsBlock[$i * 3 + 0];
|
||||
$totalCount = $rsBlock[$i * 3 + 1];
|
||||
$dataCount = $rsBlock[$i * 3 + 2];
|
||||
|
||||
for($j = 0; $j < $count; $j++)
|
||||
{
|
||||
array_push($list, new QRRSBlock($totalCount, $dataCount));
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reed-solomon block table
|
||||
*
|
||||
* @param int $typeNumber
|
||||
* @param int $errorCorrectLevel
|
||||
* @return int|NULL
|
||||
*/
|
||||
public function getRsBlockTable($typeNumber, $errorCorrectLevel)
|
||||
{
|
||||
switch ($errorCorrectLevel)
|
||||
{
|
||||
case QRErrorCorrectLevel::L:
|
||||
return $this->RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 0];
|
||||
case QRErrorCorrectLevel::M:
|
||||
return $this->RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 1];
|
||||
case QRErrorCorrectLevel::Q:
|
||||
return $this->RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 2];
|
||||
case QRErrorCorrectLevel::H:
|
||||
return $this->RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 3];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initialize the RS block
|
||||
*/
|
||||
private function initRsBlock()
|
||||
{
|
||||
if($this->loadBlockFile())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->RS_BLOCK_TABLE = array();
|
||||
|
||||
// L
|
||||
// M
|
||||
// Q
|
||||
// H
|
||||
|
||||
// 1
|
||||
$this->addRsBlock(array(1, 26, 19));
|
||||
$this->addRsBlock(array(1, 26, 16));
|
||||
$this->addRsBlock(array(1, 26, 13));
|
||||
$this->addRsBlock(array(1, 26, 9));
|
||||
|
||||
// 2
|
||||
$this->addRsBlock(array(1, 44, 34));
|
||||
$this->addRsBlock(array(1, 44, 28));
|
||||
$this->addRsBlock(array(1, 44, 22));
|
||||
$this->addRsBlock(array(1, 44, 16));
|
||||
|
||||
// 3
|
||||
$this->addRsBlock(array(1, 70, 55));
|
||||
$this->addRsBlock(array(1, 70, 44));
|
||||
$this->addRsBlock(array(2, 35, 17));
|
||||
$this->addRsBlock(array(2, 35, 13));
|
||||
|
||||
// 4
|
||||
$this->addRsBlock(array(1, 100, 80));
|
||||
$this->addRsBlock(array(2, 50, 32));
|
||||
$this->addRsBlock(array(2, 50, 24));
|
||||
$this->addRsBlock(array(4, 25, 9));
|
||||
|
||||
// 5
|
||||
$this->addRsBlock(array(1, 134, 108));
|
||||
$this->addRsBlock(array(2, 67, 43));
|
||||
$this->addRsBlock(array(2, 33, 15, 2, 34, 16));
|
||||
$this->addRsBlock(array(2, 33, 11, 2, 34, 12));
|
||||
|
||||
// 6
|
||||
$this->addRsBlock(array(2, 86, 68));
|
||||
$this->addRsBlock(array(4, 43, 27));
|
||||
$this->addRsBlock(array(4, 43, 19));
|
||||
$this->addRsBlock(array(4, 43, 15));
|
||||
|
||||
// 7
|
||||
$this->addRsBlock(array(2, 98, 78));
|
||||
$this->addRsBlock(array(4, 49, 31));
|
||||
$this->addRsBlock(array(2, 32, 14, 4, 33, 15));
|
||||
$this->addRsBlock(array(4, 39, 13, 1, 40, 14));
|
||||
|
||||
// 8
|
||||
$this->addRsBlock(array(2, 121, 97));
|
||||
$this->addRsBlock(array(2, 60, 38, 2, 61, 39));
|
||||
$this->addRsBlock(array(4, 40, 18, 2, 41, 19));
|
||||
$this->addRsBlock(array(4, 40, 14, 2, 41, 15));
|
||||
|
||||
// 9
|
||||
$this->addRsBlock(array(2, 146, 116));
|
||||
$this->addRsBlock(array(3, 58, 36, 2, 59, 37));
|
||||
$this->addRsBlock(array(4, 36, 16, 4, 37, 17));
|
||||
$this->addRsBlock(array(4, 36, 12, 4, 37, 13));
|
||||
|
||||
// 10
|
||||
$this->addRsBlock(array(2, 86, 68, 2, 87, 69));
|
||||
$this->addRsBlock(array(4, 69, 43, 1, 70, 44));
|
||||
$this->addRsBlock(array(6, 43, 19, 2, 44, 20));
|
||||
$this->addRsBlock(array(6, 43, 15, 2, 44, 16));
|
||||
|
||||
// 11
|
||||
$this->addRsBlock(array(4, 101, 81));
|
||||
$this->addRsBlock(array(1, 80, 50, 4, 81, 51));
|
||||
$this->addRsBlock(array(4, 50, 22, 4, 51, 23));
|
||||
$this->addRsBlock(array(3, 36, 12, 8, 37, 13));
|
||||
|
||||
// 12
|
||||
$this->addRsBlock(array(2, 116, 92, 2, 117, 93));
|
||||
$this->addRsBlock(array(6, 58, 36, 2, 59, 37));
|
||||
$this->addRsBlock(array(4, 46, 20, 6, 47, 21));
|
||||
$this->addRsBlock(array(7, 42, 14, 4, 43, 15));
|
||||
|
||||
// 13
|
||||
$this->addRsBlock(array(4, 133, 107));
|
||||
$this->addRsBlock(array(8, 59, 37, 1, 60, 38));
|
||||
$this->addRsBlock(array(8, 44, 20, 4, 45, 21));
|
||||
$this->addRsBlock(array(12, 33, 11, 4, 34, 12));
|
||||
|
||||
// 14
|
||||
$this->addRsBlock(array(3, 145, 115, 1, 146, 116));
|
||||
$this->addRsBlock(array(4, 64, 40, 5, 65, 41));
|
||||
$this->addRsBlock(array(11, 36, 16, 5, 37, 17));
|
||||
$this->addRsBlock(array(11, 36, 12, 5, 37, 13));
|
||||
|
||||
// 15
|
||||
$this->addRsBlock(array(5, 109, 87, 1, 110, 88));
|
||||
$this->addRsBlock(array(5, 65, 41, 5, 66, 42));
|
||||
$this->addRsBlock(array(5, 54, 24, 7, 55, 25));
|
||||
$this->addRsBlock(array(11, 36, 12));
|
||||
|
||||
// 16
|
||||
$this->addRsBlock(array(5, 122, 98, 1, 123, 99));
|
||||
$this->addRsBlock(array(7, 73, 45, 3, 74, 46));
|
||||
$this->addRsBlock(array(15, 43, 19, 2, 44, 20));
|
||||
$this->addRsBlock(array(3, 45, 15, 13, 46, 16));
|
||||
|
||||
// 17
|
||||
$this->addRsBlock(array(1, 135, 107, 5, 136, 108));
|
||||
$this->addRsBlock(array(10, 74, 46, 1, 75, 47));
|
||||
$this->addRsBlock(array(1, 50, 22, 15, 51, 23));
|
||||
$this->addRsBlock(array(2, 42, 14, 17, 43, 15));
|
||||
|
||||
// 18
|
||||
$this->addRsBlock(array(5, 150, 120, 1, 151, 121));
|
||||
$this->addRsBlock(array(9, 69, 43, 4, 70, 44));
|
||||
$this->addRsBlock(array(17, 50, 22, 1, 51, 23));
|
||||
$this->addRsBlock(array(2, 42, 14, 19, 43, 15));
|
||||
|
||||
// 19
|
||||
$this->addRsBlock(array(3, 141, 113, 4, 142, 114));
|
||||
$this->addRsBlock(array(3, 70, 44, 11, 71, 45));
|
||||
$this->addRsBlock(array(17, 47, 21, 4, 48, 22));
|
||||
$this->addRsBlock(array(9, 39, 13, 16, 40, 14));
|
||||
|
||||
// 20
|
||||
$this->addRsBlock(array(3, 135, 107, 5, 136, 108));
|
||||
$this->addRsBlock(array(3, 67, 41, 13, 68, 42));
|
||||
$this->addRsBlock(array(15, 54, 24, 5, 55, 25));
|
||||
$this->addRsBlock(array(15, 43, 15, 10, 44, 16));
|
||||
|
||||
// 21
|
||||
$this->addRsBlock(array(4, 144, 116, 4, 145, 117));
|
||||
$this->addRsBlock(array(17, 68, 42));
|
||||
$this->addRsBlock(array(17, 50, 22, 6, 51, 23));
|
||||
$this->addRsBlock(array(19, 46, 16, 6, 47, 17));
|
||||
|
||||
// 22
|
||||
$this->addRsBlock(array(2, 139, 111, 7, 140, 112));
|
||||
$this->addRsBlock(array(17, 74, 46));
|
||||
$this->addRsBlock(array(7, 54, 24, 16, 55, 25));
|
||||
$this->addRsBlock(array(34, 37, 13));
|
||||
|
||||
// 23
|
||||
$this->addRsBlock(array(4, 151, 121, 5, 152, 122));
|
||||
$this->addRsBlock(array(4, 75, 47, 14, 76, 48));
|
||||
$this->addRsBlock(array(11, 54, 24, 14, 55, 25));
|
||||
$this->addRsBlock(array(16, 45, 15, 14, 46, 16));
|
||||
|
||||
// 24
|
||||
$this->addRsBlock(array(6, 147, 117, 4, 148, 118));
|
||||
$this->addRsBlock(array(6, 73, 45, 14, 74, 46));
|
||||
$this->addRsBlock(array(11, 54, 24, 16, 55, 25));
|
||||
$this->addRsBlock(array(30, 46, 16, 2, 47, 17));
|
||||
|
||||
// 25
|
||||
$this->addRsBlock(array(8, 132, 106, 4, 133, 107));
|
||||
$this->addRsBlock(array(8, 75, 47, 13, 76, 48));
|
||||
$this->addRsBlock(array(7, 54, 24, 22, 55, 25));
|
||||
$this->addRsBlock(array(22, 45, 15, 13, 46, 16));
|
||||
|
||||
// 26
|
||||
$this->addRsBlock(array(10, 142, 114, 2, 143, 115));
|
||||
$this->addRsBlock(array(19, 74, 46, 4, 75, 47));
|
||||
$this->addRsBlock(array(28, 50, 22, 6, 51, 23));
|
||||
$this->addRsBlock(array(33, 46, 16, 4, 47, 17));
|
||||
|
||||
// 27
|
||||
$this->addRsBlock(array(8, 152, 122, 4, 153, 123));
|
||||
$this->addRsBlock(array(22, 73, 45, 3, 74, 46));
|
||||
$this->addRsBlock(array(8, 53, 23, 26, 54, 24));
|
||||
$this->addRsBlock(array(12, 45, 15, 28, 46, 16));
|
||||
|
||||
// 28
|
||||
$this->addRsBlock(array(3, 147, 117, 10, 148, 118));
|
||||
$this->addRsBlock(array(3, 73, 45, 23, 74, 46));
|
||||
$this->addRsBlock(array(4, 54, 24, 31, 55, 25));
|
||||
$this->addRsBlock(array(11, 45, 15, 31, 46, 16));
|
||||
|
||||
// 29
|
||||
$this->addRsBlock(array(7, 146, 116, 7, 147, 117));
|
||||
$this->addRsBlock(array(21, 73, 45, 7, 74, 46));
|
||||
$this->addRsBlock(array(1, 53, 23, 37, 54, 24));
|
||||
$this->addRsBlock(array(19, 45, 15, 26, 46, 16));
|
||||
|
||||
// 30
|
||||
$this->addRsBlock(array(5, 145, 115, 10, 146, 116));
|
||||
$this->addRsBlock(array(19, 75, 47, 10, 76, 48));
|
||||
$this->addRsBlock(array(15, 54, 24, 25, 55, 25));
|
||||
$this->addRsBlock(array(23, 45, 15, 25, 46, 16));
|
||||
|
||||
// 31
|
||||
$this->addRsBlock(array(13, 145, 115, 3, 146, 116));
|
||||
$this->addRsBlock(array(2, 74, 46, 29, 75, 47));
|
||||
$this->addRsBlock(array(42, 54, 24, 1, 55, 25));
|
||||
$this->addRsBlock(array(23, 45, 15, 28, 46, 16));
|
||||
|
||||
// 32
|
||||
$this->addRsBlock(array(17, 145, 115));
|
||||
$this->addRsBlock(array(10, 74, 46, 23, 75, 47));
|
||||
$this->addRsBlock(array(42, 54, 24, 1, 55, 25));
|
||||
$this->addRsBlock(array(23, 45, 15, 28, 46, 16));
|
||||
|
||||
// 33
|
||||
$this->addRsBlock(array(17, 145, 115, 1, 146, 116));
|
||||
$this->addRsBlock(array(14, 74, 46, 21, 75, 47));
|
||||
$this->addRsBlock(array(29, 54, 24, 19, 55, 25));
|
||||
$this->addRsBlock(array(11, 45, 15, 46, 46, 16));
|
||||
|
||||
// 34
|
||||
$this->addRsBlock(array(13, 145, 115, 6, 146, 116));
|
||||
$this->addRsBlock(array(14, 74, 46, 21, 75, 47));
|
||||
$this->addRsBlock(array(44, 54, 24, 7, 55, 25));
|
||||
$this->addRsBlock(array(59, 46, 16, 1, 47, 17));
|
||||
|
||||
// 35
|
||||
$this->addRsBlock(array(12, 151, 121, 7, 152, 122));
|
||||
$this->addRsBlock(array(12, 75, 47, 26, 76, 48));
|
||||
$this->addRsBlock(array(39, 54, 24, 14, 55, 25));
|
||||
$this->addRsBlock(array(22, 45, 15, 41, 46, 16));
|
||||
|
||||
// 36
|
||||
$this->addRsBlock(array(6, 151, 121, 14, 152, 122));
|
||||
$this->addRsBlock(array(6, 75, 47, 34, 76, 48));
|
||||
$this->addRsBlock(array(46, 54, 24, 10, 55, 25));
|
||||
$this->addRsBlock(array(2, 45, 15, 64, 46, 16));
|
||||
|
||||
// 37
|
||||
$this->addRsBlock(array(17, 152, 122, 4, 153, 123));
|
||||
$this->addRsBlock(array(29, 74, 46, 14, 75, 47));
|
||||
$this->addRsBlock(array(49, 54, 24, 10, 55, 25));
|
||||
$this->addRsBlock(array(24, 45, 15, 46, 46, 16));
|
||||
|
||||
// 38
|
||||
$this->addRsBlock(array(4, 152, 122, 18, 153, 123));
|
||||
$this->addRsBlock(array(13, 74, 46, 32, 75, 47));
|
||||
$this->addRsBlock(array(48, 54, 24, 14, 55, 25));
|
||||
$this->addRsBlock(array(42, 45, 15, 32, 46, 16));
|
||||
|
||||
// 39
|
||||
$this->addRsBlock(array(20, 147, 117, 4, 148, 118));
|
||||
$this->addRsBlock(array(40, 75, 47, 7, 76, 48));
|
||||
$this->addRsBlock(array(43, 54, 24, 22, 55, 25));
|
||||
$this->addRsBlock(array(10, 45, 15, 67, 46, 16));
|
||||
|
||||
// 40
|
||||
$this->addRsBlock(array(19, 148, 118, 6, 149, 119));
|
||||
$this->addRsBlock(array(18, 75, 47, 31, 76, 48));
|
||||
$this->addRsBlock(array(34, 54, 24, 34, 55, 25));
|
||||
$this->addRsBlock(array(20, 45, 15, 61, 46, 16));
|
||||
|
||||
$this->saveBlockFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new block information to the block
|
||||
*
|
||||
* @param array $block
|
||||
*/
|
||||
private function addRsBlock($block)
|
||||
{
|
||||
array_push($this->RS_BLOCK_TABLE, $block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute path to the block file
|
||||
* @return string
|
||||
*/
|
||||
private function getBlockFileAbsolute()
|
||||
{
|
||||
return sprintf("%s%s%s", dirname(__FILE__), DIRECTORY_SEPARATOR, $this->blockFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to load the block file
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function loadBlockFile()
|
||||
{
|
||||
$file = $this->getBlockFileAbsolute();
|
||||
|
||||
if(!file_exists($file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$serialized = file_get_contents($file);
|
||||
|
||||
if(!$serialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->RS_BLOCK_TABLE = unserialize($serialized);
|
||||
|
||||
if(!$this->RS_BLOCK_TABLE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to save the block file
|
||||
*/
|
||||
private function saveBlockFile()
|
||||
{
|
||||
$file = $this->getBlockFileAbsolute();
|
||||
|
||||
if(file_exists($file))
|
||||
{
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
file_put_contents($file, serialize($this->RS_BLOCK_TABLE));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,464 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of the phpQr package
|
||||
*
|
||||
* See @see QRCode class for description of package and license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Import necessary dependencies
|
||||
*/
|
||||
require_once 'QRCodeException.php';
|
||||
require_once 'QRPolynominal.php';
|
||||
|
||||
/**
|
||||
* Derived exception
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRUtilException extends QRCodeException {};
|
||||
|
||||
/**
|
||||
* Mask pattern enumeration
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
abstract class QRMaskPattern
|
||||
{
|
||||
const PATTERN000 = 0;
|
||||
const PATTERN001 = 1;
|
||||
const PATTERN010 = 2;
|
||||
const PATTERN011 = 3;
|
||||
const PATTERN100 = 4;
|
||||
const PATTERN101 = 5;
|
||||
const PATTERN110 = 6;
|
||||
const PATTERN111 = 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* The purpose of this class is to provide some common utility
|
||||
* functionality for the QRCode class and its parts.
|
||||
*
|
||||
* @author Maik Greubel <greubel@nkey.de>
|
||||
* @package phpQr
|
||||
*/
|
||||
class QRUtil
|
||||
{
|
||||
/**
|
||||
* Pattern position table
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $PATTERN_POSITION_TABLE = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int G15 pattern
|
||||
*/
|
||||
private $G15;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int G18 pattern
|
||||
*/
|
||||
private $G18;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int G15 mask pattern
|
||||
*/
|
||||
private $G15_MASK;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var QRUtil Singleton
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* Singleton pattern
|
||||
*
|
||||
* @return QRUtil
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if(!self::$instance)
|
||||
{
|
||||
self::$instance = new self;
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of QRUtil
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
$this->init();
|
||||
$this->G15 = ((1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0));
|
||||
$this->G18 = ((1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0));
|
||||
$this->G15_MASK = ((1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Bose-Chaudhuri-Hocquenghem code type info
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBCHTypeInfo($data)
|
||||
{
|
||||
$d = $data << 10;
|
||||
while($this->getBCHDigit($d) - $this->getBCHDigit($this->G15) >= 0)
|
||||
{
|
||||
$d ^= ($this->G15 << ($this->getBCHDigit($d) - $this->getBCHDigit($this->G15)));
|
||||
}
|
||||
|
||||
return (($data << 10) | $d) ^ $this->G15_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Bose-Chaudhuri-Hocquenghem code type number
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBCHTypeNumber($data)
|
||||
{
|
||||
$d = $data << 12;
|
||||
while($this->getBCHDigit($d) - $this->getBCHDigit($this->G18) >= 0)
|
||||
{
|
||||
$d ^= ($this->G18 << ($this->getBCHDigit($d) - $this->getBCHDigit($this->G18)));
|
||||
}
|
||||
return ($data << 12) | $d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Bose-Chaudhuri-Hocquenghem digit
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBCHDigit($data)
|
||||
{
|
||||
$digit = 0;
|
||||
while($data != 0)
|
||||
{
|
||||
$digit++;
|
||||
$data = $data >> 1;
|
||||
}
|
||||
|
||||
return $digit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pattern position
|
||||
*
|
||||
* @param int $typeNumber
|
||||
* @return array
|
||||
*/
|
||||
public function getPatternPosition($typeNumber)
|
||||
{
|
||||
return $this->PATTERN_POSITION_TABLE[$typeNumber - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to mask a bit
|
||||
*
|
||||
* @param int $maskPattern
|
||||
* @param int $i
|
||||
* @param int $j
|
||||
* @throws QRUtilException
|
||||
* @return boolean
|
||||
*/
|
||||
public function getMask($maskPattern, $i, $j)
|
||||
{
|
||||
switch($maskPattern)
|
||||
{
|
||||
case QRMaskPattern::PATTERN000: return ($i + $j) % 2 == 0;
|
||||
case QRMaskPattern::PATTERN001: return ($i % 2) == 0;
|
||||
case QRMaskPattern::PATTERN010: return ($j % 3) == 0;
|
||||
case QRMaskPattern::PATTERN011: return ($i + $j) % 3 == 0;
|
||||
case QRMaskPattern::PATTERN100: return (floor($i / 2) + floor($j / 3)) % 2 == 0;
|
||||
case QRMaskPattern::PATTERN101: return ($i * $j) % 2 + ($i * $j) % 3 == 0;
|
||||
case QRMaskPattern::PATTERN110: return (($i * $j) % 2 + ($i * $j) % 3) % 2 == 0;
|
||||
case QRMaskPattern::PATTERN111: return (($i * $j) % 3 + ($i + $j) % 2) % 2 == 0;
|
||||
|
||||
default: throw new QRUtilException("Bad mask pattern " . $maskPattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return error correction polynom
|
||||
*
|
||||
* @param int $errorCorrectLength
|
||||
* @return QRPolynominal
|
||||
*/
|
||||
public function getErrorCorrectPolynominal($errorCorrectLength)
|
||||
{
|
||||
$a = new QRPolynominal(array(1), 0);
|
||||
for($i = 0; $i < $errorCorrectLength; $i++)
|
||||
{
|
||||
$a = $a->multiply(new QRPolynominal(array(1, QRMath::getInstance()->gexp($i)), 0));
|
||||
}
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bitmap length in bits
|
||||
*
|
||||
* @param int $mode
|
||||
* @param int $type
|
||||
* @throws QRUtilException
|
||||
* @return int
|
||||
*/
|
||||
public function getLengthInBits($mode, $type)
|
||||
{
|
||||
// 1 - 9
|
||||
if(1 <= $type && $type < 10)
|
||||
{
|
||||
switch($mode)
|
||||
{
|
||||
case QRMode::MODE_NUMBER: return 10;
|
||||
case QRMode::MODE_ALPHA_NUM: return 9;
|
||||
case QRMode::MODE_8BIT_BYTE: return 8;
|
||||
case QRMode::MODE_KANJI: return 8;
|
||||
default: throw new QRUtilException("Bad mode " . $mode);
|
||||
}
|
||||
}
|
||||
// 10 - 26
|
||||
else if($type < 27)
|
||||
{
|
||||
switch($mode)
|
||||
{
|
||||
case QRMode::MODE_NUMBER: return 12;
|
||||
case QRMode::MODE_ALPHA_NUM: return 11;
|
||||
case QRMode::MODE_8BIT_BYTE: return 16;
|
||||
case QRMode::MODE_KANJI: return 10;
|
||||
default: throw new QRUtilException("Bad mode " . $mode);
|
||||
}
|
||||
}
|
||||
// 27 - 40
|
||||
else if($type < 41)
|
||||
{
|
||||
switch($mode)
|
||||
{
|
||||
case QRMode::MODE_NUMBER: return 14;
|
||||
case QRMode::MODE_ALPHA_NUM: return 13;
|
||||
case QRMode::MODE_8BIT_BYTE: return 16;
|
||||
case QRMode::MODE_KANJI: return 12;
|
||||
default: throw new QRUtilException("Bad mode " . $mode);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QRUtilException("Bad type " . $type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the lost point
|
||||
*
|
||||
* @param QRCode $qrCode
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
public function getLostPoint(QRCode $qrCode)
|
||||
{
|
||||
$moduleCount = $qrCode->getModuleCount();
|
||||
|
||||
$lostPoint = 0;
|
||||
|
||||
// Level 1
|
||||
for($row = 0; $row < $moduleCount; $row++)
|
||||
{
|
||||
for($col = 0; $col < $moduleCount; $col++)
|
||||
{
|
||||
$sameCount = 0;
|
||||
$dark = $qrCode->isDark($row, $col);
|
||||
|
||||
for($r = -1; $r <= 1; $r++)
|
||||
{
|
||||
if($row + $r < 0 || $moduleCount <= $row + $r)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for($c = -1; $c <= 1; $c++)
|
||||
{
|
||||
if($col + $c < 0 || $moduleCount <= $col + $c)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if($r == 0 && $c == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if($dark == $qrCode->isDark($row + $r, $col + $c))
|
||||
{
|
||||
$sameCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($sameCount > 5)
|
||||
{
|
||||
$lostPoint += (3 + $sameCount - 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Level 2
|
||||
for($row = 0; $row < $moduleCount - 1; $row++)
|
||||
{
|
||||
for($col = 0; $col < $moduleCount - 1; $col++)
|
||||
{
|
||||
$count = 0;
|
||||
if($qrCode->isDark($row, $col )) $count++;
|
||||
if($qrCode->isDark($row + 1, $col )) $count++;
|
||||
if($qrCode->isDark($row, $col + 1)) $count++;
|
||||
if($qrCode->isDark($row + 1, $col + 1)) $count++;
|
||||
if($count == 0 || $count == 4)
|
||||
{
|
||||
$lostPoint += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Level 3
|
||||
for($row = 0; $row < $moduleCount; $row++)
|
||||
{
|
||||
for($col = 0; $col < $moduleCount - 6; $col++)
|
||||
{
|
||||
if($qrCode->isDark($row, $col)
|
||||
&& !$qrCode->isDark($row, $col + 1)
|
||||
&& $qrCode->isDark($row, $col + 2)
|
||||
&& $qrCode->isDark($row, $col + 3)
|
||||
&& $qrCode->isDark($row, $col + 4)
|
||||
&& !$qrCode->isDark($row, $col + 5)
|
||||
&& $qrCode->isDark($row, $col + 6))
|
||||
{
|
||||
$lostPoint += 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for($col = 0; $col < $moduleCount; $col++)
|
||||
{
|
||||
for($row = 0; $row < $moduleCount - 6; $row++)
|
||||
{
|
||||
if($qrCode->isDark($row, $col)
|
||||
&& !$qrCode->isDark($row + 1, $col)
|
||||
&& $qrCode->isDark($row + 2, $col)
|
||||
&& $qrCode->isDark($row + 3, $col)
|
||||
&& $qrCode->isDark($row + 4, $col)
|
||||
&& !$qrCode->isDark($row + 5, $col)
|
||||
&& $qrCode->isDark($row + 6, $col))
|
||||
{
|
||||
$lostPoint += 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Level 4
|
||||
$darkCount = 0;
|
||||
|
||||
for($col = 0; $col < $moduleCount; $col++)
|
||||
{
|
||||
for($row = 0; $row < $moduleCount; $row++)
|
||||
{
|
||||
if($qrCode->isDark($row, $col))
|
||||
{
|
||||
$darkCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ratio = abs(100 * $darkCount / $moduleCount / $moduleCount - 50) / 5;
|
||||
$lostPoint += $ratio * 10;
|
||||
|
||||
return $lostPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the pattern position table
|
||||
*/
|
||||
private function init()
|
||||
{
|
||||
$this->PATTERN_POSITION_TABLE = array();
|
||||
|
||||
$this->addPattern(array());
|
||||
$this->addPattern(array(6, 18));
|
||||
$this->addPattern(array(6, 22));
|
||||
$this->addPattern(array(6, 26));
|
||||
$this->addPattern(array(6, 30));
|
||||
$this->addPattern(array(6, 34));
|
||||
$this->addPattern(array(6, 22, 38));
|
||||
$this->addPattern(array(6, 24, 42));
|
||||
$this->addPattern(array(6, 26, 46));
|
||||
$this->addPattern(array(6, 28, 50));
|
||||
$this->addPattern(array(6, 30, 54));
|
||||
$this->addPattern(array(6, 32, 58));
|
||||
$this->addPattern(array(6, 34, 62));
|
||||
$this->addPattern(array(6, 26, 46, 66));
|
||||
$this->addPattern(array(6, 26, 48, 70));
|
||||
$this->addPattern(array(6, 26, 50, 74));
|
||||
$this->addPattern(array(6, 30, 54, 78));
|
||||
$this->addPattern(array(6, 30, 56, 82));
|
||||
$this->addPattern(array(6, 30, 58, 86));
|
||||
$this->addPattern(array(6, 34, 62, 90));
|
||||
$this->addPattern(array(6, 28, 50, 72, 94));
|
||||
$this->addPattern(array(6, 26, 50, 74, 98));
|
||||
$this->addPattern(array(6, 30, 54, 78, 102));
|
||||
$this->addPattern(array(6, 28, 54, 80, 106));
|
||||
$this->addPattern(array(6, 32, 58, 84, 110));
|
||||
$this->addPattern(array(6, 30, 58, 86, 114));
|
||||
$this->addPattern(array(6, 34, 62, 90, 118));
|
||||
$this->addPattern(array(6, 26, 50, 74, 98, 122));
|
||||
$this->addPattern(array(6, 30, 54, 78, 102, 126));
|
||||
$this->addPattern(array(6, 26, 52, 78, 104, 130));
|
||||
$this->addPattern(array(6, 30, 56, 82, 108, 134));
|
||||
$this->addPattern(array(6, 34, 60, 86, 112, 138));
|
||||
$this->addPattern(array(6, 30, 58, 86, 114, 142));
|
||||
$this->addPattern(array(6, 34, 62, 90, 118, 146));
|
||||
$this->addPattern(array(6, 30, 54, 78, 102, 126, 150));
|
||||
$this->addPattern(array(6, 24, 50, 76, 102, 128, 154));
|
||||
$this->addPattern(array(6, 28, 54, 80, 106, 132, 158));
|
||||
$this->addPattern(array(6, 32, 58, 84, 110, 136, 162));
|
||||
$this->addPattern(array(6, 26, 54, 82, 110, 138, 166));
|
||||
$this->addPattern(array(6, 30, 58, 86, 114, 142, 170));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a pattern to the pattern position table
|
||||
*
|
||||
* @param array $d
|
||||
*/
|
||||
private function addPattern($d)
|
||||
{
|
||||
array_push($this->PATTERN_POSITION_TABLE, $d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty array of n elements
|
||||
*
|
||||
* All elements are uninitialed.
|
||||
*
|
||||
* @param int $numElements
|
||||
* @return array
|
||||
*/
|
||||
public function createEmptyArray($numElements)
|
||||
{
|
||||
return array_fill(0, $numElements, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
phpQr - A QRCode encoder class
|
||||
===
|
||||
|
||||
by Maik Greubel (greubel@nkey.de)
|
||||
|
||||
The intention to create a basic qrcode encoder for PHP was a request on phpclasses.org.
|
||||
-
|
||||
|
||||
The author studied multiple sources to get an idea how qrcode implementation works under the hood.
|
||||
The best source was the JavaScript library jquery which provides a HTML Table based implementation.
|
||||
See source and documentation at <https://github.com/jeromeetienne/jquery-qrcode>
|
||||
|
||||
So the hard work was already done by Jerome Etienne. My part was only to port it to PHP code.
|
||||
|
||||
Currently this package does not have the capability to read QRCodes.
|
||||
|
||||
Further readings
|
||||
-
|
||||
For a detailed description of QRCode and its features please check <http://www.qrcode.com/>
|
||||
|
||||
Trademark information
|
||||
-
|
||||
|
||||
QR Code is registered trademark of
|
||||
DENSO WAVE INCORPORATED <http://www.denso-wave.com/qrcode/faqpatent-e.html>
|
||||
|
||||
License
|
||||
-
|
||||
All files in the package are published under the terms of the BSD 2 License. <http://opensource.org/licenses/BSD-2-Clause>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue