source: trunk/client/inc/hpdf403/_tcpdf_5.0.002/barcodes.php@ 398

Last change on this file since 398 was 349, checked in by roby, 3 years ago
File size: 59.1 KB
Line 
1<?php
2//============================================================+
3// File name : barcodes.php
4// Begin : 2008-06-09
5// Last Update : 2009-08-26
6// Version : 1.0.009
7// License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html)
8// ----------------------------------------------------------------------------
9// Copyright (C) 2008-2009 Nicola Asuni - Tecnick.com S.r.l.
10//
11// This program is free software: you can redistribute it and/or modify
12// it under the terms of the GNU Lesser General Public License as published by
13// the Free Software Foundation, either version 2.1 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public License
22// along with this program. If not, see <http://www.gnu.org/licenses/>.
23//
24// See LICENSE.TXT file for more information.
25// ----------------------------------------------------------------------------
26//
27// Description : PHP class to creates array representations for
28// common 1D barcodes to be used with TCPDF.
29//
30// Author: Nicola Asuni
31//
32// (c) Copyright:
33// Nicola Asuni
34// Tecnick.com S.r.l.
35// Via della Pace, 11
36// 09044 Quartucciu (CA)
37// ITALY
38// www.tecnick.com
39// info@tecnick.com
40//============================================================+
41
42/**
43 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF.
44 * @package com.tecnick.tcpdf
45 * @abstract Functions for generating string representation of common 1D barcodes.
46 * @author Nicola Asuni
47 * @copyright 2008-2009 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com
48 * @link http://www.tcpdf.org
49 * @license http://www.gnu.org/copyleft/lesser.html LGPL
50 * @version 1.0.008
51 */
52
53 /**
54 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF (http://www.tcpdf.org).<br>
55 * @name TCPDFBarcode
56 * @package com.tecnick.tcpdf
57 * @version 1.0.008
58 * @author Nicola Asuni
59 * @link http://www.tcpdf.org
60 * @license http://www.gnu.org/copyleft/lesser.html LGPL
61 */
62class TCPDFBarcode {
63
64 /**
65 * @var array representation of barcode.
66 * @access protected
67 */
68 protected $barcode_array;
69
70 /**
71 * This is the class constructor.
72 * Return an array representations for common 1D barcodes:<ul>
73 * <li>$arrcode['code'] code to be printed on text label</li>
74 * <li>$arrcode['maxh'] max bar height</li>
75 * <li>$arrcode['maxw'] max bar width</li>
76 * <li>$arrcode['bcode'][$k] single bar or space in $k position</li>
77 * <li>$arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.</li>
78 * <li>$arrcode['bcode'][$k]['w'] bar width in units.</li>
79 * <li>$arrcode['bcode'][$k]['h'] bar height in units.</li>
80 * <li>$arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)</li></ul>
81 * @param string $code code to print
82 * @param string $type type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>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>
83 */
84 public function __construct($code, $type) {
85 $this->setBarcode($code, $type);
86 }
87
88 /**
89 * Return an array representations of barcode.
90 * @return array
91 */
92 public function getBarcodeArray() {
93 return $this->barcode_array;
94 }
95
96 /**
97 * Set the barcode.
98 * @param string $code code to print
99 * @param string $type type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>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>
100 * @return array
101 */
102 public function setBarcode($code, $type) {
103 switch (strtoupper($type)) {
104 case 'C39': { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
105 $arrcode = $this->barcode_code39($code, false, false);
106 break;
107 }
108 case 'C39+': { // CODE 39 with checksum
109 $arrcode = $this->barcode_code39($code, false, true);
110 break;
111 }
112 case 'C39E': { // CODE 39 EXTENDED
113 $arrcode = $this->barcode_code39($code, true, false);
114 break;
115 }
116 case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM
117 $arrcode = $this->barcode_code39($code, true, true);
118 break;
119 }
120 case 'C93': { // CODE 93 - USS-93
121 $arrcode = $this->barcode_code93($code);
122 break;
123 }
124 case 'S25': { // Standard 2 of 5
125 $arrcode = $this->barcode_s25($code, false);
126 break;
127 }
128 case 'S25+': { // Standard 2 of 5 + CHECKSUM
129 $arrcode = $this->barcode_s25($code, true);
130 break;
131 }
132 case 'I25': { // Interleaved 2 of 5
133 $arrcode = $this->barcode_i25($code, false);
134 break;
135 }
136 case 'I25+': { // Interleaved 2 of 5 + CHECKSUM
137 $arrcode = $this->barcode_i25($code, true);
138 break;
139 }
140 case 'C128A': { // CODE 128 A
141 $arrcode = $this->barcode_c128($code, 'A');
142 break;
143 }
144 case 'C128B': { // CODE 128 B
145 $arrcode = $this->barcode_c128($code, 'B');
146 break;
147 }
148 case 'C128C': { // CODE 128 C
149 $arrcode = $this->barcode_c128($code, 'C');
150 break;
151 }
152 case 'EAN2': { // 2-Digits UPC-Based Extention
153 $arrcode = $this->barcode_eanext($code, 2);
154 break;
155 }
156 case 'EAN5': { // 5-Digits UPC-Based Extention
157 $arrcode = $this->barcode_eanext($code, 5);
158 break;
159 }
160 case 'EAN8': { // EAN 8
161 $arrcode = $this->barcode_eanupc($code, 8);
162 break;
163 }
164 case 'EAN13': { // EAN 13
165 $arrcode = $this->barcode_eanupc($code, 13);
166 break;
167 }
168 case 'UPCA': { // UPC-A
169 $arrcode = $this->barcode_eanupc($code, 12);
170 break;
171 }
172 case 'UPCE': { // UPC-E
173 $arrcode = $this->barcode_eanupc($code, 6);
174 break;
175 }
176 case 'MSI': { // MSI (Variation of Plessey code)
177 $arrcode = $this->barcode_msi($code, false);
178 break;
179 }
180 case 'MSI+': { // MSI + CHECKSUM (modulo 11)
181 $arrcode = $this->barcode_msi($code, true);
182 break;
183 }
184 case 'POSTNET': { // POSTNET
185 $arrcode = $this->barcode_postnet($code, false);
186 break;
187 }
188 case 'PLANET': { // PLANET
189 $arrcode = $this->barcode_postnet($code, true);
190 break;
191 }
192 case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
193 $arrcode = $this->barcode_rms4cc($code, false);
194 break;
195 }
196 case 'KIX': { // KIX (Klant index - Customer index)
197 $arrcode = $this->barcode_rms4cc($code, true);
198 break;
199 }
200 case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
201 $arrcode = $this->barcode_imb($code);
202 break;
203 }
204 case 'CODABAR': { // CODABAR
205 $arrcode = $this->barcode_codabar($code);
206 break;
207 }
208 case 'CODE11': { // CODE 11
209 $arrcode = $this->barcode_code11($code);
210 break;
211 }
212 case 'PHARMA': { // PHARMACODE
213 $arrcode = $this->barcode_pharmacode($code);
214 break;
215 }
216 case 'PHARMA2T': { // PHARMACODE TWO-TRACKS
217 $arrcode = $this->barcode_pharmacode2t($code);
218 break;
219 }
220 default: {
221 $this->barcode_array = false;
222 $arrcode = false;
223 break;
224 }
225 }
226 $this->barcode_array = $arrcode;
227 }
228
229 /**
230 * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
231 * General-purpose code in very wide use world-wide
232 * @param string $code code to represent.
233 * @param boolean $checksum if true add a checksum to the code
234 * @return array barcode representation.
235 * @access protected
236 */
237 protected function barcode_code39($code, $extended=false, $checksum=false) {
238 $chr['0'] = '111221211';
239 $chr['1'] = '211211112';
240 $chr['2'] = '112211112';
241 $chr['3'] = '212211111';
242 $chr['4'] = '111221112';
243 $chr['5'] = '211221111';
244 $chr['6'] = '112221111';
245 $chr['7'] = '111211212';
246 $chr['8'] = '211211211';
247 $chr['9'] = '112211211';
248 $chr['A'] = '211112112';
249 $chr['B'] = '112112112';
250 $chr['C'] = '212112111';
251 $chr['D'] = '111122112';
252 $chr['E'] = '211122111';
253 $chr['F'] = '112122111';
254 $chr['G'] = '111112212';
255 $chr['H'] = '211112211';
256 $chr['I'] = '112112211';
257 $chr['J'] = '111122211';
258 $chr['K'] = '211111122';
259 $chr['L'] = '112111122';
260 $chr['M'] = '212111121';
261 $chr['N'] = '111121122';
262 $chr['O'] = '211121121';
263 $chr['P'] = '112121121';
264 $chr['Q'] = '111111222';
265 $chr['R'] = '211111221';
266 $chr['S'] = '112111221';
267 $chr['T'] = '111121221';
268 $chr['U'] = '221111112';
269 $chr['V'] = '122111112';
270 $chr['W'] = '222111111';
271 $chr['X'] = '121121112';
272 $chr['Y'] = '221121111';
273 $chr['Z'] = '122121111';
274 $chr['-'] = '121111212';
275 $chr['.'] = '221111211';
276 $chr[' '] = '122111211';
277 $chr['$'] = '121212111';
278 $chr['/'] = '121211121';
279 $chr['+'] = '121112121';
280 $chr['%'] = '111212121';
281 $chr['*'] = '121121211';
282
283 $code = strtoupper($code);
284 if ($extended) {
285 // extended mode
286 $code = $this->encode_code39_ext($code);
287 }
288 if ($code === false) {
289 return false;
290 }
291 if ($checksum) {
292 // checksum
293 $code .= $this->checksum_code39($code);
294 }
295 // add start and stop codes
296 $code = '*'.$code.'*';
297
298 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
299 $k = 0;
300 $clen = strlen($code);
301 for ($i = 0; $i < $clen; ++$i) {
302 $char = $code{$i};
303 if(!isset($chr[$char])) {
304 // invalid character
305 return false;
306 }
307 for ($j = 0; $j < 9; ++$j) {
308 if (($j % 2) == 0) {
309 $t = true; // bar
310 } else {
311 $t = false; // space
312 }
313 $w = $chr[$char]{$j};
314 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
315 $bararray['maxw'] += $w;
316 ++$k;
317 }
318 $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0);
319 $bararray['maxw'] += 1;
320 ++$k;
321 }
322 return $bararray;
323 }
324
325 /**
326 * Encode a string to be used for CODE 39 Extended mode.
327 * @param string $code code to represent.
328 * @return encoded string.
329 * @access protected
330 */
331 protected function encode_code39_ext($code) {
332 $encode = array(
333 chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
334 chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
335 chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
336 chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
337 chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
338 chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
339 chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
340 chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
341 chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
342 chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
343 chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
344 chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
345 chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
346 chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
347 chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
348 chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
349 chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
350 chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
351 chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
352 chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
353 chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
354 chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
355 chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
356 chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
357 chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
358 chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
359 chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
360 chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
361 chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
362 chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
363 chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
364 chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
365 $code_ext = '';
366 $clen = strlen($code);
367 for ($i = 0 ; $i < $clen; ++$i) {
368 if (ord($code{$i}) > 127) {
369 return false;
370 }
371 $code_ext .= $encode[$code{$i}];
372 }
373 return $code_ext;
374 }
375
376 /**
377 * Calculate CODE 39 checksum (modulo 43).
378 * @param string $code code to represent.
379 * @return char checksum.
380 * @access protected
381 */
382 protected function checksum_code39($code) {
383 $chars = array(
384 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
385 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
386 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
387 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
388 $sum = 0;
389 $clen = strlen($code);
390 for ($i = 0 ; $i < $clen; ++$i) {
391 $k = array_keys($chars, $code{$i});
392 $sum += $k[0];
393 }
394 $j = ($sum % 43);
395 return $chars[$j];
396 }
397
398 /**
399 * CODE 93 - USS-93
400 * Compact code similar to Code 39
401 * @param string $code code to represent.
402 * @param boolean $checksum if true add a checksum to the code
403 * @return array barcode representation.
404 * @access protected
405 */
406 protected function barcode_code93($code) {
407 $chr['0'] = '131112';
408 $chr['1'] = '111213';
409 $chr['2'] = '111312';
410 $chr['3'] = '111411';
411 $chr['4'] = '121113';
412 $chr['5'] = '121212';
413 $chr['6'] = '121311';
414 $chr['7'] = '111114';
415 $chr['8'] = '131211';
416 $chr['9'] = '141111';
417 $chr['A'] = '211113';
418 $chr['B'] = '211212';
419 $chr['C'] = '211311';
420 $chr['D'] = '221112';
421 $chr['E'] = '221211';
422 $chr['F'] = '231111';
423 $chr['G'] = '112113';
424 $chr['H'] = '112212';
425 $chr['I'] = '112311';
426 $chr['J'] = '122112';
427 $chr['K'] = '132111';
428 $chr['L'] = '111123';
429 $chr['M'] = '111222';
430 $chr['N'] = '111321';
431 $chr['O'] = '121122';
432 $chr['P'] = '131121';
433 $chr['Q'] = '212112';
434 $chr['R'] = '212211';
435 $chr['S'] = '211122';
436 $chr['T'] = '211221';
437 $chr['U'] = '221121';
438 $chr['V'] = '222111';
439 $chr['W'] = '112122';
440 $chr['X'] = '112221';
441 $chr['Y'] = '122121';
442 $chr['Z'] = '123111';
443 $chr['-'] = '121131';
444 $chr['.'] = '311112';
445 $chr[' '] = '311211';
446 $chr['$'] = '321111';
447 $chr['/'] = '112131';
448 $chr['+'] = '113121';
449 $chr['%'] = '211131';
450 $chr[128] = '121221'; // ($)
451 $chr[129] = '311121'; // (/)
452 $chr[130] = '122211'; // (+)
453 $chr[131] = '312111'; // (%)
454 $chr['*'] = '111141';
455 $code = strtoupper($code);
456 $encode = array(
457 chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C',
458 chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G',
459 chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K',
460 chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O',
461 chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S',
462 chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W',
463 chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A',
464 chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E',
465 chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C',
466 chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G',
467 chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K',
468 chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O',
469 chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
470 chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
471 chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F',
472 chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J',
473 chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
474 chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
475 chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
476 chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
477 chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
478 chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
479 chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K',
480 chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O',
481 chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C',
482 chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G',
483 chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K',
484 chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O',
485 chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S',
486 chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W',
487 chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P',
488 chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T');
489 $code_ext = '';
490 $clen = strlen($code);
491 for ($i = 0 ; $i < $clen; ++$i) {
492 if (ord($code{$i}) > 127) {
493 return false;
494 }
495 $code_ext .= $encode[$code{$i}];
496 }
497 // checksum
498 $code .= $this->checksum_code93($code);
499 // add start and stop codes
500 $code = '*'.$code.'*';
501 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
502 $k = 0;
503 $clen = strlen($code);
504 for ($i = 0; $i < $clen; ++$i) {
505 $char = $code{$i};
506 if(!isset($chr[$char])) {
507 // invalid character
508 return false;
509 }
510 for ($j = 0; $j < 6; ++$j) {
511 if (($j % 2) == 0) {
512 $t = true; // bar
513 } else {
514 $t = false; // space
515 }
516 $w = $chr[$char]{$j};
517 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
518 $bararray['maxw'] += $w;
519 ++$k;
520 }
521 }
522 $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0);
523 $bararray['maxw'] += 1;
524 ++$k;
525 return $bararray;
526 }
527
528 /**
529 * Calculate CODE 93 checksum (modulo 47).
530 * @param string $code code to represent.
531 * @return string checksum code.
532 * @access protected
533 */
534 protected function checksum_code93($code) {
535 $chars = array(
536 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
537 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
538 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
539 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
540 // translate special characters
541 $code = strtr($code, chr(128).chr(129).chr(130).chr(131), '$/+%');
542 $len = strlen($code);
543 // calculate check digit C
544 $p = 1;
545 $check = 0;
546 for ($i = ($len - 1); $i >= 0; --$i) {
547 $k = array_keys($chars, $code{$i});
548 $check += ($k[0] * $p);
549 ++$p;
550 if ($p > 20) {
551 $p = 1;
552 }
553 }
554 $check %= 47;
555 $c = $chars[$check];
556 $code .= $c;
557 // calculate check digit K
558 $p = 1;
559 $check = 0;
560 for ($i = $len; $i >= 0; --$i) {
561 $k = array_keys($chars, $code{$i});
562 $check += ($k[0] * $p);
563 ++$p;
564 if ($p > 15) {
565 $p = 1;
566 }
567 }
568 $check %= 47;
569 $k = $chars[$check];
570 return $c.$k;
571 }
572
573 /**
574 * Checksum for standard 2 of 5 barcodes.
575 * @param string $code code to process.
576 * @return int checksum.
577 * @access protected
578 */
579 protected function checksum_s25($code) {
580 $len = strlen($code);
581 $sum = 0;
582 for ($i = 0; $i < $len; $i+=2) {
583 $sum += $code{$i};
584 }
585 $sum *= 3;
586 for ($i = 1; $i < $len; $i+=2) {
587 $sum += ($code{$i});
588 }
589 $r = $sum % 10;
590 if($r > 0) {
591 $r = (10 - $r);
592 }
593 return $r;
594 }
595
596 /**
597 * MSI.
598 * Variation of Plessey code, with similar applications
599 * Contains digits (0 to 9) and encodes the data only in the width of bars.
600 * @param string $code code to represent.
601 * @param boolean $checksum if true add a checksum to the code (modulo 11)
602 * @return array barcode representation.
603 * @access protected
604 */
605 protected function barcode_msi($code, $checksum=false) {
606 $chr['0'] = '100100100100';
607 $chr['1'] = '100100100110';
608 $chr['2'] = '100100110100';
609 $chr['3'] = '100100110110';
610 $chr['4'] = '100110100100';
611 $chr['5'] = '100110100110';
612 $chr['6'] = '100110110100';
613 $chr['7'] = '100110110110';
614 $chr['8'] = '110100100100';
615 $chr['9'] = '110100100110';
616 $chr['A'] = '110100110100';
617 $chr['B'] = '110100110110';
618 $chr['C'] = '110110100100';
619 $chr['D'] = '110110100110';
620 $chr['E'] = '110110110100';
621 $chr['F'] = '110110110110';
622 if ($checksum) {
623 // add checksum
624 $clen = strlen($code);
625 $p = 2;
626 $check = 0;
627 for ($i = ($clen - 1); $i >= 0; --$i) {
628 $check += (hexdec($code{$i}) * $p);
629 ++$p;
630 if ($p > 7) {
631 $p = 2;
632 }
633 }
634 $check %= 11;
635 if ($check > 0) {
636 $check = 11 - $check;
637 }
638 $code .= $check;
639 }
640 $seq = '110'; // left guard
641 $clen = strlen($code);
642 for ($i = 0; $i < $clen; ++$i) {
643 $digit = $code{$i};
644 if (!isset($chr[$digit])) {
645 // invalid character
646 return false;
647 }
648 $seq .= $chr[$digit];
649 }
650 $seq .= '1001'; // right guard
651 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
652 return $this->binseq_to_array($seq, $bararray);
653 }
654
655 /**
656 * Standard 2 of 5 barcodes.
657 * Used in airline ticket marking, photofinishing
658 * Contains digits (0 to 9) and encodes the data only in the width of bars.
659 * @param string $code code to represent.
660 * @param boolean $checksum if true add a checksum to the code
661 * @return array barcode representation.
662 * @access protected
663 */
664 protected function barcode_s25($code, $checksum=false) {
665 $chr['0'] = '10101110111010';
666 $chr['1'] = '11101010101110';
667 $chr['2'] = '10111010101110';
668 $chr['3'] = '11101110101010';
669 $chr['4'] = '10101110101110';
670 $chr['5'] = '11101011101010';
671 $chr['6'] = '10111011101010';
672 $chr['7'] = '10101011101110';
673 $chr['8'] = '10101110111010';
674 $chr['9'] = '10111010111010';
675 if ($checksum) {
676 // add checksum
677 $code .= $this->checksum_s25($code);
678 }
679 if((strlen($code) % 2) != 0) {
680 // add leading zero if code-length is odd
681 $code = '0'.$code;
682 }
683 $seq = '11011010';
684 $clen = strlen($code);
685 for ($i = 0; $i < $clen; ++$i) {
686 $digit = $code{$i};
687 if (!isset($chr[$digit])) {
688 // invalid character
689 return false;
690 }
691 $seq .= $chr[$digit];
692 }
693 $seq .= '1101011';
694 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
695 return $this->binseq_to_array($seq, $bararray);
696 }
697
698 /**
699 * Convert binary barcode sequence to TCPDF barcode array
700 * @param string $seq barcode as binary sequence
701 * òparam array $bararray TCPDF barcode array to fill up
702 * @return array barcode representation.
703 * @access protected
704 */
705 protected function binseq_to_array($seq, $bararray) {
706 $len = strlen($seq);
707 $w = 0;
708 $k = 0;
709 for ($i = 0; $i < $len; ++$i) {
710 $w += 1;
711 if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
712 if ($seq{$i} == '1') {
713 $t = true; // bar
714 } else {
715 $t = false; // space
716 }
717 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
718 $bararray['maxw'] += $w;
719 ++$k;
720 $w = 0;
721 }
722 }
723 return $bararray;
724 }
725
726 /**
727 * Interleaved 2 of 5 barcodes.
728 * Compact numeric code, widely used in industry, air cargo
729 * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
730 * @param string $code code to represent.
731 * @param boolean $checksum if true add a checksum to the code
732 * @return array barcode representation.
733 * @access protected
734 */
735 protected function barcode_i25($code, $checksum=false) {
736 $chr['0'] = '11221';
737 $chr['1'] = '21112';
738 $chr['2'] = '12112';
739 $chr['3'] = '22111';
740 $chr['4'] = '11212';
741 $chr['5'] = '21211';
742 $chr['6'] = '12211';
743 $chr['7'] = '11122';
744 $chr['8'] = '21121';
745 $chr['9'] = '12121';
746 $chr['A'] = '11';
747 $chr['Z'] = '21';
748 if ($checksum) {
749 // add checksum
750 $code .= $this->checksum_s25($code);
751 }
752 if((strlen($code) % 2) != 0) {
753 // add leading zero if code-length is odd
754 $code = '0'.$code;
755 }
756 // add start and stop codes
757 $code = 'AA'.strtolower($code).'ZA';
758
759 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
760 $k = 0;
761 $clen = strlen($code);
762 for ($i = 0; $i < $clen; $i = ($i + 2)) {
763 $char_bar = $code{$i};
764 $char_space = $code{$i+1};
765 if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
766 // invalid character
767 return false;
768 }
769 // create a bar-space sequence
770 $seq = '';
771 $chrlen = strlen($chr[$char_bar]);
772 for ($s = 0; $s < $chrlen; $s++){
773 $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
774 }
775 $seqlen = strlen($seq);
776 for ($j = 0; $j < $seqlen; ++$j) {
777 if (($j % 2) == 0) {
778 $t = true; // bar
779 } else {
780 $t = false; // space
781 }
782 $w = $seq{$j};
783 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
784 $bararray['maxw'] += $w;
785 ++$k;
786 }
787 }
788 return $bararray;
789 }
790
791 /**
792 * C128 barcodes.
793 * Very capable code, excellent density, high reliability; in very wide use world-wide
794 * @param string $code code to represent.
795 * @param string $type barcode type: A, B or C
796 * @return array barcode representation.
797 * @access protected
798 */
799 protected function barcode_c128($code, $type='B') {
800 $chr = array(
801 '212222', /* 00 */
802 '222122', /* 01 */
803 '222221', /* 02 */
804 '121223', /* 03 */
805 '121322', /* 04 */
806 '131222', /* 05 */
807 '122213', /* 06 */
808 '122312', /* 07 */
809 '132212', /* 08 */
810 '221213', /* 09 */
811 '221312', /* 10 */
812 '231212', /* 11 */
813 '112232', /* 12 */
814 '122132', /* 13 */
815 '122231', /* 14 */
816 '113222', /* 15 */
817 '123122', /* 16 */
818 '123221', /* 17 */
819 '223211', /* 18 */
820 '221132', /* 19 */
821 '221231', /* 20 */
822 '213212', /* 21 */
823 '223112', /* 22 */
824 '312131', /* 23 */
825 '311222', /* 24 */
826 '321122', /* 25 */
827 '321221', /* 26 */
828 '312212', /* 27 */
829 '322112', /* 28 */
830 '322211', /* 29 */
831 '212123', /* 30 */
832 '212321', /* 31 */
833 '232121', /* 32 */
834 '111323', /* 33 */
835 '131123', /* 34 */
836 '131321', /* 35 */
837 '112313', /* 36 */
838 '132113', /* 37 */
839 '132311', /* 38 */
840 '211313', /* 39 */
841 '231113', /* 40 */
842 '231311', /* 41 */
843 '112133', /* 42 */
844 '112331', /* 43 */
845 '132131', /* 44 */
846 '113123', /* 45 */
847 '113321', /* 46 */
848 '133121', /* 47 */
849 '313121', /* 48 */
850 '211331', /* 49 */
851 '231131', /* 50 */
852 '213113', /* 51 */
853 '213311', /* 52 */
854 '213131', /* 53 */
855 '311123', /* 54 */
856 '311321', /* 55 */
857 '331121', /* 56 */
858 '312113', /* 57 */
859 '312311', /* 58 */
860 '332111', /* 59 */
861 '314111', /* 60 */
862 '221411', /* 61 */
863 '431111', /* 62 */
864 '111224', /* 63 */
865 '111422', /* 64 */
866 '121124', /* 65 */
867 '121421', /* 66 */
868 '141122', /* 67 */
869 '141221', /* 68 */
870 '112214', /* 69 */
871 '112412', /* 70 */
872 '122114', /* 71 */
873 '122411', /* 72 */
874 '142112', /* 73 */
875 '142211', /* 74 */
876 '241211', /* 75 */
877 '221114', /* 76 */
878 '413111', /* 77 */
879 '241112', /* 78 */
880 '134111', /* 79 */
881 '111242', /* 80 */
882 '121142', /* 81 */
883 '121241', /* 82 */
884 '114212', /* 83 */
885 '124112', /* 84 */
886 '124211', /* 85 */
887 '411212', /* 86 */
888 '421112', /* 87 */
889 '421211', /* 88 */
890 '212141', /* 89 */
891 '214121', /* 90 */
892 '412121', /* 91 */
893 '111143', /* 92 */
894 '111341', /* 93 */
895 '131141', /* 94 */
896 '114113', /* 95 */
897 '114311', /* 96 */
898 '411113', /* 97 */
899 '411311', /* 98 */
900 '113141', /* 99 */
901 '114131', /* 100 */
902 '311141', /* 101 */
903 '411131', /* 102 */
904 '211412', /* 103 START A */
905 '211214', /* 104 START B */
906 '211232', /* 105 START C */
907 '233111', /* STOP */
908 '200000' /* END */
909 );
910 $keys = '';
911 switch(strtoupper($type)) {
912 case 'A': {
913 $startid = 103;
914 $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
915 for ($i = 0; $i < 32; ++$i) {
916 $keys .= chr($i);
917 }
918 break;
919 }
920 case 'B': {
921 $startid = 104;
922 $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
923 break;
924 }
925 case 'C': {
926 $startid = 105;
927 $keys = '';
928 if ((strlen($code) % 2) != 0) {
929 // The length of barcode value must be even ($code). You must pad the number with zeros
930 return false;
931 }
932 for ($i = 0; $i <= 99; ++$i) {
933 $keys .= chr($i);
934 }
935 $new_code = '';
936 $hclen = (strlen($code) / 2);
937 for ($i = 0; $i < $hclen; ++$i) {
938 $new_code .= chr(intval($code{(2 * $i)}.$code{(2 * $i + 1)}));
939 }
940 $code = $new_code;
941 break;
942 }
943 default: {
944 return false;
945 }
946 }
947 // calculate check character
948 $sum = $startid;
949 $clen = strlen($code);
950 for ($i = 0; $i < $clen; ++$i) {
951 $sum += (strpos($keys, $code{$i}) * ($i+1));
952 }
953 $check = ($sum % 103);
954 // add start, check and stop codes
955 $code = chr($startid).$code.chr($check).chr(106).chr(107);
956 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
957 $k = 0;
958 $len = strlen($code);
959 for ($i = 0; $i < $len; ++$i) {
960 $ck = strpos($keys, $code{$i});
961 if (($i == 0) OR ($i > ($len-4))) {
962 $char_num = ord($code{$i});
963 $seq = $chr[$char_num];
964 } elseif(($ck >= 0) AND isset($chr[$ck])) {
965 $seq = $chr[$ck];
966 } else {
967 // invalid character
968 return false;
969 }
970 for ($j = 0; $j < 6; ++$j) {
971 if (($j % 2) == 0) {
972 $t = true; // bar
973 } else {
974 $t = false; // space
975 }
976 $w = $seq{$j};
977 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
978 $bararray['maxw'] += $w;
979 ++$k;
980 }
981 }
982 return $bararray;
983 }
984
985 /**
986 * EAN13 and UPC-A barcodes.
987 * EAN13: European Article Numbering international retail product code
988 * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
989 * UPC-E: Short version of UPC symbol
990 * @param string $code code to represent.
991 * @param string $len barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
992 * @return array barcode representation.
993 * @access protected
994 */
995 protected function barcode_eanupc($code, $len=13) {
996 $upce = false;
997 if ($len == 6) {
998 $len = 12; // UPC-A
999 $upce = true; // UPC-E mode
1000 }
1001 $data_len = $len - 1;
1002 //Padding
1003 $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
1004 $code_len = strlen($code);
1005 // calculate check digit
1006 $sum_a = 0;
1007 for ($i = 1; $i < $data_len; $i+=2) {
1008 $sum_a += $code{$i};
1009 }
1010 if ($len > 12) {
1011 $sum_a *= 3;
1012 }
1013 $sum_b = 0;
1014 for ($i = 0; $i < $data_len; $i+=2) {
1015 $sum_b += ($code{$i});
1016 }
1017 if ($len < 13) {
1018 $sum_b *= 3;
1019 }
1020 $r = ($sum_a + $sum_b) % 10;
1021 if($r > 0) {
1022 $r = (10 - $r);
1023 }
1024 if ($code_len == $data_len) {
1025 // add check digit
1026 $code .= $r;
1027 } elseif ($r !== intval($code{$data_len})) {
1028 // wrong checkdigit
1029 return false;
1030 }
1031 if ($len == 12) {
1032 // UPC-A
1033 $code = '0'.$code;
1034 ++$len;
1035 }
1036 if ($upce) {
1037 // convert UPC-A to UPC-E
1038 $tmp = substr($code, 4, 3);
1039 if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
1040 // manufacturer code ends in 000, 100, or 200
1041 $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
1042 } else {
1043 $tmp = substr($code, 5, 2);
1044 if ($tmp == '00') {
1045 // manufacturer code ends in 00
1046 $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
1047 } else {
1048 $tmp = substr($code, 6, 1);
1049 if ($tmp == '0') {
1050 // manufacturer code ends in 0
1051 $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
1052 } else {
1053 // manufacturer code does not end in zero
1054 $upce_code = substr($code, 2, 5).substr($code, 11, 1);
1055 }
1056 }
1057 }
1058 }
1059 //Convert digits to bars
1060 $codes = array(
1061 'A'=>array( // left odd parity
1062 '0'=>'0001101',
1063 '1'=>'0011001',
1064 '2'=>'0010011',
1065 '3'=>'0111101',
1066 '4'=>'0100011',
1067 '5'=>'0110001',
1068 '6'=>'0101111',
1069 '7'=>'0111011',
1070 '8'=>'0110111',
1071 '9'=>'0001011'),
1072 'B'=>array( // left even parity
1073 '0'=>'0100111',
1074 '1'=>'0110011',
1075 '2'=>'0011011',
1076 '3'=>'0100001',
1077 '4'=>'0011101',
1078 '5'=>'0111001',
1079 '6'=>'0000101',
1080 '7'=>'0010001',
1081 '8'=>'0001001',
1082 '9'=>'0010111'),
1083 'C'=>array( // right
1084 '0'=>'1110010',
1085 '1'=>'1100110',
1086 '2'=>'1101100',
1087 '3'=>'1000010',
1088 '4'=>'1011100',
1089 '5'=>'1001110',
1090 '6'=>'1010000',
1091 '7'=>'1000100',
1092 '8'=>'1001000',
1093 '9'=>'1110100')
1094 );
1095 $parities = array(
1096 '0'=>array('A','A','A','A','A','A'),
1097 '1'=>array('A','A','B','A','B','B'),
1098 '2'=>array('A','A','B','B','A','B'),
1099 '3'=>array('A','A','B','B','B','A'),
1100 '4'=>array('A','B','A','A','B','B'),
1101 '5'=>array('A','B','B','A','A','B'),
1102 '6'=>array('A','B','B','B','A','A'),
1103 '7'=>array('A','B','A','B','A','B'),
1104 '8'=>array('A','B','A','B','B','A'),
1105 '9'=>array('A','B','B','A','B','A')
1106 );
1107 $upce_parities = array();
1108 $upce_parities[0] = array(
1109 '0'=>array('B','B','B','A','A','A'),
1110 '1'=>array('B','B','A','B','A','A'),
1111 '2'=>array('B','B','A','A','B','A'),
1112 '3'=>array('B','B','A','A','A','B'),
1113 '4'=>array('B','A','B','B','A','A'),
1114 '5'=>array('B','A','A','B','B','A'),
1115 '6'=>array('B','A','A','A','B','B'),
1116 '7'=>array('B','A','B','A','B','A'),
1117 '8'=>array('B','A','B','A','A','B'),
1118 '9'=>array('B','A','A','B','A','B')
1119 );
1120 $upce_parities[1] = array(
1121 '0'=>array('A','A','A','B','B','B'),
1122 '1'=>array('A','A','B','A','B','B'),
1123 '2'=>array('A','A','B','B','A','B'),
1124 '3'=>array('A','A','B','B','B','A'),
1125 '4'=>array('A','B','A','A','B','B'),
1126 '5'=>array('A','B','B','A','A','B'),
1127 '6'=>array('A','B','B','B','A','A'),
1128 '7'=>array('A','B','A','B','A','B'),
1129 '8'=>array('A','B','A','B','B','A'),
1130 '9'=>array('A','B','B','A','B','A')
1131 );
1132 $k = 0;
1133 $seq = '101'; // left guard bar
1134 if ($upce) {
1135 $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1136 $p = $upce_parities[$code{1}][$r];
1137 for ($i = 0; $i < 6; ++$i) {
1138 $seq .= $codes[$p[$i]][$upce_code{$i}];
1139 }
1140 $seq .= '010101'; // right guard bar
1141 } else {
1142 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1143 $half_len = ceil($len / 2);
1144 if ($len == 8) {
1145 for ($i = 0; $i < $half_len; ++$i) {
1146 $seq .= $codes['A'][$code{$i}];
1147 }
1148 } else {
1149 $p = $parities[$code{0}];
1150 for ($i = 1; $i < $half_len; ++$i) {
1151 $seq .= $codes[$p[$i-1]][$code{$i}];
1152 }
1153 }
1154 $seq .= '01010'; // center guard bar
1155 for ($i = $half_len; $i < $len; ++$i) {
1156 $seq .= $codes['C'][$code{$i}];
1157 }
1158 $seq .= '101'; // right guard bar
1159 }
1160 $clen = strlen($seq);
1161 $w = 0;
1162 for ($i = 0; $i < $clen; ++$i) {
1163 $w += 1;
1164 if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
1165 if ($seq{$i} == '1') {
1166 $t = true; // bar
1167 } else {
1168 $t = false; // space
1169 }
1170 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1171 $bararray['maxw'] += $w;
1172 ++$k;
1173 $w = 0;
1174 }
1175 }
1176 return $bararray;
1177 }
1178
1179 /**
1180 * UPC-Based Extentions
1181 * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
1182 * 5-Digit Ext.: Used to mark suggested retail price of books
1183 * @param string $code code to represent.
1184 * @param string $len barcode type: 2 = 2-Digit, 5 = 5-Digit
1185 * @return array barcode representation.
1186 * @access protected
1187 */
1188 protected function barcode_eanext($code, $len=5) {
1189 //Padding
1190 $code = str_pad($code, $len, '0', STR_PAD_LEFT);
1191 // calculate check digit
1192 if ($len == 2) {
1193 $r = $code % 4;
1194 } elseif ($len == 5) {
1195 $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3}));
1196 $r %= 10;
1197 } else {
1198 return false;
1199 }
1200 //Convert digits to bars
1201 $codes = array(
1202 'A'=>array( // left odd parity
1203 '0'=>'0001101',
1204 '1'=>'0011001',
1205 '2'=>'0010011',
1206 '3'=>'0111101',
1207 '4'=>'0100011',
1208 '5'=>'0110001',
1209 '6'=>'0101111',
1210 '7'=>'0111011',
1211 '8'=>'0110111',
1212 '9'=>'0001011'),
1213 'B'=>array( // left even parity
1214 '0'=>'0100111',
1215 '1'=>'0110011',
1216 '2'=>'0011011',
1217 '3'=>'0100001',
1218 '4'=>'0011101',
1219 '5'=>'0111001',
1220 '6'=>'0000101',
1221 '7'=>'0010001',
1222 '8'=>'0001001',
1223 '9'=>'0010111')
1224 );
1225 $parities = array();
1226 $parities[2] = array(
1227 '0'=>array('A','A'),
1228 '1'=>array('A','B'),
1229 '2'=>array('B','A'),
1230 '3'=>array('B','B')
1231 );
1232 $parities[5] = array(
1233 '0'=>array('B','B','A','A','A'),
1234 '1'=>array('B','A','B','A','A'),
1235 '2'=>array('B','A','A','B','A'),
1236 '3'=>array('B','A','A','A','B'),
1237 '4'=>array('A','B','B','A','A'),
1238 '5'=>array('A','A','B','B','A'),
1239 '6'=>array('A','A','A','B','B'),
1240 '7'=>array('A','B','A','B','A'),
1241 '8'=>array('A','B','A','A','B'),
1242 '9'=>array('A','A','B','A','B')
1243 );
1244 $p = $parities[$len][$r];
1245 $seq = '1011'; // left guard bar
1246 $seq .= $codes[$p[0]][$code{0}];
1247 for ($i = 1; $i < $len; ++$i) {
1248 $seq .= '01'; // separator
1249 $seq .= $codes[$p[$i]][$code{$i}];
1250 }
1251 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1252 return $this->binseq_to_array($seq, $bararray);
1253 }
1254
1255 /**
1256 * POSTNET and PLANET barcodes.
1257 * Used by U.S. Postal Service for automated mail sorting
1258 * @param string $code zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
1259 * @param boolean $planet if true print the PLANET barcode, otherwise print POSTNET
1260 * @return array barcode representation.
1261 * @access protected
1262 */
1263 protected function barcode_postnet($code, $planet=false) {
1264 // bar lenght
1265 if ($planet) {
1266 $barlen = Array(
1267 0 => Array(1,1,2,2,2),
1268 1 => Array(2,2,2,1,1),
1269 2 => Array(2,2,1,2,1),
1270 3 => Array(2,2,1,1,2),
1271 4 => Array(2,1,2,2,1),
1272 5 => Array(2,1,2,1,2),
1273 6 => Array(2,1,1,2,2),
1274 7 => Array(1,2,2,2,1),
1275 8 => Array(1,2,2,1,2),
1276 9 => Array(1,2,1,2,2)
1277 );
1278 } else {
1279 $barlen = Array(
1280 0 => Array(2,2,1,1,1),
1281 1 => Array(1,1,1,2,2),
1282 2 => Array(1,1,2,1,2),
1283 3 => Array(1,1,2,2,1),
1284 4 => Array(1,2,1,1,2),
1285 5 => Array(1,2,1,2,1),
1286 6 => Array(1,2,2,1,1),
1287 7 => Array(2,1,1,1,2),
1288 8 => Array(2,1,1,2,1),
1289 9 => Array(2,1,2,1,1)
1290 );
1291 }
1292 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1293 $k = 0;
1294 $code = str_replace('-', '', $code);
1295 $code = str_replace(' ', '', $code);
1296 $len = strlen($code);
1297 // calculate checksum
1298 $sum = 0;
1299 for ($i = 0; $i < $len; ++$i) {
1300 $sum += intval($code{$i});
1301 }
1302 $chkd = ($sum % 10);
1303 if($chkd > 0) {
1304 $chkd = (10 - $chkd);
1305 }
1306 $code .= $chkd;
1307 $len = strlen($code);
1308 // start bar
1309 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1310 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1311 $bararray['maxw'] += 2;
1312 for ($i = 0; $i < $len; ++$i) {
1313 for ($j = 0; $j < 5; ++$j) {
1314 $h = $barlen[$code{$i}][$j];
1315 $p = floor(1 / $h);
1316 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1317 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1318 $bararray['maxw'] += 2;
1319 }
1320 }
1321 // end bar
1322 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1323 $bararray['maxw'] += 1;
1324 return $bararray;
1325 }
1326
1327 /**
1328 * RMS4CC - CBC - KIX
1329 * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
1330 * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
1331 * @param string $code code to print
1332 * @param boolean $kix if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the code.
1333 * @return array barcode representation.
1334 * @access protected
1335 */
1336 protected function barcode_rms4cc($code, $kix=false) {
1337 $notkix = !$kix;
1338 // bar mode
1339 // 1 = pos 1, length 2
1340 // 2 = pos 1, length 3
1341 // 3 = pos 2, length 1
1342 // 4 = pos 2, length 2
1343 $barmode = array(
1344 '0' => array(3,3,2,2),
1345 '1' => array(3,4,1,2),
1346 '2' => array(3,4,2,1),
1347 '3' => array(4,3,1,2),
1348 '4' => array(4,3,2,1),
1349 '5' => array(4,4,1,1),
1350 '6' => array(3,1,4,2),
1351 '7' => array(3,2,3,2),
1352 '8' => array(3,2,4,1),
1353 '9' => array(4,1,3,2),
1354 'A' => array(4,1,4,1),
1355 'B' => array(4,2,3,1),
1356 'C' => array(3,1,2,4),
1357 'D' => array(3,2,1,4),
1358 'E' => array(3,2,2,3),
1359 'F' => array(4,1,1,4),
1360 'G' => array(4,1,2,3),
1361 'H' => array(4,2,1,3),
1362 'I' => array(1,3,4,2),
1363 'J' => array(1,4,3,2),
1364 'K' => array(1,4,4,1),
1365 'L' => array(2,3,3,2),
1366 'M' => array(2,3,4,1),
1367 'N' => array(2,4,3,1),
1368 'O' => array(1,3,2,4),
1369 'P' => array(1,4,1,4),
1370 'Q' => array(1,4,2,3),
1371 'R' => array(2,3,1,4),
1372 'S' => array(2,3,2,3),
1373 'T' => array(2,4,1,3),
1374 'U' => array(1,1,4,4),
1375 'V' => array(1,2,3,4),
1376 'W' => array(1,2,4,3),
1377 'X' => array(2,1,3,4),
1378 'Y' => array(2,1,4,3),
1379 'Z' => array(2,2,3,3)
1380 );
1381 $code = strtoupper($code);
1382 $len = strlen($code);
1383 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
1384 if ($notkix) {
1385 // table for checksum calculation (row,col)
1386 $checktable = array(
1387 '0' => array(1,1),
1388 '1' => array(1,2),
1389 '2' => array(1,3),
1390 '3' => array(1,4),
1391 '4' => array(1,5),
1392 '5' => array(1,0),
1393 '6' => array(2,1),
1394 '7' => array(2,2),
1395 '8' => array(2,3),
1396 '9' => array(2,4),
1397 'A' => array(2,5),
1398 'B' => array(2,0),
1399 'C' => array(3,1),
1400 'D' => array(3,2),
1401 'E' => array(3,3),
1402 'F' => array(3,4),
1403 'G' => array(3,5),
1404 'H' => array(3,0),
1405 'I' => array(4,1),
1406 'J' => array(4,2),
1407 'K' => array(4,3),
1408 'L' => array(4,4),
1409 'M' => array(4,5),
1410 'N' => array(4,0),
1411 'O' => array(5,1),
1412 'P' => array(5,2),
1413 'Q' => array(5,3),
1414 'R' => array(5,4),
1415 'S' => array(5,5),
1416 'T' => array(5,0),
1417 'U' => array(0,1),
1418 'V' => array(0,2),
1419 'W' => array(0,3),
1420 'X' => array(0,4),
1421 'Y' => array(0,5),
1422 'Z' => array(0,0)
1423 );
1424 $row = 0;
1425 $col = 0;
1426 for ($i = 0; $i < $len; ++$i) {
1427 $row += $checktable[$code{$i}][0];
1428 $col += $checktable[$code{$i}][1];
1429 }
1430 $row %= 6;
1431 $col %= 6;
1432 $chk = array_keys($checktable, array($row,$col));
1433 $code .= $chk[0];
1434 ++$len;
1435 }
1436 $k = 0;
1437 if ($notkix) {
1438 // start bar
1439 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1440 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1441 $bararray['maxw'] += 2;
1442 }
1443 for ($i = 0; $i < $len; ++$i) {
1444 for ($j = 0; $j < 4; ++$j) {
1445 switch ($barmode[$code{$i}][$j]) {
1446 case 1: {
1447 $p = 0;
1448 $h = 2;
1449 break;
1450 }
1451 case 2: {
1452 $p = 0;
1453 $h = 3;
1454 break;
1455 }
1456 case 3: {
1457 $p = 1;
1458 $h = 1;
1459 break;
1460 }
1461 case 4: {
1462 $p = 1;
1463 $h = 2;
1464 break;
1465 }
1466 }
1467 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1468 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1469 $bararray['maxw'] += 2;
1470 }
1471 }
1472 if ($notkix) {
1473 // stop bar
1474 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0);
1475 $bararray['maxw'] += 1;
1476 }
1477 return $bararray;
1478 }
1479
1480 /**
1481 * CODABAR barcodes.
1482 * Older code often used in library systems, sometimes in blood banks
1483 * @param string $code code to represent.
1484 * @return array barcode representation.
1485 * @access protected
1486 */
1487 protected function barcode_codabar($code) {
1488 $chr = array(
1489 '0' => '11111221',
1490 '1' => '11112211',
1491 '2' => '11121121',
1492 '3' => '22111111',
1493 '4' => '11211211',
1494 '5' => '21111211',
1495 '6' => '12111121',
1496 '7' => '12112111',
1497 '8' => '12211111',
1498 '9' => '21121111',
1499 '-' => '11122111',
1500 '$' => '11221111',
1501 ':' => '21112121',
1502 '/' => '21211121',
1503 '.' => '21212111',
1504 '+' => '11222221',
1505 'A' => '11221211',
1506 'B' => '12121121',
1507 'C' => '11121221',
1508 'D' => '11122211'
1509 );
1510 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1511 $k = 0;
1512 $w = 0;
1513 $seq = '';
1514 $code = 'A'.strtoupper($code).'A';
1515 $len = strlen($code);
1516 for ($i = 0; $i < $len; ++$i) {
1517 if (!isset($chr[$code{$i}])) {
1518 return false;
1519 }
1520 $seq = $chr[$code{$i}];
1521 for ($j = 0; $j < 8; ++$j) {
1522 if (($j % 2) == 0) {
1523 $t = true; // bar
1524 } else {
1525 $t = false; // space
1526 }
1527 $w = $seq{$j};
1528 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1529 $bararray['maxw'] += $w;
1530 ++$k;
1531 }
1532 }
1533 return $bararray;
1534 }
1535
1536 /**
1537 * CODE11 barcodes.
1538 * Used primarily for labeling telecommunications equipment
1539 * @param string $code code to represent.
1540 * @return array barcode representation.
1541 * @access protected
1542 */
1543 protected function barcode_code11($code) {
1544 $chr = array(
1545 '0' => '111121',
1546 '1' => '211121',
1547 '2' => '121121',
1548 '3' => '221111',
1549 '4' => '112121',
1550 '5' => '212111',
1551 '6' => '122111',
1552 '7' => '111221',
1553 '8' => '211211',
1554 '9' => '211111',
1555 '-' => '112111',
1556 'S' => '112211'
1557 );
1558
1559 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1560 $k = 0;
1561 $w = 0;
1562 $seq = '';
1563 $len = strlen($code);
1564 // calculate check digit C
1565 $p = 1;
1566 $check = 0;
1567 for ($i = ($len - 1); $i >= 0; --$i) {
1568 $digit = $code{$i};
1569 if ($digit == '-') {
1570 $dval = 10;
1571 } else {
1572 $dval = intval($digit);
1573 }
1574 $check += ($dval * $p);
1575 ++$p;
1576 if ($p > 10) {
1577 $p = 1;
1578 }
1579 }
1580 $check %= 11;
1581 if ($check == 10) {
1582 $check = '-';
1583 }
1584 $code .= $check;
1585 if ($len > 10) {
1586 // calculate check digit K
1587 $p = 1;
1588 $check = 0;
1589 for ($i = $len; $i >= 0; --$i) {
1590 $digit = $code{$i};
1591 if ($digit == '-') {
1592 $dval = 10;
1593 } else {
1594 $dval = intval($digit);
1595 }
1596 $check += ($dval * $p);
1597 ++$p;
1598 if ($p > 9) {
1599 $p = 1;
1600 }
1601 }
1602 $check %= 11;
1603 $code .= $check;
1604 ++$len;
1605 }
1606 $code = 'S'.$code.'S';
1607 $len += 3;
1608 for ($i = 0; $i < $len; ++$i) {
1609 if (!isset($chr[$code{$i}])) {
1610 return false;
1611 }
1612 $seq = $chr[$code{$i}];
1613 for ($j = 0; $j < 6; ++$j) {
1614 if (($j % 2) == 0) {
1615 $t = true; // bar
1616 } else {
1617 $t = false; // space
1618 }
1619 $w = $seq{$j};
1620 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1621 $bararray['maxw'] += $w;
1622 ++$k;
1623 }
1624 }
1625 return $bararray;
1626 }
1627
1628 /**
1629 * Pharmacode
1630 * Contains digits (0 to 9)
1631 * @param string $code code to represent.
1632 * @return array barcode representation.
1633 * @access protected
1634 */
1635 protected function barcode_pharmacode($code) {
1636 $seq = '';
1637 $code = intval($code);
1638 while ($code > 0) {
1639 if (($code % 2) == 0) {
1640 $seq .= '11100';
1641 $code -= 2;
1642 } else {
1643 $seq .= '100';
1644 $code -= 1;
1645 }
1646 $code /= 2;
1647 }
1648 $seq = substr($seq, 0, -2);
1649 $seq = strrev($seq);
1650 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1651 return $this->binseq_to_array($seq, $bararray);
1652 }
1653
1654 /**
1655 * Pharmacode two-track
1656 * Contains digits (0 to 9)
1657 * @param string $code code to represent.
1658 * @return array barcode representation.
1659 * @access protected
1660 */
1661 protected function barcode_pharmacode2t($code) {
1662 $seq = '';
1663 $code = intval($code);
1664 do {
1665 switch ($code % 3) {
1666 case 0: {
1667 $seq .= '3';
1668 $code = ($code - 3) / 3;
1669 break;
1670 }
1671 case 1: {
1672 $seq .= '1';
1673 $code = ($code - 1) / 3;
1674 break;
1675 }
1676 case 2: {
1677 $seq .= '2';
1678 $code = ($code - 2) / 3;
1679 break;
1680 }
1681 }
1682 } while($code != 0);
1683 $seq = strrev($seq);
1684 $k = 0;
1685 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1686 $len = strlen($seq);
1687 for ($i = 0; $i < $len; ++$i) {
1688 switch ($seq{$i}) {
1689 case '1': {
1690 $p = 1;
1691 $h = 1;
1692 break;
1693 }
1694 case '2': {
1695 $p = 0;
1696 $h = 1;
1697 break;
1698 }
1699 case '3': {
1700 $p = 0;
1701 $h = 2;
1702 break;
1703 }
1704 }
1705 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1706 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1707 $bararray['maxw'] += 2;
1708 }
1709 unset($bararray['bcode'][($k - 1)]);
1710 --$bararray['maxw'];
1711 return $bararray;
1712 }
1713
1714
1715 /**
1716 * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
1717 * (requires PHP bcmath extension)
1718 * Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
1719 * 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>
1720 * @param string $code code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
1721 * @return array barcode representation.
1722 * @access protected
1723 */
1724 protected function barcode_imb($code) {
1725 $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);
1726 $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);
1727 $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);
1728 $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);
1729 $code_arr = explode('-', $code);
1730 $tracking_number = $code_arr[0];
1731 if (isset($code_arr[1])) {
1732 $routing_code = $code_arr[1];
1733 } else {
1734 $routing_code = '';
1735 }
1736 // Conversion of Routing Code
1737 switch (strlen($routing_code)) {
1738 case 0: {
1739 $binary_code = 0;
1740 break;
1741 }
1742 case 5: {
1743 $binary_code = bcadd($routing_code, '1');
1744 break;
1745 }
1746 case 9: {
1747 $binary_code = bcadd($routing_code, '100001');
1748 break;
1749 }
1750 case 11: {
1751 $binary_code = bcadd($routing_code, '1000100001');
1752 break;
1753 }
1754 default: {
1755 return false;
1756 break;
1757 }
1758 }
1759 $binary_code = bcmul($binary_code, 10);
1760 $binary_code = bcadd($binary_code, $tracking_number{0});
1761 $binary_code = bcmul($binary_code, 5);
1762 $binary_code = bcadd($binary_code, $tracking_number{1});
1763 $binary_code .= substr($tracking_number, 2, 18);
1764 // convert to hexadecimal
1765 $binary_code = $this->dec_to_hex($binary_code);
1766 // pad to get 13 bytes
1767 $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
1768 // convert string to array of bytes
1769 $binary_code_arr = chunk_split($binary_code, 2, "\r");
1770 $binary_code_arr = substr($binary_code_arr, 0, -1);
1771 $binary_code_arr = explode("\r", $binary_code_arr);
1772 // calculate frame check sequence
1773 $fcs = $this->imb_crc11fcs($binary_code_arr);
1774 // exclude first 2 bits from first byte
1775 $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
1776 $binary_code_102bit = $first_byte.substr($binary_code, 2);
1777 // convert binary data to codewords
1778 $codewords = array();
1779 $data = $this->hex_to_dec($binary_code_102bit);
1780 $codewords[0] = bcmod($data, 636) * 2;
1781 $data = bcdiv($data, 636);
1782 for ($i = 1; $i < 9; ++$i) {
1783 $codewords[$i] = bcmod($data, 1365);
1784 $data = bcdiv($data, 1365);
1785 }
1786 $codewords[9] = $data;
1787 if (($fcs >> 10) == 1) {
1788 $codewords[9] += 659;
1789 }
1790 // generate lookup tables
1791 $table2of13 = $this->imb_tables(2, 78);
1792 $table5of13 = $this->imb_tables(5, 1287);
1793 // convert codewords to characters
1794 $characters = array();
1795 $bitmask = 512;
1796 foreach($codewords as $k => $val) {
1797 if ($val <= 1286) {
1798 $chrcode = $table5of13[$val];
1799 } else {
1800 $chrcode = $table2of13[($val - 1287)];
1801 }
1802 if (($fcs & $bitmask) > 0) {
1803 // bitwise invert
1804 $chrcode = ((~$chrcode) & 8191);
1805 }
1806 $characters[] = $chrcode;
1807 $bitmask /= 2;
1808 }
1809 $characters = array_reverse($characters);
1810 // build bars
1811 $k = 0;
1812 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
1813 for ($i = 0; $i < 65; ++$i) {
1814 $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0);
1815 $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0);
1816 if ($asc AND $dsc) {
1817 // full bar (F)
1818 $p = 0;
1819 $h = 3;
1820 } elseif ($asc) {
1821 // ascender (A)
1822 $p = 0;
1823 $h = 2;
1824 } elseif ($dsc) {
1825 // descender (D)
1826 $p = 1;
1827 $h = 2;
1828 } else {
1829 // tracker (T)
1830 $p = 1;
1831 $h = 1;
1832 }
1833 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1834 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1835 $bararray['maxw'] += 2;
1836 }
1837 unset($bararray['bcode'][($k - 1)]);
1838 --$bararray['maxw'];
1839 return $bararray;
1840 }
1841
1842 /**
1843 * Convert large integer number to hexadecimal representation.
1844 * (requires PHP bcmath extension)
1845 * @param string $number number to convert specified as a string
1846 * @return string hexadecimal representation
1847 */
1848 public function dec_to_hex($number) {
1849 $i = 0;
1850 $hex = array();
1851 if($number == 0) {
1852 return '00';
1853 }
1854 while($number > 0) {
1855 if($number == 0) {
1856 array_push($hex, '0');
1857 } else {
1858 array_push($hex, strtoupper(dechex(bcmod($number, '16'))));
1859 $number = bcdiv($number, '16', 0);
1860 }
1861 }
1862 $hex = array_reverse($hex);
1863 return implode($hex);
1864 }
1865
1866 /**
1867 * Convert large hexadecimal number to decimal representation (string).
1868 * (requires PHP bcmath extension)
1869 * @param string $hex hexadecimal number to convert specified as a string
1870 * @return string hexadecimal representation
1871 */
1872 public function hex_to_dec($hex) {
1873 $dec = 0;
1874 $bitval = 1;
1875 $len = strlen($hex);
1876 for($pos = ($len - 1); $pos >= 0; --$pos) {
1877 $dec = bcadd($dec, bcmul(hexdec($hex{$pos}), $bitval));
1878 $bitval = bcmul($bitval, 16);
1879 }
1880 return $dec;
1881 }
1882
1883 /**
1884 * Intelligent Mail Barcode calculation of Frame Check Sequence
1885 * @param string $code_arr array of hexadecimal values (13 bytes holding 102 bits right justified).
1886 * @return int 11 bit Frame Check Sequence as integer (decimal base)
1887 * @access protected
1888 */
1889 protected function imb_crc11fcs($code_arr) {
1890 $genpoly = 0x0F35; // generator polynomial
1891 $fcs = 0x07FF; // Frame Check Sequence
1892 // do most significant byte skipping the 2 most significant bits
1893 $data = hexdec($code_arr[0]) << 5;
1894 for ($bit = 2; $bit < 8; ++$bit) {
1895 if (($fcs ^ $data) & 0x400) {
1896 $fcs = ($fcs << 1) ^ $genpoly;
1897 } else {
1898 $fcs = ($fcs << 1);
1899 }
1900 $fcs &= 0x7FF;
1901 $data <<= 1;
1902 }
1903 // do rest of bytes
1904 for ($byte = 1; $byte < 13; ++$byte) {
1905 $data = hexdec($code_arr[$byte]) << 3;
1906 for ($bit = 0; $bit < 8; ++$bit) {
1907 if (($fcs ^ $data) & 0x400) {
1908 $fcs = ($fcs << 1) ^ $genpoly;
1909 } else {
1910 $fcs = ($fcs << 1);
1911 }
1912 $fcs &= 0x7FF;
1913 $data <<= 1;
1914 }
1915 }
1916 return $fcs;
1917 }
1918
1919 /**
1920 * Reverse unsigned short value
1921 * @param int $num value to reversr
1922 * @return int reversed value
1923 * @access protected
1924 */
1925 protected function imb_reverse_us($num) {
1926 $rev = 0;
1927 for ($i = 0; $i < 16; ++$i) {
1928 $rev <<= 1;
1929 $rev |= ($num & 1);
1930 $num >>= 1;
1931 }
1932 return $rev;
1933 }
1934
1935 /**
1936 * generate Nof13 tables used for Intelligent Mail Barcode
1937 * @param int $n is the type of table: 2 for 2of13 table, 5 for 5of13table
1938 * @param int $size size of table (78 for n=2 and 1287 for n=5)
1939 * @return array requested table
1940 * @access protected
1941 */
1942 protected function imb_tables($n, $size) {
1943 $table = array();
1944 $lli = 0; // LUT lower index
1945 $lui = $size - 1; // LUT upper index
1946 for ($count = 0; $count < 8192; ++$count) {
1947 $bit_count = 0;
1948 for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
1949 $bit_count += intval(($count & (1 << $bit_index)) != 0);
1950 }
1951 // if we don't have the right number of bits on, go on to the next value
1952 if ($bit_count == $n) {
1953 $reverse = ($this->imb_reverse_us($count) >> 3);
1954 // if the reverse is less than count, we have already visited this pair before
1955 if ($reverse >= $count) {
1956 // If count is symmetric, place it at the first free slot from the end of the list.
1957 // 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
1958 if ($reverse == $count) {
1959 $table[$lui] = $count;
1960 --$lui;
1961 } else {
1962 $table[$lli] = $count;
1963 ++$lli;
1964 $table[$lli] = $reverse;
1965 ++$lli;
1966 }
1967 }
1968 }
1969 }
1970 return $table;
1971 }
1972
1973} // end of class
1974
1975//============================================================+
1976// END OF FILE
1977//============================================================+
1978?>
Note: See TracBrowser for help on using the repository browser.