Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

   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  //============================================================+