source-class-TCPDFBarcode

It appears that you are using AdBlocking software. The cost of running this website is covered by advertisements. If you like it please feel free to a small amount of money to secure the future of this website.
Overview

Classes

Interfaces

Exceptions

Functions

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

© 2004-2018 – Nicola Asuni - Tecnick.com - All rights reserved.
about - disclaimer - privacy