Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]

   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 = 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 string $code code to print
  70   	  * @param string $type type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>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 int $w Minimum width of a single bar in user units.
  89  	  * @param int $h Height of barcode in user units.
  90  	  * @param string $color 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 int $w Minimum width of a single bar in user units.
 109  	  * @param int $h Height of barcode in user units.
 110  	  * @param string $color 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 int $w Width of a single bar element in pixels.
 142  	  * @param int $h Height of a single bar element in pixels.
 143  	  * @param string $color 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 int $w Width of a single bar element in pixels.
 168  	  * @param int $h Height of a single bar element in pixels.
 169  	  * @param array $color 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 int $w Width of a single bar element in pixels.
 187  	  * @param int $h Height of a single bar element in pixels.
 188  	  * @param array $color RGB (0-255) foreground color for bar elements (background is transparent).
 189   	  * @return string|Imagick|false 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 string $code code to print
 245   	  * @param string $type type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>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 void
 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 = array();
 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 string $code code to represent.
 388  	  * @param boolean $extended if true uses the extended mode.
 389  	  * @param boolean $checksum 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 string $code code to represent.
 483  	  * @return string 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 string $code code to represent.
 534  	  * @return string 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 string $code 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 string $code 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 string $code 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 string $code code to represent.
 759  	  * @param boolean $checksum 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 string $code code to represent.
 818  	  * @param boolean $checksum 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 WarnockPDF barcode array.
 858  	  * @param string $seq barcode as binary sequence.
 859  	  * @param array $bararray barcode array to fill up
 860  	  * @return array barcode representation.
 861  	  * @protected
 862  	  */
 863  	protected function binseq_to_array($seq, $bararray) {
 864  	 	 $len = strlen($seq);
 865  	 	 $w = 0;
 866  	 	 $k = 0;
 867  	 	 for ($i = 0; $i < $len; ++$i) {
 868  	 	 	 $w += 1;
 869  	 	 	 if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq[$i] != $seq[($i+1)]))) {
 870  	 	 	 	 if ($seq[$i] == '1') {
 871  	 	 	 	 	 $t = true; // bar
 872  	 	 	 	 } else {
 873  	 	 	 	 	 $t = false; // space
 874  	 	 	 	 }
 875  	 	 	 	 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 876  	 	 	 	 $bararray['maxw'] += $w;
 877  	 	 	 	 ++$k;
 878  	 	 	 	 $w = 0;
 879  	 	 	 }
 880  	 	 }
 881  	 	 return $bararray;
 882  	 }
 883  
 884  	 /**
 885  	  * Interleaved 2 of 5 barcodes.
 886  	  * Compact numeric code, widely used in industry, air cargo
 887  	  * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
 888  	  * @param string $code code to represent.
 889  	  * @param boolean $checksum if true add a checksum to the code
 890  	  * @return array barcode representation.
 891  	  * @protected
 892  	  */
 893  	protected function barcode_i25($code, $checksum=false) {
 894  	 	 $chr['0'] = '11221';
 895  	 	 $chr['1'] = '21112';
 896  	 	 $chr['2'] = '12112';
 897  	 	 $chr['3'] = '22111';
 898  	 	 $chr['4'] = '11212';
 899  	 	 $chr['5'] = '21211';
 900  	 	 $chr['6'] = '12211';
 901  	 	 $chr['7'] = '11122';
 902  	 	 $chr['8'] = '21121';
 903  	 	 $chr['9'] = '12121';
 904  	 	 $chr['A'] = '11';
 905  	 	 $chr['Z'] = '21';
 906  	 	 if ($checksum) {
 907  	 	 	 // add checksum
 908  	 	 	 $code .= $this->checksum_s25($code);
 909  	 	 }
 910  	 	 if((strlen($code) % 2) != 0) {
 911  	 	 	 // add leading zero if code-length is odd
 912  	 	 	 $code = '0'.$code;
 913  	 	 }
 914  	 	 // add start and stop codes
 915  	 	 $code = 'AA'.strtolower($code).'ZA';
 916  
 917  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 918  	 	 $k = 0;
 919  	 	 $clen = strlen($code);
 920  	 	 for ($i = 0; $i < $clen; $i = ($i + 2)) {
 921  	 	 	 $char_bar = $code[$i];
 922  	 	 	 $char_space = $code[$i+1];
 923  	 	 	 if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
 924  	 	 	 	 // invalid character
 925  	 	 	 	 return false;
 926  	 	 	 }
 927  	 	 	 // create a bar-space sequence
 928  	 	 	 $seq = '';
 929  	 	 	 $chrlen = strlen($chr[$char_bar]);
 930  	 	 	 for ($s = 0; $s < $chrlen; $s++){
 931  	 	 	 	 $seq .= $chr[$char_bar][$s] . $chr[$char_space][$s];
 932  	 	 	 }
 933  	 	 	 $seqlen = strlen($seq);
 934  	 	 	 for ($j = 0; $j < $seqlen; ++$j) {
 935  	 	 	 	 if (($j % 2) == 0) {
 936  	 	 	 	 	 $t = true; // bar
 937  	 	 	 	 } else {
 938  	 	 	 	 	 $t = false; // space
 939  	 	 	 	 }
 940  	 	 	 	 $w = (float)$seq[$j];
 941  	 	 	 	 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 942  	 	 	 	 $bararray['maxw'] += $w;
 943  	 	 	 	 ++$k;
 944  	 	 	 }
 945  	 	 }
 946  	 	 return $bararray;
 947  	 }
 948  
 949  	 /**
 950  	  * C128 barcodes.
 951  	  * Very capable code, excellent density, high reliability; in very wide use world-wide
 952  	  * @param string $code code to represent.
 953  	  * @param string $type barcode type: A, B, C or empty for automatic switch (AUTO mode)
 954  	  * @return array barcode representation.
 955  	  * @protected
 956  	  */
 957  	protected function barcode_c128($code, $type='') {
 958  	 	 $chr = array(
 959  	 	 	 '212222', /* 00 */
 960  	 	 	 '222122', /* 01 */
 961  	 	 	 '222221', /* 02 */
 962  	 	 	 '121223', /* 03 */
 963  	 	 	 '121322', /* 04 */
 964  	 	 	 '131222', /* 05 */
 965  	 	 	 '122213', /* 06 */
 966  	 	 	 '122312', /* 07 */
 967  	 	 	 '132212', /* 08 */
 968  	 	 	 '221213', /* 09 */
 969  	 	 	 '221312', /* 10 */
 970  	 	 	 '231212', /* 11 */
 971  	 	 	 '112232', /* 12 */
 972  	 	 	 '122132', /* 13 */
 973  	 	 	 '122231', /* 14 */
 974  	 	 	 '113222', /* 15 */
 975  	 	 	 '123122', /* 16 */
 976  	 	 	 '123221', /* 17 */
 977  	 	 	 '223211', /* 18 */
 978  	 	 	 '221132', /* 19 */
 979  	 	 	 '221231', /* 20 */
 980  	 	 	 '213212', /* 21 */
 981  	 	 	 '223112', /* 22 */
 982  	 	 	 '312131', /* 23 */
 983  	 	 	 '311222', /* 24 */
 984  	 	 	 '321122', /* 25 */
 985  	 	 	 '321221', /* 26 */
 986  	 	 	 '312212', /* 27 */
 987  	 	 	 '322112', /* 28 */
 988  	 	 	 '322211', /* 29 */
 989  	 	 	 '212123', /* 30 */
 990  	 	 	 '212321', /* 31 */
 991  	 	 	 '232121', /* 32 */
 992  	 	 	 '111323', /* 33 */
 993  	 	 	 '131123', /* 34 */
 994  	 	 	 '131321', /* 35 */
 995  	 	 	 '112313', /* 36 */
 996  	 	 	 '132113', /* 37 */
 997  	 	 	 '132311', /* 38 */
 998  	 	 	 '211313', /* 39 */
 999  	 	 	 '231113', /* 40 */
1000  	 	 	 '231311', /* 41 */
1001  	 	 	 '112133', /* 42 */
1002  	 	 	 '112331', /* 43 */
1003  	 	 	 '132131', /* 44 */
1004  	 	 	 '113123', /* 45 */
1005  	 	 	 '113321', /* 46 */
1006  	 	 	 '133121', /* 47 */
1007  	 	 	 '313121', /* 48 */
1008  	 	 	 '211331', /* 49 */
1009  	 	 	 '231131', /* 50 */
1010  	 	 	 '213113', /* 51 */
1011  	 	 	 '213311', /* 52 */
1012  	 	 	 '213131', /* 53 */
1013  	 	 	 '311123', /* 54 */
1014  	 	 	 '311321', /* 55 */
1015  	 	 	 '331121', /* 56 */
1016  	 	 	 '312113', /* 57 */
1017  	 	 	 '312311', /* 58 */
1018  	 	 	 '332111', /* 59 */
1019  	 	 	 '314111', /* 60 */
1020  	 	 	 '221411', /* 61 */
1021  	 	 	 '431111', /* 62 */
1022  	 	 	 '111224', /* 63 */
1023  	 	 	 '111422', /* 64 */
1024  	 	 	 '121124', /* 65 */
1025  	 	 	 '121421', /* 66 */
1026  	 	 	 '141122', /* 67 */
1027  	 	 	 '141221', /* 68 */
1028  	 	 	 '112214', /* 69 */
1029  	 	 	 '112412', /* 70 */
1030  	 	 	 '122114', /* 71 */
1031  	 	 	 '122411', /* 72 */
1032  	 	 	 '142112', /* 73 */
1033  	 	 	 '142211', /* 74 */
1034  	 	 	 '241211', /* 75 */
1035  	 	 	 '221114', /* 76 */
1036  	 	 	 '413111', /* 77 */
1037  	 	 	 '241112', /* 78 */
1038  	 	 	 '134111', /* 79 */
1039  	 	 	 '111242', /* 80 */
1040  	 	 	 '121142', /* 81 */
1041  	 	 	 '121241', /* 82 */
1042  	 	 	 '114212', /* 83 */
1043  	 	 	 '124112', /* 84 */
1044  	 	 	 '124211', /* 85 */
1045  	 	 	 '411212', /* 86 */
1046  	 	 	 '421112', /* 87 */
1047  	 	 	 '421211', /* 88 */
1048  	 	 	 '212141', /* 89 */
1049  	 	 	 '214121', /* 90 */
1050  	 	 	 '412121', /* 91 */
1051  	 	 	 '111143', /* 92 */
1052  	 	 	 '111341', /* 93 */
1053  	 	 	 '131141', /* 94 */
1054  	 	 	 '114113', /* 95 */
1055  	 	 	 '114311', /* 96 */
1056  	 	 	 '411113', /* 97 */
1057  	 	 	 '411311', /* 98 */
1058  	 	 	 '113141', /* 99 */
1059  	 	 	 '114131', /* 100 */
1060  	 	 	 '311141', /* 101 */
1061  	 	 	 '411131', /* 102 */
1062  	 	 	 '211412', /* 103 START A */
1063  	 	 	 '211214', /* 104 START B */
1064  	 	 	 '211232', /* 105 START C */
1065  	 	 	 '233111', /* STOP */
1066  	 	 	 '200000'  /* END */
1067  	 	 );
1068  	 	 // ASCII characters for code A (ASCII 00 - 95)
1069  	 	 $keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
1070  	 	 $keys_a .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9);
1071  	 	 $keys_a .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19);
1072  	 	 $keys_a .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29);
1073  	 	 $keys_a .= chr(30).chr(31);
1074  	 	 // ASCII characters for code B (ASCII 32 - 127)
1075  	 	 $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
1076  	 	 // special codes
1077  	 	 $fnc_a = array(241 => 102, 242 => 97, 243 => 96, 244 => 101);
1078  	 	 $fnc_b = array(241 => 102, 242 => 97, 243 => 96, 244 => 100);
1079  	 	 // array of symbols
1080  	 	 $code_data = array();
1081  	 	 // length of the code
1082  	 	 $len = strlen($code);
1083  	 	 switch(strtoupper($type)) {
1084  	 	 	 case 'A': { // MODE A
1085  	 	 	 	 $startid = 103;
1086  	 	 	 	 for ($i = 0; $i < $len; ++$i) {
1087  	 	 	 	 	 $char = $code[$i];
1088  	 	 	 	 	 $char_id = ord($char);
1089  	 	 	 	 	 if (($char_id >= 241) AND ($char_id <= 244)) {
1090  	 	 	 	 	 	 $code_data[] = $fnc_a[$char_id];
1091  	 	 	 	 	 } elseif (($char_id >= 0) AND ($char_id <= 95)) {
1092  	 	 	 	 	 	 $code_data[] = strpos($keys_a, $char);
1093  	 	 	 	 	 } else {
1094  	 	 	 	 	 	 return false;
1095  	 	 	 	 	 }
1096  	 	 	 	 }
1097  	 	 	 	 break;
1098  	 	 	 }
1099  	 	 	 case 'B': { // MODE B
1100  	 	 	 	 $startid = 104;
1101  	 	 	 	 for ($i = 0; $i < $len; ++$i) {
1102  	 	 	 	 	 $char = $code[$i];
1103  	 	 	 	 	 $char_id = ord($char);
1104  	 	 	 	 	 if (($char_id >= 241) AND ($char_id <= 244)) {
1105  	 	 	 	 	 	 $code_data[] = $fnc_b[$char_id];
1106  	 	 	 	 	 } elseif (($char_id >= 32) AND ($char_id <= 127)) {
1107  	 	 	 	 	 	 $code_data[] = strpos($keys_b, $char);
1108  	 	 	 	 	 } else {
1109  	 	 	 	 	 	 return false;
1110  	 	 	 	 	 }
1111  	 	 	 	 }
1112  	 	 	 	 break;
1113  	 	 	 }
1114  	 	 	 case 'C': { // MODE C
1115  	 	 	 	 $startid = 105;
1116  	 	 	 	 if (ord($code[0]) == 241) {
1117  	 	 	 	 	 $code_data[] = 102;
1118  	 	 	 	 	 $code = substr($code, 1);
1119  	 	 	 	 	 --$len;
1120  	 	 	 	 }
1121  	 	 	 	 if (($len % 2) != 0) {
1122  	 	 	 	 	 // the length must be even
1123  	 	 	 	 	 return false;
1124  	 	 	 	 }
1125  	 	 	 	 for ($i = 0; $i < $len; $i+=2) {
1126  	 	 	 	 	 $chrnum = $code[$i].$code[$i+1];
1127  	 	 	 	 	 if (preg_match('/([0-9]{2})/', $chrnum) > 0) {
1128  	 	 	 	 	 	 $code_data[] = intval($chrnum);
1129  	 	 	 	 	 } else {
1130  	 	 	 	 	 	 return false;
1131  	 	 	 	 	 }
1132  	 	 	 	 }
1133  	 	 	 	 break;
1134  	 	 	 }
1135  	 	 	 default: { // MODE AUTO
1136  	 	 	 	 // split code into sequences
1137  	 	 	 	 $sequence = array();
1138  	 	 	 	 // get numeric sequences (if any)
1139  	 	 	 	 $numseq = array();
1140  	 	 	 	 preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE);
1141  	 	 	 	 if (isset($numseq[1]) AND !empty($numseq[1])) {
1142  	 	 	 	 	 $end_offset = 0;
1143  	 	 	 	 	 foreach ($numseq[1] as $val) {
1144  	 	 	 	 	 	 $offset = $val[1];
1145  	 	 	 	 	 	 if ($offset > $end_offset) {
1146  	 	 	 	 	 	 	 // non numeric sequence
1147  	 	 	 	 	 	 	 $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset))));
1148  	 	 	 	 	 	 }
1149  	 	 	 	 	 	 // numeric sequence
1150  	 	 	 	 	 	 $slen = strlen($val[0]);
1151  	 	 	 	 	 	 if (($slen % 2) != 0) {
1152  	 	 	 	 	 	 	 // the length must be even
1153  	 	 	 	 	 	 	 --$slen;
1154  	 	 	 	 	 	 }
1155  	 	 	 	 	 	 $sequence[] = array('C', substr($code, $offset, $slen), $slen);
1156  	 	 	 	 	 	 $end_offset = $offset + $slen;
1157  	 	 	 	 	 }
1158  	 	 	 	 	 if ($end_offset < $len) {
1159  	 	 	 	 	 	 $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset)));
1160  	 	 	 	 	 }
1161  	 	 	 	 } else {
1162  	 	 	 	 	 // text code (non C mode)
1163  	 	 	 	 	 $sequence = array_merge($sequence, $this->get128ABsequence($code));
1164  	 	 	 	 }
1165  	 	 	 	 // process the sequence
1166  	 	 	 	 foreach ($sequence as $key => $seq) {
1167  	 	 	 	 	 switch($seq[0]) {
1168  	 	 	 	 	 	 case 'A': {
1169  	 	 	 	 	 	 	 if ($key == 0) {
1170  	 	 	 	 	 	 	 	 $startid = 103;
1171  	 	 	 	 	 	 	 } elseif ($sequence[($key - 1)][0] != 'A') {
1172  	 	 	 	 	 	 	 	 if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'B') AND (!isset($sequence[($key - 1)][3]))) {
1173  	 	 	 	 	 	 	 	 	 // single character shift
1174  	 	 	 	 	 	 	 	 	 $code_data[] = 98;
1175  	 	 	 	 	 	 	 	 	 // mark shift
1176  	 	 	 	 	 	 	 	 	 $sequence[$key][3] = true;
1177  	 	 	 	 	 	 	 	 } elseif (!isset($sequence[($key - 1)][3])) {
1178  	 	 	 	 	 	 	 	 	 $code_data[] = 101;
1179  	 	 	 	 	 	 	 	 }
1180  	 	 	 	 	 	 	 }
1181  	 	 	 	 	 	 	 for ($i = 0; $i < $seq[2]; ++$i) {
1182  	 	 	 	 	 	 	 	 $char = $seq[1][$i];
1183  	 	 	 	 	 	 	 	 $char_id = ord($char);
1184  	 	 	 	 	 	 	 	 if (($char_id >= 241) AND ($char_id <= 244)) {
1185  	 	 	 	 	 	 	 	 	 $code_data[] = $fnc_a[$char_id];
1186  	 	 	 	 	 	 	 	 } else {
1187  	 	 	 	 	 	 	 	 	 $code_data[] = strpos($keys_a, $char);
1188  	 	 	 	 	 	 	 	 }
1189  	 	 	 	 	 	 	 }
1190  	 	 	 	 	 	 	 break;
1191  	 	 	 	 	 	 }
1192  	 	 	 	 	 	 case 'B': {
1193  	 	 	 	 	 	 	 if ($key == 0) {
1194  	 	 	 	 	 	 	 	 $tmpchr = ord($seq[1][0]);
1195  	 	 	 	 	 	 	 	 if (($seq[2] == 1) AND ($tmpchr >= 241) AND ($tmpchr <= 244) AND isset($sequence[($key + 1)]) AND ($sequence[($key + 1)][0] != 'B')) {
1196  	 	 	 	 	 	 	 	 	 switch ($sequence[($key + 1)][0]) {
1197  	 	 	 	 	 	 	 	 	 	 case 'A': {
1198  	 	 	 	 	 	 	 	 	 	 	 $startid = 103;
1199  	 	 	 	 	 	 	 	 	 	 	 $sequence[$key][0] = 'A';
1200  	 	 	 	 	 	 	 	 	 	 	 $code_data[] = $fnc_a[$tmpchr];
1201  	 	 	 	 	 	 	 	 	 	 	 break;
1202  	 	 	 	 	 	 	 	 	 	 }
1203  	 	 	 	 	 	 	 	 	 	 case 'C': {
1204  	 	 	 	 	 	 	 	 	 	 	 $startid = 105;
1205  	 	 	 	 	 	 	 	 	 	 	 $sequence[$key][0] = 'C';
1206  	 	 	 	 	 	 	 	 	 	 	 $code_data[] = $fnc_a[$tmpchr];
1207  	 	 	 	 	 	 	 	 	 	 	 break;
1208  	 	 	 	 	 	 	 	 	 	 }
1209  	 	 	 	 	 	 	 	 	 }
1210  	 	 	 	 	 	 	 	 	 break;
1211  	 	 	 	 	 	 	 	 } else {
1212  	 	 	 	 	 	 	 	 	 $startid = 104;
1213  	 	 	 	 	 	 	 	 }
1214  	 	 	 	 	 	 	 } elseif ($sequence[($key - 1)][0] != 'B') {
1215  	 	 	 	 	 	 	 	 if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'A') AND (!isset($sequence[($key - 1)][3]))) {
1216  	 	 	 	 	 	 	 	 	 // single character shift
1217  	 	 	 	 	 	 	 	 	 $code_data[] = 98;
1218  	 	 	 	 	 	 	 	 	 // mark shift
1219  	 	 	 	 	 	 	 	 	 $sequence[$key][3] = true;
1220  	 	 	 	 	 	 	 	 } elseif (!isset($sequence[($key - 1)][3])) {
1221  	 	 	 	 	 	 	 	 	 $code_data[] = 100;
1222  	 	 	 	 	 	 	 	 }
1223  	 	 	 	 	 	 	 }
1224  	 	 	 	 	 	 	 for ($i = 0; $i < $seq[2]; ++$i) {
1225  	 	 	 	 	 	 	 	 $char = $seq[1][$i];
1226  	 	 	 	 	 	 	 	 $char_id = ord($char);
1227  	 	 	 	 	 	 	 	 if (($char_id >= 241) AND ($char_id <= 244)) {
1228  	 	 	 	 	 	 	 	 	 $code_data[] = $fnc_b[$char_id];
1229  	 	 	 	 	 	 	 	 } else {
1230  	 	 	 	 	 	 	 	 	 $code_data[] = strpos($keys_b, $char);
1231  	 	 	 	 	 	 	 	 }
1232  	 	 	 	 	 	 	 }
1233  	 	 	 	 	 	 	 break;
1234  	 	 	 	 	 	 }
1235  	 	 	 	 	 	 case 'C': {
1236  	 	 	 	 	 	 	 if ($key == 0) {
1237  	 	 	 	 	 	 	 	 $startid = 105;
1238  	 	 	 	 	 	 	 } elseif ($sequence[($key - 1)][0] != 'C') {
1239  	 	 	 	 	 	 	 	 $code_data[] = 99;
1240  	 	 	 	 	 	 	 }
1241  	 	 	 	 	 	 	 for ($i = 0; $i < $seq[2]; $i+=2) {
1242  	 	 	 	 	 	 	 	 $chrnum = $seq[1][$i].$seq[1][$i+1];
1243  	 	 	 	 	 	 	 	 $code_data[] = intval($chrnum);
1244  	 	 	 	 	 	 	 }
1245  	 	 	 	 	 	 	 break;
1246  	 	 	 	 	 	 }
1247  	 	 	 	 	 }
1248  	 	 	 	 }
1249  	 	 	 }
1250  	 	 }
1251  	 	 // calculate check character
1252  	 	 $sum = $startid;
1253  	 	 foreach ($code_data as $key => $val) {
1254  	 	 	 $sum += ($val * ($key + 1));
1255  	 	 }
1256  	 	 // add check character
1257  	 	 $code_data[] = ($sum % 103);
1258  	 	 // add stop sequence
1259  	 	 $code_data[] = 106;
1260  	 	 $code_data[] = 107;
1261  	 	 // add start code at the beginning
1262  	 	 array_unshift($code_data, $startid);
1263  	 	 // build barcode array
1264  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1265  	 	 foreach ($code_data as $val) {
1266  	 	 	 $seq = $chr[$val];
1267  	 	 	 for ($j = 0; $j < 6; ++$j) {
1268  	 	 	 	 if (($j % 2) == 0) {
1269  	 	 	 	 	 $t = true; // bar
1270  	 	 	 	 } else {
1271  	 	 	 	 	 $t = false; // space
1272  	 	 	 	 }
1273  	 	 	 	 $w = (float)$seq[$j];
1274  	 	 	 	 $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1275  	 	 	 	 $bararray['maxw'] += $w;
1276  	 	 	 }
1277  	 	 }
1278  	 	 return $bararray;
1279  	 }
1280  
1281  	 /**
1282  	  * Split text code in A/B sequence for 128 code
1283  	  * @param string $code code to split.
1284  	  * @return array sequence
1285  	  * @protected
1286  	  */
1287  	protected function get128ABsequence($code) {
1288  	 	 $len = strlen($code);
1289  	 	 $sequence = array();
1290  	 	 // get A sequences (if any)
1291  	 	 $numseq = array();
1292  	 	 preg_match_all('/([\0-\31])/', $code, $numseq, PREG_OFFSET_CAPTURE);
1293  	 	 if (isset($numseq[1]) AND !empty($numseq[1])) {
1294  	 	 	 $end_offset = 0;
1295  	 	 	 foreach ($numseq[1] as $val) {
1296  	 	 	 	 $offset = $val[1];
1297  	 	 	 	 if ($offset > $end_offset) {
1298  	 	 	 	 	 // B sequence
1299  	 	 	 	 	 $sequence[] = array('B', substr($code, $end_offset, ($offset - $end_offset)), ($offset - $end_offset));
1300  	 	 	 	 }
1301  	 	 	 	 // A sequence
1302  	 	 	 	 $slen = strlen($val[0]);
1303  	 	 	 	 $sequence[] = array('A', substr($code, $offset, $slen), $slen);
1304  	 	 	 	 $end_offset = $offset + $slen;
1305  	 	 	 }
1306  	 	 	 if ($end_offset < $len) {
1307  	 	 	 	 $sequence[] = array('B', substr($code, $end_offset), ($len - $end_offset));
1308  	 	 	 }
1309  	 	 } else {
1310  	 	 	 // only B sequence
1311  	 	 	 $sequence[] = array('B', $code, $len);
1312  	 	 }
1313  	 	 return $sequence;
1314  	 }
1315  
1316  	 /**
1317  	  * EAN13 and UPC-A barcodes.
1318  	  * EAN13: European Article Numbering international retail product code
1319  	  * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
1320  	  * UPC-E: Short version of UPC symbol
1321  	  * @param string $code code to represent.
1322  	  * @param string $len barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
1323  	  * @return array barcode representation.
1324  	  * @protected
1325  	  */
1326  	protected function barcode_eanupc($code, $len=13) {
1327  	 	 $upce = false;
1328  	 	 if ($len == 6) {
1329  	 	 	 $len = 12; // UPC-A
1330  	 	 	 $upce = true; // UPC-E mode
1331  	 	 }
1332  	 	 $data_len = $len - 1;
1333  	 	 //Padding
1334  	 	 $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
1335  	 	 $code_len = strlen($code);
1336  	 	 // calculate check digit
1337  	 	 $sum_a = 0;
1338  	 	 for ($i = 1; $i < $data_len; $i+=2) {
1339  	 	 	 $sum_a += $code[$i];
1340  	 	 }
1341  	 	 if ($len > 12) {
1342  	 	 	 $sum_a *= 3;
1343  	 	 }
1344  	 	 $sum_b = 0;
1345  	 	 for ($i = 0; $i < $data_len; $i+=2) {
1346  	 	 	 $sum_b += ($code[$i]);
1347  	 	 }
1348  	 	 if ($len < 13) {
1349  	 	 	 $sum_b *= 3;
1350  	 	 }
1351  	 	 $r = ($sum_a + $sum_b) % 10;
1352  	 	 if($r > 0) {
1353  	 	 	 $r = (10 - $r);
1354  	 	 }
1355  	 	 if ($code_len == $data_len) {
1356  	 	 	 // add check digit
1357  	 	 	 $code .= $r;
1358  	 	 } elseif ($r !== intval($code[$data_len])) {
1359  	 	 	 // wrong checkdigit
1360  	 	 	 return false;
1361  	 	 }
1362  	 	 if ($len == 12) {
1363  	 	 	 // UPC-A
1364  	 	 	 $code = '0'.$code;
1365  	 	 	 ++$len;
1366  	 	 }
1367  	 	 if ($upce) {
1368  	 	 	 // convert UPC-A to UPC-E
1369  	 	 	 $tmp = substr($code, 4, 3);
1370  	 	 	 if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
1371  	 	 	 	 // manufacturer code ends in 000, 100, or 200
1372  	 	 	 	 $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
1373  	 	 	 } else {
1374  	 	 	 	 $tmp = substr($code, 5, 2);
1375  	 	 	 	 if ($tmp == '00') {
1376  	 	 	 	 	 // manufacturer code ends in 00
1377  	 	 	 	 	 $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
1378  	 	 	 	 } else {
1379  	 	 	 	 	 $tmp = substr($code, 6, 1);
1380  	 	 	 	 	 if ($tmp == '0') {
1381  	 	 	 	 	 	 // manufacturer code ends in 0
1382  	 	 	 	 	 	 $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
1383  	 	 	 	 	 } else {
1384  	 	 	 	 	 	 // manufacturer code does not end in zero
1385  	 	 	 	 	 	 $upce_code = substr($code, 2, 5).substr($code, 11, 1);
1386  	 	 	 	 	 }
1387  	 	 	 	 }
1388  	 	 	 }
1389  	 	 }
1390  	 	 //Convert digits to bars
1391  	 	 $codes = array(
1392  	 	 	 'A'=>array( // left odd parity
1393  	 	 	 	 '0'=>'0001101',
1394  	 	 	 	 '1'=>'0011001',
1395  	 	 	 	 '2'=>'0010011',
1396  	 	 	 	 '3'=>'0111101',
1397  	 	 	 	 '4'=>'0100011',
1398  	 	 	 	 '5'=>'0110001',
1399  	 	 	 	 '6'=>'0101111',
1400  	 	 	 	 '7'=>'0111011',
1401  	 	 	 	 '8'=>'0110111',
1402  	 	 	 	 '9'=>'0001011'),
1403  	 	 	 'B'=>array( // left even parity
1404  	 	 	 	 '0'=>'0100111',
1405  	 	 	 	 '1'=>'0110011',
1406  	 	 	 	 '2'=>'0011011',
1407  	 	 	 	 '3'=>'0100001',
1408  	 	 	 	 '4'=>'0011101',
1409  	 	 	 	 '5'=>'0111001',
1410  	 	 	 	 '6'=>'0000101',
1411  	 	 	 	 '7'=>'0010001',
1412  	 	 	 	 '8'=>'0001001',
1413  	 	 	 	 '9'=>'0010111'),
1414  	 	 	 'C'=>array( // right
1415  	 	 	 	 '0'=>'1110010',
1416  	 	 	 	 '1'=>'1100110',
1417  	 	 	 	 '2'=>'1101100',
1418  	 	 	 	 '3'=>'1000010',
1419  	 	 	 	 '4'=>'1011100',
1420  	 	 	 	 '5'=>'1001110',
1421  	 	 	 	 '6'=>'1010000',
1422  	 	 	 	 '7'=>'1000100',
1423  	 	 	 	 '8'=>'1001000',
1424  	 	 	 	 '9'=>'1110100')
1425  	 	 );
1426  	 	 $parities = array(
1427  	 	 	 '0'=>array('A','A','A','A','A','A'),
1428  	 	 	 '1'=>array('A','A','B','A','B','B'),
1429  	 	 	 '2'=>array('A','A','B','B','A','B'),
1430  	 	 	 '3'=>array('A','A','B','B','B','A'),
1431  	 	 	 '4'=>array('A','B','A','A','B','B'),
1432  	 	 	 '5'=>array('A','B','B','A','A','B'),
1433  	 	 	 '6'=>array('A','B','B','B','A','A'),
1434  	 	 	 '7'=>array('A','B','A','B','A','B'),
1435  	 	 	 '8'=>array('A','B','A','B','B','A'),
1436  	 	 	 '9'=>array('A','B','B','A','B','A')
1437  	 	 );
1438  	 	 $upce_parities = array();
1439  	 	 $upce_parities[0] = array(
1440  	 	 	 '0'=>array('B','B','B','A','A','A'),
1441  	 	 	 '1'=>array('B','B','A','B','A','A'),
1442  	 	 	 '2'=>array('B','B','A','A','B','A'),
1443  	 	 	 '3'=>array('B','B','A','A','A','B'),
1444  	 	 	 '4'=>array('B','A','B','B','A','A'),
1445  	 	 	 '5'=>array('B','A','A','B','B','A'),
1446  	 	 	 '6'=>array('B','A','A','A','B','B'),
1447  	 	 	 '7'=>array('B','A','B','A','B','A'),
1448  	 	 	 '8'=>array('B','A','B','A','A','B'),
1449  	 	 	 '9'=>array('B','A','A','B','A','B')
1450  	 	 );
1451  	 	 $upce_parities[1] = array(
1452  	 	 	 '0'=>array('A','A','A','B','B','B'),
1453  	 	 	 '1'=>array('A','A','B','A','B','B'),
1454  	 	 	 '2'=>array('A','A','B','B','A','B'),
1455  	 	 	 '3'=>array('A','A','B','B','B','A'),
1456  	 	 	 '4'=>array('A','B','A','A','B','B'),
1457  	 	 	 '5'=>array('A','B','B','A','A','B'),
1458  	 	 	 '6'=>array('A','B','B','B','A','A'),
1459  	 	 	 '7'=>array('A','B','A','B','A','B'),
1460  	 	 	 '8'=>array('A','B','A','B','B','A'),
1461  	 	 	 '9'=>array('A','B','B','A','B','A')
1462  	 	 );
1463  	 	 $k = 0;
1464  	 	 $seq = '101'; // left guard bar
1465  	 	 if ($upce) {
1466  	 	 	 $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1467  	 	 	 $p = $upce_parities[$code[1]][$r];
1468  	 	 	 for ($i = 0; $i < 6; ++$i) {
1469  	 	 	 	 $seq .= $codes[$p[$i]][$upce_code[$i]];
1470  	 	 	 }
1471  	 	 	 $seq .= '010101'; // right guard bar
1472  	 	 } else {
1473  	 	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1474  	 	 	 $half_len = intval(ceil($len / 2));
1475  	 	 	 if ($len == 8) {
1476  	 	 	 	 for ($i = 0; $i < $half_len; ++$i) {
1477  	 	 	 	 	 $seq .= $codes['A'][$code[$i]];
1478  	 	 	 	 }
1479  	 	 	 } else {
1480  	 	 	 	 $p = $parities[$code[0]];
1481  	 	 	 	 for ($i = 1; $i < $half_len; ++$i) {
1482  	 	 	 	 	 $seq .= $codes[$p[$i-1]][$code[$i]];
1483  	 	 	 	 }
1484  	 	 	 }
1485  	 	 	 $seq .= '01010'; // center guard bar
1486  	 	 	 for ($i = $half_len; $i < $len; ++$i) {
1487  	 	 	 	 $seq .= $codes['C'][$code[$i]];
1488  	 	 	 }
1489  	 	 	 $seq .= '101'; // right guard bar
1490  	 	 }
1491  	 	 $clen = strlen($seq);
1492  	 	 $w = 0;
1493  	 	 for ($i = 0; $i < $clen; ++$i) {
1494  	 	 	 $w += 1;
1495  	 	 	 if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq[$i] != $seq[$i+1]))) {
1496  	 	 	 	 if ($seq[$i] == '1') {
1497  	 	 	 	 	 $t = true; // bar
1498  	 	 	 	 } else {
1499  	 	 	 	 	 $t = false; // space
1500  	 	 	 	 }
1501  	 	 	 	 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1502  	 	 	 	 $bararray['maxw'] += $w;
1503  	 	 	 	 ++$k;
1504  	 	 	 	 $w = 0;
1505  	 	 	 }
1506  	 	 }
1507  	 	 return $bararray;
1508  	 }
1509  
1510  	 /**
1511  	  * UPC-Based Extensions
1512  	  * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
1513  	  * 5-Digit Ext.: Used to mark suggested retail price of books
1514  	  * @param string $code code to represent.
1515  	  * @param string $len barcode type: 2 = 2-Digit, 5 = 5-Digit
1516  	  * @return array barcode representation.
1517  	  * @protected
1518  	  */
1519  	protected function barcode_eanext($code, $len=5) {
1520  	 	 //Padding
1521  	 	 $code = str_pad($code, $len, '0', STR_PAD_LEFT);
1522  	 	 // calculate check digit
1523  	 	 if ($len == 2) {
1524  	 	 	 $r = $code % 4;
1525  	 	 } elseif ($len == 5) {
1526  	 	 	 $r = (3 * ($code[0] + $code[2] + $code[4])) + (9 * ($code[1] + $code[3]));
1527  	 	 	 $r %= 10;
1528  	 	 } else {
1529  	 	 	 return false;
1530  	 	 }
1531  	 	 //Convert digits to bars
1532  	 	 $codes = array(
1533  	 	 	 'A'=>array( // left odd parity
1534  	 	 	 	 '0'=>'0001101',
1535  	 	 	 	 '1'=>'0011001',
1536  	 	 	 	 '2'=>'0010011',
1537  	 	 	 	 '3'=>'0111101',
1538  	 	 	 	 '4'=>'0100011',
1539  	 	 	 	 '5'=>'0110001',
1540  	 	 	 	 '6'=>'0101111',
1541  	 	 	 	 '7'=>'0111011',
1542  	 	 	 	 '8'=>'0110111',
1543  	 	 	 	 '9'=>'0001011'),
1544  	 	 	 'B'=>array( // left even parity
1545  	 	 	 	 '0'=>'0100111',
1546  	 	 	 	 '1'=>'0110011',
1547  	 	 	 	 '2'=>'0011011',
1548  	 	 	 	 '3'=>'0100001',
1549  	 	 	 	 '4'=>'0011101',
1550  	 	 	 	 '5'=>'0111001',
1551  	 	 	 	 '6'=>'0000101',
1552  	 	 	 	 '7'=>'0010001',
1553  	 	 	 	 '8'=>'0001001',
1554  	 	 	 	 '9'=>'0010111')
1555  	 	 );
1556  	 	 $parities = array();
1557  	 	 $parities[2] = array(
1558  	 	 	 '0'=>array('A','A'),
1559  	 	 	 '1'=>array('A','B'),
1560  	 	 	 '2'=>array('B','A'),
1561  	 	 	 '3'=>array('B','B')
1562  	 	 );
1563  	 	 $parities[5] = array(
1564  	 	 	 '0'=>array('B','B','A','A','A'),
1565  	 	 	 '1'=>array('B','A','B','A','A'),
1566  	 	 	 '2'=>array('B','A','A','B','A'),
1567  	 	 	 '3'=>array('B','A','A','A','B'),
1568  	 	 	 '4'=>array('A','B','B','A','A'),
1569  	 	 	 '5'=>array('A','A','B','B','A'),
1570  	 	 	 '6'=>array('A','A','A','B','B'),
1571  	 	 	 '7'=>array('A','B','A','B','A'),
1572  	 	 	 '8'=>array('A','B','A','A','B'),
1573  	 	 	 '9'=>array('A','A','B','A','B')
1574  	 	 );
1575  	 	 $p = $parities[$len][$r];
1576  	 	 $seq = '1011'; // left guard bar
1577  	 	 $seq .= $codes[$p[0]][$code[0]];
1578  	 	 for ($i = 1; $i < $len; ++$i) {
1579  	 	 	 $seq .= '01'; // separator
1580  	 	 	 $seq .= $codes[$p[$i]][$code[$i]];
1581  	 	 }
1582  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1583  	 	 return $this->binseq_to_array($seq, $bararray);
1584  	 }
1585  
1586  	 /**
1587  	  * POSTNET and PLANET barcodes.
1588  	  * Used by U.S. Postal Service for automated mail sorting
1589  	  * @param string $code zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
1590  	  * @param boolean $planet if true print the PLANET barcode, otherwise print POSTNET
1591  	  * @return array barcode representation.
1592  	  * @protected
1593  	  */
1594  	protected function barcode_postnet($code, $planet=false) {
1595  	 	 // bar length
1596  	 	 if ($planet) {
1597  	 	 	 $barlen = Array(
1598  	 	 	 	 0 => Array(1,1,2,2,2),
1599  	 	 	 	 1 => Array(2,2,2,1,1),
1600  	 	 	 	 2 => Array(2,2,1,2,1),
1601  	 	 	 	 3 => Array(2,2,1,1,2),
1602  	 	 	 	 4 => Array(2,1,2,2,1),
1603  	 	 	 	 5 => Array(2,1,2,1,2),
1604  	 	 	 	 6 => Array(2,1,1,2,2),
1605  	 	 	 	 7 => Array(1,2,2,2,1),
1606  	 	 	 	 8 => Array(1,2,2,1,2),
1607  	 	 	 	 9 => Array(1,2,1,2,2)
1608  	 	 	 );
1609  	 	 } else {
1610  	 	 	 $barlen = Array(
1611  	 	 	 	 0 => Array(2,2,1,1,1),
1612  	 	 	 	 1 => Array(1,1,1,2,2),
1613  	 	 	 	 2 => Array(1,1,2,1,2),
1614  	 	 	 	 3 => Array(1,1,2,2,1),
1615  	 	 	 	 4 => Array(1,2,1,1,2),
1616  	 	 	 	 5 => Array(1,2,1,2,1),
1617  	 	 	 	 6 => Array(1,2,2,1,1),
1618  	 	 	 	 7 => Array(2,1,1,1,2),
1619  	 	 	 	 8 => Array(2,1,1,2,1),
1620  	 	 	 	 9 => Array(2,1,2,1,1)
1621  	 	 	 );
1622  	 	 }
1623  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1624  	 	 $k = 0;
1625  	 	 $code = str_replace('-', '', $code);
1626  	 	 $code = str_replace(' ', '', $code);
1627  	 	 $len = strlen($code);
1628  	 	 // calculate checksum
1629  	 	 $sum = 0;
1630  	 	 for ($i = 0; $i < $len; ++$i) {
1631  	 	 	 $sum += intval($code[$i]);
1632  	 	 }
1633  	 	 $chkd = ($sum % 10);
1634  	 	 if($chkd > 0) {
1635  	 	 	 $chkd = (10 - $chkd);
1636  	 	 }
1637  	 	 $code .= $chkd;
1638  	 	 $len = strlen($code);
1639  	 	 // start bar
1640  	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1641  	 	 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1642  	 	 $bararray['maxw'] += 2;
1643  	 	 for ($i = 0; $i < $len; ++$i) {
1644  	 	 	 for ($j = 0; $j < 5; ++$j) {
1645  	 	 	 	 $h = $barlen[$code[$i]][$j];
1646  	 	 	 	 $p = floor(1 / $h);
1647  	 	 	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1648  	 	 	 	 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1649  	 	 	 	 $bararray['maxw'] += 2;
1650  	 	 	 }
1651  	 	 }
1652  	 	 // end bar
1653  	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1654  	 	 $bararray['maxw'] += 1;
1655  	 	 return $bararray;
1656  	 }
1657  
1658  	 /**
1659  	  * RMS4CC - CBC - KIX
1660  	  * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
1661  	  * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
1662  	  * @param string $code code to print
1663  	  * @param boolean $kix if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the code.
1664  	  * @return array barcode representation.
1665  	  * @protected
1666  	  */
1667  	protected function barcode_rms4cc($code, $kix=false) {
1668  	 	 $notkix = !$kix;
1669  	 	 // bar mode
1670  	 	 // 1 = pos 1, length 2
1671  	 	 // 2 = pos 1, length 3
1672  	 	 // 3 = pos 2, length 1
1673  	 	 // 4 = pos 2, length 2
1674  	 	 $barmode = array(
1675  	 	 	 '0' => array(3,3,2,2),
1676  	 	 	 '1' => array(3,4,1,2),
1677  	 	 	 '2' => array(3,4,2,1),
1678  	 	 	 '3' => array(4,3,1,2),
1679  	 	 	 '4' => array(4,3,2,1),
1680  	 	 	 '5' => array(4,4,1,1),
1681  	 	 	 '6' => array(3,1,4,2),
1682  	 	 	 '7' => array(3,2,3,2),
1683  	 	 	 '8' => array(3,2,4,1),
1684  	 	 	 '9' => array(4,1,3,2),
1685  	 	 	 'A' => array(4,1,4,1),
1686  	 	 	 'B' => array(4,2,3,1),
1687  	 	 	 'C' => array(3,1,2,4),
1688  	 	 	 'D' => array(3,2,1,4),
1689  	 	 	 'E' => array(3,2,2,3),
1690  	 	 	 'F' => array(4,1,1,4),
1691  	 	 	 'G' => array(4,1,2,3),
1692  	 	 	 'H' => array(4,2,1,3),
1693  	 	 	 'I' => array(1,3,4,2),
1694  	 	 	 'J' => array(1,4,3,2),
1695  	 	 	 'K' => array(1,4,4,1),
1696  	 	 	 'L' => array(2,3,3,2),
1697  	 	 	 'M' => array(2,3,4,1),
1698  	 	 	 'N' => array(2,4,3,1),
1699  	 	 	 'O' => array(1,3,2,4),
1700  	 	 	 'P' => array(1,4,1,4),
1701  	 	 	 'Q' => array(1,4,2,3),
1702  	 	 	 'R' => array(2,3,1,4),
1703  	 	 	 'S' => array(2,3,2,3),
1704  	 	 	 'T' => array(2,4,1,3),
1705  	 	 	 'U' => array(1,1,4,4),
1706  	 	 	 'V' => array(1,2,3,4),
1707  	 	 	 'W' => array(1,2,4,3),
1708  	 	 	 'X' => array(2,1,3,4),
1709  	 	 	 'Y' => array(2,1,4,3),
1710  	 	 	 'Z' => array(2,2,3,3)
1711  	 	 );
1712  	 	 $code = strtoupper($code);
1713  	 	 $len = strlen($code);
1714  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
1715  	 	 if ($notkix) {
1716  	 	 	 // table for checksum calculation (row,col)
1717  	 	 	 $checktable = array(
1718  	 	 	 	 '0' => array(1,1),
1719  	 	 	 	 '1' => array(1,2),
1720  	 	 	 	 '2' => array(1,3),
1721  	 	 	 	 '3' => array(1,4),
1722  	 	 	 	 '4' => array(1,5),
1723  	 	 	 	 '5' => array(1,0),
1724  	 	 	 	 '6' => array(2,1),
1725  	 	 	 	 '7' => array(2,2),
1726  	 	 	 	 '8' => array(2,3),
1727  	 	 	 	 '9' => array(2,4),
1728  	 	 	 	 'A' => array(2,5),
1729  	 	 	 	 'B' => array(2,0),
1730  	 	 	 	 'C' => array(3,1),
1731  	 	 	 	 'D' => array(3,2),
1732  	 	 	 	 'E' => array(3,3),
1733  	 	 	 	 'F' => array(3,4),
1734  	 	 	 	 'G' => array(3,5),
1735  	 	 	 	 'H' => array(3,0),
1736  	 	 	 	 'I' => array(4,1),
1737  	 	 	 	 'J' => array(4,2),
1738  	 	 	 	 'K' => array(4,3),
1739  	 	 	 	 'L' => array(4,4),
1740  	 	 	 	 'M' => array(4,5),
1741  	 	 	 	 'N' => array(4,0),
1742  	 	 	 	 'O' => array(5,1),
1743  	 	 	 	 'P' => array(5,2),
1744  	 	 	 	 'Q' => array(5,3),
1745  	 	 	 	 'R' => array(5,4),
1746  	 	 	 	 'S' => array(5,5),
1747  	 	 	 	 'T' => array(5,0),
1748  	 	 	 	 'U' => array(0,1),
1749  	 	 	 	 'V' => array(0,2),
1750  	 	 	 	 'W' => array(0,3),
1751  	 	 	 	 'X' => array(0,4),
1752  	 	 	 	 'Y' => array(0,5),
1753  	 	 	 	 'Z' => array(0,0)
1754  	 	 	 );
1755  	 	 	 $row = 0;
1756  	 	 	 $col = 0;
1757  	 	 	 for ($i = 0; $i < $len; ++$i) {
1758  	 	 	 	 $row += $checktable[$code[$i]][0];
1759  	 	 	 	 $col += $checktable[$code[$i]][1];
1760  	 	 	 }
1761  	 	 	 $row %= 6;
1762  	 	 	 $col %= 6;
1763  	 	 	 $chk = array_keys($checktable, array($row,$col));
1764  	 	 	 $code .= $chk[0];
1765  	 	 	 ++$len;
1766  	 	 }
1767  	 	 $k = 0;
1768  	 	 if ($notkix) {
1769  	 	 	 // start bar
1770  	 	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1771  	 	 	 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1772  	 	 	 $bararray['maxw'] += 2;
1773  	 	 }
1774  	 	 for ($i = 0; $i < $len; ++$i) {
1775  	 	 	 for ($j = 0; $j < 4; ++$j) {
1776  	 	 	 	 switch ($barmode[$code[$i]][$j]) {
1777  	 	 	 	 	 case 1: {
1778  	 	 	 	 	 	 $p = 0;
1779  	 	 	 	 	 	 $h = 2;
1780  	 	 	 	 	 	 break;
1781  	 	 	 	 	 }
1782  	 	 	 	 	 case 2: {
1783  	 	 	 	 	 	 $p = 0;
1784  	 	 	 	 	 	 $h = 3;
1785  	 	 	 	 	 	 break;
1786  	 	 	 	 	 }
1787  	 	 	 	 	 case 3: {
1788  	 	 	 	 	 	 $p = 1;
1789  	 	 	 	 	 	 $h = 1;
1790  	 	 	 	 	 	 break;
1791  	 	 	 	 	 }
1792  	 	 	 	 	 case 4: {
1793  	 	 	 	 	 	 $p = 1;
1794  	 	 	 	 	 	 $h = 2;
1795  	 	 	 	 	 	 break;
1796  	 	 	 	 	 }
1797  	 	 	 	 }
1798  	 	 	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1799  	 	 	 	 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1800  	 	 	 	 $bararray['maxw'] += 2;
1801  	 	 	 }
1802  	 	 }
1803  	 	 if ($notkix) {
1804  	 	 	 // stop bar
1805  	 	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0);
1806  	 	 	 $bararray['maxw'] += 1;
1807  	 	 }
1808  	 	 return $bararray;
1809  	 }
1810  
1811  	 /**
1812  	  * CODABAR barcodes.
1813  	  * Older code often used in library systems, sometimes in blood banks
1814  	  * @param string $code code to represent.
1815  	  * @return array barcode representation.
1816  	  * @protected
1817  	  */
1818  	protected function barcode_codabar($code) {
1819  	 	 $chr = array(
1820  	 	 	 '0' => '11111221',
1821  	 	 	 '1' => '11112211',
1822  	 	 	 '2' => '11121121',
1823  	 	 	 '3' => '22111111',
1824  	 	 	 '4' => '11211211',
1825  	 	 	 '5' => '21111211',
1826  	 	 	 '6' => '12111121',
1827  	 	 	 '7' => '12112111',
1828  	 	 	 '8' => '12211111',
1829  	 	 	 '9' => '21121111',
1830  	 	 	 '-' => '11122111',
1831  	 	 	 '$' => '11221111',
1832  	 	 	 ':' => '21112121',
1833  	 	 	 '/' => '21211121',
1834  	 	 	 '.' => '21212111',
1835  	 	 	 '+' => '11222221',
1836  	 	 	 'A' => '11221211',
1837  	 	 	 'B' => '12121121',
1838  	 	 	 'C' => '11121221',
1839  	 	 	 'D' => '11122211'
1840  	 	 );
1841  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1842  	 	 $k = 0;
1843  	 	 $w = 0;
1844  	 	 $seq = '';
1845  	 	 $code = 'A'.strtoupper($code).'A';
1846  	 	 $len = strlen($code);
1847  	 	 for ($i = 0; $i < $len; ++$i) {
1848  	 	 	 if (!isset($chr[$code[$i]])) {
1849  	 	 	 	 return false;
1850  	 	 	 }
1851  	 	 	 $seq = $chr[$code[$i]];
1852  	 	 	 for ($j = 0; $j < 8; ++$j) {
1853  	 	 	 	 if (($j % 2) == 0) {
1854  	 	 	 	 	 $t = true; // bar
1855  	 	 	 	 } else {
1856  	 	 	 	 	 $t = false; // space
1857  	 	 	 	 }
1858  	 	 	 	 $w = (float)$seq[$j];
1859  	 	 	 	 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1860  	 	 	 	 $bararray['maxw'] += $w;
1861  	 	 	 	 ++$k;
1862  	 	 	 }
1863  	 	 }
1864  	 	 return $bararray;
1865  	 }
1866  
1867  	 /**
1868  	  * CODE11 barcodes.
1869  	  * Used primarily for labeling telecommunications equipment
1870  	  * @param string $code code to represent.
1871  	  * @return array barcode representation.
1872  	  * @protected
1873  	  */
1874  	protected function barcode_code11($code) {
1875  	 	 $chr = array(
1876  	 	 	 '0' => '111121',
1877  	 	 	 '1' => '211121',
1878  	 	 	 '2' => '121121',
1879  	 	 	 '3' => '221111',
1880  	 	 	 '4' => '112121',
1881  	 	 	 '5' => '212111',
1882  	 	 	 '6' => '122111',
1883  	 	 	 '7' => '111221',
1884  	 	 	 '8' => '211211',
1885  	 	 	 '9' => '211111',
1886  	 	 	 '-' => '112111',
1887  	 	 	 'S' => '112211'
1888  	 	 );
1889  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1890  	 	 $k = 0;
1891  	 	 $w = 0;
1892  	 	 $seq = '';
1893  	 	 $len = strlen($code);
1894  	 	 // calculate check digit C
1895  	 	 $p = 1;
1896  	 	 $check = 0;
1897  	 	 for ($i = ($len - 1); $i >= 0; --$i) {
1898  	 	 	 $digit = $code[$i];
1899  	 	 	 if ($digit == '-') {
1900  	 	 	 	 $dval = 10;
1901  	 	 	 } else {
1902  	 	 	 	 $dval = intval($digit);
1903  	 	 	 }
1904  	 	 	 $check += ($dval * $p);
1905  	 	 	 ++$p;
1906  	 	 	 if ($p > 10) {
1907  	 	 	 	 $p = 1;
1908  	 	 	 }
1909  	 	 }
1910  	 	 $check %= 11;
1911  	 	 if ($check == 10) {
1912  	 	 	 $check = '-';
1913  	 	 }
1914  	 	 $code .= $check;
1915  	 	 if ($len > 10) {
1916  	 	 	 // calculate check digit K
1917  	 	 	 $p = 1;
1918  	 	 	 $check = 0;
1919  	 	 	 for ($i = $len; $i >= 0; --$i) {
1920  	 	 	 	 $digit = $code[$i];
1921  	 	 	 	 if ($digit == '-') {
1922  	 	 	 	 	 $dval = 10;
1923  	 	 	 	 } else {
1924  	 	 	 	 	 $dval = intval($digit);
1925  	 	 	 	 }
1926  	 	 	 	 $check += ($dval * $p);
1927  	 	 	 	 ++$p;
1928  	 	 	 	 if ($p > 9) {
1929  	 	 	 	 	 $p = 1;
1930  	 	 	 	 }
1931  	 	 	 }
1932  	 	 	 $check %= 11;
1933  	 	 	 $code .= $check;
1934  	 	 	 ++$len;
1935  	 	 }
1936  	 	 $code = 'S'.$code.'S';
1937  	 	 $len += 3;
1938  	 	 for ($i = 0; $i < $len; ++$i) {
1939  	 	 	 if (!isset($chr[$code[$i]])) {
1940  	 	 	 	 return false;
1941  	 	 	 }
1942  	 	 	 $seq = $chr[$code[$i]];
1943  	 	 	 for ($j = 0; $j < 6; ++$j) {
1944  	 	 	 	 if (($j % 2) == 0) {
1945  	 	 	 	 	 $t = true; // bar
1946  	 	 	 	 } else {
1947  	 	 	 	 	 $t = false; // space
1948  	 	 	 	 }
1949  	 	 	 	 $w = (float)$seq[$j];
1950  	 	 	 	 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1951  	 	 	 	 $bararray['maxw'] += $w;
1952  	 	 	 	 ++$k;
1953  	 	 	 }
1954  	 	 }
1955  	 	 return $bararray;
1956  	 }
1957  
1958  	 /**
1959  	  * Pharmacode
1960  	  * Contains digits (0 to 9)
1961  	  * @param string $code code to represent.
1962  	  * @return array barcode representation.
1963  	  * @protected
1964  	  */
1965  	protected function barcode_pharmacode($code) {
1966  	 	 $seq = '';
1967  	 	 $code = intval($code);
1968  	 	 while ($code > 0) {
1969  	 	 	 if (($code % 2) == 0) {
1970  	 	 	 	 $seq .= '11100';
1971  	 	 	 	 $code -= 2;
1972  	 	 	 } else {
1973  	 	 	 	 $seq .= '100';
1974  	 	 	 	 $code -= 1;
1975  	 	 	 }
1976  	 	 	 $code /= 2;
1977  	 	 }
1978  	 	 $seq = substr($seq, 0, -2);
1979  	 	 $seq = strrev($seq);
1980  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1981  	 	 return $this->binseq_to_array($seq, $bararray);
1982  	 }
1983  
1984  	 /**
1985  	  * Pharmacode two-track
1986  	  * Contains digits (0 to 9)
1987  	  * @param string $code code to represent.
1988  	  * @return array barcode representation.
1989  	  * @protected
1990  	  */
1991  	protected function barcode_pharmacode2t($code) {
1992  	 	 $seq = '';
1993  	 	 $code = intval($code);
1994  	 	 do {
1995  	 	 	 switch ($code % 3) {
1996  	 	 	 	 case 0: {
1997  	 	 	 	 	 $seq .= '3';
1998  	 	 	 	 	 $code = ($code - 3) / 3;
1999  	 	 	 	 	 break;
2000  	 	 	 	 }
2001  	 	 	 	 case 1: {
2002  	 	 	 	 	 $seq .= '1';
2003  	 	 	 	 	 $code = ($code - 1) / 3;
2004  	 	 	 	 	 break;
2005  	 	 	 	 }
2006  	 	 	 	 case 2: {
2007  	 	 	 	 	 $seq .= '2';
2008  	 	 	 	 	 $code = ($code - 2) / 3;
2009  	 	 	 	 	 break;
2010  	 	 	 	 }
2011  	 	 	 }
2012  	 	 } while($code != 0);
2013  	 	 $seq = strrev($seq);
2014  	 	 $k = 0;
2015  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
2016  	 	 $len = strlen($seq);
2017  	 	 for ($i = 0; $i < $len; ++$i) {
2018  	 	 	 switch ($seq[$i]) {
2019  	 	 	 	 case '1': {
2020  	 	 	 	 	 $p = 1;
2021  	 	 	 	 	 $h = 1;
2022  	 	 	 	 	 break;
2023  	 	 	 	 }
2024  	 	 	 	 case '2': {
2025  	 	 	 	 	 $p = 0;
2026  	 	 	 	 	 $h = 1;
2027  	 	 	 	 	 break;
2028  	 	 	 	 }
2029  	 	 	 	 case '3': {
2030  	 	 	 	 	 $p = 0;
2031  	 	 	 	 	 $h = 2;
2032  	 	 	 	 	 break;
2033  	 	 	 	 }
2034  	 	 	 }
2035  	 	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2036  	 	 	 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2037  	 	 	 $bararray['maxw'] += 2;
2038  	 	 }
2039  	 	 unset($bararray['bcode'][($k - 1)]);
2040  	 	 --$bararray['maxw'];
2041  	 	 return $bararray;
2042  	 }
2043  
2044  	 /**
2045  	  * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
2046  	  * (requires PHP bcmath extension)
2047  	  * Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
2048  	  * 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>
2049  	  * @param string $code code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
2050  	  * @return array barcode representation.
2051  	  * @protected
2052  	  */
2053  	protected function barcode_imb($code) {
2054  	 	 $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);
2055  	 	 $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);
2056  	 	 $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);
2057  	 	 $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);
2058  	 	 $code_arr = explode('-', $code);
2059  	 	 $tracking_number = $code_arr[0];
2060  	 	 if (isset($code_arr[1])) {
2061  	 	 	 $routing_code = $code_arr[1];
2062  	 	 } else {
2063  	 	 	 $routing_code = '';
2064  	 	 }
2065  	 	 // Conversion of Routing Code
2066  	 	 switch (strlen($routing_code)) {
2067  	 	 	 case 0: {
2068  	 	 	 	 $binary_code = 0;
2069  	 	 	 	 break;
2070  	 	 	 }
2071  	 	 	 case 5: {
2072  	 	 	 	 $binary_code = bcadd($routing_code, '1');
2073  	 	 	 	 break;
2074  	 	 	 }
2075  	 	 	 case 9: {
2076  	 	 	 	 $binary_code = bcadd($routing_code, '100001');
2077  	 	 	 	 break;
2078  	 	 	 }
2079  	 	 	 case 11: {
2080  	 	 	 	 $binary_code = bcadd($routing_code, '1000100001');
2081  	 	 	 	 break;
2082  	 	 	 }
2083  	 	 	 default: {
2084  	 	 	 	 return false;
2085  	 	 	 	 break;
2086  	 	 	 }
2087  	 	 }
2088  	 	 $binary_code = bcmul($binary_code, 10);
2089  	 	 $binary_code = bcadd($binary_code, $tracking_number[0]);
2090  	 	 $binary_code = bcmul($binary_code, 5);
2091  	 	 $binary_code = bcadd($binary_code, $tracking_number[1]);
2092  	 	 $binary_code .= substr($tracking_number, 2, 18);
2093  	 	 // convert to hexadecimal
2094  	 	 $binary_code = $this->dec_to_hex($binary_code);
2095  	 	 // pad to get 13 bytes
2096  	 	 $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
2097  	 	 // convert string to array of bytes
2098  	 	 $binary_code_arr = chunk_split($binary_code, 2, "\r");
2099  	 	 $binary_code_arr = substr($binary_code_arr, 0, -1);
2100  	 	 $binary_code_arr = explode("\r", $binary_code_arr);
2101  	 	 // calculate frame check sequence
2102  	 	 $fcs = $this->imb_crc11fcs($binary_code_arr);
2103  	 	 // exclude first 2 bits from first byte
2104  	 	 $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
2105  	 	 $binary_code_102bit = $first_byte.substr($binary_code, 2);
2106  	 	 // convert binary data to codewords
2107  	 	 $codewords = array();
2108  	 	 $data = $this->hex_to_dec($binary_code_102bit);
2109  	 	 $codewords[0] = bcmod($data, 636) * 2;
2110  	 	 $data = bcdiv($data, 636);
2111  	 	 for ($i = 1; $i < 9; ++$i) {
2112  	 	 	 $codewords[$i] = bcmod($data, 1365);
2113  	 	 	 $data = bcdiv($data, 1365);
2114  	 	 }
2115  	 	 $codewords[9] = $data;
2116  	 	 if (($fcs >> 10) == 1) {
2117  	 	 	 $codewords[9] += 659;
2118  	 	 }
2119  	 	 // generate lookup tables
2120  	 	 $table2of13 = $this->imb_tables(2, 78);
2121  	 	 $table5of13 = $this->imb_tables(5, 1287);
2122  	 	 // convert codewords to characters
2123  	 	 $characters = array();
2124  	 	 $bitmask = 512;
2125  	 	 foreach($codewords as $k => $val) {
2126  	 	 	 if ($val <= 1286) {
2127  	 	 	 	 $chrcode = $table5of13[$val];
2128  	 	 	 } else {
2129  	 	 	 	 $chrcode = $table2of13[($val - 1287)];
2130  	 	 	 }
2131  	 	 	 if (($fcs & $bitmask) > 0) {
2132  	 	 	 	 // bitwise invert
2133  	 	 	 	 $chrcode = ((~$chrcode) & 8191);
2134  	 	 	 }
2135  	 	 	 $characters[] = $chrcode;
2136  	 	 	 $bitmask /= 2;
2137  	 	 }
2138  	 	 $characters = array_reverse($characters);
2139  	 	 // build bars
2140  	 	 $k = 0;
2141  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
2142  	 	 for ($i = 0; $i < 65; ++$i) {
2143  	 	 	 $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0);
2144  	 	 	 $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0);
2145  	 	 	 if ($asc AND $dsc) {
2146  	 	 	 	 // full bar (F)
2147  	 	 	 	 $p = 0;
2148  	 	 	 	 $h = 3;
2149  	 	 	 } elseif ($asc) {
2150  	 	 	 	 // ascender (A)
2151  	 	 	 	 $p = 0;
2152  	 	 	 	 $h = 2;
2153  	 	 	 } elseif ($dsc) {
2154  	 	 	 	 // descender (D)
2155  	 	 	 	 $p = 1;
2156  	 	 	 	 $h = 2;
2157  	 	 	 } else {
2158  	 	 	 	 // tracker (T)
2159  	 	 	 	 $p = 1;
2160  	 	 	 	 $h = 1;
2161  	 	 	 }
2162  	 	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2163  	 	 	 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2164  	 	 	 $bararray['maxw'] += 2;
2165  	 	 }
2166  	 	 unset($bararray['bcode'][($k - 1)]);
2167  	 	 --$bararray['maxw'];
2168  	 	 return $bararray;
2169  	 }
2170  
2171  	 /**
2172  	  * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
2173  	  *
2174  	  * @param string $code pre-formatted IMB barcode (65 chars "FADT")
2175  	  * @return array barcode representation.
2176  	  * @protected
2177  	  */
2178  	protected function barcode_imb_pre($code) {
2179  	 	 if (!preg_match('/^[fadtFADT]{65}$/', $code) == 1) {
2180  	 	 	 return false;
2181  	 	 }
2182  	 	 $characters = str_split(strtolower($code), 1);
2183  	 	 // build bars
2184  	 	 $k = 0;
2185  	 	 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
2186  	 	 for ($i = 0; $i < 65; ++$i) {
2187  	 	 	 switch($characters[$i]) {
2188  	 	 	 	 case 'f': {
2189  	 	 	 	 	 // full bar
2190  	 	 	 	 	 $p = 0;
2191  	 	 	 	 	 $h = 3;
2192  	 	 	 	 	 break;
2193  	 	 	 	 }
2194  	 	 	 	 case 'a': {
2195  	 	 	 	 	 // ascender
2196  	 	 	 	 	 $p = 0;
2197  	 	 	 	 	 $h = 2;
2198  	 	 	 	 	 break;
2199  	 	 	 	 }
2200  	 	 	 	 case 'd': {
2201  	 	 	 	 	 // descender
2202  	 	 	 	 	 $p = 1;
2203  	 	 	 	 	 $h = 2;
2204  	 	 	 	 	 break;
2205  	 	 	 	 }
2206  	 	 	 	 case 't': {
2207  	 	 	 	 	 // tracker (short)
2208  	 	 	 	 	 $p = 1;
2209  	 	 	 	 	 $h = 1;
2210  	 	 	 	 	 break;
2211  	 	 	 	 }
2212  	 	 	 }
2213  	 	 	 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2214  	 	 	 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2215  	 	 	 $bararray['maxw'] += 2;
2216  	 	 }
2217  	 	 unset($bararray['bcode'][($k - 1)]);
2218  	 	 --$bararray['maxw'];
2219  	 	 return $bararray;
2220  	 }
2221  
2222  	 /**
2223  	  * Convert large integer number to hexadecimal representation.
2224  	  * (requires PHP bcmath extension)
2225  	  * @param string $number number to convert specified as a string
2226  	  * @return string hexadecimal representation
2227  	  */
2228  	public function dec_to_hex($number) {
2229  	 	 $i = 0;
2230  	 	 $hex = array();
2231  	 	 if($number == 0) {
2232  	 	 	 return '00';
2233  	 	 }
2234  	 	 while($number > 0) {
2235  	 	 	 if($number == 0) {
2236  	 	 	 	 array_push($hex, '0');
2237  	 	 	 } else {
2238  	 	 	 	 array_push($hex, strtoupper(dechex(bcmod($number, '16'))));
2239  	 	 	 	 $number = bcdiv($number, '16', 0);
2240  	 	 	 }
2241  	 	 }
2242  	 	 $hex = array_reverse($hex);
2243  	 	 return implode($hex);
2244  	 }
2245  
2246  	 /**
2247  	  * Convert large hexadecimal number to decimal representation (string).
2248  	  * (requires PHP bcmath extension)
2249  	  * @param string $hex hexadecimal number to convert specified as a string
2250  	  * @return string hexadecimal representation
2251  	  */
2252  	public function hex_to_dec($hex) {
2253  	 	 $dec = 0;
2254  	 	 $bitval = 1;
2255  	 	 $len = strlen($hex);
2256  	 	 for($pos = ($len - 1); $pos >= 0; --$pos) {
2257  	 	 	 $dec = bcadd($dec, bcmul(hexdec($hex[$pos]), $bitval));
2258  	 	 	 $bitval = bcmul($bitval, 16);
2259  	 	 }
2260  	 	 return $dec;
2261  	 }
2262  
2263  	 /**
2264  	  * Intelligent Mail Barcode calculation of Frame Check Sequence
2265  	  * @param string $code_arr array of hexadecimal values (13 bytes holding 102 bits right justified).
2266  	  * @return int 11 bit Frame Check Sequence as integer (decimal base)
2267  	  * @protected
2268  	  */
2269  	protected function imb_crc11fcs($code_arr) {
2270  	 	 $genpoly = 0x0F35; // generator polynomial
2271  	 	 $fcs = 0x07FF; // Frame Check Sequence
2272  	 	 // do most significant byte skipping the 2 most significant bits
2273  	 	 $data = hexdec($code_arr[0]) << 5;
2274  	 	 for ($bit = 2; $bit < 8; ++$bit) {
2275  	 	 	 if (($fcs ^ $data) & 0x400) {
2276  	 	 	 	 $fcs = ($fcs << 1) ^ $genpoly;
2277  	 	 	 } else {
2278  	 	 	 	 $fcs = ($fcs << 1);
2279  	 	 	 }
2280  	 	 	 $fcs &= 0x7FF;
2281  	 	 	 $data <<= 1;
2282  	 	 }
2283  	 	 // do rest of bytes
2284  	 	 for ($byte = 1; $byte < 13; ++$byte) {
2285  	 	 	 $data = hexdec($code_arr[$byte]) << 3;
2286  	 	 	 for ($bit = 0; $bit < 8; ++$bit) {
2287  	 	 	 	 if (($fcs ^ $data) & 0x400) {
2288  	 	 	 	 	 $fcs = ($fcs << 1) ^ $genpoly;
2289  	 	 	 	 } else {
2290  	 	 	 	 	 $fcs = ($fcs << 1);
2291  	 	 	 	 }
2292  	 	 	 	 $fcs &= 0x7FF;
2293  	 	 	 	 $data <<= 1;
2294  	 	 	 }
2295  	 	 }
2296  	 	 return $fcs;
2297  	 }
2298  
2299  	 /**
2300  	  * Reverse unsigned short value
2301  	  * @param int $num value to reversr
2302  	  * @return int reversed value
2303  	  * @protected
2304  	  */
2305  	protected function imb_reverse_us($num) {
2306  	 	 $rev = 0;
2307  	 	 for ($i = 0; $i < 16; ++$i) {
2308  	 	 	 $rev <<= 1;
2309  	 	 	 $rev |= ($num & 1);
2310  	 	 	 $num >>= 1;
2311  	 	 }
2312  	 	 return $rev;
2313  	 }
2314  
2315  	 /**
2316  	  * generate Nof13 tables used for Intelligent Mail Barcode
2317  	  * @param int $n is the type of table: 2 for 2of13 table, 5 for 5of13table
2318  	  * @param int $size size of table (78 for n=2 and 1287 for n=5)
2319  	  * @return array requested table
2320  	  * @protected
2321  	  */
2322  	protected function imb_tables($n, $size) {
2323  	 	 $table = array();
2324  	 	 $lli = 0; // LUT lower index
2325  	 	 $lui = $size - 1; // LUT upper index
2326  	 	 for ($count = 0; $count < 8192; ++$count) {
2327  	 	 	 $bit_count = 0;
2328  	 	 	 for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
2329  	 	 	 	 $bit_count += intval(($count & (1 << $bit_index)) != 0);
2330  	 	 	 }
2331  	 	 	 // if we don't have the right number of bits on, go on to the next value
2332  	 	 	 if ($bit_count == $n) {
2333  	 	 	 	 $reverse = ($this->imb_reverse_us($count) >> 3);
2334  	 	 	 	 // if the reverse is less than count, we have already visited this pair before
2335  	 	 	 	 if ($reverse >= $count) {
2336  	 	 	 	 	 // If count is symmetric, place it at the first free slot from the end of the list.
2337  	 	 	 	 	 // 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
2338  	 	 	 	 	 if ($reverse == $count) {
2339  	 	 	 	 	 	 $table[$lui] = $count;
2340  	 	 	 	 	 	 --$lui;
2341  	 	 	 	 	 } else {
2342  	 	 	 	 	 	 $table[$lli] = $count;
2343  	 	 	 	 	 	 ++$lli;
2344  	 	 	 	 	 	 $table[$lli] = $reverse;
2345  	 	 	 	 	 	 ++$lli;
2346  	 	 	 	 	 }
2347  	 	 	 	 }
2348  	 	 	 }
2349  	 	 }
2350  	 	 return $table;
2351  	 }
2352  
2353  } // end of class
2354  //============================================================+
2355  // END OF FILE
2356  //============================================================+