[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/se3master/var/www/se3/html2pdf/_tcpdf_5.0.002/ -> barcodes.php (source)

   1  <?php
   2  //============================================================+
   3  // File name   : barcodes.php
   4  // Begin       : 2008-06-09
   5  // Last Update : 2009-08-26
   6  // Version     : 1.0.009
   7  // License     : GNU LGPL (http://www.gnu.org/copyleft/lesser.html)
   8  //     ----------------------------------------------------------------------------
   9  //  Copyright (C) 2008-2009 Nicola Asuni - Tecnick.com S.r.l.
  10  //     
  11  //     This program is free software: you can redistribute it and/or modify
  12  //     it under the terms of the GNU Lesser General Public License as published by
  13  //     the Free Software Foundation, either version 2.1 of the License, or
  14  //     (at your option) any later version.
  15  //     
  16  //     This program is distributed in the hope that it will be useful,
  17  //     but WITHOUT ANY WARRANTY; without even the implied warranty of
  18  //     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19  //     GNU Lesser General Public License for more details.
  20  //     
  21  //     You should have received a copy of the GNU Lesser General Public License
  22  //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23  //     
  24  //     See LICENSE.TXT file for more information.
  25  //  ----------------------------------------------------------------------------
  26  //
  27  // Description : PHP class to creates array representations for 
  28  //               common 1D barcodes to be used with TCPDF.
  29  //
  30  // Author: Nicola Asuni
  31  //
  32  // (c) Copyright:
  33  //               Nicola Asuni
  34  //               Tecnick.com S.r.l.
  35  //               Via della Pace, 11
  36  //               09044 Quartucciu (CA)
  37  //               ITALY
  38  //               www.tecnick.com
  39  //               info@tecnick.com
  40  //============================================================+
  41  
  42  /**
  43   * PHP class to creates array representations for common 1D barcodes to be used with TCPDF.
  44   * @package com.tecnick.tcpdf
  45   * @abstract Functions for generating string representation of common 1D barcodes.
  46   * @author Nicola Asuni
  47   * @copyright 2008-2009 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
  48   * @link http://www.tcpdf.org
  49   * @license http://www.gnu.org/copyleft/lesser.html LGPL
  50   * @version 1.0.008
  51   */
  52  
  53      /**
  54      * PHP class to creates array representations for common 1D barcodes to be used with TCPDF (http://www.tcpdf.org).<br>
  55      * @name TCPDFBarcode
  56      * @package com.tecnick.tcpdf
  57      * @version 1.0.008
  58      * @author Nicola Asuni
  59      * @link http://www.tcpdf.org
  60      * @license http://www.gnu.org/copyleft/lesser.html LGPL
  61      */
  62  class TCPDFBarcode {
  63      
  64      /**
  65       * @var array representation of barcode.
  66       * @access protected
  67       */
  68      protected $barcode_array;
  69          
  70      /**
  71       * This is the class constructor. 
  72       * Return an array representations for common 1D barcodes:<ul>
  73       * <li>$arrcode['code'] code to be printed on text label</li>
  74       * <li>$arrcode['maxh'] max bar height</li>
  75       * <li>$arrcode['maxw'] max bar width</li>
  76       * <li>$arrcode['bcode'][$k] single bar or space in $k position</li>
  77       * <li>$arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.</li>
  78       * <li>$arrcode['bcode'][$k]['w'] bar width in units.</li>
  79       * <li>$arrcode['bcode'][$k]['h'] bar height in units.</li>
  80       * <li>$arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)</li></ul>
  81       * @param string $code code to print
  82        * @param string $type type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
  83       */
  84  	public function __construct($code, $type) {
  85          $this->setBarcode($code, $type);
  86      }
  87      
  88      /** 
  89       * Return an array representations of barcode.
  90        * @return array
  91       */
  92  	public function getBarcodeArray() {
  93          return $this->barcode_array;
  94      }
  95      
  96      /** 
  97       * Set the barcode.
  98       * @param string $code code to print
  99        * @param string $type type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
 100        * @return array
 101       */
 102  	public function setBarcode($code, $type) {
 103          switch (strtoupper($type)) {
 104              case 'C39': { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
 105                  $arrcode = $this->barcode_code39($code, false, false);
 106                  break;
 107              }
 108              case 'C39+': { // CODE 39 with checksum
 109                  $arrcode = $this->barcode_code39($code, false, true);
 110                  break;
 111              }
 112              case 'C39E': { // CODE 39 EXTENDED
 113                  $arrcode = $this->barcode_code39($code, true, false);
 114                  break;
 115              }
 116              case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM
 117                  $arrcode = $this->barcode_code39($code, true, true);
 118                  break;
 119              }
 120              case 'C93': { // CODE 93 - USS-93
 121                  $arrcode = $this->barcode_code93($code);
 122                  break;
 123              }
 124              case 'S25': { // Standard 2 of 5
 125                  $arrcode = $this->barcode_s25($code, false);
 126                  break;
 127              }
 128              case 'S25+': { // Standard 2 of 5 + CHECKSUM
 129                  $arrcode = $this->barcode_s25($code, true);
 130                  break;
 131              }
 132              case 'I25': { // Interleaved 2 of 5
 133                  $arrcode = $this->barcode_i25($code, false);
 134                  break;
 135              }
 136              case 'I25+': { // Interleaved 2 of 5 + CHECKSUM
 137                  $arrcode = $this->barcode_i25($code, true);
 138                  break;
 139              }
 140              case 'C128A': { // CODE 128 A
 141                  $arrcode = $this->barcode_c128($code, 'A');
 142                  break;
 143              }
 144              case 'C128B': { // CODE 128 B
 145                  $arrcode = $this->barcode_c128($code, 'B');
 146                  break;
 147              }
 148              case 'C128C': { // CODE 128 C
 149                  $arrcode = $this->barcode_c128($code, 'C');
 150                  break;
 151              }
 152              case 'EAN2': { // 2-Digits UPC-Based Extention
 153                  $arrcode = $this->barcode_eanext($code, 2);
 154                  break;
 155              }
 156              case 'EAN5': { // 5-Digits UPC-Based Extention
 157                  $arrcode = $this->barcode_eanext($code, 5);
 158                  break;
 159              }
 160              case 'EAN8': { // EAN 8
 161                  $arrcode = $this->barcode_eanupc($code, 8);
 162                  break;
 163              }
 164              case 'EAN13': { // EAN 13
 165                  $arrcode = $this->barcode_eanupc($code, 13);
 166                  break;
 167              }
 168              case 'UPCA': { // UPC-A
 169                  $arrcode = $this->barcode_eanupc($code, 12);
 170                  break;
 171              }
 172              case 'UPCE': { // UPC-E
 173                  $arrcode = $this->barcode_eanupc($code, 6);
 174                  break;
 175              }
 176              case 'MSI': { // MSI (Variation of Plessey code)
 177                  $arrcode = $this->barcode_msi($code, false);
 178                  break;
 179              }
 180              case 'MSI+': { // MSI + CHECKSUM (modulo 11)
 181                  $arrcode = $this->barcode_msi($code, true);
 182                  break;
 183              }
 184              case 'POSTNET': { // POSTNET
 185                  $arrcode = $this->barcode_postnet($code, false);
 186                  break;
 187              }
 188              case 'PLANET': { // PLANET
 189                  $arrcode = $this->barcode_postnet($code, true);
 190                  break;
 191              }
 192              case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
 193                  $arrcode = $this->barcode_rms4cc($code, false);
 194                  break;
 195              }
 196              case 'KIX': { // KIX (Klant index - Customer index)
 197                  $arrcode = $this->barcode_rms4cc($code, true);
 198                  break;
 199              }
 200              case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
 201                  $arrcode = $this->barcode_imb($code);
 202                  break;
 203              }
 204              case 'CODABAR': { // CODABAR
 205                  $arrcode = $this->barcode_codabar($code);
 206                  break;
 207              }
 208              case 'CODE11': { // CODE 11
 209                  $arrcode = $this->barcode_code11($code);
 210                  break;
 211              }
 212              case 'PHARMA': { // PHARMACODE
 213                  $arrcode = $this->barcode_pharmacode($code);
 214                  break;
 215              }
 216              case 'PHARMA2T': { // PHARMACODE TWO-TRACKS
 217                  $arrcode = $this->barcode_pharmacode2t($code);
 218                  break;
 219              }
 220              default: {
 221                  $this->barcode_array = false;
 222                  $arrcode = false;
 223                  break;
 224              }
 225          }
 226          $this->barcode_array = $arrcode;
 227      }
 228      
 229      /**
 230       * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
 231       * General-purpose code in very wide use world-wide
 232       * @param string $code code to represent.
 233       * @param boolean $checksum if true add a checksum to the code
 234       * @return array barcode representation.
 235       * @access protected
 236       */
 237  	protected function barcode_code39($code, $extended=false, $checksum=false) {
 238          $chr['0'] = '111221211';
 239          $chr['1'] = '211211112';
 240          $chr['2'] = '112211112';
 241          $chr['3'] = '212211111';
 242          $chr['4'] = '111221112';
 243          $chr['5'] = '211221111';
 244          $chr['6'] = '112221111';
 245          $chr['7'] = '111211212';
 246          $chr['8'] = '211211211';
 247          $chr['9'] = '112211211';
 248          $chr['A'] = '211112112';
 249          $chr['B'] = '112112112';
 250          $chr['C'] = '212112111';
 251          $chr['D'] = '111122112';
 252          $chr['E'] = '211122111';
 253          $chr['F'] = '112122111';
 254          $chr['G'] = '111112212';
 255          $chr['H'] = '211112211';
 256          $chr['I'] = '112112211';
 257          $chr['J'] = '111122211';
 258          $chr['K'] = '211111122';
 259          $chr['L'] = '112111122';
 260          $chr['M'] = '212111121';
 261          $chr['N'] = '111121122';
 262          $chr['O'] = '211121121';
 263          $chr['P'] = '112121121';
 264          $chr['Q'] = '111111222';
 265          $chr['R'] = '211111221';
 266          $chr['S'] = '112111221';
 267          $chr['T'] = '111121221';
 268          $chr['U'] = '221111112';
 269          $chr['V'] = '122111112';
 270          $chr['W'] = '222111111';
 271          $chr['X'] = '121121112';
 272          $chr['Y'] = '221121111';
 273          $chr['Z'] = '122121111';
 274          $chr['-'] = '121111212';
 275          $chr['.'] = '221111211';
 276          $chr[' '] = '122111211';
 277          $chr['$'] = '121212111';
 278          $chr['/'] = '121211121';
 279          $chr['+'] = '121112121';
 280          $chr['%'] = '111212121';
 281          $chr['*'] = '121121211';
 282          
 283          $code = strtoupper($code);
 284          if ($extended) {
 285              // extended mode
 286              $code = $this->encode_code39_ext($code);
 287          }
 288          if ($code === false) {
 289              return false;
 290          }
 291          if ($checksum) {
 292              // checksum
 293              $code .= $this->checksum_code39($code);
 294          }
 295          // add start and stop codes
 296          $code = '*'.$code.'*';
 297          
 298          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 299          $k = 0;
 300          $clen = strlen($code);
 301          for ($i = 0; $i < $clen; ++$i) {
 302              $char = $code{$i};
 303              if(!isset($chr[$char])) {
 304                  // invalid character
 305                  return false;
 306              }
 307              for ($j = 0; $j < 9; ++$j) {
 308                  if (($j % 2) == 0) {
 309                      $t = true; // bar
 310                  } else {
 311                      $t = false; // space
 312                  }
 313                  $w = $chr[$char]{$j};
 314                  $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 315                  $bararray['maxw'] += $w;
 316                  ++$k;
 317              }
 318              $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0);
 319              $bararray['maxw'] += 1;
 320              ++$k;
 321          }
 322          return $bararray;
 323      }
 324      
 325      /**
 326       * Encode a string to be used for CODE 39 Extended mode.
 327       * @param string $code code to represent.
 328       * @return encoded string.
 329       * @access protected
 330       */
 331  	protected function encode_code39_ext($code) {
 332          $encode = array(
 333              chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
 334              chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
 335              chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
 336              chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
 337              chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
 338              chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
 339              chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
 340              chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
 341              chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
 342              chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
 343              chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
 344              chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
 345              chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
 346              chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
 347              chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
 348              chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
 349              chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
 350              chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
 351              chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
 352              chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
 353              chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
 354              chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
 355              chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
 356              chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
 357              chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
 358              chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
 359              chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
 360              chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
 361              chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
 362              chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
 363              chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
 364              chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
 365          $code_ext = '';
 366          $clen = strlen($code);
 367          for ($i = 0 ; $i < $clen; ++$i) {
 368              if (ord($code{$i}) > 127) {
 369                  return false;
 370              }
 371              $code_ext .= $encode[$code{$i}];
 372          }
 373          return $code_ext;
 374      }
 375      
 376      /**
 377       * Calculate CODE 39 checksum (modulo 43).
 378       * @param string $code code to represent.
 379       * @return char checksum.
 380       * @access protected
 381       */
 382  	protected function checksum_code39($code) {
 383          $chars = array(
 384              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 385              'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
 386              'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 387              'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
 388          $sum = 0;
 389          $clen = strlen($code);
 390          for ($i = 0 ; $i < $clen; ++$i) {
 391              $k = array_keys($chars, $code{$i});
 392              $sum += $k[0];
 393          }
 394          $j = ($sum % 43);
 395          return $chars[$j];
 396      }
 397      
 398      /**
 399       * CODE 93 - USS-93
 400       * Compact code similar to Code 39
 401       * @param string $code code to represent.
 402       * @param boolean $checksum if true add a checksum to the code
 403       * @return array barcode representation.
 404       * @access protected
 405       */
 406  	protected function barcode_code93($code) {
 407          $chr['0'] = '131112';
 408          $chr['1'] = '111213';
 409          $chr['2'] = '111312';
 410          $chr['3'] = '111411';
 411          $chr['4'] = '121113';
 412          $chr['5'] = '121212';
 413          $chr['6'] = '121311';
 414          $chr['7'] = '111114';
 415          $chr['8'] = '131211';
 416          $chr['9'] = '141111';
 417          $chr['A'] = '211113';
 418          $chr['B'] = '211212';
 419          $chr['C'] = '211311';
 420          $chr['D'] = '221112';
 421          $chr['E'] = '221211';
 422          $chr['F'] = '231111';
 423          $chr['G'] = '112113';
 424          $chr['H'] = '112212';
 425          $chr['I'] = '112311';
 426          $chr['J'] = '122112';
 427          $chr['K'] = '132111';
 428          $chr['L'] = '111123';
 429          $chr['M'] = '111222';
 430          $chr['N'] = '111321';
 431          $chr['O'] = '121122';
 432          $chr['P'] = '131121';
 433          $chr['Q'] = '212112';
 434          $chr['R'] = '212211';
 435          $chr['S'] = '211122';
 436          $chr['T'] = '211221';
 437          $chr['U'] = '221121';
 438          $chr['V'] = '222111';
 439          $chr['W'] = '112122';
 440          $chr['X'] = '112221';
 441          $chr['Y'] = '122121';
 442          $chr['Z'] = '123111';
 443          $chr['-'] = '121131';
 444          $chr['.'] = '311112';
 445          $chr[' '] = '311211';
 446          $chr['$'] = '321111';
 447          $chr['/'] = '112131';
 448          $chr['+'] = '113121';
 449          $chr['%'] = '211131';
 450          $chr[128] = '121221'; // ($)
 451          $chr[129] = '311121'; // (/)
 452          $chr[130] = '122211'; // (+)
 453          $chr[131] = '312111'; // (%)
 454          $chr['*'] = '111141';
 455          $code = strtoupper($code);
 456          $encode = array(
 457              chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C',
 458              chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G',
 459              chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K',
 460              chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O',
 461              chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S',
 462              chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W',
 463              chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A',
 464              chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E',
 465              chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C',
 466              chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G',
 467              chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K',
 468              chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O',
 469              chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
 470              chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
 471              chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F',
 472              chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J',
 473              chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
 474              chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
 475              chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
 476              chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
 477              chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
 478              chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
 479              chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K',
 480              chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O',
 481              chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C',
 482              chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G',
 483              chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K',
 484              chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O',
 485              chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S',
 486              chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W',
 487              chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P',
 488              chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T');
 489          $code_ext = '';
 490          $clen = strlen($code);
 491          for ($i = 0 ; $i < $clen; ++$i) {
 492              if (ord($code{$i}) > 127) {
 493                  return false;
 494              }
 495              $code_ext .= $encode[$code{$i}];
 496          }
 497          // checksum
 498          $code .= $this->checksum_code93($code);
 499          // add start and stop codes
 500          $code = '*'.$code.'*';
 501          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 502          $k = 0;
 503          $clen = strlen($code);
 504          for ($i = 0; $i < $clen; ++$i) {
 505              $char = $code{$i};
 506              if(!isset($chr[$char])) {
 507                  // invalid character
 508                  return false;
 509              }
 510              for ($j = 0; $j < 6; ++$j) {
 511                  if (($j % 2) == 0) {
 512                      $t = true; // bar
 513                  } else {
 514                      $t = false; // space
 515                  }
 516                  $w = $chr[$char]{$j};
 517                  $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 518                  $bararray['maxw'] += $w;
 519                  ++$k;
 520              }
 521          }
 522          $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0);
 523          $bararray['maxw'] += 1;
 524          ++$k;        
 525          return $bararray;
 526      }
 527      
 528      /**
 529       * Calculate CODE 93 checksum (modulo 47).
 530       * @param string $code code to represent.
 531       * @return string checksum code.
 532       * @access protected
 533       */
 534  	protected function checksum_code93($code) {
 535          $chars = array(
 536              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 537              'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
 538              'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 539              'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
 540          // translate special characters
 541          $code = strtr($code, chr(128).chr(129).chr(130).chr(131), '$/+%');    
 542          $len = strlen($code);
 543          // calculate check digit C
 544          $p = 1;
 545          $check = 0;
 546          for ($i = ($len - 1); $i >= 0; --$i) {
 547              $k = array_keys($chars, $code{$i});
 548              $check += ($k[0] * $p);
 549              ++$p;
 550              if ($p > 20) {
 551                  $p = 1;
 552              }
 553          }
 554          $check %= 47;
 555          $c = $chars[$check];
 556          $code .= $c;
 557          // calculate check digit K
 558          $p = 1;
 559          $check = 0;
 560          for ($i = $len; $i >= 0; --$i) {
 561              $k = array_keys($chars, $code{$i});
 562              $check += ($k[0] * $p);
 563              ++$p;
 564              if ($p > 15) {
 565                  $p = 1;
 566              }
 567          }
 568          $check %= 47;
 569          $k = $chars[$check];
 570          return $c.$k;
 571      }
 572      
 573      /**
 574       * Checksum for standard 2 of 5 barcodes.
 575       * @param string $code code to process.
 576       * @return int checksum.
 577       * @access protected
 578       */
 579  	protected function checksum_s25($code) {
 580          $len = strlen($code);
 581          $sum = 0;
 582          for ($i = 0; $i < $len; $i+=2) {
 583              $sum += $code{$i};
 584          }
 585          $sum *= 3;
 586          for ($i = 1; $i < $len; $i+=2) {
 587              $sum += ($code{$i});
 588          }
 589          $r = $sum % 10;
 590          if($r > 0) {
 591              $r = (10 - $r);
 592          }
 593          return $r;
 594      }
 595      
 596      /**
 597       * MSI.
 598       * Variation of Plessey code, with similar applications 
 599       * Contains digits (0 to 9) and encodes the data only in the width of bars.
 600       * @param string $code code to represent.
 601       * @param boolean $checksum if true add a checksum to the code (modulo 11)
 602       * @return array barcode representation.
 603       * @access protected
 604       */
 605  	protected function barcode_msi($code, $checksum=false) {
 606          $chr['0'] = '100100100100';
 607          $chr['1'] = '100100100110';
 608          $chr['2'] = '100100110100';
 609          $chr['3'] = '100100110110';
 610          $chr['4'] = '100110100100';
 611          $chr['5'] = '100110100110';
 612          $chr['6'] = '100110110100';
 613          $chr['7'] = '100110110110';
 614          $chr['8'] = '110100100100';
 615          $chr['9'] = '110100100110';
 616          $chr['A'] = '110100110100';
 617          $chr['B'] = '110100110110';
 618          $chr['C'] = '110110100100';
 619          $chr['D'] = '110110100110';
 620          $chr['E'] = '110110110100';
 621          $chr['F'] = '110110110110';
 622          if ($checksum) {
 623              // add checksum
 624              $clen = strlen($code);
 625              $p = 2;
 626              $check = 0;
 627              for ($i = ($clen - 1); $i >= 0; --$i) {
 628                  $check += (hexdec($code{$i}) * $p);
 629                  ++$p;
 630                  if ($p > 7) {
 631                      $p = 2;
 632                  }
 633              }
 634              $check %= 11;
 635              if ($check > 0) {
 636                  $check = 11 - $check;
 637              }
 638              $code .= $check;
 639          }
 640          $seq = '110'; // left guard
 641          $clen = strlen($code);
 642          for ($i = 0; $i < $clen; ++$i) {
 643              $digit = $code{$i};
 644              if (!isset($chr[$digit])) {
 645                  // invalid character
 646                  return false;
 647              }
 648              $seq .= $chr[$digit];
 649          }        
 650          $seq .= '1001'; // right guard
 651          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 652          return $this->binseq_to_array($seq, $bararray);
 653      }
 654      
 655      /**
 656       * Standard 2 of 5 barcodes.
 657       * Used in airline ticket marking, photofinishing
 658       * Contains digits (0 to 9) and encodes the data only in the width of bars.
 659       * @param string $code code to represent.
 660       * @param boolean $checksum if true add a checksum to the code
 661       * @return array barcode representation.
 662       * @access protected
 663       */
 664  	protected function barcode_s25($code, $checksum=false) {
 665          $chr['0'] = '10101110111010';
 666          $chr['1'] = '11101010101110';
 667          $chr['2'] = '10111010101110';
 668          $chr['3'] = '11101110101010';
 669          $chr['4'] = '10101110101110';
 670          $chr['5'] = '11101011101010';
 671          $chr['6'] = '10111011101010';
 672          $chr['7'] = '10101011101110';
 673          $chr['8'] = '10101110111010';
 674          $chr['9'] = '10111010111010';
 675          if ($checksum) {
 676              // add checksum
 677              $code .= $this->checksum_s25($code);
 678          }
 679          if((strlen($code) % 2) != 0) {
 680              // add leading zero if code-length is odd
 681              $code = '0'.$code;
 682          }
 683          $seq = '11011010';
 684          $clen = strlen($code);
 685          for ($i = 0; $i < $clen; ++$i) {
 686              $digit = $code{$i};
 687              if (!isset($chr[$digit])) {
 688                  // invalid character
 689                  return false;
 690              }
 691              $seq .= $chr[$digit];
 692          }        
 693          $seq .= '1101011';
 694          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 695          return $this->binseq_to_array($seq, $bararray);
 696      }
 697      
 698      /**
 699       * Convert binary barcode sequence to TCPDF barcode array
 700       * @param string $seq barcode as binary sequence
 701       * òparam array $bararray TCPDF barcode array to fill up
 702       * @return array barcode representation.
 703       * @access protected
 704       */
 705  	protected function binseq_to_array($seq, $bararray) {
 706          $len = strlen($seq);
 707          $w = 0;
 708          $k = 0;
 709          for ($i = 0; $i < $len; ++$i) {
 710              $w += 1;
 711              if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
 712                  if ($seq{$i} == '1') {
 713                      $t = true; // bar
 714                  } else {
 715                      $t = false; // space
 716                  }
 717                  $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 718                  $bararray['maxw'] += $w;
 719                  ++$k;
 720                  $w = 0;
 721              }
 722          }
 723          return $bararray;
 724      }
 725      
 726      /**
 727       * Interleaved 2 of 5 barcodes.
 728       * Compact numeric code, widely used in industry, air cargo
 729       * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
 730       * @param string $code code to represent.
 731       * @param boolean $checksum if true add a checksum to the code
 732       * @return array barcode representation.
 733       * @access protected
 734       */
 735  	protected function barcode_i25($code, $checksum=false) {
 736          $chr['0'] = '11221';
 737          $chr['1'] = '21112';
 738          $chr['2'] = '12112';
 739          $chr['3'] = '22111';
 740          $chr['4'] = '11212';
 741          $chr['5'] = '21211';
 742          $chr['6'] = '12211';
 743          $chr['7'] = '11122';
 744          $chr['8'] = '21121';
 745          $chr['9'] = '12121';
 746          $chr['A'] = '11';
 747          $chr['Z'] = '21';
 748          if ($checksum) {
 749              // add checksum
 750              $code .= $this->checksum_s25($code);
 751          }
 752          if((strlen($code) % 2) != 0) {
 753              // add leading zero if code-length is odd
 754              $code = '0'.$code;
 755          }
 756          // add start and stop codes
 757          $code = 'AA'.strtolower($code).'ZA';
 758              
 759          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 760          $k = 0;
 761          $clen = strlen($code);
 762          for ($i = 0; $i < $clen; $i = ($i + 2)) {
 763              $char_bar = $code{$i};
 764              $char_space = $code{$i+1};
 765              if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
 766                  // invalid character
 767                  return false;
 768              }
 769              // create a bar-space sequence
 770              $seq = '';
 771              $chrlen = strlen($chr[$char_bar]);
 772              for ($s = 0; $s < $chrlen; $s++){
 773                  $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
 774              }
 775              $seqlen = strlen($seq);
 776              for ($j = 0; $j < $seqlen; ++$j) {
 777                  if (($j % 2) == 0) {
 778                      $t = true; // bar
 779                  } else {
 780                      $t = false; // space
 781                  }
 782                  $w = $seq{$j};
 783                  $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 784                  $bararray['maxw'] += $w;
 785                  ++$k;
 786              }
 787          }
 788          return $bararray;
 789      }
 790      
 791      /**
 792       * C128 barcodes. 
 793       * Very capable code, excellent density, high reliability; in very wide use world-wide
 794       * @param string $code code to represent.
 795       * @param string $type barcode type: A, B or C
 796       * @return array barcode representation.
 797       * @access protected
 798       */
 799  	protected function barcode_c128($code, $type='B') {
 800          $chr = array(
 801              '212222', /* 00 */
 802              '222122', /* 01 */
 803              '222221', /* 02 */
 804              '121223', /* 03 */
 805              '121322', /* 04 */
 806              '131222', /* 05 */
 807              '122213', /* 06 */
 808              '122312', /* 07 */
 809              '132212', /* 08 */
 810              '221213', /* 09 */
 811              '221312', /* 10 */
 812              '231212', /* 11 */
 813              '112232', /* 12 */
 814              '122132', /* 13 */
 815              '122231', /* 14 */
 816              '113222', /* 15 */
 817              '123122', /* 16 */
 818              '123221', /* 17 */
 819              '223211', /* 18 */
 820              '221132', /* 19 */
 821              '221231', /* 20 */
 822              '213212', /* 21 */
 823              '223112', /* 22 */
 824              '312131', /* 23 */
 825              '311222', /* 24 */
 826              '321122', /* 25 */
 827              '321221', /* 26 */
 828              '312212', /* 27 */
 829              '322112', /* 28 */
 830              '322211', /* 29 */
 831              '212123', /* 30 */
 832              '212321', /* 31 */
 833              '232121', /* 32 */
 834              '111323', /* 33 */
 835              '131123', /* 34 */
 836              '131321', /* 35 */
 837              '112313', /* 36 */
 838              '132113', /* 37 */
 839              '132311', /* 38 */
 840              '211313', /* 39 */
 841              '231113', /* 40 */
 842              '231311', /* 41 */
 843              '112133', /* 42 */
 844              '112331', /* 43 */
 845              '132131', /* 44 */
 846              '113123', /* 45 */
 847              '113321', /* 46 */
 848              '133121', /* 47 */
 849              '313121', /* 48 */
 850              '211331', /* 49 */
 851              '231131', /* 50 */
 852              '213113', /* 51 */
 853              '213311', /* 52 */
 854              '213131', /* 53 */
 855              '311123', /* 54 */
 856              '311321', /* 55 */
 857              '331121', /* 56 */
 858              '312113', /* 57 */
 859              '312311', /* 58 */
 860              '332111', /* 59 */
 861              '314111', /* 60 */
 862              '221411', /* 61 */
 863              '431111', /* 62 */
 864              '111224', /* 63 */
 865              '111422', /* 64 */
 866              '121124', /* 65 */
 867              '121421', /* 66 */
 868              '141122', /* 67 */
 869              '141221', /* 68 */
 870              '112214', /* 69 */
 871              '112412', /* 70 */
 872              '122114', /* 71 */
 873              '122411', /* 72 */
 874              '142112', /* 73 */
 875              '142211', /* 74 */
 876              '241211', /* 75 */
 877              '221114', /* 76 */
 878              '413111', /* 77 */
 879              '241112', /* 78 */
 880              '134111', /* 79 */
 881              '111242', /* 80 */
 882              '121142', /* 81 */
 883              '121241', /* 82 */
 884              '114212', /* 83 */
 885              '124112', /* 84 */
 886              '124211', /* 85 */
 887              '411212', /* 86 */
 888              '421112', /* 87 */
 889              '421211', /* 88 */
 890              '212141', /* 89 */
 891              '214121', /* 90 */
 892              '412121', /* 91 */
 893              '111143', /* 92 */
 894              '111341', /* 93 */
 895              '131141', /* 94 */
 896              '114113', /* 95 */
 897              '114311', /* 96 */
 898              '411113', /* 97 */
 899              '411311', /* 98 */
 900              '113141', /* 99 */
 901              '114131', /* 100 */
 902              '311141', /* 101 */
 903              '411131', /* 102 */
 904              '211412', /* 103 START A */
 905              '211214', /* 104 START B  */
 906              '211232', /* 105 START C  */
 907              '233111', /* STOP */
 908              '200000'  /* END */
 909          );
 910          $keys = '';
 911          switch(strtoupper($type)) {
 912              case 'A': {
 913                  $startid = 103;
 914                  $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
 915                  for ($i = 0; $i < 32; ++$i) {
 916                      $keys .= chr($i);
 917                  }
 918                  break;
 919              }
 920              case 'B': {
 921                  $startid = 104;
 922                  $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
 923                  break;
 924              }
 925              case 'C': {
 926                  $startid = 105;
 927                  $keys = '';
 928                  if ((strlen($code) % 2) != 0) {
 929                      // The length of barcode value must be even ($code). You must pad the number with zeros
 930                      return false;
 931                  }
 932                  for ($i = 0; $i <= 99; ++$i) {
 933                      $keys .= chr($i);
 934                  }
 935                  $new_code = '';
 936                  $hclen = (strlen($code) / 2);
 937                  for ($i = 0; $i < $hclen; ++$i) {
 938                      $new_code .= chr(intval($code{(2 * $i)}.$code{(2 * $i + 1)}));
 939                  }
 940                  $code = $new_code;
 941                  break;
 942              }
 943              default: {
 944                  return false;
 945              }
 946          }
 947          // calculate check character
 948          $sum = $startid;
 949          $clen = strlen($code);
 950          for ($i = 0; $i < $clen; ++$i) {
 951              $sum +=  (strpos($keys, $code{$i}) * ($i+1));
 952          }
 953          $check = ($sum % 103);
 954          // add start, check and stop codes
 955          $code = chr($startid).$code.chr($check).chr(106).chr(107);
 956          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 957          $k = 0;
 958          $len = strlen($code);
 959          for ($i = 0; $i < $len; ++$i) {
 960              $ck = strpos($keys, $code{$i});
 961              if (($i == 0) OR ($i > ($len-4))) {
 962                  $char_num = ord($code{$i});
 963                  $seq = $chr[$char_num];
 964              } elseif(($ck >= 0) AND isset($chr[$ck])) {
 965                      $seq = $chr[$ck];
 966              } else {
 967                  // invalid character
 968                  return false;
 969              }
 970              for ($j = 0; $j < 6; ++$j) {
 971                  if (($j % 2) == 0) {
 972                      $t = true; // bar
 973                  } else {
 974                      $t = false; // space
 975                  }
 976                  $w = $seq{$j};
 977                  $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 978                  $bararray['maxw'] += $w;
 979                  ++$k;
 980              }
 981          }
 982          return $bararray;        
 983      }
 984      
 985      /**
 986       * EAN13 and UPC-A barcodes.
 987       * EAN13: European Article Numbering international retail product code
 988       * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
 989       * UPC-E: Short version of UPC symbol
 990       * @param string $code code to represent.
 991       * @param string $len barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
 992       * @return array barcode representation.
 993       * @access protected
 994       */
 995  	protected function barcode_eanupc($code, $len=13) {
 996          $upce = false;
 997          if ($len == 6) {
 998              $len = 12; // UPC-A
 999              $upce = true; // UPC-E mode
1000          }
1001          $data_len = $len - 1;
1002          //Padding
1003          $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
1004          $code_len = strlen($code);
1005          // calculate check digit
1006          $sum_a = 0;
1007          for ($i = 1; $i < $data_len; $i+=2) {
1008              $sum_a += $code{$i};
1009          }
1010          if ($len > 12) {
1011              $sum_a *= 3;
1012          }
1013          $sum_b = 0;
1014          for ($i = 0; $i < $data_len; $i+=2) {
1015              $sum_b += ($code{$i});
1016          }
1017          if ($len < 13) {
1018              $sum_b *= 3;
1019          }
1020          $r = ($sum_a + $sum_b) % 10;
1021          if($r > 0) {
1022              $r = (10 - $r);
1023          }
1024          if ($code_len == $data_len) {
1025              // add check digit
1026              $code .= $r;
1027          } elseif ($r !== intval($code{$data_len})) {
1028              // wrong checkdigit
1029              return false;
1030          }
1031          if ($len == 12) {
1032              // UPC-A
1033              $code = '0'.$code;
1034              ++$len;
1035          }
1036          if ($upce) {
1037              // convert UPC-A to UPC-E
1038              $tmp = substr($code, 4, 3);
1039              if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
1040                  // manufacturer code ends in 000, 100, or 200
1041                  $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
1042              } else {
1043                  $tmp = substr($code, 5, 2);
1044                  if ($tmp == '00') {
1045                      // manufacturer code ends in 00
1046                      $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
1047                  } else {
1048                      $tmp = substr($code, 6, 1);
1049                      if ($tmp == '0') {
1050                          // manufacturer code ends in 0
1051                          $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
1052                      } else {
1053                          // manufacturer code does not end in zero
1054                          $upce_code = substr($code, 2, 5).substr($code, 11, 1);
1055                      }
1056                  }
1057              }
1058          }
1059          //Convert digits to bars
1060          $codes = array(
1061              'A'=>array( // left odd parity
1062                  '0'=>'0001101',
1063                  '1'=>'0011001',
1064                  '2'=>'0010011',
1065                  '3'=>'0111101',
1066                  '4'=>'0100011',
1067                  '5'=>'0110001',
1068                  '6'=>'0101111',
1069                  '7'=>'0111011',
1070                  '8'=>'0110111',
1071                  '9'=>'0001011'),
1072              'B'=>array( // left even parity
1073                  '0'=>'0100111',
1074                  '1'=>'0110011',
1075                  '2'=>'0011011',
1076                  '3'=>'0100001',
1077                  '4'=>'0011101',
1078                  '5'=>'0111001',
1079                  '6'=>'0000101',
1080                  '7'=>'0010001',
1081                  '8'=>'0001001',
1082                  '9'=>'0010111'),
1083              'C'=>array( // right
1084                  '0'=>'1110010',
1085                  '1'=>'1100110',
1086                  '2'=>'1101100',
1087                  '3'=>'1000010',
1088                  '4'=>'1011100',
1089                  '5'=>'1001110',
1090                  '6'=>'1010000',
1091                  '7'=>'1000100',
1092                  '8'=>'1001000',
1093                  '9'=>'1110100')
1094          );
1095          $parities = array(
1096              '0'=>array('A','A','A','A','A','A'),
1097              '1'=>array('A','A','B','A','B','B'),
1098              '2'=>array('A','A','B','B','A','B'),
1099              '3'=>array('A','A','B','B','B','A'),
1100              '4'=>array('A','B','A','A','B','B'),
1101              '5'=>array('A','B','B','A','A','B'),
1102              '6'=>array('A','B','B','B','A','A'),
1103              '7'=>array('A','B','A','B','A','B'),
1104              '8'=>array('A','B','A','B','B','A'),
1105              '9'=>array('A','B','B','A','B','A')
1106          );
1107          $upce_parities = array();
1108          $upce_parities[0] = array(
1109              '0'=>array('B','B','B','A','A','A'),
1110              '1'=>array('B','B','A','B','A','A'),
1111              '2'=>array('B','B','A','A','B','A'),
1112              '3'=>array('B','B','A','A','A','B'),
1113              '4'=>array('B','A','B','B','A','A'),
1114              '5'=>array('B','A','A','B','B','A'),
1115              '6'=>array('B','A','A','A','B','B'),
1116              '7'=>array('B','A','B','A','B','A'),
1117              '8'=>array('B','A','B','A','A','B'),
1118              '9'=>array('B','A','A','B','A','B')
1119          );
1120          $upce_parities[1] = array(
1121              '0'=>array('A','A','A','B','B','B'),
1122              '1'=>array('A','A','B','A','B','B'),
1123              '2'=>array('A','A','B','B','A','B'),
1124              '3'=>array('A','A','B','B','B','A'),
1125              '4'=>array('A','B','A','A','B','B'),
1126              '5'=>array('A','B','B','A','A','B'),
1127              '6'=>array('A','B','B','B','A','A'),
1128              '7'=>array('A','B','A','B','A','B'),
1129              '8'=>array('A','B','A','B','B','A'),
1130              '9'=>array('A','B','B','A','B','A')
1131          );
1132          $k = 0;
1133          $seq = '101'; // left guard bar
1134          if ($upce) {
1135              $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1136              $p = $upce_parities[$code{1}][$r];
1137              for ($i = 0; $i < 6; ++$i) {
1138                  $seq .= $codes[$p[$i]][$upce_code{$i}];
1139              }
1140              $seq .= '010101'; // right guard bar
1141          } else {
1142              $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1143              $half_len = ceil($len / 2);
1144              if ($len == 8) {
1145                  for ($i = 0; $i < $half_len; ++$i) {
1146                      $seq .= $codes['A'][$code{$i}];
1147                  }
1148              } else {
1149                  $p = $parities[$code{0}];
1150                  for ($i = 1; $i < $half_len; ++$i) {
1151                      $seq .= $codes[$p[$i-1]][$code{$i}];
1152                  }
1153              }
1154              $seq .= '01010'; // center guard bar
1155              for ($i = $half_len; $i < $len; ++$i) {
1156                  $seq .= $codes['C'][$code{$i}];
1157              }
1158              $seq .= '101'; // right guard bar
1159          }
1160          $clen = strlen($seq);
1161          $w = 0;
1162          for ($i = 0; $i < $clen; ++$i) {
1163              $w += 1;
1164              if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
1165                  if ($seq{$i} == '1') {
1166                      $t = true; // bar
1167                  } else {
1168                      $t = false; // space
1169                  }
1170                  $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1171                  $bararray['maxw'] += $w;
1172                  ++$k;
1173                  $w = 0;
1174              }
1175          }
1176          return $bararray;
1177      }
1178      
1179      /**
1180       * UPC-Based Extentions
1181       * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
1182       * 5-Digit Ext.: Used to mark suggested retail price of books
1183       * @param string $code code to represent.
1184       * @param string $len barcode type: 2 = 2-Digit, 5 = 5-Digit
1185       * @return array barcode representation.
1186       * @access protected
1187       */
1188  	protected function barcode_eanext($code, $len=5) {
1189          //Padding
1190          $code = str_pad($code, $len, '0', STR_PAD_LEFT);
1191          // calculate check digit
1192          if ($len == 2) {
1193              $r = $code % 4;
1194          } elseif ($len == 5) {
1195              $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3}));
1196              $r %= 10;
1197          } else {
1198              return false;
1199          }
1200          //Convert digits to bars
1201          $codes = array(
1202              'A'=>array( // left odd parity
1203                  '0'=>'0001101',
1204                  '1'=>'0011001',
1205                  '2'=>'0010011',
1206                  '3'=>'0111101',
1207                  '4'=>'0100011',
1208                  '5'=>'0110001',
1209                  '6'=>'0101111',
1210                  '7'=>'0111011',
1211                  '8'=>'0110111',
1212                  '9'=>'0001011'),
1213              'B'=>array( // left even parity
1214                  '0'=>'0100111',
1215                  '1'=>'0110011',
1216                  '2'=>'0011011',
1217                  '3'=>'0100001',
1218                  '4'=>'0011101',
1219                  '5'=>'0111001',
1220                  '6'=>'0000101',
1221                  '7'=>'0010001',
1222                  '8'=>'0001001',
1223                  '9'=>'0010111')
1224          );
1225          $parities = array();
1226          $parities[2] = array(
1227              '0'=>array('A','A'),
1228              '1'=>array('A','B'),
1229              '2'=>array('B','A'),
1230              '3'=>array('B','B')
1231          );
1232          $parities[5] = array(
1233              '0'=>array('B','B','A','A','A'),
1234              '1'=>array('B','A','B','A','A'),
1235              '2'=>array('B','A','A','B','A'),
1236              '3'=>array('B','A','A','A','B'),
1237              '4'=>array('A','B','B','A','A'),
1238              '5'=>array('A','A','B','B','A'),
1239              '6'=>array('A','A','A','B','B'),
1240              '7'=>array('A','B','A','B','A'),
1241              '8'=>array('A','B','A','A','B'),
1242              '9'=>array('A','A','B','A','B')
1243          );    
1244          $p = $parities[$len][$r];
1245          $seq = '1011'; // left guard bar
1246          $seq .= $codes[$p[0]][$code{0}];
1247          for ($i = 1; $i < $len; ++$i) {
1248              $seq .= '01'; // separator
1249              $seq .= $codes[$p[$i]][$code{$i}];
1250          }
1251          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1252          return $this->binseq_to_array($seq, $bararray);
1253      }
1254      
1255      /**
1256       * POSTNET and PLANET barcodes.
1257       * Used by U.S. Postal Service for automated mail sorting
1258       * @param string $code zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
1259       * @param boolean $planet if true print the PLANET barcode, otherwise print POSTNET
1260       * @return array barcode representation.
1261       * @access protected
1262       */
1263  	protected function barcode_postnet($code, $planet=false) {
1264          // bar lenght
1265          if ($planet) {
1266              $barlen = Array(
1267                  0 => Array(1,1,2,2,2),
1268                  1 => Array(2,2,2,1,1),
1269                  2 => Array(2,2,1,2,1),
1270                  3 => Array(2,2,1,1,2),
1271                  4 => Array(2,1,2,2,1),
1272                  5 => Array(2,1,2,1,2),
1273                  6 => Array(2,1,1,2,2),
1274                  7 => Array(1,2,2,2,1),
1275                  8 => Array(1,2,2,1,2),
1276                  9 => Array(1,2,1,2,2)
1277              );
1278          } else {
1279              $barlen = Array(
1280                  0 => Array(2,2,1,1,1),
1281                  1 => Array(1,1,1,2,2),
1282                  2 => Array(1,1,2,1,2),
1283                  3 => Array(1,1,2,2,1),
1284                  4 => Array(1,2,1,1,2),
1285                  5 => Array(1,2,1,2,1),
1286                  6 => Array(1,2,2,1,1),
1287                  7 => Array(2,1,1,1,2),
1288                  8 => Array(2,1,1,2,1),
1289                  9 => Array(2,1,2,1,1)
1290              );
1291          }
1292          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1293          $k = 0;
1294          $code = str_replace('-', '', $code);
1295          $code = str_replace(' ', '', $code);
1296          $len = strlen($code);
1297          // calculate checksum
1298          $sum = 0;
1299          for ($i = 0; $i < $len; ++$i) {
1300              $sum += intval($code{$i});
1301          }
1302          $chkd = ($sum % 10);
1303          if($chkd > 0) {
1304              $chkd = (10 - $chkd);
1305          }
1306          $code .= $chkd;
1307          $len = strlen($code);
1308          // start bar
1309          $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1310          $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1311          $bararray['maxw'] += 2;
1312          for ($i = 0; $i < $len; ++$i) {
1313              for ($j = 0; $j < 5; ++$j) {
1314                  $h = $barlen[$code{$i}][$j];
1315                  $p = floor(1 / $h);
1316                  $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1317                  $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1318                  $bararray['maxw'] += 2;
1319              }
1320          }
1321          // end bar
1322          $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1323          $bararray['maxw'] += 1;
1324          return $bararray;
1325      }
1326      
1327      /**
1328       * RMS4CC - CBC - KIX
1329       * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
1330       * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
1331       * @param string $code code to print
1332       * @param boolean $kix if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the code.
1333       * @return array barcode representation.
1334       * @access protected
1335       */
1336  	protected function barcode_rms4cc($code, $kix=false) {
1337          $notkix = !$kix;
1338          // bar mode
1339          // 1 = pos 1, length 2
1340          // 2 = pos 1, length 3
1341          // 3 = pos 2, length 1
1342          // 4 = pos 2, length 2
1343          $barmode = array(
1344              '0' => array(3,3,2,2),
1345              '1' => array(3,4,1,2),
1346              '2' => array(3,4,2,1),
1347              '3' => array(4,3,1,2),
1348              '4' => array(4,3,2,1),
1349              '5' => array(4,4,1,1),
1350              '6' => array(3,1,4,2),
1351              '7' => array(3,2,3,2),
1352              '8' => array(3,2,4,1),
1353              '9' => array(4,1,3,2),
1354              'A' => array(4,1,4,1),
1355              'B' => array(4,2,3,1),
1356              'C' => array(3,1,2,4),
1357              'D' => array(3,2,1,4),
1358              'E' => array(3,2,2,3),
1359              'F' => array(4,1,1,4),
1360              'G' => array(4,1,2,3),
1361              'H' => array(4,2,1,3),
1362              'I' => array(1,3,4,2),
1363              'J' => array(1,4,3,2),
1364              'K' => array(1,4,4,1),
1365              'L' => array(2,3,3,2),
1366              'M' => array(2,3,4,1),
1367              'N' => array(2,4,3,1),
1368              'O' => array(1,3,2,4),
1369              'P' => array(1,4,1,4),
1370              'Q' => array(1,4,2,3),
1371              'R' => array(2,3,1,4),
1372              'S' => array(2,3,2,3),
1373              'T' => array(2,4,1,3),
1374              'U' => array(1,1,4,4),
1375              'V' => array(1,2,3,4),
1376              'W' => array(1,2,4,3),
1377              'X' => array(2,1,3,4),
1378              'Y' => array(2,1,4,3),
1379              'Z' => array(2,2,3,3)        
1380          );
1381          $code = strtoupper($code);
1382          $len = strlen($code);
1383          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
1384          if ($notkix) {
1385              // table for checksum calculation (row,col)
1386              $checktable = array(
1387                  '0' => array(1,1),
1388                  '1' => array(1,2),
1389                  '2' => array(1,3),
1390                  '3' => array(1,4),
1391                  '4' => array(1,5),
1392                  '5' => array(1,0),
1393                  '6' => array(2,1),
1394                  '7' => array(2,2),
1395                  '8' => array(2,3),
1396                  '9' => array(2,4),
1397                  'A' => array(2,5),
1398                  'B' => array(2,0),
1399                  'C' => array(3,1),
1400                  'D' => array(3,2),
1401                  'E' => array(3,3),
1402                  'F' => array(3,4),
1403                  'G' => array(3,5),
1404                  'H' => array(3,0),
1405                  'I' => array(4,1),
1406                  'J' => array(4,2),
1407                  'K' => array(4,3),
1408                  'L' => array(4,4),
1409                  'M' => array(4,5),
1410                  'N' => array(4,0),
1411                  'O' => array(5,1),
1412                  'P' => array(5,2),
1413                  'Q' => array(5,3),
1414                  'R' => array(5,4),
1415                  'S' => array(5,5),
1416                  'T' => array(5,0),
1417                  'U' => array(0,1),
1418                  'V' => array(0,2),
1419                  'W' => array(0,3),
1420                  'X' => array(0,4),
1421                  'Y' => array(0,5),
1422                  'Z' => array(0,0)
1423              );
1424              $row = 0;
1425              $col = 0;
1426              for ($i = 0; $i < $len; ++$i) {
1427                  $row += $checktable[$code{$i}][0];
1428                  $col += $checktable[$code{$i}][1];
1429              }
1430              $row %= 6;
1431              $col %= 6;
1432              $chk = array_keys($checktable, array($row,$col));
1433              $code .= $chk[0];
1434              ++$len;
1435          }
1436          $k = 0;
1437          if ($notkix) {
1438              // start bar
1439              $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1440              $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1441              $bararray['maxw'] += 2;
1442          }
1443          for ($i = 0; $i < $len; ++$i) {
1444              for ($j = 0; $j < 4; ++$j) {
1445                  switch ($barmode[$code{$i}][$j]) {
1446                      case 1: {
1447                          $p = 0;
1448                          $h = 2;
1449                          break;
1450                      }
1451                      case 2: {
1452                          $p = 0;
1453                          $h = 3;
1454                          break;
1455                      }
1456                      case 3: {
1457                          $p = 1;
1458                          $h = 1;
1459                          break;
1460                      }
1461                      case 4: {
1462                          $p = 1;
1463                          $h = 2;
1464                          break;
1465                      }
1466                  }
1467                  $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1468                  $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1469                  $bararray['maxw'] += 2;
1470              }
1471          }
1472          if ($notkix) {
1473              // stop bar
1474              $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0);
1475              $bararray['maxw'] += 1;
1476          }
1477          return $bararray;
1478      }
1479      
1480      /**
1481       * CODABAR barcodes.
1482       * Older code often used in library systems, sometimes in blood banks
1483       * @param string $code code to represent.
1484       * @return array barcode representation.
1485       * @access protected
1486       */
1487  	protected function barcode_codabar($code) {
1488          $chr = array(
1489              '0' => '11111221',
1490              '1' => '11112211',
1491              '2' => '11121121',
1492              '3' => '22111111',
1493              '4' => '11211211',
1494              '5' => '21111211',
1495              '6' => '12111121',
1496              '7' => '12112111',
1497              '8' => '12211111',
1498              '9' => '21121111',
1499              '-' => '11122111',
1500              '$' => '11221111',
1501              ':' => '21112121',
1502              '/' => '21211121',
1503              '.' => '21212111',
1504              '+' => '11222221',
1505              'A' => '11221211',
1506              'B' => '12121121',
1507              'C' => '11121221',
1508              'D' => '11122211'
1509          );
1510          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1511          $k = 0;
1512          $w = 0;
1513          $seq = '';
1514          $code = 'A'.strtoupper($code).'A';
1515          $len = strlen($code);
1516          for ($i = 0; $i < $len; ++$i) {
1517              if (!isset($chr[$code{$i}])) {
1518                  return false;
1519              }
1520              $seq = $chr[$code{$i}];
1521              for ($j = 0; $j < 8; ++$j) {
1522                  if (($j % 2) == 0) {
1523                      $t = true; // bar
1524                  } else {
1525                      $t = false; // space
1526                  }
1527                  $w = $seq{$j};
1528                  $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1529                  $bararray['maxw'] += $w;
1530                  ++$k;
1531              }
1532          }
1533          return $bararray;
1534      }
1535      
1536      /**
1537       * CODE11 barcodes.
1538       * Used primarily for labeling telecommunications equipment
1539       * @param string $code code to represent.
1540       * @return array barcode representation.
1541       * @access protected
1542       */
1543  	protected function barcode_code11($code) {
1544          $chr = array(
1545              '0' => '111121',
1546              '1' => '211121',
1547              '2' => '121121',
1548              '3' => '221111',
1549              '4' => '112121',
1550              '5' => '212111',
1551              '6' => '122111',
1552              '7' => '111221',
1553              '8' => '211211',
1554              '9' => '211111',
1555              '-' => '112111',
1556              'S' => '112211'
1557          );
1558          
1559          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1560          $k = 0;
1561          $w = 0;
1562          $seq = '';
1563          $len = strlen($code);
1564          // calculate check digit C
1565          $p = 1;
1566          $check = 0;
1567          for ($i = ($len - 1); $i >= 0; --$i) {
1568              $digit = $code{$i};
1569              if ($digit == '-') {
1570                  $dval = 10;
1571              } else {
1572                  $dval = intval($digit);
1573              }
1574              $check += ($dval * $p);
1575              ++$p;
1576              if ($p > 10) {
1577                  $p = 1;
1578              }
1579          }
1580          $check %= 11;
1581          if ($check == 10) {
1582              $check = '-';
1583          } 
1584          $code .= $check;
1585          if ($len > 10) {
1586              // calculate check digit K
1587              $p = 1;
1588              $check = 0;
1589              for ($i = $len; $i >= 0; --$i) {
1590                  $digit = $code{$i};
1591                  if ($digit == '-') {
1592                      $dval = 10;
1593                  } else {
1594                      $dval = intval($digit);
1595                  }
1596                  $check += ($dval * $p);
1597                  ++$p;
1598                  if ($p > 9) {
1599                      $p = 1;
1600                  }
1601              }
1602              $check %= 11;
1603              $code .= $check;
1604              ++$len;
1605          }
1606          $code = 'S'.$code.'S';
1607          $len += 3;
1608          for ($i = 0; $i < $len; ++$i) {
1609              if (!isset($chr[$code{$i}])) {
1610                  return false;
1611              }
1612              $seq = $chr[$code{$i}];
1613              for ($j = 0; $j < 6; ++$j) {
1614                  if (($j % 2) == 0) {
1615                      $t = true; // bar
1616                  } else {
1617                      $t = false; // space
1618                  }
1619                  $w = $seq{$j};
1620                  $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1621                  $bararray['maxw'] += $w;
1622                  ++$k;
1623              }
1624          }
1625          return $bararray;
1626      }
1627      
1628      /**
1629       * Pharmacode
1630       * Contains digits (0 to 9)
1631       * @param string $code code to represent.
1632       * @return array barcode representation.
1633       * @access protected
1634       */
1635  	protected function barcode_pharmacode($code) {
1636          $seq = '';
1637          $code = intval($code);
1638          while ($code > 0) {
1639              if (($code % 2) == 0) {
1640                  $seq .= '11100';
1641                  $code -= 2;
1642              } else {
1643                  $seq .= '100';
1644                  $code -= 1;
1645              }
1646              $code /= 2;
1647          }
1648          $seq = substr($seq, 0, -2);
1649          $seq = strrev($seq);
1650          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1651          return $this->binseq_to_array($seq, $bararray);
1652      }
1653      
1654      /**
1655       * Pharmacode two-track
1656       * Contains digits (0 to 9)
1657       * @param string $code code to represent.
1658       * @return array barcode representation.
1659       * @access protected
1660       */
1661  	protected function barcode_pharmacode2t($code) {
1662          $seq = '';
1663          $code = intval($code);
1664          do {
1665              switch ($code % 3) {
1666                  case 0: {
1667                      $seq .= '3';
1668                      $code = ($code - 3) / 3;
1669                      break;
1670                  }
1671                  case 1: {
1672                      $seq .= '1';
1673                      $code = ($code - 1) / 3;
1674                      break;
1675                  }
1676                  case 2: {
1677                      $seq .= '2';
1678                      $code = ($code - 2) / 3;
1679                      break;
1680                  }
1681              }
1682          } while($code != 0);
1683          $seq = strrev($seq);
1684          $k = 0;
1685          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1686          $len = strlen($seq);
1687          for ($i = 0; $i < $len; ++$i) {
1688              switch ($seq{$i}) {
1689                  case '1': {
1690                      $p = 1;
1691                      $h = 1;
1692                      break;
1693                  }
1694                  case '2': {
1695                      $p = 0;
1696                      $h = 1;
1697                      break;
1698                  }
1699                  case '3': {
1700                      $p = 0;
1701                      $h = 2;
1702                      break;
1703                  }
1704              }
1705              $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1706              $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1707              $bararray['maxw'] += 2;
1708          }
1709          unset($bararray['bcode'][($k - 1)]);
1710          --$bararray['maxw'];
1711          return $bararray;
1712      }
1713      
1714      
1715      /**
1716       * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
1717       * (requires PHP bcmath extension) 
1718       * Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
1719       * The fields are described as follows:<ul><li>The Barcode Identifier shall be assigned by USPS to encode the presort identification that is currently printed in human readable form on the optional endorsement line (OEL) as well as for future USPS use. This shall be two digits, with the second digit in the range of 0–4. The allowable encoding ranges shall be 00–04, 10–14, 20–24, 30–34, 40–44, 50–54, 60–64, 70–74, 80–84, and 90–94.</li><li>The Service Type Identifier shall be assigned by USPS for any combination of services requested on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php–999. Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier values.</li><li>The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digit number that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000- 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.</li><li>The Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The allowable encoding range shall be 000000000–999999999 when used with a 6 digit Mailer ID and 000000-999999 when used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000–99999,  000000000–999999999, and 00000000000–99999999999.</li></ul>
1720       * @param string $code code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
1721       * @return array barcode representation.
1722       * @access protected
1723       */
1724  	protected function barcode_imb($code) {
1725          $asc_chr = 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);
1726          $dsc_chr = 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);
1727          $asc_pos = 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);
1728          $dsc_pos = 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);
1729          $code_arr = explode('-', $code);
1730          $tracking_number = $code_arr[0];
1731          if (isset($code_arr[1])) {
1732              $routing_code = $code_arr[1];
1733          } else {
1734              $routing_code = '';
1735          }
1736          // Conversion of Routing Code
1737          switch (strlen($routing_code)) {
1738              case 0: {
1739                  $binary_code = 0;
1740                  break;
1741              }
1742              case 5: {
1743                  $binary_code = bcadd($routing_code, '1');
1744                  break;
1745              }
1746              case 9: {
1747                  $binary_code = bcadd($routing_code, '100001');
1748                  break;
1749              }
1750              case 11: {
1751                  $binary_code = bcadd($routing_code, '1000100001');
1752                  break;
1753              }
1754              default: {
1755                  return false;
1756                  break;
1757              }
1758          }
1759          $binary_code = bcmul($binary_code, 10);
1760          $binary_code = bcadd($binary_code, $tracking_number{0});
1761          $binary_code = bcmul($binary_code, 5);
1762          $binary_code = bcadd($binary_code, $tracking_number{1});
1763          $binary_code .= substr($tracking_number, 2, 18);
1764          // convert to hexadecimal
1765          $binary_code = $this->dec_to_hex($binary_code);
1766          // pad to get 13 bytes
1767          $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
1768          // convert string to array of bytes
1769          $binary_code_arr = chunk_split($binary_code, 2, "\r");
1770          $binary_code_arr = substr($binary_code_arr, 0, -1);
1771          $binary_code_arr = explode("\r", $binary_code_arr);
1772          // calculate frame check sequence
1773          $fcs = $this->imb_crc11fcs($binary_code_arr);
1774          // exclude first 2 bits from first byte
1775          $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
1776          $binary_code_102bit = $first_byte.substr($binary_code, 2);
1777          // convert binary data to codewords
1778          $codewords = array();
1779          $data = $this->hex_to_dec($binary_code_102bit);
1780          $codewords[0] = bcmod($data, 636) * 2;
1781          $data = bcdiv($data, 636);
1782          for ($i = 1; $i < 9; ++$i) {
1783              $codewords[$i] = bcmod($data, 1365);
1784              $data = bcdiv($data, 1365);
1785          }
1786          $codewords[9] = $data;
1787          if (($fcs >> 10) == 1) {
1788              $codewords[9] += 659;
1789          }
1790          // generate lookup tables
1791          $table2of13 = $this->imb_tables(2, 78);
1792          $table5of13 = $this->imb_tables(5, 1287);
1793          // convert codewords to characters
1794          $characters = array();
1795          $bitmask = 512;
1796          foreach($codewords as $k => $val) {
1797              if ($val <= 1286) {
1798                  $chrcode = $table5of13[$val];
1799              } else {
1800                  $chrcode = $table2of13[($val - 1287)];
1801              }
1802              if (($fcs & $bitmask) > 0) {
1803                  // bitwise invert
1804                  $chrcode = ((~$chrcode) & 8191);
1805              }
1806              $characters[] = $chrcode;
1807              $bitmask /= 2;
1808          }
1809          $characters = array_reverse($characters);
1810          // build bars
1811          $k = 0;
1812          $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
1813          for ($i = 0; $i < 65; ++$i) {
1814              $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0);
1815              $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0);
1816              if ($asc AND $dsc) {
1817                  // full bar (F)
1818                  $p = 0;
1819                  $h = 3;
1820              } elseif ($asc) {
1821                  // ascender (A)
1822                  $p = 0;
1823                  $h = 2;
1824              } elseif ($dsc) {
1825                  // descender (D)
1826                  $p = 1;
1827                  $h = 2;
1828              } else {
1829                  // tracker (T)
1830                  $p = 1;
1831                  $h = 1;
1832              }
1833              $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1834              $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1835              $bararray['maxw'] += 2;
1836          }
1837          unset($bararray['bcode'][($k - 1)]);
1838          --$bararray['maxw'];
1839          return $bararray;
1840      }
1841      
1842      /**
1843       * Convert large integer number to hexadecimal representation.
1844       * (requires PHP bcmath extension) 
1845       * @param string $number number to convert specified as a string
1846       * @return string hexadecimal representation
1847       */
1848  	public function dec_to_hex($number) {
1849          $i = 0;
1850          $hex = array();
1851          if($number == 0) {
1852              return '00';
1853          }
1854          while($number > 0) {
1855              if($number == 0) {
1856                  array_push($hex, '0');
1857              } else {
1858                  array_push($hex, strtoupper(dechex(bcmod($number, '16'))));
1859                  $number = bcdiv($number, '16', 0);
1860              }
1861          }
1862          $hex = array_reverse($hex);
1863          return implode($hex);
1864      }
1865      
1866      /**
1867       * Convert large hexadecimal number to decimal representation (string).
1868       * (requires PHP bcmath extension) 
1869       * @param string $hex hexadecimal number to convert specified as a string
1870       * @return string hexadecimal representation
1871       */
1872  	public function hex_to_dec($hex) {
1873          $dec = 0;
1874          $bitval = 1;
1875          $len = strlen($hex);
1876          for($pos = ($len - 1); $pos >= 0; --$pos) {
1877              $dec = bcadd($dec, bcmul(hexdec($hex{$pos}), $bitval));
1878              $bitval = bcmul($bitval, 16);
1879          }
1880          return $dec;
1881      }    
1882      
1883      /**
1884       * Intelligent Mail Barcode calculation of Frame Check Sequence
1885       * @param string $code_arr array of hexadecimal values (13 bytes holding 102 bits right justified).
1886       * @return int 11 bit Frame Check Sequence as integer (decimal base)
1887       * @access protected
1888       */
1889  	protected function imb_crc11fcs($code_arr) {
1890          $genpoly = 0x0F35; // generator polynomial
1891          $fcs = 0x07FF; // Frame Check Sequence
1892          // do most significant byte skipping the 2 most significant bits
1893          $data = hexdec($code_arr[0]) << 5;
1894          for ($bit = 2; $bit < 8; ++$bit) {
1895              if (($fcs ^ $data) & 0x400) {
1896                  $fcs = ($fcs << 1) ^ $genpoly;
1897              } else {
1898                  $fcs = ($fcs << 1);
1899              }
1900              $fcs &= 0x7FF;
1901              $data <<= 1;
1902          }
1903          // do rest of bytes
1904          for ($byte = 1; $byte < 13; ++$byte) {
1905              $data = hexdec($code_arr[$byte]) << 3;
1906              for ($bit = 0; $bit < 8; ++$bit) {
1907                  if (($fcs ^ $data) & 0x400) {
1908                      $fcs = ($fcs << 1) ^ $genpoly;
1909                  } else {
1910                      $fcs = ($fcs << 1);
1911                  }
1912                  $fcs &= 0x7FF;
1913                  $data <<= 1;
1914              }
1915          }
1916          return $fcs;        
1917      }
1918      
1919      /**
1920       * Reverse unsigned short value
1921       * @param int $num value to reversr
1922       * @return int reversed value
1923       * @access protected
1924       */
1925  	protected function imb_reverse_us($num) {
1926          $rev = 0;
1927          for ($i = 0; $i < 16; ++$i) {
1928              $rev <<= 1;
1929              $rev |= ($num & 1);
1930              $num >>= 1;
1931          }
1932          return $rev;
1933      }
1934      
1935      /**
1936       * generate Nof13 tables used for Intelligent Mail Barcode
1937       * @param int $n is the type of table: 2 for 2of13 table, 5 for 5of13table
1938       * @param int $size size of table (78 for n=2 and 1287 for n=5)
1939       * @return array requested table
1940       * @access protected
1941       */
1942  	protected function imb_tables($n, $size) {
1943          $table = array();
1944          $lli = 0; // LUT lower index
1945          $lui = $size - 1; // LUT upper index
1946          for ($count = 0; $count < 8192; ++$count) {
1947              $bit_count = 0;
1948              for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
1949                  $bit_count += intval(($count & (1 << $bit_index)) != 0);
1950              }
1951              // if we don't have the right number of bits on, go on to the next value
1952              if ($bit_count == $n) {
1953                  $reverse = ($this->imb_reverse_us($count) >> 3);
1954                  // if the reverse is less than count, we have already visited this pair before
1955                  if ($reverse >= $count) {
1956                      // If count is symmetric, place it at the first free slot from the end of the list.
1957                      // Otherwise, place it at the first free slot from the beginning of the list AND place $reverse ath the next free slot from the beginning of the list
1958                      if ($reverse == $count) {
1959                          $table[$lui] = $count;
1960                          --$lui;
1961                      } else {
1962                          $table[$lli] = $count;
1963                          ++$lli;
1964                          $table[$lli] = $reverse;
1965                          ++$lli;
1966                      }
1967                  }
1968              }
1969          }
1970          return $table;
1971      }
1972      
1973  } // end of class
1974  
1975  //============================================================+
1976  // END OF FILE                                                 
1977  //============================================================+
1978  ?>


Generated: Tue Mar 17 22:47:18 2015 Cross-referenced by PHPXref 0.7.1