]>
Raphaƫl G. Git Repositories - cdn/blob - vendor/phpqrcode/qrspec.php
5 * QR Code specifications
7 * Based on libqrencode C library distributed under LGPL 2.1
8 * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
10 * PHP QR Code is distributed under LGPL 3
11 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
13 * The following data / specifications are taken from
14 * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004)
16 * "Automatic identification and data capture techniques --
17 * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006)
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.
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.
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
34 define('QRSPEC_VERSION_MAX', 40);
35 define('QRSPEC_WIDTH_MAX', 177);
37 define('QRCAP_WIDTH', 0);
38 define('QRCAP_WORDS', 1);
39 define('QRCAP_REMINDER', 2);
40 define('QRCAP_EC', 3);
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
88 //----------------------------------------------------------------------
89 public static function getDataLength($version, $level)
91 return self
::$capacity[$version][QRCAP_WORDS
] - self
::$capacity[$version][QRCAP_EC
][$level];
94 //----------------------------------------------------------------------
95 public static function getECCLength($version, $level)
97 return self
::$capacity[$version][QRCAP_EC
][$level];
100 //----------------------------------------------------------------------
101 public static function getWidth($version)
103 return self
::$capacity[$version][QRCAP_WIDTH
];
106 //----------------------------------------------------------------------
107 public static function getRemainder($version)
109 return self
::$capacity[$version][QRCAP_REMINDER
];
112 //----------------------------------------------------------------------
113 public static function getMinimumVersion($size, $level)
116 for($i=1; $i<= QRSPEC_VERSION_MAX
; $i++
) {
117 $words = self
::$capacity[$i][QRCAP_WORDS
] - self
::$capacity[$i][QRCAP_EC
][$level];
125 //######################################################################
127 public static $lengthTableBits = array(
134 //----------------------------------------------------------------------
135 public static function lengthIndicator($mode, $version)
137 if ($mode == QR_MODE_STRUCTURE
)
142 } else if ($version <= 26) {
148 return self
::$lengthTableBits[$mode][$l];
151 //----------------------------------------------------------------------
152 public static function maximumWords($mode, $version)
154 if($mode == QR_MODE_STRUCTURE
)
159 } else if($version <= 26) {
165 $bits = self
::$lengthTableBits[$mode][$l];
166 $words = (1 << $bits) - 1;
168 if($mode == QR_MODE_KANJI
) {
169 $words *= 2; // the number of bytes is required
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.
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
223 //----------------------------------------------------------------------
226 public static function getEccSpec($version, $level, array &$spec)
228 if (count($spec) < 5) {
229 $spec = array(0,0,0,0,0);
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);
239 $spec[1] = (int)($data / $b1);
240 $spec[2] = (int)($ecc / $b1);
245 $spec[1] = (int)($data / ($b1 +
$b2));
246 $spec[2] = (int)($ecc / ($b1 +
$b2));
248 $spec[4] = $spec[1] +
1;
252 // Alignment pattern ---------------------------------------------------
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
259 // See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
261 public static $alignmentPattern = array(
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
274 /** --------------------------------------------------------------------
275 * Put an alignment marker.
278 * @param ox,oy center coordinate of the pattern
280 public static function putAlignmentMarker(array &$frame, $ox, $oy)
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"
293 for($y=0; $y<5; $y++
) {
294 QRstr
::set($frame, $xStart, $yStart+
$y, $finder[$y]);
298 //----------------------------------------------------------------------
299 public static function putAlignmentPattern($version, &$frame, $width)
304 $d = self
::$alignmentPattern[$version][1] - self
::$alignmentPattern[$version][0];
308 $w = (int)(($width - self
::$alignmentPattern[$version][0]) / $d +
2);
311 if($w * $w - 3 == 1) {
312 $x = self
::$alignmentPattern[$version][0];
313 $y = self
::$alignmentPattern[$version][0];
314 self
::putAlignmentMarker($frame, $x, $y);
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);
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);
336 // Version information pattern -----------------------------------------
338 // Version information pattern (BCH coded).
339 // See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
341 // size: [QRSPEC_VERSION_MAX - 6]
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,
351 //----------------------------------------------------------------------
352 public static function getVersionPattern($version)
354 if($version < 7 || $version > QRSPEC_VERSION_MAX
)
357 return self
::$versionPattern[$version -7];
360 // Format information --------------------------------------------------
361 // See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib)
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)
370 public static function getFormatInfo($mask, $level)
372 if($mask < 0 || $mask > 7)
375 if($level < 0 || $level > 3)
378 return self
::$formatInfo[$level][$mask];
381 // Frame ---------------------------------------------------------------
382 // Cache of initial frames.
384 public static $frames = array();
386 /** --------------------------------------------------------------------
387 * Put a finder pattern.
390 * @param ox,oy upper-left coordinate of the pattern
392 public static function putFinderPattern(&$frame, $ox, $oy)
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"
404 for($y=0; $y<7; $y++
) {
405 QRstr
::set($frame, $ox, $oy+
$y, $finder[$y]);
409 //----------------------------------------------------------------------
410 public static function createFrame($version)
412 $width = self
::$capacity[$version][QRCAP_WIDTH
];
413 $frameLine = str_repeat ("\0", $width);
414 $frame = array_fill(0, $width, $frameLine);
417 self
::putFinderPattern($frame, 0, 0);
418 self
::putFinderPattern($frame, $width - 7, 0);
419 self
::putFinderPattern($frame, 0, $width - 7);
422 $yOffset = $width - 7;
424 for($y=0; $y<7; $y++
) {
425 $frame[$y][7] = "\xc0";
426 $frame[$y][$width - 8] = "\xc0";
427 $frame[$yOffset][7] = "\xc0";
431 $setPattern = str_repeat("\xc0", 8);
433 QRstr
::set($frame, 0, 7, $setPattern);
434 QRstr
::set($frame, $width-8, 7, $setPattern);
435 QRstr
::set($frame, 0, $width - 8, $setPattern);
438 $setPattern = str_repeat("\x84", 9);
439 QRstr
::set($frame, 0, 8, $setPattern);
440 QRstr
::set($frame, $width - 8, 8, $setPattern, 8);
442 $yOffset = $width - 8;
444 for($y=0; $y<8; $y++
,$yOffset++
) {
445 $frame[$y][8] = "\x84";
446 $frame[$yOffset][8] = "\x84";
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));
457 self
::putAlignmentPattern($version, $frame, $width);
459 // Version information
461 $vinf = self
::getVersionPattern($version);
465 for($x=0; $x<6; $x++
) {
466 for($y=0; $y<3; $y++
) {
467 $frame[($width - 11)+
$y][$x] = chr(0x88 | ($v & 1));
473 for($y=0; $y<6; $y++
) {
474 for($x=0; $x<3; $x++
) {
475 $frame[$y][$x+
($width - 11)] = chr(0x88 | ($v & 1));
481 // and a little bit...
482 $frame[$width - 8][8] = "\x81";
487 //----------------------------------------------------------------------
488 public static function debug($frame, $binary_mode = false)
492 foreach ($frame as &$frameLine) {
493 $frameLine = join('<span class="m"> </span>', explode('0', $frameLine));
494 $frameLine = join('██', explode('1', $frameLine));
499 .m { background
-color
: white
; }
502 echo '<pre><tt><br/ ><br/ ><br/ > ';
503 echo join("<br/ > ", $frame);
504 echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >';
508 foreach ($frame as &$frameLine) {
509 $frameLine = join('<span class="m"> </span>', explode("\xc0", $frameLine));
510 $frameLine = join('<span class="m">▒</span>', explode("\xc1", $frameLine));
511 $frameLine = join('<span class="p"> </span>', explode("\xa0", $frameLine));
512 $frameLine = join('<span class="p">▒</span>', explode("\xa1", $frameLine));
513 $frameLine = join('<span class="s">◇</span>', explode("\x84", $frameLine)); //format 0
514 $frameLine = join('<span class="s">◆</span>', explode("\x85", $frameLine)); //format 1
515 $frameLine = join('<span class="x">☢</span>', explode("\x81", $frameLine)); //special bit
516 $frameLine = join('<span class="c"> </span>', explode("\x90", $frameLine)); //clock 0
517 $frameLine = join('<span class="c">◷</span>', explode("\x91", $frameLine)); //clock 1
518 $frameLine = join('<span class="f"> </span>', explode("\x88", $frameLine)); //version
519 $frameLine = join('<span class="f">▒</span>', explode("\x89", $frameLine)); //version
520 $frameLine = join('♦', explode("\x01", $frameLine));
521 $frameLine = join('⋅', explode("\0", $frameLine));
526 .p { background
-color
: yellow
; }
527 .m { background
-color
: #00FF00; }
528 .s { background
-color
: #FF0000; }
529 .c { background
-color
: aqua
; }
530 .x { background
-color
: pink
; }
531 .f { background
-color
: gold
; }
535 echo join("<br/ >", $frame);
541 //----------------------------------------------------------------------
542 public static function serial($frame)
544 return gzcompress(join("\n", $frame), 9);
547 //----------------------------------------------------------------------
548 public static function unserial($code)
550 return explode("\n", gzuncompress($code));
553 //----------------------------------------------------------------------
554 public static function newFrame($version)
556 if($version < 1 || $version > QRSPEC_VERSION_MAX
)
559 if(!isset(self
::$frames[$version])) {
561 $fileName = QR_CACHE_DIR
.'frame_'.$version.'.dat';
564 if (file_exists($fileName)) {
565 self
::$frames[$version] = self
::unserial(file_get_contents($fileName));
567 self
::$frames[$version] = self
::createFrame($version);
568 file_put_contents($fileName, self
::serial(self
::$frames[$version]));
571 self
::$frames[$version] = self
::createFrame($version);
575 if(is_null(self
::$frames[$version]))
578 return self
::$frames[$version];
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]; }