diff --git a/.gitattributes b/.gitattributes old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.travis.yml b/.travis.yml old mode 100644 new mode 100755 diff --git a/Base1DBarcode.php b/Base1DBarcode.php old mode 100644 new mode 100755 index 7ce6e89..d768cfd --- a/Base1DBarcode.php +++ b/Base1DBarcode.php @@ -45,2534 +45,2534 @@ */ class Base1DBarcode { - /** - * @const C_DEFAULT_ROTATION_DEG default value for barcode rotation - */ - const C_DEFAULT_ROTATION_DEG = 90; - - /** - * Array representation of barcode. - * @protected - */ - protected $barcodeArray; - - /** - *path to save png in getBarcodePNGPath - * @var - */ - public $savePath; - - /** - * Return an array representations of barcode. - * @return array - * @public - */ - public function getBarcodeArray() - { - return $this->barcodeArray; - } - - /** - * setup temporary path for barcode cache - * - * @param string $serverPath - * - * @throws \Exception - */ - public function setTempPath($serverPath) - { - try { - if (!file_exists($serverPath)) { - mkdir($serverPath, 0770, true); - } - } catch (\Exception $e) { - throw new \Exception("An error occurred while creating barcode cache directory at " . $serverPath); - } - } - - /** - * Send barcode as SVG image object to the standard output. - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param string $color - */ - public function getBarcodeSVG($code, $type,$w=2, $h=30, $color='black') - { - $this->setBarcode($code, $type); - $code = $this->getBarcodeSVGcode($w, $h, $color); - header('Content-Type: application/svg+xml'); - header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 - header('Pragma: public'); - header('Expires: Sat, 12 Nov 1977 23:50:00 GMT'); // Date in the past - header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - header('Content-Disposition: inline; filename="'.md5($code).'.svg";'); - header('Content-Length: '.strlen($code)); - echo $code; - } - - /** - * Return a SVG string representation of barcode. - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param string $color - * - * @return string - */ - public function getBarcodeSVGcode($code, $type,$w=2, $h=30, $color='black') - { - $this->setBarcode($code, $type); - // replace table for special characters - $repstr = array("\0" => '', '&' => '&', '<' => '<', '>' => '>'); - $svg = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n"; - $svg .= ''."\n"; - $svg .= ''."\n"; - $svg .= "\t".''.strtr($this->barcodeArray['code'], $repstr).''."\n"; - $svg .= "\t".''."\n"; - // print bars - $x = 0; - foreach ($this->barcodeArray['bcode'] as $v) { - $bw = round(($v['w'] * $w), 3); - $bh = round(($v['h'] * $h / $this->barcodeArray['maxh']), 3); - if ($v['t']) { - $y = round(($v['p'] * $h / $this->barcodeArray['maxh']), 3); - // draw a vertical bar - $svg .= "\t\t".''."\n"; - } - $x += $bw; - } - $svg .= "\t".''."\n"; - $svg .= ''."\n"; - - return $svg; - } - - /** - * Return an HTML representation of barcode. - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param string $color - * - * @return string - */ - public function getBarcodeHTML($code, $type,$w=2, $h=30, $color='black') - { - $this->setBarcode($code, $type); - $html = '
'."\n"; - // print bars - $x = 0; - foreach ($this->barcodeArray['bcode'] as $v) { - $bw = round(($v['w'] * $w), 3); - $bh = round(($v['h'] * $h / $this->barcodeArray['maxh']), 3); - if ($v['t']) { - $y = round(($v['p'] * $h / $this->barcodeArray['maxh']), 3); - // draw a vertical bar - $html .= '
 
'."\n"; - } - $x += $bw; - } - $html .= '
'."\n"; - - return $html; - } - - /** - * Return a PNG image representation of barcode (requires GD or Imagick library). - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param array $color - * @param bool $vertical - * - * @return bool - */ - public function getBarcodePNG($code, $type,$w=2, $h=30, $color=array(0,0,0), $vertical = false) - { - $this->setBarcode($code, $type); - $bar = null; - - // calculate image size - $width = ($this->barcodeArray['maxw'] * $w); - $height = $h; - if (function_exists('imagecreate')) { - // GD library - $imagick = false; - $png = imagecreate($width, $height); - $bgcol = imagecolorallocate($png, 255, 255, 255); - imagecolortransparent($png, $bgcol); - $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); - } elseif (extension_loaded('imagick')) { - $imagick = true; - $fgcol = new \imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')'); - $png = new \Imagick(); - $png->newImage($width, $height, 'none', 'png'); - $bar = new \imagickdraw(); - $bar->setFillColor($fgcol); - } else { - - return false; - } - // print bars - $x = 0; - $sharp = 3; - $bwPerc = 100; - - foreach ($this->barcodeArray['bcode'] as $v) { - - $bw = round(round(($v['w'] * $w), $sharp) * $bwPerc / 100, $sharp); - $bh = round(($v['h'] * $h / $this->barcodeArray['maxh']), $sharp); - - if ($v['t']) { - $y = round(($v['p'] * $h / $this->barcodeArray['maxh']), 3); - // draw a vertical bar - if ($imagick) { - $bar->rectangle($x, $y, ($x + $bw), ($y + $bh)); - } else { - imagefilledrectangle($png, $x, $y, ($x + $bw), ($y + $bh), $fgcol); - } - } - $x += $bw; - } - - if ($vertical) - { - $png = $this->rotateImage($png, self::C_DEFAULT_ROTATION_DEG); - } - - // send headers - header('Content-Type: image/png'); - header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 - header('Pragma: public'); - header('Expires: Sat, 12 Nov 1977 23:50:00 GMT'); // Date in the past - header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - if ($imagick) { - $png->drawimage($bar); - echo $png; - } else { - imagepng($png); - imagedestroy($png); - } - - return true; - } - - /** - * return filename from give path - * - * @todo: refactor this, move method in some kind of utility class - * - * @param string $path - * - * @return mixed - */ - public function getBarcodeFilenameFromGenPath($path) - { - $bcPathArr = explode('/', $path); - return $bcPathArr[count($bcPathArr)-1]; - } - - /** - * Return a rotated version of source image - * - * @param resource $image - * @param int $angel - * - * @return resource - */ - public function rotateImage($image, $angel) - { - if (function_exists('imagecreate')) { - imagealphablending($image, false); - imagesavealpha($image, true); - - $imageRotate = imagerotate($image, $angel, imageColorAllocateAlpha($image, 0, 0, 0, 127)); - imagealphablending($imageRotate, false); - imagesavealpha($imageRotate, true); - - return $imageRotate; - } - else { - /** @var $image \Imagick */ - $image->rotateImage(new \imagickpixel('rgb(0,0,0)'), $angel); - return $image; - } - } - - /** - * Return a .png file path which create in server - * - * @param string $code - * @param string $type - * @param string $name - * @param int $w - * @param int $h - * @param array $color - * @param bool $vertical - * @param bool $transparent - * - * @return bool - * - * @throws \Exception - */ - public function getBarcodePNGPath($code, $type, $name=null, $w=2, $h=30, $color=array(0,0,0), $vertical=false, $transparent = true) - { - $this->setBarcode($code, $type); - $bar = null; - - if (true === empty($name)) { - $name = md5($code); - } - - // calculate image size - $width = ($this->barcodeArray['maxw'] * $w); - $height = $h; - - if (empty($this->barcodeArray) || (!$this->barcodeArray)) { - throw new \Exception('It not possible to generate barcode of type: '.$type.' for number/code: '.$code.'! May be this is an invalid code pattern!'); - } - - if (function_exists('imagecreate')) { - // GD library - $imagick = false; - - $png = imagecreate($width, $height); - $bgcol = imagecolorallocate($png, 255, 255, 255); - if($transparent){ - imagecolortransparent($png, $bgcol); - } - $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); - } elseif (extension_loaded('imagick')) { - $imagick = true; - $fgcol = new \imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')'); - $png = new \Imagick(); - $png->newImage($width, $height, 'none', 'png'); - $bar = new \imagickdraw(); - $bar->setFillColor($fgcol); - } else { - - return false; - } - - // print bars - $x = 0; - $sharp = 3; - $bwPerc = 100; - - foreach ($this->barcodeArray['bcode'] as $v) { - - $bw = round(round(($v['w'] * $w), $sharp) * $bwPerc / 100, $sharp); - $bh = round(($v['h'] * $h / $this->barcodeArray['maxh']), $sharp); - if ($v['t']) { - $y = round(($v['p'] * $h / $this->barcodeArray['maxh']), $sharp); - // draw a vertical bar - if ($imagick) { - $bar->rectangle($x, $y, ($x + $bw), ($y + $bh)); - } else { - imagefilledrectangle($png, $x, $y, ($x + $bw), ($y + $bh), $fgcol); - } - } - - $x += ($bw); - - } - - if ($vertical) - { - $png = $this->rotateImage($png, self::C_DEFAULT_ROTATION_DEG); - } - - $nType = str_replace('+', 'PLUS', $type); - - $this->setTempPath($this->savePath); - $saveFile = $this->checkfile($this->savePath . $nType . '_' . $name . '.png', true); - - if ($imagick) { - $png->drawImage($bar); - $png->writeImage($saveFile); - return $saveFile; - } - - if (imagepng($png, $saveFile)) { - - imagedestroy($png); - - return $saveFile; - - } else { - - imagedestroy($png); - - throw new \Exception('It not possible to write barcode cache file to path '.$this->savePath); - } - } - - /** - * @param string $code - * @param string $type - */ - public function setBarcode($code, $type) - { - switch (strtoupper(trim($type))) { - case 'C39': // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. - $arrcode = $this->barcode_code39($code, false, false); - break; - - case 'C39+': // CODE 39 with checksum - $arrcode = $this->barcode_code39($code, false, true); - break; - - case 'C39E': // CODE 39 EXTENDED - $arrcode = $this->barcode_code39($code, true, false); - break; - - case 'C39E+': // CODE 39 EXTENDED + CHECKSUM - $arrcode = $this->barcode_code39($code, true, true); - break; - - case 'C93': // CODE 93 - USS-93 - $arrcode = $this->barcode_code93($code); - break; - - case 'S25': // Standard 2 of 5 - $arrcode = $this->barcode_s25($code, false); - break; - - case 'S25+': // Standard 2 of 5 + CHECKSUM - $arrcode = $this->barcode_s25($code, true); - break; - - case 'I25': // Interleaved 2 of 5 - $arrcode = $this->barcode_i25($code, false); - break; - - case 'I25+': // Interleaved 2 of 5 + CHECKSUM - $arrcode = $this->barcode_i25($code, true); - break; - - case 'C128': // CODE 128 - $arrcode = $this->barcode_c128($code, ''); - break; - - case 'C128A': // CODE 128 A - $arrcode = $this->barcode_c128($code, 'A'); - break; - - case 'C128B': // CODE 128 B - $arrcode = $this->barcode_c128($code, 'B'); - break; - - case 'C128C': // CODE 128 C - $arrcode = $this->barcode_c128($code, 'C'); - break; - - case 'EAN2': // 2-Digits UPC-Based Extention - $arrcode = $this->barcode_eanext($code, 2); - break; - - case 'EAN5': // 5-Digits UPC-Based Extention - $arrcode = $this->barcode_eanext($code, 5); - break; - - case 'EAN8': // EAN 8 - $arrcode = $this->barcode_eanupc($code, 8); - break; - - case 'EAN13': // EAN 13 - $arrcode = $this->barcode_eanupc($code, 13); - break; - - case 'UPCA': // UPC-A - $arrcode = $this->barcode_eanupc($code, 12); - break; - - case 'UPCE': // UPC-E - $arrcode = $this->barcode_eanupc($code, 6); - break; - - case 'MSI': // MSI (Variation of Plessey code) - $arrcode = $this->barcode_msi($code, false); - break; - - case 'MSI+': // MSI + CHECKSUM (modulo 11) - $arrcode = $this->barcode_msi($code, true); - break; - - case 'POSTNET': // POSTNET - $arrcode = $this->barcode_postnet($code, false); - break; - - case 'PLANET': // PLANET - $arrcode = $this->barcode_postnet($code, true); - break; - - case 'RMS4CC': // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - $arrcode = $this->barcode_rms4cc($code, false); - break; - - case 'KIX': // KIX (Klant index - Customer index) - $arrcode = $this->barcode_rms4cc($code, true); - break; - - case 'IMB': // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 - $arrcode = $this->barcode_imb($code); - break; - - case 'CODABAR': // CODABAR - $arrcode = $this->barcode_codabar($code); - break; - - case 'CODE11': // CODE 11 - $arrcode = $this->barcode_code11($code); - break; - - case 'PHARMA': // PHARMACODE - $arrcode = $this->barcode_pharmacode($code); - break; - - case 'PHARMA2T': // PHARMACODE TWO-TRACKS - $arrcode = $this->barcode_pharmacode2t($code); - break; - - default: - $this->barcodeArray = false; - $arrcode = false; - break; - } - - $this->barcodeArray = $arrcode; - - } - - /** - * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. General-purpose code in very wide use world-wide - * - * @param string $code - * @param bool $extended - * @param bool $checksum - * - * @return array|bool - */ - protected function barcode_code39($code, $extended=false, $checksum=false) - { - $chr['0'] = '111331311'; - $chr['1'] = '311311113'; - $chr['2'] = '113311113'; - $chr['3'] = '313311111'; - $chr['4'] = '111331113'; - $chr['5'] = '311331111'; - $chr['6'] = '113331111'; - $chr['7'] = '111311313'; - $chr['8'] = '311311311'; - $chr['9'] = '113311311'; - $chr['A'] = '311113113'; - $chr['B'] = '113113113'; - $chr['C'] = '313113111'; - $chr['D'] = '111133113'; - $chr['E'] = '311133111'; - $chr['F'] = '113133111'; - $chr['G'] = '111113313'; - $chr['H'] = '311113311'; - $chr['I'] = '113113311'; - $chr['J'] = '111133311'; - $chr['K'] = '311111133'; - $chr['L'] = '113111133'; - $chr['M'] = '313111131'; - $chr['N'] = '111131133'; - $chr['O'] = '311131131'; - $chr['P'] = '113131131'; - $chr['Q'] = '111111333'; - $chr['R'] = '311111331'; - $chr['S'] = '113111331'; - $chr['T'] = '111131331'; - $chr['U'] = '331111113'; - $chr['V'] = '133111113'; - $chr['W'] = '333111111'; - $chr['X'] = '131131113'; - $chr['Y'] = '331131111'; - $chr['Z'] = '133131111'; - $chr['-'] = '131111313'; - $chr['.'] = '331111311'; - $chr[' '] = '133111311'; - $chr['$'] = '131313111'; - $chr['/'] = '131311131'; - $chr['+'] = '131113131'; - $chr['%'] = '111313131'; - $chr['*'] = '131131311'; - $code = strtoupper($code); - if ($extended) { - // extended mode - $code = $this->encode_code39_ext($code); - } - if ($code === false) { - return false; - } - if ($checksum) { - // checksum - $code .= $this->checksum_code39($code); - } - // add start and stop codes - $code = '*'.$code.'*'; - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - $k = 0; - $clen = strlen($code); - for ($i = 0; $i < $clen; ++$i) { - $char = $code{$i}; - if (!isset($chr[$char])) { - // invalid character - return false; - } - for ($j = 0; $j < 9; ++$j) { - if (($j % 2) == 0) { - $t = true; // bar - } else { - $t = false; // space - } - $w = $chr[$char]{$j}; - $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); - $bararray['maxw'] += $w; - ++$k; - } - // intercharacter gap - $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0); - $bararray['maxw'] += 1; - ++$k; - } - - return $bararray; - } - - /** - * Encode a string to be used for CODE 39 Extended mode. - * - * @param string $code - * - * @return bool|string - */ - protected function encode_code39_ext($code) - { - $encode = array( - chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C', - chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G', - chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K', - chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O', - chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S', - chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W', - chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A', - chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E', - chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C', - chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G', - chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K', - chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O', - chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', - chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', - chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F', - chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J', - chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', - chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', - chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', - chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', - chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', - chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', - chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K', - chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O', - chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C', - chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G', - chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K', - chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O', - chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S', - chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W', - chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P', - chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T'); - $codeExt = ''; - $clen = strlen($code); - for ($i = 0; $i < $clen; ++$i) { - if (ord($code{$i}) > 127) { - return false; - } - $codeExt .= $encode[$code{$i}]; - } - - return $codeExt; - } - - /** - * Calculate CODE 39 checksum (modulo 43). - * - * @param string $code - * - * @return mixed - */ - protected function checksum_code39($code) - { - $chars = array( - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'); - $sum = 0; - $clen = strlen($code); - for ($i = 0; $i < $clen; ++$i) { - $k = array_keys($chars, $code{$i}); - $sum += $k[0]; - } - $j = ($sum % 43); - - return $chars[$j]; - } - - /** - * CODE 93 - USS-93 - * - * @param string $code - * - * @return array|bool - */ - protected function barcode_code93($code) - { - $chr[48] = '131112'; // 0 - $chr[49] = '111213'; // 1 - $chr[50] = '111312'; // 2 - $chr[51] = '111411'; // 3 - $chr[52] = '121113'; // 4 - $chr[53] = '121212'; // 5 - $chr[54] = '121311'; // 6 - $chr[55] = '111114'; // 7 - $chr[56] = '131211'; // 8 - $chr[57] = '141111'; // 9 - $chr[65] = '211113'; // A - $chr[66] = '211212'; // B - $chr[67] = '211311'; // C - $chr[68] = '221112'; // D - $chr[69] = '221211'; // E - $chr[70] = '231111'; // F - $chr[71] = '112113'; // G - $chr[72] = '112212'; // H - $chr[73] = '112311'; // I - $chr[74] = '122112'; // J - $chr[75] = '132111'; // K - $chr[76] = '111123'; // L - $chr[77] = '111222'; // M - $chr[78] = '111321'; // N - $chr[79] = '121122'; // O - $chr[80] = '131121'; // P - $chr[81] = '212112'; // Q - $chr[82] = '212211'; // R - $chr[83] = '211122'; // S - $chr[84] = '211221'; // T - $chr[85] = '221121'; // U - $chr[86] = '222111'; // V - $chr[87] = '112122'; // W - $chr[88] = '112221'; // X - $chr[89] = '122121'; // Y - $chr[90] = '123111'; // Z - $chr[45] = '121131'; // - - $chr[46] = '311112'; // . - $chr[32] = '311211'; // - $chr[36] = '321111'; // $ - $chr[47] = '112131'; // / - $chr[43] = '113121'; // + - $chr[37] = '211131'; // % - $chr[128] = '121221'; // ($) - $chr[129] = '311121'; // (/) - $chr[130] = '122211'; // (+) - $chr[131] = '312111'; // (%) - $chr[42] = '111141'; // start-stop - $code = strtoupper($code); - $encode = array( - chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C', - chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G', - chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K', - chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O', - chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S', - chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W', - chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A', - chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E', - chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C', - chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G', - chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K', - chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O', - chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', - chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', - chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F', - chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J', - chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', - chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', - chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', - chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', - chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', - chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', - chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K', - chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O', - chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C', - chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G', - chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K', - chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O', - chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S', - chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W', - chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P', - chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T'); - - $codeExt = ''; - $clen = strlen($code); - - for ($i = 0; $i < $clen; ++$i) { - if (ord($code{$i}) > 127) { - return false; - } - $codeExt .= $encode[$code{$i}]; - } - - // checksum - $codeExt .= $this->checksum_code93($codeExt); - // add start and stop codes - $code = '*'.$codeExt.'*'; - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - $k = 0; - $clen = strlen($code); - for ($i = 0; $i < $clen; ++$i) { - $char = ord($code{$i}); - if (!isset($chr[$char])) { - // invalid character - return false; - } - for ($j = 0; $j < 6; ++$j) { - if (($j % 2) == 0) { - $t = true; // bar - } else { - $t = false; // space - } - $w = $chr[$char]{$j}; - $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); - $bararray['maxw'] += $w; - ++$k; - } - } - $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0); - $bararray['maxw'] += 1; - ++$k; - - return $bararray; - } - - /** - * Calculate CODE 93 checksum (modulo 47). - * - * @param string $code - * - * @return string - */ - protected function checksum_code93($code) - { - $chars = array( - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', - 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', - '<', '=', '>', '?'); - // translate special characters - $code = strtr($code, chr(128).chr(131).chr(129).chr(130), '<=>?'); - $len = strlen($code); - // calculate check digit C - $p = 1; - $check = 0; - for ($i = ($len - 1); $i >= 0; --$i) { - $k = array_keys($chars, $code{$i}); - $check += ($k[0] * $p); - ++$p; - if ($p > 20) { - $p = 1; - } - } - $check %= 47; - $c = $chars[$check]; - $code .= $c; - // calculate check digit K - $p = 1; - $check = 0; - for ($i = $len; $i >= 0; --$i) { - $k = array_keys($chars, $code{$i}); - $check += ($k[0] * $p); - ++$p; - if ($p > 15) { - $p = 1; - } - } - $check %= 47; - $k = $chars[$check]; - $checksum = $c.$k; - // resto respecial characters - $checksum = strtr($checksum, '<=>?', chr(128).chr(131).chr(129).chr(130)); - - return $checksum; - } - - /** - * Checksum for standard 2 of 5 barcodes. - * - * @param string $code - * - * @return int - */ - protected function checksum_s25($code) - { - $len = strlen($code); - $sum = 0; - for ($i = 0; $i < $len; $i+=2) { - $sum += $code{$i}; - } - $sum *= 3; - for ($i = 1; $i < $len; $i+=2) { - $sum += ($code{$i}); - } - $r = $sum % 10; - if ($r > 0) { - $r = (10 - $r); - } - - return $r; - } - - /** - * MSI - Variation of Plessey code, with similar applications - * Contains digits (0 to 9) and encodes the data only in the width of bars. - * - * @param string $code - * @param bool $checksum - * - * @return array|bool - */ - protected function barcode_msi($code, $checksum=false) - { - $chr['0'] = '100100100100'; - $chr['1'] = '100100100110'; - $chr['2'] = '100100110100'; - $chr['3'] = '100100110110'; - $chr['4'] = '100110100100'; - $chr['5'] = '100110100110'; - $chr['6'] = '100110110100'; - $chr['7'] = '100110110110'; - $chr['8'] = '110100100100'; - $chr['9'] = '110100100110'; - $chr['A'] = '110100110100'; - $chr['B'] = '110100110110'; - $chr['C'] = '110110100100'; - $chr['D'] = '110110100110'; - $chr['E'] = '110110110100'; - $chr['F'] = '110110110110'; - if ($checksum) { - // add checksum - $clen = strlen($code); - $p = 2; - $check = 0; - for ($i = ($clen - 1); $i >= 0; --$i) { - $check += (hexdec($code{$i}) * $p); - ++$p; - if ($p > 7) { - $p = 2; - } - } - $check %= 11; - if ($check > 0) { - $check = 11 - $check; - } - $code .= $check; - } - $seq = '110'; // left guard - $clen = strlen($code); - for ($i = 0; $i < $clen; ++$i) { - $digit = $code{$i}; - if (!isset($chr[$digit])) { - // invalid character - return false; - } - $seq .= $chr[$digit]; - } - $seq .= '1001'; // right guard - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - - return $this->binseq_to_array($seq, $bararray); - } - - /** - * Standard 2 of 5 barcodes. - * Used in airline ticket marking, photofinishing - * Contains digits (0 to 9) and encodes the data only in the width of bars. - * - * @param string $code - * @param bool $checksum - * - * @return array|bool - */ - protected function barcode_s25($code, $checksum=false) - { - $chr['0'] = '10101110111010'; - $chr['1'] = '11101010101110'; - $chr['2'] = '10111010101110'; - $chr['3'] = '11101110101010'; - $chr['4'] = '10101110101110'; - $chr['5'] = '11101011101010'; - $chr['6'] = '10111011101010'; - $chr['7'] = '10101011101110'; - $chr['8'] = '10101110111010'; - $chr['9'] = '10111010111010'; - if ($checksum) { - // add checksum - $code .= $this->checksum_s25($code); - } - if ((strlen($code) % 2) != 0) { - // add leading zero if code-length is odd - $code = '0'.$code; - } - $seq = '11011010'; - $clen = strlen($code); - for ($i = 0; $i < $clen; ++$i) { - $digit = $code{$i}; - if (!isset($chr[$digit])) { - // invalid character - return false; - } - $seq .= $chr[$digit]; - } - $seq .= '1101011'; - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - - return $this->binseq_to_array($seq, $bararray); - } - - /** - * Convert binary barcode sequence to DNS1DBarcode barcode array. - * - * @param string $seq - * @param array $bararray - * - * @return mixed - */ - protected function binseq_to_array($seq, $bararray) - { - $len = strlen($seq); - $w = 0; - $k = 0; - for ($i = 0; $i < $len; ++$i) { - $w += 1; - if (($i == ($len - 1)) || (($i < ($len - 1)) && ($seq{$i} != $seq{($i+1)}))) { - if ($seq{$i} == '1') { - $t = true; // bar - } else { - $t = false; // space - } - $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); - $bararray['maxw'] += $w; - ++$k; - $w = 0; - } - } - - return $bararray; - } - - /** - * Interleaved 2 of 5 barcodes. - * Compact numeric code, widely used in industry, air cargo - * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces. - * - * @param string $code - * @param bool $checksum - * - * @return array|bool - */ - protected function barcode_i25($code, $checksum=false) - { - $chr['0'] = '11221'; - $chr['1'] = '21112'; - $chr['2'] = '12112'; - $chr['3'] = '22111'; - $chr['4'] = '11212'; - $chr['5'] = '21211'; - $chr['6'] = '12211'; - $chr['7'] = '11122'; - $chr['8'] = '21121'; - $chr['9'] = '12121'; - $chr['A'] = '11'; - $chr['Z'] = '21'; - if ($checksum) { - // add checksum - $code .= $this->checksum_s25($code); - } - if ((strlen($code) % 2) != 0) { - // add leading zero if code-length is odd - $code = '0'.$code; - } - // add start and stop codes - $code = 'AA'.strtolower($code).'ZA'; - - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - $k = 0; - $clen = strlen($code); - for ($i = 0; $i < $clen; $i = ($i + 2)) { - $charBar = $code{$i}; - $charSpace = $code{$i+1}; - if ((!isset($chr[$charBar])) || (!isset($chr[$charSpace]))) { - // invalid character - return false; - } - // create a bar-space sequence - $seq = ''; - $chrlen = strlen($chr[$charBar]); - for ($s = 0; $s < $chrlen; $s++) { - $seq .= $chr[$charBar]{$s} . $chr[$charSpace]{$s}; - } - $seqlen = strlen($seq); - for ($j = 0; $j < $seqlen; ++$j) { - if (($j % 2) == 0) { - $t = true; // bar - } else { - $t = false; // space - } - $w = $seq{$j}; - $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); - $bararray['maxw'] += $w; - ++$k; - } - } - - return $bararray; - } - - /** - * C128 barcodes - very capable code, excellent density, high reliability; in very wide use world-wide - * - * @param string $code - * @param string $type - * - * @return array|bool - */ - protected function barcode_c128($code, $type='') - { - $chr = array( - '212222', /* 00 */ - '222122', /* 01 */ - '222221', /* 02 */ - '121223', /* 03 */ - '121322', /* 04 */ - '131222', /* 05 */ - '122213', /* 06 */ - '122312', /* 07 */ - '132212', /* 08 */ - '221213', /* 09 */ - '221312', /* 10 */ - '231212', /* 11 */ - '112232', /* 12 */ - '122132', /* 13 */ - '122231', /* 14 */ - '113222', /* 15 */ - '123122', /* 16 */ - '123221', /* 17 */ - '223211', /* 18 */ - '221132', /* 19 */ - '221231', /* 20 */ - '213212', /* 21 */ - '223112', /* 22 */ - '312131', /* 23 */ - '311222', /* 24 */ - '321122', /* 25 */ - '321221', /* 26 */ - '312212', /* 27 */ - '322112', /* 28 */ - '322211', /* 29 */ - '212123', /* 30 */ - '212321', /* 31 */ - '232121', /* 32 */ - '111323', /* 33 */ - '131123', /* 34 */ - '131321', /* 35 */ - '112313', /* 36 */ - '132113', /* 37 */ - '132311', /* 38 */ - '211313', /* 39 */ - '231113', /* 40 */ - '231311', /* 41 */ - '112133', /* 42 */ - '112331', /* 43 */ - '132131', /* 44 */ - '113123', /* 45 */ - '113321', /* 46 */ - '133121', /* 47 */ - '313121', /* 48 */ - '211331', /* 49 */ - '231131', /* 50 */ - '213113', /* 51 */ - '213311', /* 52 */ - '213131', /* 53 */ - '311123', /* 54 */ - '311321', /* 55 */ - '331121', /* 56 */ - '312113', /* 57 */ - '312311', /* 58 */ - '332111', /* 59 */ - '314111', /* 60 */ - '221411', /* 61 */ - '431111', /* 62 */ - '111224', /* 63 */ - '111422', /* 64 */ - '121124', /* 65 */ - '121421', /* 66 */ - '141122', /* 67 */ - '141221', /* 68 */ - '112214', /* 69 */ - '112412', /* 70 */ - '122114', /* 71 */ - '122411', /* 72 */ - '142112', /* 73 */ - '142211', /* 74 */ - '241211', /* 75 */ - '221114', /* 76 */ - '413111', /* 77 */ - '241112', /* 78 */ - '134111', /* 79 */ - '111242', /* 80 */ - '121142', /* 81 */ - '121241', /* 82 */ - '114212', /* 83 */ - '124112', /* 84 */ - '124211', /* 85 */ - '411212', /* 86 */ - '421112', /* 87 */ - '421211', /* 88 */ - '212141', /* 89 */ - '214121', /* 90 */ - '412121', /* 91 */ - '111143', /* 92 */ - '111341', /* 93 */ - '131141', /* 94 */ - '114113', /* 95 */ - '114311', /* 96 */ - '411113', /* 97 */ - '411311', /* 98 */ - '113141', /* 99 */ - '114131', /* 100 */ - '311141', /* 101 */ - '411131', /* 102 */ - '211412', /* 103 START A */ - '211214', /* 104 START B */ - '211232', /* 105 START C */ - '233111', /* STOP */ - '200000' /* END */ - ); - // ASCII characters for code A (ASCII 00 - 95) - $keysA = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; - $keysA .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9); - $keysA .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19); - $keysA .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29); - $keysA .= chr(30).chr(31); - // ASCII characters for code B (ASCII 32 - 127) - $keysB = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127); - // special codes - $fncA = array(241 => 102, 242 => 97, 243 => 96, 244 => 101); - $fncB = array(241 => 102, 242 => 97, 243 => 96, 244 => 100); - // array of symbols - $codeData = array(); - // lenght of the code - $len = strlen($code); - $startid = 0; - - switch(strtoupper(trim($type))) { - case 'A': // MODE A - $startid = 103; - for ($i = 0; $i < $len; ++$i) { - $char = $code{$i}; - $charId = ord($char); - if (($charId >= 241) && ($charId <= 244)) { - $codeData[] = $fncA[$charId]; - } elseif (($charId >= 0) && ($charId <= 95)) { - $codeData[] = strpos($keysA, $char); - } else { - return false; - } - } - break; - - case 'B': // MODE B - $startid = 104; - for ($i = 0; $i < $len; ++$i) { - $char = $code{$i}; - $charId = ord($char); - if (($charId >= 241) && ($charId <= 244)) { - $codeData[] = $fncB[$charId]; - } elseif (($charId >= 32) && ($charId <= 127)) { - $codeData[] = strpos($keysB, $char); - } else { - return false; - } - } - break; - - case 'C': // MODE C - $startid = 105; - if (ord($code{0}) == 241) { - $codeData[] = 102; - $code = substr($code, 1); - --$len; - } - if (($len % 2) != 0) { - // the length must be even - return false; - } - for ($i = 0; $i < $len; $i+=2) { - $chrnum = $code{$i}.$code{$i+1}; - if (preg_match('/([0-9]{2})/', $chrnum) > 0) { - $codeData[] = intval($chrnum); - } else { - return false; - } - } - break; - - default: // MODE AUTO - // split code into sequences - $sequence = array(); - // get numeric sequences (if any) - $numseq = array(); - preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE); - if (isset($numseq[1]) && !empty($numseq[1])) { - $endOffset = 0; - foreach ($numseq[1] as $val) { - $offset = $val[1]; - if ($offset > $endOffset) { - // non numeric sequence - $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $endOffset, ($offset - $endOffset)))); - } - // numeric sequence - $slen = strlen($val[0]); - if (($slen % 2) != 0) { - // the length must be even - --$slen; - } - $sequence[] = array('C', substr($code, $offset, $slen), $slen); - $endOffset = $offset + $slen; - } - if ($endOffset < $len) { - $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $endOffset))); - } - } else { - // text code (non C mode) - $sequence = array_merge($sequence, $this->get128ABsequence($code)); - } - // process the sequence - foreach ($sequence as $key => $seq) { - switch($seq[0]) { - case 'A': - if ($key == 0) { - $startid = 103; - } elseif ($sequence[($key - 1)][0] != 'A') { - if (($seq[2] == 1) && ($key > 0) && ($sequence[($key - 1)][0] == 'B') && (!isset($sequence[($key - 1)][3]))) { - // single character shift - $codeData[] = 98; - // mark shift - $sequence[$key][3] = true; - } elseif (!isset($sequence[($key - 1)][3])) { - $codeData[] = 101; - } - } - for ($i = 0; $i < $seq[2]; ++$i) { - $char = $seq[1]{$i}; - $charId = ord($char); - if (($charId >= 241) && ($charId <= 244)) { - $codeData[] = $fncA[$charId]; - } else { - $codeData[] = strpos($keysA, $char); - } - } - break; - - case 'B': - if ($key == 0) { - $tmpchr = ord($seq[1]{0}); - if (($seq[2] == 1) && ($tmpchr >= 241) && ($tmpchr <= 244) && isset($sequence[($key + 1)]) && ($sequence[($key + 1)][0] != 'B')) { - switch ($sequence[($key + 1)][0]) { - case 'A': - $startid = 103; - $sequence[$key][0] = 'A'; - $codeData[] = $fncA[$tmpchr]; - break; - - case 'C': - $startid = 105; - $sequence[$key][0] = 'C'; - $codeData[] = $fncA[$tmpchr]; - break; - - } - break; - } else { - $startid = 104; - } - } elseif ($sequence[($key - 1)][0] != 'B') { - if (($seq[2] == 1) && ($key > 0) && ($sequence[($key - 1)][0] == 'A') && (!isset($sequence[($key - 1)][3]))) { - // single character shift - $codeData[] = 98; - // mark shift - $sequence[$key][3] = true; - } elseif (!isset($sequence[($key - 1)][3])) { - $codeData[] = 100; - } - } - for ($i = 0; $i < $seq[2]; ++$i) { - $char = $seq[1]{$i}; - $charId = ord($char); - if (($charId >= 241) && ($charId <= 244)) { - $codeData[] = $fncB[$charId]; - } else { - $codeData[] = strpos($keysB, $char); - } - } - break; - - case 'C': - if ($key == 0) { - $startid = 105; - } elseif ($sequence[($key - 1)][0] != 'C') { - $codeData[] = 99; - } - for ($i = 0; $i < $seq[2]; $i+=2) { - $chrnum = $seq[1]{$i}.$seq[1]{$i+1}; - $codeData[] = intval($chrnum); - } - break; - } - } - } - // calculate check character - $sum = $startid; - foreach ($codeData as $key => $val) { - $sum += ($val * ($key + 1)); - } - // add check character - $codeData[] = ($sum % 103); - // add stop sequence - $codeData[] = 106; - $codeData[] = 107; - // add start code at the beginning - array_unshift($codeData, $startid); - // build barcode array - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - foreach ($codeData as $val) { - $seq = $chr[$val]; - for ($j = 0; $j < 6; ++$j) { - if (($j % 2) == 0) { - $t = true; // bar - } else { - $t = false; // space - } - $w = $seq{$j}; - $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); - $bararray['maxw'] += $w; - } - } - - return $bararray; - } - - /** - * Split text code in A/B sequence for 128 code - * - * @param string $code - * - * @return array - */ - protected function get128ABsequence($code) - { - $len = strlen($code); - $sequence = array(); - // get A sequences (if any) - $numseq = array(); - preg_match_all('/([\0-\31])/', $code, $numseq, PREG_OFFSET_CAPTURE); - if (isset($numseq[1]) && !empty($numseq[1])) { - $endOffset = 0; - foreach ($numseq[1] as $val) { - $offset = $val[1]; - if ($offset > $endOffset) { - // B sequence - $sequence[] = array('B', substr($code, $endOffset, ($offset - $endOffset)), ($offset - $endOffset)); - } - // A sequence - $slen = strlen($val[0]); - $sequence[] = array('A', substr($code, $offset, $slen), $slen); - $endOffset = $offset + $slen; - } - if ($endOffset < $len) { - $sequence[] = array('B', substr($code, $endOffset), ($len - $endOffset)); - } - } else { - // only B sequence - $sequence[] = array('B', $code, $len); - } - - return $sequence; - } - - /** - * EAN13 and UPC-A barcodes. - * EAN13: European Article Numbering international retail product code - * UPC-A: Universal product code seen on almost all retail products in the USA and Canada - * UPC-E: Short version of UPC symbol - * - * @param string $code - * @param int $len - * - * @return array|bool - */ - protected function barcode_eanupc($code, $len=13) - { - $upce = false; - $upceCode = null; - - if ($len == 6) { - $len = 12; // UPC-A - $upce = true; // UPC-E mode - } - $dataLen = $len - 1; - //Padding - $code = str_pad($code, $dataLen, '0', STR_PAD_LEFT); - $codeLen = strlen($code); - // calculate check digit - $sumA = 0; - for ($i = 1; $i < $dataLen; $i+=2) { - $sumA += $code{$i}; - } - if ($len > 12) { - $sumA *= 3; - } - $sumB = 0; - for ($i = 0; $i < $dataLen; $i+=2) { - $sumB += ($code{$i}); - } - if ($len < 13) { - $sumB *= 3; - } - $r = ($sumA + $sumB) % 10; - if ($r > 0) { - $r = (10 - $r); - } - if ($codeLen == $dataLen) { - // add check digit - $code .= $r; - } elseif ($r !== intval($code{$dataLen})) { - // wrong checkdigit - return false; - } - if ($len == 12) { - // UPC-A - $code = '0'.$code; - ++$len; - } - if ($upce) { - // convert UPC-A to UPC-E - $tmp = substr($code, 4, 3); - if (($tmp == '000') || ($tmp == '100') || ($tmp == '200')) { - // manufacturer code ends in 000, 100, or 200 - $upceCode = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1); - } else { - $tmp = substr($code, 5, 2); - if ($tmp == '00') { - // manufacturer code ends in 00 - $upceCode = substr($code, 2, 3).substr($code, 10, 2).'3'; - } else { - $tmp = substr($code, 6, 1); - if ($tmp == '0') { - // manufacturer code ends in 0 - $upceCode = substr($code, 2, 4).substr($code, 11, 1).'4'; - } else { - // manufacturer code does not end in zero - $upceCode = substr($code, 2, 5).substr($code, 11, 1); - } - } - } - } - //Convert digits to bars - $codes = array( - 'A'=>array( // left odd parity - '0'=>'0001101', - '1'=>'0011001', - '2'=>'0010011', - '3'=>'0111101', - '4'=>'0100011', - '5'=>'0110001', - '6'=>'0101111', - '7'=>'0111011', - '8'=>'0110111', - '9'=>'0001011'), - 'B'=>array( // left even parity - '0'=>'0100111', - '1'=>'0110011', - '2'=>'0011011', - '3'=>'0100001', - '4'=>'0011101', - '5'=>'0111001', - '6'=>'0000101', - '7'=>'0010001', - '8'=>'0001001', - '9'=>'0010111'), - 'C'=>array( // right - '0'=>'1110010', - '1'=>'1100110', - '2'=>'1101100', - '3'=>'1000010', - '4'=>'1011100', - '5'=>'1001110', - '6'=>'1010000', - '7'=>'1000100', - '8'=>'1001000', - '9'=>'1110100') - ); - $parities = array( - '0'=>array('A','A','A','A','A','A'), - '1'=>array('A','A','B','A','B','B'), - '2'=>array('A','A','B','B','A','B'), - '3'=>array('A','A','B','B','B','A'), - '4'=>array('A','B','A','A','B','B'), - '5'=>array('A','B','B','A','A','B'), - '6'=>array('A','B','B','B','A','A'), - '7'=>array('A','B','A','B','A','B'), - '8'=>array('A','B','A','B','B','A'), - '9'=>array('A','B','B','A','B','A') - ); - $upceParities = array(); - $upceParities[0] = array( - '0'=>array('B','B','B','A','A','A'), - '1'=>array('B','B','A','B','A','A'), - '2'=>array('B','B','A','A','B','A'), - '3'=>array('B','B','A','A','A','B'), - '4'=>array('B','A','B','B','A','A'), - '5'=>array('B','A','A','B','B','A'), - '6'=>array('B','A','A','A','B','B'), - '7'=>array('B','A','B','A','B','A'), - '8'=>array('B','A','B','A','A','B'), - '9'=>array('B','A','A','B','A','B') - ); - $upceParities[1] = array( - '0'=>array('A','A','A','B','B','B'), - '1'=>array('A','A','B','A','B','B'), - '2'=>array('A','A','B','B','A','B'), - '3'=>array('A','A','B','B','B','A'), - '4'=>array('A','B','A','A','B','B'), - '5'=>array('A','B','B','A','A','B'), - '6'=>array('A','B','B','B','A','A'), - '7'=>array('A','B','A','B','A','B'), - '8'=>array('A','B','A','B','B','A'), - '9'=>array('A','B','B','A','B','A') - ); - $k = 0; - $seq = '101'; // left guard bar - if ($upce) { - $bararray = array('code' => $upceCode, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - $p = $upceParities[$code{1}][$r]; - for ($i = 0; $i < 6; ++$i) { - $seq .= $codes[$p[$i]][$upceCode{$i}]; - } - $seq .= '010101'; // right guard bar - } else { - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - $halfLen = ceil($len / 2); - if ($len == 8) { - for ($i = 0; $i < $halfLen; ++$i) { - $seq .= $codes['A'][$code{$i}]; - } - } else { - $p = $parities[$code{0}]; - for ($i = 1; $i < $halfLen; ++$i) { - $seq .= $codes[$p[$i-1]][$code{$i}]; - } - } - $seq .= '01010'; // center guard bar - for ($i = $halfLen; $i < $len; ++$i) { - $seq .= $codes['C'][$code{intval($i)}]; - } - $seq .= '101'; // right guard bar - } - $clen = strlen($seq); - $w = 0; - for ($i = 0; $i < $clen; ++$i) { - $w += 1; - if (($i == ($clen - 1)) || (($i < ($clen - 1)) && ($seq{$i} != $seq{($i+1)}))) { - if ($seq{$i} == '1') { - $t = true; // bar - } else { - $t = false; // space - } - $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); - $bararray['maxw'] += $w; - ++$k; - $w = 0; - } - } - - return $bararray; - } - - /** - * UPC-Based Extentions - * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers - * 5-Digit Ext.: Used to mark suggested retail price of books - * - * @param string $code - * @param int $len - * - * @return bool|mixed - */ - protected function barcode_eanext($code, $len=5) - { - //Padding - $code = str_pad($code, $len, '0', STR_PAD_LEFT); - // calculate check digit - if ($len == 2) { - $r = $code % 4; - } elseif ($len == 5) { - $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3})); - $r %= 10; - } else { - return false; - } - //Convert digits to bars - $codes = array( - 'A'=>array( // left odd parity - '0'=>'0001101', - '1'=>'0011001', - '2'=>'0010011', - '3'=>'0111101', - '4'=>'0100011', - '5'=>'0110001', - '6'=>'0101111', - '7'=>'0111011', - '8'=>'0110111', - '9'=>'0001011'), - 'B'=>array( // left even parity - '0'=>'0100111', - '1'=>'0110011', - '2'=>'0011011', - '3'=>'0100001', - '4'=>'0011101', - '5'=>'0111001', - '6'=>'0000101', - '7'=>'0010001', - '8'=>'0001001', - '9'=>'0010111') - ); - $parities = array(); - $parities[2] = array( - '0'=>array('A','A'), - '1'=>array('A','B'), - '2'=>array('B','A'), - '3'=>array('B','B') - ); - $parities[5] = array( - '0'=>array('B','B','A','A','A'), - '1'=>array('B','A','B','A','A'), - '2'=>array('B','A','A','B','A'), - '3'=>array('B','A','A','A','B'), - '4'=>array('A','B','B','A','A'), - '5'=>array('A','A','B','B','A'), - '6'=>array('A','A','A','B','B'), - '7'=>array('A','B','A','B','A'), - '8'=>array('A','B','A','A','B'), - '9'=>array('A','A','B','A','B') - ); - $p = $parities[$len][$r]; - $seq = '1011'; // left guard bar - $seq .= $codes[$p[0]][$code{0}]; - for ($i = 1; $i < $len; ++$i) { - $seq .= '01'; // separator - $seq .= $codes[$p[$i]][$code{$i}]; - } - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - - return $this->binseq_to_array($seq, $bararray); - } - - /** - * POSTNET and PLANET barcodes. - * Used by U.S. Postal Service for automated mail sorting - * - * @param string $code - * @param bool $planet - * - * @return array - */ - protected function barcode_postnet($code, $planet=false) - { - // bar length - if ($planet) { - $barlen = Array( - 0 => Array(1,1,2,2,2), - 1 => Array(2,2,2,1,1), - 2 => Array(2,2,1,2,1), - 3 => Array(2,2,1,1,2), - 4 => Array(2,1,2,2,1), - 5 => Array(2,1,2,1,2), - 6 => Array(2,1,1,2,2), - 7 => Array(1,2,2,2,1), - 8 => Array(1,2,2,1,2), - 9 => Array(1,2,1,2,2) - ); - } else { - $barlen = Array( - 0 => Array(2,2,1,1,1), - 1 => Array(1,1,1,2,2), - 2 => Array(1,1,2,1,2), - 3 => Array(1,1,2,2,1), - 4 => Array(1,2,1,1,2), - 5 => Array(1,2,1,2,1), - 6 => Array(1,2,2,1,1), - 7 => Array(2,1,1,1,2), - 8 => Array(2,1,1,2,1), - 9 => Array(2,1,2,1,1) - ); - } - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array()); - $k = 0; - $code = str_replace('-', '', $code); - $code = str_replace(' ', '', $code); - $len = strlen($code); - // calculate checksum - $sum = 0; - for ($i = 0; $i < $len; ++$i) { - $sum += intval($code{$i}); - } - $chkd = ($sum % 10); - if ($chkd > 0) { - $chkd = (10 - $chkd); - } - $code .= $chkd; - $len = strlen($code); - // start bar - $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['maxw'] += 2; - for ($i = 0; $i < $len; ++$i) { - for ($j = 0; $j < 5; ++$j) { - $h = $barlen[$code{$i}][$j]; - $p = floor(1 / $h); - $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); - $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['maxw'] += 2; - } - } - // end bar - $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['maxw'] += 1; - - return $bararray; - } - - /** - * RMS4CC - CBC - KIX - * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index) - * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service. - * - * @param string $code - * @param bool $kix - * - * @return array - */ - protected function barcode_rms4cc($code, $kix=false) - { - $notkix = !$kix; - // bar mode - // 1 = pos 1, length 2 - // 2 = pos 1, length 3 - // 3 = pos 2, length 1 - // 4 = pos 2, length 2 - $barmode = array( - '0' => array(3,3,2,2), - '1' => array(3,4,1,2), - '2' => array(3,4,2,1), - '3' => array(4,3,1,2), - '4' => array(4,3,2,1), - '5' => array(4,4,1,1), - '6' => array(3,1,4,2), - '7' => array(3,2,3,2), - '8' => array(3,2,4,1), - '9' => array(4,1,3,2), - 'A' => array(4,1,4,1), - 'B' => array(4,2,3,1), - 'C' => array(3,1,2,4), - 'D' => array(3,2,1,4), - 'E' => array(3,2,2,3), - 'F' => array(4,1,1,4), - 'G' => array(4,1,2,3), - 'H' => array(4,2,1,3), - 'I' => array(1,3,4,2), - 'J' => array(1,4,3,2), - 'K' => array(1,4,4,1), - 'L' => array(2,3,3,2), - 'M' => array(2,3,4,1), - 'N' => array(2,4,3,1), - 'O' => array(1,3,2,4), - 'P' => array(1,4,1,4), - 'Q' => array(1,4,2,3), - 'R' => array(2,3,1,4), - 'S' => array(2,3,2,3), - 'T' => array(2,4,1,3), - 'U' => array(1,1,4,4), - 'V' => array(1,2,3,4), - 'W' => array(1,2,4,3), - 'X' => array(2,1,3,4), - 'Y' => array(2,1,4,3), - 'Z' => array(2,2,3,3) - ); - $code = strtoupper($code); - $len = strlen($code); - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); - if ($notkix) { - // table for checksum calculation (row,col) - $checktable = array( - '0' => array(1,1), - '1' => array(1,2), - '2' => array(1,3), - '3' => array(1,4), - '4' => array(1,5), - '5' => array(1,0), - '6' => array(2,1), - '7' => array(2,2), - '8' => array(2,3), - '9' => array(2,4), - 'A' => array(2,5), - 'B' => array(2,0), - 'C' => array(3,1), - 'D' => array(3,2), - 'E' => array(3,3), - 'F' => array(3,4), - 'G' => array(3,5), - 'H' => array(3,0), - 'I' => array(4,1), - 'J' => array(4,2), - 'K' => array(4,3), - 'L' => array(4,4), - 'M' => array(4,5), - 'N' => array(4,0), - 'O' => array(5,1), - 'P' => array(5,2), - 'Q' => array(5,3), - 'R' => array(5,4), - 'S' => array(5,5), - 'T' => array(5,0), - 'U' => array(0,1), - 'V' => array(0,2), - 'W' => array(0,3), - 'X' => array(0,4), - 'Y' => array(0,5), - 'Z' => array(0,0) - ); - $row = 0; - $col = 0; - for ($i = 0; $i < $len; ++$i) { - $row += $checktable[$code{$i}][0]; - $col += $checktable[$code{$i}][1]; - } - $row %= 6; - $col %= 6; - $chk = array_keys($checktable, array($row,$col)); - $code .= $chk[0]; - ++$len; - } - $k = 0; - if ($notkix) { - // start bar - $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['maxw'] += 2; - } - for ($i = 0; $i < $len; ++$i) { - for ($j = 0; $j < 4; ++$j) { - switch ($barmode[$code{$i}][$j]) { - case 1: - $p = 0; - $h = 2; - break; - - case 2: - $p = 0; - $h = 3; - break; - - case 3: - $p = 1; - $h = 1; - break; - - case 4: - $p = 1; - $h = 2; - break; - } - $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); - $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['maxw'] += 2; - } - } - if ($notkix) { - // stop bar - $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0); - $bararray['maxw'] += 1; - } - - return $bararray; - } - - /** - * CODABAR barcodes. - * Older code often used in library systems, sometimes in blood banks - * - * @param string $code - * - * @return array|bool - */ - protected function barcode_codabar($code) - { - $chr = array( - '0' => '11111221', - '1' => '11112211', - '2' => '11121121', - '3' => '22111111', - '4' => '11211211', - '5' => '21111211', - '6' => '12111121', - '7' => '12112111', - '8' => '12211111', - '9' => '21121111', - '-' => '11122111', - '$' => '11221111', - ':' => '21112121', - '/' => '21211121', - '.' => '21212111', - '+' => '11222221', - 'A' => '11221211', - 'B' => '12121121', - 'C' => '11121221', - 'D' => '11122211' - ); - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - $k = 0; - // $w = 0; - $seq = null; - $code = 'A'.strtoupper($code).'A'; - $len = strlen($code); - for ($i = 0; $i < $len; ++$i) { - if (!isset($chr[$code{$i}])) { - return false; - } - $seq = $chr[$code{$i}]; - for ($j = 0; $j < 8; ++$j) { - if (($j % 2) == 0) { - $t = true; // bar - } else { - $t = false; // space - } - $w = $seq{$j}; - $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); - $bararray['maxw'] += $w; - ++$k; - } - } - - return $bararray; - } - - /** - * CODE11 barcodes. - * Used primarily for labeling telecommunications equipment - * - * @param string $code - * - * @return array|bool - */ - protected function barcode_code11($code) - { - $chr = array( - '0' => '111121', - '1' => '211121', - '2' => '121121', - '3' => '221111', - '4' => '112121', - '5' => '212111', - '6' => '122111', - '7' => '111221', - '8' => '211211', - '9' => '211111', - '-' => '112111', - 'S' => '112211' - ); - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - $k = 0; - // $w = 0; - $seq = null; - $len = strlen($code); - // calculate check digit C - $p = 1; - $check = 0; - for ($i = ($len - 1); $i >= 0; --$i) { - $digit = $code{$i}; - if ($digit == '-') { - $dval = 10; - } else { - $dval = intval($digit); - } - $check += ($dval * $p); - ++$p; - if ($p > 10) { - $p = 1; - } - } - $check %= 11; - if ($check == 10) { - $check = '-'; - } - $code .= $check; - if ($len > 10) { - // calculate check digit K - $p = 1; - $check = 0; - for ($i = $len; $i >= 0; --$i) { - $digit = $code{$i}; - if ($digit == '-') { - $dval = 10; - } else { - $dval = intval($digit); - } - $check += ($dval * $p); - ++$p; - if ($p > 9) { - $p = 1; - } - } - $check %= 11; - $code .= $check; - ++$len; - } - $code = 'S'.$code.'S'; - $len += 3; - for ($i = 0; $i < $len; ++$i) { - if (!isset($chr[$code{$i}])) { - return false; - } - $seq = $chr[$code{$i}]; - for ($j = 0; $j < 6; ++$j) { - if (($j % 2) == 0) { - $t = true; // bar - } else { - $t = false; // space - } - $w = $seq{$j}; - $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); - $bararray['maxw'] += $w; - ++$k; - } - } - - return $bararray; - } - - /** - * Pharmacode - * Contains digits (0 to 9) - * - * @param string $code - * - * @return mixed - */ - protected function barcode_pharmacode($code) - { - $seq = ''; - $code = intval($code); - while ($code > 0) { - if (($code % 2) == 0) { - $seq .= '11100'; - $code -= 2; - } else { - $seq .= '100'; - $code -= 1; - } - $code /= 2; - } - $seq = substr($seq, 0, -2); - $seq = strrev($seq); - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); - - return $this->binseq_to_array($seq, $bararray); - } - - /** - * Pharmacode two-track, contains digits (0 to 9) - * - * @param string $code - * - * @return array - */ - protected function barcode_pharmacode2t($code) - { - $seq = ''; - $code = intval($code); - do { - switch ($code % 3) { - case 0: - $seq .= '3'; - $code = ($code - 3) / 3; - break; - - case 1: - $seq .= '1'; - $code = ($code - 1) / 3; - break; - - case 2: - $seq .= '2'; - $code = ($code - 2) / 3; - break; - - } - } while ($code != 0); - - $seq = strrev($seq); - $k = 0; - $h = 0; - $p = 0; - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array()); - $len = strlen($seq); - for ($i = 0; $i < $len; ++$i) { - switch ($seq{$i}) { - case '1': - $p = 1; - $h = 1; - break; - - case '2': - $p = 0; - $h = 1; - break; - - case '3': - $p = 0; - $h = 2; - break; - - } - $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); - $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['maxw'] += 2; - } - unset($bararray['bcode'][($k - 1)]); - --$bararray['maxw']; - - return $bararray; - } - - /** - * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 (requires PHP bcmath extension) - * Intelligent Mail barcode is a 65-bar code for use on mail in the United States. - * The fields are described as follows: - * - * @param string $code - * - * @return array|bool - */ - protected function barcode_imb($code) - { - $ascChr = array(4,0,2,6,3,5,1,9,8,7,1,2,0,6,4,8,2,9,5,3,0,1,3,7,4,6,8,9,2,0,5,1,9,4,3,8,6,7,1,2,4,3,9,5,7,8,3,0,2,1,4,0,9,1,7,0,2,4,6,3,7,1,9,5,8); - $dscChr = array(7,1,9,5,8,0,2,4,6,3,5,8,9,7,3,0,6,1,7,4,6,8,9,2,5,1,7,5,4,3,8,7,6,0,2,5,4,9,3,0,1,6,8,2,0,4,5,9,6,7,5,2,6,3,8,5,1,9,8,7,4,0,2,6,3); - $ascPos = array(3,0,8,11,1,12,8,11,10,6,4,12,2,7,9,6,7,9,2,8,4,0,12,7,10,9,0,7,10,5,7,9,6,8,2,12,1,4,2,0,1,5,4,6,12,1,0,9,4,7,5,10,2,6,9,11,2,12,6,7,5,11,0,3,2); - $dscPos = array(2,10,12,5,9,1,5,4,3,9,11,5,10,1,6,3,4,1,10,0,2,11,8,6,1,12,3,8,6,4,4,11,0,6,1,9,11,5,3,7,3,10,7,11,8,2,10,3,5,8,0,3,12,11,8,4,5,1,3,0,7,12,9,8,10); - $codeArr = explode('-', $code); - $trackingNumber = $codeArr[0]; - if (isset($codeArr[1])) { - $routingCode = $codeArr[1]; - } else { - $routingCode = ''; - } - // Conversion of Routing Code - switch (strlen($routingCode)) { - case 0: - $binaryCode = 0; - break; - - case 5: - $binaryCode = bcadd($routingCode, '1'); - break; - - case 9: - $binaryCode = bcadd($routingCode, '100001'); - break; - - case 11: - $binaryCode = bcadd($routingCode, '1000100001'); - break; - - default: - return false; - break; - - } - $binaryCode = bcmul($binaryCode, 10); - $binaryCode = bcadd($binaryCode, $trackingNumber{0}); - $binaryCode = bcmul($binaryCode, 5); - $binaryCode = bcadd($binaryCode, $trackingNumber{1}); - $binaryCode .= substr($trackingNumber, 2, 18); - // convert to hexadecimal - $binaryCode = $this->dec_to_hex($binaryCode); - // pad to get 13 bytes - $binaryCode = str_pad($binaryCode, 26, '0', STR_PAD_LEFT); - // convert string to array of bytes - $binaryCodeArr = chunk_split($binaryCode, 2, "\r"); - $binaryCodeArr = substr($binaryCodeArr, 0, -1); - $binaryCodeArr = explode("\r", $binaryCodeArr); - // calculate frame check sequence - $fcs = $this->imb_crc11fcs($binaryCodeArr); - // exclude first 2 bits from first byte - $firstByte = sprintf('%2s', dechex((hexdec($binaryCodeArr[0]) << 2) >> 2)); - $binaryCode102bit = $firstByte.substr($binaryCode, 2); - // convert binary data to codewords - $codewords = array(); - $data = $this->hex_to_dec($binaryCode102bit); - $codewords[0] = bcmod($data, 636) * 2; - $data = bcdiv($data, 636); - for ($i = 1; $i < 9; ++$i) { - $codewords[$i] = bcmod($data, 1365); - $data = bcdiv($data, 1365); - } - $codewords[9] = $data; - if (($fcs >> 10) == 1) { - $codewords[9] += 659; - } - // generate lookup tables - $table2of13 = $this->imb_tables(2, 78); - $table5of13 = $this->imb_tables(5, 1287); - // convert codewords to characters - $characters = array(); - $bitmask = 512; - foreach ($codewords as $val) { - if ($val <= 1286) { - $chrcode = $table5of13[$val]; - } else { - $chrcode = $table2of13[($val - 1287)]; - } - if (($fcs & $bitmask) > 0) { - // bitwise invert - $chrcode = ((~$chrcode) & 8191); - } - $characters[] = $chrcode; - $bitmask /= 2; - } - $characters = array_reverse($characters); - // build bars - $k = 0; - $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); - for ($i = 0; $i < 65; ++$i) { - $asc = (($characters[$ascChr[$i]] & pow(2, $ascPos[$i])) > 0); - $dsc = (($characters[$dscChr[$i]] & pow(2, $dscPos[$i])) > 0); - if ($asc && $dsc) { - // full bar (F) - $p = 0; - $h = 3; - } elseif ($asc) { - // ascender (A) - $p = 0; - $h = 2; - } elseif ($dsc) { - // descender (D) - $p = 1; - $h = 2; - } else { - // tracker (T) - $p = 1; - $h = 1; - } - $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); - $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); - $bararray['maxw'] += 2; - } - unset($bararray['bcode'][($k - 1)]); - --$bararray['maxw']; - - return $bararray; - } - - /** - * Convert large integer number to hexadecimal representation. (requires PHP bcmath extension) - * - * @param string $number - * - * @return string - */ - public function dec_to_hex($number) - { - $hex = array(); - if ($number == 0) { - return '00'; - } - while ($number > 0) { - if ($number == 0) { - array_push($hex, '0'); - } else { - array_push($hex, strtoupper(dechex(bcmod($number, '16')))); - $number = bcdiv($number, '16', 0); - } - } - $hex = array_reverse($hex); - - return implode($hex); - } - - /** - * Convert large hexadecimal number to decimal representation (string). (requires PHP bcmath extension) - * - * @param string $hex - * - * @return int|string - */ - public function hex_to_dec($hex) - { - $dec = 0; - $bitval = 1; - $len = strlen($hex); - for ($pos = ($len - 1); $pos >= 0; --$pos) { - $dec = bcadd($dec, bcmul(hexdec($hex{$pos}), $bitval)); - $bitval = bcmul($bitval, 16); - } - - return $dec; - } - - /** - * Intelligent Mail Barcode calculation of Frame Check Sequence - * - * @param string $codeArr - * - * @return int - */ - protected function imb_crc11fcs($codeArr) - { - $genpoly = 0x0F35; // generator polynomial - $fcs = 0x07FF; // Frame Check Sequence - // do most significant byte skipping the 2 most significant bits - $data = hexdec($codeArr[0]) << 5; - for ($bit = 2; $bit < 8; ++$bit) { - if (($fcs ^ $data) & 0x400) { - $fcs = ($fcs << 1) ^ $genpoly; - } else { - $fcs = ($fcs << 1); - } - $fcs &= 0x7FF; - $data <<= 1; - } - // do rest of bytes - for ($byte = 1; $byte < 13; ++$byte) { - $data = hexdec($codeArr[$byte]) << 3; - for ($bit = 0; $bit < 8; ++$bit) { - if (($fcs ^ $data) & 0x400) { - $fcs = ($fcs << 1) ^ $genpoly; - } else { - $fcs = ($fcs << 1); - } - $fcs &= 0x7FF; - $data <<= 1; - } - } - - return $fcs; - } - - /** - * Reverse unsigned short value - * - * @param int $num - * - * @return int - */ - protected function imb_reverse_us($num) - { - $rev = 0; - for ($i = 0; $i < 16; ++$i) { - $rev <<= 1; - $rev |= ($num & 1); - $num >>= 1; - } - - return $rev; - } - - /** - * generate Nof13 tables used for Intelligent Mail Barcode - * - * @param int $n - * @param int $size - * - * @return array - */ - protected function imb_tables($n, $size) - { - $table = array(); - $lli = 0; // LUT lower index - $lui = $size - 1; // LUT upper index - for ($count = 0; $count < 8192; ++$count) { - $bitCount = 0; - for ($bitIndex = 0; $bitIndex < 13; ++$bitIndex) { - $bitCount += intval(($count & (1 << $bitIndex)) != 0); - } - // if we don't have the right number of bits on, go on to the next value - if ($bitCount == $n) { - $reverse = ($this->imb_reverse_us($count) >> 3); - // if the reverse is less than count, we have already visited this pair before - if ($reverse >= $count) { - // If count is symmetric, place it at the first free slot from the end of the list. - // Otherwise, place it at the first free slot from the beginning of the list && place $reverse ath the next free slot from the beginning of the list - if ($reverse == $count) { - $table[$lui] = $count; - --$lui; - } else { - $table[$lli] = $count; - ++$lli; - $table[$lli] = $reverse; - ++$lli; - } - } - } - } - - return $table; - } - - /** - * unlink old barcode image file or optional rand prefix file - * - * @param string $path - * @param bool $overwrite - * - * @return mixed - */ - public function checkfile($path, $overwrite) - { - if (file_exists($path)) { - - if (!$overwrite) { - $baseName = pathinfo($path, PATHINFO_BASENAME); - - return $this->checkfile(str_replace($baseName, rand(0, 9999) . $baseName, $path), $overwrite); - - } else { - - unlink($path); - - } - } - - return $path; - } + /** + * @const C_DEFAULT_ROTATION_DEG default value for barcode rotation + */ + const C_DEFAULT_ROTATION_DEG = 90; + + /** + * Array representation of barcode. + * @protected + */ + protected $barcodeArray; + + /** + *path to save png in getBarcodePNGPath + * @var + */ + public $savePath; + + /** + * Return an array representations of barcode. + * @return array + * @public + */ + public function getBarcodeArray() + { + return $this->barcodeArray; + } + + /** + * setup temporary path for barcode cache + * + * @param string $serverPath + * + * @throws \Exception + */ + public function setTempPath($serverPath) + { + try { + if (!file_exists($serverPath)) { + mkdir($serverPath, 0770, true); + } + } catch (\Exception $e) { + throw new \Exception("An error occurred while creating barcode cache directory at " . $serverPath); + } + } + + /** + * Send barcode as SVG image object to the standard output. + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param string $color + */ + public function getBarcodeSVG($code, $type,$w=2, $h=30, $color='black') + { + $this->setBarcode($code, $type); + $code = $this->getBarcodeSVGcode($w, $h, $color); + header('Content-Type: application/svg+xml'); + header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 + header('Pragma: public'); + header('Expires: Sat, 12 Nov 1977 23:50:00 GMT'); // Date in the past + header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + header('Content-Disposition: inline; filename="'.md5($code).'.svg";'); + header('Content-Length: '.strlen($code)); + echo $code; + } + + /** + * Return a SVG string representation of barcode. + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param string $color + * + * @return string + */ + public function getBarcodeSVGcode($code, $type,$w=2, $h=30, $color='black') + { + $this->setBarcode($code, $type); + // replace table for special characters + $repstr = array("\0" => '', '&' => '&', '<' => '<', '>' => '>'); + $svg = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n"; + $svg .= ''."\n"; + $svg .= ''."\n"; + $svg .= "\t".''.strtr($this->barcodeArray['code'], $repstr).''."\n"; + $svg .= "\t".''."\n"; + // print bars + $x = 0; + foreach ($this->barcodeArray['bcode'] as $v) { + $bw = round(($v['w'] * $w), 3); + $bh = round(($v['h'] * $h / $this->barcodeArray['maxh']), 3); + if ($v['t']) { + $y = round(($v['p'] * $h / $this->barcodeArray['maxh']), 3); + // draw a vertical bar + $svg .= "\t\t".''."\n"; + } + $x += $bw; + } + $svg .= "\t".''."\n"; + $svg .= ''."\n"; + + return $svg; + } + + /** + * Return an HTML representation of barcode. + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param string $color + * + * @return string + */ + public function getBarcodeHTML($code, $type,$w=2, $h=30, $color='black') + { + $this->setBarcode($code, $type); + $html = '
'."\n"; + // print bars + $x = 0; + foreach ($this->barcodeArray['bcode'] as $v) { + $bw = round(($v['w'] * $w), 3); + $bh = round(($v['h'] * $h / $this->barcodeArray['maxh']), 3); + if ($v['t']) { + $y = round(($v['p'] * $h / $this->barcodeArray['maxh']), 3); + // draw a vertical bar + $html .= '
 
'."\n"; + } + $x += $bw; + } + $html .= '
'."\n"; + + return $html; + } + + /** + * Return a PNG image representation of barcode (requires GD or Imagick library). + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param array $color + * @param bool $vertical + * + * @return bool + */ + public function getBarcodePNG($code, $type,$w=2, $h=30, $color=array(0,0,0), $vertical = false) + { + $this->setBarcode($code, $type); + $bar = null; + + // calculate image size + $width = ($this->barcodeArray['maxw'] * $w); + $height = $h; + if (function_exists('imagecreate')) { + // GD library + $imagick = false; + $png = imagecreate($width, $height); + $bgcol = imagecolorallocate($png, 255, 255, 255); + imagecolortransparent($png, $bgcol); + $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); + } elseif (extension_loaded('imagick')) { + $imagick = true; + $fgcol = new \imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')'); + $png = new \Imagick(); + $png->newImage($width, $height, 'none', 'png'); + $bar = new \imagickdraw(); + $bar->setFillColor($fgcol); + } else { + + return false; + } + // print bars + $x = 0; + $sharp = 3; + $bwPerc = 100; + + foreach ($this->barcodeArray['bcode'] as $v) { + + $bw = round(round(($v['w'] * $w), $sharp) * $bwPerc / 100, $sharp); + $bh = round(($v['h'] * $h / $this->barcodeArray['maxh']), $sharp); + + if ($v['t']) { + $y = round(($v['p'] * $h / $this->barcodeArray['maxh']), 3); + // draw a vertical bar + if ($imagick) { + $bar->rectangle($x, $y, ($x + $bw), ($y + $bh)); + } else { + imagefilledrectangle($png, $x, $y, ($x + $bw), ($y + $bh), $fgcol); + } + } + $x += $bw; + } + + if ($vertical) + { + $png = $this->rotateImage($png, self::C_DEFAULT_ROTATION_DEG); + } + + // send headers + header('Content-Type: image/png'); + header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 + header('Pragma: public'); + header('Expires: Sat, 12 Nov 1977 23:50:00 GMT'); // Date in the past + header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + if ($imagick) { + $png->drawimage($bar); + echo $png; + } else { + imagepng($png); + imagedestroy($png); + } + + return true; + } + + /** + * return filename from give path + * + * @todo: refactor this, move method in some kind of utility class + * + * @param string $path + * + * @return mixed + */ + public function getBarcodeFilenameFromGenPath($path) + { + $bcPathArr = explode('/', $path); + return $bcPathArr[count($bcPathArr)-1]; + } + + /** + * Return a rotated version of source image + * + * @param resource $image + * @param int $angel + * + * @return resource + */ + public function rotateImage($image, $angel) + { + if (function_exists('imagecreate')) { + imagealphablending($image, false); + imagesavealpha($image, true); + + $imageRotate = imagerotate($image, $angel, imageColorAllocateAlpha($image, 0, 0, 0, 127)); + imagealphablending($imageRotate, false); + imagesavealpha($imageRotate, true); + + return $imageRotate; + } + else { + /** @var $image \Imagick */ + $image->rotateImage(new \imagickpixel('rgb(0,0,0)'), $angel); + return $image; + } + } + + /** + * Return a .png file path which create in server + * + * @param string $code + * @param string $type + * @param string $name + * @param int $w + * @param int $h + * @param array $color + * @param bool $vertical + * @param bool $transparent + * + * @return bool + * + * @throws \Exception + */ + public function getBarcodePNGPath($code, $type, $name=null, $w=2, $h=30, $color=array(0,0,0), $vertical=false, $transparent = true) + { + $this->setBarcode($code, $type); + $bar = null; + + if (true === empty($name)) { + $name = md5($code); + } + + // calculate image size + $width = ($this->barcodeArray['maxw'] * $w); + $height = $h; + + if (empty($this->barcodeArray) || (!$this->barcodeArray)) { + throw new \Exception('It not possible to generate barcode of type: '.$type.' for number/code: '.$code.'! May be this is an invalid code pattern!'); + } + + if (function_exists('imagecreate')) { + // GD library + $imagick = false; + + $png = imagecreate($width, $height); + $bgcol = imagecolorallocate($png, 255, 255, 255); + if($transparent){ + imagecolortransparent($png, $bgcol); + } + $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); + } elseif (extension_loaded('imagick')) { + $imagick = true; + $fgcol = new \imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')'); + $png = new \Imagick(); + $png->newImage($width, $height, 'none', 'png'); + $bar = new \imagickdraw(); + $bar->setFillColor($fgcol); + } else { + + return false; + } + + // print bars + $x = 0; + $sharp = 3; + $bwPerc = 100; + + foreach ($this->barcodeArray['bcode'] as $v) { + + $bw = round(round(($v['w'] * $w), $sharp) * $bwPerc / 100, $sharp); + $bh = round(($v['h'] * $h / $this->barcodeArray['maxh']), $sharp); + if ($v['t']) { + $y = round(($v['p'] * $h / $this->barcodeArray['maxh']), $sharp); + // draw a vertical bar + if ($imagick) { + $bar->rectangle($x, $y, ($x + $bw), ($y + $bh)); + } else { + imagefilledrectangle($png, $x, $y, ($x + $bw), ($y + $bh), $fgcol); + } + } + + $x += ($bw); + + } + + if ($vertical) + { + $png = $this->rotateImage($png, self::C_DEFAULT_ROTATION_DEG); + } + + $nType = str_replace('+', 'PLUS', $type); + + $this->setTempPath($this->savePath); + $saveFile = $this->checkfile($this->savePath . $nType . '_' . $name . '.png', true); + + if ($imagick) { + $png->drawImage($bar); + $png->writeImage($saveFile); + return $saveFile; + } + + if (imagepng($png, $saveFile)) { + + imagedestroy($png); + + return $saveFile; + + } else { + + imagedestroy($png); + + throw new \Exception('It not possible to write barcode cache file to path '.$this->savePath); + } + } + + /** + * @param string $code + * @param string $type + */ + public function setBarcode($code, $type) + { + switch (strtoupper(trim($type))) { + case 'C39': // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. + $arrcode = $this->barcode_code39($code, false, false); + break; + + case 'C39+': // CODE 39 with checksum + $arrcode = $this->barcode_code39($code, false, true); + break; + + case 'C39E': // CODE 39 EXTENDED + $arrcode = $this->barcode_code39($code, true, false); + break; + + case 'C39E+': // CODE 39 EXTENDED + CHECKSUM + $arrcode = $this->barcode_code39($code, true, true); + break; + + case 'C93': // CODE 93 - USS-93 + $arrcode = $this->barcode_code93($code); + break; + + case 'S25': // Standard 2 of 5 + $arrcode = $this->barcode_s25($code, false); + break; + + case 'S25+': // Standard 2 of 5 + CHECKSUM + $arrcode = $this->barcode_s25($code, true); + break; + + case 'I25': // Interleaved 2 of 5 + $arrcode = $this->barcode_i25($code, false); + break; + + case 'I25+': // Interleaved 2 of 5 + CHECKSUM + $arrcode = $this->barcode_i25($code, true); + break; + + case 'C128': // CODE 128 + $arrcode = $this->barcode_c128($code, ''); + break; + + case 'C128A': // CODE 128 A + $arrcode = $this->barcode_c128($code, 'A'); + break; + + case 'C128B': // CODE 128 B + $arrcode = $this->barcode_c128($code, 'B'); + break; + + case 'C128C': // CODE 128 C + $arrcode = $this->barcode_c128($code, 'C'); + break; + + case 'EAN2': // 2-Digits UPC-Based Extention + $arrcode = $this->barcode_eanext($code, 2); + break; + + case 'EAN5': // 5-Digits UPC-Based Extention + $arrcode = $this->barcode_eanext($code, 5); + break; + + case 'EAN8': // EAN 8 + $arrcode = $this->barcode_eanupc($code, 8); + break; + + case 'EAN13': // EAN 13 + $arrcode = $this->barcode_eanupc($code, 13); + break; + + case 'UPCA': // UPC-A + $arrcode = $this->barcode_eanupc($code, 12); + break; + + case 'UPCE': // UPC-E + $arrcode = $this->barcode_eanupc($code, 6); + break; + + case 'MSI': // MSI (Variation of Plessey code) + $arrcode = $this->barcode_msi($code, false); + break; + + case 'MSI+': // MSI + CHECKSUM (modulo 11) + $arrcode = $this->barcode_msi($code, true); + break; + + case 'POSTNET': // POSTNET + $arrcode = $this->barcode_postnet($code, false); + break; + + case 'PLANET': // PLANET + $arrcode = $this->barcode_postnet($code, true); + break; + + case 'RMS4CC': // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) + $arrcode = $this->barcode_rms4cc($code, false); + break; + + case 'KIX': // KIX (Klant index - Customer index) + $arrcode = $this->barcode_rms4cc($code, true); + break; + + case 'IMB': // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 + $arrcode = $this->barcode_imb($code); + break; + + case 'CODABAR': // CODABAR + $arrcode = $this->barcode_codabar($code); + break; + + case 'CODE11': // CODE 11 + $arrcode = $this->barcode_code11($code); + break; + + case 'PHARMA': // PHARMACODE + $arrcode = $this->barcode_pharmacode($code); + break; + + case 'PHARMA2T': // PHARMACODE TWO-TRACKS + $arrcode = $this->barcode_pharmacode2t($code); + break; + + default: + $this->barcodeArray = false; + $arrcode = false; + break; + } + + $this->barcodeArray = $arrcode; + + } + + /** + * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. General-purpose code in very wide use world-wide + * + * @param string $code + * @param bool $extended + * @param bool $checksum + * + * @return array|bool + */ + protected function barcode_code39($code, $extended=false, $checksum=false) + { + $chr['0'] = '111331311'; + $chr['1'] = '311311113'; + $chr['2'] = '113311113'; + $chr['3'] = '313311111'; + $chr['4'] = '111331113'; + $chr['5'] = '311331111'; + $chr['6'] = '113331111'; + $chr['7'] = '111311313'; + $chr['8'] = '311311311'; + $chr['9'] = '113311311'; + $chr['A'] = '311113113'; + $chr['B'] = '113113113'; + $chr['C'] = '313113111'; + $chr['D'] = '111133113'; + $chr['E'] = '311133111'; + $chr['F'] = '113133111'; + $chr['G'] = '111113313'; + $chr['H'] = '311113311'; + $chr['I'] = '113113311'; + $chr['J'] = '111133311'; + $chr['K'] = '311111133'; + $chr['L'] = '113111133'; + $chr['M'] = '313111131'; + $chr['N'] = '111131133'; + $chr['O'] = '311131131'; + $chr['P'] = '113131131'; + $chr['Q'] = '111111333'; + $chr['R'] = '311111331'; + $chr['S'] = '113111331'; + $chr['T'] = '111131331'; + $chr['U'] = '331111113'; + $chr['V'] = '133111113'; + $chr['W'] = '333111111'; + $chr['X'] = '131131113'; + $chr['Y'] = '331131111'; + $chr['Z'] = '133131111'; + $chr['-'] = '131111313'; + $chr['.'] = '331111311'; + $chr[' '] = '133111311'; + $chr['$'] = '131313111'; + $chr['/'] = '131311131'; + $chr['+'] = '131113131'; + $chr['%'] = '111313131'; + $chr['*'] = '131131311'; + $code = strtoupper($code); + if ($extended) { + // extended mode + $code = $this->encode_code39_ext($code); + } + if ($code === false) { + return false; + } + if ($checksum) { + // checksum + $code .= $this->checksum_code39($code); + } + // add start and stop codes + $code = '*'.$code.'*'; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $char = $code[$i]; + if (!isset($chr[$char])) { + // invalid character + return false; + } + for ($j = 0; $j < 9; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $chr[$char][$j]; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + // intercharacter gap + $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0); + $bararray['maxw'] += 1; + ++$k; + } + + return $bararray; + } + + /** + * Encode a string to be used for CODE 39 Extended mode. + * + * @param string $code + * + * @return bool|string + */ + protected function encode_code39_ext($code) + { + $encode = array( + chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C', + chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G', + chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K', + chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O', + chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S', + chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W', + chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A', + chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E', + chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C', + chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G', + chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K', + chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O', + chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', + chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', + chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F', + chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J', + chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', + chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', + chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', + chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', + chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', + chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', + chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K', + chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O', + chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C', + chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G', + chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K', + chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O', + chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S', + chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W', + chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P', + chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T'); + $codeExt = ''; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + if (ord($code[$i]) > 127) { + return false; + } + $codeExt .= $encode[$code[$i]]; + } + + return $codeExt; + } + + /** + * Calculate CODE 39 checksum (modulo 43). + * + * @param string $code + * + * @return mixed + */ + protected function checksum_code39($code) + { + $chars = array( + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'); + $sum = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $k = array_keys($chars, $code[$i]); + $sum += $k[0]; + } + $j = ($sum % 43); + + return $chars[$j]; + } + + /** + * CODE 93 - USS-93 + * + * @param string $code + * + * @return array|bool + */ + protected function barcode_code93($code) + { + $chr[48] = '131112'; // 0 + $chr[49] = '111213'; // 1 + $chr[50] = '111312'; // 2 + $chr[51] = '111411'; // 3 + $chr[52] = '121113'; // 4 + $chr[53] = '121212'; // 5 + $chr[54] = '121311'; // 6 + $chr[55] = '111114'; // 7 + $chr[56] = '131211'; // 8 + $chr[57] = '141111'; // 9 + $chr[65] = '211113'; // A + $chr[66] = '211212'; // B + $chr[67] = '211311'; // C + $chr[68] = '221112'; // D + $chr[69] = '221211'; // E + $chr[70] = '231111'; // F + $chr[71] = '112113'; // G + $chr[72] = '112212'; // H + $chr[73] = '112311'; // I + $chr[74] = '122112'; // J + $chr[75] = '132111'; // K + $chr[76] = '111123'; // L + $chr[77] = '111222'; // M + $chr[78] = '111321'; // N + $chr[79] = '121122'; // O + $chr[80] = '131121'; // P + $chr[81] = '212112'; // Q + $chr[82] = '212211'; // R + $chr[83] = '211122'; // S + $chr[84] = '211221'; // T + $chr[85] = '221121'; // U + $chr[86] = '222111'; // V + $chr[87] = '112122'; // W + $chr[88] = '112221'; // X + $chr[89] = '122121'; // Y + $chr[90] = '123111'; // Z + $chr[45] = '121131'; // - + $chr[46] = '311112'; // . + $chr[32] = '311211'; // + $chr[36] = '321111'; // $ + $chr[47] = '112131'; // / + $chr[43] = '113121'; // + + $chr[37] = '211131'; // % + $chr[128] = '121221'; // ($) + $chr[129] = '311121'; // (/) + $chr[130] = '122211'; // (+) + $chr[131] = '312111'; // (%) + $chr[42] = '111141'; // start-stop + $code = strtoupper($code); + $encode = array( + chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C', + chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G', + chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K', + chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O', + chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S', + chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W', + chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A', + chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E', + chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C', + chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G', + chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K', + chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O', + chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', + chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', + chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F', + chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J', + chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', + chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', + chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', + chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', + chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', + chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', + chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K', + chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O', + chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C', + chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G', + chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K', + chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O', + chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S', + chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W', + chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P', + chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T'); + + $codeExt = ''; + $clen = strlen($code); + + for ($i = 0; $i < $clen; ++$i) { + if (ord($code[$i]) > 127) { + return false; + } + $codeExt .= $encode[$code[$i]]; + } + + // checksum + $codeExt .= $this->checksum_code93($codeExt); + // add start and stop codes + $code = '*'.$codeExt.'*'; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $char = ord($code[$i]); + if (!isset($chr[$char])) { + // invalid character + return false; + } + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $chr[$char][$j]; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0); + $bararray['maxw'] += 1; + ++$k; + + return $bararray; + } + + /** + * Calculate CODE 93 checksum (modulo 47). + * + * @param string $code + * + * @return string + */ + protected function checksum_code93($code) + { + $chars = array( + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', + '<', '=', '>', '?'); + // translate special characters + $code = strtr($code, chr(128).chr(131).chr(129).chr(130), '<=>?'); + $len = strlen($code); + // calculate check digit C + $p = 1; + $check = 0; + for ($i = ($len - 1); $i >= 0; --$i) { + $k = array_keys($chars, $code[$i]); + $check += ($k[0] * $p); + ++$p; + if ($p > 20) { + $p = 1; + } + } + $check %= 47; + $c = $chars[$check]; + $code .= $c; + // calculate check digit K + $p = 1; + $check = 0; + for ($i = $len; $i >= 0; --$i) { + $k = array_keys($chars, $code[$i]); + $check += ($k[0] * $p); + ++$p; + if ($p > 15) { + $p = 1; + } + } + $check %= 47; + $k = $chars[$check]; + $checksum = $c.$k; + // resto respecial characters + $checksum = strtr($checksum, '<=>?', chr(128).chr(131).chr(129).chr(130)); + + return $checksum; + } + + /** + * Checksum for standard 2 of 5 barcodes. + * + * @param string $code + * + * @return int + */ + protected function checksum_s25($code) + { + $len = strlen($code); + $sum = 0; + for ($i = 0; $i < $len; $i+=2) { + $sum += $code[$i]; + } + $sum *= 3; + for ($i = 1; $i < $len; $i+=2) { + $sum += ($code[$i]); + } + $r = $sum % 10; + if ($r > 0) { + $r = (10 - $r); + } + + return $r; + } + + /** + * MSI - Variation of Plessey code, with similar applications + * Contains digits (0 to 9) and encodes the data only in the width of bars. + * + * @param string $code + * @param bool $checksum + * + * @return array|bool + */ + protected function barcode_msi($code, $checksum=false) + { + $chr['0'] = '100100100100'; + $chr['1'] = '100100100110'; + $chr['2'] = '100100110100'; + $chr['3'] = '100100110110'; + $chr['4'] = '100110100100'; + $chr['5'] = '100110100110'; + $chr['6'] = '100110110100'; + $chr['7'] = '100110110110'; + $chr['8'] = '110100100100'; + $chr['9'] = '110100100110'; + $chr['A'] = '110100110100'; + $chr['B'] = '110100110110'; + $chr['C'] = '110110100100'; + $chr['D'] = '110110100110'; + $chr['E'] = '110110110100'; + $chr['F'] = '110110110110'; + if ($checksum) { + // add checksum + $clen = strlen($code); + $p = 2; + $check = 0; + for ($i = ($clen - 1); $i >= 0; --$i) { + $check += (hexdec($code[$i]) * $p); + ++$p; + if ($p > 7) { + $p = 2; + } + } + $check %= 11; + if ($check > 0) { + $check = 11 - $check; + } + $code .= $check; + } + $seq = '110'; // left guard + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $digit = $code[$i]; + if (!isset($chr[$digit])) { + // invalid character + return false; + } + $seq .= $chr[$digit]; + } + $seq .= '1001'; // right guard + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Standard 2 of 5 barcodes. + * Used in airline ticket marking, photofinishing + * Contains digits (0 to 9) and encodes the data only in the width of bars. + * + * @param string $code + * @param bool $checksum + * + * @return array|bool + */ + protected function barcode_s25($code, $checksum=false) + { + $chr['0'] = '10101110111010'; + $chr['1'] = '11101010101110'; + $chr['2'] = '10111010101110'; + $chr['3'] = '11101110101010'; + $chr['4'] = '10101110101110'; + $chr['5'] = '11101011101010'; + $chr['6'] = '10111011101010'; + $chr['7'] = '10101011101110'; + $chr['8'] = '10101110111010'; + $chr['9'] = '10111010111010'; + if ($checksum) { + // add checksum + $code .= $this->checksum_s25($code); + } + if ((strlen($code) % 2) != 0) { + // add leading zero if code-length is odd + $code = '0'.$code; + } + $seq = '11011010'; + $clen = strlen($code); + for ($i = 0; $i < $clen; ++$i) { + $digit = $code[$i]; + if (!isset($chr[$digit])) { + // invalid character + return false; + } + $seq .= $chr[$digit]; + } + $seq .= '1101011'; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Convert binary barcode sequence to DNS1DBarcode barcode array. + * + * @param string $seq + * @param array $bararray + * + * @return mixed + */ + protected function binseq_to_array($seq, $bararray) + { + $len = strlen($seq); + $w = 0; + $k = 0; + for ($i = 0; $i < $len; ++$i) { + $w += 1; + if (($i == ($len - 1)) || (($i < ($len - 1)) && ($seq[$i] != $seq[($i+1)]))) { + if ($seq[$i] == '1') { + $t = true; // bar + } else { + $t = false; // space + } + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + $w = 0; + } + } + + return $bararray; + } + + /** + * Interleaved 2 of 5 barcodes. + * Compact numeric code, widely used in industry, air cargo + * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces. + * + * @param string $code + * @param bool $checksum + * + * @return array|bool + */ + protected function barcode_i25($code, $checksum=false) + { + $chr['0'] = '11221'; + $chr['1'] = '21112'; + $chr['2'] = '12112'; + $chr['3'] = '22111'; + $chr['4'] = '11212'; + $chr['5'] = '21211'; + $chr['6'] = '12211'; + $chr['7'] = '11122'; + $chr['8'] = '21121'; + $chr['9'] = '12121'; + $chr['A'] = '11'; + $chr['Z'] = '21'; + if ($checksum) { + // add checksum + $code .= $this->checksum_s25($code); + } + if ((strlen($code) % 2) != 0) { + // add leading zero if code-length is odd + $code = '0'.$code; + } + // add start and stop codes + $code = 'AA'.strtolower($code).'ZA'; + + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + $clen = strlen($code); + for ($i = 0; $i < $clen; $i = ($i + 2)) { + $charBar = $code[$i]; + $charSpace = $code[$i+1]; + if ((!isset($chr[$charBar])) || (!isset($chr[$charSpace]))) { + // invalid character + return false; + } + // create a bar-space sequence + $seq = ''; + $chrlen = strlen($chr[$charBar]); + for ($s = 0; $s < $chrlen; $s++) { + $seq .= $chr[$charBar][$s] . $chr[$charSpace][$s]; + } + $seqlen = strlen($seq); + for ($j = 0; $j < $seqlen; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq[$j]; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + + return $bararray; + } + + /** + * C128 barcodes - very capable code, excellent density, high reliability; in very wide use world-wide + * + * @param string $code + * @param string $type + * + * @return array|bool + */ + protected function barcode_c128($code, $type='') + { + $chr = array( + '212222', /* 00 */ + '222122', /* 01 */ + '222221', /* 02 */ + '121223', /* 03 */ + '121322', /* 04 */ + '131222', /* 05 */ + '122213', /* 06 */ + '122312', /* 07 */ + '132212', /* 08 */ + '221213', /* 09 */ + '221312', /* 10 */ + '231212', /* 11 */ + '112232', /* 12 */ + '122132', /* 13 */ + '122231', /* 14 */ + '113222', /* 15 */ + '123122', /* 16 */ + '123221', /* 17 */ + '223211', /* 18 */ + '221132', /* 19 */ + '221231', /* 20 */ + '213212', /* 21 */ + '223112', /* 22 */ + '312131', /* 23 */ + '311222', /* 24 */ + '321122', /* 25 */ + '321221', /* 26 */ + '312212', /* 27 */ + '322112', /* 28 */ + '322211', /* 29 */ + '212123', /* 30 */ + '212321', /* 31 */ + '232121', /* 32 */ + '111323', /* 33 */ + '131123', /* 34 */ + '131321', /* 35 */ + '112313', /* 36 */ + '132113', /* 37 */ + '132311', /* 38 */ + '211313', /* 39 */ + '231113', /* 40 */ + '231311', /* 41 */ + '112133', /* 42 */ + '112331', /* 43 */ + '132131', /* 44 */ + '113123', /* 45 */ + '113321', /* 46 */ + '133121', /* 47 */ + '313121', /* 48 */ + '211331', /* 49 */ + '231131', /* 50 */ + '213113', /* 51 */ + '213311', /* 52 */ + '213131', /* 53 */ + '311123', /* 54 */ + '311321', /* 55 */ + '331121', /* 56 */ + '312113', /* 57 */ + '312311', /* 58 */ + '332111', /* 59 */ + '314111', /* 60 */ + '221411', /* 61 */ + '431111', /* 62 */ + '111224', /* 63 */ + '111422', /* 64 */ + '121124', /* 65 */ + '121421', /* 66 */ + '141122', /* 67 */ + '141221', /* 68 */ + '112214', /* 69 */ + '112412', /* 70 */ + '122114', /* 71 */ + '122411', /* 72 */ + '142112', /* 73 */ + '142211', /* 74 */ + '241211', /* 75 */ + '221114', /* 76 */ + '413111', /* 77 */ + '241112', /* 78 */ + '134111', /* 79 */ + '111242', /* 80 */ + '121142', /* 81 */ + '121241', /* 82 */ + '114212', /* 83 */ + '124112', /* 84 */ + '124211', /* 85 */ + '411212', /* 86 */ + '421112', /* 87 */ + '421211', /* 88 */ + '212141', /* 89 */ + '214121', /* 90 */ + '412121', /* 91 */ + '111143', /* 92 */ + '111341', /* 93 */ + '131141', /* 94 */ + '114113', /* 95 */ + '114311', /* 96 */ + '411113', /* 97 */ + '411311', /* 98 */ + '113141', /* 99 */ + '114131', /* 100 */ + '311141', /* 101 */ + '411131', /* 102 */ + '211412', /* 103 START A */ + '211214', /* 104 START B */ + '211232', /* 105 START C */ + '233111', /* STOP */ + '200000' /* END */ + ); + // ASCII characters for code A (ASCII 00 - 95) + $keysA = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; + $keysA .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9); + $keysA .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19); + $keysA .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29); + $keysA .= chr(30).chr(31); + // ASCII characters for code B (ASCII 32 - 127) + $keysB = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127); + // special codes + $fncA = array(241 => 102, 242 => 97, 243 => 96, 244 => 101); + $fncB = array(241 => 102, 242 => 97, 243 => 96, 244 => 100); + // array of symbols + $codeData = array(); + // lenght of the code + $len = strlen($code); + $startid = 0; + + switch(strtoupper(trim($type))) { + case 'A': // MODE A + $startid = 103; + for ($i = 0; $i < $len; ++$i) { + $char = $code[$i]; + $charId = ord($char); + if (($charId >= 241) && ($charId <= 244)) { + $codeData[] = $fncA[$charId]; + } elseif (($charId >= 0) && ($charId <= 95)) { + $codeData[] = strpos($keysA, $char); + } else { + return false; + } + } + break; + + case 'B': // MODE B + $startid = 104; + for ($i = 0; $i < $len; ++$i) { + $char = $code[$i]; + $charId = ord($char); + if (($charId >= 241) && ($charId <= 244)) { + $codeData[] = $fncB[$charId]; + } elseif (($charId >= 32) && ($charId <= 127)) { + $codeData[] = strpos($keysB, $char); + } else { + return false; + } + } + break; + + case 'C': // MODE C + $startid = 105; + if (ord($code[0]) == 241) { + $codeData[] = 102; + $code = substr($code, 1); + --$len; + } + if (($len % 2) != 0) { + // the length must be even + return false; + } + for ($i = 0; $i < $len; $i+=2) { + $chrnum = $code[$i].$code[$i+1]; + if (preg_match('/([0-9]{2})/', $chrnum) > 0) { + $codeData[] = intval($chrnum); + } else { + return false; + } + } + break; + + default: // MODE AUTO + // split code into sequences + $sequence = array(); + // get numeric sequences (if any) + $numseq = array(); + preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE); + if (isset($numseq[1]) && !empty($numseq[1])) { + $endOffset = 0; + foreach ($numseq[1] as $val) { + $offset = $val[1]; + if ($offset > $endOffset) { + // non numeric sequence + $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $endOffset, ($offset - $endOffset)))); + } + // numeric sequence + $slen = strlen($val[0]); + if (($slen % 2) != 0) { + // the length must be even + --$slen; + } + $sequence[] = array('C', substr($code, $offset, $slen), $slen); + $endOffset = $offset + $slen; + } + if ($endOffset < $len) { + $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $endOffset))); + } + } else { + // text code (non C mode) + $sequence = array_merge($sequence, $this->get128ABsequence($code)); + } + // process the sequence + foreach ($sequence as $key => $seq) { + switch($seq[0]) { + case 'A': + if ($key == 0) { + $startid = 103; + } elseif ($sequence[($key - 1)][0] != 'A') { + if (($seq[2] == 1) && ($key > 0) && ($sequence[($key - 1)][0] == 'B') && (!isset($sequence[($key - 1)][3]))) { + // single character shift + $codeData[] = 98; + // mark shift + $sequence[$key][3] = true; + } elseif (!isset($sequence[($key - 1)][3])) { + $codeData[] = 101; + } + } + for ($i = 0; $i < $seq[2]; ++$i) { + $char = $seq[1][$i]; + $charId = ord($char); + if (($charId >= 241) && ($charId <= 244)) { + $codeData[] = $fncA[$charId]; + } else { + $codeData[] = strpos($keysA, $char); + } + } + break; + + case 'B': + if ($key == 0) { + $tmpchr = ord($seq[1][0]); + if (($seq[2] == 1) && ($tmpchr >= 241) && ($tmpchr <= 244) && isset($sequence[($key + 1)]) && ($sequence[($key + 1)][0] != 'B')) { + switch ($sequence[($key + 1)][0]) { + case 'A': + $startid = 103; + $sequence[$key][0] = 'A'; + $codeData[] = $fncA[$tmpchr]; + break; + + case 'C': + $startid = 105; + $sequence[$key][0] = 'C'; + $codeData[] = $fncA[$tmpchr]; + break; + + } + break; + } else { + $startid = 104; + } + } elseif ($sequence[($key - 1)][0] != 'B') { + if (($seq[2] == 1) && ($key > 0) && ($sequence[($key - 1)][0] == 'A') && (!isset($sequence[($key - 1)][3]))) { + // single character shift + $codeData[] = 98; + // mark shift + $sequence[$key][3] = true; + } elseif (!isset($sequence[($key - 1)][3])) { + $codeData[] = 100; + } + } + for ($i = 0; $i < $seq[2]; ++$i) { + $char = $seq[1][$i]; + $charId = ord($char); + if (($charId >= 241) && ($charId <= 244)) { + $codeData[] = $fncB[$charId]; + } else { + $codeData[] = strpos($keysB, $char); + } + } + break; + + case 'C': + if ($key == 0) { + $startid = 105; + } elseif ($sequence[($key - 1)][0] != 'C') { + $codeData[] = 99; + } + for ($i = 0; $i < $seq[2]; $i+=2) { + $chrnum = $seq[1][$i].$seq[1][$i+1]; + $codeData[] = intval($chrnum); + } + break; + } + } + } + // calculate check character + $sum = $startid; + foreach ($codeData as $key => $val) { + $sum += ($val * ($key + 1)); + } + // add check character + $codeData[] = ($sum % 103); + // add stop sequence + $codeData[] = 106; + $codeData[] = 107; + // add start code at the beginning + array_unshift($codeData, $startid); + // build barcode array + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + foreach ($codeData as $val) { + $seq = $chr[$val]; + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq[$j]; + $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + } + } + + return $bararray; + } + + /** + * Split text code in A/B sequence for 128 code + * + * @param string $code + * + * @return array + */ + protected function get128ABsequence($code) + { + $len = strlen($code); + $sequence = array(); + // get A sequences (if any) + $numseq = array(); + preg_match_all('/([\0-\31])/', $code, $numseq, PREG_OFFSET_CAPTURE); + if (isset($numseq[1]) && !empty($numseq[1])) { + $endOffset = 0; + foreach ($numseq[1] as $val) { + $offset = $val[1]; + if ($offset > $endOffset) { + // B sequence + $sequence[] = array('B', substr($code, $endOffset, ($offset - $endOffset)), ($offset - $endOffset)); + } + // A sequence + $slen = strlen($val[0]); + $sequence[] = array('A', substr($code, $offset, $slen), $slen); + $endOffset = $offset + $slen; + } + if ($endOffset < $len) { + $sequence[] = array('B', substr($code, $endOffset), ($len - $endOffset)); + } + } else { + // only B sequence + $sequence[] = array('B', $code, $len); + } + + return $sequence; + } + + /** + * EAN13 and UPC-A barcodes. + * EAN13: European Article Numbering international retail product code + * UPC-A: Universal product code seen on almost all retail products in the USA and Canada + * UPC-E: Short version of UPC symbol + * + * @param string $code + * @param int $len + * + * @return array|bool + */ + protected function barcode_eanupc($code, $len=13) + { + $upce = false; + $upceCode = null; + + if ($len == 6) { + $len = 12; // UPC-A + $upce = true; // UPC-E mode + } + $dataLen = $len - 1; + //Padding + $code = str_pad($code, $dataLen, '0', STR_PAD_LEFT); + $codeLen = strlen($code); + // calculate check digit + $sumA = 0; + for ($i = 1; $i < $dataLen; $i+=2) { + $sumA += $code[$i]; + } + if ($len > 12) { + $sumA *= 3; + } + $sumB = 0; + for ($i = 0; $i < $dataLen; $i+=2) { + $sumB += ($code[$i]); + } + if ($len < 13) { + $sumB *= 3; + } + $r = ($sumA + $sumB) % 10; + if ($r > 0) { + $r = (10 - $r); + } + if ($codeLen == $dataLen) { + // add check digit + $code .= $r; + } elseif ($r !== intval($code[$dataLen])) { + // wrong checkdigit + return false; + } + if ($len == 12) { + // UPC-A + $code = '0'.$code; + ++$len; + } + if ($upce) { + // convert UPC-A to UPC-E + $tmp = substr($code, 4, 3); + if (($tmp == '000') || ($tmp == '100') || ($tmp == '200')) { + // manufacturer code ends in 000, 100, or 200 + $upceCode = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1); + } else { + $tmp = substr($code, 5, 2); + if ($tmp == '00') { + // manufacturer code ends in 00 + $upceCode = substr($code, 2, 3).substr($code, 10, 2).'3'; + } else { + $tmp = substr($code, 6, 1); + if ($tmp == '0') { + // manufacturer code ends in 0 + $upceCode = substr($code, 2, 4).substr($code, 11, 1).'4'; + } else { + // manufacturer code does not end in zero + $upceCode = substr($code, 2, 5).substr($code, 11, 1); + } + } + } + } + //Convert digits to bars + $codes = array( + 'A'=>array( // left odd parity + '0'=>'0001101', + '1'=>'0011001', + '2'=>'0010011', + '3'=>'0111101', + '4'=>'0100011', + '5'=>'0110001', + '6'=>'0101111', + '7'=>'0111011', + '8'=>'0110111', + '9'=>'0001011'), + 'B'=>array( // left even parity + '0'=>'0100111', + '1'=>'0110011', + '2'=>'0011011', + '3'=>'0100001', + '4'=>'0011101', + '5'=>'0111001', + '6'=>'0000101', + '7'=>'0010001', + '8'=>'0001001', + '9'=>'0010111'), + 'C'=>array( // right + '0'=>'1110010', + '1'=>'1100110', + '2'=>'1101100', + '3'=>'1000010', + '4'=>'1011100', + '5'=>'1001110', + '6'=>'1010000', + '7'=>'1000100', + '8'=>'1001000', + '9'=>'1110100') + ); + $parities = array( + '0'=>array('A','A','A','A','A','A'), + '1'=>array('A','A','B','A','B','B'), + '2'=>array('A','A','B','B','A','B'), + '3'=>array('A','A','B','B','B','A'), + '4'=>array('A','B','A','A','B','B'), + '5'=>array('A','B','B','A','A','B'), + '6'=>array('A','B','B','B','A','A'), + '7'=>array('A','B','A','B','A','B'), + '8'=>array('A','B','A','B','B','A'), + '9'=>array('A','B','B','A','B','A') + ); + $upceParities = array(); + $upceParities[0] = array( + '0'=>array('B','B','B','A','A','A'), + '1'=>array('B','B','A','B','A','A'), + '2'=>array('B','B','A','A','B','A'), + '3'=>array('B','B','A','A','A','B'), + '4'=>array('B','A','B','B','A','A'), + '5'=>array('B','A','A','B','B','A'), + '6'=>array('B','A','A','A','B','B'), + '7'=>array('B','A','B','A','B','A'), + '8'=>array('B','A','B','A','A','B'), + '9'=>array('B','A','A','B','A','B') + ); + $upceParities[1] = array( + '0'=>array('A','A','A','B','B','B'), + '1'=>array('A','A','B','A','B','B'), + '2'=>array('A','A','B','B','A','B'), + '3'=>array('A','A','B','B','B','A'), + '4'=>array('A','B','A','A','B','B'), + '5'=>array('A','B','B','A','A','B'), + '6'=>array('A','B','B','B','A','A'), + '7'=>array('A','B','A','B','A','B'), + '8'=>array('A','B','A','B','B','A'), + '9'=>array('A','B','B','A','B','A') + ); + $k = 0; + $seq = '101'; // left guard bar + if ($upce) { + $bararray = array('code' => $upceCode, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $p = $upceParities[$code[1]][$r]; + for ($i = 0; $i < 6; ++$i) { + $seq .= $codes[$p[$i]][$upceCode[$i]]; + } + $seq .= '010101'; // right guard bar + } else { + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $halfLen = ceil($len / 2); + if ($len == 8) { + for ($i = 0; $i < $halfLen; ++$i) { + $seq .= $codes['A'][$code[$i]]; + } + } else { + $p = $parities[$code[0]]; + for ($i = 1; $i < $halfLen; ++$i) { + $seq .= $codes[$p[$i-1]][$code[$i]]; + } + } + $seq .= '01010'; // center guard bar + for ($i = $halfLen; $i < $len; ++$i) { + $seq .= $codes['C'][$code[intval($i)]]; + } + $seq .= '101'; // right guard bar + } + $clen = strlen($seq); + $w = 0; + for ($i = 0; $i < $clen; ++$i) { + $w += 1; + if (($i == ($clen - 1)) || (($i < ($clen - 1)) && ($seq[$i] != $seq[($i+1)]))) { + if ($seq[$i] == '1') { + $t = true; // bar + } else { + $t = false; // space + } + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + $w = 0; + } + } + + return $bararray; + } + + /** + * UPC-Based Extentions + * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers + * 5-Digit Ext.: Used to mark suggested retail price of books + * + * @param string $code + * @param int $len + * + * @return bool|mixed + */ + protected function barcode_eanext($code, $len=5) + { + //Padding + $code = str_pad($code, $len, '0', STR_PAD_LEFT); + // calculate check digit + if ($len == 2) { + $r = $code % 4; + } elseif ($len == 5) { + $r = (3 * ($code[0] + $code[2] + $code[4])) + (9 * ($code[1] + $code[3])); + $r %= 10; + } else { + return false; + } + //Convert digits to bars + $codes = array( + 'A'=>array( // left odd parity + '0'=>'0001101', + '1'=>'0011001', + '2'=>'0010011', + '3'=>'0111101', + '4'=>'0100011', + '5'=>'0110001', + '6'=>'0101111', + '7'=>'0111011', + '8'=>'0110111', + '9'=>'0001011'), + 'B'=>array( // left even parity + '0'=>'0100111', + '1'=>'0110011', + '2'=>'0011011', + '3'=>'0100001', + '4'=>'0011101', + '5'=>'0111001', + '6'=>'0000101', + '7'=>'0010001', + '8'=>'0001001', + '9'=>'0010111') + ); + $parities = array(); + $parities[2] = array( + '0'=>array('A','A'), + '1'=>array('A','B'), + '2'=>array('B','A'), + '3'=>array('B','B') + ); + $parities[5] = array( + '0'=>array('B','B','A','A','A'), + '1'=>array('B','A','B','A','A'), + '2'=>array('B','A','A','B','A'), + '3'=>array('B','A','A','A','B'), + '4'=>array('A','B','B','A','A'), + '5'=>array('A','A','B','B','A'), + '6'=>array('A','A','A','B','B'), + '7'=>array('A','B','A','B','A'), + '8'=>array('A','B','A','A','B'), + '9'=>array('A','A','B','A','B') + ); + $p = $parities[$len][$r]; + $seq = '1011'; // left guard bar + $seq .= $codes[$p[0]][$code[0]]; + for ($i = 1; $i < $len; ++$i) { + $seq .= '01'; // separator + $seq .= $codes[$p[$i]][$code[$i]]; + } + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + + return $this->binseq_to_array($seq, $bararray); + } + + /** + * POSTNET and PLANET barcodes. + * Used by U.S. Postal Service for automated mail sorting + * + * @param string $code + * @param bool $planet + * + * @return array + */ + protected function barcode_postnet($code, $planet=false) + { + // bar length + if ($planet) { + $barlen = Array( + 0 => Array(1,1,2,2,2), + 1 => Array(2,2,2,1,1), + 2 => Array(2,2,1,2,1), + 3 => Array(2,2,1,1,2), + 4 => Array(2,1,2,2,1), + 5 => Array(2,1,2,1,2), + 6 => Array(2,1,1,2,2), + 7 => Array(1,2,2,2,1), + 8 => Array(1,2,2,1,2), + 9 => Array(1,2,1,2,2) + ); + } else { + $barlen = Array( + 0 => Array(2,2,1,1,1), + 1 => Array(1,1,1,2,2), + 2 => Array(1,1,2,1,2), + 3 => Array(1,1,2,2,1), + 4 => Array(1,2,1,1,2), + 5 => Array(1,2,1,2,1), + 6 => Array(1,2,2,1,1), + 7 => Array(2,1,1,1,2), + 8 => Array(2,1,1,2,1), + 9 => Array(2,1,2,1,1) + ); + } + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array()); + $k = 0; + $code = str_replace('-', '', $code); + $code = str_replace(' ', '', $code); + $len = strlen($code); + // calculate checksum + $sum = 0; + for ($i = 0; $i < $len; ++$i) { + $sum += intval($code[$i]); + } + $chkd = ($sum % 10); + if ($chkd > 0) { + $chkd = (10 - $chkd); + } + $code .= $chkd; + $len = strlen($code); + // start bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + for ($i = 0; $i < $len; ++$i) { + for ($j = 0; $j < 5; ++$j) { + $h = $barlen[$code[$i]][$j]; + $p = floor(1 / $h); + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + } + // end bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 1; + + return $bararray; + } + + /** + * RMS4CC - CBC - KIX + * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index) + * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service. + * + * @param string $code + * @param bool $kix + * + * @return array + */ + protected function barcode_rms4cc($code, $kix=false) + { + $notkix = !$kix; + // bar mode + // 1 = pos 1, length 2 + // 2 = pos 1, length 3 + // 3 = pos 2, length 1 + // 4 = pos 2, length 2 + $barmode = array( + '0' => array(3,3,2,2), + '1' => array(3,4,1,2), + '2' => array(3,4,2,1), + '3' => array(4,3,1,2), + '4' => array(4,3,2,1), + '5' => array(4,4,1,1), + '6' => array(3,1,4,2), + '7' => array(3,2,3,2), + '8' => array(3,2,4,1), + '9' => array(4,1,3,2), + 'A' => array(4,1,4,1), + 'B' => array(4,2,3,1), + 'C' => array(3,1,2,4), + 'D' => array(3,2,1,4), + 'E' => array(3,2,2,3), + 'F' => array(4,1,1,4), + 'G' => array(4,1,2,3), + 'H' => array(4,2,1,3), + 'I' => array(1,3,4,2), + 'J' => array(1,4,3,2), + 'K' => array(1,4,4,1), + 'L' => array(2,3,3,2), + 'M' => array(2,3,4,1), + 'N' => array(2,4,3,1), + 'O' => array(1,3,2,4), + 'P' => array(1,4,1,4), + 'Q' => array(1,4,2,3), + 'R' => array(2,3,1,4), + 'S' => array(2,3,2,3), + 'T' => array(2,4,1,3), + 'U' => array(1,1,4,4), + 'V' => array(1,2,3,4), + 'W' => array(1,2,4,3), + 'X' => array(2,1,3,4), + 'Y' => array(2,1,4,3), + 'Z' => array(2,2,3,3) + ); + $code = strtoupper($code); + $len = strlen($code); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); + if ($notkix) { + // table for checksum calculation (row,col) + $checktable = array( + '0' => array(1,1), + '1' => array(1,2), + '2' => array(1,3), + '3' => array(1,4), + '4' => array(1,5), + '5' => array(1,0), + '6' => array(2,1), + '7' => array(2,2), + '8' => array(2,3), + '9' => array(2,4), + 'A' => array(2,5), + 'B' => array(2,0), + 'C' => array(3,1), + 'D' => array(3,2), + 'E' => array(3,3), + 'F' => array(3,4), + 'G' => array(3,5), + 'H' => array(3,0), + 'I' => array(4,1), + 'J' => array(4,2), + 'K' => array(4,3), + 'L' => array(4,4), + 'M' => array(4,5), + 'N' => array(4,0), + 'O' => array(5,1), + 'P' => array(5,2), + 'Q' => array(5,3), + 'R' => array(5,4), + 'S' => array(5,5), + 'T' => array(5,0), + 'U' => array(0,1), + 'V' => array(0,2), + 'W' => array(0,3), + 'X' => array(0,4), + 'Y' => array(0,5), + 'Z' => array(0,0) + ); + $row = 0; + $col = 0; + for ($i = 0; $i < $len; ++$i) { + $row += $checktable[$code[$i]][0]; + $col += $checktable[$code[$i]][1]; + } + $row %= 6; + $col %= 6; + $chk = array_keys($checktable, array($row,$col)); + $code .= $chk[0]; + ++$len; + } + $k = 0; + if ($notkix) { + // start bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + for ($i = 0; $i < $len; ++$i) { + for ($j = 0; $j < 4; ++$j) { + switch ($barmode[$code[$i]][$j]) { + case 1: + $p = 0; + $h = 2; + break; + + case 2: + $p = 0; + $h = 3; + break; + + case 3: + $p = 1; + $h = 1; + break; + + case 4: + $p = 1; + $h = 2; + break; + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + } + if ($notkix) { + // stop bar + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0); + $bararray['maxw'] += 1; + } + + return $bararray; + } + + /** + * CODABAR barcodes. + * Older code often used in library systems, sometimes in blood banks + * + * @param string $code + * + * @return array|bool + */ + protected function barcode_codabar($code) + { + $chr = array( + '0' => '11111221', + '1' => '11112211', + '2' => '11121121', + '3' => '22111111', + '4' => '11211211', + '5' => '21111211', + '6' => '12111121', + '7' => '12112111', + '8' => '12211111', + '9' => '21121111', + '-' => '11122111', + '$' => '11221111', + ':' => '21112121', + '/' => '21211121', + '.' => '21212111', + '+' => '11222221', + 'A' => '11221211', + 'B' => '12121121', + 'C' => '11121221', + 'D' => '11122211' + ); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + // $w = 0; + $seq = null; + $code = 'A'.strtoupper($code).'A'; + $len = strlen($code); + for ($i = 0; $i < $len; ++$i) { + if (!isset($chr[$code[$i]])) { + return false; + } + $seq = $chr[$code[$i]]; + for ($j = 0; $j < 8; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq[$j]; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + + return $bararray; + } + + /** + * CODE11 barcodes. + * Used primarily for labeling telecommunications equipment + * + * @param string $code + * + * @return array|bool + */ + protected function barcode_code11($code) + { + $chr = array( + '0' => '111121', + '1' => '211121', + '2' => '121121', + '3' => '221111', + '4' => '112121', + '5' => '212111', + '6' => '122111', + '7' => '111221', + '8' => '211211', + '9' => '211111', + '-' => '112111', + 'S' => '112211' + ); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + $k = 0; + // $w = 0; + $seq = null; + $len = strlen($code); + // calculate check digit C + $p = 1; + $check = 0; + for ($i = ($len - 1); $i >= 0; --$i) { + $digit = $code[$i]; + if ($digit == '-') { + $dval = 10; + } else { + $dval = intval($digit); + } + $check += ($dval * $p); + ++$p; + if ($p > 10) { + $p = 1; + } + } + $check %= 11; + if ($check == 10) { + $check = '-'; + } + $code .= $check; + if ($len > 10) { + // calculate check digit K + $p = 1; + $check = 0; + for ($i = $len; $i >= 0; --$i) { + $digit = $code[$i]; + if ($digit == '-') { + $dval = 10; + } else { + $dval = intval($digit); + } + $check += ($dval * $p); + ++$p; + if ($p > 9) { + $p = 1; + } + } + $check %= 11; + $code .= $check; + ++$len; + } + $code = 'S'.$code.'S'; + $len += 3; + for ($i = 0; $i < $len; ++$i) { + if (!isset($chr[$code[$i]])) { + return false; + } + $seq = $chr[$code[$i]]; + for ($j = 0; $j < 6; ++$j) { + if (($j % 2) == 0) { + $t = true; // bar + } else { + $t = false; // space + } + $w = $seq[$j]; + $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); + $bararray['maxw'] += $w; + ++$k; + } + } + + return $bararray; + } + + /** + * Pharmacode + * Contains digits (0 to 9) + * + * @param string $code + * + * @return mixed + */ + protected function barcode_pharmacode($code) + { + $seq = ''; + $code = intval($code); + while ($code > 0) { + if (($code % 2) == 0) { + $seq .= '11100'; + $code -= 2; + } else { + $seq .= '100'; + $code -= 1; + } + $code /= 2; + } + $seq = substr($seq, 0, -2); + $seq = strrev($seq); + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); + + return $this->binseq_to_array($seq, $bararray); + } + + /** + * Pharmacode two-track, contains digits (0 to 9) + * + * @param string $code + * + * @return array + */ + protected function barcode_pharmacode2t($code) + { + $seq = ''; + $code = intval($code); + do { + switch ($code % 3) { + case 0: + $seq .= '3'; + $code = ($code - 3) / 3; + break; + + case 1: + $seq .= '1'; + $code = ($code - 1) / 3; + break; + + case 2: + $seq .= '2'; + $code = ($code - 2) / 3; + break; + + } + } while ($code != 0); + + $seq = strrev($seq); + $k = 0; + $h = 0; + $p = 0; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array()); + $len = strlen($seq); + for ($i = 0; $i < $len; ++$i) { + switch ($seq[$i]) { + case '1': + $p = 1; + $h = 1; + break; + + case '2': + $p = 0; + $h = 1; + break; + + case '3': + $p = 0; + $h = 2; + break; + + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + unset($bararray['bcode'][($k - 1)]); + --$bararray['maxw']; + + return $bararray; + } + + /** + * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 (requires PHP bcmath extension) + * Intelligent Mail barcode is a 65-bar code for use on mail in the United States. + * The fields are described as follows: + * + * @param string $code + * + * @return array|bool + */ + protected function barcode_imb($code) + { + $ascChr = array(4,0,2,6,3,5,1,9,8,7,1,2,0,6,4,8,2,9,5,3,0,1,3,7,4,6,8,9,2,0,5,1,9,4,3,8,6,7,1,2,4,3,9,5,7,8,3,0,2,1,4,0,9,1,7,0,2,4,6,3,7,1,9,5,8); + $dscChr = array(7,1,9,5,8,0,2,4,6,3,5,8,9,7,3,0,6,1,7,4,6,8,9,2,5,1,7,5,4,3,8,7,6,0,2,5,4,9,3,0,1,6,8,2,0,4,5,9,6,7,5,2,6,3,8,5,1,9,8,7,4,0,2,6,3); + $ascPos = array(3,0,8,11,1,12,8,11,10,6,4,12,2,7,9,6,7,9,2,8,4,0,12,7,10,9,0,7,10,5,7,9,6,8,2,12,1,4,2,0,1,5,4,6,12,1,0,9,4,7,5,10,2,6,9,11,2,12,6,7,5,11,0,3,2); + $dscPos = array(2,10,12,5,9,1,5,4,3,9,11,5,10,1,6,3,4,1,10,0,2,11,8,6,1,12,3,8,6,4,4,11,0,6,1,9,11,5,3,7,3,10,7,11,8,2,10,3,5,8,0,3,12,11,8,4,5,1,3,0,7,12,9,8,10); + $codeArr = explode('-', $code); + $trackingNumber = $codeArr[0]; + if (isset($codeArr[1])) { + $routingCode = $codeArr[1]; + } else { + $routingCode = ''; + } + // Conversion of Routing Code + switch (strlen($routingCode)) { + case 0: + $binaryCode = 0; + break; + + case 5: + $binaryCode = bcadd($routingCode, '1'); + break; + + case 9: + $binaryCode = bcadd($routingCode, '100001'); + break; + + case 11: + $binaryCode = bcadd($routingCode, '1000100001'); + break; + + default: + return false; + break; + + } + $binaryCode = bcmul($binaryCode, 10); + $binaryCode = bcadd($binaryCode, $trackingNumber[0]); + $binaryCode = bcmul($binaryCode, 5); + $binaryCode = bcadd($binaryCode, $trackingNumber[1]); + $binaryCode .= substr($trackingNumber, 2, 18); + // convert to hexadecimal + $binaryCode = $this->dec_to_hex($binaryCode); + // pad to get 13 bytes + $binaryCode = str_pad($binaryCode, 26, '0', STR_PAD_LEFT); + // convert string to array of bytes + $binaryCodeArr = chunk_split($binaryCode, 2, "\r"); + $binaryCodeArr = substr($binaryCodeArr, 0, -1); + $binaryCodeArr = explode("\r", $binaryCodeArr); + // calculate frame check sequence + $fcs = $this->imb_crc11fcs($binaryCodeArr); + // exclude first 2 bits from first byte + $firstByte = sprintf('%2s', dechex((hexdec($binaryCodeArr[0]) << 2) >> 2)); + $binaryCode102bit = $firstByte.substr($binaryCode, 2); + // convert binary data to codewords + $codewords = array(); + $data = $this->hex_to_dec($binaryCode102bit); + $codewords[0] = bcmod($data, 636) * 2; + $data = bcdiv($data, 636); + for ($i = 1; $i < 9; ++$i) { + $codewords[$i] = bcmod($data, 1365); + $data = bcdiv($data, 1365); + } + $codewords[9] = $data; + if (($fcs >> 10) == 1) { + $codewords[9] += 659; + } + // generate lookup tables + $table2of13 = $this->imb_tables(2, 78); + $table5of13 = $this->imb_tables(5, 1287); + // convert codewords to characters + $characters = array(); + $bitmask = 512; + foreach ($codewords as $val) { + if ($val <= 1286) { + $chrcode = $table5of13[$val]; + } else { + $chrcode = $table2of13[($val - 1287)]; + } + if (($fcs & $bitmask) > 0) { + // bitwise invert + $chrcode = ((~$chrcode) & 8191); + } + $characters[] = $chrcode; + $bitmask /= 2; + } + $characters = array_reverse($characters); + // build bars + $k = 0; + $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array()); + for ($i = 0; $i < 65; ++$i) { + $asc = (($characters[$ascChr[$i]] & pow(2, $ascPos[$i])) > 0); + $dsc = (($characters[$dscChr[$i]] & pow(2, $dscPos[$i])) > 0); + if ($asc && $dsc) { + // full bar (F) + $p = 0; + $h = 3; + } elseif ($asc) { + // ascender (A) + $p = 0; + $h = 2; + } elseif ($dsc) { + // descender (D) + $p = 1; + $h = 2; + } else { + // tracker (T) + $p = 1; + $h = 1; + } + $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); + $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0); + $bararray['maxw'] += 2; + } + unset($bararray['bcode'][($k - 1)]); + --$bararray['maxw']; + + return $bararray; + } + + /** + * Convert large integer number to hexadecimal representation. (requires PHP bcmath extension) + * + * @param string $number + * + * @return string + */ + public function dec_to_hex($number) + { + $hex = array(); + if ($number == 0) { + return '00'; + } + while ($number > 0) { + if ($number == 0) { + array_push($hex, '0'); + } else { + array_push($hex, strtoupper(dechex(bcmod($number, '16')))); + $number = bcdiv($number, '16', 0); + } + } + $hex = array_reverse($hex); + + return implode($hex); + } + + /** + * Convert large hexadecimal number to decimal representation (string). (requires PHP bcmath extension) + * + * @param string $hex + * + * @return int|string + */ + public function hex_to_dec($hex) + { + $dec = 0; + $bitval = 1; + $len = strlen($hex); + for ($pos = ($len - 1); $pos >= 0; --$pos) { + $dec = bcadd($dec, bcmul(hexdec($hex[$pos]), $bitval)); + $bitval = bcmul($bitval, 16); + } + + return $dec; + } + + /** + * Intelligent Mail Barcode calculation of Frame Check Sequence + * + * @param string $codeArr + * + * @return int + */ + protected function imb_crc11fcs($codeArr) + { + $genpoly = 0x0F35; // generator polynomial + $fcs = 0x07FF; // Frame Check Sequence + // do most significant byte skipping the 2 most significant bits + $data = hexdec($codeArr[0]) << 5; + for ($bit = 2; $bit < 8; ++$bit) { + if (($fcs ^ $data) & 0x400) { + $fcs = ($fcs << 1) ^ $genpoly; + } else { + $fcs = ($fcs << 1); + } + $fcs &= 0x7FF; + $data <<= 1; + } + // do rest of bytes + for ($byte = 1; $byte < 13; ++$byte) { + $data = hexdec($codeArr[$byte]) << 3; + for ($bit = 0; $bit < 8; ++$bit) { + if (($fcs ^ $data) & 0x400) { + $fcs = ($fcs << 1) ^ $genpoly; + } else { + $fcs = ($fcs << 1); + } + $fcs &= 0x7FF; + $data <<= 1; + } + } + + return $fcs; + } + + /** + * Reverse unsigned short value + * + * @param int $num + * + * @return int + */ + protected function imb_reverse_us($num) + { + $rev = 0; + for ($i = 0; $i < 16; ++$i) { + $rev <<= 1; + $rev |= ($num & 1); + $num >>= 1; + } + + return $rev; + } + + /** + * generate Nof13 tables used for Intelligent Mail Barcode + * + * @param int $n + * @param int $size + * + * @return array + */ + protected function imb_tables($n, $size) + { + $table = array(); + $lli = 0; // LUT lower index + $lui = $size - 1; // LUT upper index + for ($count = 0; $count < 8192; ++$count) { + $bitCount = 0; + for ($bitIndex = 0; $bitIndex < 13; ++$bitIndex) { + $bitCount += intval(($count & (1 << $bitIndex)) != 0); + } + // if we don't have the right number of bits on, go on to the next value + if ($bitCount == $n) { + $reverse = ($this->imb_reverse_us($count) >> 3); + // if the reverse is less than count, we have already visited this pair before + if ($reverse >= $count) { + // If count is symmetric, place it at the first free slot from the end of the list. + // Otherwise, place it at the first free slot from the beginning of the list && place $reverse ath the next free slot from the beginning of the list + if ($reverse == $count) { + $table[$lui] = $count; + --$lui; + } else { + $table[$lli] = $count; + ++$lli; + $table[$lli] = $reverse; + ++$lli; + } + } + } + } + + return $table; + } + + /** + * unlink old barcode image file or optional rand prefix file + * + * @param string $path + * @param bool $overwrite + * + * @return mixed + */ + public function checkfile($path, $overwrite) + { + if (file_exists($path)) { + + if (!$overwrite) { + $baseName = pathinfo($path, PATHINFO_BASENAME); + + return $this->checkfile(str_replace($baseName, rand(0, 9999) . $baseName, $path), $overwrite); + + } else { + + unlink($path); + + } + } + + return $path; + } } diff --git a/Base2DBarcode.php b/Base2DBarcode.php old mode 100644 new mode 100755 index 7d4cd8a..7833a8b --- a/Base2DBarcode.php +++ b/Base2DBarcode.php @@ -40,8 +40,8 @@ include_once('modules/QRCode.php'); use BG\Barcode\Modules\PDF417, - BG\Barcode\Modules\Datamatrix, - BG\Barcode\Modules\QRCode; +BG\Barcode\Modules\Datamatrix, +BG\Barcode\Modules\QRCode; /** * class Base2DBarcode 1.0.0, based on 2dbarcodes.php v1.0.013 (Nicola Asuni) @@ -54,452 +54,452 @@ */ class Base2DBarcode { - /** - * Array representation of barcode. - */ - protected $barcodeArray = false; - /** - * path to save png in getBarcodePNGPath - * @var - */ - public $savePath; - - /** - * Return an array representations of barcode. - * @return array - */ - public function getBarcodeArray() - { - return $this->barcodeArray; - } - - /** - * setup temporary path for barcode cache - * - * @param string $serverPath - * - * @throws \Exception - */ - public function setTempPath($serverPath) - { - try { - if (!file_exists($serverPath)) { - mkdir($serverPath, 0770, true); - } - } catch (\Exception $e) { - throw new \Exception("An error occurred while creating barcode cache directory at " . $serverPath); - } - } - - /** - * get svg brcode (header stream) - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param string $color - */ - public function getBarcodeSVG($code, $type, $w=3, $h=3, $color='black') - { - //set barcode code and type - $this->setBarcode($code, $type); - // send headers - $code = $this->getBarcodeSVGcode($w, $h, $color); - header('Content-Type: application/svg+xml'); - header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 - header('Pragma: public'); - header('Expires: Sat, 12 Nov 1977 23:50:00 GMT'); // Date in the past - header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); - header('Content-Disposition: inline; filename="' . md5($code) . '.svg";'); - //header('Content-Length: '.strlen($code)); - echo $code; - } - - /** - * Return a Full Doctype SVG string representation of barcode. - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param string $color - * - * @return string - */ - public function getBarcodeSVGcode($code, $type, $w=3, $h=3, $color='black') - { - return '' . "\n" - . '' . "\n" - . $this->getRawBarcodeSVGcode($code, $type, $w=3, $h=3, $color='black'); - } - - /** - * Return an inline SVG string representation of barcode. - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param string $color - * - * @return string - */ - public function getRawBarcodeSVGcode($code, $type, $w=3, $h=3, $color='black') - { - //set barcode code and type - $this->setBarcode($code, $type); - // replace table for special characters - $repstr = strtr($this->barcodeArray['code'], array("\0" => '', '&' => '&', '<' => '<', '>' => '>')); - $tw = round(($this->barcodeArray['num_cols'] * $w), 3); - $th = round(($this->barcodeArray['num_cols'] * $h), 3); - $svg = " + /** + * Array representation of barcode. + */ + protected $barcodeArray = false; + /** + * path to save png in getBarcodePNGPath + * @var + */ + public $savePath; + + /** + * Return an array representations of barcode. + * @return array + */ + public function getBarcodeArray() + { + return $this->barcodeArray; + } + + /** + * setup temporary path for barcode cache + * + * @param string $serverPath + * + * @throws \Exception + */ + public function setTempPath($serverPath) + { + try { + if (!file_exists($serverPath)) { + mkdir($serverPath, 0770, true); + } + } catch (\Exception $e) { + throw new \Exception("An error occurred while creating barcode cache directory at " . $serverPath); + } + } + + /** + * get svg brcode (header stream) + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param string $color + */ + public function getBarcodeSVG($code, $type, $w=3, $h=3, $color='black') + { + //set barcode code and type + $this->setBarcode($code, $type); + // send headers + $code = $this->getBarcodeSVGcode($w, $h, $color); + header('Content-Type: application/svg+xml'); + header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 + header('Pragma: public'); + header('Expires: Sat, 12 Nov 1977 23:50:00 GMT'); // Date in the past + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Content-Disposition: inline; filename="' . md5($code) . '.svg";'); + //header('Content-Length: '.strlen($code)); + echo $code; + } + + /** + * Return a Full Doctype SVG string representation of barcode. + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param string $color + * + * @return string + */ + public function getBarcodeSVGcode($code, $type, $w=3, $h=3, $color='black') + { + return '' . "\n" + . '' . "\n" + . $this->getRawBarcodeSVGcode($code, $type, $w=3, $h=3, $color='black'); + } + + /** + * Return an inline SVG string representation of barcode. + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param string $color + * + * @return string + */ + public function getRawBarcodeSVGcode($code, $type, $w=3, $h=3, $color='black') + { + //set barcode code and type + $this->setBarcode($code, $type); + // replace table for special characters + $repstr = strtr($this->barcodeArray['code'], array("\0" => '', '&' => '&', '<' => '<', '>' => '>')); + $tw = round(($this->barcodeArray['num_cols'] * $w), 3); + $th = round(($this->barcodeArray['num_cols'] * $h), 3); + $svg = " $repstr "; - // print barcode elements - $y = 0; - // for each row - for ($r = 0; $r < $this->barcodeArray['num_rows']; ++$r) { - $x = 0; - // for each column - for ($c = 0; $c < $this->barcodeArray['num_cols']; ++$c) { - if ($this->barcodeArray['bcode'][$r][$c] == 1) { - // draw a single barcode cell - $svg .= "\t\t" . '' . "\n"; - } - $x += $w; - } - $y += $h; - } - $svg .= "\t" . '' . "\n"; - $svg .= '' . "\n"; - - return $svg; - } - - /** - * Return an HTML representation of barcode. - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param string $color - * - * @return string - */ - public function getBarcodeHTML($code, $type, $w=10, $h=10, $color='black') - { - //set barcode code and type - $this->setBarcode($code, $type); - $html = '
' . "\n"; - // print barcode elements - $y = 0; - // for each row - for ($r = 0; $r < $this->barcodeArray['num_rows']; ++$r) { - $x = 0; - // for each column - for ($c = 0; $c < $this->barcodeArray['num_cols']; ++$c) { - if ($this->barcodeArray['bcode'][$r][$c] == 1) { - // draw a single barcode cell - $html .= '
 
' . "\n"; - } - $x += $w; - } - $y += $h; - } - $html .= '
' . "\n"; - - return $html; - } - - /** - * Return a PNG image representation of barcode (requires GD or Imagick library). - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param array $color - * - * @return bool - */ - public function getBarcodePNG($code, $type, $w=3, $h=3, $color=array(0, 0, 0)) - { - //set barcode code and type - $this->setBarcode($code, $type); - $bar = null; - - // calculate image size - $width = ($this->barcodeArray['num_cols'] * $w); - $height = ($this->barcodeArray['num_rows'] * $h); - if (function_exists('imagecreate')) { - // GD library - $imagick = false; - $png = imagecreate($width, $height); - $bgcol = imagecolorallocate($png, 255, 255, 255); - imagecolortransparent($png, $bgcol); - $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); - } elseif (extension_loaded('imagick')) { - $imagick = true; - $fgcol = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')'); - $png = new \Imagick(); - $png->newImage($width, $height, 'none', 'png'); - $bar = new \imagickdraw(); - $bar->setFillColor($fgcol); - } else { - - return false; - } - // print barcode elements - $y = 0; - // for each row - for ($r = 0; $r < $this->barcodeArray['num_rows']; ++$r) { - $x = 0; - // for each column - for ($c = 0; $c < $this->barcodeArray['num_cols']; ++$c) { - if ($this->barcodeArray['bcode'][$r][$c] == 1) { - // draw a single barcode cell - if ($imagick) { - $bar->rectangle($x, $y, ($x + $w), ($y + $h)); - } else { - imagefilledrectangle($png, $x, $y, ($x + $w), ($y + $h), $fgcol); - } - } - $x += $w; - } - $y += $h; - } - // send headers - header('Content-Type: image/png'); - header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 - header('Pragma: public'); - header('Expires: Sat, 12 Nov 1977 23:50:00 GMT'); // Date in the past - header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); - if ($imagick) { - $png->drawimage($bar); - echo $png; - } else { - imagepng($png); - imagedestroy($png); - } - - return true; - } - - /** - * return filename from give path - * - * @todo: refactor this, move method in some kind of utility class - * - * @param string $path - * - * @return mixed - */ - public function getBarcodeFilenameFromGenPath($path) - { - $bcPathArr = explode('/', $path); - return $bcPathArr[count($bcPathArr)-1]; - } - - /** - * Return a .png file path which create in server - * - * @param string $code - * @param string $type - * @param int $w - * @param int $h - * @param array $color - * - * @throws \Exception - * - * @return bool - */ - public function getBarcodePNGPath($code, $type, $name, $w=3, $h=3, $color=array(0, 0, 0)) - { - - //set barcode code and type - $this->setBarcode($code, $type); - $bar = null; - - if (empty($this->barcodeArray) || (!$this->barcodeArray)) { - throw new \Exception('It not possible to generate barcode of type: '.$type.' for number/code: '.$code.'! May be this is an invalid code pattern!'); - } - - // calculate image size - $width = ($this->barcodeArray['num_cols'] * $w); - $height = ($this->barcodeArray['num_rows'] * $h); - if (function_exists('imagecreate')) { - // GD library - $imagick = false; - $png = imagecreate($width, $height); - $bgcol = imagecolorallocate($png, 255, 255, 255); - imagecolortransparent($png, $bgcol); - $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); - } elseif (extension_loaded('imagick')) { - $imagick = true; - $fgcol = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')'); - $png = new \Imagick(); - $png->newImage($width, $height, 'none', 'png'); - $bar = new \imagickdraw(); - $bar->setFillColor($fgcol); - } else { - - return false; - } - // print barcode elements - $y = 0; - // for each row - for ($r = 0; $r < $this->barcodeArray['num_rows']; ++$r) { - $x = 0; - // for each column - for ($c = 0; $c < $this->barcodeArray['num_cols']; ++$c) { - if ($this->barcodeArray['bcode'][$r][$c] == 1) { - // draw a single barcode cell - if ($imagick) { - $bar->rectangle($x, $y, ($x + $w), ($y + $h)); - } else { - imagefilledrectangle($png, $x, $y, ($x + $w), ($y + $h), $fgcol); - } - } - $x += $w; - } - $y += $h; - } - - $nType = str_replace('+', 'PLUS', $type); - - $this->setTempPath($this->savePath); - $saveFile = $this->checkfile($this->savePath . $nType . '_' . $name . '.png', true); - - if ($imagick) { - $png->drawImage($bar); - $png->writeImage($saveFile); - return $saveFile; - } - // ImagePng : weazL - if (imagepng($png, $saveFile)) { - imagedestroy($png); - - return $saveFile; - } else { - imagedestroy($png); - throw new \Exception('It not possible to write barcode cache file to path '.$this->savePath); - } - } - - /** - * Set the barcode. - * - * @param string $code - * @param string $type - */ - public function setBarcode($code, $type) - { - $mode = explode(',', $type); - $qrtype = strtoupper($mode[0]); - switch ($qrtype) { - case 'DATAMATRIX': // DATAMATRIX (ISO/IEC 16022) - $qrcode = new Datamatrix($code); - $this->barcodeArray = $qrcode->getBarcodeArray(); - $this->barcodeArray['code'] = $code; - break; - - case 'PDF417': // PDF417 (ISO/IEC 15438:2006) - if (!isset($mode[1]) || ($mode[1] === '')) { - $aspectratio = 2; // default aspect ratio (width / height) - } else { - $aspectratio = floatval($mode[1]); - } - if (!isset($mode[2]) || ($mode[2] === '')) { - $ecl = -1; // default error correction level (auto) - } else { - $ecl = intval($mode[2]); - } - // set macro block - $macro = array(); - if (isset($mode[3]) && ($mode[3] !== '') && isset($mode[4]) && ($mode[4] !== '') && isset($mode[5]) && ($mode[5] !== '')) { - $macro['segment_total'] = intval($mode[3]); - $macro['segment_index'] = intval($mode[4]); - $macro['file_id'] = strtr($mode[5], "\xff", ','); - for ($i = 0; $i < 7; ++$i) { - $o = $i + 6; - if (isset($mode[$o]) && ($mode[$o] !== '')) { - // add option - $macro['option_' . $i] = strtr($mode[$o], "\xff", ','); - } - } - } - $qrcode = new PDF417($code, $ecl, $aspectratio, $macro); - $this->barcodeArray = $qrcode->getBarcodeArray(); - $this->barcodeArray['code'] = $code; - break; - - case 'QRCODE': // QR-CODE - if (!isset($mode[1]) || (!in_array($mode[1], array('L', 'M', 'Q', 'H')))) { - $mode[1] = 'L'; // Ddefault: Low error correction - } - $qrcode = new QRCode($code, strtoupper($mode[1])); - $this->barcodeArray = $qrcode->getBarcodeArray(); - $this->barcodeArray['code'] = $code; - break; - - case 'RAW': - case 'RAW2': // RAW MODE - // remove spaces - $code = preg_replace('/[\s]*/si', '', $code); - if (strlen($code) < 3) { - break; - } - if ($qrtype == 'RAW') { - // comma-separated rows - $rows = explode(',', $code); - } else { - // rows enclosed in square parentheses - $code = substr($code, 1, -1); - $rows = explode('][', $code); - } - $this->barcodeArray['num_rows'] = count($rows); - $this->barcodeArray['num_cols'] = strlen($rows[0]); - $this->barcodeArray['bcode'] = array(); - foreach ($rows as $r) { - $this->barcodeArray['bcode'][] = str_split($r, 1); - } - $this->barcodeArray['code'] = $code; - break; - - default: - $this->barcodeArray = false; - break; - } - } - - /** - * unlink old barcode image file or optional rand prefix file - * - * @param string $path - * @param bool $overwrite - * - * @return mixed - */ - public function checkfile($path, $overwrite) - { - if (file_exists($path)) { - - if (!$overwrite) { - $baseName = pathinfo($path, PATHINFO_BASENAME); - - return $this->checkfile(str_replace($baseName, rand(0, 9999) . $baseName, $path), $overwrite); - - } else { - - unlink($path); - - } - } - - return $path; - } + // print barcode elements + $y = 0; + // for each row + for ($r = 0; $r < $this->barcodeArray['num_rows']; ++$r) { + $x = 0; + // for each column + for ($c = 0; $c < $this->barcodeArray['num_cols']; ++$c) { + if ($this->barcodeArray['bcode'][$r][$c] == 1) { + // draw a single barcode cell + $svg .= "\t\t" . '' . "\n"; + } + $x += $w; + } + $y += $h; + } + $svg .= "\t" . '' . "\n"; + $svg .= '' . "\n"; + + return $svg; + } + + /** + * Return an HTML representation of barcode. + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param string $color + * + * @return string + */ + public function getBarcodeHTML($code, $type, $w=10, $h=10, $color='black') + { + //set barcode code and type + $this->setBarcode($code, $type); + $html = '
' . "\n"; + // print barcode elements + $y = 0; + // for each row + for ($r = 0; $r < $this->barcodeArray['num_rows']; ++$r) { + $x = 0; + // for each column + for ($c = 0; $c < $this->barcodeArray['num_cols']; ++$c) { + if ($this->barcodeArray['bcode'][$r][$c] == 1) { + // draw a single barcode cell + $html .= '
 
' . "\n"; + } + $x += $w; + } + $y += $h; + } + $html .= '
' . "\n"; + + return $html; + } + + /** + * Return a PNG image representation of barcode (requires GD or Imagick library). + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param array $color + * + * @return bool + */ + public function getBarcodePNG($code, $type, $w=3, $h=3, $color=array(0, 0, 0)) + { + //set barcode code and type + $this->setBarcode($code, $type); + $bar = null; + + // calculate image size + $width = ($this->barcodeArray['num_cols'] * $w); + $height = ($this->barcodeArray['num_rows'] * $h); + if (function_exists('imagecreate')) { + // GD library + $imagick = false; + $png = imagecreate($width, $height); + $bgcol = imagecolorallocate($png, 255, 255, 255); + imagecolortransparent($png, $bgcol); + $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); + } elseif (extension_loaded('imagick')) { + $imagick = true; + $fgcol = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')'); + $png = new \Imagick(); + $png->newImage($width, $height, 'none', 'png'); + $bar = new \imagickdraw(); + $bar->setFillColor($fgcol); + } else { + + return false; + } + // print barcode elements + $y = 0; + // for each row + for ($r = 0; $r < $this->barcodeArray['num_rows']; ++$r) { + $x = 0; + // for each column + for ($c = 0; $c < $this->barcodeArray['num_cols']; ++$c) { + if ($this->barcodeArray['bcode'][$r][$c] == 1) { + // draw a single barcode cell + if ($imagick) { + $bar->rectangle($x, $y, ($x + $w), ($y + $h)); + } else { + imagefilledrectangle($png, $x, $y, ($x + $w), ($y + $h), $fgcol); + } + } + $x += $w; + } + $y += $h; + } + // send headers + header('Content-Type: image/png'); + header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1 + header('Pragma: public'); + header('Expires: Sat, 12 Nov 1977 23:50:00 GMT'); // Date in the past + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + if ($imagick) { + $png->drawimage($bar); + echo $png; + } else { + imagepng($png); + imagedestroy($png); + } + + return true; + } + + /** + * return filename from give path + * + * @todo: refactor this, move method in some kind of utility class + * + * @param string $path + * + * @return mixed + */ + public function getBarcodeFilenameFromGenPath($path) + { + $bcPathArr = explode('/', $path); + return $bcPathArr[count($bcPathArr)-1]; + } + + /** + * Return a .png file path which create in server + * + * @param string $code + * @param string $type + * @param int $w + * @param int $h + * @param array $color + * + * @throws \Exception + * + * @return bool + */ + public function getBarcodePNGPath($code, $type, $name, $w=3, $h=3, $color=array(0, 0, 0)) + { + + //set barcode code and type + $this->setBarcode($code, $type); + $bar = null; + + if (empty($this->barcodeArray) || (!$this->barcodeArray)) { + throw new \Exception('It not possible to generate barcode of type: '.$type.' for number/code: '.$code.'! May be this is an invalid code pattern!'); + } + + // calculate image size + $width = ($this->barcodeArray['num_cols'] * $w); + $height = ($this->barcodeArray['num_rows'] * $h); + if (function_exists('imagecreate')) { + // GD library + $imagick = false; + $png = imagecreate($width, $height); + $bgcol = imagecolorallocate($png, 255, 255, 255); + imagecolortransparent($png, $bgcol); + $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]); + } elseif (extension_loaded('imagick')) { + $imagick = true; + $fgcol = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')'); + $png = new \Imagick(); + $png->newImage($width, $height, 'none', 'png'); + $bar = new \imagickdraw(); + $bar->setFillColor($fgcol); + } else { + + return false; + } + // print barcode elements + $y = 0; + // for each row + for ($r = 0; $r < $this->barcodeArray['num_rows']; ++$r) { + $x = 0; + // for each column + for ($c = 0; $c < $this->barcodeArray['num_cols']; ++$c) { + if ($this->barcodeArray['bcode'][$r][$c] == 1) { + // draw a single barcode cell + if ($imagick) { + $bar->rectangle($x, $y, ($x + $w), ($y + $h)); + } else { + imagefilledrectangle($png, $x, $y, ($x + $w), ($y + $h), $fgcol); + } + } + $x += $w; + } + $y += $h; + } + + $nType = str_replace('+', 'PLUS', $type); + + $this->setTempPath($this->savePath); + $saveFile = $this->checkfile($this->savePath . $nType . '_' . $name . '.png', true); + + if ($imagick) { + $png->drawImage($bar); + $png->writeImage($saveFile); + return $saveFile; + } + // ImagePng : weazL + if (imagepng($png, $saveFile)) { + imagedestroy($png); + + return $saveFile; + } else { + imagedestroy($png); + throw new \Exception('It not possible to write barcode cache file to path '.$this->savePath); + } + } + + /** + * Set the barcode. + * + * @param string $code + * @param string $type + */ + public function setBarcode($code, $type) + { + $mode = explode(',', $type); + $qrtype = strtoupper($mode[0]); + switch ($qrtype) { + case 'DATAMATRIX': // DATAMATRIX (ISO/IEC 16022) + $qrcode = new Datamatrix($code); + $this->barcodeArray = $qrcode->getBarcodeArray(); + $this->barcodeArray['code'] = $code; + break; + + case 'PDF417': // PDF417 (ISO/IEC 15438:2006) + if (!isset($mode[1]) || ($mode[1] === '')) { + $aspectratio = 2; // default aspect ratio (width / height) + } else { + $aspectratio = floatval($mode[1]); + } + if (!isset($mode[2]) || ($mode[2] === '')) { + $ecl = -1; // default error correction level (auto) + } else { + $ecl = intval($mode[2]); + } + // set macro block + $macro = array(); + if (isset($mode[3]) && ($mode[3] !== '') && isset($mode[4]) && ($mode[4] !== '') && isset($mode[5]) && ($mode[5] !== '')) { + $macro['segment_total'] = intval($mode[3]); + $macro['segment_index'] = intval($mode[4]); + $macro['file_id'] = strtr($mode[5], "\xff", ','); + for ($i = 0; $i < 7; ++$i) { + $o = $i + 6; + if (isset($mode[$o]) && ($mode[$o] !== '')) { + // add option + $macro['option_' . $i] = strtr($mode[$o], "\xff", ','); + } + } + } + $qrcode = new PDF417($code, $ecl, $aspectratio, $macro); + $this->barcodeArray = $qrcode->getBarcodeArray(); + $this->barcodeArray['code'] = $code; + break; + + case 'QRCODE': // QR-CODE + if (!isset($mode[1]) || (!in_array($mode[1], array('L', 'M', 'Q', 'H')))) { + $mode[1] = 'L'; // Ddefault: Low error correction + } + $qrcode = new QRCode($code, strtoupper($mode[1])); + $this->barcodeArray = $qrcode->getBarcodeArray(); + $this->barcodeArray['code'] = $code; + break; + + case 'RAW': + case 'RAW2': // RAW MODE + // remove spaces + $code = preg_replace('/[\s]*/si', '', $code); + if (strlen($code) < 3) { + break; + } + if ($qrtype == 'RAW') { + // comma-separated rows + $rows = explode(',', $code); + } else { + // rows enclosed in square parentheses + $code = substr($code, 1, -1); + $rows = explode('][', $code); + } + $this->barcodeArray['num_rows'] = count($rows); + $this->barcodeArray['num_cols'] = strlen($rows[0]); + $this->barcodeArray['bcode'] = array(); + foreach ($rows as $r) { + $this->barcodeArray['bcode'][] = str_split($r, 1); + } + $this->barcodeArray['code'] = $code; + break; + + default: + $this->barcodeArray = false; + break; + } + } + + /** + * unlink old barcode image file or optional rand prefix file + * + * @param string $path + * @param bool $overwrite + * + * @return mixed + */ + public function checkfile($path, $overwrite) + { + if (file_exists($path)) { + + if (!$overwrite) { + $baseName = pathinfo($path, PATHINFO_BASENAME); + + return $this->checkfile(str_replace($baseName, rand(0, 9999) . $baseName, $path), $overwrite); + + } else { + + unlink($path); + + } + } + + return $path; + } } diff --git a/CHANGES b/CHANGES old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/LICENSE.TCPDF b/LICENSE.TCPDF old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/VERSION b/VERSION old mode 100644 new mode 100755 diff --git a/composer.json b/composer.json old mode 100644 new mode 100755 diff --git a/modules/Datamatrix.php b/modules/Datamatrix.php old mode 100644 new mode 100755 index a873d41..b59fdaf --- a/modules/Datamatrix.php +++ b/modules/Datamatrix.php @@ -46,1050 +46,1050 @@ */ class Datamatrix { - const - - DATAMATRIXDEFS = true, - ENC_ASCII = 0, // ASCII encoding: ASCII character 0 to 127 (1 byte per CW) - ENC_C40 = 1, // C40 encoding: Upper-case alphanumeric (3/2 bytes per CW) - ENC_TXT = 2, // TEXT encoding: Lower-case alphanumeric (3/2 bytes per CW) - ENC_X12 = 3, // X12 encoding: ANSI X12 (3/2 byte per CW) - ENC_EDF = 4, // EDIFACT encoding: ASCII character 32 to 94 (4/3 bytes per CW) - ENC_BASE256 = 5, // BASE 256 encoding: ASCII character 0 to 255 (1 byte per CW) - ENC_ASCII_EXT = 6, // ASCII extended encoding: ASCII character 128 to 255 (1/2 byte per CW) - ENC_ASCII_NUM = 7; // ASCII number encoding: ASCII digits (2 bytes per CW) - - protected $barcodeArray = array(); - - protected $lastEnc = self::ENC_ASCII; - - protected $symbattr = array( - array(0x00a,0x00a,0x008,0x008,0x00a,0x00a,0x008,0x008,0x001,0x001,0x001,0x003,0x005,0x001,0x003,0x005), // 10x10 - array(0x00c,0x00c,0x00a,0x00a,0x00c,0x00c,0x00a,0x00a,0x001,0x001,0x001,0x005,0x007,0x001,0x005,0x007), // 12x12 - array(0x00e,0x00e,0x00c,0x00c,0x00e,0x00e,0x00c,0x00c,0x001,0x001,0x001,0x008,0x00a,0x001,0x008,0x00a), // 14x14 - array(0x010,0x010,0x00e,0x00e,0x010,0x010,0x00e,0x00e,0x001,0x001,0x001,0x00c,0x00c,0x001,0x00c,0x00c), // 16x16 - array(0x012,0x012,0x010,0x010,0x012,0x012,0x010,0x010,0x001,0x001,0x001,0x012,0x00e,0x001,0x012,0x00e), // 18x18 - array(0x014,0x014,0x012,0x012,0x014,0x014,0x012,0x012,0x001,0x001,0x001,0x016,0x012,0x001,0x016,0x012), // 20x20 - array(0x016,0x016,0x014,0x014,0x016,0x016,0x014,0x014,0x001,0x001,0x001,0x01e,0x014,0x001,0x01e,0x014), // 22x22 - array(0x018,0x018,0x016,0x016,0x018,0x018,0x016,0x016,0x001,0x001,0x001,0x024,0x018,0x001,0x024,0x018), // 24x24 - array(0x01a,0x01a,0x018,0x018,0x01a,0x01a,0x018,0x018,0x001,0x001,0x001,0x02c,0x01c,0x001,0x02c,0x01c), // 26x26 - array(0x020,0x020,0x01c,0x01c,0x010,0x010,0x00e,0x00e,0x002,0x002,0x004,0x03e,0x024,0x001,0x03e,0x024), // 32x32 - array(0x024,0x024,0x020,0x020,0x012,0x012,0x010,0x010,0x002,0x002,0x004,0x056,0x02a,0x001,0x056,0x02a), // 36x36 - array(0x028,0x028,0x024,0x024,0x014,0x014,0x012,0x012,0x002,0x002,0x004,0x072,0x030,0x001,0x072,0x030), // 40x40 - array(0x02c,0x02c,0x028,0x028,0x016,0x016,0x014,0x014,0x002,0x002,0x004,0x090,0x038,0x001,0x090,0x038), // 44x44 - array(0x030,0x030,0x02c,0x02c,0x018,0x018,0x016,0x016,0x002,0x002,0x004,0x0ae,0x044,0x001,0x0ae,0x044), // 48x48 - array(0x034,0x034,0x030,0x030,0x01a,0x01a,0x018,0x018,0x002,0x002,0x004,0x0cc,0x054,0x002,0x066,0x02a), // 52x52 - array(0x040,0x040,0x038,0x038,0x010,0x010,0x00e,0x00e,0x004,0x004,0x010,0x118,0x070,0x002,0x08c,0x038), // 64x64 - array(0x048,0x048,0x040,0x040,0x012,0x012,0x010,0x010,0x004,0x004,0x010,0x170,0x090,0x004,0x05c,0x024), // 72x72 - array(0x050,0x050,0x048,0x048,0x014,0x014,0x012,0x012,0x004,0x004,0x010,0x1c8,0x0c0,0x004,0x072,0x030), // 80x80 - array(0x058,0x058,0x050,0x050,0x016,0x016,0x014,0x014,0x004,0x004,0x010,0x240,0x0e0,0x004,0x090,0x038), // 88x88 - array(0x060,0x060,0x058,0x058,0x018,0x018,0x016,0x016,0x004,0x004,0x010,0x2b8,0x110,0x004,0x0ae,0x044), // 96x96 - array(0x068,0x068,0x060,0x060,0x01a,0x01a,0x018,0x018,0x004,0x004,0x010,0x330,0x150,0x006,0x088,0x038), // 104x104 - array(0x078,0x078,0x06c,0x06c,0x014,0x014,0x012,0x012,0x006,0x006,0x024,0x41a,0x198,0x006,0x0af,0x044), // 120x120 - array(0x084,0x084,0x078,0x078,0x016,0x016,0x014,0x014,0x006,0x006,0x024,0x518,0x1f0,0x008,0x0a3,0x03e), // 132x132 - array(0x090,0x090,0x084,0x084,0x018,0x018,0x016,0x016,0x006,0x006,0x024,0x616,0x26c,0x00a,0x09c,0x03e), // 144x144 - // rectangular form (currently unused) --------------------------------------------------------------------------- - array(0x008,0x012,0x006,0x010,0x008,0x012,0x006,0x010,0x001,0x001,0x001,0x005,0x007,0x001,0x005,0x007), // 8x18 - array(0x008,0x020,0x006,0x01c,0x008,0x010,0x006,0x00e,0x001,0x002,0x002,0x00a,0x00b,0x001,0x00a,0x00b), // 8x32 - array(0x00c,0x01a,0x00a,0x018,0x00c,0x01a,0x00a,0x018,0x001,0x001,0x001,0x010,0x00e,0x001,0x010,0x00e), // 12x26 - array(0x00c,0x024,0x00a,0x020,0x00c,0x012,0x00a,0x010,0x001,0x002,0x002,0x00c,0x012,0x001,0x00c,0x012), // 12x36 - array(0x010,0x024,0x00e,0x020,0x010,0x012,0x00e,0x010,0x001,0x002,0x002,0x020,0x018,0x001,0x020,0x018), // 16x36 - array(0x010,0x030,0x00e,0x02c,0x010,0x018,0x00e,0x016,0x001,0x002,0x002,0x031,0x01c,0x001,0x031,0x01c) // 16x48 - ); - - protected $chsetId = array(self::ENC_C40 => 'C40', self::ENC_TXT => 'TXT', self::ENC_X12 =>'X12'); - - protected $chset = array( - 'C40' => array( // Basic set for C40 ---------------------------------------------------------------------------- - 'S1'=>0x00,'S2'=>0x01,'S3'=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, // - 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x41=>0x0e,0x42=>0x0f,0x43=>0x10,0x44=>0x11,0x45=>0x12,0x46=>0x13, // - 0x47=>0x14,0x48=>0x15,0x49=>0x16,0x4a=>0x17,0x4b=>0x18,0x4c=>0x19,0x4d=>0x1a,0x4e=>0x1b,0x4f=>0x1c,0x50=>0x1d, // - 0x51=>0x1e,0x52=>0x1f,0x53=>0x20,0x54=>0x21,0x55=>0x22,0x56=>0x23,0x57=>0x24,0x58=>0x25,0x59=>0x26,0x5a=>0x27),// - 'TXT' => array( // Basic set for TEXT --------------------------------------------------------------------------- - 'S1'=>0x00,'S2'=>0x01,'S3'=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, // - 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x61=>0x0e,0x62=>0x0f,0x63=>0x10,0x64=>0x11,0x65=>0x12,0x66=>0x13, // - 0x67=>0x14,0x68=>0x15,0x69=>0x16,0x6a=>0x17,0x6b=>0x18,0x6c=>0x19,0x6d=>0x1a,0x6e=>0x1b,0x6f=>0x1c,0x70=>0x1d, // - 0x71=>0x1e,0x72=>0x1f,0x73=>0x20,0x74=>0x21,0x75=>0x22,0x76=>0x23,0x77=>0x24,0x78=>0x25,0x79=>0x26,0x7a=>0x27),// - 'SH1' => array( // Shift 1 set ---------------------------------------------------------------------------------- - 0x00=>0x00,0x01=>0x01,0x02=>0x02,0x03=>0x03,0x04=>0x04,0x05=>0x05,0x06=>0x06,0x07=>0x07,0x08=>0x08,0x09=>0x09, // - 0x0a=>0x0a,0x0b=>0x0b,0x0c=>0x0c,0x0d=>0x0d,0x0e=>0x0e,0x0f=>0x0f,0x10=>0x10,0x11=>0x11,0x12=>0x12,0x13=>0x13, // - 0x14=>0x14,0x15=>0x15,0x16=>0x16,0x17=>0x17,0x18=>0x18,0x19=>0x19,0x1a=>0x1a,0x1b=>0x1b,0x1c=>0x1c,0x1d=>0x1d, // - 0x1e=>0x1e,0x1f=>0x1f), // - 'SH2' => array( // Shift 2 set ---------------------------------------------------------------------------------- - 0x21=>0x00,0x22=>0x01,0x23=>0x02,0x24=>0x03,0x25=>0x04,0x26=>0x05,0x27=>0x06,0x28=>0x07,0x29=>0x08,0x2a=>0x09, // - 0x2b=>0x0a,0x2c=>0x0b,0x2d=>0x0c,0x2e=>0x0d,0x2f=>0x0e,0x3a=>0x0f,0x3b=>0x10,0x3c=>0x11,0x3d=>0x12,0x3e=>0x13, // - 0x3f=>0x14,0x40=>0x15,0x5b=>0x16,0x5c=>0x17,0x5d=>0x18,0x5e=>0x19,0x5f=>0x1a,'F1'=>0x1b,'US'=>0x1e), // - 'S3C' => array( // Shift 3 set for C40 -------------------------------------------------------------------------- - 0x60=>0x00,0x61=>0x01,0x62=>0x02,0x63=>0x03,0x64=>0x04,0x65=>0x05,0x66=>0x06,0x67=>0x07,0x68=>0x08,0x69=>0x09, // - 0x6a=>0x0a,0x6b=>0x0b,0x6c=>0x0c,0x6d=>0x0d,0x6e=>0x0e,0x6f=>0x0f,0x70=>0x10,0x71=>0x11,0x72=>0x12,0x73=>0x13, // - 0x74=>0x14,0x75=>0x15,0x76=>0x16,0x77=>0x17,0x78=>0x18,0x79=>0x19,0x7a=>0x1a,0x7b=>0x1b,0x7c=>0x1c,0x7d=>0x1d, // - 0x7e=>0x1e,0x7f=>0x1f), - 'S3T' => array( // Shift 3 set for TEXT ------------------------------------------------------------------------- - 0x60=>0x00,0x41=>0x01,0x42=>0x02,0x43=>0x03,0x44=>0x04,0x45=>0x05,0x46=>0x06,0x47=>0x07,0x48=>0x08,0x49=>0x09, // - 0x4a=>0x0a,0x4b=>0x0b,0x4c=>0x0c,0x4d=>0x0d,0x4e=>0x0e,0x4f=>0x0f,0x50=>0x10,0x51=>0x11,0x52=>0x12,0x53=>0x13, // - 0x54=>0x14,0x55=>0x15,0x56=>0x16,0x57=>0x17,0x58=>0x18,0x59=>0x19,0x5a=>0x1a,0x7b=>0x1b,0x7c=>0x1c,0x7d=>0x1d, // - 0x7e=>0x1e,0x7f=>0x1f), // - 'X12' => array( // Set for X12 ---------------------------------------------------------------------------------- - 0x0d=>0x00,0x2a=>0x01,0x3e=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, // - 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x41=>0x0e,0x42=>0x0f,0x43=>0x10,0x44=>0x11,0x45=>0x12,0x46=>0x13, // - 0x47=>0x14,0x48=>0x15,0x49=>0x16,0x4a=>0x17,0x4b=>0x18,0x4c=>0x19,0x4d=>0x1a,0x4e=>0x1b,0x4f=>0x1c,0x50=>0x1d, // - 0x51=>0x1e,0x52=>0x1f,0x53=>0x20,0x54=>0x21,0x55=>0x22,0x56=>0x23,0x57=>0x24,0x58=>0x25,0x59=>0x26,0x5a=>0x27) // - ); - - /** - * @param string $code - */ - public function __construct($code) - { - $params = array(); - - if ((is_null($code)) || ($code == '\0') || ($code == '')) { - return false; - } - // get data codewords - $cw = $this->getHighLevelEncoding($code); - // number of data codewords - $nd = count($cw); - // check size - if ($nd > 1558) { - return false; - } - // get minimum required matrix size. - foreach ($this->symbattr as $params) { - if ($params[11] >= $nd) { - break; - } - } - if ($params[11] < $nd) { - // too much data - return false; - } elseif ($params[11] > $nd) { - // add padding - if ($this->lastEnc == self::ENC_EDF) { - // switch to ASCII encoding - $cw[] = 124; - ++$nd; - } elseif (($this->lastEnc != self::ENC_ASCII) && ($this->lastEnc != self::ENC_BASE256)) { - // switch to ASCII encoding - $cw[] = 254; - ++$nd; - } - if ($params[11] > $nd) { - // add first pad - $cw[] = 129; - ++$nd; - // add remaining pads - for ($i = $nd; $i <= $params[11]; ++$i) { - $cw[] = $this->get253StateCodeword(129, $i); - } - } - } - // add error correction codewords - $cw = $this->getErrorCorrection($cw, $params[13], $params[14], $params[15]); - // initialize empty arrays - // $grid = array_fill(0, ($params[2] * $params[3]), 0); - $grid = array(); - // get placement map - $places = $this->getPlacemetMap($params[2], $params[3]); - $i = 0; - // region data row max index - $rdri = ($params[4] - 1); - // region data column max index - $rdci = ($params[5] - 1); - // for each vertical region - for ($vr = 0; $vr < $params[9]; ++$vr) { - // for each row on region - for ($r = 0; $r < $params[4]; ++$r) { - // get row - $row = (($vr * $params[4]) + $r); - // for each horizontal region - for ($hr = 0; $hr < $params[8]; ++$hr) { - // for each column on region - for ($c = 0; $c < $params[5]; ++$c) { - // get column - $col = (($hr * $params[5]) + $c); - // braw bits by case - if ($r == 0) { - // top finder pattern - if ($c % 2) { - $grid[$row][$col] = 0; - } else { - $grid[$row][$col] = 1; - } - } elseif ($r == $rdri) { - // bottom finder pattern - $grid[$row][$col] = 1; - } elseif ($c == 0) { - // left finder pattern - $grid[$row][$col] = 1; - } elseif ($c == $rdci) { - // right finder pattern - if ($r % 2) { - $grid[$row][$col] = 1; - } else { - $grid[$row][$col] = 0; - } - } else { - if ($places[$i] < 2) { - $grid[$row][$col] = $places[$i]; - } else { - // codeword ID - $cwId = (int) (floor($places[$i] / 10) - 1); - // codeword BIT mask - $cwBit = pow(2, (8 - ($places[$i] % 10))); - $grid[$row][$col] = (($cw[$cwId] & $cwBit) == 0) ? 0 : 1; - } - ++$i; - } - } - } - } - } - $this->barcodeArray['num_rows'] = $params[0]; - $this->barcodeArray['num_cols'] = $params[1]; - $this->barcodeArray['bcode'] = $grid; - - return false; - } - - /** - * Returns a barcode array which is readable by Dinesh Rabara - * @return array barcode array readable by Dinesh Rabara; - * @public - */ - public function getBarcodeArray() - { - return $this->barcodeArray; - } - - /** - * @param int $a - * @param int $b - * @param array $log - * @param array $alog - * @param int $gf - * - * @return int - */ - protected function getGFProduct($a, $b, $log, $alog, $gf) - { - if (($a == 0) || ($b == 0)) { - return 0; - } - - return $alog[($log[$a] + $log[$b]) % ($gf - 1)]; - } - - /** - * Add error correction codewords to data codewords array (ANNEX E). - * - * @param array $wd - * @param int $nb - * @param int $nd - * @param int $nc - * @param int $gf - * @param int $pp - * - * @return mixed - */ - protected function getErrorCorrection($wd, $nb, $nd, $nc, $gf=256, $pp=301) - { - // generate the log ($log) and antilog ($alog) tables - $log[0] = 0; - $alog[0] = 1; - for ($i = 1; $i < $gf; ++$i) { - $alog[$i] = ($alog[($i - 1)] * 2); - if ($alog[$i] >= $gf) { - $alog[$i] ^= $pp; - } - $log[$alog[$i]] = $i; - } - ksort($log); - // generate the polynomial coefficients (c) - $c = array_fill(0, ($nc + 1), 0); - $c[0] = 1; - for ($i = 1; $i <= $nc; ++$i) { - $c[$i] = $c[($i-1)]; - for ($j = ($i - 1); $j >= 1; --$j) { - $c[$j] = $c[($j - 1)] ^ $this->getGFProduct($c[$j], $alog[$i], $log, $alog, $gf); - } - $c[0] = $this->getGFProduct($c[0], $alog[$i], $log, $alog, $gf); - } - ksort($c); - // total number of data codewords - $numWd = ($nb * $nd); - // total number of error codewords - $numWe = ($nb * $nc); - // for each block - for ($b = 0; $b < $nb; ++$b) { - // create interleaved data block - $block = array(); - for ($n = $b; $n < $numWd; $n += $nb) { - $block[] = $wd[$n]; - } - // initialize error codewords - $we = array_fill(0, ($nc + 1), 0); - // calculate error correction codewords for this block - for ($i = 0; $i < $nd; ++$i) { - $k = ($we[0] ^ $block[$i]); - for ($j = 0; $j < $nc; ++$j) { - $we[$j] = ($we[($j + 1)] ^ $this->getGFProduct($k, $c[($nc - $j - 1)], $log, $alog, $gf)); - } - } - // add error codewords at the end of data codewords - $j = 0; - for ($i = $b; $i < $numWe; $i += $nb) { - $wd[($numWd + $i)] = $we[$j]; - ++$j; - } - } - // reorder codewords - ksort($wd); - - return $wd; - } - - /** - * Return the 253-state codeword - * - * @param int $cwpad - * @param int $cwpos - * - * @return int - */ - protected function get253StateCodeword($cwpad, $cwpos) - { - $pad = ($cwpad + (((149 * $cwpos) % 253) + 1)); - if ($pad > 254) { - $pad -= 254; - } - - return $pad; - } - - /** - * Return the 255-state codeword - * - * @param int $cwpad - * @param int $cwpos - * - * @return int - */ - protected function get255StateCodeword($cwpad, $cwpos) - { - $pad = ($cwpad + (((149 * $cwpos) % 255) + 1)); - if ($pad > 255) { - $pad -= 256; - } - - return $pad; - } - - /** - * Returns true if the char belongs to the selected mode - * - * @param int $chr - * @param int $mode - * - * @return bool - */ - protected function isCharMode($chr, $mode) - { - $status = false; - switch ($mode) { - case self::ENC_ASCII: // ASCII character 0 to 127 - $status = (($chr >= 0) && ($chr <= 127)); - break; - - case self::ENC_C40: // Upper-case alphanumeric - $status = (($chr == 32) || (($chr >= 48) && ($chr <= 57)) || (($chr >= 65) && ($chr <= 90))); - break; - - case self::ENC_TXT: // Lower-case alphanumeric - $status = (($chr == 32) || (($chr >= 48) && ($chr <= 57)) || (($chr >= 97) && ($chr <= 122))); - break; - - case self::ENC_X12: // ANSI X12 - $status = (($chr == 13) || ($chr == 42) || ($chr == 62)); - break; - - case self::ENC_EDF: // ASCII character 32 to 94 - $status = (($chr >= 32) && ($chr <= 94)); - break; - - case self::ENC_BASE256: // Function character (FNC1, Structured Append, Reader Program, or Code Page) - $status = (($chr == 232) || ($chr == 233) || ($chr == 234) || ($chr == 241)); - break; - - case self::ENC_ASCII_EXT: // ASCII character 128 to 255 - $status = (($chr >= 128) && ($chr <= 255)); - break; - - case self::ENC_ASCII_NUM: // ASCII digits - $status = (($chr >= 48) && ($chr <= 57)); - break; - - } - - return $status; - } - - /** - * The look-ahead test scans the data to be encoded to find the best mode (Annex P - steps from J to S). - * - * @param string $data - * @param int $pos - * @param int $mode - * - * @return int - */ - protected function lookAheadTest($data, $pos, $mode) - { - $dataLength = strlen($data); - if ($pos >= $dataLength) { - return $mode; - } - $charscount = 0; // count processed chars - // STEP J - if ($mode == self::ENC_ASCII) { - $numch = array(0, 1, 1, 1, 1, 1.25); - } else { - $numch = array(1, 2, 2, 2, 2, 2.25); - $numch[$mode] = 0; - } - while (true) { - // STEP K - if (($pos + $charscount) == $dataLength) { - if ($numch[self::ENC_ASCII] <= ceil(min($numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_EDF], $numch[self::ENC_BASE256]))) { - return self::ENC_ASCII; - } - if ($numch[self::ENC_BASE256] < ceil(min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_EDF]))) { - return self::ENC_BASE256; - } - if ($numch[self::ENC_EDF] < ceil(min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_BASE256]))) { - return self::ENC_EDF; - } - if ($numch[self::ENC_TXT] < ceil(min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_X12], $numch[self::ENC_EDF], $numch[self::ENC_BASE256]))) { - return self::ENC_TXT; - } - if ($numch[self::ENC_X12] < ceil(min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_EDF], $numch[self::ENC_BASE256]))) { - return self::ENC_X12; - } - - return self::ENC_C40; - } - // get char - $chr = ord($data{($pos + $charscount)}); - $charscount++; - // STEP L - if ($this->isCharMode($chr, self::ENC_ASCII_NUM)) { - $numch[self::ENC_ASCII] += (1 / 2); - } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { - $numch[self::ENC_ASCII] = ceil($numch[self::ENC_ASCII]); - $numch[self::ENC_ASCII] += 2; - } else { - $numch[self::ENC_ASCII] = ceil($numch[self::ENC_ASCII]); - $numch[self::ENC_ASCII] += 1; - } - // STEP M - if ($this->isCharMode($chr, self::ENC_C40)) { - $numch[self::ENC_C40] += (2 / 3); - } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { - $numch[self::ENC_C40] += (8 / 3); - } else { - $numch[self::ENC_C40] += (4 / 3); - } - // STEP N - if ($this->isCharMode($chr, self::ENC_TXT)) { - $numch[self::ENC_TXT] += (2 / 3); - } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { - $numch[self::ENC_TXT] += (8 / 3); - } else { - $numch[self::ENC_TXT] += (4 / 3); - } - // STEP O - if ($this->isCharMode($chr, self::ENC_X12) || $this->isCharMode($chr, self::ENC_C40)) { - $numch[self::ENC_X12] += (2 / 3); - } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { - $numch[self::ENC_X12] += (13 / 3); - } else { - $numch[self::ENC_X12] += (10 / 3); - } - // STEP P - if ($this->isCharMode($chr, self::ENC_EDF)) { - $numch[self::ENC_EDF] += (3 / 4); - } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { - $numch[self::ENC_EDF] += (17 / 4); - } else { - $numch[self::ENC_EDF] += (13 / 4); - } - // STEP Q - if ($this->isCharMode($chr, self::ENC_BASE256)) { - $numch[self::ENC_BASE256] += 4; - } else { - $numch[self::ENC_BASE256] += 1; - } - // STEP R - if ($charscount >= 4) { - if (($numch[self::ENC_ASCII] + 1) <= min($numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_EDF], $numch[self::ENC_BASE256])) { - return self::ENC_ASCII; - } - if ((($numch[self::ENC_BASE256] + 1) <= $numch[self::ENC_ASCII]) - || (($numch[self::ENC_BASE256] + 1) < min($numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_EDF]))) { - return self::ENC_BASE256; - } - if (($numch[self::ENC_EDF] + 1) < min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_BASE256])) { - return self::ENC_EDF; - } - if (($numch[self::ENC_TXT] + 1) < min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_X12], $numch[self::ENC_EDF], $numch[self::ENC_BASE256])) { - return self::ENC_TXT; - } - if (($numch[self::ENC_X12] + 1) < min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_EDF], $numch[self::ENC_BASE256])) { - return self::ENC_X12; - } - if (($numch[self::ENC_C40] + 1) < min($numch[self::ENC_ASCII], $numch[self::ENC_TXT], $numch[self::ENC_EDF], $numch[self::ENC_BASE256])) { - if ($numch[self::ENC_C40] < $numch[self::ENC_X12]) { - return self::ENC_C40; - } - if ($numch[self::ENC_C40] == $numch[self::ENC_X12]) { - $k = ($pos + $charscount + 1); - while ($k < $dataLength) { - $tmpchr = ord($data{$k}); - if ($this->isCharMode($tmpchr, self::ENC_X12)) { - return self::ENC_X12; - } elseif (!($this->isCharMode($tmpchr, self::ENC_X12) || $this->isCharMode($tmpchr, self::ENC_C40))) { - break; - } - ++$k; - } - - return self::ENC_C40; - } - } - } - } // end of while - - return true; - } - - /** - * Get the switching codeword to a new encoding mode (latch codeword) - * - * @param int $mode - * - * @return int - */ - protected function getSwitchEncodingCodeword($mode) - { - $cw = 0; - - switch ($mode) { - case self::ENC_ASCII: // ASCII character 0 to 127 - $cw = 254; - break; - - case self::ENC_C40: // Upper-case alphanumeric - $cw = 230; - break; - - case self::ENC_TXT: // Lower-case alphanumeric - $cw = 239; - break; - - case self::ENC_X12: // ANSI X12 - $cw = 238; - break; - - case self::ENC_EDF: // ASCII character 32 to 94 - $cw = 240; - break; - - case self::ENC_BASE256: // Function character (FNC1, Structured Append, Reader Program, or Code Page) - $cw = 231; - break; - - } - - return $cw; - } - - /** - * Choose the minimum matrix size and return the max number of data codewords. - * - * @param int $numcw - * - * @return int - */ - protected function getMaxDataCodewords($numcw) - { - foreach ($this->symbattr as $matrix) { - if ($matrix[11] >= $numcw) { - return $matrix[11]; - } - } - - return 0; - } - - /** - * Get high level encoding using the minimum symbol data characters for ECC 200 - * - * @param string $data - * - * @return array|bool - */ - protected function getHighLevelEncoding($data) - { - // STEP A. Start in ASCII encodation. - $enc = self::ENC_ASCII; // current encoding mode - $chr = 0; - $pos = 0; // current position - $cw = array(); // array of codewords to be returned - $cwNum = 0; // number of data codewords - $dataLenght = strlen($data); // number of chars - while ($pos < $dataLenght) { - switch ($enc) { - case self::ENC_ASCII : // STEP B. While in ASCII encodation - if (($dataLenght > 1) && ($pos < ($dataLenght - 1)) && ($this->isCharMode(ord($data{($pos)}), self::ENC_ASCII_NUM) && $this->isCharMode(ord($data{($pos + 1)}), self::ENC_ASCII_NUM))) { - // 1. If the next data sequence is at least 2 consecutive digits, encode the next two digits as a double digit in ASCII mode. - $cw[] = (intval(substr($data, $pos, 2)) + 130); - ++$cwNum; - $pos += 2; - } else { - // 2. If the look-ahead test (starting at step J) indicates another mode, switch to that mode. - $newenc = $this->lookAheadTest($data, $pos, $enc); - if ($newenc != $enc) { - // switch to new encoding - $enc = $newenc; - $cw[] = $this->getSwitchEncodingCodeword($enc); - ++$cwNum; - } else { - // get new byte - $chr = ord($data{($pos)}); - ++$pos; - if ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { - // 3. If the next data character is extended ASCII (greater than 127) encode it in ASCII mode first using the Upper Shift (value 235) character. - $cw[] = 235; - $cw[] = ($chr - 127); - $cwNum += 2; - } else { - // 4. Otherwise process the next data character in ASCII encodation. - $cw[] = ($chr + 1); - ++$cwNum; - } - } - } - break; - case self::ENC_C40 : // Upper-case alphanumeric - case self::ENC_TXT : // Lower-case alphanumeric - case self::ENC_X12 : // ANSI X12 - $tempCw = array(); - $p = 0; - $epos = $pos; - // get charset ID - $setId = $this->chsetId[$enc]; - // get basic charset for current encoding - $charset = $this->chset[$setId]; - do { - // 2. process the next character in C40 encodation. - $chr = ord($data{($epos)}); - ++$epos; - // check for extended character - if ($chr & 0x80) { - if ($enc == self::ENC_X12) { - return false; - } - $chr = ($chr & 0x7f); - $tempCw[] = 1; // shift 2 - $tempCw[] = 30; // upper shift - $p += 2; - } - if (isset($charset[$chr])) { - $tempCw[] = $charset[$chr]; - ++$p; - } else { - if (isset($this->chset['SH1'][$chr])) { - $tempCw[] = 0; // shift 1 - $shiftset = $this->chset['SH1']; - } elseif (isset($chr, $this->chset['SH2'][$chr])) { - $tempCw[] = 1; // shift 2 - $shiftset = $this->chset['SH2']; - } elseif (($enc == self::ENC_C40) && isset($this->chset['S3C'][$chr])) { - $tempCw[] = 2; // shift 3 - $shiftset = $this->chset['S3C']; - } elseif (($enc == self::ENC_TXT) && isset($this->chset['S3T'][$chr])) { - $tempCw[] = 2; // shift 3 - $shiftset = $this->chset['S3T']; - } else { - return false; - } - $tempCw[] = $shiftset[$chr]; - $p += 2; - } - if ($p >= 3) { - $c1 = array_shift($tempCw); - $c2 = array_shift($tempCw); - $c3 = array_shift($tempCw); - $p -= 3; - $tmp = ((1600 * $c1) + (40 * $c2) + $c3 + 1); - $cw[] = ($tmp >> 8); - $cw[] = ($tmp % 256); - $cwNum += 2; - $pos = $epos; - // 1. If the C40 encoding is at the point of starting a new double symbol character and if the look-ahead test (starting at step J) indicates another mode, switch to that mode. - $newenc = $this->lookAheadTest($data, $pos, $enc); - if ($newenc != $enc) { - $enc = $newenc; - $cw[] = $this->getSwitchEncodingCodeword($enc); - ++$cwNum; - break; - } - } - } while (($p > 0) && ($epos < $dataLenght)); - // process last data (if any) - if ($p > 0) { - // get remaining number of data symbols - $cwr = ($this->getMaxDataCodewords($cwNum + 2) - $cwNum); - if (($cwr == 1) && ($p == 1)) { - // d. If one symbol character remains and one C40 value (data character) remains to be encoded - $c1 = array_shift($tempCw); - --$p; - $cw[] = ($c1 + 1); - ++$cwNum; - } elseif (($cwr == 2) && ($p == 1)) { - // c. If two symbol characters remain and only one C40 value (data character) remains to be encoded - $c1 = array_shift($tempCw); - --$p; - $cw[] = 254; - $cw[] = ($c1 + 1); - $cwNum += 2; - } elseif (($cwr == 2) && ($p == 2)) { - // b. If two symbol characters remain and two C40 values remain to be encoded - $c1 = array_shift($tempCw); - $c2 = array_shift($tempCw); - $p -= 2; - $tmp = ((1600 * $c1) + (40 * $c2) + 1); - $cw[] = ($tmp >> 8); - $cw[] = ($tmp % 256); - $cwNum += 2; - } else { - // switch to ASCII encoding - $enc = self::ENC_ASCII; - $cw[] = $this->getSwitchEncodingCodeword($enc); - ++$cwNum; - } - } - break; - case self::ENC_EDF : // F. While in EDIFACT (EDF) encodation - // initialize temporary array with 0 lenght - $tempCw = array(); - $epos = $pos; - $fieldLenght = 0; - while ($epos < $dataLenght) { - // 2. process the next character in EDIFACT encodation. - $chr = ord($data{($epos)}); - ++$epos; - $tempCw[] = $chr; - ++$fieldLenght; - if (($fieldLenght == 4) || ($epos == $dataLenght)) { - if ($fieldLenght < 4) { - // set unlatch character - $tempCw[] = 0x1f; - ++$fieldLenght; - $enc = self::ENC_ASCII; - // fill empty characters - for ($i = $fieldLenght; $i < 4; ++$i) { - $tempCw[] = 0; - } - } - // encodes four data characters in three codewords - $cw[] = (($tempCw[0] & 0x3F) << 2) + (($tempCw[1] & 0x30) >> 4); - $cw[] = (($tempCw[1] & 0x0F) << 4) + (($tempCw[2] & 0x3C) >> 2); - $cw[] = (($tempCw[2] & 0x03) << 6) + ($tempCw[3] & 0x3F); - $cwNum += 3; - $tempCw = array(); - $pos = $epos; - $fieldLenght = 0; - } - // 1. If the EDIFACT encoding is at the point of starting a new triple symbol character and if the look-ahead test (starting at step J) indicates another mode, switch to that mode. - if ($fieldLenght == 0) { - // get remaining number of data symbols - $cwr = ($this->getMaxDataCodewords($cwNum + 2) - $cwNum); - if ($cwr < 3) { - // return to ascii without unlatch - $enc = self::ENC_ASCII; - break; // exit from EDIFACT mode - } else { - $newenc = $this->lookAheadTest($data, $pos, $enc); - if ($newenc != $enc) { - // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode. - $enc = $newenc; - $cw[] = $this->getSwitchEncodingCodeword($enc); - ++$cwNum; - break; // exit from EDIFACT mode - } - } - } - } - break; - case self::ENC_BASE256 : // G. While in Base 256 (B256) encodation - // initialize temporary array with 0 lenght - $tempCw = array(); - $fieldLenght = 0; - while (($pos < $dataLenght) && ($fieldLenght <= 1555)) { - $newenc = $this->lookAheadTest($data, $pos, $enc); - if ($newenc != $enc) { - // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode. - $enc = $newenc; - $cw[] = $this->getSwitchEncodingCodeword($enc); - ++$cwNum; - break; // exit from B256 mode - } else { - // 2. Otherwise, process the next character in Base 256 encodation. - $chr = ord($data{($pos)}); - ++$pos; - $tempCw[] = $chr; - ++$fieldLenght; - } - } - // set field lenght - if ($fieldLenght <= 249) { - $cw[] = $fieldLenght; - ++$cwNum; - } else { - $cw[] = (floor($fieldLenght / 250) + 249); - $cw[] = ($fieldLenght % 250); - $cwNum += 2; - } - if (!empty($tempCw)) { - // add B256 field - foreach ($tempCw as $p => $cht) { - $cw[] = $this->get255StateCodeword($chr, ($cwNum + $p)); - } - } - break; - - } // end of switch enc - } // end of while - // set last used encoding - $this->lastEnc = $enc; - - return $cw; - } - - /** - * Places "chr+bit" with appropriate wrapping within array[] (Annex F - ECC 200 symbol character placement) - * - * @param array $marr - * @param int $nrow - * @param int $ncol - * @param int $row - * @param int $col - * @param int $chr - * @param int $bit - * - * @return mixed - */ - protected function placeModule($marr, $nrow, $ncol, $row, $col, $chr, $bit) - { - if ($row < 0) { - $row += $nrow; - $col += (4 - (($nrow + 4) % 8)); - } - if ($col < 0) { - $col += $ncol; - $row += (4 - (($ncol + 4) % 8)); - } - $marr[(($row * $ncol) + $col)] = ((10 * $chr) + $bit); - - return $marr; - } - - /** - * Places the 8 bits of a utah-shaped symbol character (Annex F - ECC 200 symbol character placement) - * - * @param array $marr - * @param int $nrow - * @param int $ncol - * @param int $row - * @param int $col - * @param int $chr - * - * @return mixed - */ - protected function placeUtah($marr, $nrow, $ncol, $row, $col, $chr) - { - $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-2, $chr, 1); - $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-1, $chr, 2); - $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-2, $chr, 3); - $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-1, $chr, 4); - $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col, $chr, 5); - $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-2, $chr, 6); - $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-1, $chr, 7); - $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col, $chr, 8); - - return $marr; - } - - /** - * Places the 8 bits of the first special corner case (Annex F - ECC 200 symbol character placement) - * - * @param array $marr - * @param int $nrow - * @param int $ncol - * @param int $chr - * - * @return mixed - */ - protected function placeCornerA($marr, $nrow, $ncol, $chr) - { - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1); - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 1, $chr, 2); - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 2, $chr, 3); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); - $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6); - $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7); - $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8); - - return $marr; - } - - /** - * Places the 8 bits of the second special corner case (Annex F - ECC 200 symbol character placement) - * - * @param array $marr - * @param int $nrow - * @param int $ncol - * @param int $chr - * - * @return mixed - */ - protected function placeCornerB($marr, $nrow, $ncol, $chr) - { - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1); - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2); - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-4, $chr, 4); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 5); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 6); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 7); - $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8); - - return $marr; - } - - /** - * Places the 8 bits of the third special corner case (Annex F - ECC 200 symbol character placement) - * - * @param array $marr - * @param int $nrow - * @param int $ncol - * @param int $chr - * - * @return mixed - */ - protected function placeCornerC($marr, $nrow, $ncol, $chr) - { - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1); - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2); - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); - $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6); - $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7); - $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8); - - return $marr; - } - - /** - * Places the 8 bits of the fourth special corner case (Annex F - ECC 200 symbol character placement) - * - * @param array $marr - * @param int $nrow - * @param int $ncol - * @param int $chr - * - * @return mixed - */ - protected function placeCornerD($marr, $nrow, $ncol, $chr) - { - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1); - $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, $ncol-1, $chr, 2); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 3); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); - $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); - $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-3, $chr, 6); - $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-2, $chr, 7); - $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8); - - return $marr; - } - - /** - * Build a placement map (Annex F - ECC 200 symbol character placement) - * - * @param int $nrow - * @param int $ncol - * - * @return array|mixed - */ - protected function getPlacemetMap($nrow, $ncol) - { - // initialize array with zeros - $marr = array_fill(0, ($nrow * $ncol), 0); - // set starting values - $chr = 1; - $row = 4; - $col = 0; - do { - // repeatedly first check for one of the special corner cases, then - if (($row == $nrow) && ($col == 0)) { - $marr = $this->placeCornerA($marr, $nrow, $ncol, $chr); - ++$chr; - } - if (($row == ($nrow - 2)) && ($col == 0) && ($ncol % 4)) { - $marr = $this->placeCornerB($marr, $nrow, $ncol, $chr); - ++$chr; - } - if (($row == ($nrow - 2)) && ($col == 0) && (($ncol % 8) == 4)) { - $marr = $this->placeCornerC($marr, $nrow, $ncol, $chr); - ++$chr; - } - if (($row == ($nrow + 4)) && ($col == 2) && (!($ncol % 8))) { - $marr = $this->placeCornerD($marr, $nrow, $ncol, $chr); - ++$chr; - } - // sweep upward diagonally, inserting successive characters, - do { - if (($row < $nrow) && ($col >= 0) && (!$marr[(($row * $ncol) + $col)])) { - $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr); - ++$chr; - } - $row -= 2; - $col += 2; - } while (($row >= 0) && ($col < $ncol)); - ++$row; - $col += 3; - // & then sweep downward diagonally, inserting successive characters,... - do { - if (($row >= 0) && ($col < $ncol) && (!$marr[(($row * $ncol) + $col)])) { - $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr); - ++$chr; - } - $row += 2; - $col -= 2; - } while (($row < $nrow) && ($col >= 0)); - $row += 3; - ++$col; - // ... until the entire array is scanned - } while (($row < $nrow) || ($col < $ncol)); - // lastly, if the lower righthand corner is untouched, fill in fixed pattern - if (!$marr[(($nrow * $ncol) - 1)]) { - $marr[(($nrow * $ncol) - 1)] = 1; - $marr[(($nrow * $ncol) - $ncol - 2)] = 1; - } - - return $marr; - } + const + + DATAMATRIXDEFS = true, + ENC_ASCII = 0, // ASCII encoding: ASCII character 0 to 127 (1 byte per CW) + ENC_C40 = 1, // C40 encoding: Upper-case alphanumeric (3/2 bytes per CW) + ENC_TXT = 2, // TEXT encoding: Lower-case alphanumeric (3/2 bytes per CW) + ENC_X12 = 3, // X12 encoding: ANSI X12 (3/2 byte per CW) + ENC_EDF = 4, // EDIFACT encoding: ASCII character 32 to 94 (4/3 bytes per CW) + ENC_BASE256 = 5, // BASE 256 encoding: ASCII character 0 to 255 (1 byte per CW) + ENC_ASCII_EXT = 6, // ASCII extended encoding: ASCII character 128 to 255 (1/2 byte per CW) + ENC_ASCII_NUM = 7; // ASCII number encoding: ASCII digits (2 bytes per CW) + + protected $barcodeArray = array(); + + protected $lastEnc = self::ENC_ASCII; + + protected $symbattr = array( + array(0x00a,0x00a,0x008,0x008,0x00a,0x00a,0x008,0x008,0x001,0x001,0x001,0x003,0x005,0x001,0x003,0x005), // 10x10 + array(0x00c,0x00c,0x00a,0x00a,0x00c,0x00c,0x00a,0x00a,0x001,0x001,0x001,0x005,0x007,0x001,0x005,0x007), // 12x12 + array(0x00e,0x00e,0x00c,0x00c,0x00e,0x00e,0x00c,0x00c,0x001,0x001,0x001,0x008,0x00a,0x001,0x008,0x00a), // 14x14 + array(0x010,0x010,0x00e,0x00e,0x010,0x010,0x00e,0x00e,0x001,0x001,0x001,0x00c,0x00c,0x001,0x00c,0x00c), // 16x16 + array(0x012,0x012,0x010,0x010,0x012,0x012,0x010,0x010,0x001,0x001,0x001,0x012,0x00e,0x001,0x012,0x00e), // 18x18 + array(0x014,0x014,0x012,0x012,0x014,0x014,0x012,0x012,0x001,0x001,0x001,0x016,0x012,0x001,0x016,0x012), // 20x20 + array(0x016,0x016,0x014,0x014,0x016,0x016,0x014,0x014,0x001,0x001,0x001,0x01e,0x014,0x001,0x01e,0x014), // 22x22 + array(0x018,0x018,0x016,0x016,0x018,0x018,0x016,0x016,0x001,0x001,0x001,0x024,0x018,0x001,0x024,0x018), // 24x24 + array(0x01a,0x01a,0x018,0x018,0x01a,0x01a,0x018,0x018,0x001,0x001,0x001,0x02c,0x01c,0x001,0x02c,0x01c), // 26x26 + array(0x020,0x020,0x01c,0x01c,0x010,0x010,0x00e,0x00e,0x002,0x002,0x004,0x03e,0x024,0x001,0x03e,0x024), // 32x32 + array(0x024,0x024,0x020,0x020,0x012,0x012,0x010,0x010,0x002,0x002,0x004,0x056,0x02a,0x001,0x056,0x02a), // 36x36 + array(0x028,0x028,0x024,0x024,0x014,0x014,0x012,0x012,0x002,0x002,0x004,0x072,0x030,0x001,0x072,0x030), // 40x40 + array(0x02c,0x02c,0x028,0x028,0x016,0x016,0x014,0x014,0x002,0x002,0x004,0x090,0x038,0x001,0x090,0x038), // 44x44 + array(0x030,0x030,0x02c,0x02c,0x018,0x018,0x016,0x016,0x002,0x002,0x004,0x0ae,0x044,0x001,0x0ae,0x044), // 48x48 + array(0x034,0x034,0x030,0x030,0x01a,0x01a,0x018,0x018,0x002,0x002,0x004,0x0cc,0x054,0x002,0x066,0x02a), // 52x52 + array(0x040,0x040,0x038,0x038,0x010,0x010,0x00e,0x00e,0x004,0x004,0x010,0x118,0x070,0x002,0x08c,0x038), // 64x64 + array(0x048,0x048,0x040,0x040,0x012,0x012,0x010,0x010,0x004,0x004,0x010,0x170,0x090,0x004,0x05c,0x024), // 72x72 + array(0x050,0x050,0x048,0x048,0x014,0x014,0x012,0x012,0x004,0x004,0x010,0x1c8,0x0c0,0x004,0x072,0x030), // 80x80 + array(0x058,0x058,0x050,0x050,0x016,0x016,0x014,0x014,0x004,0x004,0x010,0x240,0x0e0,0x004,0x090,0x038), // 88x88 + array(0x060,0x060,0x058,0x058,0x018,0x018,0x016,0x016,0x004,0x004,0x010,0x2b8,0x110,0x004,0x0ae,0x044), // 96x96 + array(0x068,0x068,0x060,0x060,0x01a,0x01a,0x018,0x018,0x004,0x004,0x010,0x330,0x150,0x006,0x088,0x038), // 104x104 + array(0x078,0x078,0x06c,0x06c,0x014,0x014,0x012,0x012,0x006,0x006,0x024,0x41a,0x198,0x006,0x0af,0x044), // 120x120 + array(0x084,0x084,0x078,0x078,0x016,0x016,0x014,0x014,0x006,0x006,0x024,0x518,0x1f0,0x008,0x0a3,0x03e), // 132x132 + array(0x090,0x090,0x084,0x084,0x018,0x018,0x016,0x016,0x006,0x006,0x024,0x616,0x26c,0x00a,0x09c,0x03e), // 144x144 + // rectangular form (currently unused) --------------------------------------------------------------------------- + array(0x008,0x012,0x006,0x010,0x008,0x012,0x006,0x010,0x001,0x001,0x001,0x005,0x007,0x001,0x005,0x007), // 8x18 + array(0x008,0x020,0x006,0x01c,0x008,0x010,0x006,0x00e,0x001,0x002,0x002,0x00a,0x00b,0x001,0x00a,0x00b), // 8x32 + array(0x00c,0x01a,0x00a,0x018,0x00c,0x01a,0x00a,0x018,0x001,0x001,0x001,0x010,0x00e,0x001,0x010,0x00e), // 12x26 + array(0x00c,0x024,0x00a,0x020,0x00c,0x012,0x00a,0x010,0x001,0x002,0x002,0x00c,0x012,0x001,0x00c,0x012), // 12x36 + array(0x010,0x024,0x00e,0x020,0x010,0x012,0x00e,0x010,0x001,0x002,0x002,0x020,0x018,0x001,0x020,0x018), // 16x36 + array(0x010,0x030,0x00e,0x02c,0x010,0x018,0x00e,0x016,0x001,0x002,0x002,0x031,0x01c,0x001,0x031,0x01c) // 16x48 + ); + + protected $chsetId = array(self::ENC_C40 => 'C40', self::ENC_TXT => 'TXT', self::ENC_X12 =>'X12'); + + protected $chset = array( + 'C40' => array( // Basic set for C40 ---------------------------------------------------------------------------- + 'S1'=>0x00,'S2'=>0x01,'S3'=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, // + 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x41=>0x0e,0x42=>0x0f,0x43=>0x10,0x44=>0x11,0x45=>0x12,0x46=>0x13, // + 0x47=>0x14,0x48=>0x15,0x49=>0x16,0x4a=>0x17,0x4b=>0x18,0x4c=>0x19,0x4d=>0x1a,0x4e=>0x1b,0x4f=>0x1c,0x50=>0x1d, // + 0x51=>0x1e,0x52=>0x1f,0x53=>0x20,0x54=>0x21,0x55=>0x22,0x56=>0x23,0x57=>0x24,0x58=>0x25,0x59=>0x26,0x5a=>0x27),// + 'TXT' => array( // Basic set for TEXT --------------------------------------------------------------------------- + 'S1'=>0x00,'S2'=>0x01,'S3'=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, // + 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x61=>0x0e,0x62=>0x0f,0x63=>0x10,0x64=>0x11,0x65=>0x12,0x66=>0x13, // + 0x67=>0x14,0x68=>0x15,0x69=>0x16,0x6a=>0x17,0x6b=>0x18,0x6c=>0x19,0x6d=>0x1a,0x6e=>0x1b,0x6f=>0x1c,0x70=>0x1d, // + 0x71=>0x1e,0x72=>0x1f,0x73=>0x20,0x74=>0x21,0x75=>0x22,0x76=>0x23,0x77=>0x24,0x78=>0x25,0x79=>0x26,0x7a=>0x27),// + 'SH1' => array( // Shift 1 set ---------------------------------------------------------------------------------- + 0x00=>0x00,0x01=>0x01,0x02=>0x02,0x03=>0x03,0x04=>0x04,0x05=>0x05,0x06=>0x06,0x07=>0x07,0x08=>0x08,0x09=>0x09, // + 0x0a=>0x0a,0x0b=>0x0b,0x0c=>0x0c,0x0d=>0x0d,0x0e=>0x0e,0x0f=>0x0f,0x10=>0x10,0x11=>0x11,0x12=>0x12,0x13=>0x13, // + 0x14=>0x14,0x15=>0x15,0x16=>0x16,0x17=>0x17,0x18=>0x18,0x19=>0x19,0x1a=>0x1a,0x1b=>0x1b,0x1c=>0x1c,0x1d=>0x1d, // + 0x1e=>0x1e,0x1f=>0x1f), // + 'SH2' => array( // Shift 2 set ---------------------------------------------------------------------------------- + 0x21=>0x00,0x22=>0x01,0x23=>0x02,0x24=>0x03,0x25=>0x04,0x26=>0x05,0x27=>0x06,0x28=>0x07,0x29=>0x08,0x2a=>0x09, // + 0x2b=>0x0a,0x2c=>0x0b,0x2d=>0x0c,0x2e=>0x0d,0x2f=>0x0e,0x3a=>0x0f,0x3b=>0x10,0x3c=>0x11,0x3d=>0x12,0x3e=>0x13, // + 0x3f=>0x14,0x40=>0x15,0x5b=>0x16,0x5c=>0x17,0x5d=>0x18,0x5e=>0x19,0x5f=>0x1a,'F1'=>0x1b,'US'=>0x1e), // + 'S3C' => array( // Shift 3 set for C40 -------------------------------------------------------------------------- + 0x60=>0x00,0x61=>0x01,0x62=>0x02,0x63=>0x03,0x64=>0x04,0x65=>0x05,0x66=>0x06,0x67=>0x07,0x68=>0x08,0x69=>0x09, // + 0x6a=>0x0a,0x6b=>0x0b,0x6c=>0x0c,0x6d=>0x0d,0x6e=>0x0e,0x6f=>0x0f,0x70=>0x10,0x71=>0x11,0x72=>0x12,0x73=>0x13, // + 0x74=>0x14,0x75=>0x15,0x76=>0x16,0x77=>0x17,0x78=>0x18,0x79=>0x19,0x7a=>0x1a,0x7b=>0x1b,0x7c=>0x1c,0x7d=>0x1d, // + 0x7e=>0x1e,0x7f=>0x1f), + 'S3T' => array( // Shift 3 set for TEXT ------------------------------------------------------------------------- + 0x60=>0x00,0x41=>0x01,0x42=>0x02,0x43=>0x03,0x44=>0x04,0x45=>0x05,0x46=>0x06,0x47=>0x07,0x48=>0x08,0x49=>0x09, // + 0x4a=>0x0a,0x4b=>0x0b,0x4c=>0x0c,0x4d=>0x0d,0x4e=>0x0e,0x4f=>0x0f,0x50=>0x10,0x51=>0x11,0x52=>0x12,0x53=>0x13, // + 0x54=>0x14,0x55=>0x15,0x56=>0x16,0x57=>0x17,0x58=>0x18,0x59=>0x19,0x5a=>0x1a,0x7b=>0x1b,0x7c=>0x1c,0x7d=>0x1d, // + 0x7e=>0x1e,0x7f=>0x1f), // + 'X12' => array( // Set for X12 ---------------------------------------------------------------------------------- + 0x0d=>0x00,0x2a=>0x01,0x3e=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, // + 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x41=>0x0e,0x42=>0x0f,0x43=>0x10,0x44=>0x11,0x45=>0x12,0x46=>0x13, // + 0x47=>0x14,0x48=>0x15,0x49=>0x16,0x4a=>0x17,0x4b=>0x18,0x4c=>0x19,0x4d=>0x1a,0x4e=>0x1b,0x4f=>0x1c,0x50=>0x1d, // + 0x51=>0x1e,0x52=>0x1f,0x53=>0x20,0x54=>0x21,0x55=>0x22,0x56=>0x23,0x57=>0x24,0x58=>0x25,0x59=>0x26,0x5a=>0x27) // + ); + + /** + * @param string $code + */ + public function __construct($code) + { + $params = array(); + + if ((is_null($code)) || ($code == '\0') || ($code == '')) { + return false; + } + // get data codewords + $cw = $this->getHighLevelEncoding($code); + // number of data codewords + $nd = count($cw); + // check size + if ($nd > 1558) { + return false; + } + // get minimum required matrix size. + foreach ($this->symbattr as $params) { + if ($params[11] >= $nd) { + break; + } + } + if ($params[11] < $nd) { + // too much data + return false; + } elseif ($params[11] > $nd) { + // add padding + if ($this->lastEnc == self::ENC_EDF) { + // switch to ASCII encoding + $cw[] = 124; + ++$nd; + } elseif (($this->lastEnc != self::ENC_ASCII) && ($this->lastEnc != self::ENC_BASE256)) { + // switch to ASCII encoding + $cw[] = 254; + ++$nd; + } + if ($params[11] > $nd) { + // add first pad + $cw[] = 129; + ++$nd; + // add remaining pads + for ($i = $nd; $i <= $params[11]; ++$i) { + $cw[] = $this->get253StateCodeword(129, $i); + } + } + } + // add error correction codewords + $cw = $this->getErrorCorrection($cw, $params[13], $params[14], $params[15]); + // initialize empty arrays + // $grid = array_fill(0, ($params[2] * $params[3]), 0); + $grid = array(); + // get placement map + $places = $this->getPlacemetMap($params[2], $params[3]); + $i = 0; + // region data row max index + $rdri = ($params[4] - 1); + // region data column max index + $rdci = ($params[5] - 1); + // for each vertical region + for ($vr = 0; $vr < $params[9]; ++$vr) { + // for each row on region + for ($r = 0; $r < $params[4]; ++$r) { + // get row + $row = (($vr * $params[4]) + $r); + // for each horizontal region + for ($hr = 0; $hr < $params[8]; ++$hr) { + // for each column on region + for ($c = 0; $c < $params[5]; ++$c) { + // get column + $col = (($hr * $params[5]) + $c); + // braw bits by case + if ($r == 0) { + // top finder pattern + if ($c % 2) { + $grid[$row][$col] = 0; + } else { + $grid[$row][$col] = 1; + } + } elseif ($r == $rdri) { + // bottom finder pattern + $grid[$row][$col] = 1; + } elseif ($c == 0) { + // left finder pattern + $grid[$row][$col] = 1; + } elseif ($c == $rdci) { + // right finder pattern + if ($r % 2) { + $grid[$row][$col] = 1; + } else { + $grid[$row][$col] = 0; + } + } else { + if ($places[$i] < 2) { + $grid[$row][$col] = $places[$i]; + } else { + // codeword ID + $cwId = (int) (floor($places[$i] / 10) - 1); + // codeword BIT mask + $cwBit = pow(2, (8 - ($places[$i] % 10))); + $grid[$row][$col] = (($cw[$cwId] & $cwBit) == 0) ? 0 : 1; + } + ++$i; + } + } + } + } + } + $this->barcodeArray['num_rows'] = $params[0]; + $this->barcodeArray['num_cols'] = $params[1]; + $this->barcodeArray['bcode'] = $grid; + + return false; + } + + /** + * Returns a barcode array which is readable by Dinesh Rabara + * @return array barcode array readable by Dinesh Rabara; + * @public + */ + public function getBarcodeArray() + { + return $this->barcodeArray; + } + + /** + * @param int $a + * @param int $b + * @param array $log + * @param array $alog + * @param int $gf + * + * @return int + */ + protected function getGFProduct($a, $b, $log, $alog, $gf) + { + if (($a == 0) || ($b == 0)) { + return 0; + } + + return $alog[($log[$a] + $log[$b]) % ($gf - 1)]; + } + + /** + * Add error correction codewords to data codewords array (ANNEX E). + * + * @param array $wd + * @param int $nb + * @param int $nd + * @param int $nc + * @param int $gf + * @param int $pp + * + * @return mixed + */ + protected function getErrorCorrection($wd, $nb, $nd, $nc, $gf=256, $pp=301) + { + // generate the log ($log) and antilog ($alog) tables + $log[0] = 0; + $alog[0] = 1; + for ($i = 1; $i < $gf; ++$i) { + $alog[$i] = ($alog[($i - 1)] * 2); + if ($alog[$i] >= $gf) { + $alog[$i] ^= $pp; + } + $log[$alog[$i]] = $i; + } + ksort($log); + // generate the polynomial coefficients (c) + $c = array_fill(0, ($nc + 1), 0); + $c[0] = 1; + for ($i = 1; $i <= $nc; ++$i) { + $c[$i] = $c[($i-1)]; + for ($j = ($i - 1); $j >= 1; --$j) { + $c[$j] = $c[($j - 1)] ^ $this->getGFProduct($c[$j], $alog[$i], $log, $alog, $gf); + } + $c[0] = $this->getGFProduct($c[0], $alog[$i], $log, $alog, $gf); + } + ksort($c); + // total number of data codewords + $numWd = ($nb * $nd); + // total number of error codewords + $numWe = ($nb * $nc); + // for each block + for ($b = 0; $b < $nb; ++$b) { + // create interleaved data block + $block = array(); + for ($n = $b; $n < $numWd; $n += $nb) { + $block[] = $wd[$n]; + } + // initialize error codewords + $we = array_fill(0, ($nc + 1), 0); + // calculate error correction codewords for this block + for ($i = 0; $i < $nd; ++$i) { + $k = ($we[0] ^ $block[$i]); + for ($j = 0; $j < $nc; ++$j) { + $we[$j] = ($we[($j + 1)] ^ $this->getGFProduct($k, $c[($nc - $j - 1)], $log, $alog, $gf)); + } + } + // add error codewords at the end of data codewords + $j = 0; + for ($i = $b; $i < $numWe; $i += $nb) { + $wd[($numWd + $i)] = $we[$j]; + ++$j; + } + } + // reorder codewords + ksort($wd); + + return $wd; + } + + /** + * Return the 253-state codeword + * + * @param int $cwpad + * @param int $cwpos + * + * @return int + */ + protected function get253StateCodeword($cwpad, $cwpos) + { + $pad = ($cwpad + (((149 * $cwpos) % 253) + 1)); + if ($pad > 254) { + $pad -= 254; + } + + return $pad; + } + + /** + * Return the 255-state codeword + * + * @param int $cwpad + * @param int $cwpos + * + * @return int + */ + protected function get255StateCodeword($cwpad, $cwpos) + { + $pad = ($cwpad + (((149 * $cwpos) % 255) + 1)); + if ($pad > 255) { + $pad -= 256; + } + + return $pad; + } + + /** + * Returns true if the char belongs to the selected mode + * + * @param int $chr + * @param int $mode + * + * @return bool + */ + protected function isCharMode($chr, $mode) + { + $status = false; + switch ($mode) { + case self::ENC_ASCII: // ASCII character 0 to 127 + $status = (($chr >= 0) && ($chr <= 127)); + break; + + case self::ENC_C40: // Upper-case alphanumeric + $status = (($chr == 32) || (($chr >= 48) && ($chr <= 57)) || (($chr >= 65) && ($chr <= 90))); + break; + + case self::ENC_TXT: // Lower-case alphanumeric + $status = (($chr == 32) || (($chr >= 48) && ($chr <= 57)) || (($chr >= 97) && ($chr <= 122))); + break; + + case self::ENC_X12: // ANSI X12 + $status = (($chr == 13) || ($chr == 42) || ($chr == 62)); + break; + + case self::ENC_EDF: // ASCII character 32 to 94 + $status = (($chr >= 32) && ($chr <= 94)); + break; + + case self::ENC_BASE256: // Function character (FNC1, Structured Append, Reader Program, or Code Page) + $status = (($chr == 232) || ($chr == 233) || ($chr == 234) || ($chr == 241)); + break; + + case self::ENC_ASCII_EXT: // ASCII character 128 to 255 + $status = (($chr >= 128) && ($chr <= 255)); + break; + + case self::ENC_ASCII_NUM: // ASCII digits + $status = (($chr >= 48) && ($chr <= 57)); + break; + + } + + return $status; + } + + /** + * The look-ahead test scans the data to be encoded to find the best mode (Annex P - steps from J to S). + * + * @param string $data + * @param int $pos + * @param int $mode + * + * @return int + */ + protected function lookAheadTest($data, $pos, $mode) + { + $dataLength = strlen($data); + if ($pos >= $dataLength) { + return $mode; + } + $charscount = 0; // count processed chars + // STEP J + if ($mode == self::ENC_ASCII) { + $numch = array(0, 1, 1, 1, 1, 1.25); + } else { + $numch = array(1, 2, 2, 2, 2, 2.25); + $numch[$mode] = 0; + } + while (true) { + // STEP K + if (($pos + $charscount) == $dataLength) { + if ($numch[self::ENC_ASCII] <= ceil(min($numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_EDF], $numch[self::ENC_BASE256]))) { + return self::ENC_ASCII; + } + if ($numch[self::ENC_BASE256] < ceil(min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_EDF]))) { + return self::ENC_BASE256; + } + if ($numch[self::ENC_EDF] < ceil(min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_BASE256]))) { + return self::ENC_EDF; + } + if ($numch[self::ENC_TXT] < ceil(min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_X12], $numch[self::ENC_EDF], $numch[self::ENC_BASE256]))) { + return self::ENC_TXT; + } + if ($numch[self::ENC_X12] < ceil(min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_EDF], $numch[self::ENC_BASE256]))) { + return self::ENC_X12; + } + + return self::ENC_C40; + } + // get char + $chr = ord($data[($pos + $charscount)]); + $charscount++; + // STEP L + if ($this->isCharMode($chr, self::ENC_ASCII_NUM)) { + $numch[self::ENC_ASCII] += (1 / 2); + } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { + $numch[self::ENC_ASCII] = ceil($numch[self::ENC_ASCII]); + $numch[self::ENC_ASCII] += 2; + } else { + $numch[self::ENC_ASCII] = ceil($numch[self::ENC_ASCII]); + $numch[self::ENC_ASCII] += 1; + } + // STEP M + if ($this->isCharMode($chr, self::ENC_C40)) { + $numch[self::ENC_C40] += (2 / 3); + } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { + $numch[self::ENC_C40] += (8 / 3); + } else { + $numch[self::ENC_C40] += (4 / 3); + } + // STEP N + if ($this->isCharMode($chr, self::ENC_TXT)) { + $numch[self::ENC_TXT] += (2 / 3); + } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { + $numch[self::ENC_TXT] += (8 / 3); + } else { + $numch[self::ENC_TXT] += (4 / 3); + } + // STEP O + if ($this->isCharMode($chr, self::ENC_X12) || $this->isCharMode($chr, self::ENC_C40)) { + $numch[self::ENC_X12] += (2 / 3); + } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { + $numch[self::ENC_X12] += (13 / 3); + } else { + $numch[self::ENC_X12] += (10 / 3); + } + // STEP P + if ($this->isCharMode($chr, self::ENC_EDF)) { + $numch[self::ENC_EDF] += (3 / 4); + } elseif ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { + $numch[self::ENC_EDF] += (17 / 4); + } else { + $numch[self::ENC_EDF] += (13 / 4); + } + // STEP Q + if ($this->isCharMode($chr, self::ENC_BASE256)) { + $numch[self::ENC_BASE256] += 4; + } else { + $numch[self::ENC_BASE256] += 1; + } + // STEP R + if ($charscount >= 4) { + if (($numch[self::ENC_ASCII] + 1) <= min($numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_EDF], $numch[self::ENC_BASE256])) { + return self::ENC_ASCII; + } + if ((($numch[self::ENC_BASE256] + 1) <= $numch[self::ENC_ASCII]) + || (($numch[self::ENC_BASE256] + 1) < min($numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_EDF]))) { + return self::ENC_BASE256; + } + if (($numch[self::ENC_EDF] + 1) < min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_X12], $numch[self::ENC_BASE256])) { + return self::ENC_EDF; + } + if (($numch[self::ENC_TXT] + 1) < min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_X12], $numch[self::ENC_EDF], $numch[self::ENC_BASE256])) { + return self::ENC_TXT; + } + if (($numch[self::ENC_X12] + 1) < min($numch[self::ENC_ASCII], $numch[self::ENC_C40], $numch[self::ENC_TXT], $numch[self::ENC_EDF], $numch[self::ENC_BASE256])) { + return self::ENC_X12; + } + if (($numch[self::ENC_C40] + 1) < min($numch[self::ENC_ASCII], $numch[self::ENC_TXT], $numch[self::ENC_EDF], $numch[self::ENC_BASE256])) { + if ($numch[self::ENC_C40] < $numch[self::ENC_X12]) { + return self::ENC_C40; + } + if ($numch[self::ENC_C40] == $numch[self::ENC_X12]) { + $k = ($pos + $charscount + 1); + while ($k < $dataLength) { + $tmpchr = ord($data[$k]); + if ($this->isCharMode($tmpchr, self::ENC_X12)) { + return self::ENC_X12; + } elseif (!($this->isCharMode($tmpchr, self::ENC_X12) || $this->isCharMode($tmpchr, self::ENC_C40))) { + break; + } + ++$k; + } + + return self::ENC_C40; + } + } + } + } // end of while + + return true; + } + + /** + * Get the switching codeword to a new encoding mode (latch codeword) + * + * @param int $mode + * + * @return int + */ + protected function getSwitchEncodingCodeword($mode) + { + $cw = 0; + + switch ($mode) { + case self::ENC_ASCII: // ASCII character 0 to 127 + $cw = 254; + break; + + case self::ENC_C40: // Upper-case alphanumeric + $cw = 230; + break; + + case self::ENC_TXT: // Lower-case alphanumeric + $cw = 239; + break; + + case self::ENC_X12: // ANSI X12 + $cw = 238; + break; + + case self::ENC_EDF: // ASCII character 32 to 94 + $cw = 240; + break; + + case self::ENC_BASE256: // Function character (FNC1, Structured Append, Reader Program, or Code Page) + $cw = 231; + break; + + } + + return $cw; + } + + /** + * Choose the minimum matrix size and return the max number of data codewords. + * + * @param int $numcw + * + * @return int + */ + protected function getMaxDataCodewords($numcw) + { + foreach ($this->symbattr as $matrix) { + if ($matrix[11] >= $numcw) { + return $matrix[11]; + } + } + + return 0; + } + + /** + * Get high level encoding using the minimum symbol data characters for ECC 200 + * + * @param string $data + * + * @return array|bool + */ + protected function getHighLevelEncoding($data) + { + // STEP A. Start in ASCII encodation. + $enc = self::ENC_ASCII; // current encoding mode + $chr = 0; + $pos = 0; // current position + $cw = array(); // array of codewords to be returned + $cwNum = 0; // number of data codewords + $dataLenght = strlen($data); // number of chars + while ($pos < $dataLenght) { + switch ($enc) { + case self::ENC_ASCII : // STEP B. While in ASCII encodation + if (($dataLenght > 1) && ($pos < ($dataLenght - 1)) && ($this->isCharMode(ord($data[($pos)]), self::ENC_ASCII_NUM) && $this->isCharMode(ord($data[($pos + 1)]), self::ENC_ASCII_NUM))) { + // 1. If the next data sequence is at least 2 consecutive digits, encode the next two digits as a double digit in ASCII mode. + $cw[] = (intval(substr($data, $pos, 2)) + 130); + ++$cwNum; + $pos += 2; + } else { + // 2. If the look-ahead test (starting at step J) indicates another mode, switch to that mode. + $newenc = $this->lookAheadTest($data, $pos, $enc); + if ($newenc != $enc) { + // switch to new encoding + $enc = $newenc; + $cw[] = $this->getSwitchEncodingCodeword($enc); + ++$cwNum; + } else { + // get new byte + $chr = ord($data[($pos)]); + ++$pos; + if ($this->isCharMode($chr, self::ENC_ASCII_EXT)) { + // 3. If the next data character is extended ASCII (greater than 127) encode it in ASCII mode first using the Upper Shift (value 235) character. + $cw[] = 235; + $cw[] = ($chr - 127); + $cwNum += 2; + } else { + // 4. Otherwise process the next data character in ASCII encodation. + $cw[] = ($chr + 1); + ++$cwNum; + } + } + } + break; + case self::ENC_C40 : // Upper-case alphanumeric + case self::ENC_TXT : // Lower-case alphanumeric + case self::ENC_X12 : // ANSI X12 + $tempCw = array(); + $p = 0; + $epos = $pos; + // get charset ID + $setId = $this->chsetId[$enc]; + // get basic charset for current encoding + $charset = $this->chset[$setId]; + do { + // 2. process the next character in C40 encodation. + $chr = ord($data[($epos)]); + ++$epos; + // check for extended character + if ($chr & 0x80) { + if ($enc == self::ENC_X12) { + return false; + } + $chr = ($chr & 0x7f); + $tempCw[] = 1; // shift 2 + $tempCw[] = 30; // upper shift + $p += 2; + } + if (isset($charset[$chr])) { + $tempCw[] = $charset[$chr]; + ++$p; + } else { + if (isset($this->chset['SH1'][$chr])) { + $tempCw[] = 0; // shift 1 + $shiftset = $this->chset['SH1']; + } elseif (isset($chr, $this->chset['SH2'][$chr])) { + $tempCw[] = 1; // shift 2 + $shiftset = $this->chset['SH2']; + } elseif (($enc == self::ENC_C40) && isset($this->chset['S3C'][$chr])) { + $tempCw[] = 2; // shift 3 + $shiftset = $this->chset['S3C']; + } elseif (($enc == self::ENC_TXT) && isset($this->chset['S3T'][$chr])) { + $tempCw[] = 2; // shift 3 + $shiftset = $this->chset['S3T']; + } else { + return false; + } + $tempCw[] = $shiftset[$chr]; + $p += 2; + } + if ($p >= 3) { + $c1 = array_shift($tempCw); + $c2 = array_shift($tempCw); + $c3 = array_shift($tempCw); + $p -= 3; + $tmp = ((1600 * $c1) + (40 * $c2) + $c3 + 1); + $cw[] = ($tmp >> 8); + $cw[] = ($tmp % 256); + $cwNum += 2; + $pos = $epos; + // 1. If the C40 encoding is at the point of starting a new double symbol character and if the look-ahead test (starting at step J) indicates another mode, switch to that mode. + $newenc = $this->lookAheadTest($data, $pos, $enc); + if ($newenc != $enc) { + $enc = $newenc; + $cw[] = $this->getSwitchEncodingCodeword($enc); + ++$cwNum; + break; + } + } + } while (($p > 0) && ($epos < $dataLenght)); + // process last data (if any) + if ($p > 0) { + // get remaining number of data symbols + $cwr = ($this->getMaxDataCodewords($cwNum + 2) - $cwNum); + if (($cwr == 1) && ($p == 1)) { + // d. If one symbol character remains and one C40 value (data character) remains to be encoded + $c1 = array_shift($tempCw); + --$p; + $cw[] = ($c1 + 1); + ++$cwNum; + } elseif (($cwr == 2) && ($p == 1)) { + // c. If two symbol characters remain and only one C40 value (data character) remains to be encoded + $c1 = array_shift($tempCw); + --$p; + $cw[] = 254; + $cw[] = ($c1 + 1); + $cwNum += 2; + } elseif (($cwr == 2) && ($p == 2)) { + // b. If two symbol characters remain and two C40 values remain to be encoded + $c1 = array_shift($tempCw); + $c2 = array_shift($tempCw); + $p -= 2; + $tmp = ((1600 * $c1) + (40 * $c2) + 1); + $cw[] = ($tmp >> 8); + $cw[] = ($tmp % 256); + $cwNum += 2; + } else { + // switch to ASCII encoding + $enc = self::ENC_ASCII; + $cw[] = $this->getSwitchEncodingCodeword($enc); + ++$cwNum; + } + } + break; + case self::ENC_EDF : // F. While in EDIFACT (EDF) encodation + // initialize temporary array with 0 lenght + $tempCw = array(); + $epos = $pos; + $fieldLenght = 0; + while ($epos < $dataLenght) { + // 2. process the next character in EDIFACT encodation. + $chr = ord($data[($epos)]); + ++$epos; + $tempCw[] = $chr; + ++$fieldLenght; + if (($fieldLenght == 4) || ($epos == $dataLenght)) { + if ($fieldLenght < 4) { + // set unlatch character + $tempCw[] = 0x1f; + ++$fieldLenght; + $enc = self::ENC_ASCII; + // fill empty characters + for ($i = $fieldLenght; $i < 4; ++$i) { + $tempCw[] = 0; + } + } + // encodes four data characters in three codewords + $cw[] = (($tempCw[0] & 0x3F) << 2) + (($tempCw[1] & 0x30) >> 4); + $cw[] = (($tempCw[1] & 0x0F) << 4) + (($tempCw[2] & 0x3C) >> 2); + $cw[] = (($tempCw[2] & 0x03) << 6) + ($tempCw[3] & 0x3F); + $cwNum += 3; + $tempCw = array(); + $pos = $epos; + $fieldLenght = 0; + } + // 1. If the EDIFACT encoding is at the point of starting a new triple symbol character and if the look-ahead test (starting at step J) indicates another mode, switch to that mode. + if ($fieldLenght == 0) { + // get remaining number of data symbols + $cwr = ($this->getMaxDataCodewords($cwNum + 2) - $cwNum); + if ($cwr < 3) { + // return to ascii without unlatch + $enc = self::ENC_ASCII; + break; // exit from EDIFACT mode + } else { + $newenc = $this->lookAheadTest($data, $pos, $enc); + if ($newenc != $enc) { + // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode. + $enc = $newenc; + $cw[] = $this->getSwitchEncodingCodeword($enc); + ++$cwNum; + break; // exit from EDIFACT mode + } + } + } + } + break; + case self::ENC_BASE256 : // G. While in Base 256 (B256) encodation + // initialize temporary array with 0 lenght + $tempCw = array(); + $fieldLenght = 0; + while (($pos < $dataLenght) && ($fieldLenght <= 1555)) { + $newenc = $this->lookAheadTest($data, $pos, $enc); + if ($newenc != $enc) { + // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode. + $enc = $newenc; + $cw[] = $this->getSwitchEncodingCodeword($enc); + ++$cwNum; + break; // exit from B256 mode + } else { + // 2. Otherwise, process the next character in Base 256 encodation. + $chr = ord($data[($pos)]); + ++$pos; + $tempCw[] = $chr; + ++$fieldLenght; + } + } + // set field lenght + if ($fieldLenght <= 249) { + $cw[] = $fieldLenght; + ++$cwNum; + } else { + $cw[] = (floor($fieldLenght / 250) + 249); + $cw[] = ($fieldLenght % 250); + $cwNum += 2; + } + if (!empty($tempCw)) { + // add B256 field + foreach ($tempCw as $p => $cht) { + $cw[] = $this->get255StateCodeword($chr, ($cwNum + $p)); + } + } + break; + + } // end of switch enc + } // end of while + // set last used encoding + $this->lastEnc = $enc; + + return $cw; + } + + /** + * Places "chr+bit" with appropriate wrapping within array[] (Annex F - ECC 200 symbol character placement) + * + * @param array $marr + * @param int $nrow + * @param int $ncol + * @param int $row + * @param int $col + * @param int $chr + * @param int $bit + * + * @return mixed + */ + protected function placeModule($marr, $nrow, $ncol, $row, $col, $chr, $bit) + { + if ($row < 0) { + $row += $nrow; + $col += (4 - (($nrow + 4) % 8)); + } + if ($col < 0) { + $col += $ncol; + $row += (4 - (($ncol + 4) % 8)); + } + $marr[(($row * $ncol) + $col)] = ((10 * $chr) + $bit); + + return $marr; + } + + /** + * Places the 8 bits of a utah-shaped symbol character (Annex F - ECC 200 symbol character placement) + * + * @param array $marr + * @param int $nrow + * @param int $ncol + * @param int $row + * @param int $col + * @param int $chr + * + * @return mixed + */ + protected function placeUtah($marr, $nrow, $ncol, $row, $col, $chr) + { + $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-2, $chr, 1); + $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-1, $chr, 2); + $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-2, $chr, 3); + $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-1, $chr, 4); + $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col, $chr, 5); + $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-2, $chr, 6); + $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-1, $chr, 7); + $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col, $chr, 8); + + return $marr; + } + + /** + * Places the 8 bits of the first special corner case (Annex F - ECC 200 symbol character placement) + * + * @param array $marr + * @param int $nrow + * @param int $ncol + * @param int $chr + * + * @return mixed + */ + protected function placeCornerA($marr, $nrow, $ncol, $chr) + { + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1); + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 1, $chr, 2); + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 2, $chr, 3); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); + $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6); + $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7); + $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8); + + return $marr; + } + + /** + * Places the 8 bits of the second special corner case (Annex F - ECC 200 symbol character placement) + * + * @param array $marr + * @param int $nrow + * @param int $ncol + * @param int $chr + * + * @return mixed + */ + protected function placeCornerB($marr, $nrow, $ncol, $chr) + { + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1); + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2); + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-4, $chr, 4); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 5); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 6); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 7); + $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8); + + return $marr; + } + + /** + * Places the 8 bits of the third special corner case (Annex F - ECC 200 symbol character placement) + * + * @param array $marr + * @param int $nrow + * @param int $ncol + * @param int $chr + * + * @return mixed + */ + protected function placeCornerC($marr, $nrow, $ncol, $chr) + { + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1); + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2); + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); + $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6); + $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7); + $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8); + + return $marr; + } + + /** + * Places the 8 bits of the fourth special corner case (Annex F - ECC 200 symbol character placement) + * + * @param array $marr + * @param int $nrow + * @param int $ncol + * @param int $chr + * + * @return mixed + */ + protected function placeCornerD($marr, $nrow, $ncol, $chr) + { + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1); + $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, $ncol-1, $chr, 2); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 3); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); + $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); + $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-3, $chr, 6); + $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-2, $chr, 7); + $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8); + + return $marr; + } + + /** + * Build a placement map (Annex F - ECC 200 symbol character placement) + * + * @param int $nrow + * @param int $ncol + * + * @return array|mixed + */ + protected function getPlacemetMap($nrow, $ncol) + { + // initialize array with zeros + $marr = array_fill(0, ($nrow * $ncol), 0); + // set starting values + $chr = 1; + $row = 4; + $col = 0; + do { + // repeatedly first check for one of the special corner cases, then + if (($row == $nrow) && ($col == 0)) { + $marr = $this->placeCornerA($marr, $nrow, $ncol, $chr); + ++$chr; + } + if (($row == ($nrow - 2)) && ($col == 0) && ($ncol % 4)) { + $marr = $this->placeCornerB($marr, $nrow, $ncol, $chr); + ++$chr; + } + if (($row == ($nrow - 2)) && ($col == 0) && (($ncol % 8) == 4)) { + $marr = $this->placeCornerC($marr, $nrow, $ncol, $chr); + ++$chr; + } + if (($row == ($nrow + 4)) && ($col == 2) && (!($ncol % 8))) { + $marr = $this->placeCornerD($marr, $nrow, $ncol, $chr); + ++$chr; + } + // sweep upward diagonally, inserting successive characters, + do { + if (($row < $nrow) && ($col >= 0) && (!$marr[(($row * $ncol) + $col)])) { + $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr); + ++$chr; + } + $row -= 2; + $col += 2; + } while (($row >= 0) && ($col < $ncol)); + ++$row; + $col += 3; + // & then sweep downward diagonally, inserting successive characters,... + do { + if (($row >= 0) && ($col < $ncol) && (!$marr[(($row * $ncol) + $col)])) { + $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr); + ++$chr; + } + $row += 2; + $col -= 2; + } while (($row < $nrow) && ($col >= 0)); + $row += 3; + ++$col; + // ... until the entire array is scanned + } while (($row < $nrow) || ($col < $ncol)); + // lastly, if the lower righthand corner is untouched, fill in fixed pattern + if (!$marr[(($nrow * $ncol) - 1)]) { + $marr[(($nrow * $ncol) - 1)] = 1; + $marr[(($nrow * $ncol) - $ncol - 2)] = 1; + } + + return $marr; + } } diff --git a/modules/PDF417.php b/modules/PDF417.php old mode 100644 new mode 100755 index 13fff0d..9002d32 --- a/modules/PDF417.php +++ b/modules/PDF417.php @@ -57,4531 +57,4531 @@ */ class PDF417 { - const - - PDF417DEFS = true, - ROWHEIGHT = 4, - QUIETH = 2, - QUIETV = 4; - - /** - * Barcode array to be returned which is readable by Dinesh Rabara. - * @protected - */ - protected $barcodeArray = array(); - - /** - * Start pattern. - * @protected - */ - protected $startPattern = '11111111010101000'; - - /** - * Stop pattern. - * @protected - */ - protected $stopPattern = '111111101000101001'; - - /** - * Array of text Compaction Sub-Modes (values 0xFB - 0xFF are used for submode changers). - * @protected - */ - protected $textsubmodes = array( - array( - 0x41, - 0x42, - 0x43, - 0x44, - 0x45, - 0x46, - 0x47, - 0x48, - 0x49, - 0x4a, - 0x4b, - 0x4c, - 0x4d, - 0x4e, - 0x4f, - 0x50, - 0x51, - 0x52, - 0x53, - 0x54, - 0x55, - 0x56, - 0x57, - 0x58, - 0x59, - 0x5a, - 0x20, - 0xFD, - 0xFE, - 0xFF - ), // Alpha - array( - 0x61, - 0x62, - 0x63, - 0x64, - 0x65, - 0x66, - 0x67, - 0x68, - 0x69, - 0x6a, - 0x6b, - 0x6c, - 0x6d, - 0x6e, - 0x6f, - 0x70, - 0x71, - 0x72, - 0x73, - 0x74, - 0x75, - 0x76, - 0x77, - 0x78, - 0x79, - 0x7a, - 0x20, - 0xFD, - 0xFE, - 0xFF - ), // Lower - array( - 0x30, - 0x31, - 0x32, - 0x33, - 0x34, - 0x35, - 0x36, - 0x37, - 0x38, - 0x39, - 0x26, - 0x0d, - 0x09, - 0x2c, - 0x3a, - 0x23, - 0x2d, - 0x2e, - 0x24, - 0x2f, - 0x2b, - 0x25, - 0x2a, - 0x3d, - 0x5e, - 0xFB, - 0x20, - 0xFD, - 0xFE, - 0xFF - ), // Mixed - array( - 0x3b, - 0x3c, - 0x3e, - 0x40, - 0x5b, - 0x5c, - 0x5d, - 0x5f, - 0x60, - 0x7e, - 0x21, - 0x0d, - 0x09, - 0x2c, - 0x3a, - 0x0a, - 0x2d, - 0x2e, - 0x24, - 0x2f, - 0x22, - 0x7c, - 0x2a, - 0x28, - 0x29, - 0x3f, - 0x7b, - 0x7d, - 0x27, - 0xFF - ) // Puntuaction - ); - - /** - * Array of switching codes for Text Compaction Sub-Modes. - * @protected - */ - protected $textlatch = array( - '01' => array(27), - '02' => array(28), - '03' => array(28, 25), // - '10' => array(28, 28), - '12' => array(28), - '13' => array(28, 25), // - '20' => array(28), - '21' => array(27), - '23' => array(25), // - '30' => array(29), - '31' => array(29, 27), - '32' => array(29, 28) // - ); - - /** - * Clusters of codewords (0, 3, 6)
- * Values are hex equivalents of binary representation of bars (1 = bar, 0 = space).
- * The codewords numbered from 900 to 928 have special meaning, some enable to switch between modes in order to optimise the code:
    - *
  • 900 : Switch to "Text" mode
  • - *
  • 901 : Switch to "Byte" mode
  • - *
  • 902 : Switch to "Numeric" mode
  • - *
  • 903 - 912 : Reserved
  • - *
  • 913 : Switch to "Octet" only for the next codeword
  • - *
  • 914 - 920 : Reserved
  • - *
  • 921 : Initialization
  • - *
  • 922 : Terminator codeword for Macro PDF control block
  • - *
  • 923 : Sequence tag to identify the beginning of optional fields in the Macro PDF control block
  • - *
  • 924 : Switch to "Byte" mode (If the total number of byte is multiple of 6)
  • - *
  • 925 : Identifier for a user defined Extended Channel Interpretation (ECI)
  • - *
  • 926 : Identifier for a general purpose ECI format
  • - *
  • 927 : Identifier for an ECI of a character set or code page
  • - *
  • 928 : Macro marker codeword to indicate the beginning of a Macro PDF Control Block
  • - *
- * @protected - */ - protected $clusters = array( - array( // cluster 0 - 0x1d5c0, - 0x1eaf0, - 0x1f57c, - 0x1d4e0, - 0x1ea78, - 0x1f53e, - 0x1a8c0, - 0x1d470, - 0x1a860, - 0x15040, // cluster 10 - 0x1a830, - 0x15020, - 0x1adc0, - 0x1d6f0, - 0x1eb7c, - 0x1ace0, - 0x1d678, - 0x1eb3e, - 0x158c0, - 0x1ac70, // cluster 20 - 0x15860, - 0x15dc0, - 0x1aef0, - 0x1d77c, - 0x15ce0, - 0x1ae78, - 0x1d73e, - 0x15c70, - 0x1ae3c, - 0x15ef0, // cluster 30 - 0x1af7c, - 0x15e78, - 0x1af3e, - 0x15f7c, - 0x1f5fa, - 0x1d2e0, - 0x1e978, - 0x1f4be, - 0x1a4c0, - 0x1d270, // cluster 40 - 0x1e93c, - 0x1a460, - 0x1d238, - 0x14840, - 0x1a430, - 0x1d21c, - 0x14820, - 0x1a418, - 0x14810, - 0x1a6e0, // cluster 50 - 0x1d378, - 0x1e9be, - 0x14cc0, - 0x1a670, - 0x1d33c, - 0x14c60, - 0x1a638, - 0x1d31e, - 0x14c30, - 0x1a61c, // cluster 60 - 0x14ee0, - 0x1a778, - 0x1d3be, - 0x14e70, - 0x1a73c, - 0x14e38, - 0x1a71e, - 0x14f78, - 0x1a7be, - 0x14f3c, // cluster 70 - 0x14f1e, - 0x1a2c0, - 0x1d170, - 0x1e8bc, - 0x1a260, - 0x1d138, - 0x1e89e, - 0x14440, - 0x1a230, - 0x1d11c, // cluster 80 - 0x14420, - 0x1a218, - 0x14410, - 0x14408, - 0x146c0, - 0x1a370, - 0x1d1bc, - 0x14660, - 0x1a338, - 0x1d19e, // cluster 90 - 0x14630, - 0x1a31c, - 0x14618, - 0x1460c, - 0x14770, - 0x1a3bc, - 0x14738, - 0x1a39e, - 0x1471c, - 0x147bc, // cluster 100 - 0x1a160, - 0x1d0b8, - 0x1e85e, - 0x14240, - 0x1a130, - 0x1d09c, - 0x14220, - 0x1a118, - 0x1d08e, - 0x14210, // cluster 110 - 0x1a10c, - 0x14208, - 0x1a106, - 0x14360, - 0x1a1b8, - 0x1d0de, - 0x14330, - 0x1a19c, - 0x14318, - 0x1a18e, // cluster 120 - 0x1430c, - 0x14306, - 0x1a1de, - 0x1438e, - 0x14140, - 0x1a0b0, - 0x1d05c, - 0x14120, - 0x1a098, - 0x1d04e, // cluster 130 - 0x14110, - 0x1a08c, - 0x14108, - 0x1a086, - 0x14104, - 0x141b0, - 0x14198, - 0x1418c, - 0x140a0, - 0x1d02e, // cluster 140 - 0x1a04c, - 0x1a046, - 0x14082, - 0x1cae0, - 0x1e578, - 0x1f2be, - 0x194c0, - 0x1ca70, - 0x1e53c, - 0x19460, // cluster 150 - 0x1ca38, - 0x1e51e, - 0x12840, - 0x19430, - 0x12820, - 0x196e0, - 0x1cb78, - 0x1e5be, - 0x12cc0, - 0x19670, // cluster 160 - 0x1cb3c, - 0x12c60, - 0x19638, - 0x12c30, - 0x12c18, - 0x12ee0, - 0x19778, - 0x1cbbe, - 0x12e70, - 0x1973c, // cluster 170 - 0x12e38, - 0x12e1c, - 0x12f78, - 0x197be, - 0x12f3c, - 0x12fbe, - 0x1dac0, - 0x1ed70, - 0x1f6bc, - 0x1da60, // cluster 180 - 0x1ed38, - 0x1f69e, - 0x1b440, - 0x1da30, - 0x1ed1c, - 0x1b420, - 0x1da18, - 0x1ed0e, - 0x1b410, - 0x1da0c, // cluster 190 - 0x192c0, - 0x1c970, - 0x1e4bc, - 0x1b6c0, - 0x19260, - 0x1c938, - 0x1e49e, - 0x1b660, - 0x1db38, - 0x1ed9e, // cluster 200 - 0x16c40, - 0x12420, - 0x19218, - 0x1c90e, - 0x16c20, - 0x1b618, - 0x16c10, - 0x126c0, - 0x19370, - 0x1c9bc, // cluster 210 - 0x16ec0, - 0x12660, - 0x19338, - 0x1c99e, - 0x16e60, - 0x1b738, - 0x1db9e, - 0x16e30, - 0x12618, - 0x16e18, // cluster 220 - 0x12770, - 0x193bc, - 0x16f70, - 0x12738, - 0x1939e, - 0x16f38, - 0x1b79e, - 0x16f1c, - 0x127bc, - 0x16fbc, // cluster 230 - 0x1279e, - 0x16f9e, - 0x1d960, - 0x1ecb8, - 0x1f65e, - 0x1b240, - 0x1d930, - 0x1ec9c, - 0x1b220, - 0x1d918, // cluster 240 - 0x1ec8e, - 0x1b210, - 0x1d90c, - 0x1b208, - 0x1b204, - 0x19160, - 0x1c8b8, - 0x1e45e, - 0x1b360, - 0x19130, // cluster 250 - 0x1c89c, - 0x16640, - 0x12220, - 0x1d99c, - 0x1c88e, - 0x16620, - 0x12210, - 0x1910c, - 0x16610, - 0x1b30c, // cluster 260 - 0x19106, - 0x12204, - 0x12360, - 0x191b8, - 0x1c8de, - 0x16760, - 0x12330, - 0x1919c, - 0x16730, - 0x1b39c, // cluster 270 - 0x1918e, - 0x16718, - 0x1230c, - 0x12306, - 0x123b8, - 0x191de, - 0x167b8, - 0x1239c, - 0x1679c, - 0x1238e, // cluster 280 - 0x1678e, - 0x167de, - 0x1b140, - 0x1d8b0, - 0x1ec5c, - 0x1b120, - 0x1d898, - 0x1ec4e, - 0x1b110, - 0x1d88c, // cluster 290 - 0x1b108, - 0x1d886, - 0x1b104, - 0x1b102, - 0x12140, - 0x190b0, - 0x1c85c, - 0x16340, - 0x12120, - 0x19098, // cluster 300 - 0x1c84e, - 0x16320, - 0x1b198, - 0x1d8ce, - 0x16310, - 0x12108, - 0x19086, - 0x16308, - 0x1b186, - 0x16304, // cluster 310 - 0x121b0, - 0x190dc, - 0x163b0, - 0x12198, - 0x190ce, - 0x16398, - 0x1b1ce, - 0x1638c, - 0x12186, - 0x16386, // cluster 320 - 0x163dc, - 0x163ce, - 0x1b0a0, - 0x1d858, - 0x1ec2e, - 0x1b090, - 0x1d84c, - 0x1b088, - 0x1d846, - 0x1b084, // cluster 330 - 0x1b082, - 0x120a0, - 0x19058, - 0x1c82e, - 0x161a0, - 0x12090, - 0x1904c, - 0x16190, - 0x1b0cc, - 0x19046, // cluster 340 - 0x16188, - 0x12084, - 0x16184, - 0x12082, - 0x120d8, - 0x161d8, - 0x161cc, - 0x161c6, - 0x1d82c, - 0x1d826, // cluster 350 - 0x1b042, - 0x1902c, - 0x12048, - 0x160c8, - 0x160c4, - 0x160c2, - 0x18ac0, - 0x1c570, - 0x1e2bc, - 0x18a60, // cluster 360 - 0x1c538, - 0x11440, - 0x18a30, - 0x1c51c, - 0x11420, - 0x18a18, - 0x11410, - 0x11408, - 0x116c0, - 0x18b70, // cluster 370 - 0x1c5bc, - 0x11660, - 0x18b38, - 0x1c59e, - 0x11630, - 0x18b1c, - 0x11618, - 0x1160c, - 0x11770, - 0x18bbc, // cluster 380 - 0x11738, - 0x18b9e, - 0x1171c, - 0x117bc, - 0x1179e, - 0x1cd60, - 0x1e6b8, - 0x1f35e, - 0x19a40, - 0x1cd30, // cluster 390 - 0x1e69c, - 0x19a20, - 0x1cd18, - 0x1e68e, - 0x19a10, - 0x1cd0c, - 0x19a08, - 0x1cd06, - 0x18960, - 0x1c4b8, // cluster 400 - 0x1e25e, - 0x19b60, - 0x18930, - 0x1c49c, - 0x13640, - 0x11220, - 0x1cd9c, - 0x1c48e, - 0x13620, - 0x19b18, // cluster 410 - 0x1890c, - 0x13610, - 0x11208, - 0x13608, - 0x11360, - 0x189b8, - 0x1c4de, - 0x13760, - 0x11330, - 0x1cdde, // cluster 420 - 0x13730, - 0x19b9c, - 0x1898e, - 0x13718, - 0x1130c, - 0x1370c, - 0x113b8, - 0x189de, - 0x137b8, - 0x1139c, // cluster 430 - 0x1379c, - 0x1138e, - 0x113de, - 0x137de, - 0x1dd40, - 0x1eeb0, - 0x1f75c, - 0x1dd20, - 0x1ee98, - 0x1f74e, // cluster 440 - 0x1dd10, - 0x1ee8c, - 0x1dd08, - 0x1ee86, - 0x1dd04, - 0x19940, - 0x1ccb0, - 0x1e65c, - 0x1bb40, - 0x19920, // cluster 450 - 0x1eedc, - 0x1e64e, - 0x1bb20, - 0x1dd98, - 0x1eece, - 0x1bb10, - 0x19908, - 0x1cc86, - 0x1bb08, - 0x1dd86, // cluster 460 - 0x19902, - 0x11140, - 0x188b0, - 0x1c45c, - 0x13340, - 0x11120, - 0x18898, - 0x1c44e, - 0x17740, - 0x13320, // cluster 470 - 0x19998, - 0x1ccce, - 0x17720, - 0x1bb98, - 0x1ddce, - 0x18886, - 0x17710, - 0x13308, - 0x19986, - 0x17708, // cluster 480 - 0x11102, - 0x111b0, - 0x188dc, - 0x133b0, - 0x11198, - 0x188ce, - 0x177b0, - 0x13398, - 0x199ce, - 0x17798, // cluster 490 - 0x1bbce, - 0x11186, - 0x13386, - 0x111dc, - 0x133dc, - 0x111ce, - 0x177dc, - 0x133ce, - 0x1dca0, - 0x1ee58, // cluster 500 - 0x1f72e, - 0x1dc90, - 0x1ee4c, - 0x1dc88, - 0x1ee46, - 0x1dc84, - 0x1dc82, - 0x198a0, - 0x1cc58, - 0x1e62e, // cluster 510 - 0x1b9a0, - 0x19890, - 0x1ee6e, - 0x1b990, - 0x1dccc, - 0x1cc46, - 0x1b988, - 0x19884, - 0x1b984, - 0x19882, // cluster 520 - 0x1b982, - 0x110a0, - 0x18858, - 0x1c42e, - 0x131a0, - 0x11090, - 0x1884c, - 0x173a0, - 0x13190, - 0x198cc, // cluster 530 - 0x18846, - 0x17390, - 0x1b9cc, - 0x11084, - 0x17388, - 0x13184, - 0x11082, - 0x13182, - 0x110d8, - 0x1886e, // cluster 540 - 0x131d8, - 0x110cc, - 0x173d8, - 0x131cc, - 0x110c6, - 0x173cc, - 0x131c6, - 0x110ee, - 0x173ee, - 0x1dc50, // cluster 550 - 0x1ee2c, - 0x1dc48, - 0x1ee26, - 0x1dc44, - 0x1dc42, - 0x19850, - 0x1cc2c, - 0x1b8d0, - 0x19848, - 0x1cc26, // cluster 560 - 0x1b8c8, - 0x1dc66, - 0x1b8c4, - 0x19842, - 0x1b8c2, - 0x11050, - 0x1882c, - 0x130d0, - 0x11048, - 0x18826, // cluster 570 - 0x171d0, - 0x130c8, - 0x19866, - 0x171c8, - 0x1b8e6, - 0x11042, - 0x171c4, - 0x130c2, - 0x171c2, - 0x130ec, // cluster 580 - 0x171ec, - 0x171e6, - 0x1ee16, - 0x1dc22, - 0x1cc16, - 0x19824, - 0x19822, - 0x11028, - 0x13068, - 0x170e8, // cluster 590 - 0x11022, - 0x13062, - 0x18560, - 0x10a40, - 0x18530, - 0x10a20, - 0x18518, - 0x1c28e, - 0x10a10, - 0x1850c, // cluster 600 - 0x10a08, - 0x18506, - 0x10b60, - 0x185b8, - 0x1c2de, - 0x10b30, - 0x1859c, - 0x10b18, - 0x1858e, - 0x10b0c, // cluster 610 - 0x10b06, - 0x10bb8, - 0x185de, - 0x10b9c, - 0x10b8e, - 0x10bde, - 0x18d40, - 0x1c6b0, - 0x1e35c, - 0x18d20, // cluster 620 - 0x1c698, - 0x18d10, - 0x1c68c, - 0x18d08, - 0x1c686, - 0x18d04, - 0x10940, - 0x184b0, - 0x1c25c, - 0x11b40, // cluster 630 - 0x10920, - 0x1c6dc, - 0x1c24e, - 0x11b20, - 0x18d98, - 0x1c6ce, - 0x11b10, - 0x10908, - 0x18486, - 0x11b08, // cluster 640 - 0x18d86, - 0x10902, - 0x109b0, - 0x184dc, - 0x11bb0, - 0x10998, - 0x184ce, - 0x11b98, - 0x18dce, - 0x11b8c, // cluster 650 - 0x10986, - 0x109dc, - 0x11bdc, - 0x109ce, - 0x11bce, - 0x1cea0, - 0x1e758, - 0x1f3ae, - 0x1ce90, - 0x1e74c, // cluster 660 - 0x1ce88, - 0x1e746, - 0x1ce84, - 0x1ce82, - 0x18ca0, - 0x1c658, - 0x19da0, - 0x18c90, - 0x1c64c, - 0x19d90, // cluster 670 - 0x1cecc, - 0x1c646, - 0x19d88, - 0x18c84, - 0x19d84, - 0x18c82, - 0x19d82, - 0x108a0, - 0x18458, - 0x119a0, // cluster 680 - 0x10890, - 0x1c66e, - 0x13ba0, - 0x11990, - 0x18ccc, - 0x18446, - 0x13b90, - 0x19dcc, - 0x10884, - 0x13b88, // cluster 690 - 0x11984, - 0x10882, - 0x11982, - 0x108d8, - 0x1846e, - 0x119d8, - 0x108cc, - 0x13bd8, - 0x119cc, - 0x108c6, // cluster 700 - 0x13bcc, - 0x119c6, - 0x108ee, - 0x119ee, - 0x13bee, - 0x1ef50, - 0x1f7ac, - 0x1ef48, - 0x1f7a6, - 0x1ef44, // cluster 710 - 0x1ef42, - 0x1ce50, - 0x1e72c, - 0x1ded0, - 0x1ef6c, - 0x1e726, - 0x1dec8, - 0x1ef66, - 0x1dec4, - 0x1ce42, // cluster 720 - 0x1dec2, - 0x18c50, - 0x1c62c, - 0x19cd0, - 0x18c48, - 0x1c626, - 0x1bdd0, - 0x19cc8, - 0x1ce66, - 0x1bdc8, // cluster 730 - 0x1dee6, - 0x18c42, - 0x1bdc4, - 0x19cc2, - 0x1bdc2, - 0x10850, - 0x1842c, - 0x118d0, - 0x10848, - 0x18426, // cluster 740 - 0x139d0, - 0x118c8, - 0x18c66, - 0x17bd0, - 0x139c8, - 0x19ce6, - 0x10842, - 0x17bc8, - 0x1bde6, - 0x118c2, // cluster 750 - 0x17bc4, - 0x1086c, - 0x118ec, - 0x10866, - 0x139ec, - 0x118e6, - 0x17bec, - 0x139e6, - 0x17be6, - 0x1ef28, // cluster 760 - 0x1f796, - 0x1ef24, - 0x1ef22, - 0x1ce28, - 0x1e716, - 0x1de68, - 0x1ef36, - 0x1de64, - 0x1ce22, - 0x1de62, // cluster 770 - 0x18c28, - 0x1c616, - 0x19c68, - 0x18c24, - 0x1bce8, - 0x19c64, - 0x18c22, - 0x1bce4, - 0x19c62, - 0x1bce2, // cluster 780 - 0x10828, - 0x18416, - 0x11868, - 0x18c36, - 0x138e8, - 0x11864, - 0x10822, - 0x179e8, - 0x138e4, - 0x11862, // 790 - 0x179e4, - 0x138e2, - 0x179e2, - 0x11876, - 0x179f6, - 0x1ef12, - 0x1de34, - 0x1de32, - 0x19c34, - 0x1bc74, // 800 - 0x1bc72, - 0x11834, - 0x13874, - 0x178f4, - 0x178f2, - 0x10540, - 0x10520, - 0x18298, - 0x10510, - 0x10508, // 810 - 0x10504, - 0x105b0, - 0x10598, - 0x1058c, - 0x10586, - 0x105dc, - 0x105ce, - 0x186a0, - 0x18690, - 0x1c34c, // 820 - 0x18688, - 0x1c346, - 0x18684, - 0x18682, - 0x104a0, - 0x18258, - 0x10da0, - 0x186d8, - 0x1824c, - 0x10d90, // 830 - 0x186cc, - 0x10d88, - 0x186c6, - 0x10d84, - 0x10482, - 0x10d82, - 0x104d8, - 0x1826e, - 0x10dd8, - 0x186ee, // 840 - 0x10dcc, - 0x104c6, - 0x10dc6, - 0x104ee, - 0x10dee, - 0x1c750, - 0x1c748, - 0x1c744, - 0x1c742, - 0x18650, // 850 - 0x18ed0, - 0x1c76c, - 0x1c326, - 0x18ec8, - 0x1c766, - 0x18ec4, - 0x18642, - 0x18ec2, - 0x10450, - 0x10cd0, // 860 - 0x10448, - 0x18226, - 0x11dd0, - 0x10cc8, - 0x10444, - 0x11dc8, - 0x10cc4, - 0x10442, - 0x11dc4, - 0x10cc2, // 870 - 0x1046c, - 0x10cec, - 0x10466, - 0x11dec, - 0x10ce6, - 0x11de6, - 0x1e7a8, - 0x1e7a4, - 0x1e7a2, - 0x1c728, // 880 - 0x1cf68, - 0x1e7b6, - 0x1cf64, - 0x1c722, - 0x1cf62, - 0x18628, - 0x1c316, - 0x18e68, - 0x1c736, - 0x19ee8, // 890 - 0x18e64, - 0x18622, - 0x19ee4, - 0x18e62, - 0x19ee2, - 0x10428, - 0x18216, - 0x10c68, - 0x18636, - 0x11ce8, // 900 - 0x10c64, - 0x10422, - 0x13de8, - 0x11ce4, - 0x10c62, - 0x13de4, - 0x11ce2, - 0x10436, - 0x10c76, - 0x11cf6, // 910 - 0x13df6, - 0x1f7d4, - 0x1f7d2, - 0x1e794, - 0x1efb4, - 0x1e792, - 0x1efb2, - 0x1c714, - 0x1cf34, - 0x1c712, // 920 - 0x1df74, - 0x1cf32, - 0x1df72, - 0x18614, - 0x18e34, - 0x18612, - 0x19e74, - 0x18e32, - 0x1bef4 - ), // 929 - array( // cluster 3 ----------------------------------------------------------------------- - 0x1f560, - 0x1fab8, - 0x1ea40, - 0x1f530, - 0x1fa9c, - 0x1ea20, - 0x1f518, - 0x1fa8e, - 0x1ea10, - 0x1f50c, // 10 - 0x1ea08, - 0x1f506, - 0x1ea04, - 0x1eb60, - 0x1f5b8, - 0x1fade, - 0x1d640, - 0x1eb30, - 0x1f59c, - 0x1d620, // 20 - 0x1eb18, - 0x1f58e, - 0x1d610, - 0x1eb0c, - 0x1d608, - 0x1eb06, - 0x1d604, - 0x1d760, - 0x1ebb8, - 0x1f5de, // 30 - 0x1ae40, - 0x1d730, - 0x1eb9c, - 0x1ae20, - 0x1d718, - 0x1eb8e, - 0x1ae10, - 0x1d70c, - 0x1ae08, - 0x1d706, // 40 - 0x1ae04, - 0x1af60, - 0x1d7b8, - 0x1ebde, - 0x15e40, - 0x1af30, - 0x1d79c, - 0x15e20, - 0x1af18, - 0x1d78e, // 50 - 0x15e10, - 0x1af0c, - 0x15e08, - 0x1af06, - 0x15f60, - 0x1afb8, - 0x1d7de, - 0x15f30, - 0x1af9c, - 0x15f18, // 60 - 0x1af8e, - 0x15f0c, - 0x15fb8, - 0x1afde, - 0x15f9c, - 0x15f8e, - 0x1e940, - 0x1f4b0, - 0x1fa5c, - 0x1e920, // 70 - 0x1f498, - 0x1fa4e, - 0x1e910, - 0x1f48c, - 0x1e908, - 0x1f486, - 0x1e904, - 0x1e902, - 0x1d340, - 0x1e9b0, // 80 - 0x1f4dc, - 0x1d320, - 0x1e998, - 0x1f4ce, - 0x1d310, - 0x1e98c, - 0x1d308, - 0x1e986, - 0x1d304, - 0x1d302, // 90 - 0x1a740, - 0x1d3b0, - 0x1e9dc, - 0x1a720, - 0x1d398, - 0x1e9ce, - 0x1a710, - 0x1d38c, - 0x1a708, - 0x1d386, // 100 - 0x1a704, - 0x1a702, - 0x14f40, - 0x1a7b0, - 0x1d3dc, - 0x14f20, - 0x1a798, - 0x1d3ce, - 0x14f10, - 0x1a78c, // 110 - 0x14f08, - 0x1a786, - 0x14f04, - 0x14fb0, - 0x1a7dc, - 0x14f98, - 0x1a7ce, - 0x14f8c, - 0x14f86, - 0x14fdc, // 120 - 0x14fce, - 0x1e8a0, - 0x1f458, - 0x1fa2e, - 0x1e890, - 0x1f44c, - 0x1e888, - 0x1f446, - 0x1e884, - 0x1e882, // 130 - 0x1d1a0, - 0x1e8d8, - 0x1f46e, - 0x1d190, - 0x1e8cc, - 0x1d188, - 0x1e8c6, - 0x1d184, - 0x1d182, - 0x1a3a0, // 140 - 0x1d1d8, - 0x1e8ee, - 0x1a390, - 0x1d1cc, - 0x1a388, - 0x1d1c6, - 0x1a384, - 0x1a382, - 0x147a0, - 0x1a3d8, // 150 - 0x1d1ee, - 0x14790, - 0x1a3cc, - 0x14788, - 0x1a3c6, - 0x14784, - 0x14782, - 0x147d8, - 0x1a3ee, - 0x147cc, // 160 - 0x147c6, - 0x147ee, - 0x1e850, - 0x1f42c, - 0x1e848, - 0x1f426, - 0x1e844, - 0x1e842, - 0x1d0d0, - 0x1e86c, // 170 - 0x1d0c8, - 0x1e866, - 0x1d0c4, - 0x1d0c2, - 0x1a1d0, - 0x1d0ec, - 0x1a1c8, - 0x1d0e6, - 0x1a1c4, - 0x1a1c2, // 180 - 0x143d0, - 0x1a1ec, - 0x143c8, - 0x1a1e6, - 0x143c4, - 0x143c2, - 0x143ec, - 0x143e6, - 0x1e828, - 0x1f416, // 190 - 0x1e824, - 0x1e822, - 0x1d068, - 0x1e836, - 0x1d064, - 0x1d062, - 0x1a0e8, - 0x1d076, - 0x1a0e4, - 0x1a0e2, // 200 - 0x141e8, - 0x1a0f6, - 0x141e4, - 0x141e2, - 0x1e814, - 0x1e812, - 0x1d034, - 0x1d032, - 0x1a074, - 0x1a072, // 210 - 0x1e540, - 0x1f2b0, - 0x1f95c, - 0x1e520, - 0x1f298, - 0x1f94e, - 0x1e510, - 0x1f28c, - 0x1e508, - 0x1f286, // 220 - 0x1e504, - 0x1e502, - 0x1cb40, - 0x1e5b0, - 0x1f2dc, - 0x1cb20, - 0x1e598, - 0x1f2ce, - 0x1cb10, - 0x1e58c, // 230 - 0x1cb08, - 0x1e586, - 0x1cb04, - 0x1cb02, - 0x19740, - 0x1cbb0, - 0x1e5dc, - 0x19720, - 0x1cb98, - 0x1e5ce, // 240 - 0x19710, - 0x1cb8c, - 0x19708, - 0x1cb86, - 0x19704, - 0x19702, - 0x12f40, - 0x197b0, - 0x1cbdc, - 0x12f20, // 250 - 0x19798, - 0x1cbce, - 0x12f10, - 0x1978c, - 0x12f08, - 0x19786, - 0x12f04, - 0x12fb0, - 0x197dc, - 0x12f98, // 260 - 0x197ce, - 0x12f8c, - 0x12f86, - 0x12fdc, - 0x12fce, - 0x1f6a0, - 0x1fb58, - 0x16bf0, - 0x1f690, - 0x1fb4c, // 270 - 0x169f8, - 0x1f688, - 0x1fb46, - 0x168fc, - 0x1f684, - 0x1f682, - 0x1e4a0, - 0x1f258, - 0x1f92e, - 0x1eda0, // 280 - 0x1e490, - 0x1fb6e, - 0x1ed90, - 0x1f6cc, - 0x1f246, - 0x1ed88, - 0x1e484, - 0x1ed84, - 0x1e482, - 0x1ed82, // 290 - 0x1c9a0, - 0x1e4d8, - 0x1f26e, - 0x1dba0, - 0x1c990, - 0x1e4cc, - 0x1db90, - 0x1edcc, - 0x1e4c6, - 0x1db88, // 300 - 0x1c984, - 0x1db84, - 0x1c982, - 0x1db82, - 0x193a0, - 0x1c9d8, - 0x1e4ee, - 0x1b7a0, - 0x19390, - 0x1c9cc, // 310 - 0x1b790, - 0x1dbcc, - 0x1c9c6, - 0x1b788, - 0x19384, - 0x1b784, - 0x19382, - 0x1b782, - 0x127a0, - 0x193d8, // 320 - 0x1c9ee, - 0x16fa0, - 0x12790, - 0x193cc, - 0x16f90, - 0x1b7cc, - 0x193c6, - 0x16f88, - 0x12784, - 0x16f84, // 330 - 0x12782, - 0x127d8, - 0x193ee, - 0x16fd8, - 0x127cc, - 0x16fcc, - 0x127c6, - 0x16fc6, - 0x127ee, - 0x1f650, // 340 - 0x1fb2c, - 0x165f8, - 0x1f648, - 0x1fb26, - 0x164fc, - 0x1f644, - 0x1647e, - 0x1f642, - 0x1e450, - 0x1f22c, // 350 - 0x1ecd0, - 0x1e448, - 0x1f226, - 0x1ecc8, - 0x1f666, - 0x1ecc4, - 0x1e442, - 0x1ecc2, - 0x1c8d0, - 0x1e46c, // 360 - 0x1d9d0, - 0x1c8c8, - 0x1e466, - 0x1d9c8, - 0x1ece6, - 0x1d9c4, - 0x1c8c2, - 0x1d9c2, - 0x191d0, - 0x1c8ec, // 370 - 0x1b3d0, - 0x191c8, - 0x1c8e6, - 0x1b3c8, - 0x1d9e6, - 0x1b3c4, - 0x191c2, - 0x1b3c2, - 0x123d0, - 0x191ec, // 380 - 0x167d0, - 0x123c8, - 0x191e6, - 0x167c8, - 0x1b3e6, - 0x167c4, - 0x123c2, - 0x167c2, - 0x123ec, - 0x167ec, // 390 - 0x123e6, - 0x167e6, - 0x1f628, - 0x1fb16, - 0x162fc, - 0x1f624, - 0x1627e, - 0x1f622, - 0x1e428, - 0x1f216, // 400 - 0x1ec68, - 0x1f636, - 0x1ec64, - 0x1e422, - 0x1ec62, - 0x1c868, - 0x1e436, - 0x1d8e8, - 0x1c864, - 0x1d8e4, // 410 - 0x1c862, - 0x1d8e2, - 0x190e8, - 0x1c876, - 0x1b1e8, - 0x1d8f6, - 0x1b1e4, - 0x190e2, - 0x1b1e2, - 0x121e8, // 420 - 0x190f6, - 0x163e8, - 0x121e4, - 0x163e4, - 0x121e2, - 0x163e2, - 0x121f6, - 0x163f6, - 0x1f614, - 0x1617e, // 430 - 0x1f612, - 0x1e414, - 0x1ec34, - 0x1e412, - 0x1ec32, - 0x1c834, - 0x1d874, - 0x1c832, - 0x1d872, - 0x19074, // 440 - 0x1b0f4, - 0x19072, - 0x1b0f2, - 0x120f4, - 0x161f4, - 0x120f2, - 0x161f2, - 0x1f60a, - 0x1e40a, - 0x1ec1a, // 450 - 0x1c81a, - 0x1d83a, - 0x1903a, - 0x1b07a, - 0x1e2a0, - 0x1f158, - 0x1f8ae, - 0x1e290, - 0x1f14c, - 0x1e288, // 460 - 0x1f146, - 0x1e284, - 0x1e282, - 0x1c5a0, - 0x1e2d8, - 0x1f16e, - 0x1c590, - 0x1e2cc, - 0x1c588, - 0x1e2c6, // 470 - 0x1c584, - 0x1c582, - 0x18ba0, - 0x1c5d8, - 0x1e2ee, - 0x18b90, - 0x1c5cc, - 0x18b88, - 0x1c5c6, - 0x18b84, // 480 - 0x18b82, - 0x117a0, - 0x18bd8, - 0x1c5ee, - 0x11790, - 0x18bcc, - 0x11788, - 0x18bc6, - 0x11784, - 0x11782, // 490 - 0x117d8, - 0x18bee, - 0x117cc, - 0x117c6, - 0x117ee, - 0x1f350, - 0x1f9ac, - 0x135f8, - 0x1f348, - 0x1f9a6, // 500 - 0x134fc, - 0x1f344, - 0x1347e, - 0x1f342, - 0x1e250, - 0x1f12c, - 0x1e6d0, - 0x1e248, - 0x1f126, - 0x1e6c8, // 510 - 0x1f366, - 0x1e6c4, - 0x1e242, - 0x1e6c2, - 0x1c4d0, - 0x1e26c, - 0x1cdd0, - 0x1c4c8, - 0x1e266, - 0x1cdc8, // 520 - 0x1e6e6, - 0x1cdc4, - 0x1c4c2, - 0x1cdc2, - 0x189d0, - 0x1c4ec, - 0x19bd0, - 0x189c8, - 0x1c4e6, - 0x19bc8, // 530 - 0x1cde6, - 0x19bc4, - 0x189c2, - 0x19bc2, - 0x113d0, - 0x189ec, - 0x137d0, - 0x113c8, - 0x189e6, - 0x137c8, // 540 - 0x19be6, - 0x137c4, - 0x113c2, - 0x137c2, - 0x113ec, - 0x137ec, - 0x113e6, - 0x137e6, - 0x1fba8, - 0x175f0, // 550 - 0x1bafc, - 0x1fba4, - 0x174f8, - 0x1ba7e, - 0x1fba2, - 0x1747c, - 0x1743e, - 0x1f328, - 0x1f996, - 0x132fc, // 560 - 0x1f768, - 0x1fbb6, - 0x176fc, - 0x1327e, - 0x1f764, - 0x1f322, - 0x1767e, - 0x1f762, - 0x1e228, - 0x1f116, // 570 - 0x1e668, - 0x1e224, - 0x1eee8, - 0x1f776, - 0x1e222, - 0x1eee4, - 0x1e662, - 0x1eee2, - 0x1c468, - 0x1e236, // 580 - 0x1cce8, - 0x1c464, - 0x1dde8, - 0x1cce4, - 0x1c462, - 0x1dde4, - 0x1cce2, - 0x1dde2, - 0x188e8, - 0x1c476, // 590 - 0x199e8, - 0x188e4, - 0x1bbe8, - 0x199e4, - 0x188e2, - 0x1bbe4, - 0x199e2, - 0x1bbe2, - 0x111e8, - 0x188f6, // 600 - 0x133e8, - 0x111e4, - 0x177e8, - 0x133e4, - 0x111e2, - 0x177e4, - 0x133e2, - 0x177e2, - 0x111f6, - 0x133f6, // 610 - 0x1fb94, - 0x172f8, - 0x1b97e, - 0x1fb92, - 0x1727c, - 0x1723e, - 0x1f314, - 0x1317e, - 0x1f734, - 0x1f312, // 620 - 0x1737e, - 0x1f732, - 0x1e214, - 0x1e634, - 0x1e212, - 0x1ee74, - 0x1e632, - 0x1ee72, - 0x1c434, - 0x1cc74, // 630 - 0x1c432, - 0x1dcf4, - 0x1cc72, - 0x1dcf2, - 0x18874, - 0x198f4, - 0x18872, - 0x1b9f4, - 0x198f2, - 0x1b9f2, // 640 - 0x110f4, - 0x131f4, - 0x110f2, - 0x173f4, - 0x131f2, - 0x173f2, - 0x1fb8a, - 0x1717c, - 0x1713e, - 0x1f30a, // 650 - 0x1f71a, - 0x1e20a, - 0x1e61a, - 0x1ee3a, - 0x1c41a, - 0x1cc3a, - 0x1dc7a, - 0x1883a, - 0x1987a, - 0x1b8fa, // 660 - 0x1107a, - 0x130fa, - 0x171fa, - 0x170be, - 0x1e150, - 0x1f0ac, - 0x1e148, - 0x1f0a6, - 0x1e144, - 0x1e142, // 670 - 0x1c2d0, - 0x1e16c, - 0x1c2c8, - 0x1e166, - 0x1c2c4, - 0x1c2c2, - 0x185d0, - 0x1c2ec, - 0x185c8, - 0x1c2e6, // 680 - 0x185c4, - 0x185c2, - 0x10bd0, - 0x185ec, - 0x10bc8, - 0x185e6, - 0x10bc4, - 0x10bc2, - 0x10bec, - 0x10be6, // 690 - 0x1f1a8, - 0x1f8d6, - 0x11afc, - 0x1f1a4, - 0x11a7e, - 0x1f1a2, - 0x1e128, - 0x1f096, - 0x1e368, - 0x1e124, // 700 - 0x1e364, - 0x1e122, - 0x1e362, - 0x1c268, - 0x1e136, - 0x1c6e8, - 0x1c264, - 0x1c6e4, - 0x1c262, - 0x1c6e2, // 710 - 0x184e8, - 0x1c276, - 0x18de8, - 0x184e4, - 0x18de4, - 0x184e2, - 0x18de2, - 0x109e8, - 0x184f6, - 0x11be8, // 720 - 0x109e4, - 0x11be4, - 0x109e2, - 0x11be2, - 0x109f6, - 0x11bf6, - 0x1f9d4, - 0x13af8, - 0x19d7e, - 0x1f9d2, // 730 - 0x13a7c, - 0x13a3e, - 0x1f194, - 0x1197e, - 0x1f3b4, - 0x1f192, - 0x13b7e, - 0x1f3b2, - 0x1e114, - 0x1e334, // 740 - 0x1e112, - 0x1e774, - 0x1e332, - 0x1e772, - 0x1c234, - 0x1c674, - 0x1c232, - 0x1cef4, - 0x1c672, - 0x1cef2, // 750 - 0x18474, - 0x18cf4, - 0x18472, - 0x19df4, - 0x18cf2, - 0x19df2, - 0x108f4, - 0x119f4, - 0x108f2, - 0x13bf4, // 760 - 0x119f2, - 0x13bf2, - 0x17af0, - 0x1bd7c, - 0x17a78, - 0x1bd3e, - 0x17a3c, - 0x17a1e, - 0x1f9ca, - 0x1397c, // 770 - 0x1fbda, - 0x17b7c, - 0x1393e, - 0x17b3e, - 0x1f18a, - 0x1f39a, - 0x1f7ba, - 0x1e10a, - 0x1e31a, - 0x1e73a, // 780 - 0x1ef7a, - 0x1c21a, - 0x1c63a, - 0x1ce7a, - 0x1defa, - 0x1843a, - 0x18c7a, - 0x19cfa, - 0x1bdfa, - 0x1087a, // 790 - 0x118fa, - 0x139fa, - 0x17978, - 0x1bcbe, - 0x1793c, - 0x1791e, - 0x138be, - 0x179be, - 0x178bc, - 0x1789e, // 800 - 0x1785e, - 0x1e0a8, - 0x1e0a4, - 0x1e0a2, - 0x1c168, - 0x1e0b6, - 0x1c164, - 0x1c162, - 0x182e8, - 0x1c176, // 810 - 0x182e4, - 0x182e2, - 0x105e8, - 0x182f6, - 0x105e4, - 0x105e2, - 0x105f6, - 0x1f0d4, - 0x10d7e, - 0x1f0d2, // 820 - 0x1e094, - 0x1e1b4, - 0x1e092, - 0x1e1b2, - 0x1c134, - 0x1c374, - 0x1c132, - 0x1c372, - 0x18274, - 0x186f4, // 830 - 0x18272, - 0x186f2, - 0x104f4, - 0x10df4, - 0x104f2, - 0x10df2, - 0x1f8ea, - 0x11d7c, - 0x11d3e, - 0x1f0ca, // 840 - 0x1f1da, - 0x1e08a, - 0x1e19a, - 0x1e3ba, - 0x1c11a, - 0x1c33a, - 0x1c77a, - 0x1823a, - 0x1867a, - 0x18efa, // 850 - 0x1047a, - 0x10cfa, - 0x11dfa, - 0x13d78, - 0x19ebe, - 0x13d3c, - 0x13d1e, - 0x11cbe, - 0x13dbe, - 0x17d70, // 860 - 0x1bebc, - 0x17d38, - 0x1be9e, - 0x17d1c, - 0x17d0e, - 0x13cbc, - 0x17dbc, - 0x13c9e, - 0x17d9e, - 0x17cb8, // 870 - 0x1be5e, - 0x17c9c, - 0x17c8e, - 0x13c5e, - 0x17cde, - 0x17c5c, - 0x17c4e, - 0x17c2e, - 0x1c0b4, - 0x1c0b2, // 880 - 0x18174, - 0x18172, - 0x102f4, - 0x102f2, - 0x1e0da, - 0x1c09a, - 0x1c1ba, - 0x1813a, - 0x1837a, - 0x1027a, // 890 - 0x106fa, - 0x10ebe, - 0x11ebc, - 0x11e9e, - 0x13eb8, - 0x19f5e, - 0x13e9c, - 0x13e8e, - 0x11e5e, - 0x13ede, // 900 - 0x17eb0, - 0x1bf5c, - 0x17e98, - 0x1bf4e, - 0x17e8c, - 0x17e86, - 0x13e5c, - 0x17edc, - 0x13e4e, - 0x17ece, // 910 - 0x17e58, - 0x1bf2e, - 0x17e4c, - 0x17e46, - 0x13e2e, - 0x17e6e, - 0x17e2c, - 0x17e26, - 0x10f5e, - 0x11f5c, // 920 - 0x11f4e, - 0x13f58, - 0x19fae, - 0x13f4c, - 0x13f46, - 0x11f2e, - 0x13f6e, - 0x13f2c, - 0x13f26 - ), // 929 - array( // cluster 6 ----------------------------------------------------------------------- - 0x1abe0, - 0x1d5f8, - 0x153c0, - 0x1a9f0, - 0x1d4fc, - 0x151e0, - 0x1a8f8, - 0x1d47e, - 0x150f0, - 0x1a87c, // 10 - 0x15078, - 0x1fad0, - 0x15be0, - 0x1adf8, - 0x1fac8, - 0x159f0, - 0x1acfc, - 0x1fac4, - 0x158f8, - 0x1ac7e, // 20 - 0x1fac2, - 0x1587c, - 0x1f5d0, - 0x1faec, - 0x15df8, - 0x1f5c8, - 0x1fae6, - 0x15cfc, - 0x1f5c4, - 0x15c7e, // 30 - 0x1f5c2, - 0x1ebd0, - 0x1f5ec, - 0x1ebc8, - 0x1f5e6, - 0x1ebc4, - 0x1ebc2, - 0x1d7d0, - 0x1ebec, - 0x1d7c8, // 40 - 0x1ebe6, - 0x1d7c4, - 0x1d7c2, - 0x1afd0, - 0x1d7ec, - 0x1afc8, - 0x1d7e6, - 0x1afc4, - 0x14bc0, - 0x1a5f0, // 50 - 0x1d2fc, - 0x149e0, - 0x1a4f8, - 0x1d27e, - 0x148f0, - 0x1a47c, - 0x14878, - 0x1a43e, - 0x1483c, - 0x1fa68, // 60 - 0x14df0, - 0x1a6fc, - 0x1fa64, - 0x14cf8, - 0x1a67e, - 0x1fa62, - 0x14c7c, - 0x14c3e, - 0x1f4e8, - 0x1fa76, // 70 - 0x14efc, - 0x1f4e4, - 0x14e7e, - 0x1f4e2, - 0x1e9e8, - 0x1f4f6, - 0x1e9e4, - 0x1e9e2, - 0x1d3e8, - 0x1e9f6, // 80 - 0x1d3e4, - 0x1d3e2, - 0x1a7e8, - 0x1d3f6, - 0x1a7e4, - 0x1a7e2, - 0x145e0, - 0x1a2f8, - 0x1d17e, - 0x144f0, // 90 - 0x1a27c, - 0x14478, - 0x1a23e, - 0x1443c, - 0x1441e, - 0x1fa34, - 0x146f8, - 0x1a37e, - 0x1fa32, - 0x1467c, // 100 - 0x1463e, - 0x1f474, - 0x1477e, - 0x1f472, - 0x1e8f4, - 0x1e8f2, - 0x1d1f4, - 0x1d1f2, - 0x1a3f4, - 0x1a3f2, // 110 - 0x142f0, - 0x1a17c, - 0x14278, - 0x1a13e, - 0x1423c, - 0x1421e, - 0x1fa1a, - 0x1437c, - 0x1433e, - 0x1f43a, // 120 - 0x1e87a, - 0x1d0fa, - 0x14178, - 0x1a0be, - 0x1413c, - 0x1411e, - 0x141be, - 0x140bc, - 0x1409e, - 0x12bc0, // 130 - 0x195f0, - 0x1cafc, - 0x129e0, - 0x194f8, - 0x1ca7e, - 0x128f0, - 0x1947c, - 0x12878, - 0x1943e, - 0x1283c, // 140 - 0x1f968, - 0x12df0, - 0x196fc, - 0x1f964, - 0x12cf8, - 0x1967e, - 0x1f962, - 0x12c7c, - 0x12c3e, - 0x1f2e8, // 150 - 0x1f976, - 0x12efc, - 0x1f2e4, - 0x12e7e, - 0x1f2e2, - 0x1e5e8, - 0x1f2f6, - 0x1e5e4, - 0x1e5e2, - 0x1cbe8, // 160 - 0x1e5f6, - 0x1cbe4, - 0x1cbe2, - 0x197e8, - 0x1cbf6, - 0x197e4, - 0x197e2, - 0x1b5e0, - 0x1daf8, - 0x1ed7e, // 170 - 0x169c0, - 0x1b4f0, - 0x1da7c, - 0x168e0, - 0x1b478, - 0x1da3e, - 0x16870, - 0x1b43c, - 0x16838, - 0x1b41e, // 180 - 0x1681c, - 0x125e0, - 0x192f8, - 0x1c97e, - 0x16de0, - 0x124f0, - 0x1927c, - 0x16cf0, - 0x1b67c, - 0x1923e, // 190 - 0x16c78, - 0x1243c, - 0x16c3c, - 0x1241e, - 0x16c1e, - 0x1f934, - 0x126f8, - 0x1937e, - 0x1fb74, - 0x1f932, // 200 - 0x16ef8, - 0x1267c, - 0x1fb72, - 0x16e7c, - 0x1263e, - 0x16e3e, - 0x1f274, - 0x1277e, - 0x1f6f4, - 0x1f272, // 210 - 0x16f7e, - 0x1f6f2, - 0x1e4f4, - 0x1edf4, - 0x1e4f2, - 0x1edf2, - 0x1c9f4, - 0x1dbf4, - 0x1c9f2, - 0x1dbf2, // 220 - 0x193f4, - 0x193f2, - 0x165c0, - 0x1b2f0, - 0x1d97c, - 0x164e0, - 0x1b278, - 0x1d93e, - 0x16470, - 0x1b23c, // 230 - 0x16438, - 0x1b21e, - 0x1641c, - 0x1640e, - 0x122f0, - 0x1917c, - 0x166f0, - 0x12278, - 0x1913e, - 0x16678, // 240 - 0x1b33e, - 0x1663c, - 0x1221e, - 0x1661e, - 0x1f91a, - 0x1237c, - 0x1fb3a, - 0x1677c, - 0x1233e, - 0x1673e, // 250 - 0x1f23a, - 0x1f67a, - 0x1e47a, - 0x1ecfa, - 0x1c8fa, - 0x1d9fa, - 0x191fa, - 0x162e0, - 0x1b178, - 0x1d8be, // 260 - 0x16270, - 0x1b13c, - 0x16238, - 0x1b11e, - 0x1621c, - 0x1620e, - 0x12178, - 0x190be, - 0x16378, - 0x1213c, // 270 - 0x1633c, - 0x1211e, - 0x1631e, - 0x121be, - 0x163be, - 0x16170, - 0x1b0bc, - 0x16138, - 0x1b09e, - 0x1611c, // 280 - 0x1610e, - 0x120bc, - 0x161bc, - 0x1209e, - 0x1619e, - 0x160b8, - 0x1b05e, - 0x1609c, - 0x1608e, - 0x1205e, // 290 - 0x160de, - 0x1605c, - 0x1604e, - 0x115e0, - 0x18af8, - 0x1c57e, - 0x114f0, - 0x18a7c, - 0x11478, - 0x18a3e, // 300 - 0x1143c, - 0x1141e, - 0x1f8b4, - 0x116f8, - 0x18b7e, - 0x1f8b2, - 0x1167c, - 0x1163e, - 0x1f174, - 0x1177e, // 310 - 0x1f172, - 0x1e2f4, - 0x1e2f2, - 0x1c5f4, - 0x1c5f2, - 0x18bf4, - 0x18bf2, - 0x135c0, - 0x19af0, - 0x1cd7c, // 320 - 0x134e0, - 0x19a78, - 0x1cd3e, - 0x13470, - 0x19a3c, - 0x13438, - 0x19a1e, - 0x1341c, - 0x1340e, - 0x112f0, // 330 - 0x1897c, - 0x136f0, - 0x11278, - 0x1893e, - 0x13678, - 0x19b3e, - 0x1363c, - 0x1121e, - 0x1361e, - 0x1f89a, // 340 - 0x1137c, - 0x1f9ba, - 0x1377c, - 0x1133e, - 0x1373e, - 0x1f13a, - 0x1f37a, - 0x1e27a, - 0x1e6fa, - 0x1c4fa, // 350 - 0x1cdfa, - 0x189fa, - 0x1bae0, - 0x1dd78, - 0x1eebe, - 0x174c0, - 0x1ba70, - 0x1dd3c, - 0x17460, - 0x1ba38, // 360 - 0x1dd1e, - 0x17430, - 0x1ba1c, - 0x17418, - 0x1ba0e, - 0x1740c, - 0x132e0, - 0x19978, - 0x1ccbe, - 0x176e0, // 370 - 0x13270, - 0x1993c, - 0x17670, - 0x1bb3c, - 0x1991e, - 0x17638, - 0x1321c, - 0x1761c, - 0x1320e, - 0x1760e, // 380 - 0x11178, - 0x188be, - 0x13378, - 0x1113c, - 0x17778, - 0x1333c, - 0x1111e, - 0x1773c, - 0x1331e, - 0x1771e, // 390 - 0x111be, - 0x133be, - 0x177be, - 0x172c0, - 0x1b970, - 0x1dcbc, - 0x17260, - 0x1b938, - 0x1dc9e, - 0x17230, // 400 - 0x1b91c, - 0x17218, - 0x1b90e, - 0x1720c, - 0x17206, - 0x13170, - 0x198bc, - 0x17370, - 0x13138, - 0x1989e, // 410 - 0x17338, - 0x1b99e, - 0x1731c, - 0x1310e, - 0x1730e, - 0x110bc, - 0x131bc, - 0x1109e, - 0x173bc, - 0x1319e, // 420 - 0x1739e, - 0x17160, - 0x1b8b8, - 0x1dc5e, - 0x17130, - 0x1b89c, - 0x17118, - 0x1b88e, - 0x1710c, - 0x17106, // 430 - 0x130b8, - 0x1985e, - 0x171b8, - 0x1309c, - 0x1719c, - 0x1308e, - 0x1718e, - 0x1105e, - 0x130de, - 0x171de, // 440 - 0x170b0, - 0x1b85c, - 0x17098, - 0x1b84e, - 0x1708c, - 0x17086, - 0x1305c, - 0x170dc, - 0x1304e, - 0x170ce, // 450 - 0x17058, - 0x1b82e, - 0x1704c, - 0x17046, - 0x1302e, - 0x1706e, - 0x1702c, - 0x17026, - 0x10af0, - 0x1857c, // 460 - 0x10a78, - 0x1853e, - 0x10a3c, - 0x10a1e, - 0x10b7c, - 0x10b3e, - 0x1f0ba, - 0x1e17a, - 0x1c2fa, - 0x185fa, // 470 - 0x11ae0, - 0x18d78, - 0x1c6be, - 0x11a70, - 0x18d3c, - 0x11a38, - 0x18d1e, - 0x11a1c, - 0x11a0e, - 0x10978, // 480 - 0x184be, - 0x11b78, - 0x1093c, - 0x11b3c, - 0x1091e, - 0x11b1e, - 0x109be, - 0x11bbe, - 0x13ac0, - 0x19d70, // 490 - 0x1cebc, - 0x13a60, - 0x19d38, - 0x1ce9e, - 0x13a30, - 0x19d1c, - 0x13a18, - 0x19d0e, - 0x13a0c, - 0x13a06, // 500 - 0x11970, - 0x18cbc, - 0x13b70, - 0x11938, - 0x18c9e, - 0x13b38, - 0x1191c, - 0x13b1c, - 0x1190e, - 0x13b0e, // 510 - 0x108bc, - 0x119bc, - 0x1089e, - 0x13bbc, - 0x1199e, - 0x13b9e, - 0x1bd60, - 0x1deb8, - 0x1ef5e, - 0x17a40, // 520 - 0x1bd30, - 0x1de9c, - 0x17a20, - 0x1bd18, - 0x1de8e, - 0x17a10, - 0x1bd0c, - 0x17a08, - 0x1bd06, - 0x17a04, // 530 - 0x13960, - 0x19cb8, - 0x1ce5e, - 0x17b60, - 0x13930, - 0x19c9c, - 0x17b30, - 0x1bd9c, - 0x19c8e, - 0x17b18, // 540 - 0x1390c, - 0x17b0c, - 0x13906, - 0x17b06, - 0x118b8, - 0x18c5e, - 0x139b8, - 0x1189c, - 0x17bb8, - 0x1399c, // 550 - 0x1188e, - 0x17b9c, - 0x1398e, - 0x17b8e, - 0x1085e, - 0x118de, - 0x139de, - 0x17bde, - 0x17940, - 0x1bcb0, // 560 - 0x1de5c, - 0x17920, - 0x1bc98, - 0x1de4e, - 0x17910, - 0x1bc8c, - 0x17908, - 0x1bc86, - 0x17904, - 0x17902, // 570 - 0x138b0, - 0x19c5c, - 0x179b0, - 0x13898, - 0x19c4e, - 0x17998, - 0x1bcce, - 0x1798c, - 0x13886, - 0x17986, // 580 - 0x1185c, - 0x138dc, - 0x1184e, - 0x179dc, - 0x138ce, - 0x179ce, - 0x178a0, - 0x1bc58, - 0x1de2e, - 0x17890, // 590 - 0x1bc4c, - 0x17888, - 0x1bc46, - 0x17884, - 0x17882, - 0x13858, - 0x19c2e, - 0x178d8, - 0x1384c, - 0x178cc, // 600 - 0x13846, - 0x178c6, - 0x1182e, - 0x1386e, - 0x178ee, - 0x17850, - 0x1bc2c, - 0x17848, - 0x1bc26, - 0x17844, // 610 - 0x17842, - 0x1382c, - 0x1786c, - 0x13826, - 0x17866, - 0x17828, - 0x1bc16, - 0x17824, - 0x17822, - 0x13816, // 620 - 0x17836, - 0x10578, - 0x182be, - 0x1053c, - 0x1051e, - 0x105be, - 0x10d70, - 0x186bc, - 0x10d38, - 0x1869e, // 630 - 0x10d1c, - 0x10d0e, - 0x104bc, - 0x10dbc, - 0x1049e, - 0x10d9e, - 0x11d60, - 0x18eb8, - 0x1c75e, - 0x11d30, // 640 - 0x18e9c, - 0x11d18, - 0x18e8e, - 0x11d0c, - 0x11d06, - 0x10cb8, - 0x1865e, - 0x11db8, - 0x10c9c, - 0x11d9c, // 650 - 0x10c8e, - 0x11d8e, - 0x1045e, - 0x10cde, - 0x11dde, - 0x13d40, - 0x19eb0, - 0x1cf5c, - 0x13d20, - 0x19e98, // 660 - 0x1cf4e, - 0x13d10, - 0x19e8c, - 0x13d08, - 0x19e86, - 0x13d04, - 0x13d02, - 0x11cb0, - 0x18e5c, - 0x13db0, // 670 - 0x11c98, - 0x18e4e, - 0x13d98, - 0x19ece, - 0x13d8c, - 0x11c86, - 0x13d86, - 0x10c5c, - 0x11cdc, - 0x10c4e, // 680 - 0x13ddc, - 0x11cce, - 0x13dce, - 0x1bea0, - 0x1df58, - 0x1efae, - 0x1be90, - 0x1df4c, - 0x1be88, - 0x1df46, // 690 - 0x1be84, - 0x1be82, - 0x13ca0, - 0x19e58, - 0x1cf2e, - 0x17da0, - 0x13c90, - 0x19e4c, - 0x17d90, - 0x1becc, // 700 - 0x19e46, - 0x17d88, - 0x13c84, - 0x17d84, - 0x13c82, - 0x17d82, - 0x11c58, - 0x18e2e, - 0x13cd8, - 0x11c4c, // 710 - 0x17dd8, - 0x13ccc, - 0x11c46, - 0x17dcc, - 0x13cc6, - 0x17dc6, - 0x10c2e, - 0x11c6e, - 0x13cee, - 0x17dee, // 720 - 0x1be50, - 0x1df2c, - 0x1be48, - 0x1df26, - 0x1be44, - 0x1be42, - 0x13c50, - 0x19e2c, - 0x17cd0, - 0x13c48, // 730 - 0x19e26, - 0x17cc8, - 0x1be66, - 0x17cc4, - 0x13c42, - 0x17cc2, - 0x11c2c, - 0x13c6c, - 0x11c26, - 0x17cec, // 740 - 0x13c66, - 0x17ce6, - 0x1be28, - 0x1df16, - 0x1be24, - 0x1be22, - 0x13c28, - 0x19e16, - 0x17c68, - 0x13c24, // 750 - 0x17c64, - 0x13c22, - 0x17c62, - 0x11c16, - 0x13c36, - 0x17c76, - 0x1be14, - 0x1be12, - 0x13c14, - 0x17c34, // 760 - 0x13c12, - 0x17c32, - 0x102bc, - 0x1029e, - 0x106b8, - 0x1835e, - 0x1069c, - 0x1068e, - 0x1025e, - 0x106de, // 770 - 0x10eb0, - 0x1875c, - 0x10e98, - 0x1874e, - 0x10e8c, - 0x10e86, - 0x1065c, - 0x10edc, - 0x1064e, - 0x10ece, // 780 - 0x11ea0, - 0x18f58, - 0x1c7ae, - 0x11e90, - 0x18f4c, - 0x11e88, - 0x18f46, - 0x11e84, - 0x11e82, - 0x10e58, // 790 - 0x1872e, - 0x11ed8, - 0x18f6e, - 0x11ecc, - 0x10e46, - 0x11ec6, - 0x1062e, - 0x10e6e, - 0x11eee, - 0x19f50, // 800 - 0x1cfac, - 0x19f48, - 0x1cfa6, - 0x19f44, - 0x19f42, - 0x11e50, - 0x18f2c, - 0x13ed0, - 0x19f6c, - 0x18f26, // 810 - 0x13ec8, - 0x11e44, - 0x13ec4, - 0x11e42, - 0x13ec2, - 0x10e2c, - 0x11e6c, - 0x10e26, - 0x13eec, - 0x11e66, // 820 - 0x13ee6, - 0x1dfa8, - 0x1efd6, - 0x1dfa4, - 0x1dfa2, - 0x19f28, - 0x1cf96, - 0x1bf68, - 0x19f24, - 0x1bf64, // 830 - 0x19f22, - 0x1bf62, - 0x11e28, - 0x18f16, - 0x13e68, - 0x11e24, - 0x17ee8, - 0x13e64, - 0x11e22, - 0x17ee4, // 840 - 0x13e62, - 0x17ee2, - 0x10e16, - 0x11e36, - 0x13e76, - 0x17ef6, - 0x1df94, - 0x1df92, - 0x19f14, - 0x1bf34, // 850 - 0x19f12, - 0x1bf32, - 0x11e14, - 0x13e34, - 0x11e12, - 0x17e74, - 0x13e32, - 0x17e72, - 0x1df8a, - 0x19f0a, // 860 - 0x1bf1a, - 0x11e0a, - 0x13e1a, - 0x17e3a, - 0x1035c, - 0x1034e, - 0x10758, - 0x183ae, - 0x1074c, - 0x10746, // 870 - 0x1032e, - 0x1076e, - 0x10f50, - 0x187ac, - 0x10f48, - 0x187a6, - 0x10f44, - 0x10f42, - 0x1072c, - 0x10f6c, // 880 - 0x10726, - 0x10f66, - 0x18fa8, - 0x1c7d6, - 0x18fa4, - 0x18fa2, - 0x10f28, - 0x18796, - 0x11f68, - 0x18fb6, // 890 - 0x11f64, - 0x10f22, - 0x11f62, - 0x10716, - 0x10f36, - 0x11f76, - 0x1cfd4, - 0x1cfd2, - 0x18f94, - 0x19fb4, // 900 - 0x18f92, - 0x19fb2, - 0x10f14, - 0x11f34, - 0x10f12, - 0x13f74, - 0x11f32, - 0x13f72, - 0x1cfca, - 0x18f8a, // 910 - 0x19f9a, - 0x10f0a, - 0x11f1a, - 0x13f3a, - 0x103ac, - 0x103a6, - 0x107a8, - 0x183d6, - 0x107a4, - 0x107a2, // 920 - 0x10396, - 0x107b6, - 0x187d4, - 0x187d2, - 0x10794, - 0x10fb4, - 0x10792, - 0x10fb2, - 0x1c7ea - ) // 929 - ); // end of $clusters array - - /** - * Array of factors of the Reed-Solomon polynomial equations used for error correction; one sub array for each correction level (0-8). - * @protected - */ - protected $rsfactors = array( - array( // ECL 0 (2 factors) ------------------------------------------------------------------------------- - 0x01b, - 0x395 - ), // 2 - array( // ECL 1 (4 factors) ------------------------------------------------------------------------------- - 0x20a, - 0x238, - 0x2d3, - 0x329 - ), // 4 - array( // ECL 2 (8 factors) ------------------------------------------------------------------------------- - 0x0ed, - 0x134, - 0x1b4, - 0x11c, - 0x286, - 0x28d, - 0x1ac, - 0x17b - ), // 8 - array( // ECL 3 (16 factors) ------------------------------------------------------------------------------ - 0x112, - 0x232, - 0x0e8, - 0x2f3, - 0x257, - 0x20c, - 0x321, - 0x084, - 0x127, - 0x074, - 0x1ba, - 0x1ac, - 0x127, - 0x02a, - 0x0b0, - 0x041 - ), // 16 - array( // ECL 4 (32 factors) ------------------------------------------------------------------------------ - 0x169, - 0x23f, - 0x39a, - 0x20d, - 0x0b0, - 0x24a, - 0x280, - 0x141, - 0x218, - 0x2e6, - 0x2a5, - 0x2e6, - 0x2af, - 0x11c, - 0x0c1, - 0x205, // 16 - 0x111, - 0x1ee, - 0x107, - 0x093, - 0x251, - 0x320, - 0x23b, - 0x140, - 0x323, - 0x085, - 0x0e7, - 0x186, - 0x2ad, - 0x14a, - 0x03f, - 0x19a - ), // 32 - array( // ECL 5 (64 factors) ------------------------------------------------------------------------------ - 0x21b, - 0x1a6, - 0x006, - 0x05d, - 0x35e, - 0x303, - 0x1c5, - 0x06a, - 0x262, - 0x11f, - 0x06b, - 0x1f9, - 0x2dd, - 0x36d, - 0x17d, - 0x264, // 16 - 0x2d3, - 0x1dc, - 0x1ce, - 0x0ac, - 0x1ae, - 0x261, - 0x35a, - 0x336, - 0x21f, - 0x178, - 0x1ff, - 0x190, - 0x2a0, - 0x2fa, - 0x11b, - 0x0b8, // 32 - 0x1b8, - 0x023, - 0x207, - 0x01f, - 0x1cc, - 0x252, - 0x0e1, - 0x217, - 0x205, - 0x160, - 0x25d, - 0x09e, - 0x28b, - 0x0c9, - 0x1e8, - 0x1f6, // 48 - 0x288, - 0x2dd, - 0x2cd, - 0x053, - 0x194, - 0x061, - 0x118, - 0x303, - 0x348, - 0x275, - 0x004, - 0x17d, - 0x34b, - 0x26f, - 0x108, - 0x21f - ), // 64 - array( // ECL 6 (128 factors) ----------------------------------------------------------------------------- - 0x209, - 0x136, - 0x360, - 0x223, - 0x35a, - 0x244, - 0x128, - 0x17b, - 0x035, - 0x30b, - 0x381, - 0x1bc, - 0x190, - 0x39d, - 0x2ed, - 0x19f, // 16 - 0x336, - 0x05d, - 0x0d9, - 0x0d0, - 0x3a0, - 0x0f4, - 0x247, - 0x26c, - 0x0f6, - 0x094, - 0x1bf, - 0x277, - 0x124, - 0x38c, - 0x1ea, - 0x2c0, // 32 - 0x204, - 0x102, - 0x1c9, - 0x38b, - 0x252, - 0x2d3, - 0x2a2, - 0x124, - 0x110, - 0x060, - 0x2ac, - 0x1b0, - 0x2ae, - 0x25e, - 0x35c, - 0x239, // 48 - 0x0c1, - 0x0db, - 0x081, - 0x0ba, - 0x0ec, - 0x11f, - 0x0c0, - 0x307, - 0x116, - 0x0ad, - 0x028, - 0x17b, - 0x2c8, - 0x1cf, - 0x286, - 0x308, // 64 - 0x0ab, - 0x1eb, - 0x129, - 0x2fb, - 0x09c, - 0x2dc, - 0x05f, - 0x10e, - 0x1bf, - 0x05a, - 0x1fb, - 0x030, - 0x0e4, - 0x335, - 0x328, - 0x382, // 80 - 0x310, - 0x297, - 0x273, - 0x17a, - 0x17e, - 0x106, - 0x17c, - 0x25a, - 0x2f2, - 0x150, - 0x059, - 0x266, - 0x057, - 0x1b0, - 0x29e, - 0x268, // 96 - 0x09d, - 0x176, - 0x0f2, - 0x2d6, - 0x258, - 0x10d, - 0x177, - 0x382, - 0x34d, - 0x1c6, - 0x162, - 0x082, - 0x32e, - 0x24b, - 0x324, - 0x022, // 112 - 0x0d3, - 0x14a, - 0x21b, - 0x129, - 0x33b, - 0x361, - 0x025, - 0x205, - 0x342, - 0x13b, - 0x226, - 0x056, - 0x321, - 0x004, - 0x06c, - 0x21b - ), // 128 - array( // ECL 7 (256 factors) ----------------------------------------------------------------------------- - 0x20c, - 0x37e, - 0x04b, - 0x2fe, - 0x372, - 0x359, - 0x04a, - 0x0cc, - 0x052, - 0x24a, - 0x2c4, - 0x0fa, - 0x389, - 0x312, - 0x08a, - 0x2d0, // 16 - 0x35a, - 0x0c2, - 0x137, - 0x391, - 0x113, - 0x0be, - 0x177, - 0x352, - 0x1b6, - 0x2dd, - 0x0c2, - 0x118, - 0x0c9, - 0x118, - 0x33c, - 0x2f5, // 32 - 0x2c6, - 0x32e, - 0x397, - 0x059, - 0x044, - 0x239, - 0x00b, - 0x0cc, - 0x31c, - 0x25d, - 0x21c, - 0x391, - 0x321, - 0x2bc, - 0x31f, - 0x089, // 48 - 0x1b7, - 0x1a2, - 0x250, - 0x29c, - 0x161, - 0x35b, - 0x172, - 0x2b6, - 0x145, - 0x0f0, - 0x0d8, - 0x101, - 0x11c, - 0x225, - 0x0d1, - 0x374, // 64 - 0x13b, - 0x046, - 0x149, - 0x319, - 0x1ea, - 0x112, - 0x36d, - 0x0a2, - 0x2ed, - 0x32c, - 0x2ac, - 0x1cd, - 0x14e, - 0x178, - 0x351, - 0x209, // 80 - 0x133, - 0x123, - 0x323, - 0x2c8, - 0x013, - 0x166, - 0x18f, - 0x38c, - 0x067, - 0x1ff, - 0x033, - 0x008, - 0x205, - 0x0e1, - 0x121, - 0x1d6, // 96 - 0x27d, - 0x2db, - 0x042, - 0x0ff, - 0x395, - 0x10d, - 0x1cf, - 0x33e, - 0x2da, - 0x1b1, - 0x350, - 0x249, - 0x088, - 0x21a, - 0x38a, - 0x05a, // 112 - 0x002, - 0x122, - 0x2e7, - 0x0c7, - 0x28f, - 0x387, - 0x149, - 0x031, - 0x322, - 0x244, - 0x163, - 0x24c, - 0x0bc, - 0x1ce, - 0x00a, - 0x086, // 128 - 0x274, - 0x140, - 0x1df, - 0x082, - 0x2e3, - 0x047, - 0x107, - 0x13e, - 0x176, - 0x259, - 0x0c0, - 0x25d, - 0x08e, - 0x2a1, - 0x2af, - 0x0ea, // 144 - 0x2d2, - 0x180, - 0x0b1, - 0x2f0, - 0x25f, - 0x280, - 0x1c7, - 0x0c1, - 0x2b1, - 0x2c3, - 0x325, - 0x281, - 0x030, - 0x03c, - 0x2dc, - 0x26d, // 160 - 0x37f, - 0x220, - 0x105, - 0x354, - 0x28f, - 0x135, - 0x2b9, - 0x2f3, - 0x2f4, - 0x03c, - 0x0e7, - 0x305, - 0x1b2, - 0x1a5, - 0x2d6, - 0x210, // 176 - 0x1f7, - 0x076, - 0x031, - 0x31b, - 0x020, - 0x090, - 0x1f4, - 0x0ee, - 0x344, - 0x18a, - 0x118, - 0x236, - 0x13f, - 0x009, - 0x287, - 0x226, // 192 - 0x049, - 0x392, - 0x156, - 0x07e, - 0x020, - 0x2a9, - 0x14b, - 0x318, - 0x26c, - 0x03c, - 0x261, - 0x1b9, - 0x0b4, - 0x317, - 0x37d, - 0x2f2, // 208 - 0x25d, - 0x17f, - 0x0e4, - 0x2ed, - 0x2f8, - 0x0d5, - 0x036, - 0x129, - 0x086, - 0x036, - 0x342, - 0x12b, - 0x39a, - 0x0bf, - 0x38e, - 0x214, // 224 - 0x261, - 0x33d, - 0x0bd, - 0x014, - 0x0a7, - 0x01d, - 0x368, - 0x1c1, - 0x053, - 0x192, - 0x029, - 0x290, - 0x1f9, - 0x243, - 0x1e1, - 0x0ad, // 240 - 0x194, - 0x0fb, - 0x2b0, - 0x05f, - 0x1f1, - 0x22b, - 0x282, - 0x21f, - 0x133, - 0x09f, - 0x39c, - 0x22e, - 0x288, - 0x037, - 0x1f1, - 0x00a - ), // 256 - array( // ECL 8 (512 factors) ----------------------------------------------------------------------------- - 0x160, - 0x04d, - 0x175, - 0x1f8, - 0x023, - 0x257, - 0x1ac, - 0x0cf, - 0x199, - 0x23e, - 0x076, - 0x1f2, - 0x11d, - 0x17c, - 0x15e, - 0x1ec, // 16 - 0x0c5, - 0x109, - 0x398, - 0x09b, - 0x392, - 0x12b, - 0x0e5, - 0x283, - 0x126, - 0x367, - 0x132, - 0x058, - 0x057, - 0x0c1, - 0x160, - 0x30d, // 32 - 0x34e, - 0x04b, - 0x147, - 0x208, - 0x1b3, - 0x21f, - 0x0cb, - 0x29a, - 0x0f9, - 0x15a, - 0x30d, - 0x26d, - 0x280, - 0x10c, - 0x31a, - 0x216, // 48 - 0x21b, - 0x30d, - 0x198, - 0x186, - 0x284, - 0x066, - 0x1dc, - 0x1f3, - 0x122, - 0x278, - 0x221, - 0x025, - 0x35a, - 0x394, - 0x228, - 0x029, // 64 - 0x21e, - 0x121, - 0x07a, - 0x110, - 0x17f, - 0x320, - 0x1e5, - 0x062, - 0x2f0, - 0x1d8, - 0x2f9, - 0x06b, - 0x310, - 0x35c, - 0x292, - 0x2e5, // 80 - 0x122, - 0x0cc, - 0x2a9, - 0x197, - 0x357, - 0x055, - 0x063, - 0x03e, - 0x1e2, - 0x0b4, - 0x014, - 0x129, - 0x1c3, - 0x251, - 0x391, - 0x08e, // 96 - 0x328, - 0x2ac, - 0x11f, - 0x218, - 0x231, - 0x04c, - 0x28d, - 0x383, - 0x2d9, - 0x237, - 0x2e8, - 0x186, - 0x201, - 0x0c0, - 0x204, - 0x102, // 112 - 0x0f0, - 0x206, - 0x31a, - 0x18b, - 0x300, - 0x350, - 0x033, - 0x262, - 0x180, - 0x0a8, - 0x0be, - 0x33a, - 0x148, - 0x254, - 0x312, - 0x12f, // 128 - 0x23a, - 0x17d, - 0x19f, - 0x281, - 0x09c, - 0x0ed, - 0x097, - 0x1ad, - 0x213, - 0x0cf, - 0x2a4, - 0x2c6, - 0x059, - 0x0a8, - 0x130, - 0x192, // 144 - 0x028, - 0x2c4, - 0x23f, - 0x0a2, - 0x360, - 0x0e5, - 0x041, - 0x35d, - 0x349, - 0x200, - 0x0a4, - 0x1dd, - 0x0dd, - 0x05c, - 0x166, - 0x311, // 160 - 0x120, - 0x165, - 0x352, - 0x344, - 0x33b, - 0x2e0, - 0x2c3, - 0x05e, - 0x008, - 0x1ee, - 0x072, - 0x209, - 0x002, - 0x1f3, - 0x353, - 0x21f, // 176 - 0x098, - 0x2d9, - 0x303, - 0x05f, - 0x0f8, - 0x169, - 0x242, - 0x143, - 0x358, - 0x31d, - 0x121, - 0x033, - 0x2ac, - 0x1d2, - 0x215, - 0x334, // 192 - 0x29d, - 0x02d, - 0x386, - 0x1c4, - 0x0a7, - 0x156, - 0x0f4, - 0x0ad, - 0x023, - 0x1cf, - 0x28b, - 0x033, - 0x2bb, - 0x24f, - 0x1c4, - 0x242, // 208 - 0x025, - 0x07c, - 0x12a, - 0x14c, - 0x228, - 0x02b, - 0x1ab, - 0x077, - 0x296, - 0x309, - 0x1db, - 0x352, - 0x2fc, - 0x16c, - 0x242, - 0x38f, // 224 - 0x11b, - 0x2c7, - 0x1d8, - 0x1a4, - 0x0f5, - 0x120, - 0x252, - 0x18a, - 0x1ff, - 0x147, - 0x24d, - 0x309, - 0x2bb, - 0x2b0, - 0x02b, - 0x198, // 240 - 0x34a, - 0x17f, - 0x2d1, - 0x209, - 0x230, - 0x284, - 0x2ca, - 0x22f, - 0x03e, - 0x091, - 0x369, - 0x297, - 0x2c9, - 0x09f, - 0x2a0, - 0x2d9, // 256 - 0x270, - 0x03b, - 0x0c1, - 0x1a1, - 0x09e, - 0x0d1, - 0x233, - 0x234, - 0x157, - 0x2b5, - 0x06d, - 0x260, - 0x233, - 0x16d, - 0x0b5, - 0x304, // 272 - 0x2a5, - 0x136, - 0x0f8, - 0x161, - 0x2c4, - 0x19a, - 0x243, - 0x366, - 0x269, - 0x349, - 0x278, - 0x35c, - 0x121, - 0x218, - 0x023, - 0x309, // 288 - 0x26a, - 0x24a, - 0x1a8, - 0x341, - 0x04d, - 0x255, - 0x15a, - 0x10d, - 0x2f5, - 0x278, - 0x2b7, - 0x2ef, - 0x14b, - 0x0f7, - 0x0b8, - 0x02d, // 304 - 0x313, - 0x2a8, - 0x012, - 0x042, - 0x197, - 0x171, - 0x036, - 0x1ec, - 0x0e4, - 0x265, - 0x33e, - 0x39a, - 0x1b5, - 0x207, - 0x284, - 0x389, // 320 - 0x315, - 0x1a4, - 0x131, - 0x1b9, - 0x0cf, - 0x12c, - 0x37c, - 0x33b, - 0x08d, - 0x219, - 0x17d, - 0x296, - 0x201, - 0x038, - 0x0fc, - 0x155, // 336 - 0x0f2, - 0x31d, - 0x346, - 0x345, - 0x2d0, - 0x0e0, - 0x133, - 0x277, - 0x03d, - 0x057, - 0x230, - 0x136, - 0x2f4, - 0x299, - 0x18d, - 0x328, // 352 - 0x353, - 0x135, - 0x1d9, - 0x31b, - 0x17a, - 0x01f, - 0x287, - 0x393, - 0x1cb, - 0x326, - 0x24e, - 0x2db, - 0x1a9, - 0x0d8, - 0x224, - 0x0f9, // 368 - 0x141, - 0x371, - 0x2bb, - 0x217, - 0x2a1, - 0x30e, - 0x0d2, - 0x32f, - 0x389, - 0x12f, - 0x34b, - 0x39a, - 0x119, - 0x049, - 0x1d5, - 0x317, // 384 - 0x294, - 0x0a2, - 0x1f2, - 0x134, - 0x09b, - 0x1a6, - 0x38b, - 0x331, - 0x0bb, - 0x03e, - 0x010, - 0x1a9, - 0x217, - 0x150, - 0x11e, - 0x1b5, // 400 - 0x177, - 0x111, - 0x262, - 0x128, - 0x0b7, - 0x39b, - 0x074, - 0x29b, - 0x2ef, - 0x161, - 0x03e, - 0x16e, - 0x2b3, - 0x17b, - 0x2af, - 0x34a, // 416 - 0x025, - 0x165, - 0x2d0, - 0x2e6, - 0x14a, - 0x005, - 0x027, - 0x39b, - 0x137, - 0x1a8, - 0x0f2, - 0x2ed, - 0x141, - 0x036, - 0x29d, - 0x13c, // 432 - 0x156, - 0x12b, - 0x216, - 0x069, - 0x29b, - 0x1e8, - 0x280, - 0x2a0, - 0x240, - 0x21c, - 0x13c, - 0x1e6, - 0x2d1, - 0x262, - 0x02e, - 0x290, // 448 - 0x1bf, - 0x0ab, - 0x268, - 0x1d0, - 0x0be, - 0x213, - 0x129, - 0x141, - 0x2fa, - 0x2f0, - 0x215, - 0x0af, - 0x086, - 0x00e, - 0x17d, - 0x1b1, // 464 - 0x2cd, - 0x02d, - 0x06f, - 0x014, - 0x254, - 0x11c, - 0x2e0, - 0x08a, - 0x286, - 0x19b, - 0x36d, - 0x29d, - 0x08d, - 0x397, - 0x02d, - 0x30c, // 480 - 0x197, - 0x0a4, - 0x14c, - 0x383, - 0x0a5, - 0x2d6, - 0x258, - 0x145, - 0x1f2, - 0x28f, - 0x165, - 0x2f0, - 0x300, - 0x0df, - 0x351, - 0x287, // 496 - 0x03f, - 0x136, - 0x35f, - 0x0fb, - 0x16e, - 0x130, - 0x11a, - 0x2e2, - 0x2a3, - 0x19a, - 0x185, - 0x0f4, - 0x01f, - 0x079, - 0x12f, - 0x107 - ) // 512 - ); - - /** - * This is the class constructor - Creates a PDF417 object - * - * @param string $code - * @param int $ecl - * @param int $aspectratio - * - * @param array $macro - */ - public function __construct($code, $ecl = -1, $aspectratio = 2, $macro = array()) - { - $cL = null; - $emptyRow = null; - $macrocw = array(); - $barcodeArray = array(); - - if ((is_null($code)) || ($code == '\0') || ($code == '')) { - return false; - } - // get the input sequence array - $sequence = $this->getInputSequences($code); - $codewords = array(); // array of code-words - foreach ($sequence as $seq) { - $cw = $this->getCompaction($seq[0], $seq[1], true); - $codewords = array_merge($codewords, $cw); - } - if ($codewords[0] == 900) { - // Text Alpha is the default mode, so remove the first code - array_shift($codewords); - } - // count number of codewords - $numcw = count($codewords); - if ($numcw > 925) { - // reached maximum data codeword capacity - return false; - } - // build macro control block codewords - if (!empty($macro)) { - - // beginning of macro control block - $macrocw[] = 928; - // segment index - $cw = $this->getCompaction(902, sprintf('%05d', $macro['segment_index']), false); - $macrocw = array_merge($macrocw, $cw); - // file ID - $cw = $this->getCompaction(900, $macro['file_id'], false); - $macrocw = array_merge($macrocw, $cw); - // optional fields - $optmodes = array(900, 902, 902, 900, 900, 902, 902); - $optsize = array(-1, 2, 4, -1, -1, -1, 2); - foreach ($optmodes as $k => $omode) { - if (isset($macro['option_' . $k])) { - $macrocw[] = 923; - $macrocw[] = $k; - if ($optsize[$k] == 2) { - $macro['option_' . $k] = sprintf('%05d', $macro['option_' . $k]); - } elseif ($optsize[$k] == 4) { - $macro['option_' . $k] = sprintf('%010d', $macro['option_' . $k]); - } - $cw = $this->getCompaction($omode, $macro['option_' . $k], false); - $macrocw = array_merge($macrocw, $cw); - } - } - if ($macro['segment_index'] == ($macro['segment_total'] - 1)) { - // end of control block - $macrocw[] = 922; - } - // update total codewords - $numcw += count($macrocw); - } - // set error correction level - $ecl = $this->getErrorCorrectionLevel($ecl, $numcw); - // number of codewords for error correction - $errsize = (2 << $ecl); - // calculate number of columns (number of codewords per row) and rows - $nce = ($numcw + $errsize + 1); - $cols = round((sqrt(4761 + (68 * $aspectratio * self::ROWHEIGHT * $nce)) - 69) / 34); - // adjust cols - if ($cols < 1) { - $cols = 1; - } elseif ($cols > 30) { - $cols = 30; - } - $rows = ceil($nce / $cols); - $size = ($cols * $rows); - // adjust rows - if (($rows < 3) || ($rows > 90)) { - if ($rows < 3) { - $rows = 3; - } elseif ($rows > 90) { - $rows = 90; - } - $cols = ceil($size / $rows); - $size = ($cols * $rows); - } - if ($size > 928) { - // set dimensions to get maximum capacity - if (abs($aspectratio - (17 * 29 / 32)) < abs($aspectratio - (17 * 16 / 58))) { - $cols = 29; - $rows = 32; - } else { - $cols = 16; - $rows = 58; - } - $size = 928; - } - // calculate padding - $pad = ($size - $nce); - if ($pad > 0) { - if (($size - $rows) == $nce) { - --$rows; - $size -= $rows; - } else { - // add pading - $codewords = array_merge($codewords, array_fill(0, $pad, 900)); - } - } - if (!empty($macro)) { - // add macro section - $codewords = array_merge($codewords, $macrocw); - } - // Symbol Lenght Descriptor (number of data codewords including Symbol Lenght Descriptor and pad codewords) - $sld = $size - $errsize; - // add symbol length description - array_unshift($codewords, $sld); - // calculate error correction - $ecw = $this->getErrorCorrection($codewords, $ecl); - // add error correction codewords - $codewords = array_merge($codewords, $ecw); - // add horizontal quiet zones to start and stop patterns - $pstart = str_repeat('0', self::QUIETH) . $this->startPattern; - $pstop = $this->stopPattern . str_repeat('0', self::QUIETH); - $barcodeArray['num_rows'] = ($rows * self::ROWHEIGHT) + (2 * self::QUIETV); - $barcodeArray['num_cols'] = (($cols + 2) * 17) + 35 + (2 * self::QUIETH); - $barcodeArray['bcode'] = array(); - // build rows for vertical quiet zone - if (self::QUIETV > 0) { - $emptyRow = array_fill(0, $barcodeArray['num_cols'], 0); - for ($i = 0; $i < self::QUIETV; ++$i) { - // add vertical quiet rows - $barcodeArray['bcode'][] = $emptyRow; - } - } - $k = 0; // codeword index - $cid = 0; // initial cluster - // for each row - for ($r = 0; $r < $rows; ++$r) { - // row start code - $row = $pstart; - switch ($cid) { - case 0: - $cL = ((30 * intval($r / 3)) + intval(($rows - 1) / 3)); - break; - - case 1: - $cL = ((30 * intval($r / 3)) + ($ecl * 3) + (($rows - 1) % 3)); - break; - - case 2: - $cL = ((30 * intval($r / 3)) + ($cols - 1)); - break; - - } - - // left row indicator - $row .= sprintf('%17b', $this->clusters[$cid][$cL]); - // for each column - for ($c = 0; $c < $cols; ++$c) { - $row .= sprintf('%17b', $this->clusters[$cid][$codewords[$k]]); - ++$k; - } - - switch ($cid) { - case 0: - $cL = ((30 * intval($r / 3)) + ($cols - 1)); - break; - - case 1: - $cL = ((30 * intval($r / 3)) + intval(($rows - 1) / 3)); - break; - - case 2: - $cL = ((30 * intval($r / 3)) + ($ecl * 3) + (($rows - 1) % 3)); - break; - - } - // right row indicator - $row .= sprintf('%17b', $this->clusters[$cid][$cL]); - // row stop code - $row .= $pstop; - // convert the string to array - $arow = preg_split('//', $row, -1, PREG_SPLIT_NO_EMPTY); - // duplicate row to get the desired height - for ($h = 0; $h < self::ROWHEIGHT; ++$h) { - $barcodeArray['bcode'][] = $arow; - } - ++$cid; - if ($cid > 2) { - $cid = 0; - } - } - if (self::QUIETV > 0) { - for ($i = 0; $i < self::QUIETV; ++$i) { - // add vertical quiet rows - $barcodeArray['bcode'][] = $emptyRow; - } - } - $this->barcodeArray = $barcodeArray; - - return false; - } - - /** - * Returns a barcode array which is readable by Dinesh Rabara - * @return array barcode array readable by Dinesh Rabara; - * @public - */ - public function getBarcodeArray() - { - return $this->barcodeArray; - } - - /** - * Returns the error correction level (0-8) to be used - * - * @param int $ecl - * @param int $numcw - * - * @return int - */ - protected function getErrorCorrectionLevel($ecl, $numcw) - { - // get maximum correction level - $maxecl = 8; // starting error level - $maxerrsize = (928 - $numcw); // available codewords for error - while ($maxecl > 0) { - $errsize = (2 << $ecl); - if ($maxerrsize >= $errsize) { - break; - } - --$maxecl; - } - // check for automatic levels - if (($ecl < 0) || ($ecl > 8)) { - if ($numcw < 41) { - $ecl = 2; - } elseif ($numcw < 161) { - $ecl = 3; - } elseif ($numcw < 321) { - $ecl = 4; - } elseif ($numcw < 864) { - $ecl = 5; - } else { - $ecl = $maxecl; - } - } - if ($ecl > $maxecl) { - $ecl = $maxecl; - } - - return $ecl; - } - - /** - * Returns the error correction codewords - * - * @param array $cw - * @param int $ecl - * - * @return array - */ - protected function getErrorCorrection($cw, $ecl) - { - // get error correction coefficients - $ecc = $this->rsfactors[$ecl]; - // number of error correction factors - $eclsize = (2 << $ecl); - // maximum index for $rsfactors[$ecl] - $eclmaxid = ($eclsize - 1); - // initialize array of error correction codewords - $ecw = array_fill(0, $eclsize, 0); - // for each data codeword - foreach ($cw as $d) { - $t1 = ($d + $ecw[$eclmaxid]) % 929; - for ($j = $eclmaxid; $j > 0; --$j) { - $t2 = ($t1 * $ecc[$j]) % 929; - $t3 = 929 - $t2; - $ecw[$j] = ($ecw[($j - 1)] + $t3) % 929; - } - $t2 = ($t1 * $ecc[0]) % 929; - $t3 = 929 - $t2; - $ecw[0] = $t3 % 929; - } - foreach ($ecw as $j => $e) { - if ($e != 0) { - $ecw[$j] = 929 - $e; - } - } - $ecw = array_reverse($ecw); - - return $ecw; - } - - /** - * Create array of sequences from input - * - * @param string $code - * - * @return array - */ - protected function getInputSequences($code) - { - $sequenceArray = array(); // array to be returned - $numseq = array(); - // get numeric sequences - preg_match_all('/([0-9]{13,})/', $code, $numseq, PREG_OFFSET_CAPTURE); - $numseq[1][] = array('', strlen($code)); - $offset = 0; - foreach ($numseq[1] as $seq) { - $seqlen = strlen($seq[0]); - if ($seq[1] > 0) { - // extract text sequence before the number sequence - $prevseq = substr($code, $offset, ($seq[1] - $offset)); - $textseq = array(); - // get text sequences - preg_match_all('/([\x09\x0a\x0d\x20-\x7e]{5,})/', $prevseq, $textseq, PREG_OFFSET_CAPTURE); - $textseq[1][] = array('', strlen($prevseq)); - $txtoffset = 0; - foreach ($textseq[1] as $txtseq) { - $txtseqlen = strlen($txtseq[0]); - if ($txtseq[1] > 0) { - // extract byte sequence before the text sequence - $prevtxtseq = substr($prevseq, $txtoffset, ($txtseq[1] - $txtoffset)); - if (strlen($prevtxtseq) > 0) { - // add BYTE sequence - if ((strlen($prevtxtseq) == 1) && ((count($sequenceArray) > 0) && ($sequenceArray[(count($sequenceArray) - 1)][0] == 900))) { - $sequenceArray[] = array(913, $prevtxtseq); - } elseif ((strlen($prevtxtseq) % 6) == 0) { - $sequenceArray[] = array(924, $prevtxtseq); - } else { - $sequenceArray[] = array(901, $prevtxtseq); - } - } - } - if ($txtseqlen > 0) { - // add numeric sequence - $sequenceArray[] = array(900, $txtseq[0]); - } - $txtoffset = $txtseq[1] + $txtseqlen; - } - } - if ($seqlen > 0) { - // add numeric sequence - $sequenceArray[] = array(902, $seq[0]); - } - $offset = $seq[1] + $seqlen; - } - - return $sequenceArray; - } - - /** - * @param int $mode - * @param string $code - * @param bool $addmode - * - * @return array - */ - protected function getCompaction($mode, $code, $addmode = true) - { - $cw = array(); // array of codewords to return - switch ($mode) { - case 900: // Text Compaction mode latch - $submode = 0; // default Alpha sub-mode - $txtarr = array(); // array of characters and sub-mode switching characters - $codelen = strlen($code); - for ($i = 0; $i < $codelen; ++$i) { - $chval = ord($code{$i}); - if (($k = array_search($chval, $this->textsubmodes[$submode])) !== false) { - // we are on the same sub-mode - $txtarr[] = $k; - } else { - // the sub-mode is changed - for ($s = 0; $s < 4; ++$s) { - // search new sub-mode - if (($s != $submode) && (($k = array_search($chval, $this->textsubmodes[$s])) !== false)) { - // $s is the new submode - if (((($i + 1) == $codelen) || ((($i + 1) < $codelen) && (array_search(ord($code{($i + 1)}), $this->textsubmodes[$submode]) !== false))) && (($s == 3) || (($s == 0) && ($submode == 1)))) { - // shift (temporary change only for this char) - if ($s == 3) { - // shift to puntuaction - $txtarr[] = 29; - } else { - // shift from lower to alpha - $txtarr[] = 27; - } - } else { - // latch - $txtarr = array_merge($txtarr, $this->textlatch['' . $submode . $s]); - // set new submode - $submode = $s; - } - // add characted code to array - $txtarr[] = $k; - break; - } - } - } - } - $txtarrlen = count($txtarr); - if (($txtarrlen % 2) != 0) { - // add padding - $txtarr[] = 29; - ++$txtarrlen; - } - // calculate codewords - for ($i = 0; $i < $txtarrlen; $i += 2) { - $cw[] = (30 * $txtarr[$i]) + $txtarr[($i + 1)]; - } - break; - case 901: - case 924: // Byte Compaction mode latch - while (($codelen = strlen($code)) > 0) { - if ($codelen > 6) { - $rest = substr($code, 6); - $code = substr($code, 0, 6); - $sublen = 6; - } else { - $rest = ''; - $sublen = strlen($code); - } - - if ($sublen == 6) { - $t = bcmul('' . ord($code{0}), '1099511627776'); - $t = bcadd($t, bcmul('' . ord($code{1}), '4294967296')); - $t = bcadd($t, bcmul('' . ord($code{2}), '16777216')); - $t = bcadd($t, bcmul('' . ord($code{3}), '65536')); - $t = bcadd($t, bcmul('' . ord($code{4}), '256')); - $t = bcadd($t, '' . ord($code{5})); - do { - $d = bcmod($t, '900'); - $t = bcdiv($t, '900'); - array_unshift($cw, $d); - } while ($t != '0'); - } else { - for ($i = 0; $i < $sublen; ++$i) { - $cw[] = ord($code{$i}); - } - } - - $code = $rest; - } - break; - - case 902: // Numeric Compaction mode latch - while (($codelen = strlen($code)) > 0) { - if ($codelen > 44) { - $rest = substr($code, 44); - $code = substr($code, 0, 44); - } else { - $rest = ''; - } - $t = '1' . $code; - do { - $d = bcmod($t, '900'); - $t = bcdiv($t, '900'); - array_unshift($cw, $d); - } while ($t != '0'); - $code = $rest; - } - break; - - case 913: // Byte Compaction mode shift - $cw[] = ord($code); - break; - } - - if ($addmode) { - // add the compaction mode codeword at the beginning - array_unshift($cw, $mode); - } - - return $cw; - } + const + + PDF417DEFS = true, + ROWHEIGHT = 4, + QUIETH = 2, + QUIETV = 4; + + /** + * Barcode array to be returned which is readable by Dinesh Rabara. + * @protected + */ + protected $barcodeArray = array(); + + /** + * Start pattern. + * @protected + */ + protected $startPattern = '11111111010101000'; + + /** + * Stop pattern. + * @protected + */ + protected $stopPattern = '111111101000101001'; + + /** + * Array of text Compaction Sub-Modes (values 0xFB - 0xFF are used for submode changers). + * @protected + */ + protected $textsubmodes = array( + array( + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4a, + 0x4b, + 0x4c, + 0x4d, + 0x4e, + 0x4f, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5a, + 0x20, + 0xFD, + 0xFE, + 0xFF + ), // Alpha + array( + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6a, + 0x6b, + 0x6c, + 0x6d, + 0x6e, + 0x6f, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7a, + 0x20, + 0xFD, + 0xFE, + 0xFF + ), // Lower + array( + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x26, + 0x0d, + 0x09, + 0x2c, + 0x3a, + 0x23, + 0x2d, + 0x2e, + 0x24, + 0x2f, + 0x2b, + 0x25, + 0x2a, + 0x3d, + 0x5e, + 0xFB, + 0x20, + 0xFD, + 0xFE, + 0xFF + ), // Mixed + array( + 0x3b, + 0x3c, + 0x3e, + 0x40, + 0x5b, + 0x5c, + 0x5d, + 0x5f, + 0x60, + 0x7e, + 0x21, + 0x0d, + 0x09, + 0x2c, + 0x3a, + 0x0a, + 0x2d, + 0x2e, + 0x24, + 0x2f, + 0x22, + 0x7c, + 0x2a, + 0x28, + 0x29, + 0x3f, + 0x7b, + 0x7d, + 0x27, + 0xFF + ) // Puntuaction + ); + + /** + * Array of switching codes for Text Compaction Sub-Modes. + * @protected + */ + protected $textlatch = array( + '01' => array(27), + '02' => array(28), + '03' => array(28, 25), // + '10' => array(28, 28), + '12' => array(28), + '13' => array(28, 25), // + '20' => array(28), + '21' => array(27), + '23' => array(25), // + '30' => array(29), + '31' => array(29, 27), + '32' => array(29, 28) // + ); + + /** + * Clusters of codewords (0, 3, 6)
+ * Values are hex equivalents of binary representation of bars (1 = bar, 0 = space).
+ * The codewords numbered from 900 to 928 have special meaning, some enable to switch between modes in order to optimise the code:
    + *
  • 900 : Switch to "Text" mode
  • + *
  • 901 : Switch to "Byte" mode
  • + *
  • 902 : Switch to "Numeric" mode
  • + *
  • 903 - 912 : Reserved
  • + *
  • 913 : Switch to "Octet" only for the next codeword
  • + *
  • 914 - 920 : Reserved
  • + *
  • 921 : Initialization
  • + *
  • 922 : Terminator codeword for Macro PDF control block
  • + *
  • 923 : Sequence tag to identify the beginning of optional fields in the Macro PDF control block
  • + *
  • 924 : Switch to "Byte" mode (If the total number of byte is multiple of 6)
  • + *
  • 925 : Identifier for a user defined Extended Channel Interpretation (ECI)
  • + *
  • 926 : Identifier for a general purpose ECI format
  • + *
  • 927 : Identifier for an ECI of a character set or code page
  • + *
  • 928 : Macro marker codeword to indicate the beginning of a Macro PDF Control Block
  • + *
+ * @protected + */ + protected $clusters = array( + array( // cluster 0 + 0x1d5c0, + 0x1eaf0, + 0x1f57c, + 0x1d4e0, + 0x1ea78, + 0x1f53e, + 0x1a8c0, + 0x1d470, + 0x1a860, + 0x15040, // cluster 10 + 0x1a830, + 0x15020, + 0x1adc0, + 0x1d6f0, + 0x1eb7c, + 0x1ace0, + 0x1d678, + 0x1eb3e, + 0x158c0, + 0x1ac70, // cluster 20 + 0x15860, + 0x15dc0, + 0x1aef0, + 0x1d77c, + 0x15ce0, + 0x1ae78, + 0x1d73e, + 0x15c70, + 0x1ae3c, + 0x15ef0, // cluster 30 + 0x1af7c, + 0x15e78, + 0x1af3e, + 0x15f7c, + 0x1f5fa, + 0x1d2e0, + 0x1e978, + 0x1f4be, + 0x1a4c0, + 0x1d270, // cluster 40 + 0x1e93c, + 0x1a460, + 0x1d238, + 0x14840, + 0x1a430, + 0x1d21c, + 0x14820, + 0x1a418, + 0x14810, + 0x1a6e0, // cluster 50 + 0x1d378, + 0x1e9be, + 0x14cc0, + 0x1a670, + 0x1d33c, + 0x14c60, + 0x1a638, + 0x1d31e, + 0x14c30, + 0x1a61c, // cluster 60 + 0x14ee0, + 0x1a778, + 0x1d3be, + 0x14e70, + 0x1a73c, + 0x14e38, + 0x1a71e, + 0x14f78, + 0x1a7be, + 0x14f3c, // cluster 70 + 0x14f1e, + 0x1a2c0, + 0x1d170, + 0x1e8bc, + 0x1a260, + 0x1d138, + 0x1e89e, + 0x14440, + 0x1a230, + 0x1d11c, // cluster 80 + 0x14420, + 0x1a218, + 0x14410, + 0x14408, + 0x146c0, + 0x1a370, + 0x1d1bc, + 0x14660, + 0x1a338, + 0x1d19e, // cluster 90 + 0x14630, + 0x1a31c, + 0x14618, + 0x1460c, + 0x14770, + 0x1a3bc, + 0x14738, + 0x1a39e, + 0x1471c, + 0x147bc, // cluster 100 + 0x1a160, + 0x1d0b8, + 0x1e85e, + 0x14240, + 0x1a130, + 0x1d09c, + 0x14220, + 0x1a118, + 0x1d08e, + 0x14210, // cluster 110 + 0x1a10c, + 0x14208, + 0x1a106, + 0x14360, + 0x1a1b8, + 0x1d0de, + 0x14330, + 0x1a19c, + 0x14318, + 0x1a18e, // cluster 120 + 0x1430c, + 0x14306, + 0x1a1de, + 0x1438e, + 0x14140, + 0x1a0b0, + 0x1d05c, + 0x14120, + 0x1a098, + 0x1d04e, // cluster 130 + 0x14110, + 0x1a08c, + 0x14108, + 0x1a086, + 0x14104, + 0x141b0, + 0x14198, + 0x1418c, + 0x140a0, + 0x1d02e, // cluster 140 + 0x1a04c, + 0x1a046, + 0x14082, + 0x1cae0, + 0x1e578, + 0x1f2be, + 0x194c0, + 0x1ca70, + 0x1e53c, + 0x19460, // cluster 150 + 0x1ca38, + 0x1e51e, + 0x12840, + 0x19430, + 0x12820, + 0x196e0, + 0x1cb78, + 0x1e5be, + 0x12cc0, + 0x19670, // cluster 160 + 0x1cb3c, + 0x12c60, + 0x19638, + 0x12c30, + 0x12c18, + 0x12ee0, + 0x19778, + 0x1cbbe, + 0x12e70, + 0x1973c, // cluster 170 + 0x12e38, + 0x12e1c, + 0x12f78, + 0x197be, + 0x12f3c, + 0x12fbe, + 0x1dac0, + 0x1ed70, + 0x1f6bc, + 0x1da60, // cluster 180 + 0x1ed38, + 0x1f69e, + 0x1b440, + 0x1da30, + 0x1ed1c, + 0x1b420, + 0x1da18, + 0x1ed0e, + 0x1b410, + 0x1da0c, // cluster 190 + 0x192c0, + 0x1c970, + 0x1e4bc, + 0x1b6c0, + 0x19260, + 0x1c938, + 0x1e49e, + 0x1b660, + 0x1db38, + 0x1ed9e, // cluster 200 + 0x16c40, + 0x12420, + 0x19218, + 0x1c90e, + 0x16c20, + 0x1b618, + 0x16c10, + 0x126c0, + 0x19370, + 0x1c9bc, // cluster 210 + 0x16ec0, + 0x12660, + 0x19338, + 0x1c99e, + 0x16e60, + 0x1b738, + 0x1db9e, + 0x16e30, + 0x12618, + 0x16e18, // cluster 220 + 0x12770, + 0x193bc, + 0x16f70, + 0x12738, + 0x1939e, + 0x16f38, + 0x1b79e, + 0x16f1c, + 0x127bc, + 0x16fbc, // cluster 230 + 0x1279e, + 0x16f9e, + 0x1d960, + 0x1ecb8, + 0x1f65e, + 0x1b240, + 0x1d930, + 0x1ec9c, + 0x1b220, + 0x1d918, // cluster 240 + 0x1ec8e, + 0x1b210, + 0x1d90c, + 0x1b208, + 0x1b204, + 0x19160, + 0x1c8b8, + 0x1e45e, + 0x1b360, + 0x19130, // cluster 250 + 0x1c89c, + 0x16640, + 0x12220, + 0x1d99c, + 0x1c88e, + 0x16620, + 0x12210, + 0x1910c, + 0x16610, + 0x1b30c, // cluster 260 + 0x19106, + 0x12204, + 0x12360, + 0x191b8, + 0x1c8de, + 0x16760, + 0x12330, + 0x1919c, + 0x16730, + 0x1b39c, // cluster 270 + 0x1918e, + 0x16718, + 0x1230c, + 0x12306, + 0x123b8, + 0x191de, + 0x167b8, + 0x1239c, + 0x1679c, + 0x1238e, // cluster 280 + 0x1678e, + 0x167de, + 0x1b140, + 0x1d8b0, + 0x1ec5c, + 0x1b120, + 0x1d898, + 0x1ec4e, + 0x1b110, + 0x1d88c, // cluster 290 + 0x1b108, + 0x1d886, + 0x1b104, + 0x1b102, + 0x12140, + 0x190b0, + 0x1c85c, + 0x16340, + 0x12120, + 0x19098, // cluster 300 + 0x1c84e, + 0x16320, + 0x1b198, + 0x1d8ce, + 0x16310, + 0x12108, + 0x19086, + 0x16308, + 0x1b186, + 0x16304, // cluster 310 + 0x121b0, + 0x190dc, + 0x163b0, + 0x12198, + 0x190ce, + 0x16398, + 0x1b1ce, + 0x1638c, + 0x12186, + 0x16386, // cluster 320 + 0x163dc, + 0x163ce, + 0x1b0a0, + 0x1d858, + 0x1ec2e, + 0x1b090, + 0x1d84c, + 0x1b088, + 0x1d846, + 0x1b084, // cluster 330 + 0x1b082, + 0x120a0, + 0x19058, + 0x1c82e, + 0x161a0, + 0x12090, + 0x1904c, + 0x16190, + 0x1b0cc, + 0x19046, // cluster 340 + 0x16188, + 0x12084, + 0x16184, + 0x12082, + 0x120d8, + 0x161d8, + 0x161cc, + 0x161c6, + 0x1d82c, + 0x1d826, // cluster 350 + 0x1b042, + 0x1902c, + 0x12048, + 0x160c8, + 0x160c4, + 0x160c2, + 0x18ac0, + 0x1c570, + 0x1e2bc, + 0x18a60, // cluster 360 + 0x1c538, + 0x11440, + 0x18a30, + 0x1c51c, + 0x11420, + 0x18a18, + 0x11410, + 0x11408, + 0x116c0, + 0x18b70, // cluster 370 + 0x1c5bc, + 0x11660, + 0x18b38, + 0x1c59e, + 0x11630, + 0x18b1c, + 0x11618, + 0x1160c, + 0x11770, + 0x18bbc, // cluster 380 + 0x11738, + 0x18b9e, + 0x1171c, + 0x117bc, + 0x1179e, + 0x1cd60, + 0x1e6b8, + 0x1f35e, + 0x19a40, + 0x1cd30, // cluster 390 + 0x1e69c, + 0x19a20, + 0x1cd18, + 0x1e68e, + 0x19a10, + 0x1cd0c, + 0x19a08, + 0x1cd06, + 0x18960, + 0x1c4b8, // cluster 400 + 0x1e25e, + 0x19b60, + 0x18930, + 0x1c49c, + 0x13640, + 0x11220, + 0x1cd9c, + 0x1c48e, + 0x13620, + 0x19b18, // cluster 410 + 0x1890c, + 0x13610, + 0x11208, + 0x13608, + 0x11360, + 0x189b8, + 0x1c4de, + 0x13760, + 0x11330, + 0x1cdde, // cluster 420 + 0x13730, + 0x19b9c, + 0x1898e, + 0x13718, + 0x1130c, + 0x1370c, + 0x113b8, + 0x189de, + 0x137b8, + 0x1139c, // cluster 430 + 0x1379c, + 0x1138e, + 0x113de, + 0x137de, + 0x1dd40, + 0x1eeb0, + 0x1f75c, + 0x1dd20, + 0x1ee98, + 0x1f74e, // cluster 440 + 0x1dd10, + 0x1ee8c, + 0x1dd08, + 0x1ee86, + 0x1dd04, + 0x19940, + 0x1ccb0, + 0x1e65c, + 0x1bb40, + 0x19920, // cluster 450 + 0x1eedc, + 0x1e64e, + 0x1bb20, + 0x1dd98, + 0x1eece, + 0x1bb10, + 0x19908, + 0x1cc86, + 0x1bb08, + 0x1dd86, // cluster 460 + 0x19902, + 0x11140, + 0x188b0, + 0x1c45c, + 0x13340, + 0x11120, + 0x18898, + 0x1c44e, + 0x17740, + 0x13320, // cluster 470 + 0x19998, + 0x1ccce, + 0x17720, + 0x1bb98, + 0x1ddce, + 0x18886, + 0x17710, + 0x13308, + 0x19986, + 0x17708, // cluster 480 + 0x11102, + 0x111b0, + 0x188dc, + 0x133b0, + 0x11198, + 0x188ce, + 0x177b0, + 0x13398, + 0x199ce, + 0x17798, // cluster 490 + 0x1bbce, + 0x11186, + 0x13386, + 0x111dc, + 0x133dc, + 0x111ce, + 0x177dc, + 0x133ce, + 0x1dca0, + 0x1ee58, // cluster 500 + 0x1f72e, + 0x1dc90, + 0x1ee4c, + 0x1dc88, + 0x1ee46, + 0x1dc84, + 0x1dc82, + 0x198a0, + 0x1cc58, + 0x1e62e, // cluster 510 + 0x1b9a0, + 0x19890, + 0x1ee6e, + 0x1b990, + 0x1dccc, + 0x1cc46, + 0x1b988, + 0x19884, + 0x1b984, + 0x19882, // cluster 520 + 0x1b982, + 0x110a0, + 0x18858, + 0x1c42e, + 0x131a0, + 0x11090, + 0x1884c, + 0x173a0, + 0x13190, + 0x198cc, // cluster 530 + 0x18846, + 0x17390, + 0x1b9cc, + 0x11084, + 0x17388, + 0x13184, + 0x11082, + 0x13182, + 0x110d8, + 0x1886e, // cluster 540 + 0x131d8, + 0x110cc, + 0x173d8, + 0x131cc, + 0x110c6, + 0x173cc, + 0x131c6, + 0x110ee, + 0x173ee, + 0x1dc50, // cluster 550 + 0x1ee2c, + 0x1dc48, + 0x1ee26, + 0x1dc44, + 0x1dc42, + 0x19850, + 0x1cc2c, + 0x1b8d0, + 0x19848, + 0x1cc26, // cluster 560 + 0x1b8c8, + 0x1dc66, + 0x1b8c4, + 0x19842, + 0x1b8c2, + 0x11050, + 0x1882c, + 0x130d0, + 0x11048, + 0x18826, // cluster 570 + 0x171d0, + 0x130c8, + 0x19866, + 0x171c8, + 0x1b8e6, + 0x11042, + 0x171c4, + 0x130c2, + 0x171c2, + 0x130ec, // cluster 580 + 0x171ec, + 0x171e6, + 0x1ee16, + 0x1dc22, + 0x1cc16, + 0x19824, + 0x19822, + 0x11028, + 0x13068, + 0x170e8, // cluster 590 + 0x11022, + 0x13062, + 0x18560, + 0x10a40, + 0x18530, + 0x10a20, + 0x18518, + 0x1c28e, + 0x10a10, + 0x1850c, // cluster 600 + 0x10a08, + 0x18506, + 0x10b60, + 0x185b8, + 0x1c2de, + 0x10b30, + 0x1859c, + 0x10b18, + 0x1858e, + 0x10b0c, // cluster 610 + 0x10b06, + 0x10bb8, + 0x185de, + 0x10b9c, + 0x10b8e, + 0x10bde, + 0x18d40, + 0x1c6b0, + 0x1e35c, + 0x18d20, // cluster 620 + 0x1c698, + 0x18d10, + 0x1c68c, + 0x18d08, + 0x1c686, + 0x18d04, + 0x10940, + 0x184b0, + 0x1c25c, + 0x11b40, // cluster 630 + 0x10920, + 0x1c6dc, + 0x1c24e, + 0x11b20, + 0x18d98, + 0x1c6ce, + 0x11b10, + 0x10908, + 0x18486, + 0x11b08, // cluster 640 + 0x18d86, + 0x10902, + 0x109b0, + 0x184dc, + 0x11bb0, + 0x10998, + 0x184ce, + 0x11b98, + 0x18dce, + 0x11b8c, // cluster 650 + 0x10986, + 0x109dc, + 0x11bdc, + 0x109ce, + 0x11bce, + 0x1cea0, + 0x1e758, + 0x1f3ae, + 0x1ce90, + 0x1e74c, // cluster 660 + 0x1ce88, + 0x1e746, + 0x1ce84, + 0x1ce82, + 0x18ca0, + 0x1c658, + 0x19da0, + 0x18c90, + 0x1c64c, + 0x19d90, // cluster 670 + 0x1cecc, + 0x1c646, + 0x19d88, + 0x18c84, + 0x19d84, + 0x18c82, + 0x19d82, + 0x108a0, + 0x18458, + 0x119a0, // cluster 680 + 0x10890, + 0x1c66e, + 0x13ba0, + 0x11990, + 0x18ccc, + 0x18446, + 0x13b90, + 0x19dcc, + 0x10884, + 0x13b88, // cluster 690 + 0x11984, + 0x10882, + 0x11982, + 0x108d8, + 0x1846e, + 0x119d8, + 0x108cc, + 0x13bd8, + 0x119cc, + 0x108c6, // cluster 700 + 0x13bcc, + 0x119c6, + 0x108ee, + 0x119ee, + 0x13bee, + 0x1ef50, + 0x1f7ac, + 0x1ef48, + 0x1f7a6, + 0x1ef44, // cluster 710 + 0x1ef42, + 0x1ce50, + 0x1e72c, + 0x1ded0, + 0x1ef6c, + 0x1e726, + 0x1dec8, + 0x1ef66, + 0x1dec4, + 0x1ce42, // cluster 720 + 0x1dec2, + 0x18c50, + 0x1c62c, + 0x19cd0, + 0x18c48, + 0x1c626, + 0x1bdd0, + 0x19cc8, + 0x1ce66, + 0x1bdc8, // cluster 730 + 0x1dee6, + 0x18c42, + 0x1bdc4, + 0x19cc2, + 0x1bdc2, + 0x10850, + 0x1842c, + 0x118d0, + 0x10848, + 0x18426, // cluster 740 + 0x139d0, + 0x118c8, + 0x18c66, + 0x17bd0, + 0x139c8, + 0x19ce6, + 0x10842, + 0x17bc8, + 0x1bde6, + 0x118c2, // cluster 750 + 0x17bc4, + 0x1086c, + 0x118ec, + 0x10866, + 0x139ec, + 0x118e6, + 0x17bec, + 0x139e6, + 0x17be6, + 0x1ef28, // cluster 760 + 0x1f796, + 0x1ef24, + 0x1ef22, + 0x1ce28, + 0x1e716, + 0x1de68, + 0x1ef36, + 0x1de64, + 0x1ce22, + 0x1de62, // cluster 770 + 0x18c28, + 0x1c616, + 0x19c68, + 0x18c24, + 0x1bce8, + 0x19c64, + 0x18c22, + 0x1bce4, + 0x19c62, + 0x1bce2, // cluster 780 + 0x10828, + 0x18416, + 0x11868, + 0x18c36, + 0x138e8, + 0x11864, + 0x10822, + 0x179e8, + 0x138e4, + 0x11862, // 790 + 0x179e4, + 0x138e2, + 0x179e2, + 0x11876, + 0x179f6, + 0x1ef12, + 0x1de34, + 0x1de32, + 0x19c34, + 0x1bc74, // 800 + 0x1bc72, + 0x11834, + 0x13874, + 0x178f4, + 0x178f2, + 0x10540, + 0x10520, + 0x18298, + 0x10510, + 0x10508, // 810 + 0x10504, + 0x105b0, + 0x10598, + 0x1058c, + 0x10586, + 0x105dc, + 0x105ce, + 0x186a0, + 0x18690, + 0x1c34c, // 820 + 0x18688, + 0x1c346, + 0x18684, + 0x18682, + 0x104a0, + 0x18258, + 0x10da0, + 0x186d8, + 0x1824c, + 0x10d90, // 830 + 0x186cc, + 0x10d88, + 0x186c6, + 0x10d84, + 0x10482, + 0x10d82, + 0x104d8, + 0x1826e, + 0x10dd8, + 0x186ee, // 840 + 0x10dcc, + 0x104c6, + 0x10dc6, + 0x104ee, + 0x10dee, + 0x1c750, + 0x1c748, + 0x1c744, + 0x1c742, + 0x18650, // 850 + 0x18ed0, + 0x1c76c, + 0x1c326, + 0x18ec8, + 0x1c766, + 0x18ec4, + 0x18642, + 0x18ec2, + 0x10450, + 0x10cd0, // 860 + 0x10448, + 0x18226, + 0x11dd0, + 0x10cc8, + 0x10444, + 0x11dc8, + 0x10cc4, + 0x10442, + 0x11dc4, + 0x10cc2, // 870 + 0x1046c, + 0x10cec, + 0x10466, + 0x11dec, + 0x10ce6, + 0x11de6, + 0x1e7a8, + 0x1e7a4, + 0x1e7a2, + 0x1c728, // 880 + 0x1cf68, + 0x1e7b6, + 0x1cf64, + 0x1c722, + 0x1cf62, + 0x18628, + 0x1c316, + 0x18e68, + 0x1c736, + 0x19ee8, // 890 + 0x18e64, + 0x18622, + 0x19ee4, + 0x18e62, + 0x19ee2, + 0x10428, + 0x18216, + 0x10c68, + 0x18636, + 0x11ce8, // 900 + 0x10c64, + 0x10422, + 0x13de8, + 0x11ce4, + 0x10c62, + 0x13de4, + 0x11ce2, + 0x10436, + 0x10c76, + 0x11cf6, // 910 + 0x13df6, + 0x1f7d4, + 0x1f7d2, + 0x1e794, + 0x1efb4, + 0x1e792, + 0x1efb2, + 0x1c714, + 0x1cf34, + 0x1c712, // 920 + 0x1df74, + 0x1cf32, + 0x1df72, + 0x18614, + 0x18e34, + 0x18612, + 0x19e74, + 0x18e32, + 0x1bef4 + ), // 929 + array( // cluster 3 ----------------------------------------------------------------------- + 0x1f560, + 0x1fab8, + 0x1ea40, + 0x1f530, + 0x1fa9c, + 0x1ea20, + 0x1f518, + 0x1fa8e, + 0x1ea10, + 0x1f50c, // 10 + 0x1ea08, + 0x1f506, + 0x1ea04, + 0x1eb60, + 0x1f5b8, + 0x1fade, + 0x1d640, + 0x1eb30, + 0x1f59c, + 0x1d620, // 20 + 0x1eb18, + 0x1f58e, + 0x1d610, + 0x1eb0c, + 0x1d608, + 0x1eb06, + 0x1d604, + 0x1d760, + 0x1ebb8, + 0x1f5de, // 30 + 0x1ae40, + 0x1d730, + 0x1eb9c, + 0x1ae20, + 0x1d718, + 0x1eb8e, + 0x1ae10, + 0x1d70c, + 0x1ae08, + 0x1d706, // 40 + 0x1ae04, + 0x1af60, + 0x1d7b8, + 0x1ebde, + 0x15e40, + 0x1af30, + 0x1d79c, + 0x15e20, + 0x1af18, + 0x1d78e, // 50 + 0x15e10, + 0x1af0c, + 0x15e08, + 0x1af06, + 0x15f60, + 0x1afb8, + 0x1d7de, + 0x15f30, + 0x1af9c, + 0x15f18, // 60 + 0x1af8e, + 0x15f0c, + 0x15fb8, + 0x1afde, + 0x15f9c, + 0x15f8e, + 0x1e940, + 0x1f4b0, + 0x1fa5c, + 0x1e920, // 70 + 0x1f498, + 0x1fa4e, + 0x1e910, + 0x1f48c, + 0x1e908, + 0x1f486, + 0x1e904, + 0x1e902, + 0x1d340, + 0x1e9b0, // 80 + 0x1f4dc, + 0x1d320, + 0x1e998, + 0x1f4ce, + 0x1d310, + 0x1e98c, + 0x1d308, + 0x1e986, + 0x1d304, + 0x1d302, // 90 + 0x1a740, + 0x1d3b0, + 0x1e9dc, + 0x1a720, + 0x1d398, + 0x1e9ce, + 0x1a710, + 0x1d38c, + 0x1a708, + 0x1d386, // 100 + 0x1a704, + 0x1a702, + 0x14f40, + 0x1a7b0, + 0x1d3dc, + 0x14f20, + 0x1a798, + 0x1d3ce, + 0x14f10, + 0x1a78c, // 110 + 0x14f08, + 0x1a786, + 0x14f04, + 0x14fb0, + 0x1a7dc, + 0x14f98, + 0x1a7ce, + 0x14f8c, + 0x14f86, + 0x14fdc, // 120 + 0x14fce, + 0x1e8a0, + 0x1f458, + 0x1fa2e, + 0x1e890, + 0x1f44c, + 0x1e888, + 0x1f446, + 0x1e884, + 0x1e882, // 130 + 0x1d1a0, + 0x1e8d8, + 0x1f46e, + 0x1d190, + 0x1e8cc, + 0x1d188, + 0x1e8c6, + 0x1d184, + 0x1d182, + 0x1a3a0, // 140 + 0x1d1d8, + 0x1e8ee, + 0x1a390, + 0x1d1cc, + 0x1a388, + 0x1d1c6, + 0x1a384, + 0x1a382, + 0x147a0, + 0x1a3d8, // 150 + 0x1d1ee, + 0x14790, + 0x1a3cc, + 0x14788, + 0x1a3c6, + 0x14784, + 0x14782, + 0x147d8, + 0x1a3ee, + 0x147cc, // 160 + 0x147c6, + 0x147ee, + 0x1e850, + 0x1f42c, + 0x1e848, + 0x1f426, + 0x1e844, + 0x1e842, + 0x1d0d0, + 0x1e86c, // 170 + 0x1d0c8, + 0x1e866, + 0x1d0c4, + 0x1d0c2, + 0x1a1d0, + 0x1d0ec, + 0x1a1c8, + 0x1d0e6, + 0x1a1c4, + 0x1a1c2, // 180 + 0x143d0, + 0x1a1ec, + 0x143c8, + 0x1a1e6, + 0x143c4, + 0x143c2, + 0x143ec, + 0x143e6, + 0x1e828, + 0x1f416, // 190 + 0x1e824, + 0x1e822, + 0x1d068, + 0x1e836, + 0x1d064, + 0x1d062, + 0x1a0e8, + 0x1d076, + 0x1a0e4, + 0x1a0e2, // 200 + 0x141e8, + 0x1a0f6, + 0x141e4, + 0x141e2, + 0x1e814, + 0x1e812, + 0x1d034, + 0x1d032, + 0x1a074, + 0x1a072, // 210 + 0x1e540, + 0x1f2b0, + 0x1f95c, + 0x1e520, + 0x1f298, + 0x1f94e, + 0x1e510, + 0x1f28c, + 0x1e508, + 0x1f286, // 220 + 0x1e504, + 0x1e502, + 0x1cb40, + 0x1e5b0, + 0x1f2dc, + 0x1cb20, + 0x1e598, + 0x1f2ce, + 0x1cb10, + 0x1e58c, // 230 + 0x1cb08, + 0x1e586, + 0x1cb04, + 0x1cb02, + 0x19740, + 0x1cbb0, + 0x1e5dc, + 0x19720, + 0x1cb98, + 0x1e5ce, // 240 + 0x19710, + 0x1cb8c, + 0x19708, + 0x1cb86, + 0x19704, + 0x19702, + 0x12f40, + 0x197b0, + 0x1cbdc, + 0x12f20, // 250 + 0x19798, + 0x1cbce, + 0x12f10, + 0x1978c, + 0x12f08, + 0x19786, + 0x12f04, + 0x12fb0, + 0x197dc, + 0x12f98, // 260 + 0x197ce, + 0x12f8c, + 0x12f86, + 0x12fdc, + 0x12fce, + 0x1f6a0, + 0x1fb58, + 0x16bf0, + 0x1f690, + 0x1fb4c, // 270 + 0x169f8, + 0x1f688, + 0x1fb46, + 0x168fc, + 0x1f684, + 0x1f682, + 0x1e4a0, + 0x1f258, + 0x1f92e, + 0x1eda0, // 280 + 0x1e490, + 0x1fb6e, + 0x1ed90, + 0x1f6cc, + 0x1f246, + 0x1ed88, + 0x1e484, + 0x1ed84, + 0x1e482, + 0x1ed82, // 290 + 0x1c9a0, + 0x1e4d8, + 0x1f26e, + 0x1dba0, + 0x1c990, + 0x1e4cc, + 0x1db90, + 0x1edcc, + 0x1e4c6, + 0x1db88, // 300 + 0x1c984, + 0x1db84, + 0x1c982, + 0x1db82, + 0x193a0, + 0x1c9d8, + 0x1e4ee, + 0x1b7a0, + 0x19390, + 0x1c9cc, // 310 + 0x1b790, + 0x1dbcc, + 0x1c9c6, + 0x1b788, + 0x19384, + 0x1b784, + 0x19382, + 0x1b782, + 0x127a0, + 0x193d8, // 320 + 0x1c9ee, + 0x16fa0, + 0x12790, + 0x193cc, + 0x16f90, + 0x1b7cc, + 0x193c6, + 0x16f88, + 0x12784, + 0x16f84, // 330 + 0x12782, + 0x127d8, + 0x193ee, + 0x16fd8, + 0x127cc, + 0x16fcc, + 0x127c6, + 0x16fc6, + 0x127ee, + 0x1f650, // 340 + 0x1fb2c, + 0x165f8, + 0x1f648, + 0x1fb26, + 0x164fc, + 0x1f644, + 0x1647e, + 0x1f642, + 0x1e450, + 0x1f22c, // 350 + 0x1ecd0, + 0x1e448, + 0x1f226, + 0x1ecc8, + 0x1f666, + 0x1ecc4, + 0x1e442, + 0x1ecc2, + 0x1c8d0, + 0x1e46c, // 360 + 0x1d9d0, + 0x1c8c8, + 0x1e466, + 0x1d9c8, + 0x1ece6, + 0x1d9c4, + 0x1c8c2, + 0x1d9c2, + 0x191d0, + 0x1c8ec, // 370 + 0x1b3d0, + 0x191c8, + 0x1c8e6, + 0x1b3c8, + 0x1d9e6, + 0x1b3c4, + 0x191c2, + 0x1b3c2, + 0x123d0, + 0x191ec, // 380 + 0x167d0, + 0x123c8, + 0x191e6, + 0x167c8, + 0x1b3e6, + 0x167c4, + 0x123c2, + 0x167c2, + 0x123ec, + 0x167ec, // 390 + 0x123e6, + 0x167e6, + 0x1f628, + 0x1fb16, + 0x162fc, + 0x1f624, + 0x1627e, + 0x1f622, + 0x1e428, + 0x1f216, // 400 + 0x1ec68, + 0x1f636, + 0x1ec64, + 0x1e422, + 0x1ec62, + 0x1c868, + 0x1e436, + 0x1d8e8, + 0x1c864, + 0x1d8e4, // 410 + 0x1c862, + 0x1d8e2, + 0x190e8, + 0x1c876, + 0x1b1e8, + 0x1d8f6, + 0x1b1e4, + 0x190e2, + 0x1b1e2, + 0x121e8, // 420 + 0x190f6, + 0x163e8, + 0x121e4, + 0x163e4, + 0x121e2, + 0x163e2, + 0x121f6, + 0x163f6, + 0x1f614, + 0x1617e, // 430 + 0x1f612, + 0x1e414, + 0x1ec34, + 0x1e412, + 0x1ec32, + 0x1c834, + 0x1d874, + 0x1c832, + 0x1d872, + 0x19074, // 440 + 0x1b0f4, + 0x19072, + 0x1b0f2, + 0x120f4, + 0x161f4, + 0x120f2, + 0x161f2, + 0x1f60a, + 0x1e40a, + 0x1ec1a, // 450 + 0x1c81a, + 0x1d83a, + 0x1903a, + 0x1b07a, + 0x1e2a0, + 0x1f158, + 0x1f8ae, + 0x1e290, + 0x1f14c, + 0x1e288, // 460 + 0x1f146, + 0x1e284, + 0x1e282, + 0x1c5a0, + 0x1e2d8, + 0x1f16e, + 0x1c590, + 0x1e2cc, + 0x1c588, + 0x1e2c6, // 470 + 0x1c584, + 0x1c582, + 0x18ba0, + 0x1c5d8, + 0x1e2ee, + 0x18b90, + 0x1c5cc, + 0x18b88, + 0x1c5c6, + 0x18b84, // 480 + 0x18b82, + 0x117a0, + 0x18bd8, + 0x1c5ee, + 0x11790, + 0x18bcc, + 0x11788, + 0x18bc6, + 0x11784, + 0x11782, // 490 + 0x117d8, + 0x18bee, + 0x117cc, + 0x117c6, + 0x117ee, + 0x1f350, + 0x1f9ac, + 0x135f8, + 0x1f348, + 0x1f9a6, // 500 + 0x134fc, + 0x1f344, + 0x1347e, + 0x1f342, + 0x1e250, + 0x1f12c, + 0x1e6d0, + 0x1e248, + 0x1f126, + 0x1e6c8, // 510 + 0x1f366, + 0x1e6c4, + 0x1e242, + 0x1e6c2, + 0x1c4d0, + 0x1e26c, + 0x1cdd0, + 0x1c4c8, + 0x1e266, + 0x1cdc8, // 520 + 0x1e6e6, + 0x1cdc4, + 0x1c4c2, + 0x1cdc2, + 0x189d0, + 0x1c4ec, + 0x19bd0, + 0x189c8, + 0x1c4e6, + 0x19bc8, // 530 + 0x1cde6, + 0x19bc4, + 0x189c2, + 0x19bc2, + 0x113d0, + 0x189ec, + 0x137d0, + 0x113c8, + 0x189e6, + 0x137c8, // 540 + 0x19be6, + 0x137c4, + 0x113c2, + 0x137c2, + 0x113ec, + 0x137ec, + 0x113e6, + 0x137e6, + 0x1fba8, + 0x175f0, // 550 + 0x1bafc, + 0x1fba4, + 0x174f8, + 0x1ba7e, + 0x1fba2, + 0x1747c, + 0x1743e, + 0x1f328, + 0x1f996, + 0x132fc, // 560 + 0x1f768, + 0x1fbb6, + 0x176fc, + 0x1327e, + 0x1f764, + 0x1f322, + 0x1767e, + 0x1f762, + 0x1e228, + 0x1f116, // 570 + 0x1e668, + 0x1e224, + 0x1eee8, + 0x1f776, + 0x1e222, + 0x1eee4, + 0x1e662, + 0x1eee2, + 0x1c468, + 0x1e236, // 580 + 0x1cce8, + 0x1c464, + 0x1dde8, + 0x1cce4, + 0x1c462, + 0x1dde4, + 0x1cce2, + 0x1dde2, + 0x188e8, + 0x1c476, // 590 + 0x199e8, + 0x188e4, + 0x1bbe8, + 0x199e4, + 0x188e2, + 0x1bbe4, + 0x199e2, + 0x1bbe2, + 0x111e8, + 0x188f6, // 600 + 0x133e8, + 0x111e4, + 0x177e8, + 0x133e4, + 0x111e2, + 0x177e4, + 0x133e2, + 0x177e2, + 0x111f6, + 0x133f6, // 610 + 0x1fb94, + 0x172f8, + 0x1b97e, + 0x1fb92, + 0x1727c, + 0x1723e, + 0x1f314, + 0x1317e, + 0x1f734, + 0x1f312, // 620 + 0x1737e, + 0x1f732, + 0x1e214, + 0x1e634, + 0x1e212, + 0x1ee74, + 0x1e632, + 0x1ee72, + 0x1c434, + 0x1cc74, // 630 + 0x1c432, + 0x1dcf4, + 0x1cc72, + 0x1dcf2, + 0x18874, + 0x198f4, + 0x18872, + 0x1b9f4, + 0x198f2, + 0x1b9f2, // 640 + 0x110f4, + 0x131f4, + 0x110f2, + 0x173f4, + 0x131f2, + 0x173f2, + 0x1fb8a, + 0x1717c, + 0x1713e, + 0x1f30a, // 650 + 0x1f71a, + 0x1e20a, + 0x1e61a, + 0x1ee3a, + 0x1c41a, + 0x1cc3a, + 0x1dc7a, + 0x1883a, + 0x1987a, + 0x1b8fa, // 660 + 0x1107a, + 0x130fa, + 0x171fa, + 0x170be, + 0x1e150, + 0x1f0ac, + 0x1e148, + 0x1f0a6, + 0x1e144, + 0x1e142, // 670 + 0x1c2d0, + 0x1e16c, + 0x1c2c8, + 0x1e166, + 0x1c2c4, + 0x1c2c2, + 0x185d0, + 0x1c2ec, + 0x185c8, + 0x1c2e6, // 680 + 0x185c4, + 0x185c2, + 0x10bd0, + 0x185ec, + 0x10bc8, + 0x185e6, + 0x10bc4, + 0x10bc2, + 0x10bec, + 0x10be6, // 690 + 0x1f1a8, + 0x1f8d6, + 0x11afc, + 0x1f1a4, + 0x11a7e, + 0x1f1a2, + 0x1e128, + 0x1f096, + 0x1e368, + 0x1e124, // 700 + 0x1e364, + 0x1e122, + 0x1e362, + 0x1c268, + 0x1e136, + 0x1c6e8, + 0x1c264, + 0x1c6e4, + 0x1c262, + 0x1c6e2, // 710 + 0x184e8, + 0x1c276, + 0x18de8, + 0x184e4, + 0x18de4, + 0x184e2, + 0x18de2, + 0x109e8, + 0x184f6, + 0x11be8, // 720 + 0x109e4, + 0x11be4, + 0x109e2, + 0x11be2, + 0x109f6, + 0x11bf6, + 0x1f9d4, + 0x13af8, + 0x19d7e, + 0x1f9d2, // 730 + 0x13a7c, + 0x13a3e, + 0x1f194, + 0x1197e, + 0x1f3b4, + 0x1f192, + 0x13b7e, + 0x1f3b2, + 0x1e114, + 0x1e334, // 740 + 0x1e112, + 0x1e774, + 0x1e332, + 0x1e772, + 0x1c234, + 0x1c674, + 0x1c232, + 0x1cef4, + 0x1c672, + 0x1cef2, // 750 + 0x18474, + 0x18cf4, + 0x18472, + 0x19df4, + 0x18cf2, + 0x19df2, + 0x108f4, + 0x119f4, + 0x108f2, + 0x13bf4, // 760 + 0x119f2, + 0x13bf2, + 0x17af0, + 0x1bd7c, + 0x17a78, + 0x1bd3e, + 0x17a3c, + 0x17a1e, + 0x1f9ca, + 0x1397c, // 770 + 0x1fbda, + 0x17b7c, + 0x1393e, + 0x17b3e, + 0x1f18a, + 0x1f39a, + 0x1f7ba, + 0x1e10a, + 0x1e31a, + 0x1e73a, // 780 + 0x1ef7a, + 0x1c21a, + 0x1c63a, + 0x1ce7a, + 0x1defa, + 0x1843a, + 0x18c7a, + 0x19cfa, + 0x1bdfa, + 0x1087a, // 790 + 0x118fa, + 0x139fa, + 0x17978, + 0x1bcbe, + 0x1793c, + 0x1791e, + 0x138be, + 0x179be, + 0x178bc, + 0x1789e, // 800 + 0x1785e, + 0x1e0a8, + 0x1e0a4, + 0x1e0a2, + 0x1c168, + 0x1e0b6, + 0x1c164, + 0x1c162, + 0x182e8, + 0x1c176, // 810 + 0x182e4, + 0x182e2, + 0x105e8, + 0x182f6, + 0x105e4, + 0x105e2, + 0x105f6, + 0x1f0d4, + 0x10d7e, + 0x1f0d2, // 820 + 0x1e094, + 0x1e1b4, + 0x1e092, + 0x1e1b2, + 0x1c134, + 0x1c374, + 0x1c132, + 0x1c372, + 0x18274, + 0x186f4, // 830 + 0x18272, + 0x186f2, + 0x104f4, + 0x10df4, + 0x104f2, + 0x10df2, + 0x1f8ea, + 0x11d7c, + 0x11d3e, + 0x1f0ca, // 840 + 0x1f1da, + 0x1e08a, + 0x1e19a, + 0x1e3ba, + 0x1c11a, + 0x1c33a, + 0x1c77a, + 0x1823a, + 0x1867a, + 0x18efa, // 850 + 0x1047a, + 0x10cfa, + 0x11dfa, + 0x13d78, + 0x19ebe, + 0x13d3c, + 0x13d1e, + 0x11cbe, + 0x13dbe, + 0x17d70, // 860 + 0x1bebc, + 0x17d38, + 0x1be9e, + 0x17d1c, + 0x17d0e, + 0x13cbc, + 0x17dbc, + 0x13c9e, + 0x17d9e, + 0x17cb8, // 870 + 0x1be5e, + 0x17c9c, + 0x17c8e, + 0x13c5e, + 0x17cde, + 0x17c5c, + 0x17c4e, + 0x17c2e, + 0x1c0b4, + 0x1c0b2, // 880 + 0x18174, + 0x18172, + 0x102f4, + 0x102f2, + 0x1e0da, + 0x1c09a, + 0x1c1ba, + 0x1813a, + 0x1837a, + 0x1027a, // 890 + 0x106fa, + 0x10ebe, + 0x11ebc, + 0x11e9e, + 0x13eb8, + 0x19f5e, + 0x13e9c, + 0x13e8e, + 0x11e5e, + 0x13ede, // 900 + 0x17eb0, + 0x1bf5c, + 0x17e98, + 0x1bf4e, + 0x17e8c, + 0x17e86, + 0x13e5c, + 0x17edc, + 0x13e4e, + 0x17ece, // 910 + 0x17e58, + 0x1bf2e, + 0x17e4c, + 0x17e46, + 0x13e2e, + 0x17e6e, + 0x17e2c, + 0x17e26, + 0x10f5e, + 0x11f5c, // 920 + 0x11f4e, + 0x13f58, + 0x19fae, + 0x13f4c, + 0x13f46, + 0x11f2e, + 0x13f6e, + 0x13f2c, + 0x13f26 + ), // 929 + array( // cluster 6 ----------------------------------------------------------------------- + 0x1abe0, + 0x1d5f8, + 0x153c0, + 0x1a9f0, + 0x1d4fc, + 0x151e0, + 0x1a8f8, + 0x1d47e, + 0x150f0, + 0x1a87c, // 10 + 0x15078, + 0x1fad0, + 0x15be0, + 0x1adf8, + 0x1fac8, + 0x159f0, + 0x1acfc, + 0x1fac4, + 0x158f8, + 0x1ac7e, // 20 + 0x1fac2, + 0x1587c, + 0x1f5d0, + 0x1faec, + 0x15df8, + 0x1f5c8, + 0x1fae6, + 0x15cfc, + 0x1f5c4, + 0x15c7e, // 30 + 0x1f5c2, + 0x1ebd0, + 0x1f5ec, + 0x1ebc8, + 0x1f5e6, + 0x1ebc4, + 0x1ebc2, + 0x1d7d0, + 0x1ebec, + 0x1d7c8, // 40 + 0x1ebe6, + 0x1d7c4, + 0x1d7c2, + 0x1afd0, + 0x1d7ec, + 0x1afc8, + 0x1d7e6, + 0x1afc4, + 0x14bc0, + 0x1a5f0, // 50 + 0x1d2fc, + 0x149e0, + 0x1a4f8, + 0x1d27e, + 0x148f0, + 0x1a47c, + 0x14878, + 0x1a43e, + 0x1483c, + 0x1fa68, // 60 + 0x14df0, + 0x1a6fc, + 0x1fa64, + 0x14cf8, + 0x1a67e, + 0x1fa62, + 0x14c7c, + 0x14c3e, + 0x1f4e8, + 0x1fa76, // 70 + 0x14efc, + 0x1f4e4, + 0x14e7e, + 0x1f4e2, + 0x1e9e8, + 0x1f4f6, + 0x1e9e4, + 0x1e9e2, + 0x1d3e8, + 0x1e9f6, // 80 + 0x1d3e4, + 0x1d3e2, + 0x1a7e8, + 0x1d3f6, + 0x1a7e4, + 0x1a7e2, + 0x145e0, + 0x1a2f8, + 0x1d17e, + 0x144f0, // 90 + 0x1a27c, + 0x14478, + 0x1a23e, + 0x1443c, + 0x1441e, + 0x1fa34, + 0x146f8, + 0x1a37e, + 0x1fa32, + 0x1467c, // 100 + 0x1463e, + 0x1f474, + 0x1477e, + 0x1f472, + 0x1e8f4, + 0x1e8f2, + 0x1d1f4, + 0x1d1f2, + 0x1a3f4, + 0x1a3f2, // 110 + 0x142f0, + 0x1a17c, + 0x14278, + 0x1a13e, + 0x1423c, + 0x1421e, + 0x1fa1a, + 0x1437c, + 0x1433e, + 0x1f43a, // 120 + 0x1e87a, + 0x1d0fa, + 0x14178, + 0x1a0be, + 0x1413c, + 0x1411e, + 0x141be, + 0x140bc, + 0x1409e, + 0x12bc0, // 130 + 0x195f0, + 0x1cafc, + 0x129e0, + 0x194f8, + 0x1ca7e, + 0x128f0, + 0x1947c, + 0x12878, + 0x1943e, + 0x1283c, // 140 + 0x1f968, + 0x12df0, + 0x196fc, + 0x1f964, + 0x12cf8, + 0x1967e, + 0x1f962, + 0x12c7c, + 0x12c3e, + 0x1f2e8, // 150 + 0x1f976, + 0x12efc, + 0x1f2e4, + 0x12e7e, + 0x1f2e2, + 0x1e5e8, + 0x1f2f6, + 0x1e5e4, + 0x1e5e2, + 0x1cbe8, // 160 + 0x1e5f6, + 0x1cbe4, + 0x1cbe2, + 0x197e8, + 0x1cbf6, + 0x197e4, + 0x197e2, + 0x1b5e0, + 0x1daf8, + 0x1ed7e, // 170 + 0x169c0, + 0x1b4f0, + 0x1da7c, + 0x168e0, + 0x1b478, + 0x1da3e, + 0x16870, + 0x1b43c, + 0x16838, + 0x1b41e, // 180 + 0x1681c, + 0x125e0, + 0x192f8, + 0x1c97e, + 0x16de0, + 0x124f0, + 0x1927c, + 0x16cf0, + 0x1b67c, + 0x1923e, // 190 + 0x16c78, + 0x1243c, + 0x16c3c, + 0x1241e, + 0x16c1e, + 0x1f934, + 0x126f8, + 0x1937e, + 0x1fb74, + 0x1f932, // 200 + 0x16ef8, + 0x1267c, + 0x1fb72, + 0x16e7c, + 0x1263e, + 0x16e3e, + 0x1f274, + 0x1277e, + 0x1f6f4, + 0x1f272, // 210 + 0x16f7e, + 0x1f6f2, + 0x1e4f4, + 0x1edf4, + 0x1e4f2, + 0x1edf2, + 0x1c9f4, + 0x1dbf4, + 0x1c9f2, + 0x1dbf2, // 220 + 0x193f4, + 0x193f2, + 0x165c0, + 0x1b2f0, + 0x1d97c, + 0x164e0, + 0x1b278, + 0x1d93e, + 0x16470, + 0x1b23c, // 230 + 0x16438, + 0x1b21e, + 0x1641c, + 0x1640e, + 0x122f0, + 0x1917c, + 0x166f0, + 0x12278, + 0x1913e, + 0x16678, // 240 + 0x1b33e, + 0x1663c, + 0x1221e, + 0x1661e, + 0x1f91a, + 0x1237c, + 0x1fb3a, + 0x1677c, + 0x1233e, + 0x1673e, // 250 + 0x1f23a, + 0x1f67a, + 0x1e47a, + 0x1ecfa, + 0x1c8fa, + 0x1d9fa, + 0x191fa, + 0x162e0, + 0x1b178, + 0x1d8be, // 260 + 0x16270, + 0x1b13c, + 0x16238, + 0x1b11e, + 0x1621c, + 0x1620e, + 0x12178, + 0x190be, + 0x16378, + 0x1213c, // 270 + 0x1633c, + 0x1211e, + 0x1631e, + 0x121be, + 0x163be, + 0x16170, + 0x1b0bc, + 0x16138, + 0x1b09e, + 0x1611c, // 280 + 0x1610e, + 0x120bc, + 0x161bc, + 0x1209e, + 0x1619e, + 0x160b8, + 0x1b05e, + 0x1609c, + 0x1608e, + 0x1205e, // 290 + 0x160de, + 0x1605c, + 0x1604e, + 0x115e0, + 0x18af8, + 0x1c57e, + 0x114f0, + 0x18a7c, + 0x11478, + 0x18a3e, // 300 + 0x1143c, + 0x1141e, + 0x1f8b4, + 0x116f8, + 0x18b7e, + 0x1f8b2, + 0x1167c, + 0x1163e, + 0x1f174, + 0x1177e, // 310 + 0x1f172, + 0x1e2f4, + 0x1e2f2, + 0x1c5f4, + 0x1c5f2, + 0x18bf4, + 0x18bf2, + 0x135c0, + 0x19af0, + 0x1cd7c, // 320 + 0x134e0, + 0x19a78, + 0x1cd3e, + 0x13470, + 0x19a3c, + 0x13438, + 0x19a1e, + 0x1341c, + 0x1340e, + 0x112f0, // 330 + 0x1897c, + 0x136f0, + 0x11278, + 0x1893e, + 0x13678, + 0x19b3e, + 0x1363c, + 0x1121e, + 0x1361e, + 0x1f89a, // 340 + 0x1137c, + 0x1f9ba, + 0x1377c, + 0x1133e, + 0x1373e, + 0x1f13a, + 0x1f37a, + 0x1e27a, + 0x1e6fa, + 0x1c4fa, // 350 + 0x1cdfa, + 0x189fa, + 0x1bae0, + 0x1dd78, + 0x1eebe, + 0x174c0, + 0x1ba70, + 0x1dd3c, + 0x17460, + 0x1ba38, // 360 + 0x1dd1e, + 0x17430, + 0x1ba1c, + 0x17418, + 0x1ba0e, + 0x1740c, + 0x132e0, + 0x19978, + 0x1ccbe, + 0x176e0, // 370 + 0x13270, + 0x1993c, + 0x17670, + 0x1bb3c, + 0x1991e, + 0x17638, + 0x1321c, + 0x1761c, + 0x1320e, + 0x1760e, // 380 + 0x11178, + 0x188be, + 0x13378, + 0x1113c, + 0x17778, + 0x1333c, + 0x1111e, + 0x1773c, + 0x1331e, + 0x1771e, // 390 + 0x111be, + 0x133be, + 0x177be, + 0x172c0, + 0x1b970, + 0x1dcbc, + 0x17260, + 0x1b938, + 0x1dc9e, + 0x17230, // 400 + 0x1b91c, + 0x17218, + 0x1b90e, + 0x1720c, + 0x17206, + 0x13170, + 0x198bc, + 0x17370, + 0x13138, + 0x1989e, // 410 + 0x17338, + 0x1b99e, + 0x1731c, + 0x1310e, + 0x1730e, + 0x110bc, + 0x131bc, + 0x1109e, + 0x173bc, + 0x1319e, // 420 + 0x1739e, + 0x17160, + 0x1b8b8, + 0x1dc5e, + 0x17130, + 0x1b89c, + 0x17118, + 0x1b88e, + 0x1710c, + 0x17106, // 430 + 0x130b8, + 0x1985e, + 0x171b8, + 0x1309c, + 0x1719c, + 0x1308e, + 0x1718e, + 0x1105e, + 0x130de, + 0x171de, // 440 + 0x170b0, + 0x1b85c, + 0x17098, + 0x1b84e, + 0x1708c, + 0x17086, + 0x1305c, + 0x170dc, + 0x1304e, + 0x170ce, // 450 + 0x17058, + 0x1b82e, + 0x1704c, + 0x17046, + 0x1302e, + 0x1706e, + 0x1702c, + 0x17026, + 0x10af0, + 0x1857c, // 460 + 0x10a78, + 0x1853e, + 0x10a3c, + 0x10a1e, + 0x10b7c, + 0x10b3e, + 0x1f0ba, + 0x1e17a, + 0x1c2fa, + 0x185fa, // 470 + 0x11ae0, + 0x18d78, + 0x1c6be, + 0x11a70, + 0x18d3c, + 0x11a38, + 0x18d1e, + 0x11a1c, + 0x11a0e, + 0x10978, // 480 + 0x184be, + 0x11b78, + 0x1093c, + 0x11b3c, + 0x1091e, + 0x11b1e, + 0x109be, + 0x11bbe, + 0x13ac0, + 0x19d70, // 490 + 0x1cebc, + 0x13a60, + 0x19d38, + 0x1ce9e, + 0x13a30, + 0x19d1c, + 0x13a18, + 0x19d0e, + 0x13a0c, + 0x13a06, // 500 + 0x11970, + 0x18cbc, + 0x13b70, + 0x11938, + 0x18c9e, + 0x13b38, + 0x1191c, + 0x13b1c, + 0x1190e, + 0x13b0e, // 510 + 0x108bc, + 0x119bc, + 0x1089e, + 0x13bbc, + 0x1199e, + 0x13b9e, + 0x1bd60, + 0x1deb8, + 0x1ef5e, + 0x17a40, // 520 + 0x1bd30, + 0x1de9c, + 0x17a20, + 0x1bd18, + 0x1de8e, + 0x17a10, + 0x1bd0c, + 0x17a08, + 0x1bd06, + 0x17a04, // 530 + 0x13960, + 0x19cb8, + 0x1ce5e, + 0x17b60, + 0x13930, + 0x19c9c, + 0x17b30, + 0x1bd9c, + 0x19c8e, + 0x17b18, // 540 + 0x1390c, + 0x17b0c, + 0x13906, + 0x17b06, + 0x118b8, + 0x18c5e, + 0x139b8, + 0x1189c, + 0x17bb8, + 0x1399c, // 550 + 0x1188e, + 0x17b9c, + 0x1398e, + 0x17b8e, + 0x1085e, + 0x118de, + 0x139de, + 0x17bde, + 0x17940, + 0x1bcb0, // 560 + 0x1de5c, + 0x17920, + 0x1bc98, + 0x1de4e, + 0x17910, + 0x1bc8c, + 0x17908, + 0x1bc86, + 0x17904, + 0x17902, // 570 + 0x138b0, + 0x19c5c, + 0x179b0, + 0x13898, + 0x19c4e, + 0x17998, + 0x1bcce, + 0x1798c, + 0x13886, + 0x17986, // 580 + 0x1185c, + 0x138dc, + 0x1184e, + 0x179dc, + 0x138ce, + 0x179ce, + 0x178a0, + 0x1bc58, + 0x1de2e, + 0x17890, // 590 + 0x1bc4c, + 0x17888, + 0x1bc46, + 0x17884, + 0x17882, + 0x13858, + 0x19c2e, + 0x178d8, + 0x1384c, + 0x178cc, // 600 + 0x13846, + 0x178c6, + 0x1182e, + 0x1386e, + 0x178ee, + 0x17850, + 0x1bc2c, + 0x17848, + 0x1bc26, + 0x17844, // 610 + 0x17842, + 0x1382c, + 0x1786c, + 0x13826, + 0x17866, + 0x17828, + 0x1bc16, + 0x17824, + 0x17822, + 0x13816, // 620 + 0x17836, + 0x10578, + 0x182be, + 0x1053c, + 0x1051e, + 0x105be, + 0x10d70, + 0x186bc, + 0x10d38, + 0x1869e, // 630 + 0x10d1c, + 0x10d0e, + 0x104bc, + 0x10dbc, + 0x1049e, + 0x10d9e, + 0x11d60, + 0x18eb8, + 0x1c75e, + 0x11d30, // 640 + 0x18e9c, + 0x11d18, + 0x18e8e, + 0x11d0c, + 0x11d06, + 0x10cb8, + 0x1865e, + 0x11db8, + 0x10c9c, + 0x11d9c, // 650 + 0x10c8e, + 0x11d8e, + 0x1045e, + 0x10cde, + 0x11dde, + 0x13d40, + 0x19eb0, + 0x1cf5c, + 0x13d20, + 0x19e98, // 660 + 0x1cf4e, + 0x13d10, + 0x19e8c, + 0x13d08, + 0x19e86, + 0x13d04, + 0x13d02, + 0x11cb0, + 0x18e5c, + 0x13db0, // 670 + 0x11c98, + 0x18e4e, + 0x13d98, + 0x19ece, + 0x13d8c, + 0x11c86, + 0x13d86, + 0x10c5c, + 0x11cdc, + 0x10c4e, // 680 + 0x13ddc, + 0x11cce, + 0x13dce, + 0x1bea0, + 0x1df58, + 0x1efae, + 0x1be90, + 0x1df4c, + 0x1be88, + 0x1df46, // 690 + 0x1be84, + 0x1be82, + 0x13ca0, + 0x19e58, + 0x1cf2e, + 0x17da0, + 0x13c90, + 0x19e4c, + 0x17d90, + 0x1becc, // 700 + 0x19e46, + 0x17d88, + 0x13c84, + 0x17d84, + 0x13c82, + 0x17d82, + 0x11c58, + 0x18e2e, + 0x13cd8, + 0x11c4c, // 710 + 0x17dd8, + 0x13ccc, + 0x11c46, + 0x17dcc, + 0x13cc6, + 0x17dc6, + 0x10c2e, + 0x11c6e, + 0x13cee, + 0x17dee, // 720 + 0x1be50, + 0x1df2c, + 0x1be48, + 0x1df26, + 0x1be44, + 0x1be42, + 0x13c50, + 0x19e2c, + 0x17cd0, + 0x13c48, // 730 + 0x19e26, + 0x17cc8, + 0x1be66, + 0x17cc4, + 0x13c42, + 0x17cc2, + 0x11c2c, + 0x13c6c, + 0x11c26, + 0x17cec, // 740 + 0x13c66, + 0x17ce6, + 0x1be28, + 0x1df16, + 0x1be24, + 0x1be22, + 0x13c28, + 0x19e16, + 0x17c68, + 0x13c24, // 750 + 0x17c64, + 0x13c22, + 0x17c62, + 0x11c16, + 0x13c36, + 0x17c76, + 0x1be14, + 0x1be12, + 0x13c14, + 0x17c34, // 760 + 0x13c12, + 0x17c32, + 0x102bc, + 0x1029e, + 0x106b8, + 0x1835e, + 0x1069c, + 0x1068e, + 0x1025e, + 0x106de, // 770 + 0x10eb0, + 0x1875c, + 0x10e98, + 0x1874e, + 0x10e8c, + 0x10e86, + 0x1065c, + 0x10edc, + 0x1064e, + 0x10ece, // 780 + 0x11ea0, + 0x18f58, + 0x1c7ae, + 0x11e90, + 0x18f4c, + 0x11e88, + 0x18f46, + 0x11e84, + 0x11e82, + 0x10e58, // 790 + 0x1872e, + 0x11ed8, + 0x18f6e, + 0x11ecc, + 0x10e46, + 0x11ec6, + 0x1062e, + 0x10e6e, + 0x11eee, + 0x19f50, // 800 + 0x1cfac, + 0x19f48, + 0x1cfa6, + 0x19f44, + 0x19f42, + 0x11e50, + 0x18f2c, + 0x13ed0, + 0x19f6c, + 0x18f26, // 810 + 0x13ec8, + 0x11e44, + 0x13ec4, + 0x11e42, + 0x13ec2, + 0x10e2c, + 0x11e6c, + 0x10e26, + 0x13eec, + 0x11e66, // 820 + 0x13ee6, + 0x1dfa8, + 0x1efd6, + 0x1dfa4, + 0x1dfa2, + 0x19f28, + 0x1cf96, + 0x1bf68, + 0x19f24, + 0x1bf64, // 830 + 0x19f22, + 0x1bf62, + 0x11e28, + 0x18f16, + 0x13e68, + 0x11e24, + 0x17ee8, + 0x13e64, + 0x11e22, + 0x17ee4, // 840 + 0x13e62, + 0x17ee2, + 0x10e16, + 0x11e36, + 0x13e76, + 0x17ef6, + 0x1df94, + 0x1df92, + 0x19f14, + 0x1bf34, // 850 + 0x19f12, + 0x1bf32, + 0x11e14, + 0x13e34, + 0x11e12, + 0x17e74, + 0x13e32, + 0x17e72, + 0x1df8a, + 0x19f0a, // 860 + 0x1bf1a, + 0x11e0a, + 0x13e1a, + 0x17e3a, + 0x1035c, + 0x1034e, + 0x10758, + 0x183ae, + 0x1074c, + 0x10746, // 870 + 0x1032e, + 0x1076e, + 0x10f50, + 0x187ac, + 0x10f48, + 0x187a6, + 0x10f44, + 0x10f42, + 0x1072c, + 0x10f6c, // 880 + 0x10726, + 0x10f66, + 0x18fa8, + 0x1c7d6, + 0x18fa4, + 0x18fa2, + 0x10f28, + 0x18796, + 0x11f68, + 0x18fb6, // 890 + 0x11f64, + 0x10f22, + 0x11f62, + 0x10716, + 0x10f36, + 0x11f76, + 0x1cfd4, + 0x1cfd2, + 0x18f94, + 0x19fb4, // 900 + 0x18f92, + 0x19fb2, + 0x10f14, + 0x11f34, + 0x10f12, + 0x13f74, + 0x11f32, + 0x13f72, + 0x1cfca, + 0x18f8a, // 910 + 0x19f9a, + 0x10f0a, + 0x11f1a, + 0x13f3a, + 0x103ac, + 0x103a6, + 0x107a8, + 0x183d6, + 0x107a4, + 0x107a2, // 920 + 0x10396, + 0x107b6, + 0x187d4, + 0x187d2, + 0x10794, + 0x10fb4, + 0x10792, + 0x10fb2, + 0x1c7ea + ) // 929 + ); // end of $clusters array + + /** + * Array of factors of the Reed-Solomon polynomial equations used for error correction; one sub array for each correction level (0-8). + * @protected + */ + protected $rsfactors = array( + array( // ECL 0 (2 factors) ------------------------------------------------------------------------------- + 0x01b, + 0x395 + ), // 2 + array( // ECL 1 (4 factors) ------------------------------------------------------------------------------- + 0x20a, + 0x238, + 0x2d3, + 0x329 + ), // 4 + array( // ECL 2 (8 factors) ------------------------------------------------------------------------------- + 0x0ed, + 0x134, + 0x1b4, + 0x11c, + 0x286, + 0x28d, + 0x1ac, + 0x17b + ), // 8 + array( // ECL 3 (16 factors) ------------------------------------------------------------------------------ + 0x112, + 0x232, + 0x0e8, + 0x2f3, + 0x257, + 0x20c, + 0x321, + 0x084, + 0x127, + 0x074, + 0x1ba, + 0x1ac, + 0x127, + 0x02a, + 0x0b0, + 0x041 + ), // 16 + array( // ECL 4 (32 factors) ------------------------------------------------------------------------------ + 0x169, + 0x23f, + 0x39a, + 0x20d, + 0x0b0, + 0x24a, + 0x280, + 0x141, + 0x218, + 0x2e6, + 0x2a5, + 0x2e6, + 0x2af, + 0x11c, + 0x0c1, + 0x205, // 16 + 0x111, + 0x1ee, + 0x107, + 0x093, + 0x251, + 0x320, + 0x23b, + 0x140, + 0x323, + 0x085, + 0x0e7, + 0x186, + 0x2ad, + 0x14a, + 0x03f, + 0x19a + ), // 32 + array( // ECL 5 (64 factors) ------------------------------------------------------------------------------ + 0x21b, + 0x1a6, + 0x006, + 0x05d, + 0x35e, + 0x303, + 0x1c5, + 0x06a, + 0x262, + 0x11f, + 0x06b, + 0x1f9, + 0x2dd, + 0x36d, + 0x17d, + 0x264, // 16 + 0x2d3, + 0x1dc, + 0x1ce, + 0x0ac, + 0x1ae, + 0x261, + 0x35a, + 0x336, + 0x21f, + 0x178, + 0x1ff, + 0x190, + 0x2a0, + 0x2fa, + 0x11b, + 0x0b8, // 32 + 0x1b8, + 0x023, + 0x207, + 0x01f, + 0x1cc, + 0x252, + 0x0e1, + 0x217, + 0x205, + 0x160, + 0x25d, + 0x09e, + 0x28b, + 0x0c9, + 0x1e8, + 0x1f6, // 48 + 0x288, + 0x2dd, + 0x2cd, + 0x053, + 0x194, + 0x061, + 0x118, + 0x303, + 0x348, + 0x275, + 0x004, + 0x17d, + 0x34b, + 0x26f, + 0x108, + 0x21f + ), // 64 + array( // ECL 6 (128 factors) ----------------------------------------------------------------------------- + 0x209, + 0x136, + 0x360, + 0x223, + 0x35a, + 0x244, + 0x128, + 0x17b, + 0x035, + 0x30b, + 0x381, + 0x1bc, + 0x190, + 0x39d, + 0x2ed, + 0x19f, // 16 + 0x336, + 0x05d, + 0x0d9, + 0x0d0, + 0x3a0, + 0x0f4, + 0x247, + 0x26c, + 0x0f6, + 0x094, + 0x1bf, + 0x277, + 0x124, + 0x38c, + 0x1ea, + 0x2c0, // 32 + 0x204, + 0x102, + 0x1c9, + 0x38b, + 0x252, + 0x2d3, + 0x2a2, + 0x124, + 0x110, + 0x060, + 0x2ac, + 0x1b0, + 0x2ae, + 0x25e, + 0x35c, + 0x239, // 48 + 0x0c1, + 0x0db, + 0x081, + 0x0ba, + 0x0ec, + 0x11f, + 0x0c0, + 0x307, + 0x116, + 0x0ad, + 0x028, + 0x17b, + 0x2c8, + 0x1cf, + 0x286, + 0x308, // 64 + 0x0ab, + 0x1eb, + 0x129, + 0x2fb, + 0x09c, + 0x2dc, + 0x05f, + 0x10e, + 0x1bf, + 0x05a, + 0x1fb, + 0x030, + 0x0e4, + 0x335, + 0x328, + 0x382, // 80 + 0x310, + 0x297, + 0x273, + 0x17a, + 0x17e, + 0x106, + 0x17c, + 0x25a, + 0x2f2, + 0x150, + 0x059, + 0x266, + 0x057, + 0x1b0, + 0x29e, + 0x268, // 96 + 0x09d, + 0x176, + 0x0f2, + 0x2d6, + 0x258, + 0x10d, + 0x177, + 0x382, + 0x34d, + 0x1c6, + 0x162, + 0x082, + 0x32e, + 0x24b, + 0x324, + 0x022, // 112 + 0x0d3, + 0x14a, + 0x21b, + 0x129, + 0x33b, + 0x361, + 0x025, + 0x205, + 0x342, + 0x13b, + 0x226, + 0x056, + 0x321, + 0x004, + 0x06c, + 0x21b + ), // 128 + array( // ECL 7 (256 factors) ----------------------------------------------------------------------------- + 0x20c, + 0x37e, + 0x04b, + 0x2fe, + 0x372, + 0x359, + 0x04a, + 0x0cc, + 0x052, + 0x24a, + 0x2c4, + 0x0fa, + 0x389, + 0x312, + 0x08a, + 0x2d0, // 16 + 0x35a, + 0x0c2, + 0x137, + 0x391, + 0x113, + 0x0be, + 0x177, + 0x352, + 0x1b6, + 0x2dd, + 0x0c2, + 0x118, + 0x0c9, + 0x118, + 0x33c, + 0x2f5, // 32 + 0x2c6, + 0x32e, + 0x397, + 0x059, + 0x044, + 0x239, + 0x00b, + 0x0cc, + 0x31c, + 0x25d, + 0x21c, + 0x391, + 0x321, + 0x2bc, + 0x31f, + 0x089, // 48 + 0x1b7, + 0x1a2, + 0x250, + 0x29c, + 0x161, + 0x35b, + 0x172, + 0x2b6, + 0x145, + 0x0f0, + 0x0d8, + 0x101, + 0x11c, + 0x225, + 0x0d1, + 0x374, // 64 + 0x13b, + 0x046, + 0x149, + 0x319, + 0x1ea, + 0x112, + 0x36d, + 0x0a2, + 0x2ed, + 0x32c, + 0x2ac, + 0x1cd, + 0x14e, + 0x178, + 0x351, + 0x209, // 80 + 0x133, + 0x123, + 0x323, + 0x2c8, + 0x013, + 0x166, + 0x18f, + 0x38c, + 0x067, + 0x1ff, + 0x033, + 0x008, + 0x205, + 0x0e1, + 0x121, + 0x1d6, // 96 + 0x27d, + 0x2db, + 0x042, + 0x0ff, + 0x395, + 0x10d, + 0x1cf, + 0x33e, + 0x2da, + 0x1b1, + 0x350, + 0x249, + 0x088, + 0x21a, + 0x38a, + 0x05a, // 112 + 0x002, + 0x122, + 0x2e7, + 0x0c7, + 0x28f, + 0x387, + 0x149, + 0x031, + 0x322, + 0x244, + 0x163, + 0x24c, + 0x0bc, + 0x1ce, + 0x00a, + 0x086, // 128 + 0x274, + 0x140, + 0x1df, + 0x082, + 0x2e3, + 0x047, + 0x107, + 0x13e, + 0x176, + 0x259, + 0x0c0, + 0x25d, + 0x08e, + 0x2a1, + 0x2af, + 0x0ea, // 144 + 0x2d2, + 0x180, + 0x0b1, + 0x2f0, + 0x25f, + 0x280, + 0x1c7, + 0x0c1, + 0x2b1, + 0x2c3, + 0x325, + 0x281, + 0x030, + 0x03c, + 0x2dc, + 0x26d, // 160 + 0x37f, + 0x220, + 0x105, + 0x354, + 0x28f, + 0x135, + 0x2b9, + 0x2f3, + 0x2f4, + 0x03c, + 0x0e7, + 0x305, + 0x1b2, + 0x1a5, + 0x2d6, + 0x210, // 176 + 0x1f7, + 0x076, + 0x031, + 0x31b, + 0x020, + 0x090, + 0x1f4, + 0x0ee, + 0x344, + 0x18a, + 0x118, + 0x236, + 0x13f, + 0x009, + 0x287, + 0x226, // 192 + 0x049, + 0x392, + 0x156, + 0x07e, + 0x020, + 0x2a9, + 0x14b, + 0x318, + 0x26c, + 0x03c, + 0x261, + 0x1b9, + 0x0b4, + 0x317, + 0x37d, + 0x2f2, // 208 + 0x25d, + 0x17f, + 0x0e4, + 0x2ed, + 0x2f8, + 0x0d5, + 0x036, + 0x129, + 0x086, + 0x036, + 0x342, + 0x12b, + 0x39a, + 0x0bf, + 0x38e, + 0x214, // 224 + 0x261, + 0x33d, + 0x0bd, + 0x014, + 0x0a7, + 0x01d, + 0x368, + 0x1c1, + 0x053, + 0x192, + 0x029, + 0x290, + 0x1f9, + 0x243, + 0x1e1, + 0x0ad, // 240 + 0x194, + 0x0fb, + 0x2b0, + 0x05f, + 0x1f1, + 0x22b, + 0x282, + 0x21f, + 0x133, + 0x09f, + 0x39c, + 0x22e, + 0x288, + 0x037, + 0x1f1, + 0x00a + ), // 256 + array( // ECL 8 (512 factors) ----------------------------------------------------------------------------- + 0x160, + 0x04d, + 0x175, + 0x1f8, + 0x023, + 0x257, + 0x1ac, + 0x0cf, + 0x199, + 0x23e, + 0x076, + 0x1f2, + 0x11d, + 0x17c, + 0x15e, + 0x1ec, // 16 + 0x0c5, + 0x109, + 0x398, + 0x09b, + 0x392, + 0x12b, + 0x0e5, + 0x283, + 0x126, + 0x367, + 0x132, + 0x058, + 0x057, + 0x0c1, + 0x160, + 0x30d, // 32 + 0x34e, + 0x04b, + 0x147, + 0x208, + 0x1b3, + 0x21f, + 0x0cb, + 0x29a, + 0x0f9, + 0x15a, + 0x30d, + 0x26d, + 0x280, + 0x10c, + 0x31a, + 0x216, // 48 + 0x21b, + 0x30d, + 0x198, + 0x186, + 0x284, + 0x066, + 0x1dc, + 0x1f3, + 0x122, + 0x278, + 0x221, + 0x025, + 0x35a, + 0x394, + 0x228, + 0x029, // 64 + 0x21e, + 0x121, + 0x07a, + 0x110, + 0x17f, + 0x320, + 0x1e5, + 0x062, + 0x2f0, + 0x1d8, + 0x2f9, + 0x06b, + 0x310, + 0x35c, + 0x292, + 0x2e5, // 80 + 0x122, + 0x0cc, + 0x2a9, + 0x197, + 0x357, + 0x055, + 0x063, + 0x03e, + 0x1e2, + 0x0b4, + 0x014, + 0x129, + 0x1c3, + 0x251, + 0x391, + 0x08e, // 96 + 0x328, + 0x2ac, + 0x11f, + 0x218, + 0x231, + 0x04c, + 0x28d, + 0x383, + 0x2d9, + 0x237, + 0x2e8, + 0x186, + 0x201, + 0x0c0, + 0x204, + 0x102, // 112 + 0x0f0, + 0x206, + 0x31a, + 0x18b, + 0x300, + 0x350, + 0x033, + 0x262, + 0x180, + 0x0a8, + 0x0be, + 0x33a, + 0x148, + 0x254, + 0x312, + 0x12f, // 128 + 0x23a, + 0x17d, + 0x19f, + 0x281, + 0x09c, + 0x0ed, + 0x097, + 0x1ad, + 0x213, + 0x0cf, + 0x2a4, + 0x2c6, + 0x059, + 0x0a8, + 0x130, + 0x192, // 144 + 0x028, + 0x2c4, + 0x23f, + 0x0a2, + 0x360, + 0x0e5, + 0x041, + 0x35d, + 0x349, + 0x200, + 0x0a4, + 0x1dd, + 0x0dd, + 0x05c, + 0x166, + 0x311, // 160 + 0x120, + 0x165, + 0x352, + 0x344, + 0x33b, + 0x2e0, + 0x2c3, + 0x05e, + 0x008, + 0x1ee, + 0x072, + 0x209, + 0x002, + 0x1f3, + 0x353, + 0x21f, // 176 + 0x098, + 0x2d9, + 0x303, + 0x05f, + 0x0f8, + 0x169, + 0x242, + 0x143, + 0x358, + 0x31d, + 0x121, + 0x033, + 0x2ac, + 0x1d2, + 0x215, + 0x334, // 192 + 0x29d, + 0x02d, + 0x386, + 0x1c4, + 0x0a7, + 0x156, + 0x0f4, + 0x0ad, + 0x023, + 0x1cf, + 0x28b, + 0x033, + 0x2bb, + 0x24f, + 0x1c4, + 0x242, // 208 + 0x025, + 0x07c, + 0x12a, + 0x14c, + 0x228, + 0x02b, + 0x1ab, + 0x077, + 0x296, + 0x309, + 0x1db, + 0x352, + 0x2fc, + 0x16c, + 0x242, + 0x38f, // 224 + 0x11b, + 0x2c7, + 0x1d8, + 0x1a4, + 0x0f5, + 0x120, + 0x252, + 0x18a, + 0x1ff, + 0x147, + 0x24d, + 0x309, + 0x2bb, + 0x2b0, + 0x02b, + 0x198, // 240 + 0x34a, + 0x17f, + 0x2d1, + 0x209, + 0x230, + 0x284, + 0x2ca, + 0x22f, + 0x03e, + 0x091, + 0x369, + 0x297, + 0x2c9, + 0x09f, + 0x2a0, + 0x2d9, // 256 + 0x270, + 0x03b, + 0x0c1, + 0x1a1, + 0x09e, + 0x0d1, + 0x233, + 0x234, + 0x157, + 0x2b5, + 0x06d, + 0x260, + 0x233, + 0x16d, + 0x0b5, + 0x304, // 272 + 0x2a5, + 0x136, + 0x0f8, + 0x161, + 0x2c4, + 0x19a, + 0x243, + 0x366, + 0x269, + 0x349, + 0x278, + 0x35c, + 0x121, + 0x218, + 0x023, + 0x309, // 288 + 0x26a, + 0x24a, + 0x1a8, + 0x341, + 0x04d, + 0x255, + 0x15a, + 0x10d, + 0x2f5, + 0x278, + 0x2b7, + 0x2ef, + 0x14b, + 0x0f7, + 0x0b8, + 0x02d, // 304 + 0x313, + 0x2a8, + 0x012, + 0x042, + 0x197, + 0x171, + 0x036, + 0x1ec, + 0x0e4, + 0x265, + 0x33e, + 0x39a, + 0x1b5, + 0x207, + 0x284, + 0x389, // 320 + 0x315, + 0x1a4, + 0x131, + 0x1b9, + 0x0cf, + 0x12c, + 0x37c, + 0x33b, + 0x08d, + 0x219, + 0x17d, + 0x296, + 0x201, + 0x038, + 0x0fc, + 0x155, // 336 + 0x0f2, + 0x31d, + 0x346, + 0x345, + 0x2d0, + 0x0e0, + 0x133, + 0x277, + 0x03d, + 0x057, + 0x230, + 0x136, + 0x2f4, + 0x299, + 0x18d, + 0x328, // 352 + 0x353, + 0x135, + 0x1d9, + 0x31b, + 0x17a, + 0x01f, + 0x287, + 0x393, + 0x1cb, + 0x326, + 0x24e, + 0x2db, + 0x1a9, + 0x0d8, + 0x224, + 0x0f9, // 368 + 0x141, + 0x371, + 0x2bb, + 0x217, + 0x2a1, + 0x30e, + 0x0d2, + 0x32f, + 0x389, + 0x12f, + 0x34b, + 0x39a, + 0x119, + 0x049, + 0x1d5, + 0x317, // 384 + 0x294, + 0x0a2, + 0x1f2, + 0x134, + 0x09b, + 0x1a6, + 0x38b, + 0x331, + 0x0bb, + 0x03e, + 0x010, + 0x1a9, + 0x217, + 0x150, + 0x11e, + 0x1b5, // 400 + 0x177, + 0x111, + 0x262, + 0x128, + 0x0b7, + 0x39b, + 0x074, + 0x29b, + 0x2ef, + 0x161, + 0x03e, + 0x16e, + 0x2b3, + 0x17b, + 0x2af, + 0x34a, // 416 + 0x025, + 0x165, + 0x2d0, + 0x2e6, + 0x14a, + 0x005, + 0x027, + 0x39b, + 0x137, + 0x1a8, + 0x0f2, + 0x2ed, + 0x141, + 0x036, + 0x29d, + 0x13c, // 432 + 0x156, + 0x12b, + 0x216, + 0x069, + 0x29b, + 0x1e8, + 0x280, + 0x2a0, + 0x240, + 0x21c, + 0x13c, + 0x1e6, + 0x2d1, + 0x262, + 0x02e, + 0x290, // 448 + 0x1bf, + 0x0ab, + 0x268, + 0x1d0, + 0x0be, + 0x213, + 0x129, + 0x141, + 0x2fa, + 0x2f0, + 0x215, + 0x0af, + 0x086, + 0x00e, + 0x17d, + 0x1b1, // 464 + 0x2cd, + 0x02d, + 0x06f, + 0x014, + 0x254, + 0x11c, + 0x2e0, + 0x08a, + 0x286, + 0x19b, + 0x36d, + 0x29d, + 0x08d, + 0x397, + 0x02d, + 0x30c, // 480 + 0x197, + 0x0a4, + 0x14c, + 0x383, + 0x0a5, + 0x2d6, + 0x258, + 0x145, + 0x1f2, + 0x28f, + 0x165, + 0x2f0, + 0x300, + 0x0df, + 0x351, + 0x287, // 496 + 0x03f, + 0x136, + 0x35f, + 0x0fb, + 0x16e, + 0x130, + 0x11a, + 0x2e2, + 0x2a3, + 0x19a, + 0x185, + 0x0f4, + 0x01f, + 0x079, + 0x12f, + 0x107 + ) // 512 + ); + + /** + * This is the class constructor - Creates a PDF417 object + * + * @param string $code + * @param int $ecl + * @param int $aspectratio + * + * @param array $macro + */ + public function __construct($code, $ecl = -1, $aspectratio = 2, $macro = array()) + { + $cL = null; + $emptyRow = null; + $macrocw = array(); + $barcodeArray = array(); + + if ((is_null($code)) || ($code == '\0') || ($code == '')) { + return false; + } + // get the input sequence array + $sequence = $this->getInputSequences($code); + $codewords = array(); // array of code-words + foreach ($sequence as $seq) { + $cw = $this->getCompaction($seq[0], $seq[1], true); + $codewords = array_merge($codewords, $cw); + } + if ($codewords[0] == 900) { + // Text Alpha is the default mode, so remove the first code + array_shift($codewords); + } + // count number of codewords + $numcw = count($codewords); + if ($numcw > 925) { + // reached maximum data codeword capacity + return false; + } + // build macro control block codewords + if (!empty($macro)) { + + // beginning of macro control block + $macrocw[] = 928; + // segment index + $cw = $this->getCompaction(902, sprintf('%05d', $macro['segment_index']), false); + $macrocw = array_merge($macrocw, $cw); + // file ID + $cw = $this->getCompaction(900, $macro['file_id'], false); + $macrocw = array_merge($macrocw, $cw); + // optional fields + $optmodes = array(900, 902, 902, 900, 900, 902, 902); + $optsize = array(-1, 2, 4, -1, -1, -1, 2); + foreach ($optmodes as $k => $omode) { + if (isset($macro['option_' . $k])) { + $macrocw[] = 923; + $macrocw[] = $k; + if ($optsize[$k] == 2) { + $macro['option_' . $k] = sprintf('%05d', $macro['option_' . $k]); + } elseif ($optsize[$k] == 4) { + $macro['option_' . $k] = sprintf('%010d', $macro['option_' . $k]); + } + $cw = $this->getCompaction($omode, $macro['option_' . $k], false); + $macrocw = array_merge($macrocw, $cw); + } + } + if ($macro['segment_index'] == ($macro['segment_total'] - 1)) { + // end of control block + $macrocw[] = 922; + } + // update total codewords + $numcw += count($macrocw); + } + // set error correction level + $ecl = $this->getErrorCorrectionLevel($ecl, $numcw); + // number of codewords for error correction + $errsize = (2 << $ecl); + // calculate number of columns (number of codewords per row) and rows + $nce = ($numcw + $errsize + 1); + $cols = round((sqrt(4761 + (68 * $aspectratio * self::ROWHEIGHT * $nce)) - 69) / 34); + // adjust cols + if ($cols < 1) { + $cols = 1; + } elseif ($cols > 30) { + $cols = 30; + } + $rows = ceil($nce / $cols); + $size = ($cols * $rows); + // adjust rows + if (($rows < 3) || ($rows > 90)) { + if ($rows < 3) { + $rows = 3; + } elseif ($rows > 90) { + $rows = 90; + } + $cols = ceil($size / $rows); + $size = ($cols * $rows); + } + if ($size > 928) { + // set dimensions to get maximum capacity + if (abs($aspectratio - (17 * 29 / 32)) < abs($aspectratio - (17 * 16 / 58))) { + $cols = 29; + $rows = 32; + } else { + $cols = 16; + $rows = 58; + } + $size = 928; + } + // calculate padding + $pad = ($size - $nce); + if ($pad > 0) { + if (($size - $rows) == $nce) { + --$rows; + $size -= $rows; + } else { + // add pading + $codewords = array_merge($codewords, array_fill(0, $pad, 900)); + } + } + if (!empty($macro)) { + // add macro section + $codewords = array_merge($codewords, $macrocw); + } + // Symbol Lenght Descriptor (number of data codewords including Symbol Lenght Descriptor and pad codewords) + $sld = $size - $errsize; + // add symbol length description + array_unshift($codewords, $sld); + // calculate error correction + $ecw = $this->getErrorCorrection($codewords, $ecl); + // add error correction codewords + $codewords = array_merge($codewords, $ecw); + // add horizontal quiet zones to start and stop patterns + $pstart = str_repeat('0', self::QUIETH) . $this->startPattern; + $pstop = $this->stopPattern . str_repeat('0', self::QUIETH); + $barcodeArray['num_rows'] = ($rows * self::ROWHEIGHT) + (2 * self::QUIETV); + $barcodeArray['num_cols'] = (($cols + 2) * 17) + 35 + (2 * self::QUIETH); + $barcodeArray['bcode'] = array(); + // build rows for vertical quiet zone + if (self::QUIETV > 0) { + $emptyRow = array_fill(0, $barcodeArray['num_cols'], 0); + for ($i = 0; $i < self::QUIETV; ++$i) { + // add vertical quiet rows + $barcodeArray['bcode'][] = $emptyRow; + } + } + $k = 0; // codeword index + $cid = 0; // initial cluster + // for each row + for ($r = 0; $r < $rows; ++$r) { + // row start code + $row = $pstart; + switch ($cid) { + case 0: + $cL = ((30 * intval($r / 3)) + intval(($rows - 1) / 3)); + break; + + case 1: + $cL = ((30 * intval($r / 3)) + ($ecl * 3) + (($rows - 1) % 3)); + break; + + case 2: + $cL = ((30 * intval($r / 3)) + ($cols - 1)); + break; + + } + + // left row indicator + $row .= sprintf('%17b', $this->clusters[$cid][$cL]); + // for each column + for ($c = 0; $c < $cols; ++$c) { + $row .= sprintf('%17b', $this->clusters[$cid][$codewords[$k]]); + ++$k; + } + + switch ($cid) { + case 0: + $cL = ((30 * intval($r / 3)) + ($cols - 1)); + break; + + case 1: + $cL = ((30 * intval($r / 3)) + intval(($rows - 1) / 3)); + break; + + case 2: + $cL = ((30 * intval($r / 3)) + ($ecl * 3) + (($rows - 1) % 3)); + break; + + } + // right row indicator + $row .= sprintf('%17b', $this->clusters[$cid][$cL]); + // row stop code + $row .= $pstop; + // convert the string to array + $arow = preg_split('//', $row, -1, PREG_SPLIT_NO_EMPTY); + // duplicate row to get the desired height + for ($h = 0; $h < self::ROWHEIGHT; ++$h) { + $barcodeArray['bcode'][] = $arow; + } + ++$cid; + if ($cid > 2) { + $cid = 0; + } + } + if (self::QUIETV > 0) { + for ($i = 0; $i < self::QUIETV; ++$i) { + // add vertical quiet rows + $barcodeArray['bcode'][] = $emptyRow; + } + } + $this->barcodeArray = $barcodeArray; + + return false; + } + + /** + * Returns a barcode array which is readable by Dinesh Rabara + * @return array barcode array readable by Dinesh Rabara; + * @public + */ + public function getBarcodeArray() + { + return $this->barcodeArray; + } + + /** + * Returns the error correction level (0-8) to be used + * + * @param int $ecl + * @param int $numcw + * + * @return int + */ + protected function getErrorCorrectionLevel($ecl, $numcw) + { + // get maximum correction level + $maxecl = ($ecl >= 0 ? 8 : 0); // starting error level + $maxerrsize = (928 - $numcw); // available codewords for error + while ($maxecl > 0) { + $errsize = (2 << $ecl); + if ($maxerrsize >= $errsize) { + break; + } + --$maxecl; + } + // check for automatic levels + if (($ecl < 0) || ($ecl > 8)) { + if ($numcw < 41) { + $ecl = 2; + } elseif ($numcw < 161) { + $ecl = 3; + } elseif ($numcw < 321) { + $ecl = 4; + } elseif ($numcw < 864) { + $ecl = 5; + } else { + $ecl = $maxecl; + } + } + if ($ecl > $maxecl) { + $ecl = $maxecl; + } + + return $ecl; + } + + /** + * Returns the error correction codewords + * + * @param array $cw + * @param int $ecl + * + * @return array + */ + protected function getErrorCorrection($cw, $ecl) + { + // get error correction coefficients + $ecc = $this->rsfactors[$ecl]; + // number of error correction factors + $eclsize = (2 << $ecl); + // maximum index for $rsfactors[$ecl] + $eclmaxid = ($eclsize - 1); + // initialize array of error correction codewords + $ecw = array_fill(0, $eclsize, 0); + // for each data codeword + foreach ($cw as $d) { + $t1 = ($d + $ecw[$eclmaxid]) % 929; + for ($j = $eclmaxid; $j > 0; --$j) { + $t2 = ($t1 * $ecc[$j]) % 929; + $t3 = 929 - $t2; + $ecw[$j] = ($ecw[($j - 1)] + $t3) % 929; + } + $t2 = ($t1 * $ecc[0]) % 929; + $t3 = 929 - $t2; + $ecw[0] = $t3 % 929; + } + foreach ($ecw as $j => $e) { + if ($e != 0) { + $ecw[$j] = 929 - $e; + } + } + $ecw = array_reverse($ecw); + + return $ecw; + } + + /** + * Create array of sequences from input + * + * @param string $code + * + * @return array + */ + protected function getInputSequences($code) + { + $sequenceArray = array(); // array to be returned + $numseq = array(); + // get numeric sequences + preg_match_all('/([0-9]{13,})/', $code, $numseq, PREG_OFFSET_CAPTURE); + $numseq[1][] = array('', strlen($code)); + $offset = 0; + foreach ($numseq[1] as $seq) { + $seqlen = strlen($seq[0]); + if ($seq[1] > 0) { + // extract text sequence before the number sequence + $prevseq = substr($code, $offset, ($seq[1] - $offset)); + $textseq = array(); + // get text sequences + preg_match_all('/([\x09\x0a\x0d\x20-\x7e]{5,})/', $prevseq, $textseq, PREG_OFFSET_CAPTURE); + $textseq[1][] = array('', strlen($prevseq)); + $txtoffset = 0; + foreach ($textseq[1] as $txtseq) { + $txtseqlen = strlen($txtseq[0]); + if ($txtseq[1] > 0) { + // extract byte sequence before the text sequence + $prevtxtseq = substr($prevseq, $txtoffset, ($txtseq[1] - $txtoffset)); + if (strlen($prevtxtseq) > 0) { + // add BYTE sequence + if ((strlen($prevtxtseq) == 1) && ((count($sequenceArray) > 0) && ($sequenceArray[(count($sequenceArray) - 1)][0] == 900))) { + $sequenceArray[] = array(913, $prevtxtseq); + } elseif ((strlen($prevtxtseq) % 6) == 0) { + $sequenceArray[] = array(924, $prevtxtseq); + } else { + $sequenceArray[] = array(901, $prevtxtseq); + } + } + } + if ($txtseqlen > 0) { + // add numeric sequence + $sequenceArray[] = array(900, $txtseq[0]); + } + $txtoffset = $txtseq[1] + $txtseqlen; + } + } + if ($seqlen > 0) { + // add numeric sequence + $sequenceArray[] = array(902, $seq[0]); + } + $offset = $seq[1] + $seqlen; + } + + return $sequenceArray; + } + + /** + * @param int $mode + * @param string $code + * @param bool $addmode + * + * @return array + */ + protected function getCompaction($mode, $code, $addmode = true) + { + $cw = array(); // array of codewords to return + switch ($mode) { + case 900: // Text Compaction mode latch + $submode = 0; // default Alpha sub-mode + $txtarr = array(); // array of characters and sub-mode switching characters + $codelen = strlen($code); + for ($i = 0; $i < $codelen; ++$i) { + $chval = ord($code[$i]); + if (($k = array_search($chval, $this->textsubmodes[$submode])) !== false) { + // we are on the same sub-mode + $txtarr[] = $k; + } else { + // the sub-mode is changed + for ($s = 0; $s < 4; ++$s) { + // search new sub-mode + if (($s != $submode) && (($k = array_search($chval, $this->textsubmodes[$s])) !== false)) { + // $s is the new submode + if (((($i + 1) == $codelen) || ((($i + 1) < $codelen) && (array_search(ord($code[($i + 1)]), $this->textsubmodes[$submode]) !== false))) && (($s == 3) || (($s == 0) && ($submode == 1)))) { + // shift (temporary change only for this char) + if ($s == 3) { + // shift to puntuaction + $txtarr[] = 29; + } else { + // shift from lower to alpha + $txtarr[] = 27; + } + } else { + // latch + $txtarr = array_merge($txtarr, $this->textlatch['' . $submode . $s]); + // set new submode + $submode = $s; + } + // add characted code to array + $txtarr[] = $k; + break; + } + } + } + } + $txtarrlen = count($txtarr); + if (($txtarrlen % 2) != 0) { + // add padding + $txtarr[] = 29; + ++$txtarrlen; + } + // calculate codewords + for ($i = 0; $i < $txtarrlen; $i += 2) { + $cw[] = (30 * $txtarr[$i]) + $txtarr[($i + 1)]; + } + break; + case 901: + case 924: // Byte Compaction mode latch + while (($codelen = strlen($code)) > 0) { + if ($codelen > 6) { + $rest = substr($code, 6); + $code = substr($code, 0, 6); + $sublen = 6; + } else { + $rest = ''; + $sublen = strlen($code); + } + + if ($sublen == 6) { + $t = bcmul('' . ord($code[0]), '1099511627776'); + $t = bcadd($t, bcmul('' . ord($code[1]), '4294967296')); + $t = bcadd($t, bcmul('' . ord($code[2]), '16777216')); + $t = bcadd($t, bcmul('' . ord($code[3]), '65536')); + $t = bcadd($t, bcmul('' . ord($code[4]), '256')); + $t = bcadd($t, '' . ord($code[5])); + do { + $d = bcmod($t, '900'); + $t = bcdiv($t, '900'); + array_unshift($cw, $d); + } while ($t != '0'); + } else { + for ($i = 0; $i < $sublen; ++$i) { + $cw[] = ord($code[$i]); + } + } + + $code = $rest; + } + break; + + case 902: // Numeric Compaction mode latch + while (($codelen = strlen($code)) > 0) { + if ($codelen > 44) { + $rest = substr($code, 44); + $code = substr($code, 0, 44); + } else { + $rest = ''; + } + $t = '1' . $code; + do { + $d = bcmod($t, '900'); + $t = bcdiv($t, '900'); + array_unshift($cw, $d); + } while ($t != '0'); + $code = $rest; + } + break; + + case 913: // Byte Compaction mode shift + $cw[] = ord($code); + break; + } + + if ($addmode) { + // add the compaction mode codeword at the beginning + array_unshift($cw, $mode); + } + + return $cw; + } } \ No newline at end of file diff --git a/modules/QRCode.php b/modules/QRCode.php old mode 100644 new mode 100755 index b14343f..38f4cd8 --- a/modules/QRCode.php +++ b/modules/QRCode.php @@ -76,3150 +76,3150 @@ */ class QRCode { - const - - QRCODEDEFS = true, // Indicate that definitions for this class are set - QR_MODE_NL = -1, // Encoding modes (characters which can be encoded in QRcode) - QR_MODE_NM = 0, // Encoding mode numeric (0-9). 3 characters are encoded to 10bit length. In theory, 7089 characters or less can be stored in a QRcode. - QR_MODE_AN = 1, // Encoding mode alphanumeric (0-9A-Z $%*+-./:) 45characters. 2 characters are encoded to 11bit length. In theory, 4296 characters or less can be stored in a QRcode. - QR_MODE_8B = 2, // Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode. - QR_MODE_KJ = 3, // Encoding mode KANJI. A KANJI character (multibyte character) is encoded to 13bit length. In theory, 1817 characters or less can be stored in a QRcode. - QR_MODE_ST = 4, // Encoding mode STRUCTURED (currently unsupported) - QR_ECLEVEL_L = 0, // Error correction level L : About 7% or less errors can be corrected. - QR_ECLEVEL_M = 1, // Error correction level M : About 15% or less errors can be corrected. - QR_ECLEVEL_Q = 2, // Error correction level Q : About 25% or less errors can be corrected. - QR_ECLEVEL_H = 3, // Error correction level H : About 30% or less errors can be corrected. - - // Version. Size of QRcode is defined as version. Version is from 1 to 40. - // Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. - // So version 40 is 177*177 matrix. - - QRSPEC_VERSION_MAX = 40, // Maximum QR Code version. - QRSPEC_WIDTH_MAX = 177, // Maximum matrix size for maximum version (version 40 is 177*177 matrix). - QRCAP_WIDTH = 0, // Matrix index to get width from $capacity array. - QRCAP_WORDS = 1, // Matrix index to get number of words from $capacity array. - QRCAP_REMINDER = 2, // Matrix index to get remainder from $capacity array. - QRCAP_EC = 3, // Matrix index to get error correction level from $capacity array. - STRUCTURE_HEADER_BITS = 20, // Number of header bits for structured mode - MAX_STRUCTURED_SYMBOLS = 16, // Max number of symbols for structured mode - N1 = 3, // Down point base value for case 1 mask pattern (concatenation of same color in a line or a column) - N2 = 3, // Down point base value for case 2 mask pattern (module block of same color) - N3 = 40, // Down point base value for case 3 mask pattern (1:1:3:1:1(dark:bright:dark:bright:dark)pattern in a line or a column) - N4 = 10, // Down point base value for case 4 mask pattern (ration of dark modules in whole) - QR_FIND_BEST_MASK = true, // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code - QR_FIND_FROM_RANDOM = 2, // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly - QR_DEFAULT_MASK = 2; // when QR_FIND_BEST_MASK === false - - /** - * Barcode array to be returned which is readable by Dinesh Rabara. - * @protected - */ - protected $barcodeArray = array(); - - /** - * QR code version. Size of QRcode is defined as version. Version is from 1 to 40. Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. So version 40 is 177*177 matrix. - * @protected - */ - protected $version = 0; - - /** - * Levels of error correction. See definitions for possible values. - * @protected - */ - protected $level = self::QR_ECLEVEL_L; - - /** - * Encoding mode. - * @protected - */ - protected $hint = self::QR_MODE_8B; - - /** - * Boolean flag, if true the input string will be converted to uppercase. - * @protected - */ - protected $casesensitive = true; - - /** - * Structured QR code (not supported yet). - * @protected - */ - protected $structured = 0; - - /** - * Mask data. - * @protected - */ - protected $data; - - // FrameFiller - - /** - * Width. - * @protected - */ - protected $width; - - /** - * Frame. - * @protected - */ - protected $frame; - - /** - * X position of bit. - * @protected - */ - protected $x; - - /** - * Y position of bit. - * @protected - */ - protected $y; - - /** - * Direction. - * @protected - */ - protected $dir; - - /** - * Single bit value. - * @protected - */ - protected $bit; - - // ---- QRrawcode ---- - - /** - * Data code. - * @protected - */ - protected $datacode = array(); - - /** - * Error correction code. - * @protected - */ - protected $ecccode = array(); - - /** - * Blocks. - * @protected - */ - protected $blocks; - - /** - * Reed-Solomon blocks. - * @protected - */ - protected $rsblocks = array(); //of RSblock - - /** - * Counter. - * @protected - */ - protected $count; - - /** - * Data length. - * @protected - */ - protected $dataLength; - - /** - * Error correction length. - * @protected - */ - protected $eccLength; - - /** - * Value b1. - * @protected - */ - protected $b1; - - // ---- QRmask ---- - - /** - * Run length. - * @protected - */ - protected $runLength = array(); - - // ---- QRsplit ---- - - /** - * Input data string. - * @protected - */ - protected $dataStr = ''; - - /** - * Input items. - * @protected - */ - protected $items; - - // Reed-Solomon items - - /** - * Reed-Solomon items. - * @protected - */ - protected $rsitems = array(); - - /** - * Array of frames. - * @protected - */ - protected $frames = array(); - - /** - * Alphabet-numeric convesion table. - * @protected - */ - protected $anTable = array( - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, // - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, // - 36, - -1, - -1, - -1, - 37, - 38, - -1, - -1, - -1, - -1, - 39, - 40, - -1, - 41, - 42, - 43, // - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 44, - -1, - -1, - -1, - -1, - -1, // - -1, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, // - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - -1, - -1, - -1, - -1, - -1, // - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, // - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1 // - ); - - /** - * Array Table of the capacity of symbols. - * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004. - * @protected - */ - protected $capacity = array( - array(0, 0, 0, array(0, 0, 0, 0)), // - array(21, 26, 0, array(7, 10, 13, 17)), // 1 - array(25, 44, 7, array(10, 16, 22, 28)), // - array(29, 70, 7, array(15, 26, 36, 44)), // - array(33, 100, 7, array(20, 36, 52, 64)), // - array(37, 134, 7, array(26, 48, 72, 88)), // 5 - array(41, 172, 7, array(36, 64, 96, 112)), // - array(45, 196, 0, array(40, 72, 108, 130)), // - array(49, 242, 0, array(48, 88, 132, 156)), // - array(53, 292, 0, array(60, 110, 160, 192)), // - array(57, 346, 0, array(72, 130, 192, 224)), // 10 - array(61, 404, 0, array(80, 150, 224, 264)), // - array(65, 466, 0, array(96, 176, 260, 308)), // - array(69, 532, 0, array(104, 198, 288, 352)), // - array(73, 581, 3, array(120, 216, 320, 384)), // - array(77, 655, 3, array(132, 240, 360, 432)), // 15 - array(81, 733, 3, array(144, 280, 408, 480)), // - array(85, 815, 3, array(168, 308, 448, 532)), // - array(89, 901, 3, array(180, 338, 504, 588)), // - array(93, 991, 3, array(196, 364, 546, 650)), // - array(97, 1085, 3, array(224, 416, 600, 700)), // 20 - array(101, 1156, 4, array(224, 442, 644, 750)), // - array(105, 1258, 4, array(252, 476, 690, 816)), // - array(109, 1364, 4, array(270, 504, 750, 900)), // - array(113, 1474, 4, array(300, 560, 810, 960)), // - array(117, 1588, 4, array(312, 588, 870, 1050)), // 25 - array(121, 1706, 4, array(336, 644, 952, 1110)), // - array(125, 1828, 4, array(360, 700, 1020, 1200)), // - array(129, 1921, 3, array(390, 728, 1050, 1260)), // - array(133, 2051, 3, array(420, 784, 1140, 1350)), // - array(137, 2185, 3, array(450, 812, 1200, 1440)), // 30 - array(141, 2323, 3, array(480, 868, 1290, 1530)), // - array(145, 2465, 3, array(510, 924, 1350, 1620)), // - array(149, 2611, 3, array(540, 980, 1440, 1710)), // - array(153, 2761, 3, array(570, 1036, 1530, 1800)), // - array(157, 2876, 0, array(570, 1064, 1590, 1890)), // 35 - array(161, 3034, 0, array(600, 1120, 1680, 1980)), // - array(165, 3196, 0, array(630, 1204, 1770, 2100)), // - array(169, 3362, 0, array(660, 1260, 1860, 2220)), // - array(173, 3532, 0, array(720, 1316, 1950, 2310)), // - array(177, 3706, 0, array(750, 1372, 2040, 2430)) // 40 - ); - - /** - * Array Length indicator. - * @protected - */ - protected $lengthTableBits = array( - array(10, 12, 14), - array(9, 11, 13), - array(8, 16, 16), - array(8, 10, 12) - ); - - /** - * Array Table of the error correction code (Reed-Solomon block). - * See Table 12-16 (pp.30-36), JIS X0510:2004. - * @protected - */ - protected $eccTable = array( - array(array(0, 0), array(0, 0), array(0, 0), array(0, 0)), // - array(array(1, 0), array(1, 0), array(1, 0), array(1, 0)), // 1 - array(array(1, 0), array(1, 0), array(1, 0), array(1, 0)), // - array(array(1, 0), array(1, 0), array(2, 0), array(2, 0)), // - array(array(1, 0), array(2, 0), array(2, 0), array(4, 0)), // - array(array(1, 0), array(2, 0), array(2, 2), array(2, 2)), // 5 - array(array(2, 0), array(4, 0), array(4, 0), array(4, 0)), // - array(array(2, 0), array(4, 0), array(2, 4), array(4, 1)), // - array(array(2, 0), array(2, 2), array(4, 2), array(4, 2)), // - array(array(2, 0), array(3, 2), array(4, 4), array(4, 4)), // - array(array(2, 2), array(4, 1), array(6, 2), array(6, 2)), // 10 - array(array(4, 0), array(1, 4), array(4, 4), array(3, 8)), // - array(array(2, 2), array(6, 2), array(4, 6), array(7, 4)), // - array(array(4, 0), array(8, 1), array(8, 4), array(12, 4)), // - array(array(3, 1), array(4, 5), array(11, 5), array(11, 5)), // - array(array(5, 1), array(5, 5), array(5, 7), array(11, 7)), // 15 - array(array(5, 1), array(7, 3), array(15, 2), array(3, 13)), // - array(array(1, 5), array(10, 1), array(1, 15), array(2, 17)), // - array(array(5, 1), array(9, 4), array(17, 1), array(2, 19)), // - array(array(3, 4), array(3, 11), array(17, 4), array(9, 16)), // - array(array(3, 5), array(3, 13), array(15, 5), array(15, 10)), // 20 - array(array(4, 4), array(17, 0), array(17, 6), array(19, 6)), // - array(array(2, 7), array(17, 0), array(7, 16), array(34, 0)), // - array(array(4, 5), array(4, 14), array(11, 14), array(16, 14)), // - array(array(6, 4), array(6, 14), array(11, 16), array(30, 2)), // - array(array(8, 4), array(8, 13), array(7, 22), array(22, 13)), // 25 - array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), // - array(array(8, 4), array(22, 3), array(8, 26), array(12, 28)), // - array(array(3, 10), array(3, 23), array(4, 31), array(11, 31)), // - array(array(7, 7), array(21, 7), array(1, 37), array(19, 26)), // - array(array(5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30 - array(array(13, 3), array(2, 29), array(42, 1), array(23, 28)), // - array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), // - array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), // - array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), // - array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), // 35 - array(array(6, 14), array(6, 34), array(46, 10), array(2, 64)), // - array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), // - array(array(4, 18), array(13, 32), array(48, 14), array(42, 32)), // - array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), // - array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)) // 40 - ); - - /** - * Array Positions of alignment patterns. - * This array includes only the second and the third position of the alignment patterns. Rest of them can be calculated from the distance between them. - * See Table 1 in Appendix E (pp.71) of JIS X0510:2004. - * @protected - */ - protected $alignmentPattern = array( - array(0, 0), - array(0, 0), - array(18, 0), - array(22, 0), - array(26, 0), - array(30, 0), // 1- 5 - array(34, 0), - array(22, 38), - array(24, 42), - array(26, 46), - array(28, 50), // 6-10 - array(30, 54), - array(32, 58), - array(34, 62), - array(26, 46), - array(26, 48), // 11-15 - array(26, 50), - array(30, 54), - array(30, 56), - array(30, 58), - array(34, 62), // 16-20 - array(28, 50), - array(26, 50), - array(30, 54), - array(28, 54), - array(32, 58), // 21-25 - array(30, 58), - array(34, 62), - array(26, 50), - array(30, 54), - array(26, 52), // 26-30 - array(30, 56), - array(34, 60), - array(30, 58), - array(34, 62), - array(30, 54), // 31-35 - array(24, 50), - array(28, 54), - array(32, 58), - array(26, 54), - array(30, 58) // 35-40 - ); - - /** - * Array Version information pattern (BCH coded). - * See Table 1 in Appendix D (pp.68) of JIS X0510:2004. - * size: [QRSPEC_VERSION_MAX - 6] - * @protected - */ - protected $versionPattern = array( - 0x07c94, - 0x085bc, - 0x09a99, - 0x0a4d3, - 0x0bbf6, - 0x0c762, - 0x0d847, - 0x0e60d, // - 0x0f928, - 0x10b78, - 0x1145d, - 0x12a17, - 0x13532, - 0x149a6, - 0x15683, - 0x168c9, // - 0x177ec, - 0x18ec4, - 0x191e1, - 0x1afab, - 0x1b08e, - 0x1cc1a, - 0x1d33f, - 0x1ed75, // - 0x1f250, - 0x209d5, - 0x216f0, - 0x228ba, - 0x2379f, - 0x24b0b, - 0x2542e, - 0x26a64, // - 0x27541, - 0x28c69 - ); - - /** - * Array Format information - * @protected - */ - protected $formatInfo = array( - array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), // - array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), // - array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), // - array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) // - ); - - - /** - * This is the class constructor - creates a QRcode object - * - * @param string $code - * @param string $eclevel - */ - public function __construct($code, $eclevel = 'L') - { - $barcodeArray = array(); - if ((is_null($code)) || ($code == '\0') || ($code == '')) { - return false; - } - // set error correction level - $this->level = array_search($eclevel, array('L', 'M', 'Q', 'H')); - if ($this->level === false) { - $this->level = self::QR_ECLEVEL_L; - } - if (($this->hint != self::QR_MODE_8B) && ($this->hint != self::QR_MODE_KJ)) { - return false; - } - if (($this->version < 0) || ($this->version > self::QRSPEC_VERSION_MAX)) { - return false; - } - $this->items = array(); - $this->encodeString($code); - if (is_null($this->data)) { - return false; - } - $qrTab = $this->binarize($this->data); - $size = count($qrTab); - $barcodeArray['num_rows'] = $size; - $barcodeArray['num_cols'] = $size; - $barcodeArray['bcode'] = array(); - foreach ($qrTab as $line) { - $arrAdd = array(); - foreach (str_split($line) as $char) { - $arrAdd[] = ($char == '1') ? 1 : 0; - } - $barcodeArray['bcode'][] = $arrAdd; - } - $this->barcodeArray = $barcodeArray; - - return false; - } - - /** - * Returns a barcode array which is readable by Dinesh Rabara - * @return array barcode array readable by Dinesh Rabara; - * @public - */ - public function getBarcodeArray() - { - return $this->barcodeArray; - } - - /** - * Convert the frame in binary form - * - * @param array $frame - * - * @return mixed - */ - protected function binarize($frame) - { - $len = count($frame); - // the frame is square (width = height) - foreach ($frame as &$frameLine) { - for ($i = 0; $i < $len; $i++) { - $frameLine[$i] = (ord($frameLine[$i]) & 1) ? '1' : '0'; - } - } - - return $frame; - } - - /** - * Encode the input string to QR code - * - * @param string $string - * - * @return null - */ - protected function encodeString($string) - { - $this->dataStr = $string; - if (!$this->casesensitive) { - $this->toUpper(); - } - $ret = $this->splitString(); - if ($ret < 0) { - - return null; - } - $this->encodeMask(-1); - } - - /** - * @param int $mask - * - * @return null - */ - protected function encodeMask($mask) - { - $spec = array(0, 0, 0, 0, 0); - $this->datacode = $this->getByteStream($this->items); - if (is_null($this->datacode)) { - return null; - } - $spec = $this->getEccSpec($this->version, $this->level, $spec); - $this->b1 = $this->rsBlockNum1($spec); - $this->dataLength = $this->rsDataLength($spec); - $this->eccLength = $this->rsEccLength($spec); - $this->ecccode = array_fill(0, $this->eccLength, 0); - $this->blocks = $this->rsBlockNum($spec); - $ret = $this->init($spec); - if ($ret < 0) { - return null; - } - $this->count = 0; - $this->width = $this->getWidth($this->version); - $this->frame = $this->newFrame($this->version); - $this->x = $this->width - 1; - $this->y = $this->width - 1; - $this->dir = -1; - $this->bit = -1; - // inteleaved data and ecc codes - for ($i = 0; $i < ($this->dataLength + $this->eccLength); $i++) { - $code = $this->getCode(); - $bit = 0x80; - for ($j = 0; $j < 8; $j++) { - $addr = $this->getNextPosition(); - $this->setFrameAt($addr, 0x02 | (($bit & $code) != 0)); - $bit = $bit >> 1; - } - } - // remainder bits - $j = $this->getRemainder($this->version); - for ($i = 0; $i < $j; $i++) { - $addr = $this->getNextPosition(); - $this->setFrameAt($addr, 0x02); - } - // masking - $this->runLength = array_fill(0, self::QRSPEC_WIDTH_MAX + 1, 0); - if ($mask < 0) { - if (self::QR_FIND_BEST_MASK) { - $masked = $this->mask($this->width, $this->frame, $this->level); - } else { - $masked = $this->makeMask($this->width, $this->frame, (intval(self::QR_DEFAULT_MASK) % 8), $this->level); - } - } else { - $masked = $this->makeMask($this->width, $this->frame, $mask, $this->level); - } - if ($masked == null) { - return null; - } - $this->data = $masked; - } - - - /** - * Set frame value at specified position - * - * @param array $at - * @param int $val - */ - protected function setFrameAt($at, $val) - { - $this->frame[$at['y']][$at['x']] = chr($val); - } - - /** - * Get frame value at specified position - * - * @param array $at - * - * @return int - */ - protected function getFrameAt($at) - { - return ord($this->frame[$at['y']][$at['x']]); - } - - /** - * Return the next frame position - * - * @return array|null - */ - protected function getNextPosition() - { - do { - if ($this->bit == -1) { - $this->bit = 0; - - return array('x' => $this->x, 'y' => $this->y); - } - $x = $this->x; - $y = $this->y; - $w = $this->width; - if ($this->bit == 0) { - $x--; - $this->bit++; - } else { - $x++; - $y += $this->dir; - $this->bit--; - } - if ($this->dir < 0) { - if ($y < 0) { - $y = 0; - $x -= 2; - $this->dir = 1; - if ($x == 6) { - $x--; - $y = 9; - } - } - } else { - if ($y == $w) { - $y = $w - 1; - $x -= 2; - $this->dir = -1; - if ($x == 6) { - $x--; - $y -= 8; - } - } - } - if (($x < 0) || ($y < 0)) { - return null; - } - $this->x = $x; - $this->y = $y; - } while (ord($this->frame[$y][$x]) & 0x80); - - return array('x' => $x, 'y' => $y); - } - - /** - * Initialize code - * - * @param array $spec - * - * @return int - */ - protected function init($spec) - { - $dl = $this->rsDataCodes1($spec); - $el = $this->rsEccCodes1($spec); - $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); - $blockNo = 0; - $dataPos = 0; - $eccPos = 0; - $endfor = $this->rsBlockNum1($spec); - for ($i = 0; $i < $endfor; ++$i) { - $ecc = array_slice($this->ecccode, $eccPos); - $this->rsblocks[$blockNo] = array(); - $this->rsblocks[$blockNo]['dataLength'] = $dl; - $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos); - $this->rsblocks[$blockNo]['eccLength'] = $el; - $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc); - $this->rsblocks[$blockNo]['ecc'] = $ecc; - $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc); - $dataPos += $dl; - $eccPos += $el; - $blockNo++; - } - if ($this->rsBlockNum2($spec) == 0) { - return 0; - } - $dl = $this->rsDataCodes2($spec); - $el = $this->rsEccCodes2($spec); - $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); - if ($rs == null) { - return -1; - } - $endfor = $this->rsBlockNum2($spec); - for ($i = 0; $i < $endfor; ++$i) { - $ecc = array_slice($this->ecccode, $eccPos); - $this->rsblocks[$blockNo] = array(); - $this->rsblocks[$blockNo]['dataLength'] = $dl; - $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos); - $this->rsblocks[$blockNo]['eccLength'] = $el; - $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc); - $this->rsblocks[$blockNo]['ecc'] = $ecc; - $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc); - $dataPos += $dl; - $eccPos += $el; - $blockNo++; - } - - return 0; - } - - /** - * Return Reed-Solomon block code. - * - * @return int - */ - protected function getCode() - { - if ($this->count < $this->dataLength) { - $row = (int) ($this->count % $this->blocks); - $col = (int) ($this->count / $this->blocks); - if ($col >= $this->rsblocks[0]['dataLength']) { - $row += $this->b1; - } - $ret = $this->rsblocks[$row]['data'][$col]; - } elseif ($this->count < $this->dataLength + $this->eccLength) { - $row = (int) (($this->count - $this->dataLength) % $this->blocks); - $col = (int) (($this->count - $this->dataLength) / $this->blocks); - $ret = $this->rsblocks[$row]['ecc'][$col]; - } else { - return 0; - } - $this->count++; - - return $ret; - } - - - /** - * Write Format Information on frame and returns the number of black bits - * - * @param int $width - * @param array &$frame - * @param int $mask - * @param int $level - * - * @return int - */ - protected function writeFormatInformation($width, &$frame, $mask, $level) - { - $blacks = 0; - $format = $this->getFormatInfo($mask, $level); - for ($i = 0; $i < 8; ++$i) { - if ($format & 1) { - $blacks += 2; - $v = 0x85; - } else { - $v = 0x84; - } - $frame[8][$width - 1 - $i] = chr($v); - if ($i < 6) { - $frame[$i][8] = chr($v); - } else { - $frame[$i + 1][8] = chr($v); - } - $format = $format >> 1; - } - for ($i = 0; $i < 7; ++$i) { - if ($format & 1) { - $blacks += 2; - $v = 0x85; - } else { - $v = 0x84; - } - $frame[$width - 7 + $i][8] = chr($v); - if ($i == 0) { - $frame[8][7] = chr($v); - } else { - $frame[8][6 - $i] = chr($v); - } - $format = $format >> 1; - } - - return $blacks; - } - - /** - * mask0 - * - * @param int $x - * @param int $y - * - * @return int - */ - protected function mask0($x, $y) - { - return ($x + $y) & 1; - } - - /** - * mask1 - * - * @param int $y - * - * @return int - */ - protected function mask1($y) - { - return ($y & 1); - } - - /** - * mask 2 - * - * @param int $x - * - * @return int - */ - protected function mask2($x) - { - return ($x % 3); - } - - /** - * mask3 - * - * @param int $x - * @param int $y - * - * @return int - */ - protected function mask3($x, $y) - { - return ($x + $y) % 3; - } - - /** - * mask4 - * - * @param int $x - * @param int $y - * - * @return int - */ - protected function mask4($x, $y) - { - return (((int) ($y / 2)) + ((int) ($x / 3))) & 1; - } - - /** - * mask5 - * - * @param int $x - * @param int $y - * - * @return int - */ - protected function mask5($x, $y) - { - return (($x * $y) & 1) + ($x * $y) % 3; - } - - /** - * mask6 - * - * @param int $x - * @param int $y - * - * @return int - */ - protected function mask6($x, $y) - { - return ((($x * $y) & 1) + ($x * $y) % 3) & 1; - } - - /** - * mask7 - * - * @param int $x - * @param int $y - * - * @return int - */ - protected function mask7($x, $y) - { - return ((($x * $y) % 3) + (($x + $y) & 1)) & 1; - } - - /** - * Return bitmask - * - * @param int $maskNo - * @param int $width - * @param array $frame - * - * @return array - */ - protected function generateMaskNo($maskNo, $width, $frame) - { - $bitMask = array_fill(0, $width, array_fill(0, $width, 0)); - for ($y = 0; $y < $width; ++$y) { - for ($x = 0; $x < $width; ++$x) { - if (ord($frame[$y][$x]) & 0x80) { - $bitMask[$y][$x] = 0; - } else { - $maskFunc = call_user_func(array($this, 'mask' . $maskNo), $x, $y); - $bitMask[$y][$x] = ($maskFunc == 0) ? 1 : 0; - } - } - } - - return $bitMask; - } - - /** - * makeMaskNo - * - * @param int $maskNo - * @param int $width - * @param array $s - * @param array &$d - * @param bool $maskGenOnly - * - * @return int - */ - protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) - { - $b = 0; - $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d); - if ($maskGenOnly) { - - return null; - } - $d = $s; - for ($y = 0; $y < $width; ++$y) { - for ($x = 0; $x < $width; ++$x) { - if ($bitMask[$y][$x] == 1) { - $d[$y][$x] = chr(ord($s[$y][$x]) ^ ((int) ($bitMask[$y][$x]))); - } - $b += (int) (ord($d[$y][$x]) & 1); - } - } - - return $b; - } - - /** - * makeMask - * - * @param int $width - * @param array $frame - * @param int $maskNo - * @param int $level - * - * @return array - */ - protected function makeMask($width, $frame, $maskNo, $level) - { - $masked = array_fill(0, $width, str_repeat("\0", $width)); - $this->makeMaskNo($maskNo, $width, $frame, $masked); - $this->writeFormatInformation($width, $masked, $maskNo, $level); - - return $masked; - } - - /** - * calcN1N3 - * - * @param int $length - * - * @return int - */ - protected function calcN1N3($length) - { - $demerit = 0; - for ($i = 0; $i < $length; ++$i) { - if ($this->runLength[$i] >= 5) { - $demerit += (self::N1 + ($this->runLength[$i] - 5)); - } - if ($i & 1) { - if (($i >= 3) && ($i < ($length - 2)) && ($this->runLength[$i] % 3 == 0)) { - $fact = (int) ($this->runLength[$i] / 3); - if (($this->runLength[$i - 2] == $fact) - && ($this->runLength[$i - 1] == $fact) - && ($this->runLength[$i + 1] == $fact) - && ($this->runLength[$i + 2] == $fact) - ) { - if (($this->runLength[$i - 3] < 0) || ($this->runLength[$i - 3] >= (4 * $fact))) { - $demerit += self::N3; - } elseif ((($i + 3) >= $length) || ($this->runLength[$i + 3] >= (4 * $fact))) { - $demerit += self::N3; - } - } - } - } - } - - return $demerit; - } - - /** - * evaluateSymbol - * - * @param int $width - * @param array $frame - * - * @return int - */ - protected function evaluateSymbol($width, $frame) - { - $demerit = 0; - $frameYM = array(); - - for ($y = 0; $y < $width; ++$y) { - $head = 0; - $this->runLength[0] = 1; - $frameY = $frame[$y]; - if ($y > 0) { - $frameYM = $frame[$y - 1]; - } - for ($x = 0; $x < $width; ++$x) { - if (($x > 0) && ($y > 0)) { - $b22 = ord($frameY[$x]) & ord($frameY[$x - 1]) & ord($frameYM[$x]) & ord($frameYM[$x - 1]); - $w22 = ord($frameY[$x]) | ord($frameY[$x - 1]) | ord($frameYM[$x]) | ord($frameYM[$x - 1]); - if (($b22 | ($w22 ^ 1)) & 1) { - $demerit += self::N2; - } - } - if (($x == 0) && (ord($frameY[$x]) & 1)) { - $this->runLength[0] = -1; - $head = 1; - $this->runLength[$head] = 1; - } elseif ($x > 0) { - if ((ord($frameY[$x]) ^ ord($frameY[$x - 1])) & 1) { - $head++; - $this->runLength[$head] = 1; - } else { - $this->runLength[$head]++; - } - } - } - $demerit += $this->calcN1N3($head + 1); - } - for ($x = 0; $x < $width; ++$x) { - $head = 0; - $this->runLength[0] = 1; - for ($y = 0; $y < $width; ++$y) { - if (($y == 0) && (ord($frame[$y][$x]) & 1)) { - $this->runLength[0] = -1; - $head = 1; - $this->runLength[$head] = 1; - } elseif ($y > 0) { - if ((ord($frame[$y][$x]) ^ ord($frame[$y - 1][$x])) & 1) { - $head++; - $this->runLength[$head] = 1; - } else { - $this->runLength[$head]++; - } - } - } - $demerit += $this->calcN1N3($head + 1); - } - - return $demerit; - } - - /** - * mask - * - * @param int $width - * @param array $frame - * @param int $level - * - * @return array - */ - protected function mask($width, $frame, $level) - { - $minDemerit = PHP_INT_MAX; - $checkedMasks = array(0, 1, 2, 3, 4, 5, 6, 7); - if (self::QR_FIND_FROM_RANDOM !== false) { - $howManuOut = 8 - (self::QR_FIND_FROM_RANDOM % 9); - for ($i = 0; $i < $howManuOut; ++$i) { - $remPos = rand(0, count($checkedMasks) - 1); - unset($checkedMasks[$remPos]); - $checkedMasks = array_values($checkedMasks); - } - } - $bestMask = $frame; - foreach ($checkedMasks as $i) { - $mask = array_fill(0, $width, str_repeat("\0", $width)); - $blacks = $this->makeMaskNo($i, $width, $frame, $mask); - $blacks += $this->writeFormatInformation($width, $mask, $i, $level); - $blacks = (int) (100 * $blacks / ($width * $width)); - $demerit = (int) ((int) (abs($blacks - 50) / 5) * self::N4); - $demerit += $this->evaluateSymbol($width, $mask); - if ($demerit < $minDemerit) { - $minDemerit = $demerit; - $bestMask = $mask; - } - } - - return $bestMask; - } - - /** - * Return true if the character at specified position is a number - * - * @param string $str - * @param int $pos - * - * @return bool - */ - protected function isdigitat($str, $pos) - { - if ($pos >= strlen($str)) { - return false; - } - - return ((ord($str[$pos]) >= ord('0')) && (ord($str[$pos]) <= ord('9'))); - } - - /** - * Return true if the character at specified position is an alphanumeric character - * - * @param string $str - * @param int $pos - * - * @return bool - */ - protected function isalnumat($str, $pos) - { - if ($pos >= strlen($str)) { - return false; - } - - return ($this->lookAnTable(ord($str[$pos])) >= 0); - } - - /** - * identifyMode - * - * @param int $pos - * - * @return int - */ - protected function identifyMode($pos) - { - if ($pos >= strlen($this->dataStr)) { - return self::QR_MODE_NL; - } - $c = $this->dataStr[$pos]; - if ($this->isdigitat($this->dataStr, $pos)) { - return self::QR_MODE_NM; - } elseif ($this->isalnumat($this->dataStr, $pos)) { - return self::QR_MODE_AN; - } elseif ($this->hint == self::QR_MODE_KJ) { - if ($pos + 1 < strlen($this->dataStr)) { - $d = $this->dataStr[$pos + 1]; - $word = (ord($c) << 8) | ord($d); - if (($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) { - return self::QR_MODE_KJ; - } - } - } - - return self::QR_MODE_8B; - } - - /** - * eatNum - * @return int run - */ - protected function eatNum() - { - $ln = $this->lengthIndicator(self::QR_MODE_NM, $this->version); - $p = 0; - while ($this->isdigitat($this->dataStr, $p)) { - $p++; - } - $run = $p; - $mode = $this->identifyMode($p); - if ($mode == self::QR_MODE_8B) { - $dif = $this->estimateBitsModeNum($run) + 4 + $ln - + $this->estimateBitsMode8(1) // + 4 + l8 - - $this->estimateBitsMode8($run + 1); // - 4 - l8 - if ($dif > 0) { - return $this->eat8(); - } - } - if ($mode == self::QR_MODE_AN) { - $dif = $this->estimateBitsModeNum($run) + 4 + $ln - + $this->estimateBitsModeAn(1) // + 4 + la - - $this->estimateBitsModeAn($run + 1); - // - 4 - la - if ($dif > 0) { - return $this->eatAn(); - } - } - $this->items = $this->appendNewInputItem($this->items, self::QR_MODE_NM, $run, str_split($this->dataStr)); - - return $run; - } - - /** - * eatAn - * @return int run - */ - protected function eatAn() - { - $la = $this->lengthIndicator(self::QR_MODE_AN, $this->version); - $ln = $this->lengthIndicator(self::QR_MODE_NM, $this->version); - $p = 1; - while ($this->isalnumat($this->dataStr, $p)) { - if ($this->isdigitat($this->dataStr, $p)) { - $q = $p; - while ($this->isdigitat($this->dataStr, $q)) { - $q++; - } - $dif = $this->estimateBitsModeAn($p) // + 4 + la - + $this->estimateBitsModeNum($q - $p) + 4 + $ln - - $this->estimateBitsModeAn($q); // - 4 - la - if ($dif < 0) { - break; - } else { - $p = $q; - } - } else { - $p++; - } - } - $run = $p; - if (!$this->isalnumat($this->dataStr, $p)) { - $dif = $this->estimateBitsModeAn($run) + 4 + $la - + $this->estimateBitsMode8(1) // + 4 + l8 - - $this->estimateBitsMode8($run + 1); // - 4 - l8 - if ($dif > 0) { - return $this->eat8(); - } - } - $this->items = $this->appendNewInputItem($this->items, self::QR_MODE_AN, $run, str_split($this->dataStr)); - - return $run; - } - - /** - * eatKanji - * - * @return int - */ - protected function eatKanji() - { - $p = 0; - while ($this->identifyMode($p) == self::QR_MODE_KJ) { - $p += 2; - } - - $run = $p; - $this->items = $this->appendNewInputItem($this->items, self::QR_MODE_KJ, $p, str_split($this->dataStr)); - - return $run; - } - - /** - * eat8 - * - * @return int run - */ - protected function eat8() - { - $la = $this->lengthIndicator(self::QR_MODE_AN, $this->version); - $ln = $this->lengthIndicator(self::QR_MODE_NM, $this->version); - $p = 1; - $dataStrLen = strlen($this->dataStr); - while ($p < $dataStrLen) { - $mode = $this->identifyMode($p); - if ($mode == self::QR_MODE_KJ) { - break; - } - if ($mode == self::QR_MODE_NM) { - $q = $p; - while ($this->isdigitat($this->dataStr, $q)) { - $q++; - } - $dif = $this->estimateBitsMode8($p) // + 4 + l8 - + $this->estimateBitsModeNum($q - $p) + 4 + $ln - - $this->estimateBitsMode8($q); // - 4 - l8 - if ($dif < 0) { - break; - } else { - $p = $q; - } - } elseif ($mode == self::QR_MODE_AN) { - $q = $p; - while ($this->isalnumat($this->dataStr, $q)) { - $q++; - } - $dif = $this->estimateBitsMode8($p) // + 4 + l8 - + $this->estimateBitsModeAn($q - $p) + 4 + $la - - $this->estimateBitsMode8($q); // - 4 - l8 - if ($dif < 0) { - break; - } else { - $p = $q; - } - } else { - $p++; - } - } - $run = $p; - $this->items = $this->appendNewInputItem($this->items, self::QR_MODE_8B, $run, str_split($this->dataStr)); - - return $run; - } - - /** - * splitString - * - * @return int - */ - protected function splitString() - { - while (strlen($this->dataStr) > 0) { - if ($this->dataStr == '') { - return 0; - } - $mode = $this->identifyMode(0); - switch ($mode) { - case self::QR_MODE_NM: - { - $length = $this->eatNum(); - break; - } - case self::QR_MODE_AN: - { - $length = $this->eatAn(); - break; - } - case self::QR_MODE_KJ: - { - if ($this->hint == self::QR_MODE_KJ) { - $length = $this->eatKanji(); - } else { - $length = $this->eat8(); - } - break; - } - default: - { - $length = $this->eat8(); - break; - } - } - if ($length == 0) { - return 0; - } - if ($length < 0) { - return -1; - } - $this->dataStr = substr($this->dataStr, $length); - } - - return 0; - } - - /** - * toUpper - * - * @return string - */ - protected function toUpper() - { - $stringLen = strlen($this->dataStr); - $p = 0; - while ($p < $stringLen) { - $mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint); - if ($mode == self::QR_MODE_KJ) { - $p += 2; - } else { - if ((ord($this->dataStr[$p]) >= ord('a')) && (ord($this->dataStr[$p]) <= ord('z'))) { - $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32); - } - $p++; - } - } - - return $this->dataStr; - } - - /** - * newInputItem - * - * @param int $mode - * @param int $size - * @param array $data - * @param array $bstream - * - * @return array|null - */ - protected function newInputItem($mode, $size, $data, $bstream = null) - { - $setData = array_slice($data, 0, $size); - if (count($setData) < $size) { - $setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0)); - } - if (!$this->check($mode, $size, $setData)) { - return null; - } - $inputitem = array(); - $inputitem['mode'] = $mode; - $inputitem['size'] = $size; - $inputitem['data'] = $setData; - $inputitem['bstream'] = $bstream; - - return $inputitem; - } - - /** - * encodeModeNum - * - * @param array $inputitem - * @param int $version - * - * @return mixed - */ - protected function encodeModeNum($inputitem, $version) - { - $words = (int) ($inputitem['size'] / 3); - $inputitem['bstream'] = array(); - $val = 0x1; - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val); - $inputitem['bstream'] = $this->appendNum( - $inputitem['bstream'], - $this->lengthIndicator(self::QR_MODE_NM, $version), - $inputitem['size'] - ); - for ($i = 0; $i < $words; ++$i) { - $val = (ord($inputitem['data'][$i * 3]) - ord('0')) * 100; - $val += (ord($inputitem['data'][$i * 3 + 1]) - ord('0')) * 10; - $val += (ord($inputitem['data'][$i * 3 + 2]) - ord('0')); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val); - } - if ($inputitem['size'] - $words * 3 == 1) { - $val = ord($inputitem['data'][$words * 3]) - ord('0'); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val); - } elseif (($inputitem['size'] - ($words * 3)) == 2) { - $val = (ord($inputitem['data'][$words * 3]) - ord('0')) * 10; - $val += (ord($inputitem['data'][$words * 3 + 1]) - ord('0')); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val); - } - - return $inputitem; - } - - /** - * encodeModeAn - * - * @param array $inputitem - * @param int $version - * - * @return mixed - */ - protected function encodeModeAn($inputitem, $version) - { - $words = (int) ($inputitem['size'] / 2); - $inputitem['bstream'] = array(); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02); - $inputitem['bstream'] = $this->appendNum( - $inputitem['bstream'], - $this->lengthIndicator(self::QR_MODE_AN, $version), - $inputitem['size'] - ); - for ($i = 0; $i < $words; ++$i) { - $val = (int) ($this->lookAnTable(ord($inputitem['data'][$i * 2])) * 45); - $val += (int) ($this->lookAnTable(ord($inputitem['data'][($i * 2) + 1]))); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val); - } - if ($inputitem['size'] & 1) { - $val = $this->lookAnTable(ord($inputitem['data'][($words * 2)])); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val); - } - - return $inputitem; - } - - /** - * encodeMode8 - * - * @param array $inputitem - * @param int $version - * - * @return mixed - */ - protected function encodeMode8($inputitem, $version) - { - $inputitem['bstream'] = array(); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4); - $inputitem['bstream'] = $this->appendNum( - $inputitem['bstream'], - $this->lengthIndicator(self::QR_MODE_8B, $version), - $inputitem['size'] - ); - for ($i = 0; $i < $inputitem['size']; ++$i) { - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i])); - } - - return $inputitem; - } - - /** - * encodeModeKanji - * - * @param array $inputitem - * @param int $version - * - * @return mixed - */ - protected function encodeModeKanji($inputitem, $version) - { - $inputitem['bstream'] = array(); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8); - $inputitem['bstream'] = $this->appendNum( - $inputitem['bstream'], - $this->lengthIndicator(self::QR_MODE_KJ, $version), - (int) ($inputitem['size'] / 2) - ); - for ($i = 0; $i < $inputitem['size']; $i += 2) { - $val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i + 1]); - if ($val <= 0x9ffc) { - $val -= 0x8140; - } else { - $val -= 0xc140; - } - $h = ($val >> 8) * 0xc0; - $val = ($val & 0xff) + $h; - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val); - } - - return $inputitem; - } - - /** - * encodeModeStructure - * - * @param array $inputitem - * - * @return mixed - */ - protected function encodeModeStructure($inputitem) - { - $inputitem['bstream'] = array(); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1); - $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2])); - - return $inputitem; - } - - /** - * encodeBitStream - * - * @param array $inputitem - * @param int $version - * - * @return mixed - */ - protected function encodeBitStream($inputitem, $version) - { - $inputitem['bstream'] = array(); - $words = $this->maximumWords($inputitem['mode'], $version); - if ($inputitem['size'] > $words) { - $st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']); - $st2 = $this->newInputItem( - $inputitem['mode'], - $inputitem['size'] - $words, - array_slice($inputitem['data'], $words) - ); - $st1 = $this->encodeBitStream($st1, $version); - $st2 = $this->encodeBitStream($st2, $version); - $inputitem['bstream'] = array(); - $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']); - $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']); - } else { - switch ($inputitem['mode']) { - case self::QR_MODE_NM: - { - $inputitem = $this->encodeModeNum($inputitem, $version); - break; - } - case self::QR_MODE_AN: - { - $inputitem = $this->encodeModeAn($inputitem, $version); - break; - } - case self::QR_MODE_8B: - { - $inputitem = $this->encodeMode8($inputitem, $version); - break; - } - case self::QR_MODE_KJ: - { - $inputitem = $this->encodeModeKanji($inputitem, $version); - break; - } - case self::QR_MODE_ST: - { - $inputitem = $this->encodeModeStructure($inputitem); - break; - } - default: - { - break; - } - } - } - - return $inputitem; - } - - /** - * Append data to an input object - The data is copied and appended to the input object. - * - * @param array $items - * @param int $mode - * @param int $size - * @param array $data - * - * @return array - */ - protected function appendNewInputItem($items, $mode, $size, $data) - { - $newitem = $this->newInputItem($mode, $size, $data); - if (!empty($newitem)) { - $items[] = $newitem; - } - - return $items; - } - - /** - * insertStructuredAppendHeader - * - * @param array $items - * @param int $size - * @param int $index - * @param int $parity - * - * @return int - */ - protected function insertStructuredAppendHeader($items, $size, $index, $parity) - { - if ($size > self::MAX_STRUCTURED_SYMBOLS) { - return -1; - } - if (($index <= 0) || ($index > self::MAX_STRUCTURED_SYMBOLS)) { - return -1; - } - $buf = array($size, $index, $parity); - $entry = $this->newInputItem(self::QR_MODE_ST, 3, $buf); - array_unshift($items, $entry); - - return $items; - } - - /** - * calcParity - * - * @param array $items - * - * @return int - */ - protected function calcParity($items) - { - $parity = 0; - foreach ($items as $item) { - if ($item['mode'] != self::QR_MODE_ST) { - for ($i = $item['size'] - 1; $i >= 0; --$i) { - $parity ^= $item['data'][$i]; - } - } - } - - return $parity; - } - - /** - * checkModeNum - * - * @param int $size - * @param array $data - * - * @return bool - */ - protected function checkModeNum($size, $data) - { - for ($i = 0; $i < $size; ++$i) { - if ((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))) { - return false; - } - } - - return true; - } - - /** - * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19). - * - * @param int $c - * - * @return int - */ - protected function lookAnTable($c) - { - return (($c > 127) ? -1 : $this->anTable[$c]); - } - - /** - * checkModeAn - * - * @param int $size - * @param array $data - * - * @return bool - */ - protected function checkModeAn($size, $data) - { - for ($i = 0; $i < $size; ++$i) { - if ($this->lookAnTable(ord($data[$i])) == -1) { - return false; - } - } - - return true; - } - - /** - * estimateBitsModeNum - * - * @param int $size - * - * @return int - */ - protected function estimateBitsModeNum($size) - { - $w = (int) ($size / 3); - $bits = ($w * 10); - switch ($size - ($w * 3)) { - case 1: - { - $bits += 4; - break; - } - case 2: - { - $bits += 7; - break; - } - } - - return $bits; - } - - /** - * estimateBitsModeAn - * - * @param int $size - * - * @return int - */ - protected function estimateBitsModeAn($size) - { - $bits = (int) ($size * 5.5); // (size / 2 ) * 11 - if ($size & 1) { - $bits += 6; - } - - return $bits; - } - - /** - * estimateBitsMode8 - * - * @param int $size - * - * @return int - */ - protected function estimateBitsMode8($size) - { - return (int) ($size * 8); - } - - /** - * estimateBitsModeKanji - * - * @param int $size - * - * @return int - */ - protected function estimateBitsModeKanji($size) - { - return (int) ($size * 6.5); // (size / 2 ) * 13 - } - - /** - * checkModeKanji - * - * @param int $size - * @param array $data - * - * @return bool - */ - protected function checkModeKanji($size, $data) - { - if ($size & 1) { - return false; - } - for ($i = 0; $i < $size; $i += 2) { - $val = (ord($data[$i]) << 8) | ord($data[$i + 1]); - if (($val < 0x8140) || (($val > 0x9ffc) && ($val < 0xe040)) || ($val > 0xebbf)) { - return false; - } - } - - return true; - } - - /** - * Validate the input data. - * - * @param int $mode - * @param int $size - * @param array $data - * - * @return bool - */ - protected function check($mode, $size, $data) - { - if ($size <= 0) { - return false; - } - switch ($mode) { - case self::QR_MODE_NM: - { - return $this->checkModeNum($size, $data); - } - case self::QR_MODE_AN: - { - return $this->checkModeAn($size, $data); - } - case self::QR_MODE_KJ: - { - return $this->checkModeKanji($size, $data); - } - case self::QR_MODE_8B: - { - return true; - } - case self::QR_MODE_ST: - { - return true; - } - default: - { - break; - } - } - - return false; - } - - /** - * estimateBitStreamSize - * - * @param array $items - * @param int $version - * - * @return int - */ - protected function estimateBitStreamSize($items, $version) - { - $bits = 0; - if ($version == 0) { - $version = 1; - } - foreach ($items as $item) { - switch ($item['mode']) { - case self::QR_MODE_NM: - { - $bits = $this->estimateBitsModeNum($item['size']); - break; - } - case self::QR_MODE_AN: - { - $bits = $this->estimateBitsModeAn($item['size']); - break; - } - case self::QR_MODE_8B: - { - $bits = $this->estimateBitsMode8($item['size']); - break; - } - case self::QR_MODE_KJ: - { - $bits = $this->estimateBitsModeKanji($item['size']); - break; - } - case self::QR_MODE_ST: - { - return self::STRUCTURE_HEADER_BITS; - } - default: - { - return 0; - } - } - $l = $this->lengthIndicator($item['mode'], $version); - $m = 1 << $l; - $num = (int) (($item['size'] + $m - 1) / $m); - $bits += $num * (4 + $l); - } - - return $bits; - } - - /** - * estimateVersion - * - * @param array $items - * - * @return int - */ - protected function estimateVersion($items) - { - $version = 0; - - do { - $prev = $version; - $bits = $this->estimateBitStreamSize($items, $prev); - $version = $this->getMinimumVersion((int) (($bits + 7) / 8), $this->level); - if ($version < 0) { - return -1; - } - } while ($version > $prev); - - return $version; - } - - /** - * lengthOfCode - * - * @param int $mode - * @param int $version - * @param int $bits - * - * @return int - */ - protected function lengthOfCode($mode, $version, $bits) - { - $payload = $bits - 4 - $this->lengthIndicator($mode, $version); - switch ($mode) { - case self::QR_MODE_NM: - { - $chunks = (int) ($payload / 10); - $remain = $payload - $chunks * 10; - $size = $chunks * 3; - if ($remain >= 7) { - $size += 2; - } elseif ($remain >= 4) { - $size += 1; - } - break; - } - case self::QR_MODE_AN: - { - $chunks = (int) ($payload / 11); - $remain = $payload - $chunks * 11; - $size = $chunks * 2; - if ($remain >= 6) { - ++$size; - } - break; - } - case self::QR_MODE_8B: - { - $size = (int) ($payload / 8); - break; - } - case self::QR_MODE_KJ: - { - $size = (int) (($payload / 13) * 2); - break; - } - case self::QR_MODE_ST: - { - $size = (int) ($payload / 8); - break; - } - default: - { - $size = 0; - break; - } - } - $maxsize = $this->maximumWords($mode, $version); - if ($size < 0) { - $size = 0; - } - if ($size > $maxsize) { - $size = $maxsize; - } - - return $size; - } - - /** - * createBitStream - * - * @param array $items - * - * @return array - */ - protected function createBitStream($items) - { - $total = 0; - foreach ($items as $key => $item) { - $items[$key] = $this->encodeBitStream($item, $this->version); - $bits = count($items[$key]['bstream']); - $total += $bits; - } - - return array($items, $total); - } - - /** - * convertData - * - * @param array $items - * - * @return int - */ - protected function convertData($items) - { - $ver = $this->estimateVersion($items); - if ($ver > $this->version) { - $this->version = $ver; - } - for (;;) { - $cbs = $this->createBitStream($items); - $items = $cbs[0]; - $bits = $cbs[1]; - if ($bits < 0) { - return -1; - } - $ver = $this->getMinimumVersion((int) (($bits + 7) / 8), $this->level); - if ($ver < 0) { - return -1; - } elseif ($ver > $this->version) { - $this->version = $ver; - } else { - break; - } - } - - return $items; - } - - /** - * Append Padding Bit to bitstream - * - * @param array $bstream - * - * @return array|null - */ - protected function appendPaddingBit($bstream) - { - if (is_null($bstream)) { - return null; - } - $bits = count($bstream); - $maxwords = $this->getDataLength($this->version, $this->level); - $maxbits = $maxwords * 8; - if ($maxbits == $bits) { - return $bstream; - } - if ($maxbits - $bits < 5) { - return $this->appendNum($bstream, $maxbits - $bits, 0); - } - $bits += 4; - $words = (int) (($bits + 7) / 8); - $padding = array(); - $padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0); - $padlen = $maxwords - $words; - if ($padlen > 0) { - $padbuf = array(); - for ($i = 0; $i < $padlen; ++$i) { - $padbuf[$i] = ($i & 1) ? 0x11 : 0xec; - } - $padding = $this->appendBytes($padding, $padlen, $padbuf); - } - - return $this->appendBitstream($bstream, $padding); - } - - /** - * mergeBitStream - * - * @param array $items - * - * @return array|null - */ - protected function mergeBitStream($items) - { - $items = $this->convertData($items); - if (!is_array($items)) { - return null; - } - $bstream = array(); - foreach ($items as $item) { - $bstream = $this->appendBitstream($bstream, $item['bstream']); - } - - return $bstream; - } - - /** - * Returns a stream of bits - * - * @param array $items - * - * @return array|null - */ - protected function getBitStream($items) - { - $bstream = $this->mergeBitStream($items); - - return $this->appendPaddingBit($bstream); - } - - /** - * Pack all bit streams padding bits into a byte array. - * - * @param array $items - * - * @return array - */ - protected function getByteStream($items) - { - $bstream = $this->getBitStream($items); - - return $this->bitstreamToByte($bstream); - } - - /** - * Return an array with zeros - * - * @param int $setLength - * - * @return array - */ - protected function allocate($setLength) - { - return array_fill(0, $setLength, 0); - } - - /** - * Return new bitstream from number - * - * @param int $bits - * @param int $num - * - * @return array - */ - protected function newFromNum($bits, $num) - { - $bstream = $this->allocate($bits); - $mask = 1 << ($bits - 1); - for ($i = 0; $i < $bits; ++$i) { - if ($num & $mask) { - $bstream[$i] = 1; - } else { - $bstream[$i] = 0; - } - $mask = $mask >> 1; - } - - return $bstream; - } - - /** - * Return new bitstream from bytes - * - * @param int $size - * @param array $data - * - * @return array - */ - protected function newFromBytes($size, $data) - { - $bstream = $this->allocate($size * 8); - $p = 0; - for ($i = 0; $i < $size; ++$i) { - $mask = 0x80; - for ($j = 0; $j < 8; ++$j) { - if ($data[$i] & $mask) { - $bstream[$p] = 1; - } else { - $bstream[$p] = 0; - } - $p++; - $mask = $mask >> 1; - } - } - - return $bstream; - } - - /** - * Append one bitstream to another - * - * @param array $bitstream - * @param array $append - * - * @return array - */ - protected function appendBitstream($bitstream, $append) - { - if ((!is_array($append)) || (count($append) == 0)) { - return $bitstream; - } - if (count($bitstream) == 0) { - return $append; - } - - return array_values(array_merge($bitstream, $append)); - } - - /** - * Append one bitstream created from number to another - * - * @param array $bitstream - * @param int $bits - * @param int $num - * - * @return array|int - */ - protected function appendNum($bitstream, $bits, $num) - { - if ($bits == 0) { - return 0; - } - $b = $this->newFromNum($bits, $num); - - return $this->appendBitstream($bitstream, $b); - } - - /** - * Append one bitstream created from bytes to another - * - * @param array $bitstream - * @param int $size - * @param array $data - * - * @return array|int - */ - protected function appendBytes($bitstream, $size, $data) - { - if ($size == 0) { - return 0; - } - $b = $this->newFromBytes($size, $data); - - return $this->appendBitstream($bitstream, $b); - } - - /** - * Convert bitstream to bytes - * - * @param array $bstream - * - * @return array|null - */ - protected function bitstreamToByte($bstream) - { - if (is_null($bstream)) { - return null; - } - $size = count($bstream); - if ($size == 0) { - return array(); - } - $data = array_fill(0, (int) (($size + 7) / 8), 0); - $bytes = (int) ($size / 8); - $p = 0; - for ($i = 0; $i < $bytes; $i++) { - $v = 0; - for ($j = 0; $j < 8; $j++) { - $v = $v << 1; - $v |= $bstream[$p]; - $p++; - } - $data[$i] = $v; - } - if ($size & 7) { - $v = 0; - for ($j = 0; $j < ($size & 7); $j++) { - $v = $v << 1; - $v |= $bstream[$p]; - $p++; - } - $data[$bytes] = $v; - } - - return $data; - } - - - /** - * Replace a value on the array at the specified position - * - * @param array $srctab - * @param int $x - * @param int $y - * @param string $repl - * @param bool $replLen - * - * @return mixed - */ - protected function qrstrset($srctab, $x, $y, $repl, $replLen = false) - { - $srctab[$y] = substr_replace( - $srctab[$y], - ($replLen !== false) ? substr($repl, 0, $replLen) : $repl, - $x, - ($replLen !== false) ? $replLen : strlen($repl) - ); - - return $srctab; - } - - /** - * Return maximum data code length (bytes) for the version. - * - * @param int $version - * @param int $level - * - * @return mixed - */ - protected function getDataLength($version, $level) - { - return $this->capacity[$version][self::QRCAP_WORDS] - $this->capacity[$version][self::QRCAP_EC][$level]; - } - - /** - * Return maximum error correction code length (bytes) for the version. - * - * @param int $version - * @param int $level - * - * @return mixed - */ - protected function getECCLength($version, $level) - { - return $this->capacity[$version][self::QRCAP_EC][$level]; - } - - /** - * Return the width of the symbol for the version. - * - * @param int $version - * - * @return mixed - */ - protected function getWidth($version) - { - return $this->capacity[$version][self::QRCAP_WIDTH]; - } - - /** - * Return the number of remainder bits. - * - * @param int $version - * - * @return mixed - */ - protected function getRemainder($version) - { - return $this->capacity[$version][self::QRCAP_REMINDER]; - } - - /** - * Return a version number that satisfies the input code length. - * - * @param int $size - * @param int $level - * - * @return int - */ - protected function getMinimumVersion($size, $level) - { - for ($i = 1; $i <= self::QRSPEC_VERSION_MAX; ++$i) { - $words = $this->capacity[$i][self::QRCAP_WORDS] - $this->capacity[$i][self::QRCAP_EC][$level]; - if ($words >= $size) { - return $i; - } - } - - return -1; - } - - /** - * Return the size of length indicator for the mode and version. - * - * @param int $mode - * @param int $version - * - * @return int - */ - protected function lengthIndicator($mode, $version) - { - if ($mode == self::QR_MODE_ST) { - return 0; - } - if ($version <= 9) { - $l = 0; - } elseif ($version <= 26) { - $l = 1; - } else { - $l = 2; - } - - return $this->lengthTableBits[$mode][$l]; - } - - /** - * Return the maximum length for the mode and version. - * - * @param int $mode - * @param int $version - * - * @return int - */ - protected function maximumWords($mode, $version) - { - if ($mode == self::QR_MODE_ST) { - return 3; - } - if ($version <= 9) { - $l = 0; - } else { - if ($version <= 26) { - $l = 1; - } else { - $l = 2; - } - } - $bits = $this->lengthTableBits[$mode][$l]; - $words = (1 << $bits) - 1; - if ($mode == self::QR_MODE_KJ) { - $words *= 2; // the number of bytes is required - } - - return $words; - } - - /** - * Return an array of ECC specification. - * - * @param int $version - * @param int $level - * @param array $spec - * - * @return array - */ - protected function getEccSpec($version, $level, $spec) - { - if (count($spec) < 5) { - $spec = array(0, 0, 0, 0, 0); - } - $b1 = $this->eccTable[$version][$level][0]; - $b2 = $this->eccTable[$version][$level][1]; - $data = $this->getDataLength($version, $level); - $ecc = $this->getECCLength($version, $level); - if ($b2 == 0) { - $spec[0] = $b1; - $spec[1] = (int) ($data / $b1); - $spec[2] = (int) ($ecc / $b1); - $spec[3] = 0; - $spec[4] = 0; - } else { - $spec[0] = $b1; - $spec[1] = (int) ($data / ($b1 + $b2)); - $spec[2] = (int) ($ecc / ($b1 + $b2)); - $spec[3] = $b2; - $spec[4] = $spec[1] + 1; - } - - return $spec; - } - - /** - * Put an alignment marker. - * - * @param array $frame - * @param int $ox - * @param int $oy - * - * @return mixed - */ - protected function putAlignmentMarker($frame, $ox, $oy) - { - $finder = array( - "\xa1\xa1\xa1\xa1\xa1", - "\xa1\xa0\xa0\xa0\xa1", - "\xa1\xa0\xa1\xa0\xa1", - "\xa1\xa0\xa0\xa0\xa1", - "\xa1\xa1\xa1\xa1\xa1" - ); - $yStart = $oy - 2; - $xStart = $ox - 2; - for ($y = 0; $y < 5; $y++) { - $frame = $this->qrstrset($frame, $xStart, $yStart + $y, $finder[$y]); - } - - return $frame; - } - - /** - * Put an alignment pattern. - * - * @param int $version - * @param array $frame - * @param int $width - * - * @return mixed - */ - protected function putAlignmentPattern($version, $frame, $width) - { - if ($version < 2) { - return $frame; - } - $d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0]; - if ($d < 0) { - $w = 2; - } else { - $w = (int) (($width - $this->alignmentPattern[$version][0]) / $d + 2); - } - if ($w * $w - 3 == 1) { - $x = $this->alignmentPattern[$version][0]; - $y = $this->alignmentPattern[$version][0]; - $frame = $this->putAlignmentMarker($frame, $x, $y); - - return $frame; - } - $cx = $this->alignmentPattern[$version][0]; - $wo = $w - 1; - for ($x = 1; $x < $wo; ++$x) { - $frame = $this->putAlignmentMarker($frame, 6, $cx); - $frame = $this->putAlignmentMarker($frame, $cx, 6); - $cx += $d; - } - $cy = $this->alignmentPattern[$version][0]; - for ($y = 0; $y < $wo; ++$y) { - $cx = $this->alignmentPattern[$version][0]; - for ($x = 0; $x < $wo; ++$x) { - $frame = $this->putAlignmentMarker($frame, $cx, $cy); - $cx += $d; - } - $cy += $d; - } - - return $frame; - } - - /** - * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater. Use lower 18 bits. - * - * @param int $version - * - * @return int - */ - protected function getVersionPattern($version) - { - if (($version < 7) || ($version > self::QRSPEC_VERSION_MAX)) { - return 0; - } - - return $this->versionPattern[($version - 7)]; - } - - /** - * Return BCH encoded format information pattern. - * - * @param int $mask - * @param int $level - * - * @return int - */ - protected function getFormatInfo($mask, $level) - { - if (($mask < 0) || ($mask > 7)) { - return 0; - } - if (($level < 0) || ($level > 3)) { - return 0; - } - - return $this->formatInfo[$level][$mask]; - } - - /** - * Put a finder pattern. - * - * @param array $frame - * @param int $ox - * @param int $oy - * - * @return mixed - */ - protected function putFinderPattern($frame, $ox, $oy) - { - $finder = array( - "\xc1\xc1\xc1\xc1\xc1\xc1\xc1", - "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", - "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", - "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", - "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", - "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", - "\xc1\xc1\xc1\xc1\xc1\xc1\xc1" - ); - for ($y = 0; $y < 7; $y++) { - $frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]); - } - - return $frame; - } - - /** - * Return a copy of initialized frame. - * - * @param int $version - * - * @return array|mixed - */ - protected function createFrame($version) - { - $width = $this->capacity[$version][self::QRCAP_WIDTH]; - $frameLine = str_repeat("\0", $width); - $frame = array_fill(0, $width, $frameLine); - // Finder pattern - $frame = $this->putFinderPattern($frame, 0, 0); - $frame = $this->putFinderPattern($frame, $width - 7, 0); - $frame = $this->putFinderPattern($frame, 0, $width - 7); - // Separator - $yOffset = $width - 7; - for ($y = 0; $y < 7; ++$y) { - $frame[$y][7] = "\xc0"; - $frame[$y][$width - 8] = "\xc0"; - $frame[$yOffset][7] = "\xc0"; - ++$yOffset; - } - $setPattern = str_repeat("\xc0", 8); - $frame = $this->qrstrset($frame, 0, 7, $setPattern); - $frame = $this->qrstrset($frame, $width - 8, 7, $setPattern); - $frame = $this->qrstrset($frame, 0, $width - 8, $setPattern); - // Format info - $setPattern = str_repeat("\x84", 9); - $frame = $this->qrstrset($frame, 0, 8, $setPattern); - $frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8); - $yOffset = $width - 8; - for ($y = 0; $y < 8; ++$y, ++$yOffset) { - $frame[$y][8] = "\x84"; - $frame[$yOffset][8] = "\x84"; - } - // Timing pattern - $wo = $width - 15; - for ($i = 1; $i < $wo; ++$i) { - $frame[6][7 + $i] = chr(0x90 | ($i & 1)); - $frame[7 + $i][6] = chr(0x90 | ($i & 1)); - } - // Alignment pattern - $frame = $this->putAlignmentPattern($version, $frame, $width); - // Version information - if ($version >= 7) { - $vinf = $this->getVersionPattern($version); - $v = $vinf; - for ($x = 0; $x < 6; ++$x) { - for ($y = 0; $y < 3; ++$y) { - $frame[($width - 11) + $y][$x] = chr(0x88 | ($v & 1)); - $v = $v >> 1; - } - } - $v = $vinf; - for ($y = 0; $y < 6; ++$y) { - for ($x = 0; $x < 3; ++$x) { - $frame[$y][$x + ($width - 11)] = chr(0x88 | ($v & 1)); - $v = $v >> 1; - } - } - } - // and a little bit... - $frame[$width - 8][8] = "\x81"; - - return $frame; - } - - /** - * Set new frame for the specified version. - * - * @param int $version - * - * @return null - */ - protected function newFrame($version) - { - if (($version < 1) || ($version > self::QRSPEC_VERSION_MAX)) { - return null; - } - if (!isset($this->frames[$version])) { - $this->frames[$version] = $this->createFrame($version); - } - if (is_null($this->frames[$version])) { - return null; - } - - return $this->frames[$version]; - } - - /** - * Return block number 0 - * - * @param array $spec - * - * @return mixed - */ - protected function rsBlockNum($spec) - { - return ($spec[0] + $spec[3]); - } - - /** - * Return block number 1 - * - * @param array $spec - * - * @return mixed - */ - protected function rsBlockNum1($spec) - { - return $spec[0]; - } - - /** - * Return data codes 1 - * - * @param array $spec - * - * @return mixed - */ - protected function rsDataCodes1($spec) - { - return $spec[1]; - } - - /** - * Return ecc codes 1 - * - * @param array $spec - * - * @return mixed - */ - protected function rsEccCodes1($spec) - { - return $spec[2]; - } - - /** - * Return block number 2 - * - * @param array $spec - * - * @return mixed - */ - protected function rsBlockNum2($spec) - { - return $spec[3]; - } - - /** - * Return data codes 2 - * - * @param array $spec - * - * @return mixed - */ - protected function rsDataCodes2($spec) - { - return $spec[4]; - } - - /** - * Return ecc codes 2 - * - * @param array $spec - * - * @return mixed - */ - protected function rsEccCodes2($spec) - { - return $spec[2]; - } - - /** - * Return data length - * - * @param array $spec - * - * @return mixed - */ - protected function rsDataLength($spec) - { - return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]); - } - - /** - * Return ecc length - * - * @param array $spec - * - * @return mixed - */ - protected function rsEccLength($spec) - { - return ($spec[0] + $spec[3]) * $spec[2]; - } - - /** - * Initialize a Reed-Solomon codec and add it to existing rsitems - * - * @param int $symsize - * @param int $gfpoly - * @param int $fcr - * @param int $prim - * @param int $nroots - * @param int $pad - * - * @return array - */ - protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) - { - foreach ($this->rsitems as $rs) { - if (($rs['pad'] != $pad) || ($rs['nroots'] != $nroots) || ($rs['mm'] != $symsize) - || ($rs['gfpoly'] != $gfpoly) || ($rs['fcr'] != $fcr) || ($rs['prim'] != $prim) - ) { - continue; - } - - return $rs; - } - $rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad); - array_unshift($this->rsitems, $rs); - - return $rs; - } - - /** - * modnn - * - * @param array $rs - * @param int $x - * - * @return int - */ - protected function modnn($rs, $x) - { - while ($x >= $rs['nn']) { - $x -= $rs['nn']; - $x = ($x >> $rs['mm']) + ($x & $rs['nn']); - } - - return $x; - } - - /** - * Initialize a Reed-Solomon codec and returns an array of values. - * - * @param int $symsize - * @param int $gfpoly - * @param int $fcr - * @param int $prim - * @param int $nroots - * @param int $pad - * - * @return array|null - */ - protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) - { - // Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2) - $rs = null; - // Check parameter ranges - if (($symsize < 0) || ($symsize > 8)) { - return $rs; - } - if (($fcr < 0) || ($fcr >= (1 << $symsize))) { - return $rs; - } - if (($prim <= 0) || ($prim >= (1 << $symsize))) { - return $rs; - } - if (($nroots < 0) || ($nroots >= (1 << $symsize))) { - return $rs; - } - if (($pad < 0) || ($pad >= ((1 << $symsize) - 1 - $nroots))) { - return $rs; - } - $rs = array(); - $rs['mm'] = $symsize; - $rs['nn'] = (1 << $symsize) - 1; - $rs['pad'] = $pad; - $rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0); - $rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0); - // PHP style macro replacement ;) - $nn =& $rs['nn']; - $a0 =& $nn; - // Generate Galois field lookup tables - $rs['index_of'][0] = $a0; // log(zero) = -inf - $rs['alpha_to'][$a0] = 0; // alpha**-inf = 0 - $sr = 1; - for ($i = 0; $i < $rs['nn']; ++$i) { - $rs['index_of'][$sr] = $i; - $rs['alpha_to'][$i] = $sr; - $sr <<= 1; - if ($sr & (1 << $symsize)) { - $sr ^= $gfpoly; - } - $sr &= $rs['nn']; - } - if ($sr != 1) { - // field generator polynomial is not primitive! - return null; - } - // Form RS code generator polynomial from its roots - $rs['genpoly'] = array_fill(0, ($nroots + 1), 0); - $rs['fcr'] = $fcr; - $rs['prim'] = $prim; - $rs['nroots'] = $nroots; - $rs['gfpoly'] = $gfpoly; - // Find prim-th root of 1, used in decoding - for ($iprim = 1; ($iprim % $prim) != 0; $iprim += $rs['nn']) { - ; // intentional empty-body loop! - } - $rs['iprim'] = (int) ($iprim / $prim); - $rs['genpoly'][0] = 1; - for ($i = 0, $root = $fcr * $prim; $i < $nroots; $i++, $root += $prim) { - $rs['genpoly'][$i + 1] = 1; - // Multiply rs->genpoly[] by @**(root + x) - for ($j = $i; $j > 0; --$j) { - if ($rs['genpoly'][$j] != 0) { - $rs['genpoly'][$j] = $rs['genpoly'][$j - 1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)]; - } else { - $rs['genpoly'][$j] = $rs['genpoly'][$j - 1]; - } - } - // rs->genpoly[0] can never be zero - $rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)]; - } - // convert rs->genpoly[] to index form for quicker encoding - for ($i = 0; $i <= $nroots; ++$i) { - $rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]]; - } - - return $rs; - } - - /** - * Encode a Reed-Solomon codec and returns the parity array - * - * @param array $rs - * @param array $data - * @param array $parity - * - * @return array - */ - protected function encode_rs_char($rs, $data, $parity) - { - $nn =& $rs['nn']; // the total number of symbols in a RS block - $alphaTo =& $rs['alpha_to']; // the address of an array of NN elements to convert Galois field elements in index (log) form to polynomial form - $indexOf =& $rs['index_of']; // the address of an array of NN elements to convert Galois field elements in polynomial form to index (log) form - $genPoly =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form - $nRoots =& $rs['nroots']; // the number of roots in the RS code generator polynomial, which is the same as the number of parity symbols in a block - $pad =& $rs['pad']; // the number of pad symbols in a block - $a0 =& $nn; - $parity = (empty($parity)||$parity==null)?array_fill(0, $nRoots, 0):$parity; - for ($i = 0; $i < ($nn - $nRoots - $pad); $i++) { - $feedback = $indexOf[$data[$i] ^ $parity[0]]; - if ($feedback != $a0) { - // feedback term is non-zero - // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must - // always be for the polynomials constructed by init_rs() - $feedback = $this->modnn($rs, $nn - $genPoly[$nRoots] + $feedback); - for ($j = 1; $j < $nRoots; ++$j) { - $parity[$j] ^= $alphaTo[$this->modnn($rs, $feedback + $genPoly[($nRoots - $j)])]; - } - } - // Shift - array_shift($parity); - if ($feedback != $a0) { - array_push($parity, $alphaTo[$this->modnn($rs, $feedback + $genPoly[0])]); - } else { - array_push($parity, 0); - } - } - - return $parity; - } - + const + + QRCODEDEFS = true, // Indicate that definitions for this class are set + QR_MODE_NL = -1, // Encoding modes (characters which can be encoded in QRcode) + QR_MODE_NM = 0, // Encoding mode numeric (0-9). 3 characters are encoded to 10bit length. In theory, 7089 characters or less can be stored in a QRcode. + QR_MODE_AN = 1, // Encoding mode alphanumeric (0-9A-Z $%*+-./:) 45characters. 2 characters are encoded to 11bit length. In theory, 4296 characters or less can be stored in a QRcode. + QR_MODE_8B = 2, // Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode. + QR_MODE_KJ = 3, // Encoding mode KANJI. A KANJI character (multibyte character) is encoded to 13bit length. In theory, 1817 characters or less can be stored in a QRcode. + QR_MODE_ST = 4, // Encoding mode STRUCTURED (currently unsupported) + QR_ECLEVEL_L = 0, // Error correction level L : About 7% or less errors can be corrected. + QR_ECLEVEL_M = 1, // Error correction level M : About 15% or less errors can be corrected. + QR_ECLEVEL_Q = 2, // Error correction level Q : About 25% or less errors can be corrected. + QR_ECLEVEL_H = 3, // Error correction level H : About 30% or less errors can be corrected. + + // Version. Size of QRcode is defined as version. Version is from 1 to 40. + // Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. + // So version 40 is 177*177 matrix. + + QRSPEC_VERSION_MAX = 40, // Maximum QR Code version. + QRSPEC_WIDTH_MAX = 177, // Maximum matrix size for maximum version (version 40 is 177*177 matrix). + QRCAP_WIDTH = 0, // Matrix index to get width from $capacity array. + QRCAP_WORDS = 1, // Matrix index to get number of words from $capacity array. + QRCAP_REMINDER = 2, // Matrix index to get remainder from $capacity array. + QRCAP_EC = 3, // Matrix index to get error correction level from $capacity array. + STRUCTURE_HEADER_BITS = 20, // Number of header bits for structured mode + MAX_STRUCTURED_SYMBOLS = 16, // Max number of symbols for structured mode + N1 = 3, // Down point base value for case 1 mask pattern (concatenation of same color in a line or a column) + N2 = 3, // Down point base value for case 2 mask pattern (module block of same color) + N3 = 40, // Down point base value for case 3 mask pattern (1:1:3:1:1(dark:bright:dark:bright:dark)pattern in a line or a column) + N4 = 10, // Down point base value for case 4 mask pattern (ration of dark modules in whole) + QR_FIND_BEST_MASK = true, // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code + QR_FIND_FROM_RANDOM = 2, // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly + QR_DEFAULT_MASK = 2; // when QR_FIND_BEST_MASK === false + + /** + * Barcode array to be returned which is readable by Dinesh Rabara. + * @protected + */ + protected $barcodeArray = array(); + + /** + * QR code version. Size of QRcode is defined as version. Version is from 1 to 40. Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. So version 40 is 177*177 matrix. + * @protected + */ + protected $version = 0; + + /** + * Levels of error correction. See definitions for possible values. + * @protected + */ + protected $level = self::QR_ECLEVEL_L; + + /** + * Encoding mode. + * @protected + */ + protected $hint = self::QR_MODE_8B; + + /** + * Boolean flag, if true the input string will be converted to uppercase. + * @protected + */ + protected $casesensitive = true; + + /** + * Structured QR code (not supported yet). + * @protected + */ + protected $structured = 0; + + /** + * Mask data. + * @protected + */ + protected $data; + + // FrameFiller + + /** + * Width. + * @protected + */ + protected $width; + + /** + * Frame. + * @protected + */ + protected $frame; + + /** + * X position of bit. + * @protected + */ + protected $x; + + /** + * Y position of bit. + * @protected + */ + protected $y; + + /** + * Direction. + * @protected + */ + protected $dir; + + /** + * Single bit value. + * @protected + */ + protected $bit; + + // ---- QRrawcode ---- + + /** + * Data code. + * @protected + */ + protected $datacode = array(); + + /** + * Error correction code. + * @protected + */ + protected $ecccode = array(); + + /** + * Blocks. + * @protected + */ + protected $blocks; + + /** + * Reed-Solomon blocks. + * @protected + */ + protected $rsblocks = array(); //of RSblock + + /** + * Counter. + * @protected + */ + protected $count; + + /** + * Data length. + * @protected + */ + protected $dataLength; + + /** + * Error correction length. + * @protected + */ + protected $eccLength; + + /** + * Value b1. + * @protected + */ + protected $b1; + + // ---- QRmask ---- + + /** + * Run length. + * @protected + */ + protected $runLength = array(); + + // ---- QRsplit ---- + + /** + * Input data string. + * @protected + */ + protected $dataStr = ''; + + /** + * Input items. + * @protected + */ + protected $items; + + // Reed-Solomon items + + /** + * Reed-Solomon items. + * @protected + */ + protected $rsitems = array(); + + /** + * Array of frames. + * @protected + */ + protected $frames = array(); + + /** + * Alphabet-numeric convesion table. + * @protected + */ + protected $anTable = array( + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, // + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, // + 36, + -1, + -1, + -1, + 37, + 38, + -1, + -1, + -1, + -1, + 39, + 40, + -1, + 41, + 42, + 43, // + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 44, + -1, + -1, + -1, + -1, + -1, // + -1, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, // + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + -1, + -1, + -1, + -1, + -1, // + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, // + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 // + ); + + /** + * Array Table of the capacity of symbols. + * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004. + * @protected + */ + protected $capacity = array( + array(0, 0, 0, array(0, 0, 0, 0)), // + array(21, 26, 0, array(7, 10, 13, 17)), // 1 + array(25, 44, 7, array(10, 16, 22, 28)), // + array(29, 70, 7, array(15, 26, 36, 44)), // + array(33, 100, 7, array(20, 36, 52, 64)), // + array(37, 134, 7, array(26, 48, 72, 88)), // 5 + array(41, 172, 7, array(36, 64, 96, 112)), // + array(45, 196, 0, array(40, 72, 108, 130)), // + array(49, 242, 0, array(48, 88, 132, 156)), // + array(53, 292, 0, array(60, 110, 160, 192)), // + array(57, 346, 0, array(72, 130, 192, 224)), // 10 + array(61, 404, 0, array(80, 150, 224, 264)), // + array(65, 466, 0, array(96, 176, 260, 308)), // + array(69, 532, 0, array(104, 198, 288, 352)), // + array(73, 581, 3, array(120, 216, 320, 384)), // + array(77, 655, 3, array(132, 240, 360, 432)), // 15 + array(81, 733, 3, array(144, 280, 408, 480)), // + array(85, 815, 3, array(168, 308, 448, 532)), // + array(89, 901, 3, array(180, 338, 504, 588)), // + array(93, 991, 3, array(196, 364, 546, 650)), // + array(97, 1085, 3, array(224, 416, 600, 700)), // 20 + array(101, 1156, 4, array(224, 442, 644, 750)), // + array(105, 1258, 4, array(252, 476, 690, 816)), // + array(109, 1364, 4, array(270, 504, 750, 900)), // + array(113, 1474, 4, array(300, 560, 810, 960)), // + array(117, 1588, 4, array(312, 588, 870, 1050)), // 25 + array(121, 1706, 4, array(336, 644, 952, 1110)), // + array(125, 1828, 4, array(360, 700, 1020, 1200)), // + array(129, 1921, 3, array(390, 728, 1050, 1260)), // + array(133, 2051, 3, array(420, 784, 1140, 1350)), // + array(137, 2185, 3, array(450, 812, 1200, 1440)), // 30 + array(141, 2323, 3, array(480, 868, 1290, 1530)), // + array(145, 2465, 3, array(510, 924, 1350, 1620)), // + array(149, 2611, 3, array(540, 980, 1440, 1710)), // + array(153, 2761, 3, array(570, 1036, 1530, 1800)), // + array(157, 2876, 0, array(570, 1064, 1590, 1890)), // 35 + array(161, 3034, 0, array(600, 1120, 1680, 1980)), // + array(165, 3196, 0, array(630, 1204, 1770, 2100)), // + array(169, 3362, 0, array(660, 1260, 1860, 2220)), // + array(173, 3532, 0, array(720, 1316, 1950, 2310)), // + array(177, 3706, 0, array(750, 1372, 2040, 2430)) // 40 + ); + + /** + * Array Length indicator. + * @protected + */ + protected $lengthTableBits = array( + array(10, 12, 14), + array(9, 11, 13), + array(8, 16, 16), + array(8, 10, 12) + ); + + /** + * Array Table of the error correction code (Reed-Solomon block). + * See Table 12-16 (pp.30-36), JIS X0510:2004. + * @protected + */ + protected $eccTable = array( + array(array(0, 0), array(0, 0), array(0, 0), array(0, 0)), // + array(array(1, 0), array(1, 0), array(1, 0), array(1, 0)), // 1 + array(array(1, 0), array(1, 0), array(1, 0), array(1, 0)), // + array(array(1, 0), array(1, 0), array(2, 0), array(2, 0)), // + array(array(1, 0), array(2, 0), array(2, 0), array(4, 0)), // + array(array(1, 0), array(2, 0), array(2, 2), array(2, 2)), // 5 + array(array(2, 0), array(4, 0), array(4, 0), array(4, 0)), // + array(array(2, 0), array(4, 0), array(2, 4), array(4, 1)), // + array(array(2, 0), array(2, 2), array(4, 2), array(4, 2)), // + array(array(2, 0), array(3, 2), array(4, 4), array(4, 4)), // + array(array(2, 2), array(4, 1), array(6, 2), array(6, 2)), // 10 + array(array(4, 0), array(1, 4), array(4, 4), array(3, 8)), // + array(array(2, 2), array(6, 2), array(4, 6), array(7, 4)), // + array(array(4, 0), array(8, 1), array(8, 4), array(12, 4)), // + array(array(3, 1), array(4, 5), array(11, 5), array(11, 5)), // + array(array(5, 1), array(5, 5), array(5, 7), array(11, 7)), // 15 + array(array(5, 1), array(7, 3), array(15, 2), array(3, 13)), // + array(array(1, 5), array(10, 1), array(1, 15), array(2, 17)), // + array(array(5, 1), array(9, 4), array(17, 1), array(2, 19)), // + array(array(3, 4), array(3, 11), array(17, 4), array(9, 16)), // + array(array(3, 5), array(3, 13), array(15, 5), array(15, 10)), // 20 + array(array(4, 4), array(17, 0), array(17, 6), array(19, 6)), // + array(array(2, 7), array(17, 0), array(7, 16), array(34, 0)), // + array(array(4, 5), array(4, 14), array(11, 14), array(16, 14)), // + array(array(6, 4), array(6, 14), array(11, 16), array(30, 2)), // + array(array(8, 4), array(8, 13), array(7, 22), array(22, 13)), // 25 + array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), // + array(array(8, 4), array(22, 3), array(8, 26), array(12, 28)), // + array(array(3, 10), array(3, 23), array(4, 31), array(11, 31)), // + array(array(7, 7), array(21, 7), array(1, 37), array(19, 26)), // + array(array(5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30 + array(array(13, 3), array(2, 29), array(42, 1), array(23, 28)), // + array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), // + array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), // + array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), // + array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), // 35 + array(array(6, 14), array(6, 34), array(46, 10), array(2, 64)), // + array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), // + array(array(4, 18), array(13, 32), array(48, 14), array(42, 32)), // + array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), // + array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)) // 40 + ); + + /** + * Array Positions of alignment patterns. + * This array includes only the second and the third position of the alignment patterns. Rest of them can be calculated from the distance between them. + * See Table 1 in Appendix E (pp.71) of JIS X0510:2004. + * @protected + */ + protected $alignmentPattern = array( + array(0, 0), + array(0, 0), + array(18, 0), + array(22, 0), + array(26, 0), + array(30, 0), // 1- 5 + array(34, 0), + array(22, 38), + array(24, 42), + array(26, 46), + array(28, 50), // 6-10 + array(30, 54), + array(32, 58), + array(34, 62), + array(26, 46), + array(26, 48), // 11-15 + array(26, 50), + array(30, 54), + array(30, 56), + array(30, 58), + array(34, 62), // 16-20 + array(28, 50), + array(26, 50), + array(30, 54), + array(28, 54), + array(32, 58), // 21-25 + array(30, 58), + array(34, 62), + array(26, 50), + array(30, 54), + array(26, 52), // 26-30 + array(30, 56), + array(34, 60), + array(30, 58), + array(34, 62), + array(30, 54), // 31-35 + array(24, 50), + array(28, 54), + array(32, 58), + array(26, 54), + array(30, 58) // 35-40 + ); + + /** + * Array Version information pattern (BCH coded). + * See Table 1 in Appendix D (pp.68) of JIS X0510:2004. + * size: [QRSPEC_VERSION_MAX - 6] + * @protected + */ + protected $versionPattern = array( + 0x07c94, + 0x085bc, + 0x09a99, + 0x0a4d3, + 0x0bbf6, + 0x0c762, + 0x0d847, + 0x0e60d, // + 0x0f928, + 0x10b78, + 0x1145d, + 0x12a17, + 0x13532, + 0x149a6, + 0x15683, + 0x168c9, // + 0x177ec, + 0x18ec4, + 0x191e1, + 0x1afab, + 0x1b08e, + 0x1cc1a, + 0x1d33f, + 0x1ed75, // + 0x1f250, + 0x209d5, + 0x216f0, + 0x228ba, + 0x2379f, + 0x24b0b, + 0x2542e, + 0x26a64, // + 0x27541, + 0x28c69 + ); + + /** + * Array Format information + * @protected + */ + protected $formatInfo = array( + array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), // + array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), // + array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), // + array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) // + ); + + + /** + * This is the class constructor - creates a QRcode object + * + * @param string $code + * @param string $eclevel + */ + public function __construct($code, $eclevel = 'L') + { + $barcodeArray = array(); + if ((is_null($code)) || ($code == '\0') || ($code == '')) { + return false; + } + // set error correction level + $this->level = array_search($eclevel, array('L', 'M', 'Q', 'H')); + if ($this->level === false) { + $this->level = self::QR_ECLEVEL_L; + } + if (($this->hint != self::QR_MODE_8B) && ($this->hint != self::QR_MODE_KJ)) { + return false; + } + if (($this->version < 0) || ($this->version > self::QRSPEC_VERSION_MAX)) { + return false; + } + $this->items = array(); + $this->encodeString($code); + if (is_null($this->data)) { + return false; + } + $qrTab = $this->binarize($this->data); + $size = count($qrTab); + $barcodeArray['num_rows'] = $size; + $barcodeArray['num_cols'] = $size; + $barcodeArray['bcode'] = array(); + foreach ($qrTab as $line) { + $arrAdd = array(); + foreach (str_split($line) as $char) { + $arrAdd[] = ($char == '1') ? 1 : 0; + } + $barcodeArray['bcode'][] = $arrAdd; + } + $this->barcodeArray = $barcodeArray; + + return false; + } + + /** + * Returns a barcode array which is readable by Dinesh Rabara + * @return array barcode array readable by Dinesh Rabara; + * @public + */ + public function getBarcodeArray() + { + return $this->barcodeArray; + } + + /** + * Convert the frame in binary form + * + * @param array $frame + * + * @return mixed + */ + protected function binarize($frame) + { + $len = count($frame); + // the frame is square (width = height) + foreach ($frame as &$frameLine) { + for ($i = 0; $i < $len; $i++) { + $frameLine[$i] = (ord($frameLine[$i]) & 1) ? '1' : '0'; + } + } + + return $frame; + } + + /** + * Encode the input string to QR code + * + * @param string $string + * + * @return null + */ + protected function encodeString($string) + { + $this->dataStr = $string; + if (!$this->casesensitive) { + $this->toUpper(); + } + $ret = $this->splitString(); + if ($ret < 0) { + + return null; + } + $this->encodeMask(-1); + } + + /** + * @param int $mask + * + * @return null + */ + protected function encodeMask($mask) + { + $spec = array(0, 0, 0, 0, 0); + $this->datacode = $this->getByteStream($this->items); + if (is_null($this->datacode)) { + return null; + } + $spec = $this->getEccSpec($this->version, $this->level, $spec); + $this->b1 = $this->rsBlockNum1($spec); + $this->dataLength = $this->rsDataLength($spec); + $this->eccLength = $this->rsEccLength($spec); + $this->ecccode = array_fill(0, $this->eccLength, 0); + $this->blocks = $this->rsBlockNum($spec); + $ret = $this->init($spec); + if ($ret < 0) { + return null; + } + $this->count = 0; + $this->width = $this->getWidth($this->version); + $this->frame = $this->newFrame($this->version); + $this->x = $this->width - 1; + $this->y = $this->width - 1; + $this->dir = -1; + $this->bit = -1; + // inteleaved data and ecc codes + for ($i = 0; $i < ($this->dataLength + $this->eccLength); $i++) { + $code = $this->getCode(); + $bit = 0x80; + for ($j = 0; $j < 8; $j++) { + $addr = $this->getNextPosition(); + $this->setFrameAt($addr, 0x02 | (($bit & $code) != 0)); + $bit = $bit >> 1; + } + } + // remainder bits + $j = $this->getRemainder($this->version); + for ($i = 0; $i < $j; $i++) { + $addr = $this->getNextPosition(); + $this->setFrameAt($addr, 0x02); + } + // masking + $this->runLength = array_fill(0, self::QRSPEC_WIDTH_MAX + 1, 0); + if ($mask < 0) { + if (self::QR_FIND_BEST_MASK) { + $masked = $this->mask($this->width, $this->frame, $this->level); + } else { + $masked = $this->makeMask($this->width, $this->frame, (intval(self::QR_DEFAULT_MASK) % 8), $this->level); + } + } else { + $masked = $this->makeMask($this->width, $this->frame, $mask, $this->level); + } + if ($masked == null) { + return null; + } + $this->data = $masked; + } + + + /** + * Set frame value at specified position + * + * @param array $at + * @param int $val + */ + protected function setFrameAt($at, $val) + { + $this->frame[$at['y']][$at['x']] = chr($val); + } + + /** + * Get frame value at specified position + * + * @param array $at + * + * @return int + */ + protected function getFrameAt($at) + { + return ord($this->frame[$at['y']][$at['x']]); + } + + /** + * Return the next frame position + * + * @return array|null + */ + protected function getNextPosition() + { + do { + if ($this->bit == -1) { + $this->bit = 0; + + return array('x' => $this->x, 'y' => $this->y); + } + $x = $this->x; + $y = $this->y; + $w = $this->width; + if ($this->bit == 0) { + $x--; + $this->bit++; + } else { + $x++; + $y += $this->dir; + $this->bit--; + } + if ($this->dir < 0) { + if ($y < 0) { + $y = 0; + $x -= 2; + $this->dir = 1; + if ($x == 6) { + $x--; + $y = 9; + } + } + } else { + if ($y == $w) { + $y = $w - 1; + $x -= 2; + $this->dir = -1; + if ($x == 6) { + $x--; + $y -= 8; + } + } + } + if (($x < 0) || ($y < 0)) { + return null; + } + $this->x = $x; + $this->y = $y; + } while (ord($this->frame[$y][$x]) & 0x80); + + return array('x' => $x, 'y' => $y); + } + + /** + * Initialize code + * + * @param array $spec + * + * @return int + */ + protected function init($spec) + { + $dl = $this->rsDataCodes1($spec); + $el = $this->rsEccCodes1($spec); + $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); + $blockNo = 0; + $dataPos = 0; + $eccPos = 0; + $endfor = $this->rsBlockNum1($spec); + for ($i = 0; $i < $endfor; ++$i) { + $ecc = array_slice($this->ecccode, $eccPos); + $this->rsblocks[$blockNo] = array(); + $this->rsblocks[$blockNo]['dataLength'] = $dl; + $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos); + $this->rsblocks[$blockNo]['eccLength'] = $el; + $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc); + $this->rsblocks[$blockNo]['ecc'] = $ecc; + $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc); + $dataPos += $dl; + $eccPos += $el; + $blockNo++; + } + if ($this->rsBlockNum2($spec) == 0) { + return 0; + } + $dl = $this->rsDataCodes2($spec); + $el = $this->rsEccCodes2($spec); + $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el); + if ($rs == null) { + return -1; + } + $endfor = $this->rsBlockNum2($spec); + for ($i = 0; $i < $endfor; ++$i) { + $ecc = array_slice($this->ecccode, $eccPos); + $this->rsblocks[$blockNo] = array(); + $this->rsblocks[$blockNo]['dataLength'] = $dl; + $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos); + $this->rsblocks[$blockNo]['eccLength'] = $el; + $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc); + $this->rsblocks[$blockNo]['ecc'] = $ecc; + $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc); + $dataPos += $dl; + $eccPos += $el; + $blockNo++; + } + + return 0; + } + + /** + * Return Reed-Solomon block code. + * + * @return int + */ + protected function getCode() + { + if ($this->count < $this->dataLength) { + $row = (int) ($this->count % $this->blocks); + $col = (int) ($this->count / $this->blocks); + if ($col >= $this->rsblocks[0]['dataLength']) { + $row += $this->b1; + } + $ret = $this->rsblocks[$row]['data'][$col]; + } elseif ($this->count < $this->dataLength + $this->eccLength) { + $row = (int) (($this->count - $this->dataLength) % $this->blocks); + $col = (int) (($this->count - $this->dataLength) / $this->blocks); + $ret = $this->rsblocks[$row]['ecc'][$col]; + } else { + return 0; + } + $this->count++; + + return $ret; + } + + + /** + * Write Format Information on frame and returns the number of black bits + * + * @param int $width + * @param array &$frame + * @param int $mask + * @param int $level + * + * @return int + */ + protected function writeFormatInformation($width, &$frame, $mask, $level) + { + $blacks = 0; + $format = $this->getFormatInfo($mask, $level); + for ($i = 0; $i < 8; ++$i) { + if ($format & 1) { + $blacks += 2; + $v = 0x85; + } else { + $v = 0x84; + } + $frame[8][$width - 1 - $i] = chr($v); + if ($i < 6) { + $frame[$i][8] = chr($v); + } else { + $frame[$i + 1][8] = chr($v); + } + $format = $format >> 1; + } + for ($i = 0; $i < 7; ++$i) { + if ($format & 1) { + $blacks += 2; + $v = 0x85; + } else { + $v = 0x84; + } + $frame[$width - 7 + $i][8] = chr($v); + if ($i == 0) { + $frame[8][7] = chr($v); + } else { + $frame[8][6 - $i] = chr($v); + } + $format = $format >> 1; + } + + return $blacks; + } + + /** + * mask0 + * + * @param int $x + * @param int $y + * + * @return int + */ + protected function mask0($x, $y) + { + return ($x + $y) & 1; + } + + /** + * mask1 + * + * @param int $y + * + * @return int + */ + protected function mask1($y) + { + return ($y & 1); + } + + /** + * mask 2 + * + * @param int $x + * + * @return int + */ + protected function mask2($x) + { + return ($x % 3); + } + + /** + * mask3 + * + * @param int $x + * @param int $y + * + * @return int + */ + protected function mask3($x, $y) + { + return ($x + $y) % 3; + } + + /** + * mask4 + * + * @param int $x + * @param int $y + * + * @return int + */ + protected function mask4($x, $y) + { + return (((int) ($y / 2)) + ((int) ($x / 3))) & 1; + } + + /** + * mask5 + * + * @param int $x + * @param int $y + * + * @return int + */ + protected function mask5($x, $y) + { + return (($x * $y) & 1) + ($x * $y) % 3; + } + + /** + * mask6 + * + * @param int $x + * @param int $y + * + * @return int + */ + protected function mask6($x, $y) + { + return ((($x * $y) & 1) + ($x * $y) % 3) & 1; + } + + /** + * mask7 + * + * @param int $x + * @param int $y + * + * @return int + */ + protected function mask7($x, $y) + { + return ((($x * $y) % 3) + (($x + $y) & 1)) & 1; + } + + /** + * Return bitmask + * + * @param int $maskNo + * @param int $width + * @param array $frame + * + * @return array + */ + protected function generateMaskNo($maskNo, $width, $frame) + { + $bitMask = array_fill(0, $width, array_fill(0, $width, 0)); + for ($y = 0; $y < $width; ++$y) { + for ($x = 0; $x < $width; ++$x) { + if (ord($frame[$y][$x]) & 0x80) { + $bitMask[$y][$x] = 0; + } else { + $maskFunc = call_user_func(array($this, 'mask' . $maskNo), $x, $y); + $bitMask[$y][$x] = ($maskFunc == 0) ? 1 : 0; + } + } + } + + return $bitMask; + } + + /** + * makeMaskNo + * + * @param int $maskNo + * @param int $width + * @param array $s + * @param array &$d + * @param bool $maskGenOnly + * + * @return int + */ + protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) + { + $b = 0; + $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d); + if ($maskGenOnly) { + + return null; + } + $d = $s; + for ($y = 0; $y < $width; ++$y) { + for ($x = 0; $x < $width; ++$x) { + if ($bitMask[$y][$x] == 1) { + $d[$y][$x] = chr(ord($s[$y][$x]) ^ ((int) ($bitMask[$y][$x]))); + } + $b += (int) (ord($d[$y][$x]) & 1); + } + } + + return $b; + } + + /** + * makeMask + * + * @param int $width + * @param array $frame + * @param int $maskNo + * @param int $level + * + * @return array + */ + protected function makeMask($width, $frame, $maskNo, $level) + { + $masked = array_fill(0, $width, str_repeat("\0", $width)); + $this->makeMaskNo($maskNo, $width, $frame, $masked); + $this->writeFormatInformation($width, $masked, $maskNo, $level); + + return $masked; + } + + /** + * calcN1N3 + * + * @param int $length + * + * @return int + */ + protected function calcN1N3($length) + { + $demerit = 0; + for ($i = 0; $i < $length; ++$i) { + if ($this->runLength[$i] >= 5) { + $demerit += (self::N1 + ($this->runLength[$i] - 5)); + } + if ($i & 1) { + if (($i >= 3) && ($i < ($length - 2)) && ($this->runLength[$i] % 3 == 0)) { + $fact = (int) ($this->runLength[$i] / 3); + if (($this->runLength[$i - 2] == $fact) + && ($this->runLength[$i - 1] == $fact) + && ($this->runLength[$i + 1] == $fact) + && ($this->runLength[$i + 2] == $fact) + ) { + if (($this->runLength[$i - 3] < 0) || ($this->runLength[$i - 3] >= (4 * $fact))) { + $demerit += self::N3; + } elseif ((($i + 3) >= $length) || ($this->runLength[$i + 3] >= (4 * $fact))) { + $demerit += self::N3; + } + } + } + } + } + + return $demerit; + } + + /** + * evaluateSymbol + * + * @param int $width + * @param array $frame + * + * @return int + */ + protected function evaluateSymbol($width, $frame) + { + $demerit = 0; + $frameYM = array(); + + for ($y = 0; $y < $width; ++$y) { + $head = 0; + $this->runLength[0] = 1; + $frameY = $frame[$y]; + if ($y > 0) { + $frameYM = $frame[$y - 1]; + } + for ($x = 0; $x < $width; ++$x) { + if (($x > 0) && ($y > 0)) { + $b22 = ord($frameY[$x]) & ord($frameY[$x - 1]) & ord($frameYM[$x]) & ord($frameYM[$x - 1]); + $w22 = ord($frameY[$x]) | ord($frameY[$x - 1]) | ord($frameYM[$x]) | ord($frameYM[$x - 1]); + if (($b22 | ($w22 ^ 1)) & 1) { + $demerit += self::N2; + } + } + if (($x == 0) && (ord($frameY[$x]) & 1)) { + $this->runLength[0] = -1; + $head = 1; + $this->runLength[$head] = 1; + } elseif ($x > 0) { + if ((ord($frameY[$x]) ^ ord($frameY[$x - 1])) & 1) { + $head++; + $this->runLength[$head] = 1; + } else { + $this->runLength[$head]++; + } + } + } + $demerit += $this->calcN1N3($head + 1); + } + for ($x = 0; $x < $width; ++$x) { + $head = 0; + $this->runLength[0] = 1; + for ($y = 0; $y < $width; ++$y) { + if (($y == 0) && (ord($frame[$y][$x]) & 1)) { + $this->runLength[0] = -1; + $head = 1; + $this->runLength[$head] = 1; + } elseif ($y > 0) { + if ((ord($frame[$y][$x]) ^ ord($frame[$y - 1][$x])) & 1) { + $head++; + $this->runLength[$head] = 1; + } else { + $this->runLength[$head]++; + } + } + } + $demerit += $this->calcN1N3($head + 1); + } + + return $demerit; + } + + /** + * mask + * + * @param int $width + * @param array $frame + * @param int $level + * + * @return array + */ + protected function mask($width, $frame, $level) + { + $minDemerit = PHP_INT_MAX; + $checkedMasks = array(0, 1, 2, 3, 4, 5, 6, 7); + if (self::QR_FIND_FROM_RANDOM !== false) { + $howManuOut = 8 - (self::QR_FIND_FROM_RANDOM % 9); + for ($i = 0; $i < $howManuOut; ++$i) { + $remPos = rand(0, count($checkedMasks) - 1); + unset($checkedMasks[$remPos]); + $checkedMasks = array_values($checkedMasks); + } + } + $bestMask = $frame; + foreach ($checkedMasks as $i) { + $mask = array_fill(0, $width, str_repeat("\0", $width)); + $blacks = $this->makeMaskNo($i, $width, $frame, $mask); + $blacks += $this->writeFormatInformation($width, $mask, $i, $level); + $blacks = (int) (100 * $blacks / ($width * $width)); + $demerit = (int) ((int) (abs($blacks - 50) / 5) * self::N4); + $demerit += $this->evaluateSymbol($width, $mask); + if ($demerit < $minDemerit) { + $minDemerit = $demerit; + $bestMask = $mask; + } + } + + return $bestMask; + } + + /** + * Return true if the character at specified position is a number + * + * @param string $str + * @param int $pos + * + * @return bool + */ + protected function isdigitat($str, $pos) + { + if ($pos >= strlen($str)) { + return false; + } + + return ((ord($str[$pos]) >= ord('0')) && (ord($str[$pos]) <= ord('9'))); + } + + /** + * Return true if the character at specified position is an alphanumeric character + * + * @param string $str + * @param int $pos + * + * @return bool + */ + protected function isalnumat($str, $pos) + { + if ($pos >= strlen($str)) { + return false; + } + + return ($this->lookAnTable(ord($str[$pos])) >= 0); + } + + /** + * identifyMode + * + * @param int $pos + * + * @return int + */ + protected function identifyMode($pos) + { + if ($pos >= strlen($this->dataStr)) { + return self::QR_MODE_NL; + } + $c = $this->dataStr[$pos]; + if ($this->isdigitat($this->dataStr, $pos)) { + return self::QR_MODE_NM; + } elseif ($this->isalnumat($this->dataStr, $pos)) { + return self::QR_MODE_AN; + } elseif ($this->hint == self::QR_MODE_KJ) { + if ($pos + 1 < strlen($this->dataStr)) { + $d = $this->dataStr[$pos + 1]; + $word = (ord($c) << 8) | ord($d); + if (($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) { + return self::QR_MODE_KJ; + } + } + } + + return self::QR_MODE_8B; + } + + /** + * eatNum + * @return int run + */ + protected function eatNum() + { + $ln = $this->lengthIndicator(self::QR_MODE_NM, $this->version); + $p = 0; + while ($this->isdigitat($this->dataStr, $p)) { + $p++; + } + $run = $p; + $mode = $this->identifyMode($p); + if ($mode == self::QR_MODE_8B) { + $dif = $this->estimateBitsModeNum($run) + 4 + $ln + + $this->estimateBitsMode8(1) // + 4 + l8 + - $this->estimateBitsMode8($run + 1); // - 4 - l8 + if ($dif > 0) { + return $this->eat8(); + } + } + if ($mode == self::QR_MODE_AN) { + $dif = $this->estimateBitsModeNum($run) + 4 + $ln + + $this->estimateBitsModeAn(1) // + 4 + la + - $this->estimateBitsModeAn($run + 1); + // - 4 - la + if ($dif > 0) { + return $this->eatAn(); + } + } + $this->items = $this->appendNewInputItem($this->items, self::QR_MODE_NM, $run, str_split($this->dataStr)); + + return $run; + } + + /** + * eatAn + * @return int run + */ + protected function eatAn() + { + $la = $this->lengthIndicator(self::QR_MODE_AN, $this->version); + $ln = $this->lengthIndicator(self::QR_MODE_NM, $this->version); + $p = 1; + while ($this->isalnumat($this->dataStr, $p)) { + if ($this->isdigitat($this->dataStr, $p)) { + $q = $p; + while ($this->isdigitat($this->dataStr, $q)) { + $q++; + } + $dif = $this->estimateBitsModeAn($p) // + 4 + la + + $this->estimateBitsModeNum($q - $p) + 4 + $ln + - $this->estimateBitsModeAn($q); // - 4 - la + if ($dif < 0) { + break; + } else { + $p = $q; + } + } else { + $p++; + } + } + $run = $p; + if (!$this->isalnumat($this->dataStr, $p)) { + $dif = $this->estimateBitsModeAn($run) + 4 + $la + + $this->estimateBitsMode8(1) // + 4 + l8 + - $this->estimateBitsMode8($run + 1); // - 4 - l8 + if ($dif > 0) { + return $this->eat8(); + } + } + $this->items = $this->appendNewInputItem($this->items, self::QR_MODE_AN, $run, str_split($this->dataStr)); + + return $run; + } + + /** + * eatKanji + * + * @return int + */ + protected function eatKanji() + { + $p = 0; + while ($this->identifyMode($p) == self::QR_MODE_KJ) { + $p += 2; + } + + $run = $p; + $this->items = $this->appendNewInputItem($this->items, self::QR_MODE_KJ, $p, str_split($this->dataStr)); + + return $run; + } + + /** + * eat8 + * + * @return int run + */ + protected function eat8() + { + $la = $this->lengthIndicator(self::QR_MODE_AN, $this->version); + $ln = $this->lengthIndicator(self::QR_MODE_NM, $this->version); + $p = 1; + $dataStrLen = strlen($this->dataStr); + while ($p < $dataStrLen) { + $mode = $this->identifyMode($p); + if ($mode == self::QR_MODE_KJ) { + break; + } + if ($mode == self::QR_MODE_NM) { + $q = $p; + while ($this->isdigitat($this->dataStr, $q)) { + $q++; + } + $dif = $this->estimateBitsMode8($p) // + 4 + l8 + + $this->estimateBitsModeNum($q - $p) + 4 + $ln + - $this->estimateBitsMode8($q); // - 4 - l8 + if ($dif < 0) { + break; + } else { + $p = $q; + } + } elseif ($mode == self::QR_MODE_AN) { + $q = $p; + while ($this->isalnumat($this->dataStr, $q)) { + $q++; + } + $dif = $this->estimateBitsMode8($p) // + 4 + l8 + + $this->estimateBitsModeAn($q - $p) + 4 + $la + - $this->estimateBitsMode8($q); // - 4 - l8 + if ($dif < 0) { + break; + } else { + $p = $q; + } + } else { + $p++; + } + } + $run = $p; + $this->items = $this->appendNewInputItem($this->items, self::QR_MODE_8B, $run, str_split($this->dataStr)); + + return $run; + } + + /** + * splitString + * + * @return int + */ + protected function splitString() + { + while (strlen($this->dataStr) > 0) { + if ($this->dataStr == '') { + return 0; + } + $mode = $this->identifyMode(0); + switch ($mode) { + case self::QR_MODE_NM: + { + $length = $this->eatNum(); + break; + } + case self::QR_MODE_AN: + { + $length = $this->eatAn(); + break; + } + case self::QR_MODE_KJ: + { + if ($this->hint == self::QR_MODE_KJ) { + $length = $this->eatKanji(); + } else { + $length = $this->eat8(); + } + break; + } + default: + { + $length = $this->eat8(); + break; + } + } + if ($length == 0) { + return 0; + } + if ($length < 0) { + return -1; + } + $this->dataStr = substr($this->dataStr, $length); + } + + return 0; + } + + /** + * toUpper + * + * @return string + */ + protected function toUpper() + { + $stringLen = strlen($this->dataStr); + $p = 0; + while ($p < $stringLen) { + $mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint); + if ($mode == self::QR_MODE_KJ) { + $p += 2; + } else { + if ((ord($this->dataStr[$p]) >= ord('a')) && (ord($this->dataStr[$p]) <= ord('z'))) { + $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32); + } + $p++; + } + } + + return $this->dataStr; + } + + /** + * newInputItem + * + * @param int $mode + * @param int $size + * @param array $data + * @param array $bstream + * + * @return array|null + */ + protected function newInputItem($mode, $size, $data, $bstream = null) + { + $setData = array_slice($data, 0, $size); + if (count($setData) < $size) { + $setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0)); + } + if (!$this->check($mode, $size, $setData)) { + return null; + } + $inputitem = array(); + $inputitem['mode'] = $mode; + $inputitem['size'] = $size; + $inputitem['data'] = $setData; + $inputitem['bstream'] = $bstream; + + return $inputitem; + } + + /** + * encodeModeNum + * + * @param array $inputitem + * @param int $version + * + * @return mixed + */ + protected function encodeModeNum($inputitem, $version) + { + $words = (int) ($inputitem['size'] / 3); + $inputitem['bstream'] = array(); + $val = 0x1; + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val); + $inputitem['bstream'] = $this->appendNum( + $inputitem['bstream'], + $this->lengthIndicator(self::QR_MODE_NM, $version), + $inputitem['size'] + ); + for ($i = 0; $i < $words; ++$i) { + $val = (ord($inputitem['data'][$i * 3]) - ord('0')) * 100; + $val += (ord($inputitem['data'][$i * 3 + 1]) - ord('0')) * 10; + $val += (ord($inputitem['data'][$i * 3 + 2]) - ord('0')); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val); + } + if ($inputitem['size'] - $words * 3 == 1) { + $val = ord($inputitem['data'][$words * 3]) - ord('0'); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val); + } elseif (($inputitem['size'] - ($words * 3)) == 2) { + $val = (ord($inputitem['data'][$words * 3]) - ord('0')) * 10; + $val += (ord($inputitem['data'][$words * 3 + 1]) - ord('0')); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val); + } + + return $inputitem; + } + + /** + * encodeModeAn + * + * @param array $inputitem + * @param int $version + * + * @return mixed + */ + protected function encodeModeAn($inputitem, $version) + { + $words = (int) ($inputitem['size'] / 2); + $inputitem['bstream'] = array(); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02); + $inputitem['bstream'] = $this->appendNum( + $inputitem['bstream'], + $this->lengthIndicator(self::QR_MODE_AN, $version), + $inputitem['size'] + ); + for ($i = 0; $i < $words; ++$i) { + $val = (int) ($this->lookAnTable(ord($inputitem['data'][$i * 2])) * 45); + $val += (int) ($this->lookAnTable(ord($inputitem['data'][($i * 2) + 1]))); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val); + } + if ($inputitem['size'] & 1) { + $val = $this->lookAnTable(ord($inputitem['data'][($words * 2)])); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val); + } + + return $inputitem; + } + + /** + * encodeMode8 + * + * @param array $inputitem + * @param int $version + * + * @return mixed + */ + protected function encodeMode8($inputitem, $version) + { + $inputitem['bstream'] = array(); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4); + $inputitem['bstream'] = $this->appendNum( + $inputitem['bstream'], + $this->lengthIndicator(self::QR_MODE_8B, $version), + $inputitem['size'] + ); + for ($i = 0; $i < $inputitem['size']; ++$i) { + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i])); + } + + return $inputitem; + } + + /** + * encodeModeKanji + * + * @param array $inputitem + * @param int $version + * + * @return mixed + */ + protected function encodeModeKanji($inputitem, $version) + { + $inputitem['bstream'] = array(); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8); + $inputitem['bstream'] = $this->appendNum( + $inputitem['bstream'], + $this->lengthIndicator(self::QR_MODE_KJ, $version), + (int) ($inputitem['size'] / 2) + ); + for ($i = 0; $i < $inputitem['size']; $i += 2) { + $val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i + 1]); + if ($val <= 0x9ffc) { + $val -= 0x8140; + } else { + $val -= 0xc140; + } + $h = ($val >> 8) * 0xc0; + $val = ($val & 0xff) + $h; + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val); + } + + return $inputitem; + } + + /** + * encodeModeStructure + * + * @param array $inputitem + * + * @return mixed + */ + protected function encodeModeStructure($inputitem) + { + $inputitem['bstream'] = array(); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1); + $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2])); + + return $inputitem; + } + + /** + * encodeBitStream + * + * @param array $inputitem + * @param int $version + * + * @return mixed + */ + protected function encodeBitStream($inputitem, $version) + { + $inputitem['bstream'] = array(); + $words = $this->maximumWords($inputitem['mode'], $version); + if ($inputitem['size'] > $words) { + $st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']); + $st2 = $this->newInputItem( + $inputitem['mode'], + $inputitem['size'] - $words, + array_slice($inputitem['data'], $words) + ); + $st1 = $this->encodeBitStream($st1, $version); + $st2 = $this->encodeBitStream($st2, $version); + $inputitem['bstream'] = array(); + $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']); + $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']); + } else { + switch ($inputitem['mode']) { + case self::QR_MODE_NM: + { + $inputitem = $this->encodeModeNum($inputitem, $version); + break; + } + case self::QR_MODE_AN: + { + $inputitem = $this->encodeModeAn($inputitem, $version); + break; + } + case self::QR_MODE_8B: + { + $inputitem = $this->encodeMode8($inputitem, $version); + break; + } + case self::QR_MODE_KJ: + { + $inputitem = $this->encodeModeKanji($inputitem, $version); + break; + } + case self::QR_MODE_ST: + { + $inputitem = $this->encodeModeStructure($inputitem); + break; + } + default: + { + break; + } + } + } + + return $inputitem; + } + + /** + * Append data to an input object - The data is copied and appended to the input object. + * + * @param array $items + * @param int $mode + * @param int $size + * @param array $data + * + * @return array + */ + protected function appendNewInputItem($items, $mode, $size, $data) + { + $newitem = $this->newInputItem($mode, $size, $data); + if (!empty($newitem)) { + $items[] = $newitem; + } + + return $items; + } + + /** + * insertStructuredAppendHeader + * + * @param array $items + * @param int $size + * @param int $index + * @param int $parity + * + * @return int + */ + protected function insertStructuredAppendHeader($items, $size, $index, $parity) + { + if ($size > self::MAX_STRUCTURED_SYMBOLS) { + return -1; + } + if (($index <= 0) || ($index > self::MAX_STRUCTURED_SYMBOLS)) { + return -1; + } + $buf = array($size, $index, $parity); + $entry = $this->newInputItem(self::QR_MODE_ST, 3, $buf); + array_unshift($items, $entry); + + return $items; + } + + /** + * calcParity + * + * @param array $items + * + * @return int + */ + protected function calcParity($items) + { + $parity = 0; + foreach ($items as $item) { + if ($item['mode'] != self::QR_MODE_ST) { + for ($i = $item['size'] - 1; $i >= 0; --$i) { + $parity ^= $item['data'][$i]; + } + } + } + + return $parity; + } + + /** + * checkModeNum + * + * @param int $size + * @param array $data + * + * @return bool + */ + protected function checkModeNum($size, $data) + { + for ($i = 0; $i < $size; ++$i) { + if ((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))) { + return false; + } + } + + return true; + } + + /** + * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19). + * + * @param int $c + * + * @return int + */ + protected function lookAnTable($c) + { + return (($c > 127) ? -1 : $this->anTable[$c]); + } + + /** + * checkModeAn + * + * @param int $size + * @param array $data + * + * @return bool + */ + protected function checkModeAn($size, $data) + { + for ($i = 0; $i < $size; ++$i) { + if ($this->lookAnTable(ord($data[$i])) == -1) { + return false; + } + } + + return true; + } + + /** + * estimateBitsModeNum + * + * @param int $size + * + * @return int + */ + protected function estimateBitsModeNum($size) + { + $w = (int) ($size / 3); + $bits = ($w * 10); + switch ($size - ($w * 3)) { + case 1: + { + $bits += 4; + break; + } + case 2: + { + $bits += 7; + break; + } + } + + return $bits; + } + + /** + * estimateBitsModeAn + * + * @param int $size + * + * @return int + */ + protected function estimateBitsModeAn($size) + { + $bits = (int) ($size * 5.5); // (size / 2 ) * 11 + if ($size & 1) { + $bits += 6; + } + + return $bits; + } + + /** + * estimateBitsMode8 + * + * @param int $size + * + * @return int + */ + protected function estimateBitsMode8($size) + { + return (int) ($size * 8); + } + + /** + * estimateBitsModeKanji + * + * @param int $size + * + * @return int + */ + protected function estimateBitsModeKanji($size) + { + return (int) ($size * 6.5); // (size / 2 ) * 13 + } + + /** + * checkModeKanji + * + * @param int $size + * @param array $data + * + * @return bool + */ + protected function checkModeKanji($size, $data) + { + if ($size & 1) { + return false; + } + for ($i = 0; $i < $size; $i += 2) { + $val = (ord($data[$i]) << 8) | ord($data[$i + 1]); + if (($val < 0x8140) || (($val > 0x9ffc) && ($val < 0xe040)) || ($val > 0xebbf)) { + return false; + } + } + + return true; + } + + /** + * Validate the input data. + * + * @param int $mode + * @param int $size + * @param array $data + * + * @return bool + */ + protected function check($mode, $size, $data) + { + if ($size <= 0) { + return false; + } + switch ($mode) { + case self::QR_MODE_NM: + { + return $this->checkModeNum($size, $data); + } + case self::QR_MODE_AN: + { + return $this->checkModeAn($size, $data); + } + case self::QR_MODE_KJ: + { + return $this->checkModeKanji($size, $data); + } + case self::QR_MODE_8B: + { + return true; + } + case self::QR_MODE_ST: + { + return true; + } + default: + { + break; + } + } + + return false; + } + + /** + * estimateBitStreamSize + * + * @param array $items + * @param int $version + * + * @return int + */ + protected function estimateBitStreamSize($items, $version) + { + $bits = 0; + if ($version == 0) { + $version = 1; + } + foreach ($items as $item) { + switch ($item['mode']) { + case self::QR_MODE_NM: + { + $bits = $this->estimateBitsModeNum($item['size']); + break; + } + case self::QR_MODE_AN: + { + $bits = $this->estimateBitsModeAn($item['size']); + break; + } + case self::QR_MODE_8B: + { + $bits = $this->estimateBitsMode8($item['size']); + break; + } + case self::QR_MODE_KJ: + { + $bits = $this->estimateBitsModeKanji($item['size']); + break; + } + case self::QR_MODE_ST: + { + return self::STRUCTURE_HEADER_BITS; + } + default: + { + return 0; + } + } + $l = $this->lengthIndicator($item['mode'], $version); + $m = 1 << $l; + $num = (int) (($item['size'] + $m - 1) / $m); + $bits += $num * (4 + $l); + } + + return $bits; + } + + /** + * estimateVersion + * + * @param array $items + * + * @return int + */ + protected function estimateVersion($items) + { + $version = 0; + + do { + $prev = $version; + $bits = $this->estimateBitStreamSize($items, $prev); + $version = $this->getMinimumVersion((int) (($bits + 7) / 8), $this->level); + if ($version < 0) { + return -1; + } + } while ($version > $prev); + + return $version; + } + + /** + * lengthOfCode + * + * @param int $mode + * @param int $version + * @param int $bits + * + * @return int + */ + protected function lengthOfCode($mode, $version, $bits) + { + $payload = $bits - 4 - $this->lengthIndicator($mode, $version); + switch ($mode) { + case self::QR_MODE_NM: + { + $chunks = (int) ($payload / 10); + $remain = $payload - $chunks * 10; + $size = $chunks * 3; + if ($remain >= 7) { + $size += 2; + } elseif ($remain >= 4) { + $size += 1; + } + break; + } + case self::QR_MODE_AN: + { + $chunks = (int) ($payload / 11); + $remain = $payload - $chunks * 11; + $size = $chunks * 2; + if ($remain >= 6) { + ++$size; + } + break; + } + case self::QR_MODE_8B: + { + $size = (int) ($payload / 8); + break; + } + case self::QR_MODE_KJ: + { + $size = (int) (($payload / 13) * 2); + break; + } + case self::QR_MODE_ST: + { + $size = (int) ($payload / 8); + break; + } + default: + { + $size = 0; + break; + } + } + $maxsize = $this->maximumWords($mode, $version); + if ($size < 0) { + $size = 0; + } + if ($size > $maxsize) { + $size = $maxsize; + } + + return $size; + } + + /** + * createBitStream + * + * @param array $items + * + * @return array + */ + protected function createBitStream($items) + { + $total = 0; + foreach ($items as $key => $item) { + $items[$key] = $this->encodeBitStream($item, $this->version); + $bits = count($items[$key]['bstream']); + $total += $bits; + } + + return array($items, $total); + } + + /** + * convertData + * + * @param array $items + * + * @return int + */ + protected function convertData($items) + { + $ver = $this->estimateVersion($items); + if ($ver > $this->version) { + $this->version = $ver; + } + for (;;) { + $cbs = $this->createBitStream($items); + $items = $cbs[0]; + $bits = $cbs[1]; + if ($bits < 0) { + return -1; + } + $ver = $this->getMinimumVersion((int) (($bits + 7) / 8), $this->level); + if ($ver < 0) { + return -1; + } elseif ($ver > $this->version) { + $this->version = $ver; + } else { + break; + } + } + + return $items; + } + + /** + * Append Padding Bit to bitstream + * + * @param array $bstream + * + * @return array|null + */ + protected function appendPaddingBit($bstream) + { + if (is_null($bstream)) { + return null; + } + $bits = count($bstream); + $maxwords = $this->getDataLength($this->version, $this->level); + $maxbits = $maxwords * 8; + if ($maxbits == $bits) { + return $bstream; + } + if ($maxbits - $bits < 5) { + return $this->appendNum($bstream, $maxbits - $bits, 0); + } + $bits += 4; + $words = (int) (($bits + 7) / 8); + $padding = array(); + $padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0); + $padlen = $maxwords - $words; + if ($padlen > 0) { + $padbuf = array(); + for ($i = 0; $i < $padlen; ++$i) { + $padbuf[$i] = ($i & 1) ? 0x11 : 0xec; + } + $padding = $this->appendBytes($padding, $padlen, $padbuf); + } + + return $this->appendBitstream($bstream, $padding); + } + + /** + * mergeBitStream + * + * @param array $items + * + * @return array|null + */ + protected function mergeBitStream($items) + { + $items = $this->convertData($items); + if (!is_array($items)) { + return null; + } + $bstream = array(); + foreach ($items as $item) { + $bstream = $this->appendBitstream($bstream, $item['bstream']); + } + + return $bstream; + } + + /** + * Returns a stream of bits + * + * @param array $items + * + * @return array|null + */ + protected function getBitStream($items) + { + $bstream = $this->mergeBitStream($items); + + return $this->appendPaddingBit($bstream); + } + + /** + * Pack all bit streams padding bits into a byte array. + * + * @param array $items + * + * @return array + */ + protected function getByteStream($items) + { + $bstream = $this->getBitStream($items); + + return $this->bitstreamToByte($bstream); + } + + /** + * Return an array with zeros + * + * @param int $setLength + * + * @return array + */ + protected function allocate($setLength) + { + return array_fill(0, $setLength, 0); + } + + /** + * Return new bitstream from number + * + * @param int $bits + * @param int $num + * + * @return array + */ + protected function newFromNum($bits, $num) + { + $bstream = $this->allocate($bits); + $mask = 1 << ($bits - 1); + for ($i = 0; $i < $bits; ++$i) { + if ($num & $mask) { + $bstream[$i] = 1; + } else { + $bstream[$i] = 0; + } + $mask = $mask >> 1; + } + + return $bstream; + } + + /** + * Return new bitstream from bytes + * + * @param int $size + * @param array $data + * + * @return array + */ + protected function newFromBytes($size, $data) + { + $bstream = $this->allocate($size * 8); + $p = 0; + for ($i = 0; $i < $size; ++$i) { + $mask = 0x80; + for ($j = 0; $j < 8; ++$j) { + if ($data[$i] & $mask) { + $bstream[$p] = 1; + } else { + $bstream[$p] = 0; + } + $p++; + $mask = $mask >> 1; + } + } + + return $bstream; + } + + /** + * Append one bitstream to another + * + * @param array $bitstream + * @param array $append + * + * @return array + */ + protected function appendBitstream($bitstream, $append) + { + if ((!is_array($append)) || (count($append) == 0)) { + return $bitstream; + } + if (count($bitstream) == 0) { + return $append; + } + + return array_values(array_merge($bitstream, $append)); + } + + /** + * Append one bitstream created from number to another + * + * @param array $bitstream + * @param int $bits + * @param int $num + * + * @return array|int + */ + protected function appendNum($bitstream, $bits, $num) + { + if ($bits == 0) { + return 0; + } + $b = $this->newFromNum($bits, $num); + + return $this->appendBitstream($bitstream, $b); + } + + /** + * Append one bitstream created from bytes to another + * + * @param array $bitstream + * @param int $size + * @param array $data + * + * @return array|int + */ + protected function appendBytes($bitstream, $size, $data) + { + if ($size == 0) { + return 0; + } + $b = $this->newFromBytes($size, $data); + + return $this->appendBitstream($bitstream, $b); + } + + /** + * Convert bitstream to bytes + * + * @param array $bstream + * + * @return array|null + */ + protected function bitstreamToByte($bstream) + { + if (is_null($bstream)) { + return null; + } + $size = count($bstream); + if ($size == 0) { + return array(); + } + $data = array_fill(0, (int) (($size + 7) / 8), 0); + $bytes = (int) ($size / 8); + $p = 0; + for ($i = 0; $i < $bytes; $i++) { + $v = 0; + for ($j = 0; $j < 8; $j++) { + $v = $v << 1; + $v |= $bstream[$p]; + $p++; + } + $data[$i] = $v; + } + if ($size & 7) { + $v = 0; + for ($j = 0; $j < ($size & 7); $j++) { + $v = $v << 1; + $v |= $bstream[$p]; + $p++; + } + $data[$bytes] = $v; + } + + return $data; + } + + + /** + * Replace a value on the array at the specified position + * + * @param array $srctab + * @param int $x + * @param int $y + * @param string $repl + * @param bool $replLen + * + * @return mixed + */ + protected function qrstrset($srctab, $x, $y, $repl, $replLen = false) + { + $srctab[$y] = substr_replace( + $srctab[$y], + ($replLen !== false) ? substr($repl, 0, $replLen) : $repl, + $x, + ($replLen !== false) ? $replLen : strlen($repl) + ); + + return $srctab; + } + + /** + * Return maximum data code length (bytes) for the version. + * + * @param int $version + * @param int $level + * + * @return mixed + */ + protected function getDataLength($version, $level) + { + return $this->capacity[$version][self::QRCAP_WORDS] - $this->capacity[$version][self::QRCAP_EC][$level]; + } + + /** + * Return maximum error correction code length (bytes) for the version. + * + * @param int $version + * @param int $level + * + * @return mixed + */ + protected function getECCLength($version, $level) + { + return $this->capacity[$version][self::QRCAP_EC][$level]; + } + + /** + * Return the width of the symbol for the version. + * + * @param int $version + * + * @return mixed + */ + protected function getWidth($version) + { + return $this->capacity[$version][self::QRCAP_WIDTH]; + } + + /** + * Return the number of remainder bits. + * + * @param int $version + * + * @return mixed + */ + protected function getRemainder($version) + { + return $this->capacity[$version][self::QRCAP_REMINDER]; + } + + /** + * Return a version number that satisfies the input code length. + * + * @param int $size + * @param int $level + * + * @return int + */ + protected function getMinimumVersion($size, $level) + { + for ($i = 1; $i <= self::QRSPEC_VERSION_MAX; ++$i) { + $words = $this->capacity[$i][self::QRCAP_WORDS] - $this->capacity[$i][self::QRCAP_EC][$level]; + if ($words >= $size) { + return $i; + } + } + + return -1; + } + + /** + * Return the size of length indicator for the mode and version. + * + * @param int $mode + * @param int $version + * + * @return int + */ + protected function lengthIndicator($mode, $version) + { + if ($mode == self::QR_MODE_ST) { + return 0; + } + if ($version <= 9) { + $l = 0; + } elseif ($version <= 26) { + $l = 1; + } else { + $l = 2; + } + + return $this->lengthTableBits[$mode][$l]; + } + + /** + * Return the maximum length for the mode and version. + * + * @param int $mode + * @param int $version + * + * @return int + */ + protected function maximumWords($mode, $version) + { + if ($mode == self::QR_MODE_ST) { + return 3; + } + if ($version <= 9) { + $l = 0; + } else { + if ($version <= 26) { + $l = 1; + } else { + $l = 2; + } + } + $bits = $this->lengthTableBits[$mode][$l]; + $words = (1 << $bits) - 1; + if ($mode == self::QR_MODE_KJ) { + $words *= 2; // the number of bytes is required + } + + return $words; + } + + /** + * Return an array of ECC specification. + * + * @param int $version + * @param int $level + * @param array $spec + * + * @return array + */ + protected function getEccSpec($version, $level, $spec) + { + if (count($spec) < 5) { + $spec = array(0, 0, 0, 0, 0); + } + $b1 = $this->eccTable[$version][$level][0]; + $b2 = $this->eccTable[$version][$level][1]; + $data = $this->getDataLength($version, $level); + $ecc = $this->getECCLength($version, $level); + if ($b2 == 0) { + $spec[0] = $b1; + $spec[1] = (int) ($data / $b1); + $spec[2] = (int) ($ecc / $b1); + $spec[3] = 0; + $spec[4] = 0; + } else { + $spec[0] = $b1; + $spec[1] = (int) ($data / ($b1 + $b2)); + $spec[2] = (int) ($ecc / ($b1 + $b2)); + $spec[3] = $b2; + $spec[4] = $spec[1] + 1; + } + + return $spec; + } + + /** + * Put an alignment marker. + * + * @param array $frame + * @param int $ox + * @param int $oy + * + * @return mixed + */ + protected function putAlignmentMarker($frame, $ox, $oy) + { + $finder = array( + "\xa1\xa1\xa1\xa1\xa1", + "\xa1\xa0\xa0\xa0\xa1", + "\xa1\xa0\xa1\xa0\xa1", + "\xa1\xa0\xa0\xa0\xa1", + "\xa1\xa1\xa1\xa1\xa1" + ); + $yStart = $oy - 2; + $xStart = $ox - 2; + for ($y = 0; $y < 5; $y++) { + $frame = $this->qrstrset($frame, $xStart, $yStart + $y, $finder[$y]); + } + + return $frame; + } + + /** + * Put an alignment pattern. + * + * @param int $version + * @param array $frame + * @param int $width + * + * @return mixed + */ + protected function putAlignmentPattern($version, $frame, $width) + { + if ($version < 2) { + return $frame; + } + $d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0]; + if ($d < 0) { + $w = 2; + } else { + $w = (int) (($width - $this->alignmentPattern[$version][0]) / $d + 2); + } + if ($w * $w - 3 == 1) { + $x = $this->alignmentPattern[$version][0]; + $y = $this->alignmentPattern[$version][0]; + $frame = $this->putAlignmentMarker($frame, $x, $y); + + return $frame; + } + $cx = $this->alignmentPattern[$version][0]; + $wo = $w - 1; + for ($x = 1; $x < $wo; ++$x) { + $frame = $this->putAlignmentMarker($frame, 6, $cx); + $frame = $this->putAlignmentMarker($frame, $cx, 6); + $cx += $d; + } + $cy = $this->alignmentPattern[$version][0]; + for ($y = 0; $y < $wo; ++$y) { + $cx = $this->alignmentPattern[$version][0]; + for ($x = 0; $x < $wo; ++$x) { + $frame = $this->putAlignmentMarker($frame, $cx, $cy); + $cx += $d; + } + $cy += $d; + } + + return $frame; + } + + /** + * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater. Use lower 18 bits. + * + * @param int $version + * + * @return int + */ + protected function getVersionPattern($version) + { + if (($version < 7) || ($version > self::QRSPEC_VERSION_MAX)) { + return 0; + } + + return $this->versionPattern[($version - 7)]; + } + + /** + * Return BCH encoded format information pattern. + * + * @param int $mask + * @param int $level + * + * @return int + */ + protected function getFormatInfo($mask, $level) + { + if (($mask < 0) || ($mask > 7)) { + return 0; + } + if (($level < 0) || ($level > 3)) { + return 0; + } + + return $this->formatInfo[$level][$mask]; + } + + /** + * Put a finder pattern. + * + * @param array $frame + * @param int $ox + * @param int $oy + * + * @return mixed + */ + protected function putFinderPattern($frame, $ox, $oy) + { + $finder = array( + "\xc1\xc1\xc1\xc1\xc1\xc1\xc1", + "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", + "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", + "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", + "\xc1\xc0\xc1\xc1\xc1\xc0\xc1", + "\xc1\xc0\xc0\xc0\xc0\xc0\xc1", + "\xc1\xc1\xc1\xc1\xc1\xc1\xc1" + ); + for ($y = 0; $y < 7; $y++) { + $frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]); + } + + return $frame; + } + + /** + * Return a copy of initialized frame. + * + * @param int $version + * + * @return array|mixed + */ + protected function createFrame($version) + { + $width = $this->capacity[$version][self::QRCAP_WIDTH]; + $frameLine = str_repeat("\0", $width); + $frame = array_fill(0, $width, $frameLine); + // Finder pattern + $frame = $this->putFinderPattern($frame, 0, 0); + $frame = $this->putFinderPattern($frame, $width - 7, 0); + $frame = $this->putFinderPattern($frame, 0, $width - 7); + // Separator + $yOffset = $width - 7; + for ($y = 0; $y < 7; ++$y) { + $frame[$y][7] = "\xc0"; + $frame[$y][$width - 8] = "\xc0"; + $frame[$yOffset][7] = "\xc0"; + ++$yOffset; + } + $setPattern = str_repeat("\xc0", 8); + $frame = $this->qrstrset($frame, 0, 7, $setPattern); + $frame = $this->qrstrset($frame, $width - 8, 7, $setPattern); + $frame = $this->qrstrset($frame, 0, $width - 8, $setPattern); + // Format info + $setPattern = str_repeat("\x84", 9); + $frame = $this->qrstrset($frame, 0, 8, $setPattern); + $frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8); + $yOffset = $width - 8; + for ($y = 0; $y < 8; ++$y, ++$yOffset) { + $frame[$y][8] = "\x84"; + $frame[$yOffset][8] = "\x84"; + } + // Timing pattern + $wo = $width - 15; + for ($i = 1; $i < $wo; ++$i) { + $frame[6][7 + $i] = chr(0x90 | ($i & 1)); + $frame[7 + $i][6] = chr(0x90 | ($i & 1)); + } + // Alignment pattern + $frame = $this->putAlignmentPattern($version, $frame, $width); + // Version information + if ($version >= 7) { + $vinf = $this->getVersionPattern($version); + $v = $vinf; + for ($x = 0; $x < 6; ++$x) { + for ($y = 0; $y < 3; ++$y) { + $frame[($width - 11) + $y][$x] = chr(0x88 | ($v & 1)); + $v = $v >> 1; + } + } + $v = $vinf; + for ($y = 0; $y < 6; ++$y) { + for ($x = 0; $x < 3; ++$x) { + $frame[$y][$x + ($width - 11)] = chr(0x88 | ($v & 1)); + $v = $v >> 1; + } + } + } + // and a little bit... + $frame[$width - 8][8] = "\x81"; + + return $frame; + } + + /** + * Set new frame for the specified version. + * + * @param int $version + * + * @return null + */ + protected function newFrame($version) + { + if (($version < 1) || ($version > self::QRSPEC_VERSION_MAX)) { + return null; + } + if (!isset($this->frames[$version])) { + $this->frames[$version] = $this->createFrame($version); + } + if (is_null($this->frames[$version])) { + return null; + } + + return $this->frames[$version]; + } + + /** + * Return block number 0 + * + * @param array $spec + * + * @return mixed + */ + protected function rsBlockNum($spec) + { + return ($spec[0] + $spec[3]); + } + + /** + * Return block number 1 + * + * @param array $spec + * + * @return mixed + */ + protected function rsBlockNum1($spec) + { + return $spec[0]; + } + + /** + * Return data codes 1 + * + * @param array $spec + * + * @return mixed + */ + protected function rsDataCodes1($spec) + { + return $spec[1]; + } + + /** + * Return ecc codes 1 + * + * @param array $spec + * + * @return mixed + */ + protected function rsEccCodes1($spec) + { + return $spec[2]; + } + + /** + * Return block number 2 + * + * @param array $spec + * + * @return mixed + */ + protected function rsBlockNum2($spec) + { + return $spec[3]; + } + + /** + * Return data codes 2 + * + * @param array $spec + * + * @return mixed + */ + protected function rsDataCodes2($spec) + { + return $spec[4]; + } + + /** + * Return ecc codes 2 + * + * @param array $spec + * + * @return mixed + */ + protected function rsEccCodes2($spec) + { + return $spec[2]; + } + + /** + * Return data length + * + * @param array $spec + * + * @return mixed + */ + protected function rsDataLength($spec) + { + return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]); + } + + /** + * Return ecc length + * + * @param array $spec + * + * @return mixed + */ + protected function rsEccLength($spec) + { + return ($spec[0] + $spec[3]) * $spec[2]; + } + + /** + * Initialize a Reed-Solomon codec and add it to existing rsitems + * + * @param int $symsize + * @param int $gfpoly + * @param int $fcr + * @param int $prim + * @param int $nroots + * @param int $pad + * + * @return array + */ + protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) + { + foreach ($this->rsitems as $rs) { + if (($rs['pad'] != $pad) || ($rs['nroots'] != $nroots) || ($rs['mm'] != $symsize) + || ($rs['gfpoly'] != $gfpoly) || ($rs['fcr'] != $fcr) || ($rs['prim'] != $prim) + ) { + continue; + } + + return $rs; + } + $rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad); + array_unshift($this->rsitems, $rs); + + return $rs; + } + + /** + * modnn + * + * @param array $rs + * @param int $x + * + * @return int + */ + protected function modnn($rs, $x) + { + while ($x >= $rs['nn']) { + $x -= $rs['nn']; + $x = ($x >> $rs['mm']) + ($x & $rs['nn']); + } + + return $x; + } + + /** + * Initialize a Reed-Solomon codec and returns an array of values. + * + * @param int $symsize + * @param int $gfpoly + * @param int $fcr + * @param int $prim + * @param int $nroots + * @param int $pad + * + * @return array|null + */ + protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) + { + // Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2) + $rs = null; + // Check parameter ranges + if (($symsize < 0) || ($symsize > 8)) { + return $rs; + } + if (($fcr < 0) || ($fcr >= (1 << $symsize))) { + return $rs; + } + if (($prim <= 0) || ($prim >= (1 << $symsize))) { + return $rs; + } + if (($nroots < 0) || ($nroots >= (1 << $symsize))) { + return $rs; + } + if (($pad < 0) || ($pad >= ((1 << $symsize) - 1 - $nroots))) { + return $rs; + } + $rs = array(); + $rs['mm'] = $symsize; + $rs['nn'] = (1 << $symsize) - 1; + $rs['pad'] = $pad; + $rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0); + $rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0); + // PHP style macro replacement ;) + $nn =& $rs['nn']; + $a0 =& $nn; + // Generate Galois field lookup tables + $rs['index_of'][0] = $a0; // log(zero) = -inf + $rs['alpha_to'][$a0] = 0; // alpha**-inf = 0 + $sr = 1; + for ($i = 0; $i < $rs['nn']; ++$i) { + $rs['index_of'][$sr] = $i; + $rs['alpha_to'][$i] = $sr; + $sr <<= 1; + if ($sr & (1 << $symsize)) { + $sr ^= $gfpoly; + } + $sr &= $rs['nn']; + } + if ($sr != 1) { + // field generator polynomial is not primitive! + return null; + } + // Form RS code generator polynomial from its roots + $rs['genpoly'] = array_fill(0, ($nroots + 1), 0); + $rs['fcr'] = $fcr; + $rs['prim'] = $prim; + $rs['nroots'] = $nroots; + $rs['gfpoly'] = $gfpoly; + // Find prim-th root of 1, used in decoding + for ($iprim = 1; ($iprim % $prim) != 0; $iprim += $rs['nn']) { + ; // intentional empty-body loop! + } + $rs['iprim'] = (int) ($iprim / $prim); + $rs['genpoly'][0] = 1; + for ($i = 0, $root = $fcr * $prim; $i < $nroots; $i++, $root += $prim) { + $rs['genpoly'][$i + 1] = 1; + // Multiply rs->genpoly[] by @**(root + x) + for ($j = $i; $j > 0; --$j) { + if ($rs['genpoly'][$j] != 0) { + $rs['genpoly'][$j] = $rs['genpoly'][$j - 1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)]; + } else { + $rs['genpoly'][$j] = $rs['genpoly'][$j - 1]; + } + } + // rs->genpoly[0] can never be zero + $rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)]; + } + // convert rs->genpoly[] to index form for quicker encoding + for ($i = 0; $i <= $nroots; ++$i) { + $rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]]; + } + + return $rs; + } + + /** + * Encode a Reed-Solomon codec and returns the parity array + * + * @param array $rs + * @param array $data + * @param array $parity + * + * @return array + */ + protected function encode_rs_char($rs, $data, $parity) + { + $nn =& $rs['nn']; // the total number of symbols in a RS block + $alphaTo =& $rs['alpha_to']; // the address of an array of NN elements to convert Galois field elements in index (log) form to polynomial form + $indexOf =& $rs['index_of']; // the address of an array of NN elements to convert Galois field elements in polynomial form to index (log) form + $genPoly =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form + $nRoots =& $rs['nroots']; // the number of roots in the RS code generator polynomial, which is the same as the number of parity symbols in a block + $pad =& $rs['pad']; // the number of pad symbols in a block + $a0 =& $nn; + $parity = (empty($parity)||$parity==null)?array_fill(0, $nRoots, 0):$parity; + for ($i = 0; $i < ($nn - $nRoots - $pad); $i++) { + $feedback = $indexOf[$data[$i] ^ $parity[0]]; + if ($feedback != $a0) { + // feedback term is non-zero + // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must + // always be for the polynomials constructed by init_rs() + $feedback = $this->modnn($rs, $nn - $genPoly[$nRoots] + $feedback); + for ($j = 1; $j < $nRoots; ++$j) { + $parity[$j] ^= $alphaTo[$this->modnn($rs, $feedback + $genPoly[($nRoots - $j)])]; + } + } + // Shift + array_shift($parity); + if ($feedback != $a0) { + array_push($parity, $alphaTo[$this->modnn($rs, $feedback + $genPoly[0])]); + } else { + array_push($parity, 0); + } + } + + return $parity; + } + } // end QRcode class diff --git a/samples/.htaccess b/samples/.htaccess old mode 100644 new mode 100755 diff --git a/samples/404.html b/samples/404.html old mode 100644 new mode 100755 diff --git a/samples/CHANGELOG.md b/samples/CHANGELOG.md old mode 100644 new mode 100755 diff --git a/samples/CONTRIBUTING.md b/samples/CONTRIBUTING.md old mode 100644 new mode 100755 diff --git a/samples/LICENSE.md b/samples/LICENSE.md old mode 100644 new mode 100755 diff --git a/samples/README.md b/samples/README.md old mode 100644 new mode 100755 diff --git a/samples/apple-touch-icon-precomposed.png b/samples/apple-touch-icon-precomposed.png old mode 100644 new mode 100755 diff --git a/samples/crossdomain.xml b/samples/crossdomain.xml old mode 100644 new mode 100755 diff --git a/samples/css/main.css b/samples/css/main.css old mode 100644 new mode 100755 diff --git a/samples/css/normalize.css b/samples/css/normalize.css old mode 100644 new mode 100755 diff --git a/samples/doc/TOC.md b/samples/doc/TOC.md old mode 100644 new mode 100755 diff --git a/samples/doc/crossdomain.md b/samples/doc/crossdomain.md old mode 100644 new mode 100755 diff --git a/samples/doc/css.md b/samples/doc/css.md old mode 100644 new mode 100755 diff --git a/samples/doc/extend.md b/samples/doc/extend.md old mode 100644 new mode 100755 diff --git a/samples/doc/faq.md b/samples/doc/faq.md old mode 100644 new mode 100755 diff --git a/samples/doc/html.md b/samples/doc/html.md old mode 100644 new mode 100755 diff --git a/samples/doc/js.md b/samples/doc/js.md old mode 100644 new mode 100755 diff --git a/samples/doc/misc.md b/samples/doc/misc.md old mode 100644 new mode 100755 diff --git a/samples/doc/usage.md b/samples/doc/usage.md old mode 100644 new mode 100755 diff --git a/samples/favicon.ico b/samples/favicon.ico old mode 100644 new mode 100755 diff --git a/samples/humans.txt b/samples/humans.txt old mode 100644 new mode 100755 diff --git a/samples/img/.gitignore b/samples/img/.gitignore old mode 100644 new mode 100755 diff --git a/samples/index.php b/samples/index.php old mode 100644 new mode 100755 diff --git a/samples/js/main.js b/samples/js/main.js old mode 100644 new mode 100755 diff --git a/samples/js/plugins.js b/samples/js/plugins.js old mode 100644 new mode 100755 diff --git a/samples/js/vendor/jquery-1.10.2.min.js b/samples/js/vendor/jquery-1.10.2.min.js old mode 100644 new mode 100755 diff --git a/samples/js/vendor/modernizr-2.6.2.min.js b/samples/js/vendor/modernizr-2.6.2.min.js old mode 100644 new mode 100755 diff --git a/samples/robots.txt b/samples/robots.txt old mode 100644 new mode 100755 diff --git a/tests/BGBarcodeGeneratorUnitTests.php b/tests/BGBarcodeGeneratorUnitTests.php old mode 100644 new mode 100755 diff --git a/tests/bootstrap.php b/tests/bootstrap.php old mode 100644 new mode 100755 diff --git a/tests/phpunit.xml b/tests/phpunit.xml old mode 100644 new mode 100755 diff --git a/tests/tmp/.empty b/tests/tmp/.empty old mode 100644 new mode 100755