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