2020-10-19 05:03:52 +02:00
< ? php
/*
* PHP QR Code encoder
*
* This file contains MERGED version of PHP QR Code library .
* It was auto - generated from full version for your convenience .
*
* This merged version was configured to not requre any external files ,
* with disabled cache , error loging and weker but faster mask matching .
* If you need tune it up please use non - merged version .
*
* For full version , documentation , examples of use please visit :
*
* http :// phpqrcode . sourceforge . net /
* https :// sourceforge . net / projects / phpqrcode /
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
/*
* Version : 1.1 . 4
* Build : 2010100721
*/
//---- qrconst.php -----------------------------
/*
* PHP QR Code encoder
*
* Common constants
*
* Based on libqrencode C library distributed under LGPL 2.1
* Copyright ( C ) 2006 , 2007 , 2008 , 2009 Kentaro Fukuchi < fukuchi @ megaui . net >
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
// Encoding modes
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
define ( 'QR_MODE_NUL' , - 1 );
define ( 'QR_MODE_NUM' , 0 );
define ( 'QR_MODE_AN' , 1 );
define ( 'QR_MODE_8' , 2 );
define ( 'QR_MODE_KANJI' , 3 );
define ( 'QR_MODE_STRUCTURE' , 4 );
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
// Levels of error correction.
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
define ( 'QR_ECLEVEL_L' , 0 );
define ( 'QR_ECLEVEL_M' , 1 );
define ( 'QR_ECLEVEL_Q' , 2 );
define ( 'QR_ECLEVEL_H' , 3 );
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
// Supported output formats
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
define ( 'QR_FORMAT_TEXT' , 0 );
define ( 'QR_FORMAT_PNG' , 1 );
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
class qrstr
{
public static function set ( & $srctab , $x , $y , $repl , $replLen = false )
{
$srctab [ $y ] = substr_replace ( $srctab [ $y ], ( false !== $replLen ) ? substr ( $repl , 0 , $replLen ) : $repl , $x , ( false !== $replLen ) ? $replLen : strlen ( $repl ));
}
}
//---- merged_config.php -----------------------------
2020-10-19 05:03:52 +02:00
/*
* PHP QR Code encoder
*
* Config file , tuned - up for merged verion
*/
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
define ( 'QR_CACHEABLE' , false ); // use cache - more disk reads but less CPU power, masks and format templates are stored there
define ( 'QR_CACHE_DIR' , false ); // used when QR_CACHEABLE === true
2021-10-10 15:48:53 +02:00
define ( 'QR_LOG_DIR' , false ); // default error logs dir
2020-10-19 05:03:52 +02:00
define ( 'QR_FIND_BEST_MASK' , true ); // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
define ( 'QR_FIND_FROM_RANDOM' , 2 ); // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
define ( 'QR_DEFAULT_MASK' , 2 ); // when QR_FIND_BEST_MASK === false
2021-10-10 15:48:53 +02:00
define ( 'QR_PNG_MAXIMUM_SIZE' , 1024 ); // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images
2020-10-19 05:03:52 +02:00
//---- qrtools.php -----------------------------
/*
* PHP QR Code encoder
*
* Toolset , handy and debug utilites .
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
class QRtools
{
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function binarize ( $frame )
{
$len = count ( $frame );
foreach ( $frame as & $frameLine ) {
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $len ; ++ $i ) {
$frameLine [ $i ] = ( ord ( $frameLine [ $i ]) & 1 ) ? '1' : '0' ;
2020-10-19 05:03:52 +02:00
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $frame ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function tcpdfBarcodeArray ( $code , $mode = 'QR,L' , $tcPdfVersion = '4.5.037' )
{
2021-10-10 15:48:53 +02:00
$barcode_array = [];
if ( ! is_array ( $mode )) {
2020-10-19 05:03:52 +02:00
$mode = explode ( ',' , $mode );
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$eccLevel = 'L' ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
if ( count ( $mode ) > 1 ) {
$eccLevel = $mode [ 1 ];
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$qrTab = QRcode :: text ( $code , false , $eccLevel );
$size = count ( $qrTab );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$barcode_array [ 'num_rows' ] = $size ;
$barcode_array [ 'num_cols' ] = $size ;
2021-10-10 15:48:53 +02:00
$barcode_array [ 'bcode' ] = [];
2020-10-19 05:03:52 +02:00
foreach ( $qrTab as $line ) {
2021-10-10 15:48:53 +02:00
$arrAdd = [];
foreach ( str_split ( $line ) as $char ) {
$arrAdd [] = ( '1' == $char ) ? 1 : 0 ;
}
2020-10-19 05:03:52 +02:00
$barcode_array [ 'bcode' ][] = $arrAdd ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $barcode_array ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function clearCache ()
{
2021-10-10 15:48:53 +02:00
self :: $frames = [];
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function buildCache ()
{
2021-10-10 15:48:53 +02:00
QRtools :: markTime ( 'before_build_cache' );
$mask = new QRmask ();
for ( $a = 1 ; $a <= QRSPEC_VERSION_MAX ; ++ $a ) {
2020-10-19 05:03:52 +02:00
$frame = QRspec :: newFrame ( $a );
if ( QR_IMAGE ) {
$fileName = QR_CACHE_DIR . 'frame_' . $a . '.png' ;
QRimage :: png ( self :: binarize ( $frame ), $fileName , 1 , 0 );
}
2021-10-10 15:48:53 +02:00
$width = count ( $frame );
$bitMask = array_fill ( 0 , $width , array_fill ( 0 , $width , 0 ));
for ( $maskNo = 0 ; $maskNo < 8 ; ++ $maskNo ) {
$mask -> makeMaskNo ( $maskNo , $width , $frame , $bitMask , true );
}
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
QRtools :: markTime ( 'after_build_cache' );
2020-10-19 05:03:52 +02:00
}
//----------------------------------------------------------------------
public static function log ( $outfile , $err )
{
if ( QR_LOG_DIR !== false ) {
2021-10-10 15:48:53 +02:00
if ( '' != $err ) {
if ( false !== $outfile ) {
2020-10-19 05:03:52 +02:00
file_put_contents ( QR_LOG_DIR . basename ( $outfile ) . '-errors.txt' , date ( 'Y-m-d H:i:s' ) . ': ' . $err , FILE_APPEND );
} else {
file_put_contents ( QR_LOG_DIR . 'errors.txt' , date ( 'Y-m-d H:i:s' ) . ': ' . $err , FILE_APPEND );
}
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public static function dumpMask ( $frame )
2020-10-19 05:03:52 +02:00
{
$width = count ( $frame );
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < $width ; ++ $y ) {
for ( $x = 0 ; $x < $width ; ++ $x ) {
2020-10-19 05:03:52 +02:00
echo ord ( $frame [ $y ][ $x ]) . ',' ;
}
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function markTime ( $markerId )
{
2021-10-10 15:48:53 +02:00
list ( $usec , $sec ) = explode ( ' ' , microtime ());
$time = (( float ) $usec + ( float ) $sec );
if ( ! isset ( $GLOBALS [ 'qr_time_bench' ])) {
$GLOBALS [ 'qr_time_bench' ] = [];
}
2020-10-19 05:03:52 +02:00
$GLOBALS [ 'qr_time_bench' ][ $markerId ] = $time ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function timeBenchmark ()
{
self :: markTime ( 'finish' );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$lastTime = 0 ;
$startTime = 0 ;
$p = 0 ;
echo ' < table cellpadding = " 3 " cellspacing = " 1 " >
< thead >< tr style = " border-bottom:1px solid silver " >< td colspan = " 2 " style = " text-align:center " > BENCHMARK </ td ></ tr ></ thead >
< tbody > ' ;
2021-10-10 15:48:53 +02:00
foreach ( $GLOBALS [ 'qr_time_bench' ] as $markerId => $thisTime ) {
2020-10-19 05:03:52 +02:00
if ( $p > 0 ) {
2021-10-10 15:48:53 +02:00
echo '<tr><th style="text-align:right">till ' . $markerId . ': </th><td>' . number_format ( $thisTime - $lastTime , 6 ) . 's</td></tr>' ;
2020-10-19 05:03:52 +02:00
} else {
$startTime = $thisTime ;
}
2021-10-10 15:48:53 +02:00
++ $p ;
2020-10-19 05:03:52 +02:00
$lastTime = $thisTime ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
echo ' </ tbody >< tfoot >
2021-10-10 15:48:53 +02:00
< tr style = " border-top:2px solid black " >< th style = " text-align:right " > TOTAL : </ th >< td > '.number_format($lastTime - $startTime, 6).' s </ td ></ tr >
2020-10-19 05:03:52 +02:00
</ tfoot >
</ table > ' ;
}
}
2021-10-10 15:48:53 +02:00
//##########################################################################
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
QRtools :: markTime ( 'start' );
2020-10-19 05:03:52 +02:00
//---- qrspec.php -----------------------------
/*
* PHP QR Code encoder
*
* QR Code specifications
*
* Based on libqrencode C library distributed under LGPL 2.1
* Copyright ( C ) 2006 , 2007 , 2008 , 2009 Kentaro Fukuchi < fukuchi @ megaui . net >
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* The following data / specifications are taken from
* " Two dimensional symbol -- QR-code -- Basic Specification " ( JIS X0510 : 2004 )
* or
2021-10-10 15:48:53 +02:00
* " Automatic identification and data capture techniques --
2020-10-19 05:03:52 +02:00
* QR Code 2005 bar code symbology specification " (ISO/IEC 18004:2006)
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
define ( 'QRSPEC_VERSION_MAX' , 40 );
2021-10-10 15:48:53 +02:00
define ( 'QRSPEC_WIDTH_MAX' , 177 );
define ( 'QRCAP_WIDTH' , 0 );
define ( 'QRCAP_WORDS' , 1 );
define ( 'QRCAP_REMINDER' , 2 );
define ( 'QRCAP_EC' , 3 );
class QRspec
{
public static $capacity = [
[ 0 , 0 , 0 , [ 0 , 0 , 0 , 0 ]],
[ 21 , 26 , 0 , [ 7 , 10 , 13 , 17 ]], // 1
[ 25 , 44 , 7 , [ 10 , 16 , 22 , 28 ]],
[ 29 , 70 , 7 , [ 15 , 26 , 36 , 44 ]],
[ 33 , 100 , 7 , [ 20 , 36 , 52 , 64 ]],
[ 37 , 134 , 7 , [ 26 , 48 , 72 , 88 ]], // 5
[ 41 , 172 , 7 , [ 36 , 64 , 96 , 112 ]],
[ 45 , 196 , 0 , [ 40 , 72 , 108 , 130 ]],
[ 49 , 242 , 0 , [ 48 , 88 , 132 , 156 ]],
[ 53 , 292 , 0 , [ 60 , 110 , 160 , 192 ]],
[ 57 , 346 , 0 , [ 72 , 130 , 192 , 224 ]], //10
[ 61 , 404 , 0 , [ 80 , 150 , 224 , 264 ]],
[ 65 , 466 , 0 , [ 96 , 176 , 260 , 308 ]],
[ 69 , 532 , 0 , [ 104 , 198 , 288 , 352 ]],
[ 73 , 581 , 3 , [ 120 , 216 , 320 , 384 ]],
[ 77 , 655 , 3 , [ 132 , 240 , 360 , 432 ]], //15
[ 81 , 733 , 3 , [ 144 , 280 , 408 , 480 ]],
[ 85 , 815 , 3 , [ 168 , 308 , 448 , 532 ]],
[ 89 , 901 , 3 , [ 180 , 338 , 504 , 588 ]],
[ 93 , 991 , 3 , [ 196 , 364 , 546 , 650 ]],
[ 97 , 1085 , 3 , [ 224 , 416 , 600 , 700 ]], //20
[ 101 , 1156 , 4 , [ 224 , 442 , 644 , 750 ]],
[ 105 , 1258 , 4 , [ 252 , 476 , 690 , 816 ]],
[ 109 , 1364 , 4 , [ 270 , 504 , 750 , 900 ]],
[ 113 , 1474 , 4 , [ 300 , 560 , 810 , 960 ]],
[ 117 , 1588 , 4 , [ 312 , 588 , 870 , 1050 ]], //25
[ 121 , 1706 , 4 , [ 336 , 644 , 952 , 1110 ]],
[ 125 , 1828 , 4 , [ 360 , 700 , 1020 , 1200 ]],
[ 129 , 1921 , 3 , [ 390 , 728 , 1050 , 1260 ]],
[ 133 , 2051 , 3 , [ 420 , 784 , 1140 , 1350 ]],
[ 137 , 2185 , 3 , [ 450 , 812 , 1200 , 1440 ]], //30
[ 141 , 2323 , 3 , [ 480 , 868 , 1290 , 1530 ]],
[ 145 , 2465 , 3 , [ 510 , 924 , 1350 , 1620 ]],
[ 149 , 2611 , 3 , [ 540 , 980 , 1440 , 1710 ]],
[ 153 , 2761 , 3 , [ 570 , 1036 , 1530 , 1800 ]],
[ 157 , 2876 , 0 , [ 570 , 1064 , 1590 , 1890 ]], //35
[ 161 , 3034 , 0 , [ 600 , 1120 , 1680 , 1980 ]],
[ 165 , 3196 , 0 , [ 630 , 1204 , 1770 , 2100 ]],
[ 169 , 3362 , 0 , [ 660 , 1260 , 1860 , 2220 ]],
[ 173 , 3532 , 0 , [ 720 , 1316 , 1950 , 2310 ]],
[ 177 , 3706 , 0 , [ 750 , 1372 , 2040 , 2430 ]], //40
];
//######################################################################
public static $lengthTableBits = [
[ 10 , 12 , 14 ],
[ 9 , 11 , 13 ],
[ 8 , 16 , 16 ],
[ 8 , 10 , 12 ],
];
// Error correction code -----------------------------------------------
// Table of the error correction code (Reed-Solomon block)
// See Table 12-16 (pp.30-36), JIS X0510:2004.
public static $eccTable = [
[[ 0 , 0 ], [ 0 , 0 ], [ 0 , 0 ], [ 0 , 0 ]],
[[ 1 , 0 ], [ 1 , 0 ], [ 1 , 0 ], [ 1 , 0 ]], // 1
[[ 1 , 0 ], [ 1 , 0 ], [ 1 , 0 ], [ 1 , 0 ]],
[[ 1 , 0 ], [ 1 , 0 ], [ 2 , 0 ], [ 2 , 0 ]],
[[ 1 , 0 ], [ 2 , 0 ], [ 2 , 0 ], [ 4 , 0 ]],
[[ 1 , 0 ], [ 2 , 0 ], [ 2 , 2 ], [ 2 , 2 ]], // 5
[[ 2 , 0 ], [ 4 , 0 ], [ 4 , 0 ], [ 4 , 0 ]],
[[ 2 , 0 ], [ 4 , 0 ], [ 2 , 4 ], [ 4 , 1 ]],
[[ 2 , 0 ], [ 2 , 2 ], [ 4 , 2 ], [ 4 , 2 ]],
[[ 2 , 0 ], [ 3 , 2 ], [ 4 , 4 ], [ 4 , 4 ]],
[[ 2 , 2 ], [ 4 , 1 ], [ 6 , 2 ], [ 6 , 2 ]], //10
[[ 4 , 0 ], [ 1 , 4 ], [ 4 , 4 ], [ 3 , 8 ]],
[[ 2 , 2 ], [ 6 , 2 ], [ 4 , 6 ], [ 7 , 4 ]],
[[ 4 , 0 ], [ 8 , 1 ], [ 8 , 4 ], [ 12 , 4 ]],
[[ 3 , 1 ], [ 4 , 5 ], [ 11 , 5 ], [ 11 , 5 ]],
[[ 5 , 1 ], [ 5 , 5 ], [ 5 , 7 ], [ 11 , 7 ]], //15
[[ 5 , 1 ], [ 7 , 3 ], [ 15 , 2 ], [ 3 , 13 ]],
[[ 1 , 5 ], [ 10 , 1 ], [ 1 , 15 ], [ 2 , 17 ]],
[[ 5 , 1 ], [ 9 , 4 ], [ 17 , 1 ], [ 2 , 19 ]],
[[ 3 , 4 ], [ 3 , 11 ], [ 17 , 4 ], [ 9 , 16 ]],
[[ 3 , 5 ], [ 3 , 13 ], [ 15 , 5 ], [ 15 , 10 ]], //20
[[ 4 , 4 ], [ 17 , 0 ], [ 17 , 6 ], [ 19 , 6 ]],
[[ 2 , 7 ], [ 17 , 0 ], [ 7 , 16 ], [ 34 , 0 ]],
[[ 4 , 5 ], [ 4 , 14 ], [ 11 , 14 ], [ 16 , 14 ]],
[[ 6 , 4 ], [ 6 , 14 ], [ 11 , 16 ], [ 30 , 2 ]],
[[ 8 , 4 ], [ 8 , 13 ], [ 7 , 22 ], [ 22 , 13 ]], //25
[[ 10 , 2 ], [ 19 , 4 ], [ 28 , 6 ], [ 33 , 4 ]],
[[ 8 , 4 ], [ 22 , 3 ], [ 8 , 26 ], [ 12 , 28 ]],
[[ 3 , 10 ], [ 3 , 23 ], [ 4 , 31 ], [ 11 , 31 ]],
[[ 7 , 7 ], [ 21 , 7 ], [ 1 , 37 ], [ 19 , 26 ]],
[[ 5 , 10 ], [ 19 , 10 ], [ 15 , 25 ], [ 23 , 25 ]], //30
[[ 13 , 3 ], [ 2 , 29 ], [ 42 , 1 ], [ 23 , 28 ]],
[[ 17 , 0 ], [ 10 , 23 ], [ 10 , 35 ], [ 19 , 35 ]],
[[ 17 , 1 ], [ 14 , 21 ], [ 29 , 19 ], [ 11 , 46 ]],
[[ 13 , 6 ], [ 14 , 23 ], [ 44 , 7 ], [ 59 , 1 ]],
[[ 12 , 7 ], [ 12 , 26 ], [ 39 , 14 ], [ 22 , 41 ]], //35
[[ 6 , 14 ], [ 6 , 34 ], [ 46 , 10 ], [ 2 , 64 ]],
[[ 17 , 4 ], [ 29 , 14 ], [ 49 , 10 ], [ 24 , 46 ]],
[[ 4 , 18 ], [ 13 , 32 ], [ 48 , 14 ], [ 42 , 32 ]],
[[ 20 , 4 ], [ 40 , 7 ], [ 43 , 22 ], [ 10 , 67 ]],
[[ 19 , 6 ], [ 18 , 31 ], [ 34 , 34 ], [ 20 , 61 ]], //40
];
// Alignment pattern ---------------------------------------------------
// Positions of alignment patterns.
// This array includes only the second and the third position of the
// alignment patterns. Rest of them can be calculated from the distance
// between them.
// See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
public static $alignmentPattern = [
[ 0 , 0 ],
[ 0 , 0 ], [ 18 , 0 ], [ 22 , 0 ], [ 26 , 0 ], [ 30 , 0 ], // 1- 5
[ 34 , 0 ], [ 22 , 38 ], [ 24 , 42 ], [ 26 , 46 ], [ 28 , 50 ], // 6-10
[ 30 , 54 ], [ 32 , 58 ], [ 34 , 62 ], [ 26 , 46 ], [ 26 , 48 ], //11-15
[ 26 , 50 ], [ 30 , 54 ], [ 30 , 56 ], [ 30 , 58 ], [ 34 , 62 ], //16-20
[ 28 , 50 ], [ 26 , 50 ], [ 30 , 54 ], [ 28 , 54 ], [ 32 , 58 ], //21-25
[ 30 , 58 ], [ 34 , 62 ], [ 26 , 50 ], [ 30 , 54 ], [ 26 , 52 ], //26-30
[ 30 , 56 ], [ 34 , 60 ], [ 30 , 58 ], [ 34 , 62 ], [ 30 , 54 ], //31-35
[ 24 , 50 ], [ 28 , 54 ], [ 32 , 58 ], [ 26 , 54 ], [ 30 , 58 ], //35-40
];
// Version information pattern -----------------------------------------
// Version information pattern (BCH coded).
// See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
// size: [QRSPEC_VERSION_MAX - 6]
public static $versionPattern = [
0x07C94 , 0x085BC , 0x09A99 , 0x0A4D3 , 0x0BBF6 , 0x0C762 , 0x0D847 , 0x0E60D ,
0x0F928 , 0x10B78 , 0x1145D , 0x12A17 , 0x13532 , 0x149A6 , 0x15683 , 0x168C9 ,
0x177EC , 0x18EC4 , 0x191E1 , 0x1AFAB , 0x1B08E , 0x1CC1A , 0x1D33F , 0x1ED75 ,
0x1F250 , 0x209D5 , 0x216F0 , 0x228BA , 0x2379F , 0x24B0B , 0x2542E , 0x26A64 ,
0x27541 , 0x28C69 ,
];
// Format information --------------------------------------------------
// See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib)
public static $formatInfo = [
[ 0x77C4 , 0x72F3 , 0x7DAA , 0x789D , 0x662F , 0x6318 , 0x6C41 , 0x6976 ],
[ 0x5412 , 0x5125 , 0x5E7C , 0x5B4B , 0x45F9 , 0x40CE , 0x4F97 , 0x4AA0 ],
[ 0x355F , 0x3068 , 0x3F31 , 0x3A06 , 0x24B4 , 0x2183 , 0x2EDA , 0x2BED ],
[ 0x1689 , 0x13BE , 0x1CE7 , 0x19D0 , 0x0762 , 0x0255 , 0x0D0C , 0x083B ],
];
// Frame ---------------------------------------------------------------
// Cache of initial frames.
public static $frames = [];
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function getDataLength ( $version , $level )
{
return self :: $capacity [ $version ][ QRCAP_WORDS ] - self :: $capacity [ $version ][ QRCAP_EC ][ $level ];
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function getECCLength ( $version , $level )
{
return self :: $capacity [ $version ][ QRCAP_EC ][ $level ];
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function getWidth ( $version )
{
return self :: $capacity [ $version ][ QRCAP_WIDTH ];
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function getRemainder ( $version )
{
return self :: $capacity [ $version ][ QRCAP_REMINDER ];
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function getMinimumVersion ( $size , $level )
{
2021-10-10 15:48:53 +02:00
for ( $i = 1 ; $i <= QRSPEC_VERSION_MAX ; ++ $i ) {
$words = self :: $capacity [ $i ][ QRCAP_WORDS ] - self :: $capacity [ $i ][ QRCAP_EC ][ $level ];
if ( $words >= $size ) {
2020-10-19 05:03:52 +02:00
return $i ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
}
return - 1 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function lengthIndicator ( $mode , $version )
{
2021-10-10 15:48:53 +02:00
if ( QR_MODE_STRUCTURE == $mode ) {
2020-10-19 05:03:52 +02:00
return 0 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
if ( $version <= 9 ) {
$l = 0 ;
2021-10-10 15:48:53 +02:00
} elseif ( $version <= 26 ) {
2020-10-19 05:03:52 +02:00
$l = 1 ;
} else {
$l = 2 ;
}
return self :: $lengthTableBits [ $mode ][ $l ];
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function maximumWords ( $mode , $version )
{
2021-10-10 15:48:53 +02:00
if ( QR_MODE_STRUCTURE == $mode ) {
2020-10-19 05:03:52 +02:00
return 3 ;
2021-10-10 15:48:53 +02:00
}
if ( $version <= 9 ) {
2020-10-19 05:03:52 +02:00
$l = 0 ;
2021-10-10 15:48:53 +02:00
} elseif ( $version <= 26 ) {
2020-10-19 05:03:52 +02:00
$l = 1 ;
} else {
$l = 2 ;
}
$bits = self :: $lengthTableBits [ $mode ][ $l ];
$words = ( 1 << $bits ) - 1 ;
2021-10-10 15:48:53 +02:00
if ( QR_MODE_KANJI == $mode ) {
2020-10-19 05:03:52 +02:00
$words *= 2 ; // the number of bytes is required
}
return $words ;
}
//----------------------------------------------------------------------
// CACHEABLE!!!
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
public static function getEccSpec ( $version , $level , array & $spec )
{
if ( count ( $spec ) < 5 ) {
2021-10-10 15:48:53 +02:00
$spec = [ 0 , 0 , 0 , 0 , 0 ];
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
$b1 = self :: $eccTable [ $version ][ $level ][ 0 ];
$b2 = self :: $eccTable [ $version ][ $level ][ 1 ];
2020-10-19 05:03:52 +02:00
$data = self :: getDataLength ( $version , $level );
2021-10-10 15:48:53 +02:00
$ecc = self :: getECCLength ( $version , $level );
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
if ( 0 == $b2 ) {
2020-10-19 05:03:52 +02:00
$spec [ 0 ] = $b1 ;
2021-10-10 15:48:53 +02:00
$spec [ 1 ] = ( int ) ( $data / $b1 );
$spec [ 2 ] = ( int ) ( $ecc / $b1 );
$spec [ 3 ] = 0 ;
2020-10-19 05:03:52 +02:00
$spec [ 4 ] = 0 ;
} else {
$spec [ 0 ] = $b1 ;
2021-10-10 15:48:53 +02:00
$spec [ 1 ] = ( int ) ( $data / ( $b1 + $b2 ));
$spec [ 2 ] = ( int ) ( $ecc / ( $b1 + $b2 ));
2020-10-19 05:03:52 +02:00
$spec [ 3 ] = $b2 ;
$spec [ 4 ] = $spec [ 1 ] + 1 ;
}
}
/** --------------------------------------------------------------------
* Put an alignment marker .
2021-10-10 15:48:53 +02:00
*
2020-10-19 05:03:52 +02:00
* @ param frame
* @ param width
* @ param ox , oy center coordinate of the pattern
2021-10-10 15:48:53 +02:00
* @ param mixed $ox
* @ param mixed $oy
2020-10-19 05:03:52 +02:00
*/
public static function putAlignmentMarker ( array & $frame , $ox , $oy )
{
2021-10-10 15:48:53 +02:00
$finder = [
2020-10-19 05:03:52 +02:00
" \xa1 \xa1 \xa1 \xa1 \xa1 " ,
" \xa1 \xa0 \xa0 \xa0 \xa1 " ,
" \xa1 \xa0 \xa1 \xa0 \xa1 " ,
" \xa1 \xa0 \xa0 \xa0 \xa1 " ,
2021-10-10 15:48:53 +02:00
" \xa1 \xa1 \xa1 \xa1 \xa1 " ,
];
$yStart = $oy - 2 ;
$xStart = $ox - 2 ;
for ( $y = 0 ; $y < 5 ; ++ $y ) {
QRstr :: set ( $frame , $xStart , $yStart + $y , $finder [ $y ]);
2020-10-19 05:03:52 +02:00
}
}
//----------------------------------------------------------------------
public static function putAlignmentPattern ( $version , & $frame , $width )
{
2021-10-10 15:48:53 +02:00
if ( $version < 2 ) {
2020-10-19 05:03:52 +02:00
return ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$d = self :: $alignmentPattern [ $version ][ 1 ] - self :: $alignmentPattern [ $version ][ 0 ];
2021-10-10 15:48:53 +02:00
if ( $d < 0 ) {
2020-10-19 05:03:52 +02:00
$w = 2 ;
} else {
2021-10-10 15:48:53 +02:00
$w = ( int ) (( $width - self :: $alignmentPattern [ $version ][ 0 ]) / $d + 2 );
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
if ( 1 == $w * $w - 3 ) {
2020-10-19 05:03:52 +02:00
$x = self :: $alignmentPattern [ $version ][ 0 ];
$y = self :: $alignmentPattern [ $version ][ 0 ];
self :: putAlignmentMarker ( $frame , $x , $y );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return ;
}
$cx = self :: $alignmentPattern [ $version ][ 0 ];
2021-10-10 15:48:53 +02:00
for ( $x = 1 ; $x < $w - 1 ; ++ $x ) {
2020-10-19 05:03:52 +02:00
self :: putAlignmentMarker ( $frame , 6 , $cx );
2021-10-10 15:48:53 +02:00
self :: putAlignmentMarker ( $frame , $cx , 6 );
2020-10-19 05:03:52 +02:00
$cx += $d ;
}
$cy = self :: $alignmentPattern [ $version ][ 0 ];
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < $w - 1 ; ++ $y ) {
2020-10-19 05:03:52 +02:00
$cx = self :: $alignmentPattern [ $version ][ 0 ];
2021-10-10 15:48:53 +02:00
for ( $x = 0 ; $x < $w - 1 ; ++ $x ) {
2020-10-19 05:03:52 +02:00
self :: putAlignmentMarker ( $frame , $cx , $cy );
$cx += $d ;
}
$cy += $d ;
}
}
//----------------------------------------------------------------------
public static function getVersionPattern ( $version )
{
2021-10-10 15:48:53 +02:00
if ( $version < 7 || $version > QRSPEC_VERSION_MAX ) {
2020-10-19 05:03:52 +02:00
return 0 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
return self :: $versionPattern [ $version - 7 ];
2020-10-19 05:03:52 +02:00
}
public static function getFormatInfo ( $mask , $level )
{
2021-10-10 15:48:53 +02:00
if ( $mask < 0 || $mask > 7 ) {
2020-10-19 05:03:52 +02:00
return 0 ;
2021-10-10 15:48:53 +02:00
}
if ( $level < 0 || $level > 3 ) {
return 0 ;
}
2020-10-19 05:03:52 +02:00
return self :: $formatInfo [ $level ][ $mask ];
}
/** --------------------------------------------------------------------
* Put a finder pattern .
2021-10-10 15:48:53 +02:00
*
2020-10-19 05:03:52 +02:00
* @ param frame
* @ param width
* @ param ox , oy upper - left coordinate of the pattern
2021-10-10 15:48:53 +02:00
* @ param mixed $frame
* @ param mixed $ox
* @ param mixed $oy
2020-10-19 05:03:52 +02:00
*/
public static function putFinderPattern ( & $frame , $ox , $oy )
{
2021-10-10 15:48:53 +02:00
$finder = [
2020-10-19 05:03:52 +02:00
" \xc1 \xc1 \xc1 \xc1 \xc1 \xc1 \xc1 " ,
" \xc1 \xc0 \xc0 \xc0 \xc0 \xc0 \xc1 " ,
" \xc1 \xc0 \xc1 \xc1 \xc1 \xc0 \xc1 " ,
" \xc1 \xc0 \xc1 \xc1 \xc1 \xc0 \xc1 " ,
" \xc1 \xc0 \xc1 \xc1 \xc1 \xc0 \xc1 " ,
" \xc1 \xc0 \xc0 \xc0 \xc0 \xc0 \xc1 " ,
2021-10-10 15:48:53 +02:00
" \xc1 \xc1 \xc1 \xc1 \xc1 \xc1 \xc1 " ,
];
for ( $y = 0 ; $y < 7 ; ++ $y ) {
QRstr :: set ( $frame , $ox , $oy + $y , $finder [ $y ]);
2020-10-19 05:03:52 +02:00
}
}
//----------------------------------------------------------------------
public static function createFrame ( $version )
{
$width = self :: $capacity [ $version ][ QRCAP_WIDTH ];
2021-10-10 15:48:53 +02:00
$frameLine = str_repeat ( " \0 " , $width );
2020-10-19 05:03:52 +02:00
$frame = array_fill ( 0 , $width , $frameLine );
// Finder pattern
self :: putFinderPattern ( $frame , 0 , 0 );
self :: putFinderPattern ( $frame , $width - 7 , 0 );
self :: putFinderPattern ( $frame , 0 , $width - 7 );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
// Separator
$yOffset = $width - 7 ;
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < 7 ; ++ $y ) {
2020-10-19 05:03:52 +02:00
$frame [ $y ][ 7 ] = " \xc0 " ;
$frame [ $y ][ $width - 8 ] = " \xc0 " ;
$frame [ $yOffset ][ 7 ] = " \xc0 " ;
2021-10-10 15:48:53 +02:00
++ $yOffset ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$setPattern = str_repeat ( " \xc0 " , 8 );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
QRstr :: set ( $frame , 0 , 7 , $setPattern );
2021-10-10 15:48:53 +02:00
QRstr :: set ( $frame , $width - 8 , 7 , $setPattern );
2020-10-19 05:03:52 +02:00
QRstr :: set ( $frame , 0 , $width - 8 , $setPattern );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
// Format info
$setPattern = str_repeat ( " \x84 " , 9 );
QRstr :: set ( $frame , 0 , 8 , $setPattern );
QRstr :: set ( $frame , $width - 8 , 8 , $setPattern , 8 );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$yOffset = $width - 8 ;
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < 8 ; $y ++ , $yOffset ++ ) {
2020-10-19 05:03:52 +02:00
$frame [ $y ][ 8 ] = " \x84 " ;
$frame [ $yOffset ][ 8 ] = " \x84 " ;
}
2021-10-10 15:48:53 +02:00
// Timing pattern
for ( $i = 1 ; $i < $width - 15 ; ++ $i ) {
$frame [ 6 ][ 7 + $i ] = chr ( 0x90 | ( $i & 1 ));
$frame [ 7 + $i ][ 6 ] = chr ( 0x90 | ( $i & 1 ));
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
// Alignment pattern
2020-10-19 05:03:52 +02:00
self :: putAlignmentPattern ( $version , $frame , $width );
2021-10-10 15:48:53 +02:00
// Version information
if ( $version >= 7 ) {
2020-10-19 05:03:52 +02:00
$vinf = self :: getVersionPattern ( $version );
$v = $vinf ;
2021-10-10 15:48:53 +02:00
for ( $x = 0 ; $x < 6 ; ++ $x ) {
for ( $y = 0 ; $y < 3 ; ++ $y ) {
$frame [( $width - 11 ) + $y ][ $x ] = chr ( 0x88 | ( $v & 1 ));
2020-10-19 05:03:52 +02:00
$v = $v >> 1 ;
}
}
$v = $vinf ;
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < 6 ; ++ $y ) {
for ( $x = 0 ; $x < 3 ; ++ $x ) {
$frame [ $y ][ $x + ( $width - 11 )] = chr ( 0x88 | ( $v & 1 ));
2020-10-19 05:03:52 +02:00
$v = $v >> 1 ;
}
}
}
2021-10-10 15:48:53 +02:00
// and a little bit...
2020-10-19 05:03:52 +02:00
$frame [ $width - 8 ][ 8 ] = " \x81 " ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $frame ;
}
//----------------------------------------------------------------------
public static function debug ( $frame , $binary_mode = false )
{
if ( $binary_mode ) {
2021-10-10 15:48:53 +02:00
foreach ( $frame as & $frameLine ) {
$frameLine = join ( '<span class="m"> </span>' , explode ( '0' , $frameLine ));
$frameLine = join ( '██' , explode ( '1' , $frameLine ));
} ?>
< style >
. m {
background - color : white ;
}
</ style >
< ? php
2020-10-19 05:03:52 +02:00
echo '<pre><tt><br/ ><br/ ><br/ > ' ;
2021-10-10 15:48:53 +02:00
echo join ( '<br/ > ' , $frame );
echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >' ;
2020-10-19 05:03:52 +02:00
} else {
foreach ( $frame as & $frameLine ) {
2021-10-10 15:48:53 +02:00
$frameLine = join ( '<span class="m"> </span>' , explode ( " \xc0 " , $frameLine ));
2020-10-19 05:03:52 +02:00
$frameLine = join ( '<span class="m">▒</span>' , explode ( " \xc1 " , $frameLine ));
2021-10-10 15:48:53 +02:00
$frameLine = join ( '<span class="p"> </span>' , explode ( " \xa0 " , $frameLine ));
2020-10-19 05:03:52 +02:00
$frameLine = join ( '<span class="p">▒</span>' , explode ( " \xa1 " , $frameLine ));
$frameLine = join ( '<span class="s">◇</span>' , explode ( " \x84 " , $frameLine )); //format 0
$frameLine = join ( '<span class="s">◆</span>' , explode ( " \x85 " , $frameLine )); //format 1
$frameLine = join ( '<span class="x">☢</span>' , explode ( " \x81 " , $frameLine )); //special bit
2021-10-10 15:48:53 +02:00
$frameLine = join ( '<span class="c"> </span>' , explode ( " \x90 " , $frameLine )); //clock 0
2020-10-19 05:03:52 +02:00
$frameLine = join ( '<span class="c">◷</span>' , explode ( " \x91 " , $frameLine )); //clock 1
2021-10-10 15:48:53 +02:00
$frameLine = join ( '<span class="f"> </span>' , explode ( " \x88 " , $frameLine )); //version
2020-10-19 05:03:52 +02:00
$frameLine = join ( '<span class="f">▒</span>' , explode ( " \x89 " , $frameLine )); //version
$frameLine = join ( '♦' , explode ( " \x01 " , $frameLine ));
$frameLine = join ( '⋅' , explode ( " \0 " , $frameLine ));
2021-10-10 15:48:53 +02:00
} ?>
< style >
. p {
background - color : yellow ;
}
. m {
background - color : #00FF00;
}
. s {
background - color : #FF0000;
}
. c {
background - color : aqua ;
}
. x {
background - color : pink ;
}
. f {
background - color : gold ;
}
</ style >
< ? php
echo '<pre><tt>' ;
echo join ( '<br/ >' , $frame );
echo '</tt></pre>' ;
2020-10-19 05:03:52 +02:00
}
}
//----------------------------------------------------------------------
public static function serial ( $frame )
{
return gzcompress ( join ( " \n " , $frame ), 9 );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function unserial ( $code )
{
return explode ( " \n " , gzuncompress ( $code ));
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function newFrame ( $version )
{
2021-10-10 15:48:53 +02:00
if ( $version < 1 || $version > QRSPEC_VERSION_MAX ) {
2020-10-19 05:03:52 +02:00
return null ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
if ( ! isset ( self :: $frames [ $version ])) {
2020-10-19 05:03:52 +02:00
$fileName = QR_CACHE_DIR . 'frame_' . $version . '.dat' ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
if ( QR_CACHEABLE ) {
if ( file_exists ( $fileName )) {
self :: $frames [ $version ] = self :: unserial ( file_get_contents ( $fileName ));
} else {
self :: $frames [ $version ] = self :: createFrame ( $version );
file_put_contents ( $fileName , self :: serial ( self :: $frames [ $version ]));
}
} else {
self :: $frames [ $version ] = self :: createFrame ( $version );
}
}
2021-10-10 15:48:53 +02:00
if ( is_null ( self :: $frames [ $version ])) {
2020-10-19 05:03:52 +02:00
return null ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return self :: $frames [ $version ];
}
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public static function rsBlockNum ( $spec )
{
return $spec [ 0 ] + $spec [ 3 ];
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
public static function rsBlockNum1 ( $spec )
{
return $spec [ 0 ];
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
public static function rsDataCodes1 ( $spec )
{
return $spec [ 1 ];
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
public static function rsEccCodes1 ( $spec )
{
return $spec [ 2 ];
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
public static function rsBlockNum2 ( $spec )
{
return $spec [ 3 ];
}
public static function rsDataCodes2 ( $spec )
{
return $spec [ 4 ];
}
public static function rsEccCodes2 ( $spec )
{
return $spec [ 2 ];
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
public static function rsDataLength ( $spec )
{
return ( $spec [ 0 ] * $spec [ 1 ]) + ( $spec [ 3 ] * $spec [ 4 ]);
}
public static function rsEccLength ( $spec )
{
return ( $spec [ 0 ] + $spec [ 3 ]) * $spec [ 2 ];
}
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
//---- qrimage.php -----------------------------
2020-10-19 05:03:52 +02:00
/*
* PHP QR Code encoder
*
* Image output of code using GD2
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
define ( 'QR_IMAGE' , true );
2021-10-10 15:48:53 +02:00
class QRimage
{
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public static function png ( $frame , $filename = false , $pixelPerPoint = 4 , $outerFrame = 4 , $saveandprint = false )
2020-10-19 05:03:52 +02:00
{
$image = self :: image ( $frame , $pixelPerPoint , $outerFrame );
2021-10-10 15:48:53 +02:00
if ( false === $filename ) {
header ( 'Content-type: image/png' );
imagepng ( $image );
2020-10-19 05:03:52 +02:00
} else {
2021-10-10 15:48:53 +02:00
if ( true === $saveandprint ) {
imagepng ( $image , $filename );
header ( 'Content-type: image/png' );
imagepng ( $image );
} else {
imagepng ( $image , $filename );
2020-10-19 05:03:52 +02:00
}
}
2021-10-10 15:48:53 +02:00
imagedestroy ( $image );
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public static function jpg ( $frame , $filename = false , $pixelPerPoint = 8 , $outerFrame = 4 , $q = 85 )
2020-10-19 05:03:52 +02:00
{
$image = self :: image ( $frame , $pixelPerPoint , $outerFrame );
2021-10-10 15:48:53 +02:00
if ( false === $filename ) {
header ( 'Content-type: image/jpeg' );
imagejpeg ( $image , null , $q );
2020-10-19 05:03:52 +02:00
} else {
2021-10-10 15:48:53 +02:00
imagejpeg ( $image , $filename , $q );
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
imagedestroy ( $image );
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
private static function image ( $frame , $pixelPerPoint = 4 , $outerFrame = 4 )
2020-10-19 05:03:52 +02:00
{
$h = count ( $frame );
$w = strlen ( $frame [ 0 ]);
2021-10-10 15:48:53 +02:00
$imgW = $w + 2 * $outerFrame ;
$imgH = $h + 2 * $outerFrame ;
$base_image = imagecreate ( $imgW , $imgH );
$col [ 0 ] = imagecolorallocate ( $base_image , 255 , 255 , 255 );
$col [ 1 ] = imagecolorallocate ( $base_image , 0 , 0 , 0 );
2020-10-19 05:03:52 +02:00
imagefill ( $base_image , 0 , 0 , $col [ 0 ]);
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < $h ; ++ $y ) {
for ( $x = 0 ; $x < $w ; ++ $x ) {
if ( '1' == $frame [ $y ][ $x ]) {
imagesetpixel ( $base_image , $x + $outerFrame , $y + $outerFrame , $col [ 1 ]);
2020-10-19 05:03:52 +02:00
}
}
}
2021-10-10 15:48:53 +02:00
$target_image = imagecreate ( $imgW * $pixelPerPoint , $imgH * $pixelPerPoint );
imagecopyresized ( $target_image , $base_image , 0 , 0 , 0 , 0 , $imgW * $pixelPerPoint , $imgH * $pixelPerPoint , $imgW , $imgH );
imagedestroy ( $base_image );
2020-10-19 05:03:52 +02:00
return $target_image ;
}
}
//---- qrinput.php -----------------------------
/*
* PHP QR Code encoder
*
* Input encoding class
*
* Based on libqrencode C library distributed under LGPL 2.1
* Copyright ( C ) 2006 , 2007 , 2008 , 2009 Kentaro Fukuchi < fukuchi @ megaui . net >
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
define ( 'STRUCTURE_HEADER_BITS' , 20 );
2020-10-19 05:03:52 +02:00
define ( 'MAX_STRUCTURED_SYMBOLS' , 16 );
2021-10-10 15:48:53 +02:00
class QRinputItem
{
2020-10-19 05:03:52 +02:00
public $mode ;
public $size ;
public $data ;
public $bstream ;
2021-10-10 15:48:53 +02:00
public function __construct ( $mode , $size , $data , $bstream = null )
2020-10-19 05:03:52 +02:00
{
$setData = array_slice ( $data , 0 , $size );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
if ( count ( $setData ) < $size ) {
2021-10-10 15:48:53 +02:00
$setData = array_merge ( $setData , array_fill ( 0 , $size - count ( $setData ), 0 ));
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
if ( ! QRinput :: check ( $mode , $size , $setData )) {
throw new Exception ( 'Error m:' . $mode . ',s:' . $size . ',d:' . join ( ',' , $setData ));
2020-10-19 05:03:52 +02:00
return null ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$this -> mode = $mode ;
$this -> size = $size ;
$this -> data = $setData ;
$this -> bstream = $bstream ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encodeModeNum ( $version )
{
try {
2021-10-10 15:48:53 +02:00
$words = ( int ) ( $this -> size / 3 );
2020-10-19 05:03:52 +02:00
$bs = new QRbitstream ();
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$val = 0x1 ;
$bs -> appendNum ( 4 , $val );
$bs -> appendNum ( QRspec :: lengthIndicator ( QR_MODE_NUM , $version ), $this -> size );
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $words ; ++ $i ) {
$val = ( ord ( $this -> data [ $i * 3 ]) - ord ( '0' )) * 100 ;
$val += ( ord ( $this -> data [ $i * 3 + 1 ]) - ord ( '0' )) * 10 ;
$val += ( ord ( $this -> data [ $i * 3 + 2 ]) - ord ( '0' ));
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 10 , $val );
}
2021-10-10 15:48:53 +02:00
if ( 1 == $this -> size - $words * 3 ) {
$val = ord ( $this -> data [ $words * 3 ]) - ord ( '0' );
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 4 , $val );
2021-10-10 15:48:53 +02:00
} elseif ( 2 == $this -> size - $words * 3 ) {
$val = ( ord ( $this -> data [ $words * 3 ]) - ord ( '0' )) * 10 ;
$val += ( ord ( $this -> data [ $words * 3 + 1 ]) - ord ( '0' ));
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 7 , $val );
}
$this -> bstream = $bs ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
} catch ( Exception $e ) {
return - 1 ;
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encodeModeAn ( $version )
{
try {
2021-10-10 15:48:53 +02:00
$words = ( int ) ( $this -> size / 2 );
2020-10-19 05:03:52 +02:00
$bs = new QRbitstream ();
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 4 , 0x02 );
$bs -> appendNum ( QRspec :: lengthIndicator ( QR_MODE_AN , $version ), $this -> size );
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $words ; ++ $i ) {
$val = ( int ) QRinput :: lookAnTable ( ord ( $this -> data [ $i * 2 ])) * 45 ;
$val += ( int ) QRinput :: lookAnTable ( ord ( $this -> data [ $i * 2 + 1 ]));
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 11 , $val );
}
2021-10-10 15:48:53 +02:00
if ( $this -> size & 1 ) {
2020-10-19 05:03:52 +02:00
$val = QRinput :: lookAnTable ( ord ( $this -> data [ $words * 2 ]));
$bs -> appendNum ( 6 , $val );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$this -> bstream = $bs ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
} catch ( Exception $e ) {
return - 1 ;
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encodeMode8 ( $version )
{
try {
$bs = new QRbitstream ();
$bs -> appendNum ( 4 , 0x4 );
$bs -> appendNum ( QRspec :: lengthIndicator ( QR_MODE_8 , $version ), $this -> size );
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $this -> size ; ++ $i ) {
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 8 , ord ( $this -> data [ $i ]));
}
$this -> bstream = $bs ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
} catch ( Exception $e ) {
return - 1 ;
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encodeModeKanji ( $version )
{
try {
$bs = new QRbitrtream ();
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 4 , 0x8 );
2021-10-10 15:48:53 +02:00
$bs -> appendNum ( QRspec :: lengthIndicator ( QR_MODE_KANJI , $version ), ( int ) ( $this -> size / 2 ));
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $this -> size ; $i += 2 ) {
$val = ( ord ( $this -> data [ $i ]) << 8 ) | ord ( $this -> data [ $i + 1 ]);
if ( $val <= 0x9FFC ) {
2020-10-19 05:03:52 +02:00
$val -= 0x8140 ;
} else {
2021-10-10 15:48:53 +02:00
$val -= 0xC140 ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
$h = ( $val >> 8 ) * 0xC0 ;
$val = ( $val & 0xFF ) + $h ;
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 13 , $val );
}
$this -> bstream = $bs ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
} catch ( Exception $e ) {
return - 1 ;
}
}
//----------------------------------------------------------------------
public function encodeModeStructure ()
{
try {
2021-10-10 15:48:53 +02:00
$bs = new QRbitstream ();
2020-10-19 05:03:52 +02:00
$bs -> appendNum ( 4 , 0x03 );
$bs -> appendNum ( 4 , ord ( $this -> data [ 1 ]) - 1 );
$bs -> appendNum ( 4 , ord ( $this -> data [ 0 ]) - 1 );
$bs -> appendNum ( 8 , ord ( $this -> data [ 2 ]));
$this -> bstream = $bs ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
} catch ( Exception $e ) {
return - 1 ;
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function estimateBitStreamSizeOfEntry ( $version )
{
$bits = 0 ;
2021-10-10 15:48:53 +02:00
if ( 0 == $version ) {
2020-10-19 05:03:52 +02:00
$version = 1 ;
2021-10-10 15:48:53 +02:00
}
switch ( $this -> mode ) {
case QR_MODE_NUM : $bits = QRinput :: estimateBitsModeNum ( $this -> size );
break ;
case QR_MODE_AN : $bits = QRinput :: estimateBitsModeAn ( $this -> size );
break ;
case QR_MODE_8 : $bits = QRinput :: estimateBitsMode8 ( $this -> size );
break ;
case QR_MODE_KANJI : $bits = QRinput :: estimateBitsModeKanji ( $this -> size );
break ;
case QR_MODE_STRUCTURE : return STRUCTURE_HEADER_BITS ;
2020-10-19 05:03:52 +02:00
default :
return 0 ;
}
$l = QRspec :: lengthIndicator ( $this -> mode , $version );
$m = 1 << $l ;
2021-10-10 15:48:53 +02:00
$num = ( int ) (( $this -> size + $m - 1 ) / $m );
2020-10-19 05:03:52 +02:00
$bits += $num * ( 4 + $l );
return $bits ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encodeBitStream ( $version )
{
try {
unset ( $this -> bstream );
$words = QRspec :: maximumWords ( $this -> mode , $version );
2021-10-10 15:48:53 +02:00
if ( $this -> size > $words ) {
2020-10-19 05:03:52 +02:00
$st1 = new QRinputItem ( $this -> mode , $words , $this -> data );
$st2 = new QRinputItem ( $this -> mode , $this -> size - $words , array_slice ( $this -> data , $words ));
$st1 -> encodeBitStream ( $version );
$st2 -> encodeBitStream ( $version );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$this -> bstream = new QRbitstream ();
$this -> bstream -> append ( $st1 -> bstream );
$this -> bstream -> append ( $st2 -> bstream );
2021-10-10 15:48:53 +02:00
unset ( $st1 , $st2 );
2020-10-19 05:03:52 +02:00
} else {
$ret = 0 ;
2021-10-10 15:48:53 +02:00
switch ( $this -> mode ) {
case QR_MODE_NUM : $ret = $this -> encodeModeNum ( $version );
break ;
case QR_MODE_AN : $ret = $this -> encodeModeAn ( $version );
break ;
case QR_MODE_8 : $ret = $this -> encodeMode8 ( $version );
break ;
case QR_MODE_KANJI : $ret = $this -> encodeModeKanji ( $version );
break ;
case QR_MODE_STRUCTURE : $ret = $this -> encodeModeStructure ();
break ;
2020-10-19 05:03:52 +02:00
default :
break ;
}
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
}
return $this -> bstream -> size ();
} catch ( Exception $e ) {
return - 1 ;
}
}
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
//##########################################################################
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
class QRinput
{
2020-10-19 05:03:52 +02:00
public $items ;
2021-10-10 15:48:53 +02:00
//----------------------------------------------------------------------
public static $anTable = [
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
36 , - 1 , - 1 , - 1 , 37 , 38 , - 1 , - 1 , - 1 , - 1 , 39 , 40 , - 1 , 41 , 42 , 43 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 44 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 ,
25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
];
2020-10-19 05:03:52 +02:00
private $version ;
private $level ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function __construct ( $version = 0 , $level = QR_ECLEVEL_L )
{
if ( $version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H ) {
throw new Exception ( 'Invalid version no' );
2021-10-10 15:48:53 +02:00
return null ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$this -> version = $version ;
$this -> level = $level ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function getVersion ()
{
return $this -> version ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function setVersion ( $version )
{
2021-10-10 15:48:53 +02:00
if ( $version < 0 || $version > QRSPEC_VERSION_MAX ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'Invalid version no' );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return - 1 ;
}
$this -> version = $version ;
return 0 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function getErrorCorrectionLevel ()
{
return $this -> level ;
}
//----------------------------------------------------------------------
public function setErrorCorrectionLevel ( $level )
{
2021-10-10 15:48:53 +02:00
if ( $level > QR_ECLEVEL_H ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'Invalid ECLEVEL' );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return - 1 ;
}
$this -> level = $level ;
return 0 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function appendEntry ( QRinputItem $entry )
{
$this -> items [] = $entry ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function append ( $mode , $size , $data )
{
try {
$entry = new QRinputItem ( $mode , $size , $data );
$this -> items [] = $entry ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
} catch ( Exception $e ) {
return - 1 ;
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
public function insertStructuredAppendHeader ( $size , $index , $parity )
{
2021-10-10 15:48:53 +02:00
if ( $size > MAX_STRUCTURED_SYMBOLS ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'insertStructuredAppendHeader wrong size' );
}
2021-10-10 15:48:53 +02:00
if ( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'insertStructuredAppendHeader wrong index' );
}
2021-10-10 15:48:53 +02:00
$buf = [ $size , $index , $parity ];
2020-10-19 05:03:52 +02:00
try {
$entry = new QRinputItem ( QR_MODE_STRUCTURE , 3 , buf );
array_unshift ( $this -> items , $entry );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
} catch ( Exception $e ) {
return - 1 ;
}
}
//----------------------------------------------------------------------
public function calcParity ()
{
$parity = 0 ;
2021-10-10 15:48:53 +02:00
foreach ( $this -> items as $item ) {
if ( QR_MODE_STRUCTURE != $item -> mode ) {
for ( $i = $item -> size - 1 ; $i >= 0 ; -- $i ) {
2020-10-19 05:03:52 +02:00
$parity ^= $item -> data [ $i ];
}
}
}
return $parity ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function checkModeNum ( $size , $data )
{
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $size ; ++ $i ) {
if (( ord ( $data [ $i ]) < ord ( '0' )) || ( ord ( $data [ $i ]) > ord ( '9' ))) {
2020-10-19 05:03:52 +02:00
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------
public static function estimateBitsModeNum ( $size )
{
2021-10-10 15:48:53 +02:00
$w = ( int ) $size / 3 ;
2020-10-19 05:03:52 +02:00
$bits = $w * 10 ;
2021-10-10 15:48:53 +02:00
switch ( $size - $w * 3 ) {
2020-10-19 05:03:52 +02:00
case 1 :
$bits += 4 ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case 2 :
$bits += 7 ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
default :
break ;
}
return $bits ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function lookAnTable ( $c )
{
2021-10-10 15:48:53 +02:00
return ( $c > 127 ) ? - 1 : self :: $anTable [ $c ];
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function checkModeAn ( $size , $data )
{
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $size ; ++ $i ) {
if ( - 1 == self :: lookAnTable ( ord ( $data [ $i ]))) {
2020-10-19 05:03:52 +02:00
return false ;
}
}
return true ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function estimateBitsModeAn ( $size )
{
2021-10-10 15:48:53 +02:00
$w = ( int ) ( $size / 2 );
2020-10-19 05:03:52 +02:00
$bits = $w * 11 ;
2021-10-10 15:48:53 +02:00
if ( $size & 1 ) {
2020-10-19 05:03:52 +02:00
$bits += 6 ;
}
return $bits ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function estimateBitsMode8 ( $size )
{
return $size * 8 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function estimateBitsModeKanji ( $size )
{
2021-10-10 15:48:53 +02:00
return ( int ) (( $size / 2 ) * 13 );
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function checkModeKanji ( $size , $data )
{
2021-10-10 15:48:53 +02:00
if ( $size & 1 ) {
2020-10-19 05:03:52 +02:00
return false ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $size ; $i += 2 ) {
$val = ( ord ( $data [ $i ]) << 8 ) | ord ( $data [ $i + 1 ]);
if ( $val < 0x8140
|| ( $val > 0x9FFC && $val < 0xE040 )
|| $val > 0xEBBF ) {
2020-10-19 05:03:52 +02:00
return false ;
}
}
return true ;
}
2021-10-10 15:48:53 +02:00
// Validation
2020-10-19 05:03:52 +02:00
public static function check ( $mode , $size , $data )
{
2021-10-10 15:48:53 +02:00
if ( $size <= 0 ) {
2020-10-19 05:03:52 +02:00
return false ;
2021-10-10 15:48:53 +02:00
}
switch ( $mode ) {
case QR_MODE_NUM : return self :: checkModeNum ( $size , $data );
break ;
case QR_MODE_AN : return self :: checkModeAn ( $size , $data );
break ;
case QR_MODE_KANJI : return self :: checkModeKanji ( $size , $data );
break ;
case QR_MODE_8 : return true ;
break ;
case QR_MODE_STRUCTURE : return true ;
break ;
2020-10-19 05:03:52 +02:00
default :
break ;
}
return false ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function estimateBitStreamSize ( $version )
{
$bits = 0 ;
2021-10-10 15:48:53 +02:00
foreach ( $this -> items as $item ) {
2020-10-19 05:03:52 +02:00
$bits += $item -> estimateBitStreamSizeOfEntry ( $version );
}
return $bits ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function estimateVersion ()
{
$version = 0 ;
$prev = 0 ;
do {
$prev = $version ;
$bits = $this -> estimateBitStreamSize ( $prev );
2021-10-10 15:48:53 +02:00
$version = QRspec :: getMinimumVersion (( int ) (( $bits + 7 ) / 8 ), $this -> level );
2020-10-19 05:03:52 +02:00
if ( $version < 0 ) {
return - 1 ;
}
} while ( $version > $prev );
return $version ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function lengthOfCode ( $mode , $version , $bits )
{
$payload = $bits - 4 - QRspec :: lengthIndicator ( $mode , $version );
2021-10-10 15:48:53 +02:00
switch ( $mode ) {
2020-10-19 05:03:52 +02:00
case QR_MODE_NUM :
2021-10-10 15:48:53 +02:00
$chunks = ( int ) ( $payload / 10 );
2020-10-19 05:03:52 +02:00
$remain = $payload - $chunks * 10 ;
$size = $chunks * 3 ;
2021-10-10 15:48:53 +02:00
if ( $remain >= 7 ) {
2020-10-19 05:03:52 +02:00
$size += 2 ;
2021-10-10 15:48:53 +02:00
} elseif ( $remain >= 4 ) {
++ $size ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case QR_MODE_AN :
2021-10-10 15:48:53 +02:00
$chunks = ( int ) ( $payload / 11 );
2020-10-19 05:03:52 +02:00
$remain = $payload - $chunks * 11 ;
$size = $chunks * 2 ;
2021-10-10 15:48:53 +02:00
if ( $remain >= 6 ) {
++ $size ;
}
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case QR_MODE_8 :
2021-10-10 15:48:53 +02:00
$size = ( int ) ( $payload / 8 );
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case QR_MODE_KANJI :
2021-10-10 15:48:53 +02:00
$size = ( int ) (( $payload / 13 ) * 2 );
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case QR_MODE_STRUCTURE :
2021-10-10 15:48:53 +02:00
$size = ( int ) ( $payload / 8 );
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
default :
$size = 0 ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$maxsize = QRspec :: maximumWords ( $mode , $version );
2021-10-10 15:48:53 +02:00
if ( $size < 0 ) {
$size = 0 ;
}
if ( $size > $maxsize ) {
$size = $maxsize ;
}
2020-10-19 05:03:52 +02:00
return $size ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function createBitStream ()
{
$total = 0 ;
2021-10-10 15:48:53 +02:00
foreach ( $this -> items as $item ) {
2020-10-19 05:03:52 +02:00
$bits = $item -> encodeBitStream ( $this -> version );
2021-10-10 15:48:53 +02:00
if ( $bits < 0 ) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$total += $bits ;
}
return $total ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function convertData ()
{
$ver = $this -> estimateVersion ();
2021-10-10 15:48:53 +02:00
if ( $ver > $this -> getVersion ()) {
2020-10-19 05:03:52 +02:00
$this -> setVersion ( $ver );
}
2021-10-10 15:48:53 +02:00
while ( true ) {
2020-10-19 05:03:52 +02:00
$bits = $this -> createBitStream ();
2021-10-10 15:48:53 +02:00
if ( $bits < 0 ) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
$ver = QRspec :: getMinimumVersion (( int ) (( $bits + 7 ) / 8 ), $this -> level );
if ( $ver < 0 ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'WRONG VERSION' );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
if ( $ver > $this -> getVersion ()) {
2020-10-19 05:03:52 +02:00
$this -> setVersion ( $ver );
} else {
break ;
}
}
return 0 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function appendPaddingBit ( & $bstream )
{
$bits = $bstream -> size ();
$maxwords = QRspec :: getDataLength ( $this -> version , $this -> level );
$maxbits = $maxwords * 8 ;
if ( $maxbits == $bits ) {
return 0 ;
}
if ( $maxbits - $bits < 5 ) {
return $bstream -> appendNum ( $maxbits - $bits , 0 );
}
$bits += 4 ;
2021-10-10 15:48:53 +02:00
$words = ( int ) (( $bits + 7 ) / 8 );
2020-10-19 05:03:52 +02:00
$padding = new QRbitstream ();
$ret = $padding -> appendNum ( $words * 8 - $bits + 4 , 0 );
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return $ret ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$padlen = $maxwords - $words ;
2021-10-10 15:48:53 +02:00
if ( $padlen > 0 ) {
$padbuf = [];
for ( $i = 0 ; $i < $padlen ; ++ $i ) {
$padbuf [ $i ] = ( $i & 1 ) ? 0x11 : 0xEC ;
}
2020-10-19 05:03:52 +02:00
$ret = $padding -> appendBytes ( $padlen , $padbuf );
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return $ret ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
}
$ret = $bstream -> append ( $padding );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $ret ;
}
//----------------------------------------------------------------------
public function mergeBitStream ()
{
2021-10-10 15:48:53 +02:00
if ( $this -> convertData () < 0 ) {
2020-10-19 05:03:52 +02:00
return null ;
}
$bstream = new QRbitstream ();
2021-10-10 15:48:53 +02:00
foreach ( $this -> items as $item ) {
2020-10-19 05:03:52 +02:00
$ret = $bstream -> append ( $item -> bstream );
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return null ;
}
}
return $bstream ;
}
//----------------------------------------------------------------------
public function getBitStream ()
{
$bstream = $this -> mergeBitStream ();
2021-10-10 15:48:53 +02:00
if ( null == $bstream ) {
2020-10-19 05:03:52 +02:00
return null ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$ret = $this -> appendPaddingBit ( $bstream );
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return null ;
}
return $bstream ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function getByteStream ()
{
$bstream = $this -> getBitStream ();
2021-10-10 15:48:53 +02:00
if ( null == $bstream ) {
2020-10-19 05:03:52 +02:00
return null ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $bstream -> toByte ();
}
}
//---- qrbitstream.php -----------------------------
/*
* PHP QR Code encoder
*
* Bitstream class
*
* Based on libqrencode C library distributed under LGPL 2.1
* Copyright ( C ) 2006 , 2007 , 2008 , 2009 Kentaro Fukuchi < fukuchi @ megaui . net >
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
class QRbitstream
{
public $data = [];
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function size ()
{
return count ( $this -> data );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function allocate ( $setLength )
{
$this -> data = array_fill ( 0 , $setLength , 0 );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function newFromNum ( $bits , $num )
{
$bstream = new QRbitstream ();
$bstream -> allocate ( $bits );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$mask = 1 << ( $bits - 1 );
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $bits ; ++ $i ) {
if ( $num & $mask ) {
2020-10-19 05:03:52 +02:00
$bstream -> data [ $i ] = 1 ;
} else {
$bstream -> data [ $i ] = 0 ;
}
$mask = $mask >> 1 ;
}
return $bstream ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function newFromBytes ( $size , $data )
{
$bstream = new QRbitstream ();
$bstream -> allocate ( $size * 8 );
2021-10-10 15:48:53 +02:00
$p = 0 ;
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $size ; ++ $i ) {
2020-10-19 05:03:52 +02:00
$mask = 0x80 ;
2021-10-10 15:48:53 +02:00
for ( $j = 0 ; $j < 8 ; ++ $j ) {
if ( $data [ $i ] & $mask ) {
2020-10-19 05:03:52 +02:00
$bstream -> data [ $p ] = 1 ;
} else {
$bstream -> data [ $p ] = 0 ;
}
2021-10-10 15:48:53 +02:00
++ $p ;
2020-10-19 05:03:52 +02:00
$mask = $mask >> 1 ;
}
}
return $bstream ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function append ( QRbitstream $arg )
{
if ( is_null ( $arg )) {
return - 1 ;
}
2021-10-10 15:48:53 +02:00
if ( 0 == $arg -> size ()) {
2020-10-19 05:03:52 +02:00
return 0 ;
}
2021-10-10 15:48:53 +02:00
if ( 0 == $this -> size ()) {
2020-10-19 05:03:52 +02:00
$this -> data = $arg -> data ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return 0 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$this -> data = array_values ( array_merge ( $this -> data , $arg -> data ));
return 0 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function appendNum ( $bits , $num )
{
2021-10-10 15:48:53 +02:00
if ( 0 == $bits ) {
2020-10-19 05:03:52 +02:00
return 0 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$b = QRbitstream :: newFromNum ( $bits , $num );
2021-10-10 15:48:53 +02:00
if ( is_null ( $b )) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$ret = $this -> append ( $b );
unset ( $b );
return $ret ;
}
//----------------------------------------------------------------------
public function appendBytes ( $size , $data )
{
2021-10-10 15:48:53 +02:00
if ( 0 == $size ) {
2020-10-19 05:03:52 +02:00
return 0 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$b = QRbitstream :: newFromBytes ( $size , $data );
2021-10-10 15:48:53 +02:00
if ( is_null ( $b )) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$ret = $this -> append ( $b );
unset ( $b );
return $ret ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function toByte ()
{
$size = $this -> size ();
2021-10-10 15:48:53 +02:00
if ( 0 == $size ) {
return [];
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
$data = array_fill ( 0 , ( int ) (( $size + 7 ) / 8 ), 0 );
$bytes = ( int ) ( $size / 8 );
2020-10-19 05:03:52 +02:00
$p = 0 ;
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $bytes ; ++ $i ) {
2020-10-19 05:03:52 +02:00
$v = 0 ;
2021-10-10 15:48:53 +02:00
for ( $j = 0 ; $j < 8 ; ++ $j ) {
2020-10-19 05:03:52 +02:00
$v = $v << 1 ;
$v |= $this -> data [ $p ];
2021-10-10 15:48:53 +02:00
++ $p ;
2020-10-19 05:03:52 +02:00
}
$data [ $i ] = $v ;
}
2021-10-10 15:48:53 +02:00
if ( $size & 7 ) {
2020-10-19 05:03:52 +02:00
$v = 0 ;
2021-10-10 15:48:53 +02:00
for ( $j = 0 ; $j < ( $size & 7 ); ++ $j ) {
2020-10-19 05:03:52 +02:00
$v = $v << 1 ;
$v |= $this -> data [ $p ];
2021-10-10 15:48:53 +02:00
++ $p ;
2020-10-19 05:03:52 +02:00
}
$data [ $bytes ] = $v ;
}
return $data ;
}
}
//---- qrsplit.php -----------------------------
/*
* PHP QR Code encoder
*
* Input splitting classes
*
* Based on libqrencode C library distributed under LGPL 2.1
* Copyright ( C ) 2006 , 2007 , 2008 , 2009 Kentaro Fukuchi < fukuchi @ megaui . net >
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* The following data / specifications are taken from
* " Two dimensional symbol -- QR-code -- Basic Specification " ( JIS X0510 : 2004 )
* or
2021-10-10 15:48:53 +02:00
* " Automatic identification and data capture techniques --
2020-10-19 05:03:52 +02:00
* QR Code 2005 bar code symbology specification " (ISO/IEC 18004:2006)
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
class QRsplit
{
2020-10-19 05:03:52 +02:00
public $dataStr = '' ;
public $input ;
public $modeHint ;
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public function __construct ( $dataStr , $input , $modeHint )
2020-10-19 05:03:52 +02:00
{
2021-10-10 15:48:53 +02:00
$this -> dataStr = $dataStr ;
$this -> input = $input ;
2020-10-19 05:03:52 +02:00
$this -> modeHint = $modeHint ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function isdigitat ( $str , $pos )
2021-10-10 15:48:53 +02:00
{
if ( $pos >= strlen ( $str )) {
2020-10-19 05:03:52 +02:00
return false ;
2021-10-10 15:48:53 +02:00
}
return ( ord ( $str [ $pos ]) >= ord ( '0' )) && ( ord ( $str [ $pos ]) <= ord ( '9' ));
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function isalnumat ( $str , $pos )
{
2021-10-10 15:48:53 +02:00
if ( $pos >= strlen ( $str )) {
2020-10-19 05:03:52 +02:00
return false ;
2021-10-10 15:48:53 +02:00
}
return QRinput :: lookAnTable ( ord ( $str [ $pos ])) >= 0 ;
2020-10-19 05:03:52 +02:00
}
//----------------------------------------------------------------------
public function identifyMode ( $pos )
{
2021-10-10 15:48:53 +02:00
if ( $pos >= strlen ( $this -> dataStr )) {
2020-10-19 05:03:52 +02:00
return QR_MODE_NUL ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$c = $this -> dataStr [ $pos ];
2021-10-10 15:48:53 +02:00
if ( self :: isdigitat ( $this -> dataStr , $pos )) {
2020-10-19 05:03:52 +02:00
return QR_MODE_NUM ;
2021-10-10 15:48:53 +02:00
}
if ( self :: isalnumat ( $this -> dataStr , $pos )) {
2020-10-19 05:03:52 +02:00
return QR_MODE_AN ;
2021-10-10 15:48:53 +02:00
}
if ( QR_MODE_KANJI == $this -> modeHint ) {
if ( $pos + 1 < strlen ( $this -> dataStr )) {
$d = $this -> dataStr [ $pos + 1 ];
2020-10-19 05:03:52 +02:00
$word = ( ord ( $c ) << 8 ) | ord ( $d );
2021-10-10 15:48:53 +02:00
if (( $word >= 0x8140 && $word <= 0x9FFC ) || ( $word >= 0xE040 && $word <= 0xEBBF )) {
2020-10-19 05:03:52 +02:00
return QR_MODE_KANJI ;
}
}
}
return QR_MODE_8 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function eatNum ()
{
$ln = QRspec :: lengthIndicator ( QR_MODE_NUM , $this -> input -> getVersion ());
$p = 0 ;
2021-10-10 15:48:53 +02:00
while ( self :: isdigitat ( $this -> dataStr , $p )) {
++ $p ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$run = $p ;
$mode = $this -> identifyMode ( $p );
2021-10-10 15:48:53 +02:00
if ( QR_MODE_8 == $mode ) {
2020-10-19 05:03:52 +02:00
$dif = QRinput :: estimateBitsModeNum ( $run ) + 4 + $ln
+ QRinput :: estimateBitsMode8 ( 1 ) // + 4 + l8
- QRinput :: estimateBitsMode8 ( $run + 1 ); // - 4 - l8
2021-10-10 15:48:53 +02:00
if ( $dif > 0 ) {
2020-10-19 05:03:52 +02:00
return $this -> eat8 ();
}
}
2021-10-10 15:48:53 +02:00
if ( QR_MODE_AN == $mode ) {
2020-10-19 05:03:52 +02:00
$dif = QRinput :: estimateBitsModeNum ( $run ) + 4 + $ln
+ QRinput :: estimateBitsModeAn ( 1 ) // + 4 + la
2021-10-10 15:48:53 +02:00
- QRinput :: estimateBitsModeAn ( $run + 1 ); // - 4 - la
if ( $dif > 0 ) {
2020-10-19 05:03:52 +02:00
return $this -> eatAn ();
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$ret = $this -> input -> append ( QR_MODE_NUM , $run , str_split ( $this -> dataStr ));
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return $run ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function eatAn ()
{
2021-10-10 15:48:53 +02:00
$la = QRspec :: lengthIndicator ( QR_MODE_AN , $this -> input -> getVersion ());
2020-10-19 05:03:52 +02:00
$ln = QRspec :: lengthIndicator ( QR_MODE_NUM , $this -> input -> getVersion ());
$p = 0 ;
2021-10-10 15:48:53 +02:00
while ( self :: isalnumat ( $this -> dataStr , $p )) {
if ( self :: isdigitat ( $this -> dataStr , $p )) {
2020-10-19 05:03:52 +02:00
$q = $p ;
2021-10-10 15:48:53 +02:00
while ( self :: isdigitat ( $this -> dataStr , $q )) {
++ $q ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$dif = QRinput :: estimateBitsModeAn ( $p ) // + 4 + la
+ QRinput :: estimateBitsModeNum ( $q - $p ) + 4 + $ln
- QRinput :: estimateBitsModeAn ( $q ); // - 4 - la
2021-10-10 15:48:53 +02:00
if ( $dif < 0 ) {
2020-10-19 05:03:52 +02:00
break ;
}
2021-10-10 15:48:53 +02:00
$p = $q ;
2020-10-19 05:03:52 +02:00
} else {
2021-10-10 15:48:53 +02:00
++ $p ;
2020-10-19 05:03:52 +02:00
}
}
$run = $p ;
2021-10-10 15:48:53 +02:00
if ( ! self :: isalnumat ( $this -> dataStr , $p )) {
2020-10-19 05:03:52 +02:00
$dif = QRinput :: estimateBitsModeAn ( $run ) + 4 + $la
+ QRinput :: estimateBitsMode8 ( 1 ) // + 4 + l8
- QRinput :: estimateBitsMode8 ( $run + 1 ); // - 4 - l8
2021-10-10 15:48:53 +02:00
if ( $dif > 0 ) {
2020-10-19 05:03:52 +02:00
return $this -> eat8 ();
}
}
$ret = $this -> input -> append ( QR_MODE_AN , $run , str_split ( $this -> dataStr ));
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return $run ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function eatKanji ()
{
$p = 0 ;
2021-10-10 15:48:53 +02:00
while ( QR_MODE_KANJI == $this -> identifyMode ( $p )) {
2020-10-19 05:03:52 +02:00
$p += 2 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$ret = $this -> input -> append ( QR_MODE_KANJI , $p , str_split ( $this -> dataStr ));
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return $run ;
}
//----------------------------------------------------------------------
public function eat8 ()
{
$la = QRspec :: lengthIndicator ( QR_MODE_AN , $this -> input -> getVersion ());
$ln = QRspec :: lengthIndicator ( QR_MODE_NUM , $this -> input -> getVersion ());
$p = 1 ;
$dataStrLen = strlen ( $this -> dataStr );
2021-10-10 15:48:53 +02:00
while ( $p < $dataStrLen ) {
2020-10-19 05:03:52 +02:00
$mode = $this -> identifyMode ( $p );
2021-10-10 15:48:53 +02:00
if ( QR_MODE_KANJI == $mode ) {
2020-10-19 05:03:52 +02:00
break ;
}
2021-10-10 15:48:53 +02:00
if ( QR_MODE_NUM == $mode ) {
2020-10-19 05:03:52 +02:00
$q = $p ;
2021-10-10 15:48:53 +02:00
while ( self :: isdigitat ( $this -> dataStr , $q )) {
++ $q ;
2020-10-19 05:03:52 +02:00
}
$dif = QRinput :: estimateBitsMode8 ( $p ) // + 4 + l8
+ QRinput :: estimateBitsModeNum ( $q - $p ) + 4 + $ln
- QRinput :: estimateBitsMode8 ( $q ); // - 4 - l8
2021-10-10 15:48:53 +02:00
if ( $dif < 0 ) {
2020-10-19 05:03:52 +02:00
break ;
}
2021-10-10 15:48:53 +02:00
$p = $q ;
} elseif ( QR_MODE_AN == $mode ) {
2020-10-19 05:03:52 +02:00
$q = $p ;
2021-10-10 15:48:53 +02:00
while ( self :: isalnumat ( $this -> dataStr , $q )) {
++ $q ;
2020-10-19 05:03:52 +02:00
}
$dif = QRinput :: estimateBitsMode8 ( $p ) // + 4 + l8
+ QRinput :: estimateBitsModeAn ( $q - $p ) + 4 + $la
- QRinput :: estimateBitsMode8 ( $q ); // - 4 - l8
2021-10-10 15:48:53 +02:00
if ( $dif < 0 ) {
2020-10-19 05:03:52 +02:00
break ;
}
2021-10-10 15:48:53 +02:00
$p = $q ;
2020-10-19 05:03:52 +02:00
} else {
2021-10-10 15:48:53 +02:00
++ $p ;
2020-10-19 05:03:52 +02:00
}
}
$run = $p ;
$ret = $this -> input -> append ( QR_MODE_8 , $run , str_split ( $this -> dataStr ));
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
return - 1 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return $run ;
}
//----------------------------------------------------------------------
public function splitString ()
{
2021-10-10 15:48:53 +02:00
while ( strlen ( $this -> dataStr ) > 0 ) {
if ( '' == $this -> dataStr ) {
2020-10-19 05:03:52 +02:00
return 0 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$mode = $this -> identifyMode ( 0 );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
switch ( $mode ) {
2021-10-10 15:48:53 +02:00
case QR_MODE_NUM : $length = $this -> eatNum ();
break ;
case QR_MODE_AN : $length = $this -> eatAn ();
break ;
2020-10-19 05:03:52 +02:00
case QR_MODE_KANJI :
2021-10-10 15:48:53 +02:00
if ( QR_MODE_KANJI == $hint ) {
$length = $this -> eatKanji ();
} else {
$length = $this -> eat8 ();
}
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
default : $length = $this -> eat8 ();
break ;
}
if ( 0 == $length ) {
return 0 ;
}
if ( $length < 0 ) {
return - 1 ;
2020-10-19 05:03:52 +02:00
}
$this -> dataStr = substr ( $this -> dataStr , $length );
}
}
//----------------------------------------------------------------------
public function toUpper ()
{
$stringLen = strlen ( $this -> dataStr );
$p = 0 ;
2021-10-10 15:48:53 +02:00
while ( $p < $stringLen ) {
2020-10-19 05:03:52 +02:00
$mode = self :: identifyMode ( substr ( $this -> dataStr , $p ), $this -> modeHint );
2021-10-10 15:48:53 +02:00
if ( QR_MODE_KANJI == $mode ) {
2020-10-19 05:03:52 +02:00
$p += 2 ;
} else {
if ( ord ( $this -> dataStr [ $p ]) >= ord ( 'a' ) && ord ( $this -> dataStr [ $p ]) <= ord ( 'z' )) {
$this -> dataStr [ $p ] = chr ( ord ( $this -> dataStr [ $p ]) - 32 );
}
2021-10-10 15:48:53 +02:00
++ $p ;
2020-10-19 05:03:52 +02:00
}
}
return $this -> dataStr ;
}
//----------------------------------------------------------------------
public static function splitStringToQRinput ( $string , QRinput $input , $modeHint , $casesensitive = true )
{
2021-10-10 15:48:53 +02:00
if ( is_null ( $string ) || '\0' == $string || '' == $string ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'empty string!!!' );
}
$split = new QRsplit ( $string , $input , $modeHint );
2021-10-10 15:48:53 +02:00
if ( ! $casesensitive ) {
2020-10-19 05:03:52 +02:00
$split -> toUpper ();
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return $split -> splitString ();
}
}
//---- qrrscode.php -----------------------------
/*
* PHP QR Code encoder
*
* Reed - Solomon error correction support
2021-10-10 15:48:53 +02:00
*
2020-10-19 05:03:52 +02:00
* Copyright ( C ) 2002 , 2003 , 2004 , 2006 Phil Karn , KA9Q
* ( libfec is released under the GNU Lesser General Public License . )
*
* Based on libqrencode C library distributed under LGPL 2.1
* Copyright ( C ) 2006 , 2007 , 2008 , 2009 Kentaro Fukuchi < fukuchi @ megaui . net >
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
class QRrsItem
{
public $mm ; // Bits per symbol
public $nn ; // Symbols per block (= (1<<mm)-1)
public $alpha_to = []; // log lookup table
public $index_of = []; // Antilog lookup table
public $genpoly = []; // Generator polynomial
public $nroots ; // Number of generator roots = number of parity symbols
public $fcr ; // First consecutive root, index form
public $prim ; // Primitive element, index form
public $iprim ; // prim-th root of 1, index form
public $pad ; // Padding bytes in shortened block
2020-10-19 05:03:52 +02:00
public $gfpoly ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function modnn ( $x )
{
while ( $x >= $this -> nn ) {
$x -= $this -> nn ;
$x = ( $x >> $this -> mm ) + ( $x & $this -> nn );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $x ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function init_rs_char ( $symsize , $gfpoly , $fcr , $prim , $nroots , $pad )
{
// Common code for intializing a Reed-Solomon control block (char or int symbols)
// Copyright 2004 Phil Karn, KA9Q
// May be used under the terms of the GNU Lesser General Public License (LGPL)
$rs = null ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
// Check parameter ranges
2021-10-10 15:48:53 +02:00
if ( $symsize < 0 || $symsize > 8 ) {
return $rs ;
}
if ( $fcr < 0 || $fcr >= ( 1 << $symsize )) {
return $rs ;
}
if ( $prim <= 0 || $prim >= ( 1 << $symsize )) {
return $rs ;
}
if ( $nroots < 0 || $nroots >= ( 1 << $symsize )) {
return $rs ;
} // Can't have more roots than symbol values!
if ( $pad < 0 || $pad >= (( 1 << $symsize ) - 1 - $nroots )) {
return $rs ;
} // Too much padding
2020-10-19 05:03:52 +02:00
$rs = new QRrsItem ();
$rs -> mm = $symsize ;
2021-10-10 15:48:53 +02:00
$rs -> nn = ( 1 << $symsize ) - 1 ;
2020-10-19 05:03:52 +02:00
$rs -> pad = $pad ;
2021-10-10 15:48:53 +02:00
$rs -> alpha_to = array_fill ( 0 , $rs -> nn + 1 , 0 );
$rs -> index_of = array_fill ( 0 , $rs -> nn + 1 , 0 );
2020-10-19 05:03:52 +02:00
// PHP style macro replacement ;)
2021-10-10 15:48:53 +02:00
$NN = & $rs -> nn ;
$A0 = & $NN ;
2020-10-19 05:03:52 +02:00
// Generate Galois field lookup tables
$rs -> index_of [ 0 ] = $A0 ; // log(zero) = -inf
$rs -> alpha_to [ $A0 ] = 0 ; // alpha**-inf = 0
$sr = 1 ;
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $rs -> nn ; ++ $i ) {
2020-10-19 05:03:52 +02:00
$rs -> index_of [ $sr ] = $i ;
$rs -> alpha_to [ $i ] = $sr ;
$sr <<= 1 ;
2021-10-10 15:48:53 +02:00
if ( $sr & ( 1 << $symsize )) {
2020-10-19 05:03:52 +02:00
$sr ^= $gfpoly ;
}
$sr &= $rs -> nn ;
}
2021-10-10 15:48:53 +02:00
if ( 1 != $sr ) {
2020-10-19 05:03:52 +02:00
// field generator polynomial is not primitive!
2021-10-10 15:48:53 +02:00
$rs = null ;
2020-10-19 05:03:52 +02:00
return $rs ;
}
2021-10-10 15:48:53 +02:00
// Form RS code generator polynomial from its roots
$rs -> genpoly = array_fill ( 0 , $nroots + 1 , 0 );
2020-10-19 05:03:52 +02:00
$rs -> fcr = $fcr ;
$rs -> prim = $prim ;
$rs -> nroots = $nroots ;
$rs -> gfpoly = $gfpoly ;
2021-10-10 15:48:53 +02:00
// Find prim-th root of 1, used in decoding
for ( $iprim = 1 ; ( $iprim % $prim ) != 0 ; $iprim += $rs -> nn )
2020-10-19 05:03:52 +02:00
; // intentional empty-body loop!
2021-10-10 15:48:53 +02:00
$rs -> iprim = ( int ) ( $iprim / $prim );
2020-10-19 05:03:52 +02:00
$rs -> genpoly [ 0 ] = 1 ;
2021-10-10 15:48:53 +02:00
for ( $i = 0 , $root = $fcr * $prim ; $i < $nroots ; $i ++ , $root += $prim ) {
$rs -> genpoly [ $i + 1 ] = 1 ;
2020-10-19 05:03:52 +02:00
// Multiply rs->genpoly[] by @**(root + x)
2021-10-10 15:48:53 +02:00
for ( $j = $i ; $j > 0 ; -- $j ) {
if ( 0 != $rs -> genpoly [ $j ]) {
$rs -> genpoly [ $j ] = $rs -> genpoly [ $j - 1 ] ^ $rs -> alpha_to [ $rs -> modnn ( $rs -> index_of [ $rs -> genpoly [ $j ]] + $root )];
2020-10-19 05:03:52 +02:00
} else {
2021-10-10 15:48:53 +02:00
$rs -> genpoly [ $j ] = $rs -> genpoly [ $j - 1 ];
2020-10-19 05:03:52 +02:00
}
}
// rs->genpoly[0] can never be zero
$rs -> genpoly [ 0 ] = $rs -> alpha_to [ $rs -> modnn ( $rs -> index_of [ $rs -> genpoly [ 0 ]] + $root )];
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
// convert rs->genpoly[] to index form for quicker encoding
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i <= $nroots ; ++ $i ) {
2020-10-19 05:03:52 +02:00
$rs -> genpoly [ $i ] = $rs -> index_of [ $rs -> genpoly [ $i ]];
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return $rs ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encode_rs_char ( $data , & $parity )
{
2021-10-10 15:48:53 +02:00
$MM = & $this -> mm ;
$NN = & $this -> nn ;
$ALPHA_TO = & $this -> alpha_to ;
$INDEX_OF = & $this -> index_of ;
$GENPOLY = & $this -> genpoly ;
$NROOTS = & $this -> nroots ;
$FCR = & $this -> fcr ;
$PRIM = & $this -> prim ;
$IPRIM = & $this -> iprim ;
$PAD = & $this -> pad ;
$A0 = & $NN ;
2020-10-19 05:03:52 +02:00
$parity = array_fill ( 0 , $NROOTS , 0 );
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < ( $NN - $NROOTS - $PAD ); ++ $i ) {
2020-10-19 05:03:52 +02:00
$feedback = $INDEX_OF [ $data [ $i ] ^ $parity [ 0 ]];
2021-10-10 15:48:53 +02:00
if ( $feedback != $A0 ) {
2020-10-19 05:03:52 +02:00
// feedback term is non-zero
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
// This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
// always be for the polynomials constructed by init_rs()
$feedback = $this -> modnn ( $NN - $GENPOLY [ $NROOTS ] + $feedback );
2021-10-10 15:48:53 +02:00
for ( $j = 1 ; $j < $NROOTS ; ++ $j ) {
$parity [ $j ] ^= $ALPHA_TO [ $this -> modnn ( $feedback + $GENPOLY [ $NROOTS - $j ])];
2020-10-19 05:03:52 +02:00
}
}
2021-10-10 15:48:53 +02:00
// Shift
2020-10-19 05:03:52 +02:00
array_shift ( $parity );
2021-10-10 15:48:53 +02:00
if ( $feedback != $A0 ) {
2020-10-19 05:03:52 +02:00
array_push ( $parity , $ALPHA_TO [ $this -> modnn ( $feedback + $GENPOLY [ 0 ])]);
} else {
array_push ( $parity , 0 );
}
}
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//##########################################################################
2021-10-10 15:48:53 +02:00
class QRrs
{
public static $items = [];
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function init_rs ( $symsize , $gfpoly , $fcr , $prim , $nroots , $pad )
{
2021-10-10 15:48:53 +02:00
foreach ( self :: $items as $rs ) {
if ( $rs -> pad != $pad ) {
continue ;
}
if ( $rs -> nroots != $nroots ) {
continue ;
}
if ( $rs -> mm != $symsize ) {
continue ;
}
if ( $rs -> gfpoly != $gfpoly ) {
continue ;
}
if ( $rs -> fcr != $fcr ) {
continue ;
}
if ( $rs -> prim != $prim ) {
continue ;
}
2020-10-19 05:03:52 +02:00
return $rs ;
}
$rs = QRrsItem :: init_rs_char ( $symsize , $gfpoly , $fcr , $prim , $nroots , $pad );
array_unshift ( self :: $items , $rs );
return $rs ;
}
}
//---- qrmask.php -----------------------------
/*
* PHP QR Code encoder
*
* Masking
*
* Based on libqrencode C library distributed under LGPL 2.1
* Copyright ( C ) 2006 , 2007 , 2008 , 2009 Kentaro Fukuchi < fukuchi @ megaui . net >
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
define ( 'N1' , 3 );
define ( 'N2' , 3 );
define ( 'N3' , 40 );
define ( 'N4' , 10 );
class QRmask
{
public $runLength = [];
//----------------------------------------------------------------------
public function __construct ()
2020-10-19 05:03:52 +02:00
{
$this -> runLength = array_fill ( 0 , QRSPEC_WIDTH_MAX + 1 , 0 );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function writeFormatInformation ( $width , & $frame , $mask , $level )
{
$blacks = 0 ;
2021-10-10 15:48:53 +02:00
$format = QRspec :: getFormatInfo ( $mask , $level );
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < 8 ; ++ $i ) {
if ( $format & 1 ) {
2020-10-19 05:03:52 +02:00
$blacks += 2 ;
$v = 0x85 ;
} else {
$v = 0x84 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$frame [ 8 ][ $width - 1 - $i ] = chr ( $v );
2021-10-10 15:48:53 +02:00
if ( $i < 6 ) {
2020-10-19 05:03:52 +02:00
$frame [ $i ][ 8 ] = chr ( $v );
} else {
$frame [ $i + 1 ][ 8 ] = chr ( $v );
}
$format = $format >> 1 ;
}
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < 7 ; ++ $i ) {
if ( $format & 1 ) {
2020-10-19 05:03:52 +02:00
$blacks += 2 ;
$v = 0x85 ;
} else {
$v = 0x84 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$frame [ $width - 7 + $i ][ 8 ] = chr ( $v );
2021-10-10 15:48:53 +02:00
if ( 0 == $i ) {
2020-10-19 05:03:52 +02:00
$frame [ 8 ][ 7 ] = chr ( $v );
} else {
$frame [ 8 ][ 6 - $i ] = chr ( $v );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$format = $format >> 1 ;
}
return $blacks ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public function mask0 ( $x , $y )
2020-10-19 05:03:52 +02:00
{
2021-10-10 15:48:53 +02:00
return ( $x + $y ) & 1 ;
}
public function mask1 ( $x , $y )
{
return $y & 1 ;
}
public function mask2 ( $x , $y )
{
return $x % 3 ;
}
public function mask3 ( $x , $y )
{
return ( $x + $y ) % 3 ;
}
public function mask4 ( $x , $y )
{
return ((( int ) ( $y / 2 )) + (( int ) ( $x / 3 ))) & 1 ;
}
public function mask5 ( $x , $y )
{
return (( $x * $y ) & 1 ) + ( $x * $y ) % 3 ;
}
public function mask6 ( $x , $y )
{
return ((( $x * $y ) & 1 ) + ( $x * $y ) % 3 ) & 1 ;
}
public function mask7 ( $x , $y )
{
return ((( $x * $y ) % 3 ) + (( $x + $y ) & 1 )) & 1 ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function serial ( $bitFrame )
{
2021-10-10 15:48:53 +02:00
$codeArr = [];
foreach ( $bitFrame as $line ) {
2020-10-19 05:03:52 +02:00
$codeArr [] = join ( '' , $line );
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return gzcompress ( join ( " \n " , $codeArr ), 9 );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function unserial ( $code )
{
2021-10-10 15:48:53 +02:00
$codeArr = [];
2020-10-19 05:03:52 +02:00
$codeLines = explode ( " \n " , gzuncompress ( $code ));
2021-10-10 15:48:53 +02:00
foreach ( $codeLines as $line ) {
2020-10-19 05:03:52 +02:00
$codeArr [] = str_split ( $line );
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
return $codeArr ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public function makeMaskNo ( $maskNo , $width , $s , & $d , $maskGenOnly = false )
2020-10-19 05:03:52 +02:00
{
$b = 0 ;
2021-10-10 15:48:53 +02:00
$bitMask = [];
2020-10-19 05:03:52 +02:00
$fileName = QR_CACHE_DIR . 'mask_' . $maskNo . DIRECTORY_SEPARATOR . 'mask_' . $width . '_' . $maskNo . '.dat' ;
if ( QR_CACHEABLE ) {
if ( file_exists ( $fileName )) {
$bitMask = self :: unserial ( file_get_contents ( $fileName ));
} else {
$bitMask = $this -> generateMaskNo ( $maskNo , $width , $s , $d );
2021-10-10 15:48:53 +02:00
if ( ! file_exists ( QR_CACHE_DIR . 'mask_' . $maskNo )) {
2020-10-19 05:03:52 +02:00
mkdir ( QR_CACHE_DIR . 'mask_' . $maskNo );
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
file_put_contents ( $fileName , self :: serial ( $bitMask ));
}
} else {
$bitMask = $this -> generateMaskNo ( $maskNo , $width , $s , $d );
}
2021-10-10 15:48:53 +02:00
if ( $maskGenOnly ) {
2020-10-19 05:03:52 +02:00
return ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$d = $s ;
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < $width ; ++ $y ) {
for ( $x = 0 ; $x < $width ; ++ $x ) {
if ( 1 == $bitMask [ $y ][ $x ]) {
$d [ $y ][ $x ] = chr ( ord ( $s [ $y ][ $x ]) ^ ( int ) $bitMask [ $y ][ $x ]);
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
$b += ( int ) ( ord ( $d [ $y ][ $x ]) & 1 );
2020-10-19 05:03:52 +02:00
}
}
return $b ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function makeMask ( $width , $frame , $maskNo , $level )
{
$masked = array_fill ( 0 , $width , str_repeat ( " \0 " , $width ));
$this -> makeMaskNo ( $maskNo , $width , $frame , $masked );
$this -> writeFormatInformation ( $width , $masked , $maskNo , $level );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $masked ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function calcN1N3 ( $length )
{
$demerit = 0 ;
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $length ; ++ $i ) {
if ( $this -> runLength [ $i ] >= 5 ) {
2020-10-19 05:03:52 +02:00
$demerit += ( N1 + ( $this -> runLength [ $i ] - 5 ));
}
2021-10-10 15:48:53 +02:00
if ( $i & 1 ) {
if (( $i >= 3 ) && ( $i < ( $length - 2 )) && ( $this -> runLength [ $i ] % 3 == 0 )) {
$fact = ( int ) ( $this -> runLength [ $i ] / 3 );
if (( $this -> runLength [ $i - 2 ] == $fact )
&& ( $this -> runLength [ $i - 1 ] == $fact )
&& ( $this -> runLength [ $i + 1 ] == $fact )
&& ( $this -> runLength [ $i + 2 ] == $fact )) {
if (( $this -> runLength [ $i - 3 ] < 0 ) || ( $this -> runLength [ $i - 3 ] >= ( 4 * $fact ))) {
2020-10-19 05:03:52 +02:00
$demerit += N3 ;
2021-10-10 15:48:53 +02:00
} elseif ((( $i + 3 ) >= $length ) || ( $this -> runLength [ $i + 3 ] >= ( 4 * $fact ))) {
2020-10-19 05:03:52 +02:00
$demerit += N3 ;
}
}
}
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $demerit ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function evaluateSymbol ( $width , $frame )
{
$head = 0 ;
$demerit = 0 ;
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < $width ; ++ $y ) {
2020-10-19 05:03:52 +02:00
$head = 0 ;
$this -> runLength [ 0 ] = 1 ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$frameY = $frame [ $y ];
2021-10-10 15:48:53 +02:00
if ( $y > 0 ) {
$frameYM = $frame [ $y - 1 ];
}
for ( $x = 0 ; $x < $width ; ++ $x ) {
if (( $x > 0 ) && ( $y > 0 )) {
$b22 = ord ( $frameY [ $x ]) & ord ( $frameY [ $x - 1 ]) & ord ( $frameYM [ $x ]) & ord ( $frameYM [ $x - 1 ]);
$w22 = ord ( $frameY [ $x ]) | ord ( $frameY [ $x - 1 ]) | ord ( $frameYM [ $x ]) | ord ( $frameYM [ $x - 1 ]);
if (( $b22 | ( $w22 ^ 1 )) & 1 ) {
2020-10-19 05:03:52 +02:00
$demerit += N2 ;
}
}
2021-10-10 15:48:53 +02:00
if (( 0 == $x ) && ( ord ( $frameY [ $x ]) & 1 )) {
2020-10-19 05:03:52 +02:00
$this -> runLength [ 0 ] = - 1 ;
$head = 1 ;
$this -> runLength [ $head ] = 1 ;
2021-10-10 15:48:53 +02:00
} elseif ( $x > 0 ) {
if (( ord ( $frameY [ $x ]) ^ ord ( $frameY [ $x - 1 ])) & 1 ) {
++ $head ;
2020-10-19 05:03:52 +02:00
$this -> runLength [ $head ] = 1 ;
} else {
2021-10-10 15:48:53 +02:00
++ $this -> runLength [ $head ];
2020-10-19 05:03:52 +02:00
}
}
}
2021-10-10 15:48:53 +02:00
$demerit += $this -> calcN1N3 ( $head + 1 );
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
for ( $x = 0 ; $x < $width ; ++ $x ) {
2020-10-19 05:03:52 +02:00
$head = 0 ;
$this -> runLength [ 0 ] = 1 ;
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < $width ; ++ $y ) {
if ( 0 == $y && ( ord ( $frame [ $y ][ $x ]) & 1 )) {
2020-10-19 05:03:52 +02:00
$this -> runLength [ 0 ] = - 1 ;
$head = 1 ;
$this -> runLength [ $head ] = 1 ;
2021-10-10 15:48:53 +02:00
} elseif ( $y > 0 ) {
if (( ord ( $frame [ $y ][ $x ]) ^ ord ( $frame [ $y - 1 ][ $x ])) & 1 ) {
++ $head ;
2020-10-19 05:03:52 +02:00
$this -> runLength [ $head ] = 1 ;
} else {
2021-10-10 15:48:53 +02:00
++ $this -> runLength [ $head ];
2020-10-19 05:03:52 +02:00
}
}
}
2021-10-10 15:48:53 +02:00
$demerit += $this -> calcN1N3 ( $head + 1 );
2020-10-19 05:03:52 +02:00
}
return $demerit ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function mask ( $width , $frame , $level )
{
$minDemerit = PHP_INT_MAX ;
$bestMaskNum = 0 ;
2021-10-10 15:48:53 +02:00
$bestMask = [];
$checked_masks = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ];
2020-10-19 05:03:52 +02:00
if ( QR_FIND_FROM_RANDOM !== false ) {
2021-10-10 15:48:53 +02:00
$howManuOut = 8 - ( QR_FIND_FROM_RANDOM % 9 );
for ( $i = 0 ; $i < $howManuOut ; ++ $i ) {
$remPos = rand ( 0 , count ( $checked_masks ) - 1 );
2020-10-19 05:03:52 +02:00
unset ( $checked_masks [ $remPos ]);
$checked_masks = array_values ( $checked_masks );
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$bestMask = $frame ;
2021-10-10 15:48:53 +02:00
foreach ( $checked_masks as $i ) {
2020-10-19 05:03:52 +02:00
$mask = array_fill ( 0 , $width , str_repeat ( " \0 " , $width ));
$demerit = 0 ;
$blacks = 0 ;
2021-10-10 15:48:53 +02:00
$blacks = $this -> makeMaskNo ( $i , $width , $frame , $mask );
2020-10-19 05:03:52 +02:00
$blacks += $this -> writeFormatInformation ( $width , $mask , $i , $level );
2021-10-10 15:48:53 +02:00
$blacks = ( int ) ( 100 * $blacks / ( $width * $width ));
$demerit = ( int ) (( int ) ( abs ( $blacks - 50 ) / 5 ) * N4 );
2020-10-19 05:03:52 +02:00
$demerit += $this -> evaluateSymbol ( $width , $mask );
2021-10-10 15:48:53 +02:00
if ( $demerit < $minDemerit ) {
2020-10-19 05:03:52 +02:00
$minDemerit = $demerit ;
$bestMask = $mask ;
$bestMaskNum = $i ;
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $bestMask ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
private function generateMaskNo ( $maskNo , $width , $frame )
{
$bitMask = array_fill ( 0 , $width , array_fill ( 0 , $width , 0 ));
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
for ( $y = 0 ; $y < $width ; ++ $y ) {
for ( $x = 0 ; $x < $width ; ++ $x ) {
if ( ord ( $frame [ $y ][ $x ]) & 0x80 ) {
$bitMask [ $y ][ $x ] = 0 ;
} else {
$maskFunc = call_user_func ([ $this , 'mask' . $maskNo ], $x , $y );
$bitMask [ $y ][ $x ] = ( 0 == $maskFunc ) ? 1 : 0 ;
}
}
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
return $bitMask ;
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
//----------------------------------------------------------------------
}
2020-10-19 05:03:52 +02:00
//---- qrencode.php -----------------------------
/*
* PHP QR Code encoder
*
* Main encoder classes .
*
* Based on libqrencode C library distributed under LGPL 2.1
* Copyright ( C ) 2006 , 2007 , 2008 , 2009 Kentaro Fukuchi < fukuchi @ megaui . net >
*
* PHP QR Code is distributed under LGPL 3
* Copyright ( C ) 2010 Dominik Dzienia < deltalab at poczta dot fm >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2021-10-10 15:48:53 +02:00
class QRrsblock
{
2020-10-19 05:03:52 +02:00
public $dataLength ;
2021-10-10 15:48:53 +02:00
public $data = [];
2020-10-19 05:03:52 +02:00
public $eccLength ;
2021-10-10 15:48:53 +02:00
public $ecc = [];
2020-10-19 05:03:52 +02:00
public function __construct ( $dl , $data , $el , & $ecc , QRrsItem $rs )
{
$rs -> encode_rs_char ( $data , $ecc );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$this -> dataLength = $dl ;
$this -> data = $data ;
$this -> eccLength = $el ;
$this -> ecc = $ecc ;
}
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
//##########################################################################
2021-10-10 15:48:53 +02:00
class QRrawcode
{
2020-10-19 05:03:52 +02:00
public $version ;
2021-10-10 15:48:53 +02:00
public $datacode = [];
public $ecccode = [];
2020-10-19 05:03:52 +02:00
public $blocks ;
2021-10-10 15:48:53 +02:00
public $rsblocks = []; //of RSblock
2020-10-19 05:03:52 +02:00
public $count ;
public $dataLength ;
public $eccLength ;
public $b1 ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function __construct ( QRinput $input )
{
2021-10-10 15:48:53 +02:00
$spec = [ 0 , 0 , 0 , 0 , 0 ];
2020-10-19 05:03:52 +02:00
$this -> datacode = $input -> getByteStream ();
2021-10-10 15:48:53 +02:00
if ( is_null ( $this -> datacode )) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'null imput string' );
}
QRspec :: getEccSpec ( $input -> getVersion (), $input -> getErrorCorrectionLevel (), $spec );
$this -> version = $input -> getVersion ();
$this -> b1 = QRspec :: rsBlockNum1 ( $spec );
$this -> dataLength = QRspec :: rsDataLength ( $spec );
$this -> eccLength = QRspec :: rsEccLength ( $spec );
$this -> ecccode = array_fill ( 0 , $this -> eccLength , 0 );
$this -> blocks = QRspec :: rsBlockNum ( $spec );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$ret = $this -> init ( $spec );
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'block alloc error' );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return null ;
}
$this -> count = 0 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function init ( array $spec )
{
$dl = QRspec :: rsDataCodes1 ( $spec );
$el = QRspec :: rsEccCodes1 ( $spec );
2021-10-10 15:48:53 +02:00
$rs = QRrs :: init_rs ( 8 , 0x11D , 0 , 1 , $el , 255 - $dl - $el );
2020-10-19 05:03:52 +02:00
$blockNo = 0 ;
$dataPos = 0 ;
$eccPos = 0 ;
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < QRspec :: rsBlockNum1 ( $spec ); ++ $i ) {
$ecc = array_slice ( $this -> ecccode , $eccPos );
$this -> rsblocks [ $blockNo ] = new QRrsblock ( $dl , array_slice ( $this -> datacode , $dataPos ), $el , $ecc , $rs );
$this -> ecccode = array_merge ( array_slice ( $this -> ecccode , 0 , $eccPos ), $ecc );
2020-10-19 05:03:52 +02:00
$dataPos += $dl ;
$eccPos += $el ;
2021-10-10 15:48:53 +02:00
++ $blockNo ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
if ( 0 == QRspec :: rsBlockNum2 ( $spec )) {
2020-10-19 05:03:52 +02:00
return 0 ;
2021-10-10 15:48:53 +02:00
}
2020-10-19 05:03:52 +02:00
$dl = QRspec :: rsDataCodes2 ( $spec );
$el = QRspec :: rsEccCodes2 ( $spec );
2021-10-10 15:48:53 +02:00
$rs = QRrs :: init_rs ( 8 , 0x11D , 0 , 1 , $el , 255 - $dl - $el );
if ( null == $rs ) {
return - 1 ;
}
for ( $i = 0 ; $i < QRspec :: rsBlockNum2 ( $spec ); ++ $i ) {
$ecc = array_slice ( $this -> ecccode , $eccPos );
2020-10-19 05:03:52 +02:00
$this -> rsblocks [ $blockNo ] = new QRrsblock ( $dl , array_slice ( $this -> datacode , $dataPos ), $el , $ecc , $rs );
2021-10-10 15:48:53 +02:00
$this -> ecccode = array_merge ( array_slice ( $this -> ecccode , 0 , $eccPos ), $ecc );
2020-10-19 05:03:52 +02:00
$dataPos += $dl ;
$eccPos += $el ;
2021-10-10 15:48:53 +02:00
++ $blockNo ;
2020-10-19 05:03:52 +02:00
}
return 0 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function getCode ()
{
2021-10-10 15:48:53 +02:00
if ( $this -> count < $this -> dataLength ) {
2020-10-19 05:03:52 +02:00
$row = $this -> count % $this -> blocks ;
$col = $this -> count / $this -> blocks ;
2021-10-10 15:48:53 +02:00
if ( $col >= $this -> rsblocks [ 0 ] -> dataLength ) {
2020-10-19 05:03:52 +02:00
$row += $this -> b1 ;
}
$ret = $this -> rsblocks [ $row ] -> data [ $col ];
2021-10-10 15:48:53 +02:00
} elseif ( $this -> count < $this -> dataLength + $this -> eccLength ) {
2020-10-19 05:03:52 +02:00
$row = ( $this -> count - $this -> dataLength ) % $this -> blocks ;
$col = ( $this -> count - $this -> dataLength ) / $this -> blocks ;
$ret = $this -> rsblocks [ $row ] -> ecc [ $col ];
} else {
return 0 ;
}
2021-10-10 15:48:53 +02:00
++ $this -> count ;
2020-10-19 05:03:52 +02:00
return $ret ;
}
}
//##########################################################################
2021-10-10 15:48:53 +02:00
class QRcode
{
2020-10-19 05:03:52 +02:00
public $version ;
public $width ;
2021-10-10 15:48:53 +02:00
public $data ;
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encodeMask ( QRinput $input , $mask )
{
2021-10-10 15:48:53 +02:00
if ( $input -> getVersion () < 0 || $input -> getVersion () > QRSPEC_VERSION_MAX ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'wrong version' );
}
2021-10-10 15:48:53 +02:00
if ( $input -> getErrorCorrectionLevel () > QR_ECLEVEL_H ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'wrong level' );
}
$raw = new QRrawcode ( $input );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
QRtools :: markTime ( 'after_raw' );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$version = $raw -> version ;
$width = QRspec :: getWidth ( $version );
$frame = QRspec :: newFrame ( $version );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$filler = new FrameFiller ( $width , $frame );
2021-10-10 15:48:53 +02:00
if ( is_null ( $filler )) {
return null ;
2020-10-19 05:03:52 +02:00
}
// inteleaved data and ecc codes
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $raw -> dataLength + $raw -> eccLength ; ++ $i ) {
2020-10-19 05:03:52 +02:00
$code = $raw -> getCode ();
$bit = 0x80 ;
2021-10-10 15:48:53 +02:00
for ( $j = 0 ; $j < 8 ; ++ $j ) {
2020-10-19 05:03:52 +02:00
$addr = $filler -> next ();
$filler -> setFrameAt ( $addr , 0x02 | (( $bit & $code ) != 0 ));
$bit = $bit >> 1 ;
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
QRtools :: markTime ( 'after_filler' );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
unset ( $raw );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
// remainder bits
$j = QRspec :: getRemainder ( $version );
2021-10-10 15:48:53 +02:00
for ( $i = 0 ; $i < $j ; ++ $i ) {
2020-10-19 05:03:52 +02:00
$addr = $filler -> next ();
$filler -> setFrameAt ( $addr , 0x02 );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$frame = $filler -> frame ;
unset ( $filler );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
// masking
$maskObj = new QRmask ();
2021-10-10 15:48:53 +02:00
if ( $mask < 0 ) {
2020-10-19 05:03:52 +02:00
if ( QR_FIND_BEST_MASK ) {
$masked = $maskObj -> mask ( $width , $frame , $input -> getErrorCorrectionLevel ());
} else {
$masked = $maskObj -> makeMask ( $width , $frame , ( intval ( QR_DEFAULT_MASK ) % 8 ), $input -> getErrorCorrectionLevel ());
}
} else {
$masked = $maskObj -> makeMask ( $width , $frame , $mask , $input -> getErrorCorrectionLevel ());
}
2021-10-10 15:48:53 +02:00
if ( null == $masked ) {
return null ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
QRtools :: markTime ( 'after_mask' );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
$this -> version = $version ;
$this -> width = $width ;
$this -> data = $masked ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $this ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encodeInput ( QRinput $input )
{
return $this -> encodeMask ( $input , - 1 );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function encodeString8bit ( $string , $version , $level )
{
2021-10-10 15:48:53 +02:00
if ( string == null ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'empty string!' );
2021-10-10 15:48:53 +02:00
return null ;
2020-10-19 05:03:52 +02:00
}
$input = new QRinput ( $version , $level );
2021-10-10 15:48:53 +02:00
if ( null == $input ) {
return null ;
}
2020-10-19 05:03:52 +02:00
$ret = $input -> append ( $input , QR_MODE_8 , strlen ( $string ), str_split ( $string ));
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
2020-10-19 05:03:52 +02:00
unset ( $input );
2021-10-10 15:48:53 +02:00
return null ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $this -> encodeInput ( $input );
}
//----------------------------------------------------------------------
public function encodeString ( $string , $version , $level , $hint , $casesensitive )
{
2021-10-10 15:48:53 +02:00
if ( QR_MODE_8 != $hint && QR_MODE_KANJI != $hint ) {
2020-10-19 05:03:52 +02:00
throw new Exception ( 'bad hint' );
2021-10-10 15:48:53 +02:00
return null ;
2020-10-19 05:03:52 +02:00
}
$input = new QRinput ( $version , $level );
2021-10-10 15:48:53 +02:00
if ( null == $input ) {
return null ;
}
2020-10-19 05:03:52 +02:00
$ret = QRsplit :: splitStringToQRinput ( $string , $input , $hint , $casesensitive );
2021-10-10 15:48:53 +02:00
if ( $ret < 0 ) {
return null ;
2020-10-19 05:03:52 +02:00
}
return $this -> encodeInput ( $input );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public static function png ( $text , $outfile = false , $level = QR_ECLEVEL_L , $size = 3 , $margin = 4 , $saveandprint = false )
2020-10-19 05:03:52 +02:00
{
$enc = QRencode :: factory ( $level , $size , $margin );
2021-10-10 15:48:53 +02:00
return $enc -> encodePNG ( $text , $outfile , $saveandprint = false );
2020-10-19 05:03:52 +02:00
}
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public static function text ( $text , $outfile = false , $level = QR_ECLEVEL_L , $size = 3 , $margin = 4 )
2020-10-19 05:03:52 +02:00
{
$enc = QRencode :: factory ( $level , $size , $margin );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $enc -> encode ( $text , $outfile );
}
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public static function raw ( $text , $outfile = false , $level = QR_ECLEVEL_L , $size = 3 , $margin = 4 )
2020-10-19 05:03:52 +02:00
{
$enc = QRencode :: factory ( $level , $size , $margin );
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $enc -> encodeRAW ( $text , $outfile );
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//##########################################################################
2021-10-10 15:48:53 +02:00
class FrameFiller
{
2020-10-19 05:03:52 +02:00
public $width ;
public $frame ;
public $x ;
public $y ;
public $dir ;
public $bit ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function __construct ( $width , & $frame )
{
$this -> width = $width ;
$this -> frame = $frame ;
$this -> x = $width - 1 ;
$this -> y = $width - 1 ;
$this -> dir = - 1 ;
$this -> bit = - 1 ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function setFrameAt ( $at , $val )
{
$this -> frame [ $at [ 'y' ]][ $at [ 'x' ]] = chr ( $val );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function getFrameAt ( $at )
{
return ord ( $this -> frame [ $at [ 'y' ]][ $at [ 'x' ]]);
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public function next ()
{
do {
2021-10-10 15:48:53 +02:00
if ( - 1 == $this -> bit ) {
2020-10-19 05:03:52 +02:00
$this -> bit = 0 ;
2021-10-10 15:48:53 +02:00
return [ 'x' => $this -> x , 'y' => $this -> y ];
2020-10-19 05:03:52 +02:00
}
$x = $this -> x ;
$y = $this -> y ;
$w = $this -> width ;
2021-10-10 15:48:53 +02:00
if ( 0 == $this -> bit ) {
-- $x ;
++ $this -> bit ;
2020-10-19 05:03:52 +02:00
} else {
2021-10-10 15:48:53 +02:00
++ $x ;
2020-10-19 05:03:52 +02:00
$y += $this -> dir ;
2021-10-10 15:48:53 +02:00
-- $this -> bit ;
2020-10-19 05:03:52 +02:00
}
2021-10-10 15:48:53 +02:00
if ( $this -> dir < 0 ) {
if ( $y < 0 ) {
2020-10-19 05:03:52 +02:00
$y = 0 ;
$x -= 2 ;
$this -> dir = 1 ;
2021-10-10 15:48:53 +02:00
if ( 6 == $x ) {
-- $x ;
2020-10-19 05:03:52 +02:00
$y = 9 ;
}
}
} else {
2021-10-10 15:48:53 +02:00
if ( $y == $w ) {
2020-10-19 05:03:52 +02:00
$y = $w - 1 ;
$x -= 2 ;
$this -> dir = - 1 ;
2021-10-10 15:48:53 +02:00
if ( 6 == $x ) {
-- $x ;
2020-10-19 05:03:52 +02:00
$y -= 8 ;
}
}
}
2021-10-10 15:48:53 +02:00
if ( $x < 0 || $y < 0 ) {
return null ;
}
2020-10-19 05:03:52 +02:00
$this -> x = $x ;
$this -> y = $y ;
2021-10-10 15:48:53 +02:00
} while ( ord ( $this -> frame [ $y ][ $x ]) & 0x80 );
return [ 'x' => $x , 'y' => $y ];
}
}
2020-10-19 05:03:52 +02:00
2021-10-10 15:48:53 +02:00
//##########################################################################
class QRencode
{
2020-10-19 05:03:52 +02:00
public $casesensitive = true ;
public $eightbit = false ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
public $version = 0 ;
public $size = 3 ;
public $margin = 4 ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
public $structured = 0 ; // not supported yet
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
public $level = QR_ECLEVEL_L ;
public $hint = QR_MODE_8 ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
public static function factory ( $level = QR_ECLEVEL_L , $size = 3 , $margin = 4 )
{
$enc = new QRencode ();
$enc -> size = $size ;
$enc -> margin = $margin ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
switch ( $level . '' ) {
case '0' :
case '1' :
case '2' :
case '3' :
$enc -> level = $level ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case 'l' :
case 'L' :
$enc -> level = QR_ECLEVEL_L ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case 'm' :
case 'M' :
$enc -> level = QR_ECLEVEL_M ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case 'q' :
case 'Q' :
$enc -> level = QR_ECLEVEL_Q ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
case 'h' :
case 'H' :
$enc -> level = QR_ECLEVEL_H ;
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
break ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $enc ;
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public function encodeRAW ( $intext , $outfile = false )
2020-10-19 05:03:52 +02:00
{
$code = new QRcode ();
2021-10-10 15:48:53 +02:00
if ( $this -> eightbit ) {
2020-10-19 05:03:52 +02:00
$code -> encodeString8bit ( $intext , $this -> version , $this -> level );
} else {
$code -> encodeString ( $intext , $this -> version , $this -> level , $this -> hint , $this -> casesensitive );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
return $code -> data ;
}
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public function encode ( $intext , $outfile = false )
2020-10-19 05:03:52 +02:00
{
$code = new QRcode ();
2021-10-10 15:48:53 +02:00
if ( $this -> eightbit ) {
2020-10-19 05:03:52 +02:00
$code -> encodeString8bit ( $intext , $this -> version , $this -> level );
} else {
$code -> encodeString ( $intext , $this -> version , $this -> level , $this -> hint , $this -> casesensitive );
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
QRtools :: markTime ( 'after_encode' );
2021-10-10 15:48:53 +02:00
if ( false !== $outfile ) {
2020-10-19 05:03:52 +02:00
file_put_contents ( $outfile , join ( " \n " , QRtools :: binarize ( $code -> data )));
} else {
return QRtools :: binarize ( $code -> data );
}
}
2021-10-10 15:48:53 +02:00
2020-10-19 05:03:52 +02:00
//----------------------------------------------------------------------
2021-10-10 15:48:53 +02:00
public function encodePNG ( $intext , $outfile = false , $saveandprint = false )
2020-10-19 05:03:52 +02:00
{
try {
ob_start ();
$tab = $this -> encode ( $intext );
$err = ob_get_contents ();
ob_end_clean ();
2021-10-10 15:48:53 +02:00
if ( '' != $err ) {
2020-10-19 05:03:52 +02:00
QRtools :: log ( $outfile , $err );
2021-10-10 15:48:53 +02:00
}
$maxSize = ( int ) ( QR_PNG_MAXIMUM_SIZE / ( count ( $tab ) + 2 * $this -> margin ));
QRimage :: png ( $tab , $outfile , min ( max ( 1 , $this -> size ), $maxSize ), $this -> margin , $saveandprint );
2020-10-19 05:03:52 +02:00
} catch ( Exception $e ) {
QRtools :: log ( $outfile , $e -> getMessage ());
}
}
}