2 //============================================================+
3 // File name : barcodes.php
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 //============================================================+
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
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
48 * @author Nicola Asuni
53 * Array representation of barcode.
56 protected $barcode_array;
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);
77 * Return an array representations of barcode.
80 public function getBarcodeArray() {
81 return $this->barcode_array
;
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>
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);
96 case 'C39+': { // CODE 39 with checksum
97 $arrcode = $this->barcode_code39($code, false, true);
100 case 'C39E': { // CODE 39 EXTENDED
101 $arrcode = $this->barcode_code39($code, true, false);
104 case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM
105 $arrcode = $this->barcode_code39($code, true, true);
108 case 'C93': { // CODE 93 - USS-93
109 $arrcode = $this->barcode_code93($code);
112 case 'S25': { // Standard 2 of 5
113 $arrcode = $this->barcode_s25($code, false);
116 case 'S25+': { // Standard 2 of 5 + CHECKSUM
117 $arrcode = $this->barcode_s25($code, true);
120 case 'I25': { // Interleaved 2 of 5
121 $arrcode = $this->barcode_i25($code, false);
124 case 'I25+': { // Interleaved 2 of 5 + CHECKSUM
125 $arrcode = $this->barcode_i25($code, true);
128 case 'C128A': { // CODE 128 A
129 $arrcode = $this->barcode_c128($code, 'A');
132 case 'C128B': { // CODE 128 B
133 $arrcode = $this->barcode_c128($code, 'B');
136 case 'C128C': { // CODE 128 C
137 $arrcode = $this->barcode_c128($code, 'C');
140 case 'EAN2': { // 2-Digits UPC-Based Extention
141 $arrcode = $this->barcode_eanext($code, 2);
144 case 'EAN5': { // 5-Digits UPC-Based Extention
145 $arrcode = $this->barcode_eanext($code, 5);
148 case 'EAN8': { // EAN 8
149 $arrcode = $this->barcode_eanupc($code, 8);
152 case 'EAN13': { // EAN 13
153 $arrcode = $this->barcode_eanupc($code, 13);
156 case 'UPCA': { // UPC-A
157 $arrcode = $this->barcode_eanupc($code, 12);
160 case 'UPCE': { // UPC-E
161 $arrcode = $this->barcode_eanupc($code, 6);
164 case 'MSI': { // MSI (Variation of Plessey code)
165 $arrcode = $this->barcode_msi($code, false);
168 case 'MSI+': { // MSI + CHECKSUM (modulo 11)
169 $arrcode = $this->barcode_msi($code, true);
172 case 'POSTNET': { // POSTNET
173 $arrcode = $this->barcode_postnet($code, false);
176 case 'PLANET': { // PLANET
177 $arrcode = $this->barcode_postnet($code, true);
180 case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
181 $arrcode = $this->barcode_rms4cc($code, false);
184 case 'KIX': { // KIX (Klant index - Customer index)
185 $arrcode = $this->barcode_rms4cc($code, true);
188 case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
189 $arrcode = $this->barcode_imb($code);
192 case 'CODABAR': { // CODABAR
193 $arrcode = $this->barcode_codabar($code);
196 case 'CODE11': { // CODE 11
197 $arrcode = $this->barcode_code11($code);
200 case 'PHARMA': { // PHARMACODE
201 $arrcode = $this->barcode_pharmacode($code);
204 case 'PHARMA2T': { // PHARMACODE TWO-TRACKS
205 $arrcode = $this->barcode_pharmacode2t($code);
209 $this->barcode_array
= false;
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.
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);
275 $code = $this->encode_code39_ext($code);
277 if ($code === false) {
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());
289 $clen = strlen($code);
290 for ($i = 0; $i < $clen; ++
$i) {
292 if(!isset($chr[$char])) {
296 for ($j = 0; $j < 9; ++
$j) {
302 $w = $chr[$char]{$j};
303 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
304 $bararray['maxw'] +
= $w;
307 $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0);
308 $bararray['maxw'] +
= 1;
315 * Encode a string to be used for CODE 39 Extended mode.
316 * @param $code (string) code to represent.
317 * @return encoded string.
320 protected function encode_code39_ext($code) {
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');
355 $clen = strlen($code);
356 for ($i = 0 ; $i < $clen; ++
$i) {
357 if (ord($code{$i}) > 127) {
360 $code_ext .= $encode[$code{$i}];
366 * Calculate CODE 39 checksum (modulo 43).
367 * @param $code (string) code to represent.
368 * @return char checksum.
371 protected function checksum_code39($code) {
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', '-', '.', ' ', '$', '/', '+', '%');
378 $clen = strlen($code);
379 for ($i = 0 ; $i < $clen; ++
$i) {
380 $k = array_keys($chars, $code{$i});
389 * Compact code similar to Code 39
390 * @param $code (string) code to represent.
391 * @return array barcode representation.
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);
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');
478 $clen = strlen($code);
479 for ($i = 0 ; $i < $clen; ++
$i) {
480 if (ord($code{$i}) > 127) {
483 $code_ext .= $encode[$code{$i}];
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());
491 $clen = strlen($code);
492 for ($i = 0; $i < $clen; ++
$i) {
494 if(!isset($chr[$char])) {
498 for ($j = 0; $j < 6; ++
$j) {
504 $w = $chr[$char]{$j};
505 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
506 $bararray['maxw'] +
= $w;
510 $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0);
511 $bararray['maxw'] +
= 1;
517 * Calculate CODE 93 checksum (modulo 47).
518 * @param $code (string) code to represent.
519 * @return string checksum code.
522 protected function checksum_code93($code) {
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
534 for ($i = ($len - 1); $i >= 0; --$i) {
535 $k = array_keys($chars, $code{$i});
536 $check +
= ($k[0] * $p);
545 // calculate check digit K
548 for ($i = $len; $i >= 0; --$i) {
549 $k = array_keys($chars, $code{$i});
550 $check +
= ($k[0] * $p);
562 * Checksum for standard 2 of 5 barcodes.
563 * @param $code (string) code to process.
564 * @return int checksum.
567 protected function checksum_s25($code) {
568 $len = strlen($code);
570 for ($i = 0; $i < $len; $i+
=2) {
574 for ($i = 1; $i < $len; $i+
=2) {
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.
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';
612 $clen = strlen($code);
615 for ($i = ($clen - 1); $i >= 0; --$i) {
616 $check +
= (hexdec($code{$i}) * $p);
624 $check = 11 - $check;
628 $seq = '110'; // left guard
629 $clen = strlen($code);
630 for ($i = 0; $i < $clen; ++
$i) {
632 if (!isset($chr[$digit])) {
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.
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';
665 $code .= $this->checksum_s25($code);
667 if((strlen($code) %
2) != 0) {
668 // add leading zero if code-length is odd
672 $clen = strlen($code);
673 for ($i = 0; $i < $clen; ++
$i) {
675 if (!isset($chr[$digit])) {
679 $seq .= $chr[$digit];
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.
694 protected function binseq_to_array($seq, $bararray) {
698 for ($i = 0; $i < $len; ++
$i) {
700 if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+
1)}))) {
701 if ($seq{$i} == '1') {
706 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
707 $bararray['maxw'] +
= $w;
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.
724 protected function barcode_i25($code, $checksum=false) {
739 $code .= $this->checksum_s25($code);
741 if((strlen($code) %
2) != 0) {
742 // add leading zero if code-length is odd
745 // add start and stop codes
746 $code = 'AA'.strtolower($code).'ZA';
748 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
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]))) {
758 // create a bar-space sequence
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) {
772 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
773 $bararray['maxw'] +
= $w;
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.
788 protected function barcode_c128($code, $type='B') {
893 '211412', /* 103 START A */
894 '211214', /* 104 START B */
895 '211232', /* 105 START C */
900 switch(strtoupper($type)) {
903 $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
904 for ($i = 0; $i < 32; ++
$i) {
911 $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
917 if ((strlen($code) %
2) != 0) {
918 // The length of barcode value must be even ($code). You must pad the number with zeros
921 for ($i = 0; $i <= 99; ++
$i) {
925 $hclen = (strlen($code) / 2);
926 for ($i = 0; $i < $hclen; ++
$i) {
927 $new_code .= chr(intval($code{(2 * $i)}.$code{(2 * $i +
1)}));
936 // calculate check character
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());
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])) {
959 for ($j = 0; $j < 6; ++
$j) {
966 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
967 $bararray['maxw'] +
= $w;
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.
984 protected function barcode_eanupc($code, $len=13) {
988 $upce = true; // UPC-E mode
990 $data_len = $len - 1;
992 $code = str_pad($code, $data_len, '0', STR_PAD_LEFT
);
993 $code_len = strlen($code);
994 // calculate check digit
996 for ($i = 1; $i < $data_len; $i+
=2) {
1003 for ($i = 0; $i < $data_len; $i+
=2) {
1004 $sum_b +
= ($code{$i});
1009 $r = ($sum_a +
$sum_b) %
10;
1013 if ($code_len == $data_len) {
1016 } elseif ($r !== intval($code{$data_len})) {
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);
1032 $tmp = substr($code, 5, 2);
1034 // manufacturer code ends in 00
1035 $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
1037 $tmp = substr($code, 6, 1);
1039 // manufacturer code ends in 0
1040 $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
1042 // manufacturer code does not end in zero
1043 $upce_code = substr($code, 2, 5).substr($code, 11, 1);
1048 //Convert digits to bars
1050 'A'=>array( // left odd parity
1061 'B'=>array( // left even parity
1072 'C'=>array( // right
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')
1122 $seq = '101'; // left guard bar
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
1131 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1132 $half_len = ceil($len / 2);
1134 for ($i = 0; $i < $half_len; ++
$i) {
1135 $seq .= $codes['A'][$code{$i}];
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);
1151 for ($i = 0; $i < $clen; ++
$i) {
1153 if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+
1)}))) {
1154 if ($seq{$i} == '1') {
1157 $t = false; // space
1159 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1160 $bararray['maxw'] +
= $w;
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.
1177 protected function barcode_eanext($code, $len=5) {
1179 $code = str_pad($code, $len, '0', STR_PAD_LEFT
);
1180 // calculate check digit
1183 } elseif ($len == 5) {
1184 $r = (3 * ($code{0} +
$code{2} +
$code{4})) +
(9 * ($code{1} +
$code{3}));
1189 //Convert digits to bars
1191 'A'=>array( // left odd parity
1202 'B'=>array( // left even parity
1214 $parities = array();
1215 $parities[2] = array(
1216 '0'=>array('A','A'),
1217 '1'=>array('A','B'),
1218 '2'=>array('B','A'),
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.
1252 protected function barcode_postnet($code, $planet=false) {
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)
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());
1283 $code = str_replace('-', '', $code);
1284 $code = str_replace(' ', '', $code);
1285 $len = strlen($code);
1286 // calculate checksum
1288 for ($i = 0; $i < $len; ++
$i) {
1289 $sum +
= intval($code{$i});
1291 $chkd = ($sum %
10);
1293 $chkd = (10 - $chkd);
1296 $len = strlen($code);
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];
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;
1311 $bararray['bcode'][$k++
] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1312 $bararray['maxw'] +
= 1;
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.
1325 protected function barcode_rms4cc($code, $kix=false) {
1328 // 1 = pos 1, length 2
1329 // 2 = pos 1, length 3
1330 // 3 = pos 2, length 1
1331 // 4 = pos 2, length 2
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());
1374 // table for checksum calculation (row,col)
1375 $checktable = array(
1415 for ($i = 0; $i < $len; ++
$i) {
1416 $row +
= $checktable[$code{$i}][0];
1417 $col +
= $checktable[$code{$i}][1];
1421 $chk = array_keys($checktable, array($row,$col));
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]) {
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;
1463 $bararray['bcode'][$k++
] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0);
1464 $bararray['maxw'] +
= 1;
1471 * Older code often used in library systems, sometimes in blood banks
1472 * @param $code (string) code to represent.
1473 * @return array barcode representation.
1476 protected function barcode_codabar($code) {
1499 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1503 $code = 'A'.strtoupper($code).'A';
1504 $len = strlen($code);
1505 for ($i = 0; $i < $len; ++
$i) {
1506 if (!isset($chr[$code{$i}])) {
1509 $seq = $chr[$code{$i}];
1510 for ($j = 0; $j < 8; ++
$j) {
1511 if (($j %
2) == 0) {
1514 $t = false; // space
1517 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1518 $bararray['maxw'] +
= $w;
1527 * Used primarily for labeling telecommunications equipment
1528 * @param $code (string) code to represent.
1529 * @return array barcode representation.
1532 protected function barcode_code11($code) {
1548 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1552 $len = strlen($code);
1553 // calculate check digit C
1556 for ($i = ($len - 1); $i >= 0; --$i) {
1558 if ($digit == '-') {
1561 $dval = intval($digit);
1563 $check +
= ($dval * $p);
1575 // calculate check digit K
1578 for ($i = $len; $i >= 0; --$i) {
1580 if ($digit == '-') {
1583 $dval = intval($digit);
1585 $check +
= ($dval * $p);
1595 $code = 'S'.$code.'S';
1597 for ($i = 0; $i < $len; ++
$i) {
1598 if (!isset($chr[$code{$i}])) {
1601 $seq = $chr[$code{$i}];
1602 for ($j = 0; $j < 6; ++
$j) {
1603 if (($j %
2) == 0) {
1606 $t = false; // space
1609 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1610 $bararray['maxw'] +
= $w;
1619 * Contains digits (0 to 9)
1620 * @param $code (string) code to represent.
1621 * @return array barcode representation.
1624 protected function barcode_pharmacode($code) {
1626 $code = intval($code);
1628 if (($code %
2) == 0) {
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.
1650 protected function barcode_pharmacode2t($code) {
1652 $code = intval($code);
1654 switch ($code %
3) {
1657 $code = ($code - 3) / 3;
1662 $code = ($code - 1) / 3;
1667 $code = ($code - 2) / 3;
1671 } while($code != 0);
1672 $seq = strrev($seq);
1674 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1675 $len = strlen($seq);
1676 for ($i = 0; $i < $len; ++
$i) {
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'];
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.
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];
1725 // Conversion of Routing Code
1726 switch (strlen($routing_code)) {
1732 $binary_code = bcadd($routing_code, '1');
1736 $binary_code = bcadd($routing_code, '100001');
1740 $binary_code = bcadd($routing_code, '1000100001');
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();
1785 foreach($codewords as $k => $val) {
1787 $chrcode = $table5of13[$val];
1789 $chrcode = $table2of13[($val - 1287)];
1791 if (($fcs & $bitmask) > 0) {
1793 $chrcode = ((~
$chrcode) & 8191);
1795 $characters[] = $chrcode;
1798 $characters = array_reverse($characters);
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) {
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'];
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) {
1843 while($number > 0) {
1845 array_push($hex, '0');
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) {
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);
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)
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;
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;
1909 * Reverse unsigned short value
1910 * @param $num (int) value to reversr
1911 * @return int reversed value
1914 protected function imb_reverse_us($num) {
1916 for ($i = 0; $i < 16; ++
$i) {
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
1931 protected function imb_tables($n, $size) {
1933 $lli = 0; // LUT lower index
1934 $lui = $size - 1; // LUT upper index
1935 for ($count = 0; $count < 8192; ++
$count) {
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;
1951 $table[$lli] = $count;
1953 $table[$lli] = $reverse;
1963 //============================================================+
1965 //============================================================+