[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/libraries/tcpdf/ -> barcodes.php (source)

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


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1