[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/tcpdf/ -> tcpdf_barcodes_1d.php (source)

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1