Projet

Général

Profil

Paste
Télécharger (69,7 ko) Statistiques
| Branche: | Révision:

root / htmltest / sites / all / libraries / tcpdf-version / tcpdf_barcodes_1d.php @ 4543c6c7

1
<?php
2
//============================================================+
3
// File name   : tcpdf_barcodes_1d.php
4
// Version     : 1.0.025
5
// Begin       : 2008-06-09
6
// Last Update : 2013-03-17
7
// Author      : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8
// License     : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9
// -------------------------------------------------------------------
10
// Copyright (C) 2008-2013 Nicola Asuni - Tecnick.com LTD
11
//
12
// This file is part of TCPDF software library.
13
//
14
// TCPDF is free software: you can redistribute it and/or modify it
15
// under the terms of the GNU Lesser General Public License as
16
// published by the Free Software Foundation, either version 3 of the
17
// License, or (at your option) any later version.
18
//
19
// TCPDF is distributed in the hope that it will be useful, but
20
// WITHOUT ANY WARRANTY; without even the implied warranty of
21
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22
// See the GNU Lesser General Public License for more details.
23
//
24
// You should have received a copy of the GNU Lesser General Public License
25
// along with TCPDF.  If not, see <http://www.gnu.org/licenses/>.
26
//
27
// See LICENSE.TXT file for more information.
28
// -------------------------------------------------------------------
29
//
30
// Description : PHP class to creates array representations for
31
//               common 1D barcodes to be used with TCPDF.
32
//
33
//============================================================+
34

    
35
/**
36
 * @file
37
 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF.
38
 * @package com.tecnick.tcpdf
39
 * @author Nicola Asuni
40
 * @version 1.0.025
41
 */
42

    
43
/**
44
 * @class TCPDFBarcode
45
 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF (http://www.tcpdf.org).<br>
46
 * @package com.tecnick.tcpdf
47
 * @version 1.0.025
48
 * @author Nicola Asuni
49
 */
50
class TCPDFBarcode {
51

    
52
        /**
53
         * Array representation of barcode.
54
         * @protected
55
         */
56
        protected $barcode_array;
57

    
58
        /**
59
         * This is the class constructor.
60
         * Return an array representations for common 1D barcodes:<ul>
61
         * <li>$arrcode['code'] code to be printed on text label</li>
62
         * <li>$arrcode['maxh'] max barcode height</li>
63
         * <li>$arrcode['maxw'] max barcode width</li>
64
         * <li>$arrcode['bcode'][$k] single bar or space in $k position</li>
65
         * <li>$arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.</li>
66
         * <li>$arrcode['bcode'][$k]['w'] bar width in units.</li>
67
         * <li>$arrcode['bcode'][$k]['h'] bar height in units.</li>
68
         * <li>$arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)</li></ul>
69
         * @param $code (string) code to print
70
          * @param $type (string) type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128 : CODE 128</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
71
          * @public
72
         */
73
        public function __construct($code, $type) {
74
                $this->setBarcode($code, $type);
75
        }
76

    
77
        /**
78
         * Return an array representations of barcode.
79
          * @return array
80
          * @public
81
         */
82
        public function getBarcodeArray() {
83
                return $this->barcode_array;
84
        }
85

    
86
        /**
87
         * Send barcode as SVG image object to the standard output.
88
         * @param $w (int) Minimum width of a single bar in user units.
89
         * @param $h (int) Height of barcode in user units.
90
         * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
91
          * @public
92
         */
93
        public function getBarcodeSVG($w=2, $h=30, $color='black') {
94
                // send headers
95
                $code = $this->getBarcodeSVGcode($w, $h, $color);
96
                header('Content-Type: application/svg+xml');
97
                header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
98
                header('Pragma: public');
99
                header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
100
                header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
101
                header('Content-Disposition: inline; filename="'.md5($code).'.svg";');
102
                //header('Content-Length: '.strlen($code));
103
                echo $code;
104
        }
105

    
106
        /**
107
         * Return a SVG string representation of barcode.
108
         * @param $w (int) Minimum width of a single bar in user units.
109
         * @param $h (int) Height of barcode in user units.
110
         * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
111
          * @return string SVG code.
112
          * @public
113
         */
114
        public function getBarcodeSVGcode($w=2, $h=30, $color='black') {
115
                // replace table for special characters
116
                $repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
117
                $svg = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n";
118
                $svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n";
119
                $svg .= '<svg width="'.round(($this->barcode_array['maxw'] * $w), 3).'" height="'.$h.'" version="1.1" xmlns="http://www.w3.org/2000/svg">'."\n";
120
                $svg .= "\t".'<desc>'.strtr($this->barcode_array['code'], $repstr).'</desc>'."\n";
121
                $svg .= "\t".'<g id="bars" fill="'.$color.'" stroke="none">'."\n";
122
                // print bars
123
                $x = 0;
124
                foreach ($this->barcode_array['bcode'] as $k => $v) {
125
                        $bw = round(($v['w'] * $w), 3);
126
                        $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
127
                        if ($v['t']) {
128
                                $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
129
                                // draw a vertical bar
130
                                $svg .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$bw.'" height="'.$bh.'" />'."\n";
131
                        }
132
                        $x += $bw;
133
                }
134
                $svg .= "\t".'</g>'."\n";
135
                $svg .= '</svg>'."\n";
136
                return $svg;
137
        }
138

    
139
        /**
140
         * Return an HTML representation of barcode.
141
         * @param $w (int) Width of a single bar element in pixels.
142
         * @param $h (int) Height of a single bar element in pixels.
143
         * @param $color (string) Foreground color for bar elements (background is transparent).
144
          * @return string HTML code.
145
          * @public
146
         */
147
        public function getBarcodeHTML($w=2, $h=30, $color='black') {
148
                $html = '<div style="font-size:0;position:relative;width:'.($this->barcode_array['maxw'] * $w).'px;height:'.($h).'px;">'."\n";
149
                // print bars
150
                $x = 0;
151
                foreach ($this->barcode_array['bcode'] as $k => $v) {
152
                        $bw = round(($v['w'] * $w), 3);
153
                        $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
154
                        if ($v['t']) {
155
                                $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
156
                                // draw a vertical bar
157
                                $html .= '<div style="background-color:'.$color.';width:'.$bw.'px;height:'.$bh.'px;position:absolute;left:'.$x.'px;top:'.$y.'px;">&nbsp;</div>'."\n";
158
                        }
159
                        $x += $bw;
160
                }
161
                $html .= '</div>'."\n";
162
                return $html;
163
        }
164

    
165
        /**
166
         * Return a PNG image representation of barcode (requires GD or Imagick library).
167
         * @param $w (int) Width of a single bar element in pixels.
168
         * @param $h (int) Height of a single bar element in pixels.
169
         * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
170
          * @return image or false in case of error.
171
          * @public
172
         */
173
        public function getBarcodePNG($w=2, $h=30, $color=array(0,0,0)) {
174
                // calculate image size
175
                $width = ($this->barcode_array['maxw'] * $w);
176
                $height = $h;
177
                if (function_exists('imagecreate')) {
178
                        // GD library
179
                        $imagick = false;
180
                        $png = imagecreate($width, $height);
181
                        $bgcol = imagecolorallocate($png, 255, 255, 255);
182
                        imagecolortransparent($png, $bgcol);
183
                        $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
184
                } elseif (extension_loaded('imagick')) {
185
                        $imagick = true;
186
                        $bgcol = new imagickpixel('rgb(255,255,255');
187
                        $fgcol = new imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')');
188
                        $png = new Imagick();
189
                        $png->newImage($width, $height, 'none', 'png');
190
                        $bar = new imagickdraw();
191
                        $bar->setfillcolor($fgcol);
192
                } else {
193
                        return false;
194
                }
195
                // print bars
196
                $x = 0;
197
                foreach ($this->barcode_array['bcode'] as $k => $v) {
198
                        $bw = round(($v['w'] * $w), 3);
199
                        $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
200
                        if ($v['t']) {
201
                                $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
202
                                // draw a vertical bar
203
                                if ($imagick) {
204
                                        $bar->rectangle($x, $y, ($x + $bw - 1), ($y + $bh - 1));
205
                                } else {
206
                                        imagefilledrectangle($png, $x, $y, ($x + $bw - 1), ($y + $bh - 1), $fgcol);
207
                                }
208
                        }
209
                        $x += $bw;
210
                }
211
                // send headers
212
                header('Content-Type: image/png');
213
                header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
214
                header('Pragma: public');
215
                header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
216
                header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
217
                if ($imagick) {
218
                        $png->drawimage($bar);
219
                        echo $png;
220
                } else {
221
                        imagepng($png);
222
                        imagedestroy($png);
223
                }
224
        }
225

    
226
        /**
227
         * Set the barcode.
228
         * @param $code (string) code to print
229
          * @param $type (string) type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128 : CODE 128</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
230
          * @return array barcode array
231
          * @public
232
         */
233
        public function setBarcode($code, $type) {
234
                switch (strtoupper($type)) {
235
                        case 'C39': { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
236
                                $arrcode = $this->barcode_code39($code, false, false);
237
                                break;
238
                        }
239
                        case 'C39+': { // CODE 39 with checksum
240
                                $arrcode = $this->barcode_code39($code, false, true);
241
                                break;
242
                        }
243
                        case 'C39E': { // CODE 39 EXTENDED
244
                                $arrcode = $this->barcode_code39($code, true, false);
245
                                break;
246
                        }
247
                        case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM
248
                                $arrcode = $this->barcode_code39($code, true, true);
249
                                break;
250
                        }
251
                        case 'C93': { // CODE 93 - USS-93
252
                                $arrcode = $this->barcode_code93($code);
253
                                break;
254
                        }
255
                        case 'S25': { // Standard 2 of 5
256
                                $arrcode = $this->barcode_s25($code, false);
257
                                break;
258
                        }
259
                        case 'S25+': { // Standard 2 of 5 + CHECKSUM
260
                                $arrcode = $this->barcode_s25($code, true);
261
                                break;
262
                        }
263
                        case 'I25': { // Interleaved 2 of 5
264
                                $arrcode = $this->barcode_i25($code, false);
265
                                break;
266
                        }
267
                        case 'I25+': { // Interleaved 2 of 5 + CHECKSUM
268
                                $arrcode = $this->barcode_i25($code, true);
269
                                break;
270
                        }
271
                        case 'C128': { // CODE 128
272
                                $arrcode = $this->barcode_c128($code, '');
273
                                break;
274
                        }
275
                        case 'C128A': { // CODE 128 A
276
                                $arrcode = $this->barcode_c128($code, 'A');
277
                                break;
278
                        }
279
                        case 'C128B': { // CODE 128 B
280
                                $arrcode = $this->barcode_c128($code, 'B');
281
                                break;
282
                        }
283
                        case 'C128C': { // CODE 128 C
284
                                $arrcode = $this->barcode_c128($code, 'C');
285
                                break;
286
                        }
287
                        case 'EAN2': { // 2-Digits UPC-Based Extention
288
                                $arrcode = $this->barcode_eanext($code, 2);
289
                                break;
290
                        }
291
                        case 'EAN5': { // 5-Digits UPC-Based Extention
292
                                $arrcode = $this->barcode_eanext($code, 5);
293
                                break;
294
                        }
295
                        case 'EAN8': { // EAN 8
296
                                $arrcode = $this->barcode_eanupc($code, 8);
297
                                break;
298
                        }
299
                        case 'EAN13': { // EAN 13
300
                                $arrcode = $this->barcode_eanupc($code, 13);
301
                                break;
302
                        }
303
                        case 'UPCA': { // UPC-A
304
                                $arrcode = $this->barcode_eanupc($code, 12);
305
                                break;
306
                        }
307
                        case 'UPCE': { // UPC-E
308
                                $arrcode = $this->barcode_eanupc($code, 6);
309
                                break;
310
                        }
311
                        case 'MSI': { // MSI (Variation of Plessey code)
312
                                $arrcode = $this->barcode_msi($code, false);
313
                                break;
314
                        }
315
                        case 'MSI+': { // MSI + CHECKSUM (modulo 11)
316
                                $arrcode = $this->barcode_msi($code, true);
317
                                break;
318
                        }
319
                        case 'POSTNET': { // POSTNET
320
                                $arrcode = $this->barcode_postnet($code, false);
321
                                break;
322
                        }
323
                        case 'PLANET': { // PLANET
324
                                $arrcode = $this->barcode_postnet($code, true);
325
                                break;
326
                        }
327
                        case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
328
                                $arrcode = $this->barcode_rms4cc($code, false);
329
                                break;
330
                        }
331
                        case 'KIX': { // KIX (Klant index - Customer index)
332
                                $arrcode = $this->barcode_rms4cc($code, true);
333
                                break;
334
                        }
335
                        case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
336
                                $arrcode = $this->barcode_imb($code);
337
                                break;
338
                        }
339
                        case 'CODABAR': { // CODABAR
340
                                $arrcode = $this->barcode_codabar($code);
341
                                break;
342
                        }
343
                        case 'CODE11': { // CODE 11
344
                                $arrcode = $this->barcode_code11($code);
345
                                break;
346
                        }
347
                        case 'PHARMA': { // PHARMACODE
348
                                $arrcode = $this->barcode_pharmacode($code);
349
                                break;
350
                        }
351
                        case 'PHARMA2T': { // PHARMACODE TWO-TRACKS
352
                                $arrcode = $this->barcode_pharmacode2t($code);
353
                                break;
354
                        }
355
                        default: {
356
                                $this->barcode_array = false;
357
                                $arrcode = false;
358
                                break;
359
                        }
360
                }
361
                $this->barcode_array = $arrcode;
362
        }
363

    
364
        /**
365
         * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
366
         * General-purpose code in very wide use world-wide
367
         * @param $code (string) code to represent.
368
         * @param $extended (boolean) if true uses the extended mode.
369
         * @param $checksum (boolean) if true add a checksum to the code.
370
         * @return array barcode representation.
371
         * @protected
372
         */
373
        protected function barcode_code39($code, $extended=false, $checksum=false) {
374
                $chr['0'] = '111331311';
375
                $chr['1'] = '311311113';
376
                $chr['2'] = '113311113';
377
                $chr['3'] = '313311111';
378
                $chr['4'] = '111331113';
379
                $chr['5'] = '311331111';
380
                $chr['6'] = '113331111';
381
                $chr['7'] = '111311313';
382
                $chr['8'] = '311311311';
383
                $chr['9'] = '113311311';
384
                $chr['A'] = '311113113';
385
                $chr['B'] = '113113113';
386
                $chr['C'] = '313113111';
387
                $chr['D'] = '111133113';
388
                $chr['E'] = '311133111';
389
                $chr['F'] = '113133111';
390
                $chr['G'] = '111113313';
391
                $chr['H'] = '311113311';
392
                $chr['I'] = '113113311';
393
                $chr['J'] = '111133311';
394
                $chr['K'] = '311111133';
395
                $chr['L'] = '113111133';
396
                $chr['M'] = '313111131';
397
                $chr['N'] = '111131133';
398
                $chr['O'] = '311131131';
399
                $chr['P'] = '113131131';
400
                $chr['Q'] = '111111333';
401
                $chr['R'] = '311111331';
402
                $chr['S'] = '113111331';
403
                $chr['T'] = '111131331';
404
                $chr['U'] = '331111113';
405
                $chr['V'] = '133111113';
406
                $chr['W'] = '333111111';
407
                $chr['X'] = '131131113';
408
                $chr['Y'] = '331131111';
409
                $chr['Z'] = '133131111';
410
                $chr['-'] = '131111313';
411
                $chr['.'] = '331111311';
412
                $chr[' '] = '133111311';
413
                $chr['$'] = '131313111';
414
                $chr['/'] = '131311131';
415
                $chr['+'] = '131113131';
416
                $chr['%'] = '111313131';
417
                $chr['*'] = '131131311';
418
                $code = strtoupper($code);
419
                if ($extended) {
420
                        // extended mode
421
                        $code = $this->encode_code39_ext($code);
422
                }
423
                if ($code === false) {
424
                        return false;
425
                }
426
                if ($checksum) {
427
                        // checksum
428
                        $code .= $this->checksum_code39($code);
429
                }
430
                // add start and stop codes
431
                $code = '*'.$code.'*';
432
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
433
                $k = 0;
434
                $clen = strlen($code);
435
                for ($i = 0; $i < $clen; ++$i) {
436
                        $char = $code{$i};
437
                        if(!isset($chr[$char])) {
438
                                // invalid character
439
                                return false;
440
                        }
441
                        for ($j = 0; $j < 9; ++$j) {
442
                                if (($j % 2) == 0) {
443
                                        $t = true; // bar
444
                                } else {
445
                                        $t = false; // space
446
                                }
447
                                $w = $chr[$char]{$j};
448
                                $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
449
                                $bararray['maxw'] += $w;
450
                                ++$k;
451
                        }
452
                        // intercharacter gap
453
                        $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0);
454
                        $bararray['maxw'] += 1;
455
                        ++$k;
456
                }
457
                return $bararray;
458
        }
459

    
460
        /**
461
         * Encode a string to be used for CODE 39 Extended mode.
462
         * @param $code (string) code to represent.
463
         * @return encoded string.
464
         * @protected
465
         */
466
        protected function encode_code39_ext($code) {
467
                $encode = array(
468
                        chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
469
                        chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
470
                        chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
471
                        chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
472
                        chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
473
                        chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
474
                        chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
475
                        chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
476
                        chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
477
                        chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
478
                        chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
479
                        chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
480
                        chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
481
                        chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
482
                        chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
483
                        chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
484
                        chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
485
                        chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
486
                        chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
487
                        chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
488
                        chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
489
                        chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
490
                        chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
491
                        chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
492
                        chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
493
                        chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
494
                        chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
495
                        chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
496
                        chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
497
                        chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
498
                        chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
499
                        chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
500
                $code_ext = '';
501
                $clen = strlen($code);
502
                for ($i = 0 ; $i < $clen; ++$i) {
503
                        if (ord($code{$i}) > 127) {
504
                                return false;
505
                        }
506
                        $code_ext .= $encode[$code{$i}];
507
                }
508
                return $code_ext;
509
        }
510

    
511
        /**
512
         * Calculate CODE 39 checksum (modulo 43).
513
         * @param $code (string) code to represent.
514
         * @return char checksum.
515
         * @protected
516
         */
517
        protected function checksum_code39($code) {
518
                $chars = array(
519
                        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
520
                        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
521
                        'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
522
                        'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
523
                $sum = 0;
524
                $clen = strlen($code);
525
                for ($i = 0 ; $i < $clen; ++$i) {
526
                        $k = array_keys($chars, $code{$i});
527
                        $sum += $k[0];
528
                }
529
                $j = ($sum % 43);
530
                return $chars[$j];
531
        }
532

    
533
        /**
534
         * CODE 93 - USS-93
535
         * Compact code similar to Code 39
536
         * @param $code (string) code to represent.
537
         * @return array barcode representation.
538
         * @protected
539
         */
540
        protected function barcode_code93($code) {
541
                $chr[48] = '131112'; // 0
542
                $chr[49] = '111213'; // 1
543
                $chr[50] = '111312'; // 2
544
                $chr[51] = '111411'; // 3
545
                $chr[52] = '121113'; // 4
546
                $chr[53] = '121212'; // 5
547
                $chr[54] = '121311'; // 6
548
                $chr[55] = '111114'; // 7
549
                $chr[56] = '131211'; // 8
550
                $chr[57] = '141111'; // 9
551
                $chr[65] = '211113'; // A
552
                $chr[66] = '211212'; // B
553
                $chr[67] = '211311'; // C
554
                $chr[68] = '221112'; // D
555
                $chr[69] = '221211'; // E
556
                $chr[70] = '231111'; // F
557
                $chr[71] = '112113'; // G
558
                $chr[72] = '112212'; // H
559
                $chr[73] = '112311'; // I
560
                $chr[74] = '122112'; // J
561
                $chr[75] = '132111'; // K
562
                $chr[76] = '111123'; // L
563
                $chr[77] = '111222'; // M
564
                $chr[78] = '111321'; // N
565
                $chr[79] = '121122'; // O
566
                $chr[80] = '131121'; // P
567
                $chr[81] = '212112'; // Q
568
                $chr[82] = '212211'; // R
569
                $chr[83] = '211122'; // S
570
                $chr[84] = '211221'; // T
571
                $chr[85] = '221121'; // U
572
                $chr[86] = '222111'; // V
573
                $chr[87] = '112122'; // W
574
                $chr[88] = '112221'; // X
575
                $chr[89] = '122121'; // Y
576
                $chr[90] = '123111'; // Z
577
                $chr[45] = '121131'; // -
578
                $chr[46] = '311112'; // .
579
                $chr[32] = '311211'; //
580
                $chr[36] = '321111'; // $
581
                $chr[47] = '112131'; // /
582
                $chr[43] = '113121'; // +
583
                $chr[37] = '211131'; // %
584
                $chr[128] = '121221'; // ($)
585
                $chr[129] = '311121'; // (/)
586
                $chr[130] = '122211'; // (+)
587
                $chr[131] = '312111'; // (%)
588
                $chr[42] = '111141'; // start-stop
589
                $code = strtoupper($code);
590
                $encode = array(
591
                        chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C',
592
                        chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G',
593
                        chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K',
594
                        chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O',
595
                        chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S',
596
                        chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W',
597
                        chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A',
598
                        chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E',
599
                        chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C',
600
                        chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G',
601
                        chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K',
602
                        chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O',
603
                        chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
604
                        chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
605
                        chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F',
606
                        chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J',
607
                        chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
608
                        chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
609
                        chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
610
                        chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
611
                        chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
612
                        chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
613
                        chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K',
614
                        chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O',
615
                        chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C',
616
                        chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G',
617
                        chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K',
618
                        chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O',
619
                        chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S',
620
                        chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W',
621
                        chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P',
622
                        chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T');
623
                $code_ext = '';
624
                $clen = strlen($code);
625
                for ($i = 0 ; $i < $clen; ++$i) {
626
                        if (ord($code{$i}) > 127) {
627
                                return false;
628
                        }
629
                        $code_ext .= $encode[$code{$i}];
630
                }
631
                // checksum
632
                $code_ext .= $this->checksum_code93($code_ext);
633
                // add start and stop codes
634
                $code = '*'.$code_ext.'*';
635
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
636
                $k = 0;
637
                $clen = strlen($code);
638
                for ($i = 0; $i < $clen; ++$i) {
639
                        $char = ord($code{$i});
640
                        if(!isset($chr[$char])) {
641
                                // invalid character
642
                                return false;
643
                        }
644
                        for ($j = 0; $j < 6; ++$j) {
645
                                if (($j % 2) == 0) {
646
                                        $t = true; // bar
647
                                } else {
648
                                        $t = false; // space
649
                                }
650
                                $w = $chr[$char]{$j};
651
                                $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
652
                                $bararray['maxw'] += $w;
653
                                ++$k;
654
                        }
655
                }
656
                $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0);
657
                $bararray['maxw'] += 1;
658
                ++$k;
659
                return $bararray;
660
        }
661

    
662
        /**
663
         * Calculate CODE 93 checksum (modulo 47).
664
         * @param $code (string) code to represent.
665
         * @return string checksum code.
666
         * @protected
667
         */
668
        protected function checksum_code93($code) {
669
                $chars = array(
670
                        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
671
                        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
672
                        'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
673
                        'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%',
674
                        '<', '=', '>', '?');
675
                // translate special characters
676
                $code = strtr($code, chr(128).chr(131).chr(129).chr(130), '<=>?');
677
                $len = strlen($code);
678
                // calculate check digit C
679
                $p = 1;
680
                $check = 0;
681
                for ($i = ($len - 1); $i >= 0; --$i) {
682
                        $k = array_keys($chars, $code{$i});
683
                        $check += ($k[0] * $p);
684
                        ++$p;
685
                        if ($p > 20) {
686
                                $p = 1;
687
                        }
688
                }
689
                $check %= 47;
690
                $c = $chars[$check];
691
                $code .= $c;
692
                // calculate check digit K
693
                $p = 1;
694
                $check = 0;
695
                for ($i = $len; $i >= 0; --$i) {
696
                        $k = array_keys($chars, $code{$i});
697
                        $check += ($k[0] * $p);
698
                        ++$p;
699
                        if ($p > 15) {
700
                                $p = 1;
701
                        }
702
                }
703
                $check %= 47;
704
                $k = $chars[$check];
705
                $checksum = $c.$k;
706
                // resto respecial characters
707
                $checksum = strtr($checksum, '<=>?', chr(128).chr(131).chr(129).chr(130));
708
                return $checksum;
709
        }
710

    
711
        /**
712
         * Checksum for standard 2 of 5 barcodes.
713
         * @param $code (string) code to process.
714
         * @return int checksum.
715
         * @protected
716
         */
717
        protected function checksum_s25($code) {
718
                $len = strlen($code);
719
                $sum = 0;
720
                for ($i = 0; $i < $len; $i+=2) {
721
                        $sum += $code{$i};
722
                }
723
                $sum *= 3;
724
                for ($i = 1; $i < $len; $i+=2) {
725
                        $sum += ($code{$i});
726
                }
727
                $r = $sum % 10;
728
                if($r > 0) {
729
                        $r = (10 - $r);
730
                }
731
                return $r;
732
        }
733

    
734
        /**
735
         * MSI.
736
         * Variation of Plessey code, with similar applications
737
         * Contains digits (0 to 9) and encodes the data only in the width of bars.
738
         * @param $code (string) code to represent.
739
         * @param $checksum (boolean) if true add a checksum to the code (modulo 11)
740
         * @return array barcode representation.
741
         * @protected
742
         */
743
        protected function barcode_msi($code, $checksum=false) {
744
                $chr['0'] = '100100100100';
745
                $chr['1'] = '100100100110';
746
                $chr['2'] = '100100110100';
747
                $chr['3'] = '100100110110';
748
                $chr['4'] = '100110100100';
749
                $chr['5'] = '100110100110';
750
                $chr['6'] = '100110110100';
751
                $chr['7'] = '100110110110';
752
                $chr['8'] = '110100100100';
753
                $chr['9'] = '110100100110';
754
                $chr['A'] = '110100110100';
755
                $chr['B'] = '110100110110';
756
                $chr['C'] = '110110100100';
757
                $chr['D'] = '110110100110';
758
                $chr['E'] = '110110110100';
759
                $chr['F'] = '110110110110';
760
                if ($checksum) {
761
                        // add checksum
762
                        $clen = strlen($code);
763
                        $p = 2;
764
                        $check = 0;
765
                        for ($i = ($clen - 1); $i >= 0; --$i) {
766
                                $check += (hexdec($code{$i}) * $p);
767
                                ++$p;
768
                                if ($p > 7) {
769
                                        $p = 2;
770
                                }
771
                        }
772
                        $check %= 11;
773
                        if ($check > 0) {
774
                                $check = 11 - $check;
775
                        }
776
                        $code .= $check;
777
                }
778
                $seq = '110'; // left guard
779
                $clen = strlen($code);
780
                for ($i = 0; $i < $clen; ++$i) {
781
                        $digit = $code{$i};
782
                        if (!isset($chr[$digit])) {
783
                                // invalid character
784
                                return false;
785
                        }
786
                        $seq .= $chr[$digit];
787
                }
788
                $seq .= '1001'; // right guard
789
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
790
                return $this->binseq_to_array($seq, $bararray);
791
        }
792

    
793
        /**
794
         * Standard 2 of 5 barcodes.
795
         * Used in airline ticket marking, photofinishing
796
         * Contains digits (0 to 9) and encodes the data only in the width of bars.
797
         * @param $code (string) code to represent.
798
         * @param $checksum (boolean) if true add a checksum to the code
799
         * @return array barcode representation.
800
         * @protected
801
         */
802
        protected function barcode_s25($code, $checksum=false) {
803
                $chr['0'] = '10101110111010';
804
                $chr['1'] = '11101010101110';
805
                $chr['2'] = '10111010101110';
806
                $chr['3'] = '11101110101010';
807
                $chr['4'] = '10101110101110';
808
                $chr['5'] = '11101011101010';
809
                $chr['6'] = '10111011101010';
810
                $chr['7'] = '10101011101110';
811
                $chr['8'] = '10101110111010';
812
                $chr['9'] = '10111010111010';
813
                if ($checksum) {
814
                        // add checksum
815
                        $code .= $this->checksum_s25($code);
816
                }
817
                if((strlen($code) % 2) != 0) {
818
                        // add leading zero if code-length is odd
819
                        $code = '0'.$code;
820
                }
821
                $seq = '11011010';
822
                $clen = strlen($code);
823
                for ($i = 0; $i < $clen; ++$i) {
824
                        $digit = $code{$i};
825
                        if (!isset($chr[$digit])) {
826
                                // invalid character
827
                                return false;
828
                        }
829
                        $seq .= $chr[$digit];
830
                }
831
                $seq .= '1101011';
832
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
833
                return $this->binseq_to_array($seq, $bararray);
834
        }
835

    
836
        /**
837
         * Convert binary barcode sequence to TCPDF barcode array.
838
         * @param $seq (string) barcode as binary sequence.
839
         * @param $bararray (array) barcode array.
840
         * òparam array $bararray TCPDF barcode array to fill up
841
         * @return array barcode representation.
842
         * @protected
843
         */
844
        protected function binseq_to_array($seq, $bararray) {
845
                $len = strlen($seq);
846
                $w = 0;
847
                $k = 0;
848
                for ($i = 0; $i < $len; ++$i) {
849
                        $w += 1;
850
                        if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
851
                                if ($seq{$i} == '1') {
852
                                        $t = true; // bar
853
                                } else {
854
                                        $t = false; // space
855
                                }
856
                                $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
857
                                $bararray['maxw'] += $w;
858
                                ++$k;
859
                                $w = 0;
860
                        }
861
                }
862
                return $bararray;
863
        }
864

    
865
        /**
866
         * Interleaved 2 of 5 barcodes.
867
         * Compact numeric code, widely used in industry, air cargo
868
         * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
869
         * @param $code (string) code to represent.
870
         * @param $checksum (boolean) if true add a checksum to the code
871
         * @return array barcode representation.
872
         * @protected
873
         */
874
        protected function barcode_i25($code, $checksum=false) {
875
                $chr['0'] = '11221';
876
                $chr['1'] = '21112';
877
                $chr['2'] = '12112';
878
                $chr['3'] = '22111';
879
                $chr['4'] = '11212';
880
                $chr['5'] = '21211';
881
                $chr['6'] = '12211';
882
                $chr['7'] = '11122';
883
                $chr['8'] = '21121';
884
                $chr['9'] = '12121';
885
                $chr['A'] = '11';
886
                $chr['Z'] = '21';
887
                if ($checksum) {
888
                        // add checksum
889
                        $code .= $this->checksum_s25($code);
890
                }
891
                if((strlen($code) % 2) != 0) {
892
                        // add leading zero if code-length is odd
893
                        $code = '0'.$code;
894
                }
895
                // add start and stop codes
896
                $code = 'AA'.strtolower($code).'ZA';
897

    
898
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
899
                $k = 0;
900
                $clen = strlen($code);
901
                for ($i = 0; $i < $clen; $i = ($i + 2)) {
902
                        $char_bar = $code{$i};
903
                        $char_space = $code{$i+1};
904
                        if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
905
                                // invalid character
906
                                return false;
907
                        }
908
                        // create a bar-space sequence
909
                        $seq = '';
910
                        $chrlen = strlen($chr[$char_bar]);
911
                        for ($s = 0; $s < $chrlen; $s++){
912
                                $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
913
                        }
914
                        $seqlen = strlen($seq);
915
                        for ($j = 0; $j < $seqlen; ++$j) {
916
                                if (($j % 2) == 0) {
917
                                        $t = true; // bar
918
                                } else {
919
                                        $t = false; // space
920
                                }
921
                                $w = $seq{$j};
922
                                $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
923
                                $bararray['maxw'] += $w;
924
                                ++$k;
925
                        }
926
                }
927
                return $bararray;
928
        }
929

    
930
        /**
931
         * C128 barcodes.
932
         * Very capable code, excellent density, high reliability; in very wide use world-wide
933
         * @param $code (string) code to represent.
934
         * @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
935
         * @return array barcode representation.
936
         * @protected
937
         */
938
        protected function barcode_c128($code, $type='') {
939
                $chr = array(
940
                        '212222', /* 00 */
941
                        '222122', /* 01 */
942
                        '222221', /* 02 */
943
                        '121223', /* 03 */
944
                        '121322', /* 04 */
945
                        '131222', /* 05 */
946
                        '122213', /* 06 */
947
                        '122312', /* 07 */
948
                        '132212', /* 08 */
949
                        '221213', /* 09 */
950
                        '221312', /* 10 */
951
                        '231212', /* 11 */
952
                        '112232', /* 12 */
953
                        '122132', /* 13 */
954
                        '122231', /* 14 */
955
                        '113222', /* 15 */
956
                        '123122', /* 16 */
957
                        '123221', /* 17 */
958
                        '223211', /* 18 */
959
                        '221132', /* 19 */
960
                        '221231', /* 20 */
961
                        '213212', /* 21 */
962
                        '223112', /* 22 */
963
                        '312131', /* 23 */
964
                        '311222', /* 24 */
965
                        '321122', /* 25 */
966
                        '321221', /* 26 */
967
                        '312212', /* 27 */
968
                        '322112', /* 28 */
969
                        '322211', /* 29 */
970
                        '212123', /* 30 */
971
                        '212321', /* 31 */
972
                        '232121', /* 32 */
973
                        '111323', /* 33 */
974
                        '131123', /* 34 */
975
                        '131321', /* 35 */
976
                        '112313', /* 36 */
977
                        '132113', /* 37 */
978
                        '132311', /* 38 */
979
                        '211313', /* 39 */
980
                        '231113', /* 40 */
981
                        '231311', /* 41 */
982
                        '112133', /* 42 */
983
                        '112331', /* 43 */
984
                        '132131', /* 44 */
985
                        '113123', /* 45 */
986
                        '113321', /* 46 */
987
                        '133121', /* 47 */
988
                        '313121', /* 48 */
989
                        '211331', /* 49 */
990
                        '231131', /* 50 */
991
                        '213113', /* 51 */
992
                        '213311', /* 52 */
993
                        '213131', /* 53 */
994
                        '311123', /* 54 */
995
                        '311321', /* 55 */
996
                        '331121', /* 56 */
997
                        '312113', /* 57 */
998
                        '312311', /* 58 */
999
                        '332111', /* 59 */
1000
                        '314111', /* 60 */
1001
                        '221411', /* 61 */
1002
                        '431111', /* 62 */
1003
                        '111224', /* 63 */
1004
                        '111422', /* 64 */
1005
                        '121124', /* 65 */
1006
                        '121421', /* 66 */
1007
                        '141122', /* 67 */
1008
                        '141221', /* 68 */
1009
                        '112214', /* 69 */
1010
                        '112412', /* 70 */
1011
                        '122114', /* 71 */
1012
                        '122411', /* 72 */
1013
                        '142112', /* 73 */
1014
                        '142211', /* 74 */
1015
                        '241211', /* 75 */
1016
                        '221114', /* 76 */
1017
                        '413111', /* 77 */
1018
                        '241112', /* 78 */
1019
                        '134111', /* 79 */
1020
                        '111242', /* 80 */
1021
                        '121142', /* 81 */
1022
                        '121241', /* 82 */
1023
                        '114212', /* 83 */
1024
                        '124112', /* 84 */
1025
                        '124211', /* 85 */
1026
                        '411212', /* 86 */
1027
                        '421112', /* 87 */
1028
                        '421211', /* 88 */
1029
                        '212141', /* 89 */
1030
                        '214121', /* 90 */
1031
                        '412121', /* 91 */
1032
                        '111143', /* 92 */
1033
                        '111341', /* 93 */
1034
                        '131141', /* 94 */
1035
                        '114113', /* 95 */
1036
                        '114311', /* 96 */
1037
                        '411113', /* 97 */
1038
                        '411311', /* 98 */
1039
                        '113141', /* 99 */
1040
                        '114131', /* 100 */
1041
                        '311141', /* 101 */
1042
                        '411131', /* 102 */
1043
                        '211412', /* 103 START A */
1044
                        '211214', /* 104 START B */
1045
                        '211232', /* 105 START C */
1046
                        '233111', /* STOP */
1047
                        '200000'  /* END */
1048
                );
1049
                // ASCII characters for code A (ASCII 00 - 95)
1050
                $keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
1051
                $keys_a .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9);
1052
                $keys_a .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19);
1053
                $keys_a .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29);
1054
                $keys_a .= chr(30).chr(31);
1055
                // ASCII characters for code B (ASCII 32 - 127)
1056
                $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
1057
                // special codes
1058
                $fnc_a = array(241 => 102, 242 => 97, 243 => 96, 244 => 101);
1059
                $fnc_b = array(241 => 102, 242 => 97, 243 => 96, 244 => 100);
1060
                // array of symbols
1061
                $code_data = array();
1062
                // lenght of the code
1063
                $len = strlen($code);
1064
                switch(strtoupper($type)) {
1065
                        case 'A': { // MODE A
1066
                                $startid = 103;
1067
                                for ($i = 0; $i < $len; ++$i) {
1068
                                        $char = $code{$i};
1069
                                        $char_id = ord($char);
1070
                                        if (($char_id >= 241) AND ($char_id <= 244)) {
1071
                                                $code_data[] = $fnc_a[$char_id];
1072
                                        } elseif (($char_id >= 0) AND ($char_id <= 95)) {
1073
                                                $code_data[] = strpos($keys_a, $char);
1074
                                        } else {
1075
                                                return false;
1076
                                        }
1077
                                }
1078
                                break;
1079
                        }
1080
                        case 'B': { // MODE B
1081
                                $startid = 104;
1082
                                for ($i = 0; $i < $len; ++$i) {
1083
                                        $char = $code{$i};
1084
                                        $char_id = ord($char);
1085
                                        if (($char_id >= 241) AND ($char_id <= 244)) {
1086
                                                $code_data[] = $fnc_b[$char_id];
1087
                                        } elseif (($char_id >= 32) AND ($char_id <= 127)) {
1088
                                                $code_data[] = strpos($keys_b, $char);
1089
                                        } else {
1090
                                                return false;
1091
                                        }
1092
                                }
1093
                                break;
1094
                        }
1095
                        case 'C': { // MODE C
1096
                                $startid = 105;
1097
                                if (ord($code{0}) == 241) {
1098
                                        $code_data[] = 102;
1099
                                        $code = substr($code, 1);
1100
                                        --$len;
1101
                                }
1102
                                if (($len % 2) != 0) {
1103
                                        // the length must be even
1104
                                        return false;
1105
                                }
1106
                                for ($i = 0; $i < $len; $i+=2) {
1107
                                        $chrnum = $code{$i}.$code{$i+1};
1108
                                        if (preg_match('/([0-9]{2})/', $chrnum) > 0) {
1109
                                                $code_data[] = intval($chrnum);
1110
                                        } else {
1111
                                                return false;
1112
                                        }
1113
                                }
1114
                                break;
1115
                        }
1116
                        default: { // MODE AUTO
1117
                                // split code into sequences
1118
                                $sequence = array();
1119
                                // get numeric sequences (if any)
1120
                                $numseq = array();
1121
                                preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE);
1122
                                if (isset($numseq[1]) AND !empty($numseq[1])) {
1123
                                        $end_offset = 0;
1124
                                        foreach ($numseq[1] as $val) {
1125
                                                $offset = $val[1];
1126
                                                if ($offset > $end_offset) {
1127
                                                        // non numeric sequence
1128
                                                        $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset))));
1129
                                                }
1130
                                                // numeric sequence
1131
                                                $slen = strlen($val[0]);
1132
                                                if (($slen % 2) != 0) {
1133
                                                        // the length must be even
1134
                                                        --$slen;
1135
                                                }
1136
                                                $sequence[] = array('C', substr($code, $offset, $slen), $slen);
1137
                                                $end_offset = $offset + $slen;
1138
                                        }
1139
                                        if ($end_offset < $len) {
1140
                                                $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset)));
1141
                                        }
1142
                                } else {
1143
                                        // text code (non C mode)
1144
                                        $sequence = array_merge($sequence, $this->get128ABsequence($code));
1145
                                }
1146
                                // process the sequence
1147
                                foreach ($sequence as $key => $seq) {
1148
                                        switch($seq[0]) {
1149
                                                case 'A': {
1150
                                                        if ($key == 0) {
1151
                                                                $startid = 103;
1152
                                                        } elseif ($sequence[($key - 1)][0] != 'A') {
1153
                                                                if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'B') AND (!isset($sequence[($key - 1)][3]))) {
1154
                                                                        // single character shift
1155
                                                                        $code_data[] = 98;
1156
                                                                        // mark shift
1157
                                                                        $sequence[$key][3] = true;
1158
                                                                } elseif (!isset($sequence[($key - 1)][3])) {
1159
                                                                        $code_data[] = 101;
1160
                                                                }
1161
                                                        }
1162
                                                        for ($i = 0; $i < $seq[2]; ++$i) {
1163
                                                                $char = $seq[1]{$i};
1164
                                                                $char_id = ord($char);
1165
                                                                if (($char_id >= 241) AND ($char_id <= 244)) {
1166
                                                                        $code_data[] = $fnc_a[$char_id];
1167
                                                                } else {
1168
                                                                        $code_data[] = strpos($keys_a, $char);
1169
                                                                }
1170
                                                        }
1171
                                                        break;
1172
                                                }
1173
                                                case 'B': {
1174
                                                        if ($key == 0) {
1175
                                                                $tmpchr = ord($seq[1]{0});
1176
                                                                if (($seq[2] == 1) AND ($tmpchr >= 241) AND ($tmpchr <= 244) AND isset($sequence[($key + 1)]) AND ($sequence[($key + 1)][0] != 'B')) {
1177
                                                                        switch ($sequence[($key + 1)][0]) {
1178
                                                                                case 'A': {
1179
                                                                                        $startid = 103;
1180
                                                                                        $sequence[$key][0] = 'A';
1181
                                                                                        $code_data[] = $fnc_a[$tmpchr];
1182
                                                                                        break;
1183
                                                                                }
1184
                                                                                case 'C': {
1185
                                                                                        $startid = 105;
1186
                                                                                        $sequence[$key][0] = 'C';
1187
                                                                                        $code_data[] = $fnc_a[$tmpchr];
1188
                                                                                        break;
1189
                                                                                }
1190
                                                                        }
1191
                                                                        break;
1192
                                                                } else {
1193
                                                                        $startid = 104;
1194
                                                                }
1195
                                                        } elseif ($sequence[($key - 1)][0] != 'B') {
1196
                                                                if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'A') AND (!isset($sequence[($key - 1)][3]))) {
1197
                                                                        // single character shift
1198
                                                                        $code_data[] = 98;
1199
                                                                        // mark shift
1200
                                                                        $sequence[$key][3] = true;
1201
                                                                } elseif (!isset($sequence[($key - 1)][3])) {
1202
                                                                        $code_data[] = 100;
1203
                                                                }
1204
                                                        }
1205
                                                        for ($i = 0; $i < $seq[2]; ++$i) {
1206
                                                                $char = $seq[1]{$i};
1207
                                                                $char_id = ord($char);
1208
                                                                if (($char_id >= 241) AND ($char_id <= 244)) {
1209
                                                                        $code_data[] = $fnc_b[$char_id];
1210
                                                                } else {
1211
                                                                        $code_data[] = strpos($keys_b, $char);
1212
                                                                }
1213
                                                        }
1214
                                                        break;
1215
                                                }
1216
                                                case 'C': {
1217
                                                        if ($key == 0) {
1218
                                                                $startid = 105;
1219
                                                        } elseif ($sequence[($key - 1)][0] != 'C') {
1220
                                                                $code_data[] = 99;
1221
                                                        }
1222
                                                        for ($i = 0; $i < $seq[2]; $i+=2) {
1223
                                                                $chrnum = $seq[1]{$i}.$seq[1]{$i+1};
1224
                                                                $code_data[] = intval($chrnum);
1225
                                                        }
1226
                                                        break;
1227
                                                }
1228
                                        }
1229
                                }
1230
                        }
1231
                }
1232
                // calculate check character
1233
                $sum = $startid;
1234
                foreach ($code_data as $key => $val) {
1235
                        $sum += ($val * ($key + 1));
1236
                }
1237
                // add check character
1238
                $code_data[] = ($sum % 103);
1239
                // add stop sequence
1240
                $code_data[] = 106;
1241
                $code_data[] = 107;
1242
                // add start code at the beginning
1243
                array_unshift($code_data, $startid);
1244
                // build barcode array
1245
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1246
                foreach ($code_data as $val) {
1247
                        $seq = $chr[$val];
1248
                        for ($j = 0; $j < 6; ++$j) {
1249
                                if (($j % 2) == 0) {
1250
                                        $t = true; // bar
1251
                                } else {
1252
                                        $t = false; // space
1253
                                }
1254
                                $w = $seq{$j};
1255
                                $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1256
                                $bararray['maxw'] += $w;
1257
                        }
1258
                }
1259
                return $bararray;
1260
        }
1261

    
1262
        /**
1263
         * Split text code in A/B sequence for 128 code
1264
         * @param $code (string) code to split.
1265
         * @return array sequence
1266
         * @protected
1267
         */
1268
        protected function get128ABsequence($code) {
1269
                $len = strlen($code);
1270
                $sequence = array();
1271
                // get A sequences (if any)
1272
                $numseq = array();
1273
                preg_match_all('/([\0-\31])/', $code, $numseq, PREG_OFFSET_CAPTURE);
1274
                if (isset($numseq[1]) AND !empty($numseq[1])) {
1275
                        $end_offset = 0;
1276
                        foreach ($numseq[1] as $val) {
1277
                                $offset = $val[1];
1278
                                if ($offset > $end_offset) {
1279
                                        // B sequence
1280
                                        $sequence[] = array('B', substr($code, $end_offset, ($offset - $end_offset)), ($offset - $end_offset));
1281
                                }
1282
                                // A sequence
1283
                                $slen = strlen($val[0]);
1284
                                $sequence[] = array('A', substr($code, $offset, $slen), $slen);
1285
                                $end_offset = $offset + $slen;
1286
                        }
1287
                        if ($end_offset < $len) {
1288
                                $sequence[] = array('B', substr($code, $end_offset), ($len - $end_offset));
1289
                        }
1290
                } else {
1291
                        // only B sequence
1292
                        $sequence[] = array('B', $code, $len);
1293
                }
1294
                return $sequence;
1295
        }
1296

    
1297
        /**
1298
         * EAN13 and UPC-A barcodes.
1299
         * EAN13: European Article Numbering international retail product code
1300
         * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
1301
         * UPC-E: Short version of UPC symbol
1302
         * @param $code (string) code to represent.
1303
         * @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
1304
         * @return array barcode representation.
1305
         * @protected
1306
         */
1307
        protected function barcode_eanupc($code, $len=13) {
1308
                $upce = false;
1309
                if ($len == 6) {
1310
                        $len = 12; // UPC-A
1311
                        $upce = true; // UPC-E mode
1312
                }
1313
                $data_len = $len - 1;
1314
                //Padding
1315
                $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
1316
                $code_len = strlen($code);
1317
                // calculate check digit
1318
                $sum_a = 0;
1319
                for ($i = 1; $i < $data_len; $i+=2) {
1320
                        $sum_a += $code{$i};
1321
                }
1322
                if ($len > 12) {
1323
                        $sum_a *= 3;
1324
                }
1325
                $sum_b = 0;
1326
                for ($i = 0; $i < $data_len; $i+=2) {
1327
                        $sum_b += ($code{$i});
1328
                }
1329
                if ($len < 13) {
1330
                        $sum_b *= 3;
1331
                }
1332
                $r = ($sum_a + $sum_b) % 10;
1333
                if($r > 0) {
1334
                        $r = (10 - $r);
1335
                }
1336
                if ($code_len == $data_len) {
1337
                        // add check digit
1338
                        $code .= $r;
1339
                } elseif ($r !== intval($code{$data_len})) {
1340
                        // wrong checkdigit
1341
                        return false;
1342
                }
1343
                if ($len == 12) {
1344
                        // UPC-A
1345
                        $code = '0'.$code;
1346
                        ++$len;
1347
                }
1348
                if ($upce) {
1349
                        // convert UPC-A to UPC-E
1350
                        $tmp = substr($code, 4, 3);
1351
                        if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
1352
                                // manufacturer code ends in 000, 100, or 200
1353
                                $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
1354
                        } else {
1355
                                $tmp = substr($code, 5, 2);
1356
                                if ($tmp == '00') {
1357
                                        // manufacturer code ends in 00
1358
                                        $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
1359
                                } else {
1360
                                        $tmp = substr($code, 6, 1);
1361
                                        if ($tmp == '0') {
1362
                                                // manufacturer code ends in 0
1363
                                                $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
1364
                                        } else {
1365
                                                // manufacturer code does not end in zero
1366
                                                $upce_code = substr($code, 2, 5).substr($code, 11, 1);
1367
                                        }
1368
                                }
1369
                        }
1370
                }
1371
                //Convert digits to bars
1372
                $codes = array(
1373
                        'A'=>array( // left odd parity
1374
                                '0'=>'0001101',
1375
                                '1'=>'0011001',
1376
                                '2'=>'0010011',
1377
                                '3'=>'0111101',
1378
                                '4'=>'0100011',
1379
                                '5'=>'0110001',
1380
                                '6'=>'0101111',
1381
                                '7'=>'0111011',
1382
                                '8'=>'0110111',
1383
                                '9'=>'0001011'),
1384
                        'B'=>array( // left even parity
1385
                                '0'=>'0100111',
1386
                                '1'=>'0110011',
1387
                                '2'=>'0011011',
1388
                                '3'=>'0100001',
1389
                                '4'=>'0011101',
1390
                                '5'=>'0111001',
1391
                                '6'=>'0000101',
1392
                                '7'=>'0010001',
1393
                                '8'=>'0001001',
1394
                                '9'=>'0010111'),
1395
                        'C'=>array( // right
1396
                                '0'=>'1110010',
1397
                                '1'=>'1100110',
1398
                                '2'=>'1101100',
1399
                                '3'=>'1000010',
1400
                                '4'=>'1011100',
1401
                                '5'=>'1001110',
1402
                                '6'=>'1010000',
1403
                                '7'=>'1000100',
1404
                                '8'=>'1001000',
1405
                                '9'=>'1110100')
1406
                );
1407
                $parities = array(
1408
                        '0'=>array('A','A','A','A','A','A'),
1409
                        '1'=>array('A','A','B','A','B','B'),
1410
                        '2'=>array('A','A','B','B','A','B'),
1411
                        '3'=>array('A','A','B','B','B','A'),
1412
                        '4'=>array('A','B','A','A','B','B'),
1413
                        '5'=>array('A','B','B','A','A','B'),
1414
                        '6'=>array('A','B','B','B','A','A'),
1415
                        '7'=>array('A','B','A','B','A','B'),
1416
                        '8'=>array('A','B','A','B','B','A'),
1417
                        '9'=>array('A','B','B','A','B','A')
1418
                );
1419
                $upce_parities = array();
1420
                $upce_parities[0] = array(
1421
                        '0'=>array('B','B','B','A','A','A'),
1422
                        '1'=>array('B','B','A','B','A','A'),
1423
                        '2'=>array('B','B','A','A','B','A'),
1424
                        '3'=>array('B','B','A','A','A','B'),
1425
                        '4'=>array('B','A','B','B','A','A'),
1426
                        '5'=>array('B','A','A','B','B','A'),
1427
                        '6'=>array('B','A','A','A','B','B'),
1428
                        '7'=>array('B','A','B','A','B','A'),
1429
                        '8'=>array('B','A','B','A','A','B'),
1430
                        '9'=>array('B','A','A','B','A','B')
1431
                );
1432
                $upce_parities[1] = array(
1433
                        '0'=>array('A','A','A','B','B','B'),
1434
                        '1'=>array('A','A','B','A','B','B'),
1435
                        '2'=>array('A','A','B','B','A','B'),
1436
                        '3'=>array('A','A','B','B','B','A'),
1437
                        '4'=>array('A','B','A','A','B','B'),
1438
                        '5'=>array('A','B','B','A','A','B'),
1439
                        '6'=>array('A','B','B','B','A','A'),
1440
                        '7'=>array('A','B','A','B','A','B'),
1441
                        '8'=>array('A','B','A','B','B','A'),
1442
                        '9'=>array('A','B','B','A','B','A')
1443
                );
1444
                $k = 0;
1445
                $seq = '101'; // left guard bar
1446
                if ($upce) {
1447
                        $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1448
                        $p = $upce_parities[$code{1}][$r];
1449
                        for ($i = 0; $i < 6; ++$i) {
1450
                                $seq .= $codes[$p[$i]][$upce_code{$i}];
1451
                        }
1452
                        $seq .= '010101'; // right guard bar
1453
                } else {
1454
                        $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1455
                        $half_len = intval(ceil($len / 2));
1456
                        if ($len == 8) {
1457
                                for ($i = 0; $i < $half_len; ++$i) {
1458
                                        $seq .= $codes['A'][$code{$i}];
1459
                                }
1460
                        } else {
1461
                                $p = $parities[$code{0}];
1462
                                for ($i = 1; $i < $half_len; ++$i) {
1463
                                        $seq .= $codes[$p[$i-1]][$code{$i}];
1464
                                }
1465
                        }
1466
                        $seq .= '01010'; // center guard bar
1467
                        for ($i = $half_len; $i < $len; ++$i) {
1468
                                $seq .= $codes['C'][$code{$i}];
1469
                        }
1470
                        $seq .= '101'; // right guard bar
1471
                }
1472
                $clen = strlen($seq);
1473
                $w = 0;
1474
                for ($i = 0; $i < $clen; ++$i) {
1475
                        $w += 1;
1476
                        if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
1477
                                if ($seq{$i} == '1') {
1478
                                        $t = true; // bar
1479
                                } else {
1480
                                        $t = false; // space
1481
                                }
1482
                                $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1483
                                $bararray['maxw'] += $w;
1484
                                ++$k;
1485
                                $w = 0;
1486
                        }
1487
                }
1488
                return $bararray;
1489
        }
1490

    
1491
        /**
1492
         * UPC-Based Extentions
1493
         * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
1494
         * 5-Digit Ext.: Used to mark suggested retail price of books
1495
         * @param $code (string) code to represent.
1496
         * @param $len (string) barcode type: 2 = 2-Digit, 5 = 5-Digit
1497
         * @return array barcode representation.
1498
         * @protected
1499
         */
1500
        protected function barcode_eanext($code, $len=5) {
1501
                //Padding
1502
                $code = str_pad($code, $len, '0', STR_PAD_LEFT);
1503
                // calculate check digit
1504
                if ($len == 2) {
1505
                        $r = $code % 4;
1506
                } elseif ($len == 5) {
1507
                        $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3}));
1508
                        $r %= 10;
1509
                } else {
1510
                        return false;
1511
                }
1512
                //Convert digits to bars
1513
                $codes = array(
1514
                        'A'=>array( // left odd parity
1515
                                '0'=>'0001101',
1516
                                '1'=>'0011001',
1517
                                '2'=>'0010011',
1518
                                '3'=>'0111101',
1519
                                '4'=>'0100011',
1520
                                '5'=>'0110001',
1521
                                '6'=>'0101111',
1522
                                '7'=>'0111011',
1523
                                '8'=>'0110111',
1524
                                '9'=>'0001011'),
1525
                        'B'=>array( // left even parity
1526
                                '0'=>'0100111',
1527
                                '1'=>'0110011',
1528
                                '2'=>'0011011',
1529
                                '3'=>'0100001',
1530
                                '4'=>'0011101',
1531
                                '5'=>'0111001',
1532
                                '6'=>'0000101',
1533
                                '7'=>'0010001',
1534
                                '8'=>'0001001',
1535
                                '9'=>'0010111')
1536
                );
1537
                $parities = array();
1538
                $parities[2] = array(
1539
                        '0'=>array('A','A'),
1540
                        '1'=>array('A','B'),
1541
                        '2'=>array('B','A'),
1542
                        '3'=>array('B','B')
1543
                );
1544
                $parities[5] = array(
1545
                        '0'=>array('B','B','A','A','A'),
1546
                        '1'=>array('B','A','B','A','A'),
1547
                        '2'=>array('B','A','A','B','A'),
1548
                        '3'=>array('B','A','A','A','B'),
1549
                        '4'=>array('A','B','B','A','A'),
1550
                        '5'=>array('A','A','B','B','A'),
1551
                        '6'=>array('A','A','A','B','B'),
1552
                        '7'=>array('A','B','A','B','A'),
1553
                        '8'=>array('A','B','A','A','B'),
1554
                        '9'=>array('A','A','B','A','B')
1555
                );
1556
                $p = $parities[$len][$r];
1557
                $seq = '1011'; // left guard bar
1558
                $seq .= $codes[$p[0]][$code{0}];
1559
                for ($i = 1; $i < $len; ++$i) {
1560
                        $seq .= '01'; // separator
1561
                        $seq .= $codes[$p[$i]][$code{$i}];
1562
                }
1563
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1564
                return $this->binseq_to_array($seq, $bararray);
1565
        }
1566

    
1567
        /**
1568
         * POSTNET and PLANET barcodes.
1569
         * Used by U.S. Postal Service for automated mail sorting
1570
         * @param $code (string) zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
1571
         * @param $planet (boolean) if true print the PLANET barcode, otherwise print POSTNET
1572
         * @return array barcode representation.
1573
         * @protected
1574
         */
1575
        protected function barcode_postnet($code, $planet=false) {
1576
                // bar lenght
1577
                if ($planet) {
1578
                        $barlen = Array(
1579
                                0 => Array(1,1,2,2,2),
1580
                                1 => Array(2,2,2,1,1),
1581
                                2 => Array(2,2,1,2,1),
1582
                                3 => Array(2,2,1,1,2),
1583
                                4 => Array(2,1,2,2,1),
1584
                                5 => Array(2,1,2,1,2),
1585
                                6 => Array(2,1,1,2,2),
1586
                                7 => Array(1,2,2,2,1),
1587
                                8 => Array(1,2,2,1,2),
1588
                                9 => Array(1,2,1,2,2)
1589
                        );
1590
                } else {
1591
                        $barlen = Array(
1592
                                0 => Array(2,2,1,1,1),
1593
                                1 => Array(1,1,1,2,2),
1594
                                2 => Array(1,1,2,1,2),
1595
                                3 => Array(1,1,2,2,1),
1596
                                4 => Array(1,2,1,1,2),
1597
                                5 => Array(1,2,1,2,1),
1598
                                6 => Array(1,2,2,1,1),
1599
                                7 => Array(2,1,1,1,2),
1600
                                8 => Array(2,1,1,2,1),
1601
                                9 => Array(2,1,2,1,1)
1602
                        );
1603
                }
1604
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1605
                $k = 0;
1606
                $code = str_replace('-', '', $code);
1607
                $code = str_replace(' ', '', $code);
1608
                $len = strlen($code);
1609
                // calculate checksum
1610
                $sum = 0;
1611
                for ($i = 0; $i < $len; ++$i) {
1612
                        $sum += intval($code{$i});
1613
                }
1614
                $chkd = ($sum % 10);
1615
                if($chkd > 0) {
1616
                        $chkd = (10 - $chkd);
1617
                }
1618
                $code .= $chkd;
1619
                $len = strlen($code);
1620
                // start bar
1621
                $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1622
                $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1623
                $bararray['maxw'] += 2;
1624
                for ($i = 0; $i < $len; ++$i) {
1625
                        for ($j = 0; $j < 5; ++$j) {
1626
                                $h = $barlen[$code{$i}][$j];
1627
                                $p = floor(1 / $h);
1628
                                $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1629
                                $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1630
                                $bararray['maxw'] += 2;
1631
                        }
1632
                }
1633
                // end bar
1634
                $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1635
                $bararray['maxw'] += 1;
1636
                return $bararray;
1637
        }
1638

    
1639
        /**
1640
         * RMS4CC - CBC - KIX
1641
         * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
1642
         * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
1643
         * @param $code (string) code to print
1644
         * @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.
1645
         * @return array barcode representation.
1646
         * @protected
1647
         */
1648
        protected function barcode_rms4cc($code, $kix=false) {
1649
                $notkix = !$kix;
1650
                // bar mode
1651
                // 1 = pos 1, length 2
1652
                // 2 = pos 1, length 3
1653
                // 3 = pos 2, length 1
1654
                // 4 = pos 2, length 2
1655
                $barmode = array(
1656
                        '0' => array(3,3,2,2),
1657
                        '1' => array(3,4,1,2),
1658
                        '2' => array(3,4,2,1),
1659
                        '3' => array(4,3,1,2),
1660
                        '4' => array(4,3,2,1),
1661
                        '5' => array(4,4,1,1),
1662
                        '6' => array(3,1,4,2),
1663
                        '7' => array(3,2,3,2),
1664
                        '8' => array(3,2,4,1),
1665
                        '9' => array(4,1,3,2),
1666
                        'A' => array(4,1,4,1),
1667
                        'B' => array(4,2,3,1),
1668
                        'C' => array(3,1,2,4),
1669
                        'D' => array(3,2,1,4),
1670
                        'E' => array(3,2,2,3),
1671
                        'F' => array(4,1,1,4),
1672
                        'G' => array(4,1,2,3),
1673
                        'H' => array(4,2,1,3),
1674
                        'I' => array(1,3,4,2),
1675
                        'J' => array(1,4,3,2),
1676
                        'K' => array(1,4,4,1),
1677
                        'L' => array(2,3,3,2),
1678
                        'M' => array(2,3,4,1),
1679
                        'N' => array(2,4,3,1),
1680
                        'O' => array(1,3,2,4),
1681
                        'P' => array(1,4,1,4),
1682
                        'Q' => array(1,4,2,3),
1683
                        'R' => array(2,3,1,4),
1684
                        'S' => array(2,3,2,3),
1685
                        'T' => array(2,4,1,3),
1686
                        'U' => array(1,1,4,4),
1687
                        'V' => array(1,2,3,4),
1688
                        'W' => array(1,2,4,3),
1689
                        'X' => array(2,1,3,4),
1690
                        'Y' => array(2,1,4,3),
1691
                        'Z' => array(2,2,3,3)
1692
                );
1693
                $code = strtoupper($code);
1694
                $len = strlen($code);
1695
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
1696
                if ($notkix) {
1697
                        // table for checksum calculation (row,col)
1698
                        $checktable = array(
1699
                                '0' => array(1,1),
1700
                                '1' => array(1,2),
1701
                                '2' => array(1,3),
1702
                                '3' => array(1,4),
1703
                                '4' => array(1,5),
1704
                                '5' => array(1,0),
1705
                                '6' => array(2,1),
1706
                                '7' => array(2,2),
1707
                                '8' => array(2,3),
1708
                                '9' => array(2,4),
1709
                                'A' => array(2,5),
1710
                                'B' => array(2,0),
1711
                                'C' => array(3,1),
1712
                                'D' => array(3,2),
1713
                                'E' => array(3,3),
1714
                                'F' => array(3,4),
1715
                                'G' => array(3,5),
1716
                                'H' => array(3,0),
1717
                                'I' => array(4,1),
1718
                                'J' => array(4,2),
1719
                                'K' => array(4,3),
1720
                                'L' => array(4,4),
1721
                                'M' => array(4,5),
1722
                                'N' => array(4,0),
1723
                                'O' => array(5,1),
1724
                                'P' => array(5,2),
1725
                                'Q' => array(5,3),
1726
                                'R' => array(5,4),
1727
                                'S' => array(5,5),
1728
                                'T' => array(5,0),
1729
                                'U' => array(0,1),
1730
                                'V' => array(0,2),
1731
                                'W' => array(0,3),
1732
                                'X' => array(0,4),
1733
                                'Y' => array(0,5),
1734
                                'Z' => array(0,0)
1735
                        );
1736
                        $row = 0;
1737
                        $col = 0;
1738
                        for ($i = 0; $i < $len; ++$i) {
1739
                                $row += $checktable[$code{$i}][0];
1740
                                $col += $checktable[$code{$i}][1];
1741
                        }
1742
                        $row %= 6;
1743
                        $col %= 6;
1744
                        $chk = array_keys($checktable, array($row,$col));
1745
                        $code .= $chk[0];
1746
                        ++$len;
1747
                }
1748
                $k = 0;
1749
                if ($notkix) {
1750
                        // start bar
1751
                        $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1752
                        $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1753
                        $bararray['maxw'] += 2;
1754
                }
1755
                for ($i = 0; $i < $len; ++$i) {
1756
                        for ($j = 0; $j < 4; ++$j) {
1757
                                switch ($barmode[$code{$i}][$j]) {
1758
                                        case 1: {
1759
                                                $p = 0;
1760
                                                $h = 2;
1761
                                                break;
1762
                                        }
1763
                                        case 2: {
1764
                                                $p = 0;
1765
                                                $h = 3;
1766
                                                break;
1767
                                        }
1768
                                        case 3: {
1769
                                                $p = 1;
1770
                                                $h = 1;
1771
                                                break;
1772
                                        }
1773
                                        case 4: {
1774
                                                $p = 1;
1775
                                                $h = 2;
1776
                                                break;
1777
                                        }
1778
                                }
1779
                                $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1780
                                $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1781
                                $bararray['maxw'] += 2;
1782
                        }
1783
                }
1784
                if ($notkix) {
1785
                        // stop bar
1786
                        $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0);
1787
                        $bararray['maxw'] += 1;
1788
                }
1789
                return $bararray;
1790
        }
1791

    
1792
        /**
1793
         * CODABAR barcodes.
1794
         * Older code often used in library systems, sometimes in blood banks
1795
         * @param $code (string) code to represent.
1796
         * @return array barcode representation.
1797
         * @protected
1798
         */
1799
        protected function barcode_codabar($code) {
1800
                $chr = array(
1801
                        '0' => '11111221',
1802
                        '1' => '11112211',
1803
                        '2' => '11121121',
1804
                        '3' => '22111111',
1805
                        '4' => '11211211',
1806
                        '5' => '21111211',
1807
                        '6' => '12111121',
1808
                        '7' => '12112111',
1809
                        '8' => '12211111',
1810
                        '9' => '21121111',
1811
                        '-' => '11122111',
1812
                        '$' => '11221111',
1813
                        ':' => '21112121',
1814
                        '/' => '21211121',
1815
                        '.' => '21212111',
1816
                        '+' => '11222221',
1817
                        'A' => '11221211',
1818
                        'B' => '12121121',
1819
                        'C' => '11121221',
1820
                        'D' => '11122211'
1821
                );
1822
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1823
                $k = 0;
1824
                $w = 0;
1825
                $seq = '';
1826
                $code = 'A'.strtoupper($code).'A';
1827
                $len = strlen($code);
1828
                for ($i = 0; $i < $len; ++$i) {
1829
                        if (!isset($chr[$code{$i}])) {
1830
                                return false;
1831
                        }
1832
                        $seq = $chr[$code{$i}];
1833
                        for ($j = 0; $j < 8; ++$j) {
1834
                                if (($j % 2) == 0) {
1835
                                        $t = true; // bar
1836
                                } else {
1837
                                        $t = false; // space
1838
                                }
1839
                                $w = $seq{$j};
1840
                                $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1841
                                $bararray['maxw'] += $w;
1842
                                ++$k;
1843
                        }
1844
                }
1845
                return $bararray;
1846
        }
1847

    
1848
        /**
1849
         * CODE11 barcodes.
1850
         * Used primarily for labeling telecommunications equipment
1851
         * @param $code (string) code to represent.
1852
         * @return array barcode representation.
1853
         * @protected
1854
         */
1855
        protected function barcode_code11($code) {
1856
                $chr = array(
1857
                        '0' => '111121',
1858
                        '1' => '211121',
1859
                        '2' => '121121',
1860
                        '3' => '221111',
1861
                        '4' => '112121',
1862
                        '5' => '212111',
1863
                        '6' => '122111',
1864
                        '7' => '111221',
1865
                        '8' => '211211',
1866
                        '9' => '211111',
1867
                        '-' => '112111',
1868
                        'S' => '112211'
1869
                );
1870
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1871
                $k = 0;
1872
                $w = 0;
1873
                $seq = '';
1874
                $len = strlen($code);
1875
                // calculate check digit C
1876
                $p = 1;
1877
                $check = 0;
1878
                for ($i = ($len - 1); $i >= 0; --$i) {
1879
                        $digit = $code{$i};
1880
                        if ($digit == '-') {
1881
                                $dval = 10;
1882
                        } else {
1883
                                $dval = intval($digit);
1884
                        }
1885
                        $check += ($dval * $p);
1886
                        ++$p;
1887
                        if ($p > 10) {
1888
                                $p = 1;
1889
                        }
1890
                }
1891
                $check %= 11;
1892
                if ($check == 10) {
1893
                        $check = '-';
1894
                }
1895
                $code .= $check;
1896
                if ($len > 10) {
1897
                        // calculate check digit K
1898
                        $p = 1;
1899
                        $check = 0;
1900
                        for ($i = $len; $i >= 0; --$i) {
1901
                                $digit = $code{$i};
1902
                                if ($digit == '-') {
1903
                                        $dval = 10;
1904
                                } else {
1905
                                        $dval = intval($digit);
1906
                                }
1907
                                $check += ($dval * $p);
1908
                                ++$p;
1909
                                if ($p > 9) {
1910
                                        $p = 1;
1911
                                }
1912
                        }
1913
                        $check %= 11;
1914
                        $code .= $check;
1915
                        ++$len;
1916
                }
1917
                $code = 'S'.$code.'S';
1918
                $len += 3;
1919
                for ($i = 0; $i < $len; ++$i) {
1920
                        if (!isset($chr[$code{$i}])) {
1921
                                return false;
1922
                        }
1923
                        $seq = $chr[$code{$i}];
1924
                        for ($j = 0; $j < 6; ++$j) {
1925
                                if (($j % 2) == 0) {
1926
                                        $t = true; // bar
1927
                                } else {
1928
                                        $t = false; // space
1929
                                }
1930
                                $w = $seq{$j};
1931
                                $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1932
                                $bararray['maxw'] += $w;
1933
                                ++$k;
1934
                        }
1935
                }
1936
                return $bararray;
1937
        }
1938

    
1939
        /**
1940
         * Pharmacode
1941
         * Contains digits (0 to 9)
1942
         * @param $code (string) code to represent.
1943
         * @return array barcode representation.
1944
         * @protected
1945
         */
1946
        protected function barcode_pharmacode($code) {
1947
                $seq = '';
1948
                $code = intval($code);
1949
                while ($code > 0) {
1950
                        if (($code % 2) == 0) {
1951
                                $seq .= '11100';
1952
                                $code -= 2;
1953
                        } else {
1954
                                $seq .= '100';
1955
                                $code -= 1;
1956
                        }
1957
                        $code /= 2;
1958
                }
1959
                $seq = substr($seq, 0, -2);
1960
                $seq = strrev($seq);
1961
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1962
                return $this->binseq_to_array($seq, $bararray);
1963
        }
1964

    
1965
        /**
1966
         * Pharmacode two-track
1967
         * Contains digits (0 to 9)
1968
         * @param $code (string) code to represent.
1969
         * @return array barcode representation.
1970
         * @protected
1971
         */
1972
        protected function barcode_pharmacode2t($code) {
1973
                $seq = '';
1974
                $code = intval($code);
1975
                do {
1976
                        switch ($code % 3) {
1977
                                case 0: {
1978
                                        $seq .= '3';
1979
                                        $code = ($code - 3) / 3;
1980
                                        break;
1981
                                }
1982
                                case 1: {
1983
                                        $seq .= '1';
1984
                                        $code = ($code - 1) / 3;
1985
                                        break;
1986
                                }
1987
                                case 2: {
1988
                                        $seq .= '2';
1989
                                        $code = ($code - 2) / 3;
1990
                                        break;
1991
                                }
1992
                        }
1993
                } while($code != 0);
1994
                $seq = strrev($seq);
1995
                $k = 0;
1996
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1997
                $len = strlen($seq);
1998
                for ($i = 0; $i < $len; ++$i) {
1999
                        switch ($seq{$i}) {
2000
                                case '1': {
2001
                                        $p = 1;
2002
                                        $h = 1;
2003
                                        break;
2004
                                }
2005
                                case '2': {
2006
                                        $p = 0;
2007
                                        $h = 1;
2008
                                        break;
2009
                                }
2010
                                case '3': {
2011
                                        $p = 0;
2012
                                        $h = 2;
2013
                                        break;
2014
                                }
2015
                        }
2016
                        $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2017
                        $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2018
                        $bararray['maxw'] += 2;
2019
                }
2020
                unset($bararray['bcode'][($k - 1)]);
2021
                --$bararray['maxw'];
2022
                return $bararray;
2023
        }
2024

    
2025

    
2026
        /**
2027
         * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
2028
         * (requires PHP bcmath extension)
2029
         * Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
2030
         * 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>
2031
         * @param $code (string) code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
2032
         * @return array barcode representation.
2033
         * @protected
2034
         */
2035
        protected function barcode_imb($code) {
2036
                $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);
2037
                $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);
2038
                $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);
2039
                $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);
2040
                $code_arr = explode('-', $code);
2041
                $tracking_number = $code_arr[0];
2042
                if (isset($code_arr[1])) {
2043
                        $routing_code = $code_arr[1];
2044
                } else {
2045
                        $routing_code = '';
2046
                }
2047
                // Conversion of Routing Code
2048
                switch (strlen($routing_code)) {
2049
                        case 0: {
2050
                                $binary_code = 0;
2051
                                break;
2052
                        }
2053
                        case 5: {
2054
                                $binary_code = bcadd($routing_code, '1');
2055
                                break;
2056
                        }
2057
                        case 9: {
2058
                                $binary_code = bcadd($routing_code, '100001');
2059
                                break;
2060
                        }
2061
                        case 11: {
2062
                                $binary_code = bcadd($routing_code, '1000100001');
2063
                                break;
2064
                        }
2065
                        default: {
2066
                                return false;
2067
                                break;
2068
                        }
2069
                }
2070
                $binary_code = bcmul($binary_code, 10);
2071
                $binary_code = bcadd($binary_code, $tracking_number{0});
2072
                $binary_code = bcmul($binary_code, 5);
2073
                $binary_code = bcadd($binary_code, $tracking_number{1});
2074
                $binary_code .= substr($tracking_number, 2, 18);
2075
                // convert to hexadecimal
2076
                $binary_code = $this->dec_to_hex($binary_code);
2077
                // pad to get 13 bytes
2078
                $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
2079
                // convert string to array of bytes
2080
                $binary_code_arr = chunk_split($binary_code, 2, "\r");
2081
                $binary_code_arr = substr($binary_code_arr, 0, -1);
2082
                $binary_code_arr = explode("\r", $binary_code_arr);
2083
                // calculate frame check sequence
2084
                $fcs = $this->imb_crc11fcs($binary_code_arr);
2085
                // exclude first 2 bits from first byte
2086
                $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
2087
                $binary_code_102bit = $first_byte.substr($binary_code, 2);
2088
                // convert binary data to codewords
2089
                $codewords = array();
2090
                $data = $this->hex_to_dec($binary_code_102bit);
2091
                $codewords[0] = bcmod($data, 636) * 2;
2092
                $data = bcdiv($data, 636);
2093
                for ($i = 1; $i < 9; ++$i) {
2094
                        $codewords[$i] = bcmod($data, 1365);
2095
                        $data = bcdiv($data, 1365);
2096
                }
2097
                $codewords[9] = $data;
2098
                if (($fcs >> 10) == 1) {
2099
                        $codewords[9] += 659;
2100
                }
2101
                // generate lookup tables
2102
                $table2of13 = $this->imb_tables(2, 78);
2103
                $table5of13 = $this->imb_tables(5, 1287);
2104
                // convert codewords to characters
2105
                $characters = array();
2106
                $bitmask = 512;
2107
                foreach($codewords as $k => $val) {
2108
                        if ($val <= 1286) {
2109
                                $chrcode = $table5of13[$val];
2110
                        } else {
2111
                                $chrcode = $table2of13[($val - 1287)];
2112
                        }
2113
                        if (($fcs & $bitmask) > 0) {
2114
                                // bitwise invert
2115
                                $chrcode = ((~$chrcode) & 8191);
2116
                        }
2117
                        $characters[] = $chrcode;
2118
                        $bitmask /= 2;
2119
                }
2120
                $characters = array_reverse($characters);
2121
                // build bars
2122
                $k = 0;
2123
                $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
2124
                for ($i = 0; $i < 65; ++$i) {
2125
                        $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0);
2126
                        $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0);
2127
                        if ($asc AND $dsc) {
2128
                                // full bar (F)
2129
                                $p = 0;
2130
                                $h = 3;
2131
                        } elseif ($asc) {
2132
                                // ascender (A)
2133
                                $p = 0;
2134
                                $h = 2;
2135
                        } elseif ($dsc) {
2136
                                // descender (D)
2137
                                $p = 1;
2138
                                $h = 2;
2139
                        } else {
2140
                                // tracker (T)
2141
                                $p = 1;
2142
                                $h = 1;
2143
                        }
2144
                        $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2145
                        $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2146
                        $bararray['maxw'] += 2;
2147
                }
2148
                unset($bararray['bcode'][($k - 1)]);
2149
                --$bararray['maxw'];
2150
                return $bararray;
2151
        }
2152

    
2153
        /**
2154
         * Convert large integer number to hexadecimal representation.
2155
         * (requires PHP bcmath extension)
2156
         * @param $number (string) number to convert specified as a string
2157
         * @return string hexadecimal representation
2158
         */
2159
        public function dec_to_hex($number) {
2160
                $i = 0;
2161
                $hex = array();
2162
                if($number == 0) {
2163
                        return '00';
2164
                }
2165
                while($number > 0) {
2166
                        if($number == 0) {
2167
                                array_push($hex, '0');
2168
                        } else {
2169
                                array_push($hex, strtoupper(dechex(bcmod($number, '16'))));
2170
                                $number = bcdiv($number, '16', 0);
2171
                        }
2172
                }
2173
                $hex = array_reverse($hex);
2174
                return implode($hex);
2175
        }
2176

    
2177
        /**
2178
         * Convert large hexadecimal number to decimal representation (string).
2179
         * (requires PHP bcmath extension)
2180
         * @param $hex (string) hexadecimal number to convert specified as a string
2181
         * @return string hexadecimal representation
2182
         */
2183
        public function hex_to_dec($hex) {
2184
                $dec = 0;
2185
                $bitval = 1;
2186
                $len = strlen($hex);
2187
                for($pos = ($len - 1); $pos >= 0; --$pos) {
2188
                        $dec = bcadd($dec, bcmul(hexdec($hex{$pos}), $bitval));
2189
                        $bitval = bcmul($bitval, 16);
2190
                }
2191
                return $dec;
2192
        }
2193

    
2194
        /**
2195
         * Intelligent Mail Barcode calculation of Frame Check Sequence
2196
         * @param $code_arr (string) array of hexadecimal values (13 bytes holding 102 bits right justified).
2197
         * @return int 11 bit Frame Check Sequence as integer (decimal base)
2198
         * @protected
2199
         */
2200
        protected function imb_crc11fcs($code_arr) {
2201
                $genpoly = 0x0F35; // generator polynomial
2202
                $fcs = 0x07FF; // Frame Check Sequence
2203
                // do most significant byte skipping the 2 most significant bits
2204
                $data = hexdec($code_arr[0]) << 5;
2205
                for ($bit = 2; $bit < 8; ++$bit) {
2206
                        if (($fcs ^ $data) & 0x400) {
2207
                                $fcs = ($fcs << 1) ^ $genpoly;
2208
                        } else {
2209
                                $fcs = ($fcs << 1);
2210
                        }
2211
                        $fcs &= 0x7FF;
2212
                        $data <<= 1;
2213
                }
2214
                // do rest of bytes
2215
                for ($byte = 1; $byte < 13; ++$byte) {
2216
                        $data = hexdec($code_arr[$byte]) << 3;
2217
                        for ($bit = 0; $bit < 8; ++$bit) {
2218
                                if (($fcs ^ $data) & 0x400) {
2219
                                        $fcs = ($fcs << 1) ^ $genpoly;
2220
                                } else {
2221
                                        $fcs = ($fcs << 1);
2222
                                }
2223
                                $fcs &= 0x7FF;
2224
                                $data <<= 1;
2225
                        }
2226
                }
2227
                return $fcs;
2228
        }
2229

    
2230
        /**
2231
         * Reverse unsigned short value
2232
         * @param $num (int) value to reversr
2233
         * @return int reversed value
2234
         * @protected
2235
         */
2236
        protected function imb_reverse_us($num) {
2237
                $rev = 0;
2238
                for ($i = 0; $i < 16; ++$i) {
2239
                        $rev <<= 1;
2240
                        $rev |= ($num & 1);
2241
                        $num >>= 1;
2242
                }
2243
                return $rev;
2244
        }
2245

    
2246
        /**
2247
         * generate Nof13 tables used for Intelligent Mail Barcode
2248
         * @param $n (int) is the type of table: 2 for 2of13 table, 5 for 5of13table
2249
         * @param $size (int) size of table (78 for n=2 and 1287 for n=5)
2250
         * @return array requested table
2251
         * @protected
2252
         */
2253
        protected function imb_tables($n, $size) {
2254
                $table = array();
2255
                $lli = 0; // LUT lower index
2256
                $lui = $size - 1; // LUT upper index
2257
                for ($count = 0; $count < 8192; ++$count) {
2258
                        $bit_count = 0;
2259
                        for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
2260
                                $bit_count += intval(($count & (1 << $bit_index)) != 0);
2261
                        }
2262
                        // if we don't have the right number of bits on, go on to the next value
2263
                        if ($bit_count == $n) {
2264
                                $reverse = ($this->imb_reverse_us($count) >> 3);
2265
                                // if the reverse is less than count, we have already visited this pair before
2266
                                if ($reverse >= $count) {
2267
                                        // If count is symmetric, place it at the first free slot from the end of the list.
2268
                                        // 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
2269
                                        if ($reverse == $count) {
2270
                                                $table[$lui] = $count;
2271
                                                --$lui;
2272
                                        } else {
2273
                                                $table[$lli] = $count;
2274
                                                ++$lli;
2275
                                                $table[$lli] = $reverse;
2276
                                                ++$lli;
2277
                                        }
2278
                                }
2279
                        }
2280
                }
2281
                return $table;
2282
        }
2283

    
2284
} // end of class
2285
//============================================================+
2286
// END OF FILE
2287
//============================================================+