:octocat:

This commit is contained in:
smiley
2015-12-01 17:55:20 +01:00
commit b8606b24da
21 changed files with 2314 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
#################
## PHPStorm
#################
.idea/
#################
## Eclipse
#################
.settings/
.buildpath
.project
#################
## Misc
#################
pdoc.bat
composer.lock
docs
vendor
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Smiley <smiley@chillerlan.net>
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.
+7
View File
@@ -0,0 +1,7 @@
# codemasher/php-qrcode
[![Packagist](https://img.shields.io/packagist/v/codemasher/php-qrcode.svg?style=flat-square)](https://packagist.org/packages/codemasher/php-qrcode)
[![License](https://img.shields.io/packagist/l/codemasher/php-qrcode.svg?style=flat-square)](LICENSE)
## Requirements
- PHP 5.6+, PHP 7
+24
View File
@@ -0,0 +1,24 @@
{
"name": "codemasher/php-qrcode",
"description": "A QR code generator. PHP 5.6+, PHP 7",
"homepage": "https://github.com/codemasher/php-qrcode",
"license": "MIT",
"keywords": [
"QR code",
"library"
],
"authors": [
{
"name": "Smiley",
"email": "smiley@chillerlan.net"
}
],
"require": {
"php": ">=5.6.0"
},
"autoload": {
"psr-4": {
"codemasher\\QRCode\\": "src/"
}
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
require_once '../vendor/autoload.php';
use codemasher\QRCode\QRCode;
use codemasher\QRCode\QRConst;
$qrcode = new QRCode;
$qr = $qrcode->getMinimumQRCode('イメージ作成(引数:サイズ,マージン', QRConst::ERROR_CORRECT_LEVEL_L);
header('Content-type: text/plain');
$m = $qr->getModuleCount();
for($row = 0; $row < $m; $row++){
for($col = 0; $col < $m; $col++){
echo $qr->isDark($row, $col) ? '#' : ' ';
}
echo PHP_EOL;
}
+42
View File
@@ -0,0 +1,42 @@
<?php
require_once '../vendor/autoload.php';
use codemasher\QRCode\QRCode;
use codemasher\QRCode\QRConst;
//---------------------------------------------------------
$qrcode = new QRCode;
print('<h4>明示的に型番を指定</h4>');
// エラー訂正レベルを設定
// QR_ERROR_CORRECT_LEVEL_L : 7%
// QR_ERROR_CORRECT_LEVEL_M : 15%
// QR_ERROR_CORRECT_LEVEL_Q : 25%
// QR_ERROR_CORRECT_LEVEL_H : 30%
$qrcode->setErrorCorrectLevel(QRConst::ERROR_CORRECT_LEVEL_L);
// 型番(大きさ)を設定
// 110
$qrcode->setTypeNumber(3);
// データ(文字列※)を設定
// ※日本語はSJIS
$qrcode->addData('QRコード');
// QRコードを作成
$qrcode->make();
// HTML出力
$qrcode->printHTML();
//---------------------------------------------------------
print('<h4>型番自動</h4>');
// 型番が最小となるQRコードを作成
$qr = $qrcode->getMinimumQRCode('QRコード', QRConst::ERROR_CORRECT_LEVEL_L);
// HTML出力
$qr->printHTML();
+18
View File
@@ -0,0 +1,18 @@
<?php
require_once '../vendor/autoload.php';
use codemasher\QRCode\QRCode;
use codemasher\QRCode\QRConst;
$qrcode = new QRCode;
$qr = $qrcode->getMinimumQRCode('QRコード', QRConst::ERROR_CORRECT_LEVEL_L);
// イメージ作成(引数:サイズ,マージン)
$im = $qr->createImage(2, 4);
header('Content-type: image/png');
imagepng($im);
imagedestroy($im);
+92
View File
@@ -0,0 +1,92 @@
<?php
/**
*
* @filesource BitBuffer.php
* @created 25.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode;
/**
* Class BitBuffer
*/
class BitBuffer{
/**
* @var array
*/
protected $buffer = [];
/**
* @var int
*/
protected $length = 0;
/**
* @return array
*/
public function getBuffer(){
return $this->buffer;
}
/**
* @return int
*/
public function getLengthInBits(){
return $this->length;
}
/**
* @return string
*/
public function __toString(){
$buffer = '';
for($i = 0; $i < $this->getLengthInBits(); $i++){
$buffer .= $this->get($i) ? '1' : '0';
}
return $buffer;
}
/**
* @param $index
*
* @return bool
*/
public function get($index){
return (($this->buffer[(int)floor($index / 8)] >> (7 - $index % 8))&1) === 1;
}
/**
* @param $num
* @param $length
*/
public function put($num, $length){
for($i = 0; $i < $length; $i++){
$this->putBit((($num >> ($length - $i - 1))&1) === 1);
}
}
/**
* @param $bit
*/
public function putBit($bit){
$bufIndex = floor($this->length / 8);
if(count($this->buffer) <= $bufIndex){
$this->buffer[] = 0;
}
if($bit){
$this->buffer[(int)$bufIndex] |= (0x80 >> ($this->length % 8));
}
$this->length++;
}
}
+106
View File
@@ -0,0 +1,106 @@
<?php
/**
*
* @filesource AlphaNum.php
* @created 25.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode\Data;
use codemasher\QRCode\BitBuffer;
use codemasher\QRCode\Data;
use codemasher\QRCode\Data\QRDataBase;
use codemasher\QRCode\Data\QRDataInterface;
use codemasher\QRCode\QRCodeException;
use codemasher\QRCode\QRConst;
/**
* Class AlphaNum
*/
class AlphaNum extends QRDataBase implements QRDataInterface{
/**
* AlphaNum constructor.
*
* @param $data
*/
public function __construct($data){
parent::__construct($data, QRConst::MODE_ALPHA_NUM);
}
/**
* @param $buffer
*/
public function write(BitBuffer &$buffer){
$i = 0;
$c = $this->getData();
while($i + 1 < strlen($c)){
$buffer->put($this->getCode(ord($c[$i])) * 45
+ $this->getCode(ord($c[$i + 1])), 11);
$i += 2;
}
if($i < strlen($c)){
$buffer->put($this->getCode(ord($c[$i])), 6);
}
}
/**
* @return int
*/
public function getLength(){
return strlen($this->getData());
}
/**
* @param $c
*
* @return int
* @throws \codemasher\QRCode\QRCodeException
*/
protected function getCode($c){
if($this->util->toCharCode('0') <= $c
&& $c <= $this->util->toCharCode('9')
){
return $c - $this->util->toCharCode('0');
}
else if($this->util->toCharCode('A') <= $c
&& $c <= $this->util->toCharCode('Z')
){
return $c - $this->util->toCharCode('A') + 10;
}
else{
switch($c){
case $this->util->toCharCode(' ') :
return 36;
case $this->util->toCharCode('$') :
return 37;
case $this->util->toCharCode('%') :
return 38;
case $this->util->toCharCode('*') :
return 39;
case $this->util->toCharCode('+') :
return 40;
case $this->util->toCharCode('-') :
return 41;
case $this->util->toCharCode('.') :
return 42;
case $this->util->toCharCode('/') :
return 43;
case $this->util->toCharCode(':') :
return 44;
default :
throw new QRCodeException('illegal char: '.$c);
}
}
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
/**
*
* @filesource EightBitByte.php
* @created 25.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode\Data;
use codemasher\QRCode\BitBuffer;
use codemasher\QRCode\QRConst;
use codemasher\QRCode\Data\QRDataBase;
use codemasher\QRCode\Data\QRDataInterface;
/**
* Class EightBitByte
*/
class EightBitByte extends QRDataBase implements QRDataInterface{
/**
* EightBitByte constructor.
*
* @param $data
*/
public function __construct($data){
parent::__construct($data, QRConst::MODE_8BIT_BYTE);
}
/**
* @param $buffer
*/
public function write(BitBuffer &$buffer){
$data = $this->getData();
for($i = 0; $i < strlen($data); $i++){
$buffer->put(ord($data[$i]), 8);
}
}
/**
* @return int
*/
public function getLength(){
return strlen($this->getData());
}
}
+72
View File
@@ -0,0 +1,72 @@
<?php
/**
*
* @filesource Kanji.php
* @created 25.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode\Data;
use codemasher\QRCode\BitBuffer;
use codemasher\QRCode\Data\QRDataBase;
use codemasher\QRCode\Data\QRDataInterface;
use codemasher\QRCode\QRCodeException;
use codemasher\QRCode\QRConst;
/**
* Class Kanji
*/
class Kanji extends QRDataBase implements QRDataInterface{
/**
* Kanji constructor.
*
* @param $data
*/
public function __construct($data){
parent::__construct($data, QRConst::MODE_KANJI);
}
/**
* @param $buffer
*
* @throws \codemasher\QRCode\QRCodeException
*/
public function write(BitBuffer &$buffer){
$data = $this->getData();
$i = 0;
while($i + 1 < strlen($data)){
$c = ((0xff&ord($data[$i])) << 8)|(0xff&ord($data[$i + 1]));
if(0x8140 <= $c && $c <= 0x9FFC){
$c -= 0x8140;
}
else if(0xE040 <= $c && $c <= 0xEBBF){
$c -= 0xC140;
}
else{
throw new QRCodeException('illegal char at '.($i + 1).' ('.$c.')');
}
$c = (($c >> 8)&0xff) * 0xC0 + ($c&0xff);
$buffer->put($c, 13);
$i += 2;
}
if($i < strlen($data)){
throw new QRCodeException('illegal char at '.($i + 1));
}
}
/**
* @return float
*/
public function getLength(){
return floor(strlen($this->getData()) / 2);
}
}
+101
View File
@@ -0,0 +1,101 @@
<?php
/**
*
* @filesource Number.php
* @created 26.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode\Data;
use codemasher\QRCode\BitBuffer;
use codemasher\QRCode\Data\QRDataBase;
use codemasher\QRCode\Data\QRDataInterface;
use codemasher\QRCode\QRCodeException;
use codemasher\QRCode\QRConst;
/**
* Class Number
*/
class Number extends QRDataBase implements QRDataInterface{
/**
* @var \codemasher\QRCode\Util
*/
protected $util;
/**
* Number constructor.
*
* @param $data
*/
public function __construct($data){
parent::__construct($data, QRConst::MODE_NUMBER);
}
/**
* @param $buffer
*/
public function write(BitBuffer &$buffer){
$data = $this->getData();
$i = 0;
while($i + 2 < strlen($data)){
$num = $this->parseInt(substr($data, $i, 3));
$buffer->put($num, 10);
$i += 3;
}
if($i < strlen($data)){
if(strlen($data) - $i == 1){
$num = $this->parseInt(substr($data, $i, $i + 1));
$buffer->put($num, 4);
}
else if(strlen($data) - $i == 2){
$num = $this->parseInt(substr($data, $i, $i + 2));
$buffer->put($num, 7);
}
}
}
/**
* @return int
*/
public function getLength(){
return strlen($this->getData());
}
/**
* @param $s
*
* @return int
*/
protected function parseInt($s){
$num = 0;
for($i = 0; $i < strlen($s); $i++){
$num = $num * 10 + $this->parseIntAt(ord($s[$i]));
}
return $num;
}
/**
* @param $c
*
* @return mixed
* @throws \codemasher\QRCode\QRCodeException
*/
protected function parseIntAt($c){
if($this->util->toCharCode('0') <= $c && $c <= $this->util->toCharCode('9')){
return $c - $this->util->toCharCode('0');
}
throw new QRCodeException('illegal char: '.$c);
}
}
+132
View File
@@ -0,0 +1,132 @@
<?php
/**
*
* @filesource QRDataBase.php
* @created 25.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode\Data;
use codemasher\QRCode\BitBuffer;
use codemasher\QRCode\QRConst;
use codemasher\QRCode\QRCodeException;
use codemasher\QRCode\Util;
/**
* Class QRDataBase
*/
class QRDataBase{
/**
* @var
*/
protected $mode;
/**
* @var
*/
protected $data;
/**
* @var \codemasher\QRCode\Util
*/
protected $util;
/**
* QRDataBase constructor.
*
* @param $data
* @param $mode
*/
public function __construct($data, $mode){
$this->data = $data;
$this->mode = $mode;
$this->util = new Util;
}
/**
* @return mixed
*/
public function getMode(){
return $this->mode;
}
/**
* @return mixed
*/
public function getData(){
return $this->data;
}
/**
* @throws \codemasher\QRCode\QRCodeException
*/
public function getLength(){
throw new QRCodeException('not implemented.');
}
/**
* @param $buffer
*
* @throws \codemasher\QRCode\QRCodeException
*/
public function write(BitBuffer &$buffer){
throw new QRCodeException('not implemented.');
}
/**
* @param $type
*
* @return int
* @throws \codemasher\QRCode\QRCodeException
*/
public function getLengthInBits($type){
if(1 <= $type && $type < 10){
// 1 - 9
switch($this->mode){
case QRConst::MODE_NUMBER : return 10;
case QRConst::MODE_ALPHA_NUM : return 9;
case QRConst::MODE_8BIT_BYTE : return 8;
case QRConst::MODE_KANJI : return 8;
default :
throw new QRCodeException('mode: '.$this->mode);
}
}
else if($type < 27){
// 10 - 26
switch($this->mode){
case QRConst::MODE_NUMBER : return 12;
case QRConst::MODE_ALPHA_NUM : return 11;
case QRConst::MODE_8BIT_BYTE : return 16;
case QRConst::MODE_KANJI : return 10;
default :
throw new QRCodeException('mode: '.$this->mode);
}
}
else if($type < 41){
// 27 - 40
switch($this->mode){
case QRConst::MODE_NUMBER : return 14;
case QRConst::MODE_ALPHA_NUM : return 13;
case QRConst::MODE_8BIT_BYTE : return 16;
case QRConst::MODE_KANJI : return 12;
default :
throw new QRCodeException('mode: '.$this->mode);
}
}
else{
throw new QRCodeException('mode: '.$this->mode);
}
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
/**
*
* @filesource QRDataInterface.php
* @created 01.12.2015
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode\Data;
use codemasher\QRCode\BitBuffer;
/**
* Interface QRDataInterface
*/
interface QRDataInterface{
/**
* @param \codemasher\QRCode\BitBuffer $buffer
*/
public function write(BitBuffer &$buffer);
/**
* @return int
*/
public function getLength();
/**
* @return mixed
*/
public function getData();
/**
* @return mixed
*/
public function getMode();
/**
* @param $type
*
* @return int
* @throws \codemasher\QRCode\QRCodeException
*/
public function getLengthInBits($type);
}
+104
View File
@@ -0,0 +1,104 @@
<?php
/**
*
* @filesource Math.php
* @created 25.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode;
use codemasher\QRCode\QRCodeException;
/**
* Class Math
*/
class Math{
/**
* @var array
*/
protected $QR_MATH_EXP_TABLE;
/**
* @var array
*/
protected $QR_MATH_LOG_TABLE;
/**
* Math constructor.
*/
public function __construct(){
$this->QR_MATH_EXP_TABLE = $this->createNumArray(256);
for($i = 0; $i < 8; $i++){
$this->QR_MATH_EXP_TABLE[$i] = 1 << $i;
}
for($i = 8; $i < 256; $i++){
$this->QR_MATH_EXP_TABLE[$i] =
$this->QR_MATH_EXP_TABLE[$i - 4]
^$this->QR_MATH_EXP_TABLE[$i - 5]
^$this->QR_MATH_EXP_TABLE[$i - 6]
^$this->QR_MATH_EXP_TABLE[$i - 8];
}
$this->QR_MATH_LOG_TABLE = $this->createNumArray(256);
for($i = 0; $i < 255; $i++){
$this->QR_MATH_LOG_TABLE[$this->QR_MATH_EXP_TABLE[$i]] = $i;
}
}
/**
* @param int $length
*
* @return array
*/
public function createNumArray($length){
$num_array = [];
for($i = 0; $i < $length; $i++){
$num_array[] = 0;
}
return $num_array;
}
/**
* @param int $n
*
* @return mixed
* @throws \codemasher\QRCode\QRCodeException
*/
public function glog($n){
if($n < 1){
throw new QRCodeException('log('.$n.')');
}
return $this->QR_MATH_LOG_TABLE[$n];
}
/**
* @param int $n
*
* @return mixed
*/
public function gexp($n){
while($n < 0){
$n += 255;
}
while($n >= 256){
$n -= 255;
}
return $this->QR_MATH_EXP_TABLE[$n];
}
}
+150
View File
@@ -0,0 +1,150 @@
<?php
/**
*
* @filesource Polynomial.php
* @created 25.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode;
use codemasher\QRCode\Math;
/**
* Class Polynomial
*/
class Polynomial{
/**
* @var
*/
protected $num;
/**
* @var \codemasher\QRCode\Math
*/
protected $math;
/**
* Polynomial constructor.
*
* @param array $num
* @param int $shift
*/
public function __construct(array $num, $shift = 0){
$this->math = new Math;
$offset = 0;
while($offset < count($num) && $num[$offset] === 0){
$offset++;
}
$this->num = $this->math->createNumArray(count($num) - $offset + $shift);
for($i = 0; $i < count($num) - $offset; $i++){
$this->num[$i] = $num[$i + $offset];
}
}
/**
* @param $index
* @todo rename!
*
* @return mixed
*/
public function get($index){
return $this->num[$index];
}
/**
* @return int
*/
public function getLength(){
return count($this->num);
}
/**
* PHP5
* @return string
*/
public function __toString(){
return $this->toString();
}
/**
* @return string
*/
public function toString(){
$buffer = '';
for($i = 0; $i < $this->getLength(); $i++){
if($i > 0){
$buffer .= ',';
}
$buffer .= $this->get($i);
}
return $buffer;
}
/**
* @return string
*/
public function toLogString(){
$buffer = '';
for($i = 0; $i < $this->getLength(); $i++){
if($i > 0){
$buffer .= ',';
}
$buffer .= $this->math->glog($this->get($i));
}
return $buffer;
}
/**
* @param \codemasher\QRCode\Polynomial $e
*
* @return \codemasher\QRCode\Polynomial
*/
public function multiply($e){
$num = $this->math->createNumArray($this->getLength() + $e->getLength() - 1);
for($i = 0; $i < $this->getLength(); $i++){
for($j = 0; $j < $e->getLength(); $j++){
$num[$i + $j] ^= $this->math->gexp($this->math->glog($this->get($i)) + $this->math->glog($e->get($j)));
}
}
return new Polynomial($num);
}
/**
* @param \codemasher\QRCode\Polynomial $e
*
* @return $this|\codemasher\QRCode\Polynomial
*/
public function mod($e){
if($this->getLength() - $e->getLength() < 0){
return $this;
}
$ratio = $this->math->glog($this->get(0)) - $this->math->glog($e->get(0));
$num = $this->math->createNumArray($this->getLength());
for($i = 0; $i < $this->getLength(); $i++){
$num[$i] = $this->get($i);
}
for($i = 0; $i < $e->getLength(); $i++){
$num[$i] ^= $this->math->gexp($this->math->glog($e->get($i)) + $ratio);
}
return (new Polynomial($num))->mod($e);
}
}
+597
View File
@@ -0,0 +1,597 @@
<?php
/**
*
* @filesource QRCode.php
* @created 26.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode;
use codemasher\QRCode\Data\AlphaNum;
use codemasher\QRCode\Data\EightBitByte;
use codemasher\QRCode\Data\Kanji;
use codemasher\QRCode\Data\Number;
use codemasher\QRCode\QRConst;
/**
* Class QRCode
*/
class QRCode{
const QR_PAD0 = 0xEC;
const QR_PAD1 = 0x11;
protected $typeNumber;
protected $modules;
protected $moduleCount;
protected $errorCorrectLevel;
protected $qrDataList;
protected $util;
protected $rs_block;
public function __construct(){
$this->typeNumber = 1;
$this->errorCorrectLevel = QRConst::ERROR_CORRECT_LEVEL_H;
$this->qrDataList = [];
$this->util = new Util;
$this->rs_block = new RSBlock;
}
public function getTypeNumber(){
return $this->typeNumber;
}
public function setTypeNumber($typeNumber){
$this->typeNumber = $typeNumber;
}
public function getErrorCorrectLevel(){
return $this->errorCorrectLevel;
}
public function setErrorCorrectLevel($errorCorrectLevel){
$this->errorCorrectLevel = $errorCorrectLevel;
}
public function addData($data, $mode = 0){
if($mode == 0){
$mode = $this->util->getMode($data);
}
switch($mode){
case QRConst::MODE_NUMBER :
$this->addDataImpl(new Number($data));
break;
case QRConst::MODE_ALPHA_NUM :
$this->addDataImpl(new AlphaNum($data));
break;
case QRConst::MODE_8BIT_BYTE :
$this->addDataImpl(new EightBitByte($data));
break;
case QRConst::MODE_KANJI :
$this->addDataImpl(new Kanji($data));
break;
default :
trigger_error("mode:$mode", E_USER_ERROR);
}
}
public function clearData(){
$this->qrDataList = [];
}
public function addDataImpl(&$qrData){
$this->qrDataList[] = $qrData;
}
public function getDataCount(){
return count($this->qrDataList);
}
public function getData($index){
return $this->qrDataList[$index];
}
public function isDark($row, $col){
if($this->modules[$row][$col] !== null){
return $this->modules[$row][$col];
}
else{
return false;
}
}
public function getModuleCount(){
return $this->moduleCount;
}
// used for converting fg/bg colors (e.g. #0000ff = 0x0000FF)
// added 2015.07.27 ~ DoktorJ
public function hex2rgb($hex = 0x0){
return [
'r' => floor($hex / 65536),
'g' => floor($hex / 256) % 256,
'b' => $hex % 256,
];
}
public function make(){
$this->makeImpl(false, $this->getBestMaskPattern());
}
public function getBestMaskPattern(){
$minLostPoint = 0;
$pattern = 0;
for($i = 0; $i < 8; $i++){
$this->makeImpl(true, $i);
$lostPoint = $this->util->getLostPoint($this);
if($i == 0 || $minLostPoint > $lostPoint){
$minLostPoint = $lostPoint;
$pattern = $i;
}
}
return $pattern;
}
public function createNullArray($length){
$nullArray = [];
for($i = 0; $i < $length; $i++){
$nullArray[] = null;
}
return $nullArray;
}
public function makeImpl($test, $maskPattern){
$this->moduleCount = $this->typeNumber * 4 + 17;
$this->modules = [];
for($i = 0; $i < $this->moduleCount; $i++){
$this->modules[] = $this->createNullArray($this->moduleCount);
}
$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->setupTypeNumber($test);
}
$dataArray = $this->qrDataList;
$data = $this->createData($this->typeNumber, $this->errorCorrectLevel, $dataArray);
$this->mapData($data, $maskPattern);
}
public 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 < count($data)){
$dark = ((($data[$byteIndex] >> $bitIndex)&1) == 1);
}
$mask = $this->util->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;
}
}
}
}
public function setupPositionAdjustPattern(){
$pos = $this->util->getPatternPosition($this->typeNumber);
for($i = 0; $i < count($pos); $i++){
for($j = 0; $j < count($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;
}
}
}
}
}
}
public function setupPositionProbePattern($row, $col){
for($r = -1; $r <= 7; $r++){
for($c = -1; $c <= 7; $c++){
if($row + $r <= -1 || $this->moduleCount <= $row + $r
|| $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;
}
}
}
}
public 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);
}
}
public function setupTypeNumber($test){
$bits = $this->util->getBCHTypeNumber($this->typeNumber);
for($i = 0; $i < 18; $i++){
$mod = (!$test && (($bits >> $i)&1) == 1);
$this->modules[(int)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][(int)floor($i / 3)] = $mod;
}
}
public function setupTypeInfo($test, $maskPattern){
$data = ($this->errorCorrectLevel << 3)|$maskPattern;
$bits = $this->util->getBCHTypeInfo($data);
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;
}
}
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;
}
}
$this->modules[$this->moduleCount - 8][8] = !$test;
}
public function createData($typeNumber, $errorCorrectLevel, $dataArray){
$rsBlocks = $this->rs_block->getRSBlocks($typeNumber, $errorCorrectLevel);
$buffer = new BitBuffer;
for($i = 0; $i < count($dataArray); $i++){
$data = $dataArray[$i];
$buffer->put($data->getMode(), 4);
$buffer->put($data->getLength(), $data->getLengthInBits($typeNumber));
$data->write($buffer);
}
$totalDataCount = 0;
for($i = 0; $i < count($rsBlocks); $i++){
$totalDataCount += $rsBlocks[$i]->getDataCount();
}
if($buffer->getLengthInBits() > $totalDataCount * 8){
trigger_error("code length overflow. ("
.$buffer->getLengthInBits()
.">"
.$totalDataCount * 8
.")", E_USER_ERROR);
}
// 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(self::QR_PAD0, 8);
if($buffer->getLengthInBits() >= $totalDataCount * 8){
break;
}
$buffer->put(self::QR_PAD1, 8);
}
return $this->createBytes($buffer, $rsBlocks);
}
public function createBytes(&$buffer, &$rsBlocks){
$offset = 0;
$maxDcCount = 0;
$maxEcCount = 0;
$dcdata = $this->createNullArray(count($rsBlocks));
$ecdata = $this->createNullArray(count($rsBlocks));
for($r = 0; $r < count($rsBlocks); $r++){
$dcCount = $rsBlocks[$r]->getDataCount();
$ecCount = $rsBlocks[$r]->getTotalCount() - $dcCount;
$maxDcCount = max($maxDcCount, $dcCount);
$maxEcCount = max($maxEcCount, $ecCount);
$dcdata[$r] = $this->createNullArray($dcCount);
for($i = 0; $i < count($dcdata[$r]); $i++){
$bdata = $buffer->getBuffer();
$dcdata[$r][$i] = 0xff&$bdata[$i + $offset];
}
$offset += $dcCount;
$rsPoly = $this->util->getErrorCorrectPolynomial($ecCount);
$rawPoly = new Polynomial($dcdata[$r], $rsPoly->getLength() - 1);
$modPoly = $rawPoly->mod($rsPoly);
$ecdata[$r] = $this->createNullArray($rsPoly->getLength() - 1);
for($i = 0; $i < count($ecdata[$r]); $i++){
$modIndex = $i + $modPoly->getLength() - count($ecdata[$r]);
$ecdata[$r][$i] = ($modIndex >= 0) ? $modPoly->get($modIndex) : 0;
}
}
$totalCodeCount = 0;
for($i = 0; $i < count($rsBlocks); $i++){
$totalCodeCount += $rsBlocks[$i]->getTotalCount();
}
$data = $this->createNullArray($totalCodeCount);
$index = 0;
for($i = 0; $i < $maxDcCount; $i++){
for($r = 0; $r < count($rsBlocks); $r++){
if($i < count($dcdata[$r])){
$data[$index++] = $dcdata[$r][$i];
}
}
}
for($i = 0; $i < $maxEcCount; $i++){
for($r = 0; $r < count($rsBlocks); $r++){
if($i < count($ecdata[$r])){
$data[$index++] = $ecdata[$r][$i];
}
}
}
return $data;
}
public function getMinimumQRCode($data, $errorCorrectLevel){
$mode = $this->util->getMode($data);
$qr = new QRCode();
$qr->setErrorCorrectLevel($errorCorrectLevel);
$qr->addData($data, $mode);
$qrData = $qr->getData(0);
$length = $qrData->getLength();
for($typeNumber = 1; $typeNumber <= 10; $typeNumber++){
if($length <= $this->util->getMaxLength($typeNumber, $mode, $errorCorrectLevel)){
$qr->setTypeNumber($typeNumber);
break;
}
}
$qr->make();
return $qr;
}
// added $fg (foreground), $bg (background), and $bgtrans (use transparent bg) parameters
// also added some simple error checking on parameters
// updated 2015.07.27 ~ DoktorJ
public function createImage($size = 2, $margin = 2, $fg = 0x000000, $bg = 0xFFFFFF, $bgtrans = false){
// size/margin EC
if(!is_numeric($size)){
$size = 2;
}
if(!is_numeric($margin)){
$margin = 2;
}
if($size < 1){
$size = 1;
}
if($margin < 0){
$margin = 0;
}
$image_size = $this->getModuleCount() * $size + $margin * 2;
$image = imagecreatetruecolor($image_size, $image_size);
// fg/bg EC
if($fg < 0 || $fg > 0xFFFFFF){
$fg = 0x0;
}
if($bg < 0 || $bg > 0xFFFFFF){
$bg = 0xFFFFFF;
}
// convert hexadecimal RGB to arrays for imagecolorallocate
$fgrgb = $this->hex2rgb($fg);
$bgrgb = $this->hex2rgb($bg);
// replace $black and $white with $fgc and $bgc
$fgc = imagecolorallocate($image, $fgrgb['r'], $fgrgb['g'], $fgrgb['b']);
$bgc = imagecolorallocate($image, $bgrgb['r'], $bgrgb['g'], $bgrgb['b']);
if($bgtrans){
imagecolortransparent($image, $bgc);
}
// update $white to $bgc
imagefilledrectangle($image, 0, 0, $image_size, $image_size, $bgc);
for($r = 0; $r < $this->getModuleCount(); $r++){
for($c = 0; $c < $this->getModuleCount(); $c++){
if($this->isDark($r, $c)){
// update $black to $fgc
imagefilledrectangle($image,
$margin + $c * $size,
$margin + $r * $size,
$margin + ($c + 1) * $size - 1,
$margin + ($r + 1) * $size - 1,
$fgc);
}
}
}
return $image;
}
public function printHTML($size = "2px"){
$style = "border-style:none;border-collapse:collapse;margin:0px;padding:0px;";
print("<table style='$style'>");
for($r = 0; $r < $this->getModuleCount(); $r++){
print("<tr style='$style'>");
for($c = 0; $c < $this->getModuleCount(); $c++){
$color = $this->isDark($r, $c) ? "#000000" : "#ffffff";
print("<td style='$style;width:$size;height:$size;background-color:$color'></td>");
}
print("</tr>");
}
print("</table>");
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
* Class QRCodeException
*
* @filesource QRCodeException.php
* @created 27.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode;
use Exception;
/**
* Placeholder
*/
class QRCodeException extends Exception{
}
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
*
* @filesource QRConst.php
* @created 26.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode;
/**
* Class QRConst
*/
class QRConst{
const MODE_NUMBER = 1 << 0;
const MODE_ALPHA_NUM = 1 << 1;
const MODE_8BIT_BYTE = 1 << 2;
const MODE_KANJI = 1 << 3;
const MASK_PATTERN000 = 0;
const MASK_PATTERN001 = 1;
const MASK_PATTERN010 = 2;
const MASK_PATTERN011 = 3;
const MASK_PATTERN100 = 4;
const MASK_PATTERN101 = 5;
const MASK_PATTERN110 = 6;
const MASK_PATTERN111 = 7;
const ERROR_CORRECT_LEVEL_L = 1; // 7%.
const ERROR_CORRECT_LEVEL_M = 0; // 15%.
const ERROR_CORRECT_LEVEL_Q = 3; // 25%.
const ERROR_CORRECT_LEVEL_H = 2; // 30%.
}
+180
View File
@@ -0,0 +1,180 @@
<?php
/**
*
* @filesource RSBlock.php
* @created 26.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode;
use codemasher\QRCode\QRConst;
use codemasher\QRCode\QRCodeException;
/**
* Class RSBlock
*/
class RSBlock{
/**
* @var int
*/
protected $totalCount;
/**
* @var int
*/
protected $dataCount;
/**
* @var array
*/
protected $QR_RS_BLOCK_TABLE = [
// L
// M
// Q
// H
// 1
[1, 26, 19],
[1, 26, 16],
[1, 26, 13],
[1, 26, 9],
// 2
[1, 44, 34],
[1, 44, 28],
[1, 44, 22],
[1, 44, 16],
// 3
[1, 70, 55],
[1, 70, 44],
[2, 35, 17],
[2, 35, 13],
// 4
[1, 100, 80],
[2, 50, 32],
[2, 50, 24],
[4, 25, 9],
// 5
[1, 134, 108],
[2, 67, 43],
[2, 33, 15, 2, 34, 16],
[2, 33, 11, 2, 34, 12],
// 6
[2, 86, 68],
[4, 43, 27],
[4, 43, 19],
[4, 43, 15],
// 7
[2, 98, 78],
[4, 49, 31],
[2, 32, 14, 4, 33, 15],
[4, 39, 13, 1, 40, 14],
// 8
[2, 121, 97],
[2, 60, 38, 2, 61, 39],
[4, 40, 18, 2, 41, 19],
[4, 40, 14, 2, 41, 15],
// 9
[2, 146, 116],
[3, 58, 36, 2, 59, 37],
[4, 36, 16, 4, 37, 17],
[4, 36, 12, 4, 37, 13],
// 10
[2, 86, 68, 2, 87, 69],
[4, 69, 43, 1, 70, 44],
[6, 43, 19, 2, 44, 20],
[6, 43, 15, 2, 44, 16],
];
public function __construct($totalCount = null, $dataCount = null){
if(isset($totalCount, $dataCount)){
$this->setCount($totalCount, $dataCount);
}
}
/**
* RSBlock constructor.
*
* @param int $totalCount
* @param int $dataCount
*/
public function setCount($totalCount, $dataCount){
$this->totalCount = $totalCount;
$this->dataCount = $dataCount;
}
/**
* @return int
*/
public function getDataCount(){
return $this->dataCount;
}
/**
* @return int
*/
public function getTotalCount(){
return $this->totalCount;
}
/**
* @param $typeNumber
* @param $errorCorrectLevel
*
* @return array
*/
public function getRSBlocks($typeNumber, $errorCorrectLevel){
$rsBlock = $this->getRsBlockTable($typeNumber, $errorCorrectLevel);
$length = count($rsBlock) / 3;
$list = [];
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++){
$list[] = new RSBlock($totalCount, $dataCount);
}
}
return $list;
}
/**
* @param $typeNumber
* @param $errorCorrectLevel
*
* @return mixed
* @throws \codemasher\QRCode\QRCodeException
*/
public function getRsBlockTable($typeNumber, $errorCorrectLevel){
switch($errorCorrectLevel){
case QRConst::ERROR_CORRECT_LEVEL_L: return $this->QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 0];
case QRConst::ERROR_CORRECT_LEVEL_M: return $this->QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 1];
case QRConst::ERROR_CORRECT_LEVEL_Q: return $this->QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 2];
case QRConst::ERROR_CORRECT_LEVEL_H: return $this->QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 3];
default:
throw new QRCodeException('tn:'.$typeNumber.'/ecl:'.$errorCorrectLevel);
}
}
}
+466
View File
@@ -0,0 +1,466 @@
<?php
/**
*
* @filesource Util.php
* @created 25.11.2015
* @package codemasher\QRCode
* @author Smiley <smiley@chillerlan.net>
* @copyright 2015 Smiley
* @license MIT
*/
namespace codemasher\QRCode;
use codemasher\QRCode\Math;
use codemasher\QRCode\Polynomial;
use codemasher\QRCode\QRCode;
use codemasher\QRCode\QRConst;
use codemasher\QRCode\QRCodeException;
/**
* Class Util
*/
class Util{
const QR_G15 = (1 << 10)|(1 << 8)|(1 << 5)|(1 << 4)|(1 << 2)|(1 << 1)|(1 << 0);
const QR_G18 = (1 << 12)|(1 << 11)|(1 << 10)|(1 << 9)|(1 << 8)|(1 << 5)|(1 << 2)|(1 << 0);
const QR_G15_MASK = (1 << 14)|(1 << 12)|(1 << 10)|(1 << 4)|(1 << 1);
/**
* @var array
*/
protected $QR_MAX_LENGTH = [
[[41, 25, 17, 10], [34, 20, 14, 8], [27, 16, 11, 7], [17, 10, 7, 4]],
[[77, 47, 32, 20], [63, 38, 26, 16], [48, 29, 20, 12], [34, 20, 14, 8]],
[[127, 77, 53, 32], [101, 61, 42, 26], [77, 47, 32, 20], [58, 35, 24, 15]],
[[187, 114, 78, 48], [149, 90, 62, 38], [111, 67, 46, 28], [82, 50, 34, 21]],
[[255, 154, 106, 65], [202, 122, 84, 52], [144, 87, 60, 37], [106, 64, 44, 27]],
[[322, 195, 134, 82], [255, 154, 106, 65], [178, 108, 74, 45], [139, 84, 58, 36]],
[[370, 224, 154, 95], [293, 178, 122, 75], [207, 125, 86, 53], [154, 93, 64, 39]],
[[461, 279, 192, 118], [365, 221, 152, 93], [259, 157, 108, 66], [202, 122, 84, 52]],
[[552, 335, 230, 141], [432, 262, 180, 111], [312, 189, 130, 80], [235, 143, 98, 60]],
[[652, 395, 271, 167], [513, 311, 213, 131], [364, 221, 151, 93], [288, 174, 119, 74]],
];
/**
* @var array
*/
protected $QR_PATTERN_POSITION_TABLE = [
[],
[6, 18],
[6, 22],
[6, 26],
[6, 30],
[6, 34],
[6, 22, 38],
[6, 24, 42],
[6, 26, 46],
[6, 28, 50],
[6, 30, 54],
[6, 32, 58],
[6, 34, 62],
[6, 26, 46, 66],
[6, 26, 48, 70],
[6, 26, 50, 74],
[6, 30, 54, 78],
[6, 30, 56, 82],
[6, 30, 58, 86],
[6, 34, 62, 90],
[6, 28, 50, 72, 94],
[6, 26, 50, 74, 98],
[6, 30, 54, 78, 102],
[6, 28, 54, 80, 106],
[6, 32, 58, 84, 110],
[6, 30, 58, 86, 114],
[6, 34, 62, 90, 118],
[6, 26, 50, 74, 98, 122],
[6, 30, 54, 78, 102, 126],
[6, 26, 52, 78, 104, 130],
[6, 30, 56, 82, 108, 134],
[6, 34, 60, 86, 112, 138],
[6, 30, 58, 86, 114, 142],
[6, 34, 62, 90, 118, 146],
[6, 30, 54, 78, 102, 126, 150],
[6, 24, 50, 76, 102, 128, 154],
[6, 28, 54, 80, 106, 132, 158],
[6, 32, 58, 84, 110, 136, 162],
[6, 26, 54, 82, 110, 138, 166],
[6, 30, 58, 86, 114, 142, 170],
];
/**
* @var \codemasher\QRCode\Math
*/
protected $math;
/**
* Util constructor.
*/
public function __construct(){
$this->math = new Math;
}
/**
* @param int $typeNumber
*
* @return int
*/
public function getPatternPosition($typeNumber){
return $this->QR_PATTERN_POSITION_TABLE[$typeNumber - 1];
}
/**
* @param int $typeNumber
* @param int $mode
* @param int $errorCorrectLevel
*
* @return mixed
* @throws \codemasher\QRCode\QRCodeException
*/
public function getMaxLength($typeNumber, $mode, $errorCorrectLevel){
$_type = $typeNumber - 1;
switch($errorCorrectLevel){
case QRConst::ERROR_CORRECT_LEVEL_L:
$_err = 0;
break;
case QRConst::ERROR_CORRECT_LEVEL_M:
$_err = 1;
break;
case QRConst::ERROR_CORRECT_LEVEL_Q:
$_err = 2;
break;
case QRConst::ERROR_CORRECT_LEVEL_H:
$_err = 3;
break;
default:
throw new QRCodeException('$_err: '.$errorCorrectLevel);
}
switch($mode){
case QRConst::MODE_NUMBER:
$_mode = 0;
break;
case QRConst::MODE_ALPHA_NUM:
$_mode = 1;
break;
case QRConst::MODE_8BIT_BYTE:
$_mode = 2;
break;
case QRConst::MODE_KANJI:
$_mode = 3;
break;
default :
throw new QRCodeException('$_mode: '.$mode);
}
return $this->QR_MAX_LENGTH[$_type][$_err][$_mode];
}
/**
* @param $errorCorrectLength
*
* @return \codemasher\QRCode\Polynomial
*/
public function getErrorCorrectPolynomial($errorCorrectLength){
$a = new Polynomial([1]);
for($i = 0; $i < $errorCorrectLength; $i++){
$a = $a->multiply(new Polynomial([1, $this->math->gexp($i)]));
}
return $a;
}
/**
* @param $maskPattern
* @param $i
* @param $j
*
* @return bool
* @throws \codemasher\QRCode\QRCodeException
*/
public function getMask($maskPattern, $i, $j){
switch($maskPattern){
case QRConst::MASK_PATTERN000:
return ($i + $j) % 2 === 0;
case QRConst::MASK_PATTERN001:
return $i % 2 === 0;
case QRConst::MASK_PATTERN010:
return $j % 3 === 0;
case QRConst::MASK_PATTERN011:
return ($i + $j) % 3 === 0;
case QRConst::MASK_PATTERN100:
return (floor($i / 2) + floor($j / 3)) % 2 === 0;
case QRConst::MASK_PATTERN101:
return ($i * $j) % 2 + ($i * $j) % 3 === 0;
case QRConst::MASK_PATTERN110:
return (($i * $j) % 2 + ($i * $j) % 3) % 2 === 0;
case QRConst::MASK_PATTERN111:
return (($i * $j) % 3 + ($i + $j) % 2) % 2 === 0;
default :
throw new QRCodeException('mask: '.$maskPattern);
}
}
/**
* @param \codemasher\QRCode\QRCode $qrCode
*
* @return float|int
*/
public function getLostPoint(QRCode $qrCode){
$moduleCount = $qrCode->getModuleCount();
$lostPoint = 0;
// LEVEL1
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);
}
}
}
// LEVEL2
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;
}
}
}
// LEVEL3
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;
}
}
}
// LEVEL4
$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;
}
/**
* @param $s
*
* @return int
*/
public function getMode($s){
if($this->isAlphaNum($s)){
if($this->isNumber($s)){
return QRConst::MODE_NUMBER;
}
return QRConst::MODE_ALPHA_NUM;
}
else if($this->isKanji($s)){
return QRConst::MODE_KANJI;
}
else{
return QRConst::MODE_8BIT_BYTE;
}
}
/**
* @param $s
*
* @return bool
*/
public function isNumber($s){
for($i = 0; $i < strlen($s); $i++){
$c = ord($s[$i]);
if(!($this->toCharCode('0') <= $c && $c <= $this->toCharCode('9'))){
return false;
}
}
return true;
}
/**
* @param $s
*
* @return bool
*/
public function isAlphaNum($s){
for($i = 0; $i < strlen($s); $i++){
$c = ord($s[$i]);
if(!($this->toCharCode('0') <= $c && $c <= $this->toCharCode('9'))
&& !($this->toCharCode('A') <= $c && $c <= $this->toCharCode('Z'))
&& strpos(' $%*+-./:', $s[$i]) === false
){
return false;
}
}
return true;
}
/**
* @param $s
*
* @return bool
*/
public function isKanji($s){
$data = $s;
$i = 0;
while($i + 1 < strlen($data)){
$c = ((0xff&ord($data[$i])) << 8)|(0xff&ord($data[$i + 1]));
if(!(0x8140 <= $c && $c <= 0x9FFC) && !(0xE040 <= $c && $c <= 0xEBBF)){
return false;
}
$i += 2;
}
if($i < strlen($data)){
return false;
}
return true;
}
/**
* @param $s
*
* @return int
*/
public function toCharCode($s){
return ord($s[0]);
}
/**
* @param $data
*
* @return int
*/
public function getBCHTypeInfo($data){
$d = $data << 10;
while($this->getBCHDigit($d) - $this->getBCHDigit(self::QR_G15) >= 0){
$d ^= (self::QR_G15 << ($this->getBCHDigit($d) - $this->getBCHDigit(self::QR_G15)));
}
return (($data << 10)|$d)^self::QR_G15_MASK;
}
/**
* @param $data
*
* @return int
*/
public function getBCHTypeNumber($data){
$d = $data << 12;
while($this->getBCHDigit($d) - $this->getBCHDigit(self::QR_G18) >= 0){
$d ^= (self::QR_G18 << ($this->getBCHDigit($d) - $this->getBCHDigit(self::QR_G18)));
}
return ($data << 12)|$d;
}
/**
* @param $data
*
* @return int
*/
public function getBCHDigit($data){
$digit = 0;
while($data != 0){
$digit++;
$data >>= 1;
}
return $digit;
}
}