[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1