source: sipes/libraries/tcpdf/barcodes.php @ eb502b4

stableversion-3.0
Last change on this file since eb502b4 was 307d09d, checked in by José Gregorio Puentes <jpuentes@…>, 8 años ago

se agregaron las librerias

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