survey_seahorse

Software Engineering Project - Fall 2018
Log | Files | Refs | README

qrspec.php (26612B)


      1 <?php
      2 /*
      3  * PHP QR Code encoder
      4  *
      5  * QR Code specifications
      6  *
      7  * Based on libqrencode C library distributed under LGPL 2.1
      8  * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
      9  *
     10  * PHP QR Code is distributed under LGPL 3
     11  * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
     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('<span class="m">&nbsp;&nbsp;</span>', explode('0', $frameLine));
    494                         $frameLine = join('&#9608;&#9608;', explode('1', $frameLine));
    495                     }
    496                     
    497                     ?>
    498                 <style>
    499                     .m { background-color: white; }
    500                 </style>
    501                 <?php
    502                     echo '<pre><tt><br/ ><br/ ><br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
    503                     echo join("<br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", $frame);
    504                     echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >';
    505             
    506             } else {
    507             
    508                 foreach ($frame as &$frameLine) {
    509                     $frameLine = join('<span class="m">&nbsp;</span>',  explode("\xc0", $frameLine));
    510                     $frameLine = join('<span class="m">&#9618;</span>', explode("\xc1", $frameLine));
    511                     $frameLine = join('<span class="p">&nbsp;</span>',  explode("\xa0", $frameLine));
    512                     $frameLine = join('<span class="p">&#9618;</span>', explode("\xa1", $frameLine));
    513                     $frameLine = join('<span class="s">&#9671;</span>', explode("\x84", $frameLine)); //format 0
    514                     $frameLine = join('<span class="s">&#9670;</span>', explode("\x85", $frameLine)); //format 1
    515                     $frameLine = join('<span class="x">&#9762;</span>', explode("\x81", $frameLine)); //special bit
    516                     $frameLine = join('<span class="c">&nbsp;</span>',  explode("\x90", $frameLine)); //clock 0
    517                     $frameLine = join('<span class="c">&#9719;</span>', explode("\x91", $frameLine)); //clock 1
    518                     $frameLine = join('<span class="f">&nbsp;</span>',  explode("\x88", $frameLine)); //version
    519                     $frameLine = join('<span class="f">&#9618;</span>', explode("\x89", $frameLine)); //version
    520                     $frameLine = join('&#9830;', explode("\x01", $frameLine));
    521                     $frameLine = join('&#8901;', explode("\0", $frameLine));
    522                 }
    523                 
    524                 ?>
    525                 <style>
    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; }
    532                 </style>
    533                 <?php
    534                 echo "<pre><tt>";
    535                 echo join("<br/ >", $frame);
    536                 echo "</tt></pre>";
    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     }