PageRenderTime 93ms CodeModel.GetById 16ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 1ms

/protected/vendors/tcpdf/barcodes.php

https://bitbucket.org/nochallenge/exlarlistprice
PHP | 2287 lines | 1835 code | 39 blank | 413 comment | 244 complexity | 95a8bcd8ee062567c2da61f8b822d5fb MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2//============================================================+
   3// File name   : barcodes.php
   4// Version     : 1.0.025
   5// Begin       : 2008-06-09
   6// Last Update : 2012-09-11
   7// Author      : Nicola Asuni - Tecnick.com LTD - Manor Coach House, Church Hill, Aldershot, Hants, GU12 4RQ, UK - www.tecnick.com - info@tecnick.com
   8// License     : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
   9// -------------------------------------------------------------------
  10// Copyright (C) 2008-2012  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.025
  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.025
  48 * @author Nicola Asuni
  49 */
  50class TCPDFBarcode {
  51
  52	/**
  53	 * Array representation of barcode.
  54	 * @protected
  55	 */
  56	protected $barcode_array;
  57
  58	/**
  59	 * This is the class constructor.
  60	 * Return an array representations for common 1D barcodes:<ul>
  61	 * <li>$arrcode['code'] code to be printed on text label</li>
  62	 * <li>$arrcode['maxh'] max barcode height</li>
  63	 * <li>$arrcode['maxw'] max barcode width</li>
  64	 * <li>$arrcode['bcode'][$k] single bar or space in $k position</li>
  65	 * <li>$arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.</li>
  66	 * <li>$arrcode['bcode'][$k]['w'] bar width in units.</li>
  67	 * <li>$arrcode['bcode'][$k]['h'] bar height in units.</li>
  68	 * <li>$arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)</li></ul>
  69	 * @param $code (string) code to print
  70 	 * @param $type (string) type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128 : CODE 128</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
  71 	 * @public
  72	 */
  73	public function __construct($code, $type) {
  74		$this->setBarcode($code, $type);
  75	}
  76
  77	/**
  78	 * Return an array representations of barcode.
  79 	 * @return array
  80 	 * @public
  81	 */
  82	public function getBarcodeArray() {
  83		return $this->barcode_array;
  84	}
  85
  86	/**
  87	 * Send barcode as SVG image object to the standard output.
  88	 * @param $w (int) Minimum width of a single bar in user units.
  89	 * @param $h (int) Height of barcode in user units.
  90	 * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
  91 	 * @public
  92	 */
  93	public function getBarcodeSVG($w=2, $h=30, $color='black') {
  94		// send headers
  95		$code = $this->getBarcodeSVGcode($w, $h, $color);
  96		header('Content-Type: application/svg+xml');
  97		header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
  98		header('Pragma: public');
  99		header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
 100		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
 101		header('Content-Disposition: inline; filename="'.md5($code).'.svg";');
 102		//header('Content-Length: '.strlen($code));
 103		echo $code;
 104	}
 105
 106	/**
 107	 * Return a SVG string representation of barcode.
 108	 * @param $w (int) Minimum width of a single bar in user units.
 109	 * @param $h (int) Height of barcode in user units.
 110	 * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
 111 	 * @return string SVG code.
 112 	 * @public
 113	 */
 114	public function getBarcodeSVGcode($w=2, $h=30, $color='black') {
 115		// replace table for special characters
 116		$repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
 117		$svg = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n";
 118		$svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n";
 119		$svg .= '<svg width="'.round(($this->barcode_array['maxw'] * $w), 3).'" height="'.$h.'" version="1.1" xmlns="http://www.w3.org/2000/svg">'."\n";
 120		$svg .= "\t".'<desc>'.strtr($this->barcode_array['code'], $repstr).'</desc>'."\n";
 121		$svg .= "\t".'<g id="bars" fill="'.$color.'" stroke="none">'."\n";
 122		// print bars
 123		$x = 0;
 124		foreach ($this->barcode_array['bcode'] as $k => $v) {
 125			$bw = round(($v['w'] * $w), 3);
 126			$bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
 127			if ($v['t']) {
 128				$y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
 129				// draw a vertical bar
 130				$svg .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$bw.'" height="'.$bh.'" />'."\n";
 131			}
 132			$x += $bw;
 133		}
 134		$svg .= "\t".'</g>'."\n";
 135		$svg .= '</svg>'."\n";
 136		return $svg;
 137	}
 138
 139	/**
 140	 * Return an HTML representation of barcode.
 141	 * @param $w (int) Width of a single bar element in pixels.
 142	 * @param $h (int) Height of a single bar element in pixels.
 143	 * @param $color (string) Foreground color for bar elements (background is transparent).
 144 	 * @return string HTML code.
 145 	 * @public
 146	 */
 147	public function getBarcodeHTML($w=2, $h=30, $color='black') {
 148		$html = '<div style="font-size:0;position:relative;width:'.($this->barcode_array['maxw'] * $w).'px;height:'.($h).'px;">'."\n";
 149		// print bars
 150		$x = 0;
 151		foreach ($this->barcode_array['bcode'] as $k => $v) {
 152			$bw = round(($v['w'] * $w), 3);
 153			$bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
 154			if ($v['t']) {
 155				$y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
 156				// draw a vertical bar
 157				$html .= '<div style="background-color:'.$color.';width:'.$bw.'px;height:'.$bh.'px;position:absolute;left:'.$x.'px;top:'.$y.'px;">&nbsp;</div>'."\n";
 158			}
 159			$x += $bw;
 160		}
 161		$html .= '</div>'."\n";
 162		return $html;
 163	}
 164
 165	/**
 166	 * Return 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 	 * @return image or false in case of error.
 171 	 * @public
 172	 */
 173	public function getBarcodePNG($w=2, $h=30, $color=array(0,0,0)) {
 174		// calculate image size
 175		$width = ($this->barcode_array['maxw'] * $w);
 176		$height = $h;
 177		if (function_exists('imagecreate')) {
 178			// GD library
 179			$imagick = false;
 180			$png = imagecreate($width, $height);
 181			$bgcol = imagecolorallocate($png, 255, 255, 255);
 182			imagecolortransparent($png, $bgcol);
 183			$fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
 184		} elseif (extension_loaded('imagick')) {
 185			$imagick = true;
 186			$bgcol = new imagickpixel('rgb(255,255,255');
 187			$fgcol = new imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')');
 188			$png = new Imagick();
 189			$png->newImage($width, $height, 'none', 'png');
 190			$bar = new imagickdraw();
 191			$bar->setfillcolor($fgcol);
 192		} else {
 193			return false;
 194		}
 195		// print bars
 196		$x = 0;
 197		foreach ($this->barcode_array['bcode'] as $k => $v) {
 198			$bw = round(($v['w'] * $w), 3);
 199			$bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
 200			if ($v['t']) {
 201				$y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
 202				// draw a vertical bar
 203				if ($imagick) {
 204					$bar->rectangle($x, $y, ($x + $bw - 1), ($y + $bh - 1));
 205				} else {
 206					imagefilledrectangle($png, $x, $y, ($x + $bw - 1), ($y + $bh - 1), $fgcol);
 207				}
 208			}
 209			$x += $bw;
 210		}
 211		// send headers
 212		header('Content-Type: image/png');
 213		header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
 214		header('Pragma: public');
 215		header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
 216		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
 217		if ($imagick) {
 218			$png->drawimage($bar);
 219			echo $png;
 220		} else {
 221			imagepng($png);
 222			imagedestroy($png);
 223		}
 224	}
 225
 226	/**
 227	 * Set the barcode.
 228	 * @param $code (string) code to print
 229 	 * @param $type (string) type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128 : CODE 128</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
 230 	 * @return array barcode array
 231 	 * @public
 232	 */
 233	public function setBarcode($code, $type) {
 234		switch (strtoupper($type)) {
 235			case 'C39': { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
 236				$arrcode = $this->barcode_code39($code, false, false);
 237				break;
 238			}
 239			case 'C39+': { // CODE 39 with checksum
 240				$arrcode = $this->barcode_code39($code, false, true);
 241				break;
 242			}
 243			case 'C39E': { // CODE 39 EXTENDED
 244				$arrcode = $this->barcode_code39($code, true, false);
 245				break;
 246			}
 247			case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM
 248				$arrcode = $this->barcode_code39($code, true, true);
 249				break;
 250			}
 251			case 'C93': { // CODE 93 - USS-93
 252				$arrcode = $this->barcode_code93($code);
 253				break;
 254			}
 255			case 'S25': { // Standard 2 of 5
 256				$arrcode = $this->barcode_s25($code, false);
 257				break;
 258			}
 259			case 'S25+': { // Standard 2 of 5 + CHECKSUM
 260				$arrcode = $this->barcode_s25($code, true);
 261				break;
 262			}
 263			case 'I25': { // Interleaved 2 of 5
 264				$arrcode = $this->barcode_i25($code, false);
 265				break;
 266			}
 267			case 'I25+': { // Interleaved 2 of 5 + CHECKSUM
 268				$arrcode = $this->barcode_i25($code, true);
 269				break;
 270			}
 271			case 'C128': { // CODE 128
 272				$arrcode = $this->barcode_c128($code, '');
 273				break;
 274			}
 275			case 'C128A': { // CODE 128 A
 276				$arrcode = $this->barcode_c128($code, 'A');
 277				break;
 278			}
 279			case 'C128B': { // CODE 128 B
 280				$arrcode = $this->barcode_c128($code, 'B');
 281				break;
 282			}
 283			case 'C128C': { // CODE 128 C
 284				$arrcode = $this->barcode_c128($code, 'C');
 285				break;
 286			}
 287			case 'EAN2': { // 2-Digits UPC-Based Extention
 288				$arrcode = $this->barcode_eanext($code, 2);
 289				break;
 290			}
 291			case 'EAN5': { // 5-Digits UPC-Based Extention
 292				$arrcode = $this->barcode_eanext($code, 5);
 293				break;
 294			}
 295			case 'EAN8': { // EAN 8
 296				$arrcode = $this->barcode_eanupc($code, 8);
 297				break;
 298			}
 299			case 'EAN13': { // EAN 13
 300				$arrcode = $this->barcode_eanupc($code, 13);
 301				break;
 302			}
 303			case 'UPCA': { // UPC-A
 304				$arrcode = $this->barcode_eanupc($code, 12);
 305				break;
 306			}
 307			case 'UPCE': { // UPC-E
 308				$arrcode = $this->barcode_eanupc($code, 6);
 309				break;
 310			}
 311			case 'MSI': { // MSI (Variation of Plessey code)
 312				$arrcode = $this->barcode_msi($code, false);
 313				break;
 314			}
 315			case 'MSI+': { // MSI + CHECKSUM (modulo 11)
 316				$arrcode = $this->barcode_msi($code, true);
 317				break;
 318			}
 319			case 'POSTNET': { // POSTNET
 320				$arrcode = $this->barcode_postnet($code, false);
 321				break;
 322			}
 323			case 'PLANET': { // PLANET
 324				$arrcode = $this->barcode_postnet($code, true);
 325				break;
 326			}
 327			case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
 328				$arrcode = $this->barcode_rms4cc($code, false);
 329				break;
 330			}
 331			case 'KIX': { // KIX (Klant index - Customer index)
 332				$arrcode = $this->barcode_rms4cc($code, true);
 333				break;
 334			}
 335			case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
 336				$arrcode = $this->barcode_imb($code);
 337				break;
 338			}
 339			case 'CODABAR': { // CODABAR
 340				$arrcode = $this->barcode_codabar($code);
 341				break;
 342			}
 343			case 'CODE11': { // CODE 11
 344				$arrcode = $this->barcode_code11($code);
 345				break;
 346			}
 347			case 'PHARMA': { // PHARMACODE
 348				$arrcode = $this->barcode_pharmacode($code);
 349				break;
 350			}
 351			case 'PHARMA2T': { // PHARMACODE TWO-TRACKS
 352				$arrcode = $this->barcode_pharmacode2t($code);
 353				break;
 354			}
 355			default: {
 356				$this->barcode_array = false;
 357				$arrcode = false;
 358				break;
 359			}
 360		}
 361		$this->barcode_array = $arrcode;
 362	}
 363
 364	/**
 365	 * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
 366	 * General-purpose code in very wide use world-wide
 367	 * @param $code (string) code to represent.
 368	 * @param $extended (boolean) if true uses the extended mode.
 369	 * @param $checksum (boolean) if true add a checksum to the code.
 370	 * @return array barcode representation.
 371	 * @protected
 372	 */
 373	protected function barcode_code39($code, $extended=false, $checksum=false) {
 374		$chr['0'] = '111331311';
 375		$chr['1'] = '311311113';
 376		$chr['2'] = '113311113';
 377		$chr['3'] = '313311111';
 378		$chr['4'] = '111331113';
 379		$chr['5'] = '311331111';
 380		$chr['6'] = '113331111';
 381		$chr['7'] = '111311313';
 382		$chr['8'] = '311311311';
 383		$chr['9'] = '113311311';
 384		$chr['A'] = '311113113';
 385		$chr['B'] = '113113113';
 386		$chr['C'] = '313113111';
 387		$chr['D'] = '111133113';
 388		$chr['E'] = '311133111';
 389		$chr['F'] = '113133111';
 390		$chr['G'] = '111113313';
 391		$chr['H'] = '311113311';
 392		$chr['I'] = '113113311';
 393		$chr['J'] = '111133311';
 394		$chr['K'] = '311111133';
 395		$chr['L'] = '113111133';
 396		$chr['M'] = '313111131';
 397		$chr['N'] = '111131133';
 398		$chr['O'] = '311131131';
 399		$chr['P'] = '113131131';
 400		$chr['Q'] = '111111333';
 401		$chr['R'] = '311111331';
 402		$chr['S'] = '113111331';
 403		$chr['T'] = '111131331';
 404		$chr['U'] = '331111113';
 405		$chr['V'] = '133111113';
 406		$chr['W'] = '333111111';
 407		$chr['X'] = '131131113';
 408		$chr['Y'] = '331131111';
 409		$chr['Z'] = '133131111';
 410		$chr['-'] = '131111313';
 411		$chr['.'] = '331111311';
 412		$chr[' '] = '133111311';
 413		$chr['$'] = '131313111';
 414		$chr['/'] = '131311131';
 415		$chr['+'] = '131113131';
 416		$chr['%'] = '111313131';
 417		$chr['*'] = '131131311';
 418		$code = strtoupper($code);
 419		if ($extended) {
 420			// extended mode
 421			$code = $this->encode_code39_ext($code);
 422		}
 423		if ($code === false) {
 424			return false;
 425		}
 426		if ($checksum) {
 427			// checksum
 428			$code .= $this->checksum_code39($code);
 429		}
 430		// add start and stop codes
 431		$code = '*'.$code.'*';
 432		$bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 433		$k = 0;
 434		$clen = strlen($code);
 435		for ($i = 0; $i < $clen; ++$i) {
 436			$char = $code{$i};
 437			if(!isset($chr[$char])) {
 438				// invalid character
 439				return false;
 440			}
 441			for ($j = 0; $j < 9; ++$j) {
 442				if (($j % 2) == 0) {
 443					$t = true; // bar
 444				} else {
 445					$t = false; // space
 446				}
 447				$w = $chr[$char]{$j};
 448				$bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 449				$bararray['maxw'] += $w;
 450				++$k;
 451			}
 452			// intercharacter gap
 453			$bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0);
 454			$bararray['maxw'] += 1;
 455			++$k;
 456		}
 457		return $bararray;
 458	}
 459
 460	/**
 461	 * Encode a string to be used for CODE 39 Extended mode.
 462	 * @param $code (string) code to represent.
 463	 * @return encoded string.
 464	 * @protected
 465	 */
 466	protected function encode_code39_ext($code) {
 467		$encode = array(
 468			chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
 469			chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
 470			chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
 471			chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
 472			chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
 473			chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
 474			chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
 475			chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
 476			chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
 477			chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
 478			chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
 479			chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
 480			chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
 481			chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
 482			chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
 483			chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
 484			chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
 485			chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
 486			chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
 487			chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
 488			chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
 489			chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
 490			chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
 491			chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
 492			chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
 493			chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
 494			chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
 495			chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
 496			chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
 497			chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
 498			chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
 499			chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
 500		$code_ext = '';
 501		$clen = strlen($code);
 502		for ($i = 0 ; $i < $clen; ++$i) {
 503			if (ord($code{$i}) > 127) {
 504				return false;
 505			}
 506			$code_ext .= $encode[$code{$i}];
 507		}
 508		return $code_ext;
 509	}
 510
 511	/**
 512	 * Calculate CODE 39 checksum (modulo 43).
 513	 * @param $code (string) code to represent.
 514	 * @return char checksum.
 515	 * @protected
 516	 */
 517	protected function checksum_code39($code) {
 518		$chars = array(
 519			'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 520			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
 521			'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 522			'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
 523		$sum = 0;
 524		$clen = strlen($code);
 525		for ($i = 0 ; $i < $clen; ++$i) {
 526			$k = array_keys($chars, $code{$i});
 527			$sum += $k[0];
 528		}
 529		$j = ($sum % 43);
 530		return $chars[$j];
 531	}
 532
 533	/**
 534	 * CODE 93 - USS-93
 535	 * Compact code similar to Code 39
 536	 * @param $code (string) code to represent.
 537	 * @return array barcode representation.
 538	 * @protected
 539	 */
 540	protected function barcode_code93($code) {
 541		$chr[48] = '131112'; // 0
 542		$chr[49] = '111213'; // 1
 543		$chr[50] = '111312'; // 2
 544		$chr[51] = '111411'; // 3
 545		$chr[52] = '121113'; // 4
 546		$chr[53] = '121212'; // 5
 547		$chr[54] = '121311'; // 6
 548		$chr[55] = '111114'; // 7
 549		$chr[56] = '131211'; // 8
 550		$chr[57] = '141111'; // 9
 551		$chr[65] = '211113'; // A
 552		$chr[66] = '211212'; // B
 553		$chr[67] = '211311'; // C
 554		$chr[68] = '221112'; // D
 555		$chr[69] = '221211'; // E
 556		$chr[70] = '231111'; // F
 557		$chr[71] = '112113'; // G
 558		$chr[72] = '112212'; // H
 559		$chr[73] = '112311'; // I
 560		$chr[74] = '122112'; // J
 561		$chr[75] = '132111'; // K
 562		$chr[76] = '111123'; // L
 563		$chr[77] = '111222'; // M
 564		$chr[78] = '111321'; // N
 565		$chr[79] = '121122'; // O
 566		$chr[80] = '131121'; // P
 567		$chr[81] = '212112'; // Q
 568		$chr[82] = '212211'; // R
 569		$chr[83] = '211122'; // S
 570		$chr[84] = '211221'; // T
 571		$chr[85] = '221121'; // U
 572		$chr[86] = '222111'; // V
 573		$chr[87] = '112122'; // W
 574		$chr[88] = '112221'; // X
 575		$chr[89] = '122121'; // Y
 576		$chr[90] = '123111'; // Z
 577		$chr[45] = '121131'; // -
 578		$chr[46] = '311112'; // .
 579		$chr[32] = '311211'; //
 580		$chr[36] = '321111'; // $
 581		$chr[47] = '112131'; // /
 582		$chr[43] = '113121'; // +
 583		$chr[37] = '211131'; // %
 584		$chr[128] = '121221'; // ($)
 585		$chr[129] = '311121'; // (/)
 586		$chr[130] = '122211'; // (+)
 587		$chr[131] = '312111'; // (%)
 588		$chr[42] = '111141'; // start-stop
 589		$code = strtoupper($code);
 590		$encode = array(
 591			chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C',
 592			chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G',
 593			chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K',
 594			chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O',
 595			chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S',
 596			chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W',
 597			chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A',
 598			chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E',
 599			chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C',
 600			chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G',
 601			chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K',
 602			chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O',
 603			chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
 604			chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
 605			chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F',
 606			chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J',
 607			chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
 608			chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
 609			chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
 610			chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
 611			chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
 612			chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
 613			chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K',
 614			chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O',
 615			chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C',
 616			chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G',
 617			chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K',
 618			chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O',
 619			chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S',
 620			chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W',
 621			chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P',
 622			chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T');
 623		$code_ext = '';
 624		$clen = strlen($code);
 625		for ($i = 0 ; $i < $clen; ++$i) {
 626			if (ord($code{$i}) > 127) {
 627				return false;
 628			}
 629			$code_ext .= $encode[$code{$i}];
 630		}
 631		// checksum
 632		$code_ext .= $this->checksum_code93($code_ext);
 633		// add start and stop codes
 634		$code = '*'.$code_ext.'*';
 635		$bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 636		$k = 0;
 637		$clen = strlen($code);
 638		for ($i = 0; $i < $clen; ++$i) {
 639			$char = ord($code{$i});
 640			if(!isset($chr[$char])) {
 641				// invalid character
 642				return false;
 643			}
 644			for ($j = 0; $j < 6; ++$j) {
 645				if (($j % 2) == 0) {
 646					$t = true; // bar
 647				} else {
 648					$t = false; // space
 649				}
 650				$w = $chr[$char]{$j};
 651				$bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 652				$bararray['maxw'] += $w;
 653				++$k;
 654			}
 655		}
 656		$bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0);
 657		$bararray['maxw'] += 1;
 658		++$k;
 659		return $bararray;
 660	}
 661
 662	/**
 663	 * Calculate CODE 93 checksum (modulo 47).
 664	 * @param $code (string) code to represent.
 665	 * @return string checksum code.
 666	 * @protected
 667	 */
 668	protected function checksum_code93($code) {
 669		$chars = array(
 670			'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 671			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
 672			'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 673			'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%',
 674			'<', '=', '>', '?');
 675		// translate special characters
 676		$code = strtr($code, chr(128).chr(131).chr(129).chr(130), '<=>?');
 677		$len = strlen($code);
 678		// calculate check digit C
 679		$p = 1;
 680		$check = 0;
 681		for ($i = ($len - 1); $i >= 0; --$i) {
 682			$k = array_keys($chars, $code{$i});
 683			$check += ($k[0] * $p);
 684			++$p;
 685			if ($p > 20) {
 686				$p = 1;
 687			}
 688		}
 689		$check %= 47;
 690		$c = $chars[$check];
 691		$code .= $c;
 692		// calculate check digit K
 693		$p = 1;
 694		$check = 0;
 695		for ($i = $len; $i >= 0; --$i) {
 696			$k = array_keys($chars, $code{$i});
 697			$check += ($k[0] * $p);
 698			++$p;
 699			if ($p > 15) {
 700				$p = 1;
 701			}
 702		}
 703		$check %= 47;
 704		$k = $chars[$check];
 705		$checksum = $c.$k;
 706		// resto respecial characters
 707		$checksum = strtr($checksum, '<=>?', chr(128).chr(131).chr(129).chr(130));
 708		return $checksum;
 709	}
 710
 711	/**
 712	 * Checksum for standard 2 of 5 barcodes.
 713	 * @param $code (string) code to process.
 714	 * @return int checksum.
 715	 * @protected
 716	 */
 717	protected function checksum_s25($code) {
 718		$len = strlen($code);
 719		$sum = 0;
 720		for ($i = 0; $i < $len; $i+=2) {
 721			$sum += $code{$i};
 722		}
 723		$sum *= 3;
 724		for ($i = 1; $i < $len; $i+=2) {
 725			$sum += ($code{$i});
 726		}
 727		$r = $sum % 10;
 728		if($r > 0) {
 729			$r = (10 - $r);
 730		}
 731		return $r;
 732	}
 733
 734	/**
 735	 * MSI.
 736	 * Variation of Plessey code, with similar applications
 737	 * Contains digits (0 to 9) and encodes the data only in the width of bars.
 738	 * @param $code (string) code to represent.
 739	 * @param $checksum (boolean) if true add a checksum to the code (modulo 11)
 740	 * @return array barcode representation.
 741	 * @protected
 742	 */
 743	protected function barcode_msi($code, $checksum=false) {
 744		$chr['0'] = '100100100100';
 745		$chr['1'] = '100100100110';
 746		$chr['2'] = '100100110100';
 747		$chr['3'] = '100100110110';
 748		$chr['4'] = '100110100100';
 749		$chr['5'] = '100110100110';
 750		$chr['6'] = '100110110100';
 751		$chr['7'] = '100110110110';
 752		$chr['8'] = '110100100100';
 753		$chr['9'] = '110100100110';
 754		$chr['A'] = '110100110100';
 755		$chr['B'] = '110100110110';
 756		$chr['C'] = '110110100100';
 757		$chr['D'] = '110110100110';
 758		$chr['E'] = '110110110100';
 759		$chr['F'] = '110110110110';
 760		if ($checksum) {
 761			// add checksum
 762			$clen = strlen($code);
 763			$p = 2;
 764			$check = 0;
 765			for ($i = ($clen - 1); $i >= 0; --$i) {
 766				$check += (hexdec($code{$i}) * $p);
 767				++$p;
 768				if ($p > 7) {
 769					$p = 2;
 770				}
 771			}
 772			$check %= 11;
 773			if ($check > 0) {
 774				$check = 11 - $check;
 775			}
 776			$code .= $check;
 777		}
 778		$seq = '110'; // left guard
 779		$clen = strlen($code);
 780		for ($i = 0; $i < $clen; ++$i) {
 781			$digit = $code{$i};
 782			if (!isset($chr[$digit])) {
 783				// invalid character
 784				return false;
 785			}
 786			$seq .= $chr[$digit];
 787		}
 788		$seq .= '1001'; // right guard
 789		$bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 790		return $this->binseq_to_array($seq, $bararray);
 791	}
 792
 793	/**
 794	 * Standard 2 of 5 barcodes.
 795	 * Used in airline ticket marking, photofinishing
 796	 * Contains digits (0 to 9) and encodes the data only in the width of bars.
 797	 * @param $code (string) code to represent.
 798	 * @param $checksum (boolean) if true add a checksum to the code
 799	 * @return array barcode representation.
 800	 * @protected
 801	 */
 802	protected function barcode_s25($code, $checksum=false) {
 803		$chr['0'] = '10101110111010';
 804		$chr['1'] = '11101010101110';
 805		$chr['2'] = '10111010101110';
 806		$chr['3'] = '11101110101010';
 807		$chr['4'] = '10101110101110';
 808		$chr['5'] = '11101011101010';
 809		$chr['6'] = '10111011101010';
 810		$chr['7'] = '10101011101110';
 811		$chr['8'] = '10101110111010';
 812		$chr['9'] = '10111010111010';
 813		if ($checksum) {
 814			// add checksum
 815			$code .= $this->checksum_s25($code);
 816		}
 817		if((strlen($code) % 2) != 0) {
 818			// add leading zero if code-length is odd
 819			$code = '0'.$code;
 820		}
 821		$seq = '11011010';
 822		$clen = strlen($code);
 823		for ($i = 0; $i < $clen; ++$i) {
 824			$digit = $code{$i};
 825			if (!isset($chr[$digit])) {
 826				// invalid character
 827				return false;
 828			}
 829			$seq .= $chr[$digit];
 830		}
 831		$seq .= '1101011';
 832		$bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 833		return $this->binseq_to_array($seq, $bararray);
 834	}
 835
 836	/**
 837	 * Convert binary barcode sequence to TCPDF barcode array.
 838	 * @param $seq (string) barcode as binary sequence.
 839	 * @param $bararray (array) barcode array.
 840	 * òparam array $bararray TCPDF barcode array to fill up
 841	 * @return array barcode representation.
 842	 * @protected
 843	 */
 844	protected function binseq_to_array($seq, $bararray) {
 845		$len = strlen($seq);
 846		$w = 0;
 847		$k = 0;
 848		for ($i = 0; $i < $len; ++$i) {
 849			$w += 1;
 850			if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
 851				if ($seq{$i} == '1') {
 852					$t = true; // bar
 853				} else {
 854					$t = false; // space
 855				}
 856				$bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 857				$bararray['maxw'] += $w;
 858				++$k;
 859				$w = 0;
 860			}
 861		}
 862		return $bararray;
 863	}
 864
 865	/**
 866	 * Interleaved 2 of 5 barcodes.
 867	 * Compact numeric code, widely used in industry, air cargo
 868	 * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
 869	 * @param $code (string) code to represent.
 870	 * @param $checksum (boolean) if true add a checksum to the code
 871	 * @return array barcode representation.
 872	 * @protected
 873	 */
 874	protected function barcode_i25($code, $checksum=false) {
 875		$chr['0'] = '11221';
 876		$chr['1'] = '21112';
 877		$chr['2'] = '12112';
 878		$chr['3'] = '22111';
 879		$chr['4'] = '11212';
 880		$chr['5'] = '21211';
 881		$chr['6'] = '12211';
 882		$chr['7'] = '11122';
 883		$chr['8'] = '21121';
 884		$chr['9'] = '12121';
 885		$chr['A'] = '11';
 886		$chr['Z'] = '21';
 887		if ($checksum) {
 888			// add checksum
 889			$code .= $this->checksum_s25($code);
 890		}
 891		if((strlen($code) % 2) != 0) {
 892			// add leading zero if code-length is odd
 893			$code = '0'.$code;
 894		}
 895		// add start and stop codes
 896		$code = 'AA'.strtolower($code).'ZA';
 897
 898		$bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
 899		$k = 0;
 900		$clen = strlen($code);
 901		for ($i = 0; $i < $clen; $i = ($i + 2)) {
 902			$char_bar = $code{$i};
 903			$char_space = $code{$i+1};
 904			if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
 905				// invalid character
 906				return false;
 907			}
 908			// create a bar-space sequence
 909			$seq = '';
 910			$chrlen = strlen($chr[$char_bar]);
 911			for ($s = 0; $s < $chrlen; $s++){
 912				$seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
 913			}
 914			$seqlen = strlen($seq);
 915			for ($j = 0; $j < $seqlen; ++$j) {
 916				if (($j % 2) == 0) {
 917					$t = true; // bar
 918				} else {
 919					$t = false; // space
 920				}
 921				$w = $seq{$j};
 922				$bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
 923				$bararray['maxw'] += $w;
 924				++$k;
 925			}
 926		}
 927		return $bararray;
 928	}
 929
 930	/**
 931	 * C128 barcodes.
 932	 * Very capable code, excellent density, high reliability; in very wide use world-wide
 933	 * @param $code (string) code to represent.
 934	 * @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
 935	 * @return array barcode representation.
 936	 * @protected
 937	 */
 938	protected function barcode_c128($code, $type='') {
 939		$chr = array(
 940			'212222', /* 00 */
 941			'222122', /* 01 */
 942			'222221', /* 02 */
 943			'121223', /* 03 */
 944			'121322', /* 04 */
 945			'131222', /* 05 */
 946			'122213', /* 06 */
 947			'122312', /* 07 */
 948			'132212', /* 08 */
 949			'221213', /* 09 */
 950			'221312', /* 10 */
 951			'231212', /* 11 */
 952			'112232', /* 12 */
 953			'122132', /* 13 */
 954			'122231', /* 14 */
 955			'113222', /* 15 */
 956			'123122', /* 16 */
 957			'123221', /* 17 */
 958			'223211', /* 18 */
 959			'221132', /* 19 */
 960			'221231', /* 20 */
 961			'213212', /* 21 */
 962			'223112', /* 22 */
 963			'312131', /* 23 */
 964			'311222', /* 24 */
 965			'321122', /* 25 */
 966			'321221', /* 26 */
 967			'312212', /* 27 */
 968			'322112', /* 28 */
 969			'322211', /* 29 */
 970			'212123', /* 30 */
 971			'212321', /* 31 */
 972			'232121', /* 32 */
 973			'111323', /* 33 */
 974			'131123', /* 34 */
 975			'131321', /* 35 */
 976			'112313', /* 36 */
 977			'132113', /* 37 */
 978			'132311', /* 38 */
 979			'211313', /* 39 */
 980			'231113', /* 40 */
 981			'231311', /* 41 */
 982			'112133', /* 42 */
 983			'112331', /* 43 */
 984			'132131', /* 44 */
 985			'113123', /* 45 */
 986			'113321', /* 46 */
 987			'133121', /* 47 */
 988			'313121', /* 48 */
 989			'211331', /* 49 */
 990			'231131', /* 50 */
 991			'213113', /* 51 */
 992			'213311', /* 52 */
 993			'213131', /* 53 */
 994			'311123', /* 54 */
 995			'311321', /* 55 */
 996			'331121', /* 56 */
 997			'312113', /* 57 */
 998			'312311', /* 58 */
 999			'332111', /* 59 */
1000			'314111', /* 60 */
1001			'221411', /* 61 */
1002			'431111', /* 62 */
1003			'111224', /* 63 */
1004			'111422', /* 64 */
1005			'121124', /* 65 */
1006			'121421', /* 66 */
1007			'141122', /* 67 */
1008			'141221', /* 68 */
1009			'112214', /* 69 */
1010			'112412', /* 70 */
1011			'122114', /* 71 */
1012			'122411', /* 72 */
1013			'142112', /* 73 */
1014			'142211', /* 74 */
1015			'241211', /* 75 */
1016			'221114', /* 76 */
1017			'413111', /* 77 */
1018			'241112', /* 78 */
1019			'134111', /* 79 */
1020			'111242', /* 80 */
1021			'121142', /* 81 */
1022			'121241', /* 82 */
1023			'114212', /* 83 */
1024			'124112', /* 84 */
1025			'124211', /* 85 */
1026			'411212', /* 86 */
1027			'421112', /* 87 */
1028			'421211', /* 88 */
1029			'212141', /* 89 */
1030			'214121', /* 90 */
1031			'412121', /* 91 */
1032			'111143', /* 92 */
1033			'111341', /* 93 */
1034			'131141', /* 94 */
1035			'114113', /* 95 */
1036			'114311', /* 96 */
1037			'411113', /* 97 */
1038			'411311', /* 98 */
1039			'113141', /* 99 */
1040			'114131', /* 100 */
1041			'311141', /* 101 */
1042			'411131', /* 102 */
1043			'211412', /* 103 START A */
1044			'211214', /* 104 START B */
1045			'211232', /* 105 START C */
1046			'233111', /* STOP */
1047			'200000'  /* END */
1048		);
1049		// ASCII characters for code A (ASCII 00 - 95)
1050		$keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
1051		$keys_a .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9);
1052		$keys_a .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19);
1053		$keys_a .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29);
1054		$keys_a .= chr(30).chr(31);
1055		// ASCII characters for code B (ASCII 32 - 127)
1056		$keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
1057		// special codes
1058		$fnc_a = array(241 => 102, 242 => 97, 243 => 96, 244 => 101);
1059		$fnc_b = array(241 => 102, 242 => 97, 243 => 96, 244 => 100);
1060		// array of symbols
1061		$code_data = array();
1062		// lenght of the code
1063		$len = strlen($code);
1064		switch(strtoupper($type)) {
1065			case 'A': { // MODE A
1066				$startid = 103;
1067				for ($i = 0; $i < $len; ++$i) {
1068					$char = $code{$i};
1069					$char_id = ord($char);
1070					if (($char_id >= 241) AND ($char_id <= 244)) {
1071						$code_data[] = $fnc_a[$char_id];
1072					} elseif (($char_id >= 0) AND ($char_id <= 95)) {
1073						$code_data[] = strpos($keys_a, $char);
1074					} else {
1075						return false;
1076					}
1077				}
1078				break;
1079			}
1080			case 'B': { // MODE B
1081				$startid = 104;
1082				for ($i = 0; $i < $len; ++$i) {
1083					$char = $code{$i};
1084					$char_id = ord($char);
1085					if (($char_id >= 241) AND ($char_id <= 244)) {
1086						$code_data[] = $fnc_b[$char_id];
1087					} elseif (($char_id >= 32) AND ($char_id <= 127)) {
1088						$code_data[] = strpos($keys_b, $char);
1089					} else {
1090						return false;
1091					}
1092				}
1093				break;
1094			}
1095			case 'C': { // MODE C
1096				$startid = 105;
1097				if (ord($code{0}) == 241) {
1098					$code_data[] = 102;
1099					$code = substr($code, 1);
1100					--$len;
1101				}
1102				if (($len % 2) != 0) {
1103					// the length must be even
1104					return false;
1105				}
1106				for ($i = 0; $i < $len; $i+=2) {
1107					$chrnum = $code{$i}.$code{$i+1};
1108					if (preg_match('/([0-9]{2})/', $chrnum) > 0) {
1109						$code_data[] = intval($chrnum);
1110					} else {
1111						return false;
1112					}
1113				}
1114				break;
1115			}
1116			default: { // MODE AUTO
1117				// split code into sequences
1118				$sequence = array();
1119				// get numeric sequences (if any)
1120				$numseq = array();
1121				preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE);
1122				if (isset($numseq[1]) AND !empty($numseq[1])) {
1123					$end_offset = 0;
1124					foreach ($numseq[1] as $val) {
1125						$offset = $val[1];
1126						if ($offset > $end_offset) {
1127							// non numeric sequence
1128							$sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset))));
1129						}
1130						// numeric sequence
1131						$slen = strlen($val[0]);
1132						if (($slen % 2) != 0) {
1133							// the length must be even
1134							--$slen;
1135						}
1136						$sequence[] = array('C', substr($code, $offset, $slen), $slen);
1137						$end_offset = $offset + $slen;
1138					}
1139					if ($end_offset < $len) {
1140						$sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset)));
1141					}
1142				} else {
1143					// text code (non C mode)
1144					$sequence = array_merge($sequence, $this->get128ABsequence($code));
1145				}
1146				// process the sequence
1147				foreach ($sequence as $key => $seq) {
1148					switch($seq[0]) {
1149						case 'A': {
1150							if ($key == 0) {
1151								$startid = 103;
1152							} elseif ($sequence[($key - 1)][0] != 'A') {
1153								if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'B') AND (!isset($sequence[($key - 1)][3]))) {
1154									// single character shift
1155									$code_data[] = 98;
1156									// mark shift
1157									$sequence[$key][3] = true;
1158								} elseif (!isset($sequence[($key - 1)][3])) {
1159									$code_data[] = 101;
1160								}
1161							}
1162							for ($i = 0; $i < $seq[2]; ++$i) {
1163								$char = $seq[1]{$i};
1164								$char_id = ord($char);
1165								if (($char_id >= 241) AND ($char_id <= 244)) {
1166									$code_data[] = $fnc_a[$char_id];
1167								} else {
1168									$code_data[] = strpos($keys_a, $char);
1169								}
1170							}
1171							break;
1172						}
1173						case 'B': {
1174							if ($key == 0) {
1175								$tmpchr = ord($seq[1]{0});
1176								if (($seq[2] == 1) AND ($tmpchr >= 241) AND ($tmpchr <= 244) AND isset($sequence[($key + 1)]) AND ($sequence[($key + 1)][0] != 'B')) {
1177									switch ($sequence[($key + 1)][0]) {
1178										case 'A': {
1179											$startid = 103;
1180											$sequence[$key][0] = 'A';
1181											$code_data[] = $fnc_a[$tmpchr];
1182											break;
1183										}
1184										case 'C': {
1185											$startid = 105;
1186											$sequence[$key][0] = 'C';
1187											$code_data[] = $fnc_a[$tmpchr];
1188											break;
1189										}
1190									}
1191									break;
1192								} else {
1193									$startid = 104;
1194								}
1195							} elseif ($sequence[($key - 1)][0] != 'B') {
1196								if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'A') AND (!isset($sequence[($key - 1)][3]))) {
1197									// single character shift
1198									$code_data[] = 98;
1199									// mark shift
1200									$sequence[$key][3] = true;
1201								} elseif (!isset($sequence[($key - 1)][3])) {
1202									$code_data[] = 100;
1203								}
1204							}
1205							for ($i = 0; $i < $seq[2]; ++$i) {
1206								$char = $seq[1]{$i};
1207								$char_id = ord($char);
1208								if (($char_id >= 241) AND ($char_id <= 244)) {
1209									$code_data[] = $fnc_b[$char_id];
1210								} else {
1211									$code_data[] = strpos($keys_b, $char);
1212								}
1213							}
1214							break;
1215						}
1216						case 'C': {
1217							if ($key == 0) {
1218								$startid = 105;
1219							} elseif ($sequence[($key - 1)][0] != 'C') {
1220								$code_data[] = 99;
1221							}
1222							for ($i = 0; $i < $seq[2]; $i+=2) {
1223								$chrnum = $seq[1]{$i}.$seq[1]{$i+1};
1224								$code_data[] = intval($chrnum);
1225							}
1226							break;
1227						}
1228					}
1229				}
1230			}
1231		}
1232		// calculate check character
1233		$sum = $startid;
1234		foreach ($code_data as $key => $val) {
1235			$sum += ($val * ($key + 1));
1236		}
1237		// add check character
1238		$code_data[] = ($sum % 103);
1239		// add stop sequence
1240		$code_data[] = 106;
1241		$code_data[] = 107;
1242		// add start code at the beginning
1243		array_unshift($code_data, $startid);
1244		// build barcode array
1245		$bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1246		foreach ($code_data as $val) {
1247			$seq = $chr[$val];
1248			for ($j = 0; $j < 6; ++$j) {
1249				if (($j % 2) == 0) {
1250					$t = true; // bar
1251				} else {
1252					$t = false; // space
1253				}
1254				$w = $seq{$j};
1255				$bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1256				$bararray['maxw'] += $w;
1257			}
1258		}
1259		return $bararray;
1260	}
1261
1262	/**
1263	 * Split text code in A/B sequence for 128 code
1264	 * @param $code (string) code to split.
1265	 * @return array sequence
1266	 * @protected
1267	 */
1268	protected function get128ABsequence($code) {
1269		$len = strlen($code);
1270		$sequence = array();
1271		// get A sequences (if any)
1272		$numseq = array();
1273		preg_match_all('/([\0-\31])/', $code, $numseq, PREG_OFFSET_CAPTURE);
1274		if (isset($numseq[1]) AND !empty($numseq[1])) {
1275			$end_offset = 0;
1276			foreach ($numseq[1] as $val) {
1277				$offset = $val[1];
1278				if ($offset > $end_offset) {
1279					// B sequence
1280					$sequence[] = array('B', substr($code, $end_offset, ($offset - $end_offset)), ($offset - $end_offset));
1281				}
1282				// A sequence
1283				$slen = strlen($val[0]);
1284				$sequence[] = array('A', substr($code, $offset, $slen), $slen);
1285				$end_offset = $offset + $slen;
1286			}
1287			if ($end_offset < $len) {
1288				$sequence[] = array('B', substr($code, $end_offset), ($len - $end_offset));
1289			}
1290		} else {
1291			// only B sequence
1292			$sequence[] = array('B', $code, $len);
1293		}
1294		return $sequence;
1295	}
1296
1297	/**
1298	 * EAN13 and UPC-A barcodes.
1299	 * EAN13: European Article Numbering international retail product code
1300	 * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
1301	 * UPC-E: Short version of UPC symbol
1302	 * @param $code (string) code to represent.
1303	 * @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
1304	 * @return array barcode representation.
1305	 * @protected
1306	 */
1307	protected function barcode_eanupc($code, $len=13) {
1308		$upce = false;
1309		if ($len == 6) {
1310			$len = 12; // UPC-A
1311			$upce = true; // UPC-E mode
1312		}
1313		$data_len = $len - 1;
1314		//Padding
1315		$code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
1316		$code_len = strlen($code);
1317		// calculate check digit
1318		$sum_a = 0;
1319		for ($i = 1; $i < $data_len; $i+=2) {
1320			$sum_a += $code{$i};
1321		}
1322		if ($len > 12) {
1323			$sum_a *= 3;
1324		}
1325		$sum_b = 0;
1326		for ($i = 0; $i < $data_len; $i+=2) {
1327			$sum_b += ($code{$i});
1328		}
1329		if ($len < 13) {
1330			$sum_b *= 3;
1331		}
1332		$r = ($sum_a + $sum_b) % 10;
1333		if($r > 0) {
1334			$r = (10 - $r);
1335		}
1336		if ($code_len == $data_len) {
1337			// add check digit
1338			$code .= $r;
1339		} elseif ($r !== intval($code{$data_len})) {
1340			// wrong checkdigit
1341			return false;
1342		}
1343		if ($len == 12) {
1344			// UPC-A
1345			$code = '0'.$code;
1346			++$len;
1347		}
1348		if ($upce) {
1349			// convert UPC-A to UPC-E
1350			$tmp = substr($code, 4, 3);
1351			if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
1352				// manufacturer code ends in 000, 100, or 200
1353				$upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
1354			} else {
1355				$tmp = substr($code, 5, 2);
1356				if ($tmp == '00') {
1357					// manufacturer code ends in 00
1358					$upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
1359				} else {
1360					$tmp = substr($code, 6, 1);
1361					if ($tmp == '0') {
1362						// manufacturer code ends in 0
1363						$upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
1364					} else {
1365						// manufacturer code does not end in zero
1366						$upce_code = substr($code, 2, 5).substr($code, 11, 1);
1367					}
1368				}
1369			}
1370		}
1371		//Convert digits to bars
1372		$codes = array(
1373			'A'=>array( // left odd parity
1374				'0'=>'0001101',
1375				'1'=>'0011001',
1376				'2'=>'0010011',
1377				'3'=>'0111101',
1378				'4'=>'0100011',
1379				'5'=>'0110001',
1380				'6'=>'0101111',
1381				'7'=>'0111011',
1382				'8'=>'0110111',
1383				'9'=>'0001011'),
1384			'B'=>array( // left even parity
1385				'0'=>'0100111',
1386				'1'=>'0110011',
1387				'2'=>'0011011',
1388				'3'=>'0100001',
1389				'4'=>'0011101',
1390				'5'=>'0111001',
1391				'6'=>'0000101',
1392				'7'=>'0010001',
1393				'8'=>'0001001',
1394				'9'=>'0010111'),
1395			'C'=>array( // right
1396				'0'=>'1110010',
1397				'1'=>'1100110',
1398				'2'=>'1101100',
1399				'3'=>'1000010',
1400				'4'=>'1011100',
1401				'5'=>'1001110',
1402				'6'=>'1010000',
1403				'7'=>'1000100',
1404				'8'=>'1001000',
1405				'9'=>'1110100')
1406		);
1407		$parities = array(
1408			'0'=>array('A','A','A','A','A','A'),
1409			'1'=>array('A','A','B','A','B','B'),
1410			'2'=>array('A','A','B','B','A','B'),
1411			'3'=>array('A','A','B','B','B','A'),
1412			'4'=>array('A','B','A','A','B','B'),
1413			'5'=>array('A','B','B','A','A','B'),
1414			'6'=>array('A','B','B','B','A','A'),
1415			'7'=>array('A','B','A','B','A','B'),
1416			'8'=>array('A','B','A','B','B','A'),
1417			'9'=>array('A','B','B','A','B','A')
1418		);
1419		$upce_parities = array();
1420		$upce_parities[0] = array(
1421			'0'=>array('B','B','B','A','A','A'),
1422			'1'=>array('B','B','A','B','A','A'),
1423			'2'=>array('B','B','A','A','B','A'),
1424			'3'=>array('B','B','A','A','A','B'),
1425			'4'=>array('B','A','B','B','A','A'),
1426			'5'=>array('B','A','A','B','B','A'),
1427			'6'=>array('B','A','A','A','B','B'),
1428			'7'=>array('B','A','B','A','B','A'),
1429			'8'=>array('B','A','B','A','A','B'),
1430			'9'=>array('B','A','A','B','A','B')
1431		);
1432		$upce_parities[1] = array(
1433			'0'=>array('A','A','A','B','B','B'),
1434			'1'=>array('A','A','B','A','B','B'),
1435			'2'=>array('A','A','B','B','A','B'),
1436			'3'=>array('A','A','B','B','B','A'),
1437			'4'=>array('A','B','A','A','B','B'),
1438			'5'=>array('A','B','B','A','A','B'),
1439			'6'=>array('A','B','B','B','A','A'),
1440			'7'=>array('A','B','A','B','A','B'),
1441			'8'=>array('A','B','A','B','B','A'),
1442			'9'=>array('A','B','B','A','B','A')
1443		);
1444		$k = 0;
1445		$seq = '101'; // left guard bar
1446		if ($upce) {
1447			$bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1448			$p = $upce_parities[$code{1}][$r];
1449			for ($i = 0; $i < 6; ++$i) {
1450				$seq .= $codes[$p[$i]][$upce_code{$i}];
1451			}
1452			$seq .= '010101'; // right guard bar
1453		} else {
1454			$bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1455			$half_len = intval(ceil($len / 2));
1456			if ($len == 8) {
1457				for ($i = 0; $i < $half_len; ++$i) {
1458					$seq .= $codes['A'][$code{$i}];
1459				}
1460			} else {
1461				$p = $parities[$code{0}];
1462				for ($i = 1; $i < $half_len; ++$i) {
1463					$seq .= $codes[$p[$i-1]][$code{$i}];
1464				}
1465			}
1466			$seq .= '01010'; // center guard bar
1467			for ($i = $half_len; $i < $len; ++$i) {
1468				$seq .= $codes['C'][$code{$i}];
1469			}
1470			$seq .= '101'; // right guard bar
1471		}
1472		$clen = strlen($seq);
1473		$w = 0;
1474		for ($i = 0; $i < $clen; ++$i) {
1475			$w += 1;
1476			if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
1477				if ($seq{$i} == '1') {
1478					$t = true; // bar
1479				} else {
1480					$t = false; // space
1481				}
1482				$bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1483				$bararray['maxw'] += $w;
1484				++$k;
1485				$w = 0;
1486			}
1487		}
1488		return $bararray;
1489	}
1490
1491	/**
1492	 * UPC-Based Extentions
1493	 * 2-Di…

Large files files are truncated, but you can click here to view the full file