├── qrcode ├── qrconfig.php ├── qrlib.php ├── qrconst.php ├── qrimage.php ├── qrbitstream.php ├── qrtools.php ├── qrrscode.php ├── qrsplit.php ├── qrmask.php ├── qrencode.php ├── qrinput.php └── qrspec.php ├── README.md └── Ciqrcode.php /qrcode/qrconfig.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * PHP QR Code is distributed under LGPL 3 11 | * Copyright (C) 2010 Dominik Dzienia 12 | * 13 | * This library is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 3 of the License, or any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Lesser General Public 24 | * License along with this library; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26 | */ 27 | 28 | $QR_BASEDIR = dirname(__FILE__).DIRECTORY_SEPARATOR; 29 | 30 | // Required libs 31 | 32 | include $QR_BASEDIR."qrconst.php"; 33 | include $QR_BASEDIR."qrconfig.php"; 34 | include $QR_BASEDIR."qrtools.php"; 35 | include $QR_BASEDIR."qrspec.php"; 36 | include $QR_BASEDIR."qrimage.php"; 37 | include $QR_BASEDIR."qrinput.php"; 38 | include $QR_BASEDIR."qrbitstream.php"; 39 | include $QR_BASEDIR."qrsplit.php"; 40 | include $QR_BASEDIR."qrrscode.php"; 41 | include $QR_BASEDIR."qrmask.php"; 42 | include $QR_BASEDIR."qrencode.php"; 43 | 44 | -------------------------------------------------------------------------------- /qrcode/qrconst.php: -------------------------------------------------------------------------------- 1 | 10 | * 11 | * PHP QR Code is distributed under LGPL 3 12 | * Copyright (C) 2010 Dominik Dzienia 13 | * 14 | * This library is free software; you can redistribute it and/or 15 | * modify it under the terms of the GNU Lesser General Public 16 | * License as published by the Free Software Foundation; either 17 | * version 3 of the License, or any later version. 18 | * 19 | * This library is distributed in the hope that it will be useful, 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | * Lesser General Public License for more details. 23 | * 24 | * You should have received a copy of the GNU Lesser General Public 25 | * License along with this library; if not, write to the Free Software 26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 27 | */ 28 | 29 | // Encoding modes 30 | 31 | define('QR_MODE_NUL', -1); 32 | define('QR_MODE_NUM', 0); 33 | define('QR_MODE_AN', 1); 34 | define('QR_MODE_8', 2); 35 | define('QR_MODE_KANJI', 3); 36 | define('QR_MODE_STRUCTURE', 4); 37 | 38 | // Levels of error correction. 39 | 40 | define('QR_ECLEVEL_L', 0); 41 | define('QR_ECLEVEL_M', 1); 42 | define('QR_ECLEVEL_Q', 2); 43 | define('QR_ECLEVEL_H', 3); 44 | 45 | // Supported output formats 46 | 47 | define('QR_FORMAT_TEXT', 0); 48 | define('QR_FORMAT_PNG', 1); 49 | 50 | class qrstr { 51 | public static function set(&$srctab, $x, $y, $repl, $replLen = false) { 52 | $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl)); 53 | } 54 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Codeigniter PHP QR Code 2 | ======================= 3 | 4 | Version 1 - Dec 2011 5 | by dwi.setiyadi@gmail.com 6 | 7 | 8 | 9 | Introduction 10 | ------------ 11 | 12 | This a library for CodeIgniter Framework to make QR Code from some string given, a porting code from http://phpqrcode.sourceforge.net/. 13 | 14 | 15 | Installation and Requirements 16 | ----------------------------- 17 | 18 | This library requires CodeIgniter Framework and GD2 PHP extension. 19 | 20 | 21 | ### How to use ### 22 | 23 | On the fly generate 24 | 25 | $this->load->library('ciqrcode'); 26 | 27 | header("Content-Type: image/png"); 28 | $params['data'] = 'This is a text to encode become QR Code'; 29 | $this->ciqrcode->generate($params); 30 | 31 | 32 | 33 | Saved QR Code image example 34 | 35 | $this->load->library('ciqrcode'); 36 | 37 | $params['data'] = 'This is a text to encode become QR Code'; 38 | $params['level'] = 'H'; 39 | $params['size'] = 10; 40 | $params['savename'] = FCPATH.'tes.png'; 41 | $this->ciqrcode->generate($params); 42 | 43 | echo ''; 44 | 45 | 46 | 47 | Optional configuration 48 | 49 | $this->load->library('ciqrcode'); 50 | 51 | $config['cacheable'] = true; //boolean, the default is true 52 | $config['cachedir'] = ''; //string, the default is application/cache/ 53 | $config['errorlog'] = ''; //string, the default is application/logs/ 54 | $config['quality'] = true; //boolean, the default is true 55 | $config['size'] = ''; //interger, the default is 1024 56 | $config['black'] = array(224,255,255); // array, default is array(255,255,255) 57 | $config['white'] = array(70,130,180); // array, default is array(0,0,0) 58 | $this->ciqrcode->initialize($config); 59 | 60 | 61 | Contributors 62 | ------------ 63 | 1. [Jared Hatfield](https://github.com/JaredHatfield "Jared Hatfield") 64 | 2. [Collin Price](https://github.com/collinprice "Collin Price") 65 | 3. [Jason Walker](https://github.com/jcwalker3 "Jason WalkerJason Walker") 66 | -------------------------------------------------------------------------------- /qrcode/qrimage.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU Lesser General Public 12 | * License as published by the Free Software Foundation; either 13 | * version 3 of the License, or any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | * Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public 21 | * License along with this library; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | */ 24 | 25 | define('QR_IMAGE', true); 26 | 27 | class QRimage { 28 | 29 | public static $black = array(255,255,255); 30 | public static $white = array(0,0,0); 31 | 32 | //---------------------------------------------------------------------- 33 | public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE) 34 | { 35 | $image = self::image($frame, $pixelPerPoint, $outerFrame); 36 | 37 | if ($filename === false) { 38 | Header("Content-type: image/png"); 39 | ImagePng($image); 40 | } else { 41 | if($saveandprint===TRUE){ 42 | ImagePng($image, $filename); 43 | header("Content-type: image/png"); 44 | ImagePng($image); 45 | }else{ 46 | ImagePng($image, $filename); 47 | } 48 | } 49 | 50 | ImageDestroy($image); 51 | } 52 | 53 | //---------------------------------------------------------------------- 54 | public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85) 55 | { 56 | $image = self::image($frame, $pixelPerPoint, $outerFrame); 57 | 58 | if ($filename === false) { 59 | Header("Content-type: image/jpeg"); 60 | ImageJpeg($image, null, $q); 61 | } else { 62 | ImageJpeg($image, $filename, $q); 63 | } 64 | 65 | ImageDestroy($image); 66 | } 67 | 68 | //---------------------------------------------------------------------- 69 | private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4) 70 | { 71 | $h = count($frame); 72 | $w = strlen($frame[0]); 73 | 74 | $imgW = $w + 2*$outerFrame; 75 | $imgH = $h + 2*$outerFrame; 76 | 77 | $base_image =ImageCreate($imgW, $imgH); 78 | 79 | $col[0] = ImageColorAllocate($base_image,QRImage::$black[0],QRImage::$black[1],QRImage::$black[2]); 80 | $col[1] = ImageColorAllocate($base_image,QRImage::$white[0],QRImage::$white[1],QRImage::$white[2]); 81 | 82 | imagefill($base_image, 0, 0, $col[0]); 83 | 84 | for($y=0; $y<$h; $y++) { 85 | for($x=0; $x<$w; $x++) { 86 | if ($frame[$y][$x] == '1') { 87 | ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]); 88 | } 89 | } 90 | } 91 | 92 | $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint); 93 | ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH); 94 | ImageDestroy($base_image); 95 | 96 | return $target_image; 97 | } 98 | } -------------------------------------------------------------------------------- /Ciqrcode.php: -------------------------------------------------------------------------------- 1 | initialize($config); 36 | } 37 | 38 | public function initialize($config = array()) { 39 | $this->cacheable = (isset($config['cacheable'])) ? $config['cacheable'] : $this->cacheable; 40 | $this->cachedir = (isset($config['cachedir'])) ? $config['cachedir'] : FCPATH.$this->cachedir; 41 | $this->errorlog = (isset($config['errorlog'])) ? $config['errorlog'] : FCPATH.$this->errorlog; 42 | $this->quality = (isset($config['quality'])) ? $config['quality'] : $this->quality; 43 | $this->size = (isset($config['size'])) ? $config['size'] : $this->size; 44 | 45 | // use cache - more disk reads but less CPU power, masks and format templates are stored there 46 | if (!defined('QR_CACHEABLE')) define('QR_CACHEABLE', $this->cacheable); 47 | 48 | // used when QR_CACHEABLE === true 49 | if (!defined('QR_CACHE_DIR')) define('QR_CACHE_DIR', $this->cachedir); 50 | 51 | // default error logs dir 52 | if (!defined('QR_LOG_DIR')) define('QR_LOG_DIR', $this->errorlog); 53 | 54 | // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code 55 | if ($this->quality) { 56 | if (!defined('QR_FIND_BEST_MASK')) define('QR_FIND_BEST_MASK', true); 57 | } else { 58 | if (!defined('QR_FIND_BEST_MASK')) define('QR_FIND_BEST_MASK', false); 59 | if (!defined('QR_DEFAULT_MASK')) define('QR_DEFAULT_MASK', $this->quality); 60 | } 61 | 62 | // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly 63 | if (!defined('QR_FIND_FROM_RANDOM')) define('QR_FIND_FROM_RANDOM', false); 64 | 65 | // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images 66 | if (!defined('QR_PNG_MAXIMUM_SIZE')) define('QR_PNG_MAXIMUM_SIZE', $this->size); 67 | } 68 | 69 | public function generate($params = array()) { 70 | if (isset($params['black']) 71 | && is_array($params['black']) 72 | && count($params['black']) == 3 73 | && array_filter($params['black'], 'is_int') === $params['black']) { 74 | QRimage::$black = $params['black']; 75 | } 76 | 77 | if (isset($params['white']) 78 | && is_array($params['white']) 79 | && count($params['white']) == 3 80 | && array_filter($params['white'], 'is_int') === $params['white']) { 81 | QRimage::$white = $params['white']; 82 | } 83 | 84 | $params['data'] = (isset($params['data'])) ? $params['data'] : 'QR Code Library'; 85 | if (isset($params['savename'])) { 86 | $level = 'L'; 87 | if (isset($params['level']) && in_array($params['level'], array('L','M','Q','H'))) $level = $params['level']; 88 | 89 | $size = 4; 90 | if (isset($params['size'])) $size = min(max((int)$params['size'], 1), 10); 91 | 92 | QRcode::png($params['data'], $params['savename'], $level, $size, 2); 93 | return $params['savename']; 94 | } else { 95 | $level = 'L'; 96 | if (isset($params['level']) && in_array($params['level'], array('L','M','Q','H'))) $level = $params['level']; 97 | 98 | $size = 4; 99 | if (isset($params['size'])) $size = min(max((int)$params['size'], 1), 10); 100 | 101 | QRcode::png($params['data'], NULL, $level, $size, 2); 102 | } 103 | } 104 | } 105 | 106 | /* end of file */ 107 | -------------------------------------------------------------------------------- /qrcode/qrbitstream.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * PHP QR Code is distributed under LGPL 3 11 | * Copyright (C) 2010 Dominik Dzienia 12 | * 13 | * This library is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 3 of the License, or any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Lesser General Public 24 | * License along with this library; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26 | */ 27 | 28 | class QRbitstream { 29 | 30 | public $data = array(); 31 | 32 | //---------------------------------------------------------------------- 33 | public function size() 34 | { 35 | return count($this->data); 36 | } 37 | 38 | //---------------------------------------------------------------------- 39 | public function allocate($setLength) 40 | { 41 | $this->data = array_fill(0, $setLength, 0); 42 | return 0; 43 | } 44 | 45 | //---------------------------------------------------------------------- 46 | public static function newFromNum($bits, $num) 47 | { 48 | $bstream = new QRbitstream(); 49 | $bstream->allocate($bits); 50 | 51 | $mask = 1 << ($bits - 1); 52 | for($i=0; $i<$bits; $i++) { 53 | if($num & $mask) { 54 | $bstream->data[$i] = 1; 55 | } else { 56 | $bstream->data[$i] = 0; 57 | } 58 | $mask = $mask >> 1; 59 | } 60 | 61 | return $bstream; 62 | } 63 | 64 | //---------------------------------------------------------------------- 65 | public static function newFromBytes($size, $data) 66 | { 67 | $bstream = new QRbitstream(); 68 | $bstream->allocate($size * 8); 69 | $p=0; 70 | 71 | for($i=0; $i<$size; $i++) { 72 | $mask = 0x80; 73 | for($j=0; $j<8; $j++) { 74 | if($data[$i] & $mask) { 75 | $bstream->data[$p] = 1; 76 | } else { 77 | $bstream->data[$p] = 0; 78 | } 79 | $p++; 80 | $mask = $mask >> 1; 81 | } 82 | } 83 | 84 | return $bstream; 85 | } 86 | 87 | //---------------------------------------------------------------------- 88 | public function append(QRbitstream $arg) 89 | { 90 | if (is_null($arg)) { 91 | return -1; 92 | } 93 | 94 | if($arg->size() == 0) { 95 | return 0; 96 | } 97 | 98 | if($this->size() == 0) { 99 | $this->data = $arg->data; 100 | return 0; 101 | } 102 | 103 | $this->data = array_values(array_merge($this->data, $arg->data)); 104 | 105 | return 0; 106 | } 107 | 108 | //---------------------------------------------------------------------- 109 | public function appendNum($bits, $num) 110 | { 111 | if ($bits == 0) 112 | return 0; 113 | 114 | $b = QRbitstream::newFromNum($bits, $num); 115 | 116 | if(is_null($b)) 117 | return -1; 118 | 119 | $ret = $this->append($b); 120 | unset($b); 121 | 122 | return $ret; 123 | } 124 | 125 | //---------------------------------------------------------------------- 126 | public function appendBytes($size, $data) 127 | { 128 | if ($size == 0) 129 | return 0; 130 | 131 | $b = QRbitstream::newFromBytes($size, $data); 132 | 133 | if(is_null($b)) 134 | return -1; 135 | 136 | $ret = $this->append($b); 137 | unset($b); 138 | 139 | return $ret; 140 | } 141 | 142 | //---------------------------------------------------------------------- 143 | public function toByte() 144 | { 145 | 146 | $size = $this->size(); 147 | 148 | if($size == 0) { 149 | return array(); 150 | } 151 | 152 | $data = array_fill(0, (int)(($size + 7) / 8), 0); 153 | $bytes = (int)($size / 8); 154 | 155 | $p = 0; 156 | 157 | for($i=0; $i<$bytes; $i++) { 158 | $v = 0; 159 | for($j=0; $j<8; $j++) { 160 | $v = $v << 1; 161 | $v |= $this->data[$p]; 162 | $p++; 163 | } 164 | $data[$i] = $v; 165 | } 166 | 167 | if($size & 7) { 168 | $v = 0; 169 | for($j=0; $j<($size & 7); $j++) { 170 | $v = $v << 1; 171 | $v |= $this->data[$p]; 172 | $p++; 173 | } 174 | $data[$bytes] = $v; 175 | } 176 | 177 | return $data; 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /qrcode/qrtools.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU Lesser General Public 12 | * License as published by the Free Software Foundation; either 13 | * version 3 of the License, or any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | * Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public 21 | * License along with this library; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | */ 24 | 25 | class QRtools { 26 | 27 | //---------------------------------------------------------------------- 28 | public static function binarize($frame) 29 | { 30 | $len = count($frame); 31 | foreach ($frame as &$frameLine) { 32 | 33 | for($i=0; $i<$len; $i++) { 34 | $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0'; 35 | } 36 | } 37 | 38 | return $frame; 39 | } 40 | 41 | //---------------------------------------------------------------------- 42 | public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037') 43 | { 44 | $barcode_array = array(); 45 | 46 | if (!is_array($mode)) 47 | $mode = explode(',', $mode); 48 | 49 | $eccLevel = 'L'; 50 | 51 | if (count($mode) > 1) { 52 | $eccLevel = $mode[1]; 53 | } 54 | 55 | $qrTab = QRcode::text($code, false, $eccLevel); 56 | $size = count($qrTab); 57 | 58 | $barcode_array['num_rows'] = $size; 59 | $barcode_array['num_cols'] = $size; 60 | $barcode_array['bcode'] = array(); 61 | 62 | foreach ($qrTab as $line) { 63 | $arrAdd = array(); 64 | foreach(str_split($line) as $char) 65 | $arrAdd[] = ($char=='1')?1:0; 66 | $barcode_array['bcode'][] = $arrAdd; 67 | } 68 | 69 | return $barcode_array; 70 | } 71 | 72 | //---------------------------------------------------------------------- 73 | public static function clearCache() 74 | { 75 | self::$frames = array(); 76 | } 77 | 78 | //---------------------------------------------------------------------- 79 | public static function buildCache() 80 | { 81 | QRtools::markTime('before_build_cache'); 82 | 83 | $mask = new QRmask(); 84 | for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) { 85 | $frame = QRspec::newFrame($a); 86 | if (QR_IMAGE) { 87 | $fileName = QR_CACHE_DIR.'frame_'.$a.'.png'; 88 | QRimage::png(self::binarize($frame), $fileName, 1, 0); 89 | } 90 | 91 | $width = count($frame); 92 | $bitMask = array_fill(0, $width, array_fill(0, $width, 0)); 93 | for ($maskNo=0; $maskNo<8; $maskNo++) 94 | $mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true); 95 | } 96 | 97 | QRtools::markTime('after_build_cache'); 98 | } 99 | 100 | //---------------------------------------------------------------------- 101 | public static function log($outfile, $err) 102 | { 103 | if (QR_LOG_DIR !== false) { 104 | if ($err != '') { 105 | if ($outfile !== false) { 106 | file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND); 107 | } else { 108 | file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND); 109 | } 110 | } 111 | } 112 | } 113 | 114 | //---------------------------------------------------------------------- 115 | public static function dumpMask($frame) 116 | { 117 | $width = count($frame); 118 | for($y=0;$y<$width;$y++) { 119 | for($x=0;$x<$width;$x++) { 120 | echo ord($frame[$y][$x]).','; 121 | } 122 | } 123 | } 124 | 125 | //---------------------------------------------------------------------- 126 | public static function markTime($markerId) 127 | { 128 | list($usec, $sec) = explode(" ", microtime()); 129 | $time = ((float)$usec + (float)$sec); 130 | 131 | if (!isset($GLOBALS['qr_time_bench'])) 132 | $GLOBALS['qr_time_bench'] = array(); 133 | 134 | $GLOBALS['qr_time_bench'][$markerId] = $time; 135 | } 136 | 137 | //---------------------------------------------------------------------- 138 | public static function timeBenchmark() 139 | { 140 | self::markTime('finish'); 141 | 142 | $lastTime = 0; 143 | $startTime = 0; 144 | $p = 0; 145 | 146 | echo ' 147 | 148 | '; 149 | 150 | foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) { 151 | if ($p > 0) { 152 | echo ''; 153 | } else { 154 | $startTime = $thisTime; 155 | } 156 | 157 | $p++; 158 | $lastTime = $thisTime; 159 | } 160 | 161 | echo ' 162 | 163 | 164 |
BENCHMARK
till '.$markerId.': '.number_format($thisTime-$lastTime, 6).'s
TOTAL: '.number_format($lastTime-$startTime, 6).'s
'; 165 | } 166 | 167 | } 168 | 169 | //########################################################################## 170 | 171 | QRtools::markTime('start'); 172 | -------------------------------------------------------------------------------- /qrcode/qrrscode.php: -------------------------------------------------------------------------------- 1 | 12 | * 13 | * PHP QR Code is distributed under LGPL 3 14 | * Copyright (C) 2010 Dominik Dzienia 15 | * 16 | * This library is free software; you can redistribute it and/or 17 | * modify it under the terms of the GNU Lesser General Public 18 | * License as published by the Free Software Foundation; either 19 | * version 3 of the License, or any later version. 20 | * 21 | * This library is distributed in the hope that it will be useful, 22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 | * Lesser General Public License for more details. 25 | * 26 | * You should have received a copy of the GNU Lesser General Public 27 | * License along with this library; if not, write to the Free Software 28 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 | */ 30 | 31 | class QRrsItem { 32 | 33 | public $mm; // Bits per symbol 34 | public $nn; // Symbols per block (= (1<= $this->nn) { 49 | $x -= $this->nn; 50 | $x = ($x >> $this->mm) + ($x & $this->nn); 51 | } 52 | 53 | return $x; 54 | } 55 | 56 | //---------------------------------------------------------------------- 57 | public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) 58 | { 59 | // Common code for intializing a Reed-Solomon control block (char or int symbols) 60 | // Copyright 2004 Phil Karn, KA9Q 61 | // May be used under the terms of the GNU Lesser General Public License (LGPL) 62 | 63 | $rs = null; 64 | 65 | // Check parameter ranges 66 | if($symsize < 0 || $symsize > 8) return $rs; 67 | if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs; 68 | if($prim <= 0 || $prim >= (1<<$symsize)) return $rs; 69 | if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; // Can't have more roots than symbol values! 70 | if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding 71 | 72 | $rs = new QRrsItem(); 73 | $rs->mm = $symsize; 74 | $rs->nn = (1<<$symsize)-1; 75 | $rs->pad = $pad; 76 | 77 | $rs->alpha_to = array_fill(0, $rs->nn+1, 0); 78 | $rs->index_of = array_fill(0, $rs->nn+1, 0); 79 | 80 | // PHP style macro replacement ;) 81 | $NN =& $rs->nn; 82 | $A0 =& $NN; 83 | 84 | // Generate Galois field lookup tables 85 | $rs->index_of[0] = $A0; // log(zero) = -inf 86 | $rs->alpha_to[$A0] = 0; // alpha**-inf = 0 87 | $sr = 1; 88 | 89 | for($i=0; $i<$rs->nn; $i++) { 90 | $rs->index_of[$sr] = $i; 91 | $rs->alpha_to[$i] = $sr; 92 | $sr <<= 1; 93 | if($sr & (1<<$symsize)) { 94 | $sr ^= $gfpoly; 95 | } 96 | $sr &= $rs->nn; 97 | } 98 | 99 | if($sr != 1){ 100 | // field generator polynomial is not primitive! 101 | $rs = NULL; 102 | return $rs; 103 | } 104 | 105 | /* Form RS code generator polynomial from its roots */ 106 | $rs->genpoly = array_fill(0, $nroots+1, 0); 107 | 108 | $rs->fcr = $fcr; 109 | $rs->prim = $prim; 110 | $rs->nroots = $nroots; 111 | $rs->gfpoly = $gfpoly; 112 | 113 | /* Find prim-th root of 1, used in decoding */ 114 | for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn) 115 | ; // intentional empty-body loop! 116 | 117 | $rs->iprim = (int)($iprim / $prim); 118 | $rs->genpoly[0] = 1; 119 | 120 | for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) { 121 | $rs->genpoly[$i+1] = 1; 122 | 123 | // Multiply rs->genpoly[] by @**(root + x) 124 | for ($j = $i; $j > 0; $j--) { 125 | if ($rs->genpoly[$j] != 0) { 126 | $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)]; 127 | } else { 128 | $rs->genpoly[$j] = $rs->genpoly[$j-1]; 129 | } 130 | } 131 | // rs->genpoly[0] can never be zero 132 | $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)]; 133 | } 134 | 135 | // convert rs->genpoly[] to index form for quicker encoding 136 | for ($i = 0; $i <= $nroots; $i++) 137 | $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]]; 138 | 139 | return $rs; 140 | } 141 | 142 | //---------------------------------------------------------------------- 143 | public function encode_rs_char($data, &$parity) 144 | { 145 | $MM =& $this->mm; 146 | $NN =& $this->nn; 147 | $ALPHA_TO =& $this->alpha_to; 148 | $INDEX_OF =& $this->index_of; 149 | $GENPOLY =& $this->genpoly; 150 | $NROOTS =& $this->nroots; 151 | $FCR =& $this->fcr; 152 | $PRIM =& $this->prim; 153 | $IPRIM =& $this->iprim; 154 | $PAD =& $this->pad; 155 | $A0 =& $NN; 156 | 157 | $parity = array_fill(0, $NROOTS, 0); 158 | 159 | for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) { 160 | 161 | $feedback = $INDEX_OF[$data[$i] ^ $parity[0]]; 162 | if($feedback != $A0) { 163 | // feedback term is non-zero 164 | 165 | // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must 166 | // always be for the polynomials constructed by init_rs() 167 | $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback); 168 | 169 | for($j=1;$j<$NROOTS;$j++) { 170 | $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])]; 171 | } 172 | } 173 | 174 | // Shift 175 | array_shift($parity); 176 | if($feedback != $A0) { 177 | array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]); 178 | } else { 179 | array_push($parity, 0); 180 | } 181 | } 182 | } 183 | } 184 | 185 | //########################################################################## 186 | 187 | class QRrs { 188 | 189 | public static $items = array(); 190 | 191 | //---------------------------------------------------------------------- 192 | public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) 193 | { 194 | foreach(self::$items as $rs) { 195 | if($rs->pad != $pad) continue; 196 | if($rs->nroots != $nroots) continue; 197 | if($rs->mm != $symsize) continue; 198 | if($rs->gfpoly != $gfpoly) continue; 199 | if($rs->fcr != $fcr) continue; 200 | if($rs->prim != $prim) continue; 201 | 202 | return $rs; 203 | } 204 | 205 | $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad); 206 | array_unshift(self::$items, $rs); 207 | 208 | return $rs; 209 | } 210 | } -------------------------------------------------------------------------------- /qrcode/qrsplit.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * PHP QR Code is distributed under LGPL 3 11 | * Copyright (C) 2010 Dominik Dzienia 12 | * 13 | * The following data / specifications are taken from 14 | * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) 15 | * or 16 | * "Automatic identification and data capture techniques -- 17 | * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 3 of the License, or any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library; if not, write to the Free Software 31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 32 | */ 33 | class QRsplit { 34 | 35 | public $dataStr = ''; 36 | public $input; 37 | public $modeHint; 38 | 39 | //---------------------------------------------------------------------- 40 | public function __construct($dataStr, $input, $modeHint) 41 | { 42 | $this->dataStr = $dataStr; 43 | $this->input = $input; 44 | $this->modeHint = $modeHint; 45 | } 46 | 47 | //---------------------------------------------------------------------- 48 | public static function isdigitat($str, $pos) 49 | { 50 | if ($pos >= strlen($str)) 51 | return false; 52 | 53 | return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9'))); 54 | } 55 | 56 | //---------------------------------------------------------------------- 57 | public static function isalnumat($str, $pos) 58 | { 59 | if ($pos >= strlen($str)) 60 | return false; 61 | 62 | return (QRinput::lookAnTable(ord($str[$pos])) >= 0); 63 | } 64 | 65 | //---------------------------------------------------------------------- 66 | public function identifyMode($pos) 67 | { 68 | if ($pos >= strlen($this->dataStr)) 69 | return QR_MODE_NUL; 70 | 71 | $c = $this->dataStr[$pos]; 72 | 73 | if(self::isdigitat($this->dataStr, $pos)) { 74 | return QR_MODE_NUM; 75 | } else if(self::isalnumat($this->dataStr, $pos)) { 76 | return QR_MODE_AN; 77 | } else if($this->modeHint == QR_MODE_KANJI) { 78 | 79 | if ($pos+1 < strlen($this->dataStr)) 80 | { 81 | $d = $this->dataStr[$pos+1]; 82 | $word = (ord($c) << 8) | ord($d); 83 | if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) { 84 | return QR_MODE_KANJI; 85 | } 86 | } 87 | } 88 | 89 | return QR_MODE_8; 90 | } 91 | 92 | //---------------------------------------------------------------------- 93 | public function eatNum() 94 | { 95 | $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); 96 | 97 | $p = 0; 98 | while(self::isdigitat($this->dataStr, $p)) { 99 | $p++; 100 | } 101 | 102 | $run = $p; 103 | $mode = $this->identifyMode($p); 104 | 105 | if($mode == QR_MODE_8) { 106 | $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln 107 | + QRinput::estimateBitsMode8(1) // + 4 + l8 108 | - QRinput::estimateBitsMode8($run + 1); // - 4 - l8 109 | if($dif > 0) { 110 | return $this->eat8(); 111 | } 112 | } 113 | if($mode == QR_MODE_AN) { 114 | $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln 115 | + QRinput::estimateBitsModeAn(1) // + 4 + la 116 | - QRinput::estimateBitsModeAn($run + 1);// - 4 - la 117 | if($dif > 0) { 118 | return $this->eatAn(); 119 | } 120 | } 121 | 122 | $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr)); 123 | if($ret < 0) 124 | return -1; 125 | 126 | return $run; 127 | } 128 | 129 | //---------------------------------------------------------------------- 130 | public function eatAn() 131 | { 132 | $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion()); 133 | $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); 134 | 135 | $p = 0; 136 | 137 | while(self::isalnumat($this->dataStr, $p)) { 138 | if(self::isdigitat($this->dataStr, $p)) { 139 | $q = $p; 140 | while(self::isdigitat($this->dataStr, $q)) { 141 | $q++; 142 | } 143 | 144 | $dif = QRinput::estimateBitsModeAn($p) // + 4 + la 145 | + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln 146 | - QRinput::estimateBitsModeAn($q); // - 4 - la 147 | 148 | if($dif < 0) { 149 | break; 150 | } else { 151 | $p = $q; 152 | } 153 | } else { 154 | $p++; 155 | } 156 | } 157 | 158 | $run = $p; 159 | 160 | if(!self::isalnumat($this->dataStr, $p)) { 161 | $dif = QRinput::estimateBitsModeAn($run) + 4 + $la 162 | + QRinput::estimateBitsMode8(1) // + 4 + l8 163 | - QRinput::estimateBitsMode8($run + 1); // - 4 - l8 164 | if($dif > 0) { 165 | return $this->eat8(); 166 | } 167 | } 168 | 169 | $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr)); 170 | if($ret < 0) 171 | return -1; 172 | 173 | return $run; 174 | } 175 | 176 | //---------------------------------------------------------------------- 177 | public function eatKanji() 178 | { 179 | $p = 0; 180 | 181 | while($this->identifyMode($p) == QR_MODE_KANJI) { 182 | $p += 2; 183 | } 184 | 185 | $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr)); 186 | if($ret < 0) 187 | return -1; 188 | 189 | return $run; 190 | } 191 | 192 | //---------------------------------------------------------------------- 193 | public function eat8() 194 | { 195 | $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion()); 196 | $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion()); 197 | 198 | $p = 1; 199 | $dataStrLen = strlen($this->dataStr); 200 | 201 | while($p < $dataStrLen) { 202 | 203 | $mode = $this->identifyMode($p); 204 | if($mode == QR_MODE_KANJI) { 205 | break; 206 | } 207 | if($mode == QR_MODE_NUM) { 208 | $q = $p; 209 | while(self::isdigitat($this->dataStr, $q)) { 210 | $q++; 211 | } 212 | $dif = QRinput::estimateBitsMode8($p) // + 4 + l8 213 | + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln 214 | - QRinput::estimateBitsMode8($q); // - 4 - l8 215 | if($dif < 0) { 216 | break; 217 | } else { 218 | $p = $q; 219 | } 220 | } else if($mode == QR_MODE_AN) { 221 | $q = $p; 222 | while(self::isalnumat($this->dataStr, $q)) { 223 | $q++; 224 | } 225 | $dif = QRinput::estimateBitsMode8($p) // + 4 + l8 226 | + QRinput::estimateBitsModeAn($q - $p) + 4 + $la 227 | - QRinput::estimateBitsMode8($q); // - 4 - l8 228 | if($dif < 0) { 229 | break; 230 | } else { 231 | $p = $q; 232 | } 233 | } else { 234 | $p++; 235 | } 236 | } 237 | 238 | $run = $p; 239 | $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr)); 240 | 241 | if($ret < 0) 242 | return -1; 243 | 244 | return $run; 245 | } 246 | 247 | //---------------------------------------------------------------------- 248 | public function splitString() 249 | { 250 | while (strlen($this->dataStr) > 0) 251 | { 252 | if($this->dataStr == '') 253 | return 0; 254 | 255 | $mode = $this->identifyMode(0); 256 | 257 | switch ($mode) { 258 | case QR_MODE_NUM: $length = $this->eatNum(); break; 259 | case QR_MODE_AN: $length = $this->eatAn(); break; 260 | case QR_MODE_KANJI: 261 | if ($hint == QR_MODE_KANJI) 262 | $length = $this->eatKanji(); 263 | else $length = $this->eat8(); 264 | break; 265 | default: $length = $this->eat8(); break; 266 | 267 | } 268 | 269 | if($length == 0) return 0; 270 | if($length < 0) return -1; 271 | 272 | $this->dataStr = substr($this->dataStr, $length); 273 | } 274 | } 275 | 276 | //---------------------------------------------------------------------- 277 | public function toUpper() 278 | { 279 | $stringLen = strlen($this->dataStr); 280 | $p = 0; 281 | 282 | while ($p<$stringLen) { 283 | $mode = self::identifyMode(substr($this->dataStr, $p), $this->modeHint); 284 | if($mode == QR_MODE_KANJI) { 285 | $p += 2; 286 | } else { 287 | if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) { 288 | $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32); 289 | } 290 | $p++; 291 | } 292 | } 293 | 294 | return $this->dataStr; 295 | } 296 | 297 | //---------------------------------------------------------------------- 298 | public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true) 299 | { 300 | if(is_null($string) || $string == '\0' || $string == '') { 301 | throw new Exception('empty string!!!'); 302 | } 303 | 304 | $split = new QRsplit($string, $input, $modeHint); 305 | 306 | if(!$casesensitive) 307 | $split->toUpper(); 308 | 309 | return $split->splitString(); 310 | } 311 | } -------------------------------------------------------------------------------- /qrcode/qrmask.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * PHP QR Code is distributed under LGPL 3 11 | * Copyright (C) 2010 Dominik Dzienia 12 | * 13 | * This library is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 3 of the License, or any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Lesser General Public 24 | * License along with this library; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26 | */ 27 | 28 | define('N1', 3); 29 | define('N2', 3); 30 | define('N3', 40); 31 | define('N4', 10); 32 | 33 | class QRmask { 34 | 35 | public $runLength = array(); 36 | 37 | //---------------------------------------------------------------------- 38 | public function __construct() 39 | { 40 | $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0); 41 | } 42 | 43 | //---------------------------------------------------------------------- 44 | public function writeFormatInformation($width, &$frame, $mask, $level) 45 | { 46 | $blacks = 0; 47 | $format = QRspec::getFormatInfo($mask, $level); 48 | 49 | for($i=0; $i<8; $i++) { 50 | if($format & 1) { 51 | $blacks += 2; 52 | $v = 0x85; 53 | } else { 54 | $v = 0x84; 55 | } 56 | 57 | $frame[8][$width - 1 - $i] = chr($v); 58 | if($i < 6) { 59 | $frame[$i][8] = chr($v); 60 | } else { 61 | $frame[$i + 1][8] = chr($v); 62 | } 63 | $format = $format >> 1; 64 | } 65 | 66 | for($i=0; $i<7; $i++) { 67 | if($format & 1) { 68 | $blacks += 2; 69 | $v = 0x85; 70 | } else { 71 | $v = 0x84; 72 | } 73 | 74 | $frame[$width - 7 + $i][8] = chr($v); 75 | if($i == 0) { 76 | $frame[8][7] = chr($v); 77 | } else { 78 | $frame[8][6 - $i] = chr($v); 79 | } 80 | 81 | $format = $format >> 1; 82 | } 83 | 84 | return $blacks; 85 | } 86 | 87 | //---------------------------------------------------------------------- 88 | public function mask0($x, $y) { return ($x+$y)&1; } 89 | public function mask1($x, $y) { return ($y&1); } 90 | public function mask2($x, $y) { return ($x%3); } 91 | public function mask3($x, $y) { return ($x+$y)%3; } 92 | public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; } 93 | public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3; } 94 | public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1; } 95 | public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1; } 96 | 97 | //---------------------------------------------------------------------- 98 | private function generateMaskNo($maskNo, $width, $frame) 99 | { 100 | $bitMask = array_fill(0, $width, array_fill(0, $width, 0)); 101 | 102 | for($y=0; $y<$width; $y++) { 103 | for($x=0; $x<$width; $x++) { 104 | if(ord($frame[$y][$x]) & 0x80) { 105 | $bitMask[$y][$x] = 0; 106 | } else { 107 | $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y); 108 | $bitMask[$y][$x] = ($maskFunc == 0)?1:0; 109 | } 110 | 111 | } 112 | } 113 | 114 | return $bitMask; 115 | } 116 | 117 | //---------------------------------------------------------------------- 118 | public static function serial($bitFrame) 119 | { 120 | $codeArr = array(); 121 | 122 | foreach ($bitFrame as $line) 123 | $codeArr[] = join('', $line); 124 | 125 | return gzcompress(join("\n", $codeArr), 9); 126 | } 127 | 128 | //---------------------------------------------------------------------- 129 | public static function unserial($code) 130 | { 131 | $codeArr = array(); 132 | 133 | $codeLines = explode("\n", gzuncompress($code)); 134 | foreach ($codeLines as $line) 135 | $codeArr[] = str_split($line); 136 | 137 | return $codeArr; 138 | } 139 | 140 | //---------------------------------------------------------------------- 141 | public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) 142 | { 143 | $b = 0; 144 | $bitMask = array(); 145 | 146 | $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat'; 147 | 148 | if (QR_CACHEABLE) { 149 | if (file_exists($fileName)) { 150 | $bitMask = self::unserial(file_get_contents($fileName)); 151 | } else { 152 | $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d); 153 | if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo)) 154 | mkdir(QR_CACHE_DIR.'mask_'.$maskNo); 155 | file_put_contents($fileName, self::serial($bitMask)); 156 | } 157 | } else { 158 | $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d); 159 | } 160 | 161 | if ($maskGenOnly) 162 | return; 163 | 164 | $d = $s; 165 | 166 | for($y=0; $y<$width; $y++) { 167 | for($x=0; $x<$width; $x++) { 168 | if($bitMask[$y][$x] == 1) { 169 | $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]); 170 | } 171 | $b += (int)(ord($d[$y][$x]) & 1); 172 | } 173 | } 174 | 175 | return $b; 176 | } 177 | 178 | //---------------------------------------------------------------------- 179 | public function makeMask($width, $frame, $maskNo, $level) 180 | { 181 | $masked = array_fill(0, $width, str_repeat("\0", $width)); 182 | $this->makeMaskNo($maskNo, $width, $frame, $masked); 183 | $this->writeFormatInformation($width, $masked, $maskNo, $level); 184 | 185 | return $masked; 186 | } 187 | 188 | //---------------------------------------------------------------------- 189 | public function calcN1N3($length) 190 | { 191 | $demerit = 0; 192 | 193 | for($i=0; $i<$length; $i++) { 194 | 195 | if($this->runLength[$i] >= 5) { 196 | $demerit += (N1 + ($this->runLength[$i] - 5)); 197 | } 198 | if($i & 1) { 199 | if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) { 200 | $fact = (int)($this->runLength[$i] / 3); 201 | if(($this->runLength[$i-2] == $fact) && 202 | ($this->runLength[$i-1] == $fact) && 203 | ($this->runLength[$i+1] == $fact) && 204 | ($this->runLength[$i+2] == $fact)) { 205 | if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) { 206 | $demerit += N3; 207 | } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) { 208 | $demerit += N3; 209 | } 210 | } 211 | } 212 | } 213 | } 214 | return $demerit; 215 | } 216 | 217 | //---------------------------------------------------------------------- 218 | public function evaluateSymbol($width, $frame) 219 | { 220 | $head = 0; 221 | $demerit = 0; 222 | 223 | for($y=0; $y<$width; $y++) { 224 | $head = 0; 225 | $this->runLength[0] = 1; 226 | 227 | $frameY = $frame[$y]; 228 | 229 | if ($y>0) 230 | $frameYM = $frame[$y-1]; 231 | 232 | for($x=0; $x<$width; $x++) { 233 | if(($x > 0) && ($y > 0)) { 234 | $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]); 235 | $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]); 236 | 237 | if(($b22 | ($w22 ^ 1))&1) { 238 | $demerit += N2; 239 | } 240 | } 241 | if(($x == 0) && (ord($frameY[$x]) & 1)) { 242 | $this->runLength[0] = -1; 243 | $head = 1; 244 | $this->runLength[$head] = 1; 245 | } else if($x > 0) { 246 | if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) { 247 | $head++; 248 | $this->runLength[$head] = 1; 249 | } else { 250 | $this->runLength[$head]++; 251 | } 252 | } 253 | } 254 | 255 | $demerit += $this->calcN1N3($head+1); 256 | } 257 | 258 | for($x=0; $x<$width; $x++) { 259 | $head = 0; 260 | $this->runLength[0] = 1; 261 | 262 | for($y=0; $y<$width; $y++) { 263 | if($y == 0 && (ord($frame[$y][$x]) & 1)) { 264 | $this->runLength[0] = -1; 265 | $head = 1; 266 | $this->runLength[$head] = 1; 267 | } else if($y > 0) { 268 | if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) { 269 | $head++; 270 | $this->runLength[$head] = 1; 271 | } else { 272 | $this->runLength[$head]++; 273 | } 274 | } 275 | } 276 | 277 | $demerit += $this->calcN1N3($head+1); 278 | } 279 | 280 | return $demerit; 281 | } 282 | 283 | 284 | //---------------------------------------------------------------------- 285 | public function mask($width, $frame, $level) 286 | { 287 | $minDemerit = PHP_INT_MAX; 288 | $bestMaskNum = 0; 289 | $bestMask = array(); 290 | 291 | $checked_masks = array(0,1,2,3,4,5,6,7); 292 | 293 | if (QR_FIND_FROM_RANDOM !== false) { 294 | 295 | $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9); 296 | for ($i = 0; $i < $howManuOut; $i++) { 297 | $remPos = rand (0, count($checked_masks)-1); 298 | unset($checked_masks[$remPos]); 299 | $checked_masks = array_values($checked_masks); 300 | } 301 | 302 | } 303 | 304 | $bestMask = $frame; 305 | 306 | foreach($checked_masks as $i) { 307 | $mask = array_fill(0, $width, str_repeat("\0", $width)); 308 | 309 | $demerit = 0; 310 | $blacks = 0; 311 | $blacks = $this->makeMaskNo($i, $width, $frame, $mask); 312 | $blacks += $this->writeFormatInformation($width, $mask, $i, $level); 313 | $blacks = (int)(100 * $blacks / ($width * $width)); 314 | $demerit = (int)((int)(abs($blacks - 50) / 5) * N4); 315 | $demerit += $this->evaluateSymbol($width, $mask); 316 | 317 | if($demerit < $minDemerit) { 318 | $minDemerit = $demerit; 319 | $bestMask = $mask; 320 | $bestMaskNum = $i; 321 | } 322 | } 323 | 324 | return $bestMask; 325 | } 326 | 327 | //---------------------------------------------------------------------- 328 | } 329 | -------------------------------------------------------------------------------- /qrcode/qrencode.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * PHP QR Code is distributed under LGPL 3 11 | * Copyright (C) 2010 Dominik Dzienia 12 | * 13 | * This library is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 3 of the License, or any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Lesser General Public 24 | * License along with this library; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26 | */ 27 | 28 | class QRrsblock { 29 | public $dataLength; 30 | public $data = array(); 31 | public $eccLength; 32 | public $ecc = array(); 33 | 34 | public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs) 35 | { 36 | $rs->encode_rs_char($data, $ecc); 37 | 38 | $this->dataLength = $dl; 39 | $this->data = $data; 40 | $this->eccLength = $el; 41 | $this->ecc = $ecc; 42 | } 43 | }; 44 | 45 | //########################################################################## 46 | 47 | class QRrawcode { 48 | public $version; 49 | public $datacode = array(); 50 | public $ecccode = array(); 51 | public $blocks; 52 | public $rsblocks = array(); //of RSblock 53 | public $count; 54 | public $dataLength; 55 | public $eccLength; 56 | public $b1; 57 | 58 | //---------------------------------------------------------------------- 59 | public function __construct(QRinput $input) 60 | { 61 | $spec = array(0,0,0,0,0); 62 | 63 | $this->datacode = $input->getByteStream(); 64 | if(is_null($this->datacode)) { 65 | throw new Exception('null imput string'); 66 | } 67 | 68 | QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec); 69 | 70 | $this->version = $input->getVersion(); 71 | $this->b1 = QRspec::rsBlockNum1($spec); 72 | $this->dataLength = QRspec::rsDataLength($spec); 73 | $this->eccLength = QRspec::rsEccLength($spec); 74 | $this->ecccode = array_fill(0, $this->eccLength, 0); 75 | $this->blocks = QRspec::rsBlockNum($spec); 76 | 77 | $ret = $this->init($spec); 78 | if($ret < 0) { 79 | throw new Exception('block alloc error'); 80 | return null; 81 | } 82 | 83 | $this->count = 0; 84 | } 85 | 86 | //---------------------------------------------------------------------- 87 | public function init(array $spec) 88 | { 89 | $dl = QRspec::rsDataCodes1($spec); 90 | $el = QRspec::rsEccCodes1($spec); 91 | $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); 92 | 93 | 94 | $blockNo = 0; 95 | $dataPos = 0; 96 | $eccPos = 0; 97 | for($i=0; $iecccode,$eccPos); 99 | $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs); 100 | $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc); 101 | 102 | $dataPos += $dl; 103 | $eccPos += $el; 104 | $blockNo++; 105 | } 106 | 107 | if(QRspec::rsBlockNum2($spec) == 0) 108 | return 0; 109 | 110 | $dl = QRspec::rsDataCodes2($spec); 111 | $el = QRspec::rsEccCodes2($spec); 112 | $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); 113 | 114 | if($rs == NULL) return -1; 115 | 116 | for($i=0; $iecccode,$eccPos); 118 | $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs); 119 | $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc); 120 | 121 | $dataPos += $dl; 122 | $eccPos += $el; 123 | $blockNo++; 124 | } 125 | 126 | return 0; 127 | } 128 | 129 | //---------------------------------------------------------------------- 130 | public function getCode() 131 | { 132 | $ret; 133 | 134 | if($this->count < $this->dataLength) { 135 | $row = $this->count % $this->blocks; 136 | $col = $this->count / $this->blocks; 137 | if($col >= $this->rsblocks[0]->dataLength) { 138 | $row += $this->b1; 139 | } 140 | $ret = $this->rsblocks[$row]->data[$col]; 141 | } else if($this->count < $this->dataLength + $this->eccLength) { 142 | $row = ($this->count - $this->dataLength) % $this->blocks; 143 | $col = ($this->count - $this->dataLength) / $this->blocks; 144 | $ret = $this->rsblocks[$row]->ecc[$col]; 145 | } else { 146 | return 0; 147 | } 148 | $this->count++; 149 | 150 | return $ret; 151 | } 152 | } 153 | 154 | //########################################################################## 155 | 156 | class QRcode { 157 | 158 | public $version; 159 | public $width; 160 | public $data; 161 | 162 | //---------------------------------------------------------------------- 163 | public function encodeMask(QRinput $input, $mask) 164 | { 165 | if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) { 166 | throw new Exception('wrong version'); 167 | } 168 | if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) { 169 | throw new Exception('wrong level'); 170 | } 171 | 172 | $raw = new QRrawcode($input); 173 | 174 | QRtools::markTime('after_raw'); 175 | 176 | $version = $raw->version; 177 | $width = QRspec::getWidth($version); 178 | $frame = QRspec::newFrame($version); 179 | 180 | $filler = new FrameFiller($width, $frame); 181 | if(is_null($filler)) { 182 | return NULL; 183 | } 184 | 185 | // inteleaved data and ecc codes 186 | for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) { 187 | $code = $raw->getCode(); 188 | $bit = 0x80; 189 | for($j=0; $j<8; $j++) { 190 | $addr = $filler->next(); 191 | $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0)); 192 | $bit = $bit >> 1; 193 | } 194 | } 195 | 196 | QRtools::markTime('after_filler'); 197 | 198 | unset($raw); 199 | 200 | // remainder bits 201 | $j = QRspec::getRemainder($version); 202 | for($i=0; $i<$j; $i++) { 203 | $addr = $filler->next(); 204 | $filler->setFrameAt($addr, 0x02); 205 | } 206 | 207 | $frame = $filler->frame; 208 | unset($filler); 209 | 210 | 211 | // masking 212 | $maskObj = new QRmask(); 213 | if($mask < 0) { 214 | 215 | if (QR_FIND_BEST_MASK) { 216 | $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel()); 217 | } else { 218 | $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel()); 219 | } 220 | } else { 221 | $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel()); 222 | } 223 | 224 | if($masked == NULL) { 225 | return NULL; 226 | } 227 | 228 | QRtools::markTime('after_mask'); 229 | 230 | $this->version = $version; 231 | $this->width = $width; 232 | $this->data = $masked; 233 | 234 | return $this; 235 | } 236 | 237 | //---------------------------------------------------------------------- 238 | public function encodeInput(QRinput $input) 239 | { 240 | return $this->encodeMask($input, -1); 241 | } 242 | 243 | //---------------------------------------------------------------------- 244 | public function encodeString8bit($string, $version, $level) 245 | { 246 | if(string == NULL) { 247 | throw new Exception('empty string!'); 248 | return NULL; 249 | } 250 | 251 | $input = new QRinput($version, $level); 252 | if($input == NULL) return NULL; 253 | 254 | $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string)); 255 | if($ret < 0) { 256 | unset($input); 257 | return NULL; 258 | } 259 | return $this->encodeInput($input); 260 | } 261 | 262 | //---------------------------------------------------------------------- 263 | public function encodeString($string, $version, $level, $hint, $casesensitive) 264 | { 265 | 266 | if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) { 267 | throw new Exception('bad hint'); 268 | return NULL; 269 | } 270 | 271 | $input = new QRinput($version, $level); 272 | if($input == NULL) return NULL; 273 | 274 | $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive); 275 | if($ret < 0) { 276 | return NULL; 277 | } 278 | 279 | return $this->encodeInput($input); 280 | } 281 | 282 | //---------------------------------------------------------------------- 283 | public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false) 284 | { 285 | $enc = QRencode::factory($level, $size, $margin); 286 | return $enc->encodePNG($text, $outfile, $saveandprint=false); 287 | } 288 | 289 | //---------------------------------------------------------------------- 290 | public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 291 | { 292 | $enc = QRencode::factory($level, $size, $margin); 293 | return $enc->encode($text, $outfile); 294 | } 295 | 296 | //---------------------------------------------------------------------- 297 | public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 298 | { 299 | $enc = QRencode::factory($level, $size, $margin); 300 | return $enc->encodeRAW($text, $outfile); 301 | } 302 | } 303 | 304 | //########################################################################## 305 | 306 | class FrameFiller { 307 | 308 | public $width; 309 | public $frame; 310 | public $x; 311 | public $y; 312 | public $dir; 313 | public $bit; 314 | 315 | //---------------------------------------------------------------------- 316 | public function __construct($width, &$frame) 317 | { 318 | $this->width = $width; 319 | $this->frame = $frame; 320 | $this->x = $width - 1; 321 | $this->y = $width - 1; 322 | $this->dir = -1; 323 | $this->bit = -1; 324 | } 325 | 326 | //---------------------------------------------------------------------- 327 | public function setFrameAt($at, $val) 328 | { 329 | $this->frame[$at['y']][$at['x']] = chr($val); 330 | } 331 | 332 | //---------------------------------------------------------------------- 333 | public function getFrameAt($at) 334 | { 335 | return ord($this->frame[$at['y']][$at['x']]); 336 | } 337 | 338 | //---------------------------------------------------------------------- 339 | public function next() 340 | { 341 | do { 342 | 343 | if($this->bit == -1) { 344 | $this->bit = 0; 345 | return array('x'=>$this->x, 'y'=>$this->y); 346 | } 347 | 348 | $x = $this->x; 349 | $y = $this->y; 350 | $w = $this->width; 351 | 352 | if($this->bit == 0) { 353 | $x--; 354 | $this->bit++; 355 | } else { 356 | $x++; 357 | $y += $this->dir; 358 | $this->bit--; 359 | } 360 | 361 | if($this->dir < 0) { 362 | if($y < 0) { 363 | $y = 0; 364 | $x -= 2; 365 | $this->dir = 1; 366 | if($x == 6) { 367 | $x--; 368 | $y = 9; 369 | } 370 | } 371 | } else { 372 | if($y == $w) { 373 | $y = $w - 1; 374 | $x -= 2; 375 | $this->dir = -1; 376 | if($x == 6) { 377 | $x--; 378 | $y -= 8; 379 | } 380 | } 381 | } 382 | if($x < 0 || $y < 0) return null; 383 | 384 | $this->x = $x; 385 | $this->y = $y; 386 | 387 | } while(ord($this->frame[$y][$x]) & 0x80); 388 | 389 | return array('x'=>$x, 'y'=>$y); 390 | } 391 | 392 | } ; 393 | 394 | //########################################################################## 395 | 396 | class QRencode { 397 | 398 | public $casesensitive = true; 399 | public $eightbit = false; 400 | 401 | public $version = 0; 402 | public $size = 3; 403 | public $margin = 4; 404 | 405 | public $structured = 0; // not supported yet 406 | 407 | public $level = QR_ECLEVEL_L; 408 | public $hint = QR_MODE_8; 409 | 410 | //---------------------------------------------------------------------- 411 | public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4) 412 | { 413 | $enc = new QRencode(); 414 | $enc->size = $size; 415 | $enc->margin = $margin; 416 | 417 | switch ($level.'') { 418 | case '0': 419 | case '1': 420 | case '2': 421 | case '3': 422 | $enc->level = $level; 423 | break; 424 | case 'l': 425 | case 'L': 426 | $enc->level = QR_ECLEVEL_L; 427 | break; 428 | case 'm': 429 | case 'M': 430 | $enc->level = QR_ECLEVEL_M; 431 | break; 432 | case 'q': 433 | case 'Q': 434 | $enc->level = QR_ECLEVEL_Q; 435 | break; 436 | case 'h': 437 | case 'H': 438 | $enc->level = QR_ECLEVEL_H; 439 | break; 440 | } 441 | 442 | return $enc; 443 | } 444 | 445 | //---------------------------------------------------------------------- 446 | public function encodeRAW($intext, $outfile = false) 447 | { 448 | $code = new QRcode(); 449 | 450 | if($this->eightbit) { 451 | $code->encodeString8bit($intext, $this->version, $this->level); 452 | } else { 453 | $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive); 454 | } 455 | 456 | return $code->data; 457 | } 458 | 459 | //---------------------------------------------------------------------- 460 | public function encode($intext, $outfile = false) 461 | { 462 | $code = new QRcode(); 463 | 464 | if($this->eightbit) { 465 | $code->encodeString8bit($intext, $this->version, $this->level); 466 | } else { 467 | $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive); 468 | } 469 | 470 | QRtools::markTime('after_encode'); 471 | 472 | if ($outfile!== false) { 473 | file_put_contents($outfile, join("\n", QRtools::binarize($code->data))); 474 | } else { 475 | return QRtools::binarize($code->data); 476 | } 477 | } 478 | 479 | //---------------------------------------------------------------------- 480 | public function encodePNG($intext, $outfile = false,$saveandprint=false) 481 | { 482 | try { 483 | 484 | ob_start(); 485 | $tab = $this->encode($intext); 486 | $err = ob_get_contents(); 487 | ob_end_clean(); 488 | 489 | if ($err != '') 490 | QRtools::log($outfile, $err); 491 | 492 | $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin)); 493 | 494 | QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint); 495 | 496 | } catch (Exception $e) { 497 | 498 | QRtools::log($outfile, $e->getMessage()); 499 | 500 | } 501 | } 502 | } 503 | -------------------------------------------------------------------------------- /qrcode/qrinput.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * PHP QR Code is distributed under LGPL 3 11 | * Copyright (C) 2010 Dominik Dzienia 12 | * 13 | * This library is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 3 of the License, or any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Lesser General Public 24 | * License along with this library; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26 | */ 27 | 28 | define('STRUCTURE_HEADER_BITS', 20); 29 | define('MAX_STRUCTURED_SYMBOLS', 16); 30 | 31 | class QRinputItem { 32 | 33 | public $mode; 34 | public $size; 35 | public $data; 36 | public $bstream; 37 | 38 | public function __construct($mode, $size, $data, $bstream = null) 39 | { 40 | $setData = array_slice($data, 0, $size); 41 | 42 | if (count($setData) < $size) { 43 | $setData = array_merge($setData, array_fill(0,$size-count($setData),0)); 44 | } 45 | 46 | if(!QRinput::check($mode, $size, $setData)) { 47 | throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData)); 48 | return null; 49 | } 50 | 51 | $this->mode = $mode; 52 | $this->size = $size; 53 | $this->data = $setData; 54 | $this->bstream = $bstream; 55 | } 56 | 57 | //---------------------------------------------------------------------- 58 | public function encodeModeNum($version) 59 | { 60 | try { 61 | 62 | $words = (int)($this->size / 3); 63 | $bs = new QRbitstream(); 64 | 65 | $val = 0x1; 66 | $bs->appendNum(4, $val); 67 | $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size); 68 | 69 | for($i=0; $i<$words; $i++) { 70 | $val = (ord($this->data[$i*3 ]) - ord('0')) * 100; 71 | $val += (ord($this->data[$i*3+1]) - ord('0')) * 10; 72 | $val += (ord($this->data[$i*3+2]) - ord('0')); 73 | $bs->appendNum(10, $val); 74 | } 75 | 76 | if($this->size - $words * 3 == 1) { 77 | $val = ord($this->data[$words*3]) - ord('0'); 78 | $bs->appendNum(4, $val); 79 | } else if($this->size - $words * 3 == 2) { 80 | $val = (ord($this->data[$words*3 ]) - ord('0')) * 10; 81 | $val += (ord($this->data[$words*3+1]) - ord('0')); 82 | $bs->appendNum(7, $val); 83 | } 84 | 85 | $this->bstream = $bs; 86 | return 0; 87 | 88 | } catch (Exception $e) { 89 | return -1; 90 | } 91 | } 92 | 93 | //---------------------------------------------------------------------- 94 | public function encodeModeAn($version) 95 | { 96 | try { 97 | $words = (int)($this->size / 2); 98 | $bs = new QRbitstream(); 99 | 100 | $bs->appendNum(4, 0x02); 101 | $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size); 102 | 103 | for($i=0; $i<$words; $i++) { 104 | $val = (int)QRinput::lookAnTable(ord($this->data[$i*2 ])) * 45; 105 | $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1])); 106 | 107 | $bs->appendNum(11, $val); 108 | } 109 | 110 | if($this->size & 1) { 111 | $val = QRinput::lookAnTable(ord($this->data[$words * 2])); 112 | $bs->appendNum(6, $val); 113 | } 114 | 115 | $this->bstream = $bs; 116 | return 0; 117 | 118 | } catch (Exception $e) { 119 | return -1; 120 | } 121 | } 122 | 123 | //---------------------------------------------------------------------- 124 | public function encodeMode8($version) 125 | { 126 | try { 127 | $bs = new QRbitstream(); 128 | 129 | $bs->appendNum(4, 0x4); 130 | $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size); 131 | 132 | for($i=0; $i<$this->size; $i++) { 133 | $bs->appendNum(8, ord($this->data[$i])); 134 | } 135 | 136 | $this->bstream = $bs; 137 | return 0; 138 | 139 | } catch (Exception $e) { 140 | return -1; 141 | } 142 | } 143 | 144 | //---------------------------------------------------------------------- 145 | public function encodeModeKanji($version) 146 | { 147 | try { 148 | 149 | $bs = new QRbitrtream(); 150 | 151 | $bs->appendNum(4, 0x8); 152 | $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2)); 153 | 154 | for($i=0; $i<$this->size; $i+=2) { 155 | $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]); 156 | if($val <= 0x9ffc) { 157 | $val -= 0x8140; 158 | } else { 159 | $val -= 0xc140; 160 | } 161 | 162 | $h = ($val >> 8) * 0xc0; 163 | $val = ($val & 0xff) + $h; 164 | 165 | $bs->appendNum(13, $val); 166 | } 167 | 168 | $this->bstream = $bs; 169 | return 0; 170 | 171 | } catch (Exception $e) { 172 | return -1; 173 | } 174 | } 175 | 176 | //---------------------------------------------------------------------- 177 | public function encodeModeStructure() 178 | { 179 | try { 180 | $bs = new QRbitstream(); 181 | 182 | $bs->appendNum(4, 0x03); 183 | $bs->appendNum(4, ord($this->data[1]) - 1); 184 | $bs->appendNum(4, ord($this->data[0]) - 1); 185 | $bs->appendNum(8, ord($this->data[2])); 186 | 187 | $this->bstream = $bs; 188 | return 0; 189 | 190 | } catch (Exception $e) { 191 | return -1; 192 | } 193 | } 194 | 195 | //---------------------------------------------------------------------- 196 | public function estimateBitStreamSizeOfEntry($version) 197 | { 198 | $bits = 0; 199 | 200 | if($version == 0) 201 | $version = 1; 202 | 203 | switch($this->mode) { 204 | case QR_MODE_NUM: $bits = QRinput::estimateBitsModeNum($this->size); break; 205 | case QR_MODE_AN: $bits = QRinput::estimateBitsModeAn($this->size); break; 206 | case QR_MODE_8: $bits = QRinput::estimateBitsMode8($this->size); break; 207 | case QR_MODE_KANJI: $bits = QRinput::estimateBitsModeKanji($this->size);break; 208 | case QR_MODE_STRUCTURE: return STRUCTURE_HEADER_BITS; 209 | default: 210 | return 0; 211 | } 212 | 213 | $l = QRspec::lengthIndicator($this->mode, $version); 214 | $m = 1 << $l; 215 | $num = (int)(($this->size + $m - 1) / $m); 216 | 217 | $bits += $num * (4 + $l); 218 | 219 | return $bits; 220 | } 221 | 222 | //---------------------------------------------------------------------- 223 | public function encodeBitStream($version) 224 | { 225 | try { 226 | 227 | unset($this->bstream); 228 | $words = QRspec::maximumWords($this->mode, $version); 229 | 230 | if($this->size > $words) { 231 | 232 | $st1 = new QRinputItem($this->mode, $words, $this->data); 233 | $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words)); 234 | 235 | $st1->encodeBitStream($version); 236 | $st2->encodeBitStream($version); 237 | 238 | $this->bstream = new QRbitstream(); 239 | $this->bstream->append($st1->bstream); 240 | $this->bstream->append($st2->bstream); 241 | 242 | unset($st1); 243 | unset($st2); 244 | 245 | } else { 246 | 247 | $ret = 0; 248 | 249 | switch($this->mode) { 250 | case QR_MODE_NUM: $ret = $this->encodeModeNum($version); break; 251 | case QR_MODE_AN: $ret = $this->encodeModeAn($version); break; 252 | case QR_MODE_8: $ret = $this->encodeMode8($version); break; 253 | case QR_MODE_KANJI: $ret = $this->encodeModeKanji($version);break; 254 | case QR_MODE_STRUCTURE: $ret = $this->encodeModeStructure(); break; 255 | 256 | default: 257 | break; 258 | } 259 | 260 | if($ret < 0) 261 | return -1; 262 | } 263 | 264 | return $this->bstream->size(); 265 | 266 | } catch (Exception $e) { 267 | return -1; 268 | } 269 | } 270 | }; 271 | 272 | //########################################################################## 273 | 274 | class QRinput { 275 | 276 | public $items; 277 | 278 | private $version; 279 | private $level; 280 | 281 | //---------------------------------------------------------------------- 282 | public function __construct($version = 0, $level = QR_ECLEVEL_L) 283 | { 284 | if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) { 285 | throw new Exception('Invalid version no'); 286 | return NULL; 287 | } 288 | 289 | $this->version = $version; 290 | $this->level = $level; 291 | } 292 | 293 | //---------------------------------------------------------------------- 294 | public function getVersion() 295 | { 296 | return $this->version; 297 | } 298 | 299 | //---------------------------------------------------------------------- 300 | public function setVersion($version) 301 | { 302 | if($version < 0 || $version > QRSPEC_VERSION_MAX) { 303 | throw new Exception('Invalid version no'); 304 | return -1; 305 | } 306 | 307 | $this->version = $version; 308 | 309 | return 0; 310 | } 311 | 312 | //---------------------------------------------------------------------- 313 | public function getErrorCorrectionLevel() 314 | { 315 | return $this->level; 316 | } 317 | 318 | //---------------------------------------------------------------------- 319 | public function setErrorCorrectionLevel($level) 320 | { 321 | if($level > QR_ECLEVEL_H) { 322 | throw new Exception('Invalid ECLEVEL'); 323 | return -1; 324 | } 325 | 326 | $this->level = $level; 327 | 328 | return 0; 329 | } 330 | 331 | //---------------------------------------------------------------------- 332 | public function appendEntry(QRinputItem $entry) 333 | { 334 | $this->items[] = $entry; 335 | } 336 | 337 | //---------------------------------------------------------------------- 338 | public function append($mode, $size, $data) 339 | { 340 | try { 341 | $entry = new QRinputItem($mode, $size, $data); 342 | $this->items[] = $entry; 343 | return 0; 344 | } catch (Exception $e) { 345 | return -1; 346 | } 347 | } 348 | 349 | //---------------------------------------------------------------------- 350 | 351 | public function insertStructuredAppendHeader($size, $index, $parity) 352 | { 353 | if( $size > MAX_STRUCTURED_SYMBOLS ) { 354 | throw new Exception('insertStructuredAppendHeader wrong size'); 355 | } 356 | 357 | if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) { 358 | throw new Exception('insertStructuredAppendHeader wrong index'); 359 | } 360 | 361 | $buf = array($size, $index, $parity); 362 | 363 | try { 364 | $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf); 365 | array_unshift($this->items, $entry); 366 | return 0; 367 | } catch (Exception $e) { 368 | return -1; 369 | } 370 | } 371 | 372 | //---------------------------------------------------------------------- 373 | public function calcParity() 374 | { 375 | $parity = 0; 376 | 377 | foreach($this->items as $item) { 378 | if($item->mode != QR_MODE_STRUCTURE) { 379 | for($i=$item->size-1; $i>=0; $i--) { 380 | $parity ^= $item->data[$i]; 381 | } 382 | } 383 | } 384 | 385 | return $parity; 386 | } 387 | 388 | //---------------------------------------------------------------------- 389 | public static function checkModeNum($size, $data) 390 | { 391 | for($i=0; $i<$size; $i++) { 392 | if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){ 393 | return false; 394 | } 395 | } 396 | 397 | return true; 398 | } 399 | 400 | //---------------------------------------------------------------------- 401 | public static function estimateBitsModeNum($size) 402 | { 403 | $w = (int)$size / 3; 404 | $bits = $w * 10; 405 | 406 | switch($size - $w * 3) { 407 | case 1: 408 | $bits += 4; 409 | break; 410 | case 2: 411 | $bits += 7; 412 | break; 413 | default: 414 | break; 415 | } 416 | 417 | return $bits; 418 | } 419 | 420 | //---------------------------------------------------------------------- 421 | public static $anTable = array( 422 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 423 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 424 | 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, 425 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, 426 | -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 427 | 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, 428 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 429 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 430 | ); 431 | 432 | //---------------------------------------------------------------------- 433 | public static function lookAnTable($c) 434 | { 435 | return (($c > 127)?-1:self::$anTable[$c]); 436 | } 437 | 438 | //---------------------------------------------------------------------- 439 | public static function checkModeAn($size, $data) 440 | { 441 | for($i=0; $i<$size; $i++) { 442 | if (self::lookAnTable(ord($data[$i])) == -1) { 443 | return false; 444 | } 445 | } 446 | 447 | return true; 448 | } 449 | 450 | //---------------------------------------------------------------------- 451 | public static function estimateBitsModeAn($size) 452 | { 453 | $w = (int)($size / 2); 454 | $bits = $w * 11; 455 | 456 | if($size & 1) { 457 | $bits += 6; 458 | } 459 | 460 | return $bits; 461 | } 462 | 463 | //---------------------------------------------------------------------- 464 | public static function estimateBitsMode8($size) 465 | { 466 | return $size * 8; 467 | } 468 | 469 | //---------------------------------------------------------------------- 470 | public function estimateBitsModeKanji($size) 471 | { 472 | return (int)(($size / 2) * 13); 473 | } 474 | 475 | //---------------------------------------------------------------------- 476 | public static function checkModeKanji($size, $data) 477 | { 478 | if($size & 1) 479 | return false; 480 | 481 | for($i=0; $i<$size; $i+=2) { 482 | $val = (ord($data[$i]) << 8) | ord($data[$i+1]); 483 | if( $val < 0x8140 484 | || ($val > 0x9ffc && $val < 0xe040) 485 | || $val > 0xebbf) { 486 | return false; 487 | } 488 | } 489 | 490 | return true; 491 | } 492 | 493 | /*********************************************************************** 494 | * Validation 495 | **********************************************************************/ 496 | 497 | public static function check($mode, $size, $data) 498 | { 499 | if($size <= 0) 500 | return false; 501 | 502 | switch($mode) { 503 | case QR_MODE_NUM: return self::checkModeNum($size, $data); break; 504 | case QR_MODE_AN: return self::checkModeAn($size, $data); break; 505 | case QR_MODE_KANJI: return self::checkModeKanji($size, $data); break; 506 | case QR_MODE_8: return true; break; 507 | case QR_MODE_STRUCTURE: return true; break; 508 | 509 | default: 510 | break; 511 | } 512 | 513 | return false; 514 | } 515 | 516 | 517 | //---------------------------------------------------------------------- 518 | public function estimateBitStreamSize($version) 519 | { 520 | $bits = 0; 521 | 522 | foreach($this->items as $item) { 523 | $bits += $item->estimateBitStreamSizeOfEntry($version); 524 | } 525 | 526 | return $bits; 527 | } 528 | 529 | //---------------------------------------------------------------------- 530 | public function estimateVersion() 531 | { 532 | $version = 0; 533 | $prev = 0; 534 | do { 535 | $prev = $version; 536 | $bits = $this->estimateBitStreamSize($prev); 537 | $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level); 538 | if ($version < 0) { 539 | return -1; 540 | } 541 | } while ($version > $prev); 542 | 543 | return $version; 544 | } 545 | 546 | //---------------------------------------------------------------------- 547 | public static function lengthOfCode($mode, $version, $bits) 548 | { 549 | $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version); 550 | switch($mode) { 551 | case QR_MODE_NUM: 552 | $chunks = (int)($payload / 10); 553 | $remain = $payload - $chunks * 10; 554 | $size = $chunks * 3; 555 | if($remain >= 7) { 556 | $size += 2; 557 | } else if($remain >= 4) { 558 | $size += 1; 559 | } 560 | break; 561 | case QR_MODE_AN: 562 | $chunks = (int)($payload / 11); 563 | $remain = $payload - $chunks * 11; 564 | $size = $chunks * 2; 565 | if($remain >= 6) 566 | $size++; 567 | break; 568 | case QR_MODE_8: 569 | $size = (int)($payload / 8); 570 | break; 571 | case QR_MODE_KANJI: 572 | $size = (int)(($payload / 13) * 2); 573 | break; 574 | case QR_MODE_STRUCTURE: 575 | $size = (int)($payload / 8); 576 | break; 577 | default: 578 | $size = 0; 579 | break; 580 | } 581 | 582 | $maxsize = QRspec::maximumWords($mode, $version); 583 | if($size < 0) $size = 0; 584 | if($size > $maxsize) $size = $maxsize; 585 | 586 | return $size; 587 | } 588 | 589 | //---------------------------------------------------------------------- 590 | public function createBitStream() 591 | { 592 | $total = 0; 593 | 594 | foreach($this->items as $item) { 595 | $bits = $item->encodeBitStream($this->version); 596 | 597 | if($bits < 0) 598 | return -1; 599 | 600 | $total += $bits; 601 | } 602 | 603 | return $total; 604 | } 605 | 606 | //---------------------------------------------------------------------- 607 | public function convertData() 608 | { 609 | $ver = $this->estimateVersion(); 610 | if($ver > $this->getVersion()) { 611 | $this->setVersion($ver); 612 | } 613 | 614 | for(;;) { 615 | $bits = $this->createBitStream(); 616 | 617 | if($bits < 0) 618 | return -1; 619 | 620 | $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level); 621 | if($ver < 0) { 622 | throw new Exception('WRONG VERSION'); 623 | return -1; 624 | } else if($ver > $this->getVersion()) { 625 | $this->setVersion($ver); 626 | } else { 627 | break; 628 | } 629 | } 630 | 631 | return 0; 632 | } 633 | 634 | //---------------------------------------------------------------------- 635 | public function appendPaddingBit(&$bstream) 636 | { 637 | $bits = $bstream->size(); 638 | $maxwords = QRspec::getDataLength($this->version, $this->level); 639 | $maxbits = $maxwords * 8; 640 | 641 | if ($maxbits == $bits) { 642 | return 0; 643 | } 644 | 645 | if ($maxbits - $bits < 5) { 646 | return $bstream->appendNum($maxbits - $bits, 0); 647 | } 648 | 649 | $bits += 4; 650 | $words = (int)(($bits + 7) / 8); 651 | 652 | $padding = new QRbitstream(); 653 | $ret = $padding->appendNum($words * 8 - $bits + 4, 0); 654 | 655 | if($ret < 0) 656 | return $ret; 657 | 658 | $padlen = $maxwords - $words; 659 | 660 | if($padlen > 0) { 661 | 662 | $padbuf = array(); 663 | for($i=0; $i<$padlen; $i++) { 664 | $padbuf[$i] = ($i&1)?0x11:0xec; 665 | } 666 | 667 | $ret = $padding->appendBytes($padlen, $padbuf); 668 | 669 | if($ret < 0) 670 | return $ret; 671 | 672 | } 673 | 674 | $ret = $bstream->append($padding); 675 | 676 | return $ret; 677 | } 678 | 679 | //---------------------------------------------------------------------- 680 | public function mergeBitStream() 681 | { 682 | if($this->convertData() < 0) { 683 | return null; 684 | } 685 | 686 | $bstream = new QRbitstream(); 687 | 688 | foreach($this->items as $item) { 689 | $ret = $bstream->append($item->bstream); 690 | if($ret < 0) { 691 | return null; 692 | } 693 | } 694 | 695 | return $bstream; 696 | } 697 | 698 | //---------------------------------------------------------------------- 699 | public function getBitStream() 700 | { 701 | 702 | $bstream = $this->mergeBitStream(); 703 | 704 | if($bstream == null) { 705 | return null; 706 | } 707 | 708 | $ret = $this->appendPaddingBit($bstream); 709 | if($ret < 0) { 710 | return null; 711 | } 712 | 713 | return $bstream; 714 | } 715 | 716 | //---------------------------------------------------------------------- 717 | public function getByteStream() 718 | { 719 | $bstream = $this->getBitStream(); 720 | if($bstream == null) { 721 | return null; 722 | } 723 | 724 | return $bstream->toByte(); 725 | } 726 | } 727 | 728 | 729 | -------------------------------------------------------------------------------- /qrcode/qrspec.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * PHP QR Code is distributed under LGPL 3 11 | * Copyright (C) 2010 Dominik Dzienia 12 | * 13 | * The following data / specifications are taken from 14 | * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) 15 | * or 16 | * "Automatic identification and data capture techniques -- 17 | * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) 18 | * 19 | * This library is free software; you can redistribute it and/or 20 | * modify it under the terms of the GNU Lesser General Public 21 | * License as published by the Free Software Foundation; either 22 | * version 3 of the License, or any later version. 23 | * 24 | * This library is distributed in the hope that it will be useful, 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | * Lesser General Public License for more details. 28 | * 29 | * You should have received a copy of the GNU Lesser General Public 30 | * License along with this library; if not, write to the Free Software 31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 32 | */ 33 | 34 | define('QRSPEC_VERSION_MAX', 40); 35 | define('QRSPEC_WIDTH_MAX', 177); 36 | 37 | define('QRCAP_WIDTH', 0); 38 | define('QRCAP_WORDS', 1); 39 | define('QRCAP_REMINDER', 2); 40 | define('QRCAP_EC', 3); 41 | 42 | class QRspec { 43 | 44 | public static $capacity = array( 45 | array( 0, 0, 0, array( 0, 0, 0, 0)), 46 | array( 21, 26, 0, array( 7, 10, 13, 17)), // 1 47 | array( 25, 44, 7, array( 10, 16, 22, 28)), 48 | array( 29, 70, 7, array( 15, 26, 36, 44)), 49 | array( 33, 100, 7, array( 20, 36, 52, 64)), 50 | array( 37, 134, 7, array( 26, 48, 72, 88)), // 5 51 | array( 41, 172, 7, array( 36, 64, 96, 112)), 52 | array( 45, 196, 0, array( 40, 72, 108, 130)), 53 | array( 49, 242, 0, array( 48, 88, 132, 156)), 54 | array( 53, 292, 0, array( 60, 110, 160, 192)), 55 | array( 57, 346, 0, array( 72, 130, 192, 224)), //10 56 | array( 61, 404, 0, array( 80, 150, 224, 264)), 57 | array( 65, 466, 0, array( 96, 176, 260, 308)), 58 | array( 69, 532, 0, array( 104, 198, 288, 352)), 59 | array( 73, 581, 3, array( 120, 216, 320, 384)), 60 | array( 77, 655, 3, array( 132, 240, 360, 432)), //15 61 | array( 81, 733, 3, array( 144, 280, 408, 480)), 62 | array( 85, 815, 3, array( 168, 308, 448, 532)), 63 | array( 89, 901, 3, array( 180, 338, 504, 588)), 64 | array( 93, 991, 3, array( 196, 364, 546, 650)), 65 | array( 97, 1085, 3, array( 224, 416, 600, 700)), //20 66 | array(101, 1156, 4, array( 224, 442, 644, 750)), 67 | array(105, 1258, 4, array( 252, 476, 690, 816)), 68 | array(109, 1364, 4, array( 270, 504, 750, 900)), 69 | array(113, 1474, 4, array( 300, 560, 810, 960)), 70 | array(117, 1588, 4, array( 312, 588, 870, 1050)), //25 71 | array(121, 1706, 4, array( 336, 644, 952, 1110)), 72 | array(125, 1828, 4, array( 360, 700, 1020, 1200)), 73 | array(129, 1921, 3, array( 390, 728, 1050, 1260)), 74 | array(133, 2051, 3, array( 420, 784, 1140, 1350)), 75 | array(137, 2185, 3, array( 450, 812, 1200, 1440)), //30 76 | array(141, 2323, 3, array( 480, 868, 1290, 1530)), 77 | array(145, 2465, 3, array( 510, 924, 1350, 1620)), 78 | array(149, 2611, 3, array( 540, 980, 1440, 1710)), 79 | array(153, 2761, 3, array( 570, 1036, 1530, 1800)), 80 | array(157, 2876, 0, array( 570, 1064, 1590, 1890)), //35 81 | array(161, 3034, 0, array( 600, 1120, 1680, 1980)), 82 | array(165, 3196, 0, array( 630, 1204, 1770, 2100)), 83 | array(169, 3362, 0, array( 660, 1260, 1860, 2220)), 84 | array(173, 3532, 0, array( 720, 1316, 1950, 2310)), 85 | array(177, 3706, 0, array( 750, 1372, 2040, 2430)) //40 86 | ); 87 | 88 | //---------------------------------------------------------------------- 89 | public static function getDataLength($version, $level) 90 | { 91 | return self::$capacity[$version][QRCAP_WORDS] - self::$capacity[$version][QRCAP_EC][$level]; 92 | } 93 | 94 | //---------------------------------------------------------------------- 95 | public static function getECCLength($version, $level) 96 | { 97 | return self::$capacity[$version][QRCAP_EC][$level]; 98 | } 99 | 100 | //---------------------------------------------------------------------- 101 | public static function getWidth($version) 102 | { 103 | return self::$capacity[$version][QRCAP_WIDTH]; 104 | } 105 | 106 | //---------------------------------------------------------------------- 107 | public static function getRemainder($version) 108 | { 109 | return self::$capacity[$version][QRCAP_REMINDER]; 110 | } 111 | 112 | //---------------------------------------------------------------------- 113 | public static function getMinimumVersion($size, $level) 114 | { 115 | 116 | for($i=1; $i<= QRSPEC_VERSION_MAX; $i++) { 117 | $words = self::$capacity[$i][QRCAP_WORDS] - self::$capacity[$i][QRCAP_EC][$level]; 118 | if($words >= $size) 119 | return $i; 120 | } 121 | 122 | return -1; 123 | } 124 | 125 | //###################################################################### 126 | 127 | public static $lengthTableBits = array( 128 | array(10, 12, 14), 129 | array( 9, 11, 13), 130 | array( 8, 16, 16), 131 | array( 8, 10, 12) 132 | ); 133 | 134 | //---------------------------------------------------------------------- 135 | public static function lengthIndicator($mode, $version) 136 | { 137 | if ($mode == QR_MODE_STRUCTURE) 138 | return 0; 139 | 140 | if ($version <= 9) { 141 | $l = 0; 142 | } else if ($version <= 26) { 143 | $l = 1; 144 | } else { 145 | $l = 2; 146 | } 147 | 148 | return self::$lengthTableBits[$mode][$l]; 149 | } 150 | 151 | //---------------------------------------------------------------------- 152 | public static function maximumWords($mode, $version) 153 | { 154 | if($mode == QR_MODE_STRUCTURE) 155 | return 3; 156 | 157 | if($version <= 9) { 158 | $l = 0; 159 | } else if($version <= 26) { 160 | $l = 1; 161 | } else { 162 | $l = 2; 163 | } 164 | 165 | $bits = self::$lengthTableBits[$mode][$l]; 166 | $words = (1 << $bits) - 1; 167 | 168 | if($mode == QR_MODE_KANJI) { 169 | $words *= 2; // the number of bytes is required 170 | } 171 | 172 | return $words; 173 | } 174 | 175 | // Error correction code ----------------------------------------------- 176 | // Table of the error correction code (Reed-Solomon block) 177 | // See Table 12-16 (pp.30-36), JIS X0510:2004. 178 | 179 | public static $eccTable = array( 180 | array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)), 181 | array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1 182 | array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), 183 | array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)), 184 | array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)), 185 | array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5 186 | array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)), 187 | array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)), 188 | array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)), 189 | array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)), 190 | array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), //10 191 | array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)), 192 | array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)), 193 | array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)), 194 | array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)), 195 | array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), //15 196 | array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)), 197 | array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)), 198 | array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)), 199 | array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)), 200 | array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), //20 201 | array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)), 202 | array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)), 203 | array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)), 204 | array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)), 205 | array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), //25 206 | array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), 207 | array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)), 208 | array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), 209 | array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)), 210 | array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), //30 211 | array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)), 212 | array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), 213 | array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), 214 | array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), 215 | array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), //35 216 | array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), 217 | array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), 218 | array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), 219 | array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), 220 | array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)),//40 221 | ); 222 | 223 | //---------------------------------------------------------------------- 224 | // CACHEABLE!!! 225 | 226 | public static function getEccSpec($version, $level, array &$spec) 227 | { 228 | if (count($spec) < 5) { 229 | $spec = array(0,0,0,0,0); 230 | } 231 | 232 | $b1 = self::$eccTable[$version][$level][0]; 233 | $b2 = self::$eccTable[$version][$level][1]; 234 | $data = self::getDataLength($version, $level); 235 | $ecc = self::getECCLength($version, $level); 236 | 237 | if($b2 == 0) { 238 | $spec[0] = $b1; 239 | $spec[1] = (int)($data / $b1); 240 | $spec[2] = (int)($ecc / $b1); 241 | $spec[3] = 0; 242 | $spec[4] = 0; 243 | } else { 244 | $spec[0] = $b1; 245 | $spec[1] = (int)($data / ($b1 + $b2)); 246 | $spec[2] = (int)($ecc / ($b1 + $b2)); 247 | $spec[3] = $b2; 248 | $spec[4] = $spec[1] + 1; 249 | } 250 | } 251 | 252 | // Alignment pattern --------------------------------------------------- 253 | 254 | // Positions of alignment patterns. 255 | // This array includes only the second and the third position of the 256 | // alignment patterns. Rest of them can be calculated from the distance 257 | // between them. 258 | 259 | // See Table 1 in Appendix E (pp.71) of JIS X0510:2004. 260 | 261 | public static $alignmentPattern = array( 262 | array( 0, 0), 263 | array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5 264 | array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10 265 | array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15 266 | array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20 267 | array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25 268 | array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30 269 | array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35 270 | array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //35-40 271 | ); 272 | 273 | 274 | /** -------------------------------------------------------------------- 275 | * Put an alignment marker. 276 | * @param frame 277 | * @param width 278 | * @param ox,oy center coordinate of the pattern 279 | */ 280 | public static function putAlignmentMarker(array &$frame, $ox, $oy) 281 | { 282 | $finder = array( 283 | "\xa1\xa1\xa1\xa1\xa1", 284 | "\xa1\xa0\xa0\xa0\xa1", 285 | "\xa1\xa0\xa1\xa0\xa1", 286 | "\xa1\xa0\xa0\xa0\xa1", 287 | "\xa1\xa1\xa1\xa1\xa1" 288 | ); 289 | 290 | $yStart = $oy-2; 291 | $xStart = $ox-2; 292 | 293 | for($y=0; $y<5; $y++) { 294 | QRstr::set($frame, $xStart, $yStart+$y, $finder[$y]); 295 | } 296 | } 297 | 298 | //---------------------------------------------------------------------- 299 | public static function putAlignmentPattern($version, &$frame, $width) 300 | { 301 | if($version < 2) 302 | return; 303 | 304 | $d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0]; 305 | if($d < 0) { 306 | $w = 2; 307 | } else { 308 | $w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2); 309 | } 310 | 311 | if($w * $w - 3 == 1) { 312 | $x = self::$alignmentPattern[$version][0]; 313 | $y = self::$alignmentPattern[$version][0]; 314 | self::putAlignmentMarker($frame, $x, $y); 315 | return; 316 | } 317 | 318 | $cx = self::$alignmentPattern[$version][0]; 319 | for($x=1; $x<$w - 1; $x++) { 320 | self::putAlignmentMarker($frame, 6, $cx); 321 | self::putAlignmentMarker($frame, $cx, 6); 322 | $cx += $d; 323 | } 324 | 325 | $cy = self::$alignmentPattern[$version][0]; 326 | for($y=0; $y<$w-1; $y++) { 327 | $cx = self::$alignmentPattern[$version][0]; 328 | for($x=0; $x<$w-1; $x++) { 329 | self::putAlignmentMarker($frame, $cx, $cy); 330 | $cx += $d; 331 | } 332 | $cy += $d; 333 | } 334 | } 335 | 336 | // Version information pattern ----------------------------------------- 337 | 338 | // Version information pattern (BCH coded). 339 | // See Table 1 in Appendix D (pp.68) of JIS X0510:2004. 340 | 341 | // size: [QRSPEC_VERSION_MAX - 6] 342 | 343 | public static $versionPattern = array( 344 | 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 345 | 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, 346 | 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, 347 | 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 348 | 0x27541, 0x28c69 349 | ); 350 | 351 | //---------------------------------------------------------------------- 352 | public static function getVersionPattern($version) 353 | { 354 | if($version < 7 || $version > QRSPEC_VERSION_MAX) 355 | return 0; 356 | 357 | return self::$versionPattern[$version -7]; 358 | } 359 | 360 | // Format information -------------------------------------------------- 361 | // See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib) 362 | 363 | public static $formatInfo = array( 364 | array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), 365 | array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), 366 | array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), 367 | array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) 368 | ); 369 | 370 | public static function getFormatInfo($mask, $level) 371 | { 372 | if($mask < 0 || $mask > 7) 373 | return 0; 374 | 375 | if($level < 0 || $level > 3) 376 | return 0; 377 | 378 | return self::$formatInfo[$level][$mask]; 379 | } 380 | 381 | // Frame --------------------------------------------------------------- 382 | // Cache of initial frames. 383 | 384 | public static $frames = array(); 385 | 386 | /** -------------------------------------------------------------------- 387 | * Put a finder pattern. 388 | * @param frame 389 | * @param width 390 | * @param ox,oy upper-left coordinate of the pattern 391 | */ 392 | public static function putFinderPattern(&$frame, $ox, $oy) 393 | { 394 | $finder = array( 395 | "\xc1\xc1\xc1\xc1\xc1\xc1\xc1", 396 | "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", 397 | "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", 398 | "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", 399 | "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", 400 | "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", 401 | "\xc1\xc1\xc1\xc1\xc1\xc1\xc1" 402 | ); 403 | 404 | for($y=0; $y<7; $y++) { 405 | QRstr::set($frame, $ox, $oy+$y, $finder[$y]); 406 | } 407 | } 408 | 409 | //---------------------------------------------------------------------- 410 | public static function createFrame($version) 411 | { 412 | $width = self::$capacity[$version][QRCAP_WIDTH]; 413 | $frameLine = str_repeat ("\0", $width); 414 | $frame = array_fill(0, $width, $frameLine); 415 | 416 | // Finder pattern 417 | self::putFinderPattern($frame, 0, 0); 418 | self::putFinderPattern($frame, $width - 7, 0); 419 | self::putFinderPattern($frame, 0, $width - 7); 420 | 421 | // Separator 422 | $yOffset = $width - 7; 423 | 424 | for($y=0; $y<7; $y++) { 425 | $frame[$y][7] = "\xc0"; 426 | $frame[$y][$width - 8] = "\xc0"; 427 | $frame[$yOffset][7] = "\xc0"; 428 | $yOffset++; 429 | } 430 | 431 | $setPattern = str_repeat("\xc0", 8); 432 | 433 | QRstr::set($frame, 0, 7, $setPattern); 434 | QRstr::set($frame, $width-8, 7, $setPattern); 435 | QRstr::set($frame, 0, $width - 8, $setPattern); 436 | 437 | // Format info 438 | $setPattern = str_repeat("\x84", 9); 439 | QRstr::set($frame, 0, 8, $setPattern); 440 | QRstr::set($frame, $width - 8, 8, $setPattern, 8); 441 | 442 | $yOffset = $width - 8; 443 | 444 | for($y=0; $y<8; $y++,$yOffset++) { 445 | $frame[$y][8] = "\x84"; 446 | $frame[$yOffset][8] = "\x84"; 447 | } 448 | 449 | // Timing pattern 450 | 451 | for($i=1; $i<$width-15; $i++) { 452 | $frame[6][7+$i] = chr(0x90 | ($i & 1)); 453 | $frame[7+$i][6] = chr(0x90 | ($i & 1)); 454 | } 455 | 456 | // Alignment pattern 457 | self::putAlignmentPattern($version, $frame, $width); 458 | 459 | // Version information 460 | if($version >= 7) { 461 | $vinf = self::getVersionPattern($version); 462 | 463 | $v = $vinf; 464 | 465 | for($x=0; $x<6; $x++) { 466 | for($y=0; $y<3; $y++) { 467 | $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1)); 468 | $v = $v >> 1; 469 | } 470 | } 471 | 472 | $v = $vinf; 473 | for($y=0; $y<6; $y++) { 474 | for($x=0; $x<3; $x++) { 475 | $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1)); 476 | $v = $v >> 1; 477 | } 478 | } 479 | } 480 | 481 | // and a little bit... 482 | $frame[$width - 8][8] = "\x81"; 483 | 484 | return $frame; 485 | } 486 | 487 | //---------------------------------------------------------------------- 488 | public static function debug($frame, $binary_mode = false) 489 | { 490 | if ($binary_mode) { 491 | 492 | foreach ($frame as &$frameLine) { 493 | $frameLine = join('  ', explode('0', $frameLine)); 494 | $frameLine = join('██', explode('1', $frameLine)); 495 | } 496 | 497 | ?> 498 | 501 |


        '; 503 | echo join("
        ", $frame); 504 | echo '






'; 505 | 506 | } else { 507 | 508 | foreach ($frame as &$frameLine) { 509 | $frameLine = join(' ', explode("\xc0", $frameLine)); 510 | $frameLine = join('', explode("\xc1", $frameLine)); 511 | $frameLine = join(' ', explode("\xa0", $frameLine)); 512 | $frameLine = join('', explode("\xa1", $frameLine)); 513 | $frameLine = join('', explode("\x84", $frameLine)); //format 0 514 | $frameLine = join('', explode("\x85", $frameLine)); //format 1 515 | $frameLine = join('', explode("\x81", $frameLine)); //special bit 516 | $frameLine = join(' ', explode("\x90", $frameLine)); //clock 0 517 | $frameLine = join('', explode("\x91", $frameLine)); //clock 1 518 | $frameLine = join(' ', explode("\x88", $frameLine)); //version 519 | $frameLine = join('', explode("\x89", $frameLine)); //version 520 | $frameLine = join('♦', explode("\x01", $frameLine)); 521 | $frameLine = join('⋅', explode("\0", $frameLine)); 522 | } 523 | 524 | ?> 525 | 533 | "; 535 | echo join("
", $frame); 536 | echo "
"; 537 | 538 | } 539 | } 540 | 541 | //---------------------------------------------------------------------- 542 | public static function serial($frame) 543 | { 544 | return gzcompress(join("\n", $frame), 9); 545 | } 546 | 547 | //---------------------------------------------------------------------- 548 | public static function unserial($code) 549 | { 550 | return explode("\n", gzuncompress($code)); 551 | } 552 | 553 | //---------------------------------------------------------------------- 554 | public static function newFrame($version) 555 | { 556 | if($version < 1 || $version > QRSPEC_VERSION_MAX) 557 | return null; 558 | 559 | if(!isset(self::$frames[$version])) { 560 | 561 | $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat'; 562 | 563 | if (QR_CACHEABLE) { 564 | if (file_exists($fileName)) { 565 | self::$frames[$version] = self::unserial(file_get_contents($fileName)); 566 | } else { 567 | self::$frames[$version] = self::createFrame($version); 568 | file_put_contents($fileName, self::serial(self::$frames[$version])); 569 | } 570 | } else { 571 | self::$frames[$version] = self::createFrame($version); 572 | } 573 | } 574 | 575 | if(is_null(self::$frames[$version])) 576 | return null; 577 | 578 | return self::$frames[$version]; 579 | } 580 | 581 | //---------------------------------------------------------------------- 582 | public static function rsBlockNum($spec) { return $spec[0] + $spec[3]; } 583 | public static function rsBlockNum1($spec) { return $spec[0]; } 584 | public static function rsDataCodes1($spec) { return $spec[1]; } 585 | public static function rsEccCodes1($spec) { return $spec[2]; } 586 | public static function rsBlockNum2($spec) { return $spec[3]; } 587 | public static function rsDataCodes2($spec) { return $spec[4]; } 588 | public static function rsEccCodes2($spec) { return $spec[2]; } 589 | public static function rsDataLength($spec) { return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]); } 590 | public static function rsEccLength($spec) { return ($spec[0] + $spec[3]) * $spec[2]; } 591 | 592 | } --------------------------------------------------------------------------------