PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.12.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.12.1
5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / vendor / tecnickcom / tcpdf / tcpdf_barcodes_1d.php
matomo / app / vendor / tecnickcom / tcpdf Last commit date
config 3 months ago fonts 2 years ago include 3 months ago LICENSE.TXT 3 months ago Makefile 3 months ago README.md 3 months ago VERSION 3 months ago tcpdf.php 3 months ago tcpdf_autoconfig.php 3 months ago tcpdf_barcodes_1d.php 3 months ago tcpdf_barcodes_2d.php 3 months ago
tcpdf_barcodes_1d.php
2274 lines
1 <?php
2
3 namespace {
4 //============================================================+
5 // File name : tcpdf_barcodes_1d.php
6 // Version : 1.0.027
7 // Begin : 2008-06-09
8 // Last Update : 2014-10-20
9 // Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
10 // License : GNU-LGPL v3 (https://www.gnu.org/copyleft/lesser.html)
11 // -------------------------------------------------------------------
12 // Copyright (C) 2008-2026 Nicola Asuni - Tecnick.com LTD
13 //
14 // This file is part of TCPDF software library.
15 //
16 // TCPDF is free software: you can redistribute it and/or modify it
17 // under the terms of the GNU Lesser General Public License as
18 // published by the Free Software Foundation, either version 3 of the
19 // License, or (at your option) any later version.
20 //
21 // TCPDF is distributed in the hope that it will be useful, but
22 // WITHOUT ANY WARRANTY; without even the implied warranty of
23 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 // See the GNU Lesser General Public License for more details.
25 //
26 // You should have received a copy of the GNU Lesser General Public License
27 // along with TCPDF. If not, see <https://www.gnu.org/licenses/>.
28 //
29 // See LICENSE.TXT file for more information.
30 // -------------------------------------------------------------------
31 //
32 // Description : PHP class to creates array representations for
33 // common 1D barcodes to be used with TCPDF.
34 //
35 //============================================================+
36 /**
37 * @file
38 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF.
39 * @package com.tecnick.tcpdf
40 * @author Nicola Asuni
41 * @version 1.0.027
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.027
48 * @author Nicola Asuni
49 */
50 class TCPDFBarcode
51 {
52 /**
53 * Array representation of barcode.
54 * @protected
55 */
56 protected $barcode_array = array();
57 /**
58 * This is the class constructor.
59 * Return an array representations for common 1D barcodes:<ul>
60 * <li>$arrcode['code'] code to be printed on text label</li>
61 * <li>$arrcode['maxh'] max barcode height</li>
62 * <li>$arrcode['maxw'] max barcode width</li>
63 * <li>$arrcode['bcode'][$k] single bar or space in $k position</li>
64 * <li>$arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.</li>
65 * <li>$arrcode['bcode'][$k]['w'] bar width in units.</li>
66 * <li>$arrcode['bcode'][$k]['h'] bar height in units.</li>
67 * <li>$arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)</li></ul>
68 * @param string $code code to print
69 * @param string $type type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>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 Extension</li><li>EAN5 : 5-Digits UPC-Based Extension</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
70 * @public
71 */
72 public function __construct($code, $type)
73 {
74 $this->setBarcode($code, $type);
75 }
76 /**
77 * Return an array representations of barcode.
78 * @return array
79 * @public
80 */
81 public function getBarcodeArray()
82 {
83 return $this->barcode_array;
84 }
85 /**
86 * Send barcode as SVG image object to the standard output.
87 * @param int $w Minimum width of a single bar in user units.
88 * @param int $h Height of barcode in user units.
89 * @param string $color Foreground color (in SVG format) for bar elements (background is transparent).
90 * @public
91 */
92 public function getBarcodeSVG($w = 2, $h = 30, $color = 'black')
93 {
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');
98 // HTTP/1.1
99 \header('Pragma: public');
100 \header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
101 // Date in the past
102 \header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT');
103 \header('Content-Disposition: inline; filename="' . \md5($code) . '.svg";');
104 //header('Content-Length: '.strlen($code));
105 echo $code;
106 }
107 /**
108 * Return a SVG string representation of barcode.
109 * @param int $w Minimum width of a single bar in user units.
110 * @param int $h Height of barcode in user units.
111 * @param string $color Foreground color (in SVG format) for bar elements (background is transparent).
112 * @return string SVG code.
113 * @public
114 */
115 public function getBarcodeSVGcode($w = 2, $h = 30, $color = 'black')
116 {
117 // replace table for special characters
118 $repstr = array("\x00" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
119 $svg = '<' . '?' . 'xml version="1.0" standalone="no"' . '?' . '>' . "\n";
120 $svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' . "\n";
121 $svg .= '<svg width="' . \round($this->barcode_array['maxw'] * $w, 3) . '" height="' . $h . '" version="1.1" xmlns="http://www.w3.org/2000/svg">' . "\n";
122 $svg .= "\t" . '<desc>' . \strtr($this->barcode_array['code'], $repstr) . '</desc>' . "\n";
123 $svg .= "\t" . '<g id="bars" fill="' . $color . '" stroke="none">' . "\n";
124 // print bars
125 $x = 0;
126 foreach ($this->barcode_array['bcode'] as $k => $v) {
127 $bw = \round($v['w'] * $w, 3);
128 $bh = \round($v['h'] * $h / $this->barcode_array['maxh'], 3);
129 if ($v['t']) {
130 $y = \round($v['p'] * $h / $this->barcode_array['maxh'], 3);
131 // draw a vertical bar
132 $svg .= "\t\t" . '<rect x="' . $x . '" y="' . $y . '" width="' . $bw . '" height="' . $bh . '" />' . "\n";
133 }
134 $x += $bw;
135 }
136 $svg .= "\t" . '</g>' . "\n";
137 $svg .= '</svg>' . "\n";
138 return $svg;
139 }
140 /**
141 * Return an HTML representation of barcode.
142 * @param int $w Width of a single bar element in pixels.
143 * @param int $h Height of a single bar element in pixels.
144 * @param string $color Foreground color for bar elements (background is transparent).
145 * @return string HTML code.
146 * @public
147 */
148 public function getBarcodeHTML($w = 2, $h = 30, $color = 'black')
149 {
150 $html = '<div style="font-size:0;position:relative;width:' . $this->barcode_array['maxw'] * $w . 'px;height:' . $h . 'px;">' . "\n";
151 // print bars
152 $x = 0;
153 foreach ($this->barcode_array['bcode'] as $k => $v) {
154 $bw = \round($v['w'] * $w, 3);
155 $bh = \round($v['h'] * $h / $this->barcode_array['maxh'], 3);
156 if ($v['t']) {
157 $y = \round($v['p'] * $h / $this->barcode_array['maxh'], 3);
158 // draw a vertical bar
159 $html .= '<div style="background-color:' . $color . ';width:' . $bw . 'px;height:' . $bh . 'px;position:absolute;left:' . $x . 'px;top:' . $y . 'px;">&nbsp;</div>' . "\n";
160 }
161 $x += $bw;
162 }
163 $html .= '</div>' . "\n";
164 return $html;
165 }
166 /**
167 * Send a PNG image representation of barcode (requires GD or Imagick library).
168 * @param int $w Width of a single bar element in pixels.
169 * @param int $h Height of a single bar element in pixels.
170 * @param array $color RGB (0-255) foreground color for bar elements (background is transparent).
171 * @public
172 */
173 public function getBarcodePNG($w = 2, $h = 30, $color = array(0, 0, 0))
174 {
175 $data = $this->getBarcodePngData($w, $h, $color);
176 // send headers
177 \header('Content-Type: image/png');
178 \header('Cache-Control: public, must-revalidate, max-age=0');
179 // HTTP/1.1
180 \header('Pragma: public');
181 \header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
182 // Date in the past
183 \header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT');
184 //header('Content-Length: '.strlen($data));
185 echo $data;
186 }
187 /**
188 * Return a PNG image representation of barcode (requires GD or Imagick library).
189 * @param int $w Width of a single bar element in pixels.
190 * @param int $h Height of a single bar element in pixels.
191 * @param array $color RGB (0-255) foreground color for bar elements (background is transparent).
192 * @return string|Imagick|false image or false in case of error.
193 * @public
194 */
195 public function getBarcodePngData($w = 2, $h = 30, $color = array(0, 0, 0))
196 {
197 // calculate image size
198 $width = $this->barcode_array['maxw'] * $w;
199 $height = $h;
200 if (\function_exists('imagecreate')) {
201 // GD library
202 $imagick = \false;
203 $png = \imagecreate($width, $height);
204 $bgcol = \imagecolorallocate($png, 255, 255, 255);
205 \imagecolortransparent($png, $bgcol);
206 $fgcol = \imagecolorallocate($png, $color[0], $color[1], $color[2]);
207 } elseif (\extension_loaded('imagick')) {
208 $imagick = \true;
209 $bgcol = new \imagickpixel('rgb(255,255,255');
210 $fgcol = new \imagickpixel('rgb(' . $color[0] . ',' . $color[1] . ',' . $color[2] . ')');
211 $png = new \Imagick();
212 $png->newImage($width, $height, 'none', 'png');
213 $bar = new \imagickdraw();
214 $bar->setfillcolor($fgcol);
215 } else {
216 return \false;
217 }
218 // print bars
219 $x = 0;
220 foreach ($this->barcode_array['bcode'] as $k => $v) {
221 $bw = \round($v['w'] * $w, 3);
222 $bh = \round($v['h'] * $h / $this->barcode_array['maxh'], 3);
223 if ($v['t']) {
224 $y = \round($v['p'] * $h / $this->barcode_array['maxh'], 3);
225 // draw a vertical bar
226 if ($imagick) {
227 $bar->rectangle($x, $y, $x + $bw - 1, $y + $bh - 1);
228 } else {
229 \imagefilledrectangle($png, $x, $y, $x + $bw - 1, $y + $bh - 1, $fgcol);
230 }
231 }
232 $x += $bw;
233 }
234 if ($imagick) {
235 $png->drawimage($bar);
236 return $png;
237 } else {
238 \ob_start();
239 \imagepng($png);
240 $imagedata = \ob_get_clean();
241 if (\PHP_VERSION_ID < 80000) {
242 \imagedestroy($png);
243 }
244 return $imagedata;
245 }
246 }
247 /**
248 * Set the barcode.
249 * @param string $code code to print
250 * @param string $type type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>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 Extension</li><li>EAN5 : 5-Digits UPC-Based Extension</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>IMBPRE: Pre-processed Intelligent Mail Barcode - Onecode - USPS-B-3200, using only F,A,D,T letters</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
251 * @return void
252 * @public
253 */
254 public function setBarcode($code, $type)
255 {
256 switch (\strtoupper($type)) {
257 case 'C39':
258 // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
259 $arrcode = $this->barcode_code39($code, \false, \false);
260 break;
261 case 'C39+':
262 // CODE 39 with checksum
263 $arrcode = $this->barcode_code39($code, \false, \true);
264 break;
265 case 'C39E':
266 // CODE 39 EXTENDED
267 $arrcode = $this->barcode_code39($code, \true, \false);
268 break;
269 case 'C39E+':
270 // CODE 39 EXTENDED + CHECKSUM
271 $arrcode = $this->barcode_code39($code, \true, \true);
272 break;
273 case 'C93':
274 // CODE 93 - USS-93
275 $arrcode = $this->barcode_code93($code);
276 break;
277 case 'S25':
278 // Standard 2 of 5
279 $arrcode = $this->barcode_s25($code, \false);
280 break;
281 case 'S25+':
282 // Standard 2 of 5 + CHECKSUM
283 $arrcode = $this->barcode_s25($code, \true);
284 break;
285 case 'I25':
286 // Interleaved 2 of 5
287 $arrcode = $this->barcode_i25($code, \false);
288 break;
289 case 'I25+':
290 // Interleaved 2 of 5 + CHECKSUM
291 $arrcode = $this->barcode_i25($code, \true);
292 break;
293 case 'C128':
294 // CODE 128
295 $arrcode = $this->barcode_c128($code, '');
296 break;
297 case 'C128A':
298 // CODE 128 A
299 $arrcode = $this->barcode_c128($code, 'A');
300 break;
301 case 'C128B':
302 // CODE 128 B
303 $arrcode = $this->barcode_c128($code, 'B');
304 break;
305 case 'C128C':
306 // CODE 128 C
307 $arrcode = $this->barcode_c128($code, 'C');
308 break;
309 case 'EAN2':
310 // 2-Digits UPC-Based Extension
311 $arrcode = $this->barcode_eanext($code, 2);
312 break;
313 case 'EAN5':
314 // 5-Digits UPC-Based Extension
315 $arrcode = $this->barcode_eanext($code, 5);
316 break;
317 case 'EAN8':
318 // EAN 8
319 $arrcode = $this->barcode_eanupc($code, 8);
320 break;
321 case 'EAN13':
322 // EAN 13
323 $arrcode = $this->barcode_eanupc($code, 13);
324 break;
325 case 'UPCA':
326 // UPC-A
327 $arrcode = $this->barcode_eanupc($code, 12);
328 break;
329 case 'UPCE':
330 // UPC-E
331 $arrcode = $this->barcode_eanupc($code, 6);
332 break;
333 case 'MSI':
334 // MSI (Variation of Plessey code)
335 $arrcode = $this->barcode_msi($code, \false);
336 break;
337 case 'MSI+':
338 // MSI + CHECKSUM (modulo 11)
339 $arrcode = $this->barcode_msi($code, \true);
340 break;
341 case 'POSTNET':
342 // POSTNET
343 $arrcode = $this->barcode_postnet($code, \false);
344 break;
345 case 'PLANET':
346 // PLANET
347 $arrcode = $this->barcode_postnet($code, \true);
348 break;
349 case 'RMS4CC':
350 // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
351 $arrcode = $this->barcode_rms4cc($code, \false);
352 break;
353 case 'KIX':
354 // KIX (Klant index - Customer index)
355 $arrcode = $this->barcode_rms4cc($code, \true);
356 break;
357 case 'IMB':
358 // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
359 $arrcode = $this->barcode_imb($code);
360 break;
361 case 'IMBPRE':
362 // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200- pre-processed
363 $arrcode = $this->barcode_imb_pre($code);
364 break;
365 case 'CODABAR':
366 // CODABAR
367 $arrcode = $this->barcode_codabar($code);
368 break;
369 case 'CODE11':
370 // CODE 11
371 $arrcode = $this->barcode_code11($code);
372 break;
373 case 'PHARMA':
374 // PHARMACODE
375 $arrcode = $this->barcode_pharmacode($code);
376 break;
377 case 'PHARMA2T':
378 // PHARMACODE TWO-TRACKS
379 $arrcode = $this->barcode_pharmacode2t($code);
380 break;
381 default:
382 $this->barcode_array = array();
383 $arrcode = \false;
384 break;
385 }
386 $this->barcode_array = $arrcode;
387 }
388 /**
389 * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
390 * General-purpose code in very wide use world-wide
391 * @param string $code code to represent.
392 * @param boolean $extended if true uses the extended mode.
393 * @param boolean $checksum if true add a checksum to the code.
394 * @return array barcode representation.
395 * @protected
396 */
397 protected function barcode_code39($code, $extended = \false, $checksum = \false)
398 {
399 $chr['0'] = '111331311';
400 $chr['1'] = '311311113';
401 $chr['2'] = '113311113';
402 $chr['3'] = '313311111';
403 $chr['4'] = '111331113';
404 $chr['5'] = '311331111';
405 $chr['6'] = '113331111';
406 $chr['7'] = '111311313';
407 $chr['8'] = '311311311';
408 $chr['9'] = '113311311';
409 $chr['A'] = '311113113';
410 $chr['B'] = '113113113';
411 $chr['C'] = '313113111';
412 $chr['D'] = '111133113';
413 $chr['E'] = '311133111';
414 $chr['F'] = '113133111';
415 $chr['G'] = '111113313';
416 $chr['H'] = '311113311';
417 $chr['I'] = '113113311';
418 $chr['J'] = '111133311';
419 $chr['K'] = '311111133';
420 $chr['L'] = '113111133';
421 $chr['M'] = '313111131';
422 $chr['N'] = '111131133';
423 $chr['O'] = '311131131';
424 $chr['P'] = '113131131';
425 $chr['Q'] = '111111333';
426 $chr['R'] = '311111331';
427 $chr['S'] = '113111331';
428 $chr['T'] = '111131331';
429 $chr['U'] = '331111113';
430 $chr['V'] = '133111113';
431 $chr['W'] = '333111111';
432 $chr['X'] = '131131113';
433 $chr['Y'] = '331131111';
434 $chr['Z'] = '133131111';
435 $chr['-'] = '131111313';
436 $chr['.'] = '331111311';
437 $chr[' '] = '133111311';
438 $chr['$'] = '131313111';
439 $chr['/'] = '131311131';
440 $chr['+'] = '131113131';
441 $chr['%'] = '111313131';
442 $chr['*'] = '131131311';
443 $code = \strtoupper($code);
444 if ($extended) {
445 // extended mode
446 $code = $this->encode_code39_ext($code);
447 }
448 if ($code === \false) {
449 return \false;
450 }
451 if ($checksum) {
452 // checksum
453 $code .= $this->checksum_code39($code);
454 }
455 // add start and stop codes
456 $code = '*' . $code . '*';
457 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
458 $k = 0;
459 $clen = \strlen($code);
460 for ($i = 0; $i < $clen; ++$i) {
461 $char = $code[$i];
462 if (!isset($chr[$char])) {
463 // invalid character
464 return \false;
465 }
466 for ($j = 0; $j < 9; ++$j) {
467 if ($j % 2 == 0) {
468 $t = \true;
469 // bar
470 } else {
471 $t = \false;
472 // space
473 }
474 $w = $chr[$char][$j];
475 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
476 $bararray['maxw'] += $w;
477 ++$k;
478 }
479 // intercharacter gap
480 $bararray['bcode'][$k] = array('t' => \false, 'w' => 1, 'h' => 1, 'p' => 0);
481 $bararray['maxw'] += 1;
482 ++$k;
483 }
484 return $bararray;
485 }
486 /**
487 * Encode a string to be used for CODE 39 Extended mode.
488 * @param string $code code to represent.
489 * @return string encoded string.
490 * @protected
491 */
492 protected function encode_code39_ext($code)
493 {
494 $encode = array(\chr(0) => '%U', \chr(1) => '$A', \chr(2) => '$B', \chr(3) => '$C', \chr(4) => '$D', \chr(5) => '$E', \chr(6) => '$F', \chr(7) => '$G', \chr(8) => '$H', \chr(9) => '$I', \chr(10) => '$J', \chr(11) => '£K', \chr(12) => '$L', \chr(13) => '$M', \chr(14) => '$N', \chr(15) => '$O', \chr(16) => '$P', \chr(17) => '$Q', \chr(18) => '$R', \chr(19) => '$S', \chr(20) => '$T', \chr(21) => '$U', \chr(22) => '$V', \chr(23) => '$W', \chr(24) => '$X', \chr(25) => '$Y', \chr(26) => '$Z', \chr(27) => '%A', \chr(28) => '%B', \chr(29) => '%C', \chr(30) => '%D', \chr(31) => '%E', \chr(32) => ' ', \chr(33) => '/A', \chr(34) => '/B', \chr(35) => '/C', \chr(36) => '/D', \chr(37) => '/E', \chr(38) => '/F', \chr(39) => '/G', \chr(40) => '/H', \chr(41) => '/I', \chr(42) => '/J', \chr(43) => '/K', \chr(44) => '/L', \chr(45) => '-', \chr(46) => '.', \chr(47) => '/O', \chr(48) => '0', \chr(49) => '1', \chr(50) => '2', \chr(51) => '3', \chr(52) => '4', \chr(53) => '5', \chr(54) => '6', \chr(55) => '7', \chr(56) => '8', \chr(57) => '9', \chr(58) => '/Z', \chr(59) => '%F', \chr(60) => '%G', \chr(61) => '%H', \chr(62) => '%I', \chr(63) => '%J', \chr(64) => '%V', \chr(65) => 'A', \chr(66) => 'B', \chr(67) => 'C', \chr(68) => 'D', \chr(69) => 'E', \chr(70) => 'F', \chr(71) => 'G', \chr(72) => 'H', \chr(73) => 'I', \chr(74) => 'J', \chr(75) => 'K', \chr(76) => 'L', \chr(77) => 'M', \chr(78) => 'N', \chr(79) => 'O', \chr(80) => 'P', \chr(81) => 'Q', \chr(82) => 'R', \chr(83) => 'S', \chr(84) => 'T', \chr(85) => 'U', \chr(86) => 'V', \chr(87) => 'W', \chr(88) => 'X', \chr(89) => 'Y', \chr(90) => 'Z', \chr(91) => '%K', \chr(92) => '%L', \chr(93) => '%M', \chr(94) => '%N', \chr(95) => '%O', \chr(96) => '%W', \chr(97) => '+A', \chr(98) => '+B', \chr(99) => '+C', \chr(100) => '+D', \chr(101) => '+E', \chr(102) => '+F', \chr(103) => '+G', \chr(104) => '+H', \chr(105) => '+I', \chr(106) => '+J', \chr(107) => '+K', \chr(108) => '+L', \chr(109) => '+M', \chr(110) => '+N', \chr(111) => '+O', \chr(112) => '+P', \chr(113) => '+Q', \chr(114) => '+R', \chr(115) => '+S', \chr(116) => '+T', \chr(117) => '+U', \chr(118) => '+V', \chr(119) => '+W', \chr(120) => '+X', \chr(121) => '+Y', \chr(122) => '+Z', \chr(123) => '%P', \chr(124) => '%Q', \chr(125) => '%R', \chr(126) => '%S', \chr(127) => '%T');
495 $code_ext = '';
496 $clen = \strlen($code);
497 for ($i = 0; $i < $clen; ++$i) {
498 if (\ord($code[$i]) > 127) {
499 return \false;
500 }
501 $code_ext .= $encode[$code[$i]];
502 }
503 return $code_ext;
504 }
505 /**
506 * Calculate CODE 39 checksum (modulo 43).
507 * @param string $code code to represent.
508 * @return string char checksum.
509 * @protected
510 */
511 protected function checksum_code39($code)
512 {
513 $chars = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
514 $sum = 0;
515 $clen = \strlen($code);
516 for ($i = 0; $i < $clen; ++$i) {
517 $k = \array_keys($chars, $code[$i]);
518 $sum += $k[0];
519 }
520 $j = $sum % 43;
521 return $chars[$j];
522 }
523 /**
524 * CODE 93 - USS-93
525 * Compact code similar to Code 39
526 * @param string $code code to represent.
527 * @return array barcode representation.
528 * @protected
529 */
530 protected function barcode_code93($code)
531 {
532 $chr[48] = '131112';
533 // 0
534 $chr[49] = '111213';
535 // 1
536 $chr[50] = '111312';
537 // 2
538 $chr[51] = '111411';
539 // 3
540 $chr[52] = '121113';
541 // 4
542 $chr[53] = '121212';
543 // 5
544 $chr[54] = '121311';
545 // 6
546 $chr[55] = '111114';
547 // 7
548 $chr[56] = '131211';
549 // 8
550 $chr[57] = '141111';
551 // 9
552 $chr[65] = '211113';
553 // A
554 $chr[66] = '211212';
555 // B
556 $chr[67] = '211311';
557 // C
558 $chr[68] = '221112';
559 // D
560 $chr[69] = '221211';
561 // E
562 $chr[70] = '231111';
563 // F
564 $chr[71] = '112113';
565 // G
566 $chr[72] = '112212';
567 // H
568 $chr[73] = '112311';
569 // I
570 $chr[74] = '122112';
571 // J
572 $chr[75] = '132111';
573 // K
574 $chr[76] = '111123';
575 // L
576 $chr[77] = '111222';
577 // M
578 $chr[78] = '111321';
579 // N
580 $chr[79] = '121122';
581 // O
582 $chr[80] = '131121';
583 // P
584 $chr[81] = '212112';
585 // Q
586 $chr[82] = '212211';
587 // R
588 $chr[83] = '211122';
589 // S
590 $chr[84] = '211221';
591 // T
592 $chr[85] = '221121';
593 // U
594 $chr[86] = '222111';
595 // V
596 $chr[87] = '112122';
597 // W
598 $chr[88] = '112221';
599 // X
600 $chr[89] = '122121';
601 // Y
602 $chr[90] = '123111';
603 // Z
604 $chr[45] = '121131';
605 // -
606 $chr[46] = '311112';
607 // .
608 $chr[32] = '311211';
609 //
610 $chr[36] = '321111';
611 // $
612 $chr[47] = '112131';
613 // /
614 $chr[43] = '113121';
615 // +
616 $chr[37] = '211131';
617 // %
618 $chr[128] = '121221';
619 // ($)
620 $chr[129] = '311121';
621 // (/)
622 $chr[130] = '122211';
623 // (+)
624 $chr[131] = '312111';
625 // (%)
626 $chr[42] = '111141';
627 // start-stop
628 $code = \strtoupper($code);
629 $encode = array(\chr(0) => \chr(131) . 'U', \chr(1) => \chr(128) . 'A', \chr(2) => \chr(128) . 'B', \chr(3) => \chr(128) . 'C', \chr(4) => \chr(128) . 'D', \chr(5) => \chr(128) . 'E', \chr(6) => \chr(128) . 'F', \chr(7) => \chr(128) . 'G', \chr(8) => \chr(128) . 'H', \chr(9) => \chr(128) . 'I', \chr(10) => \chr(128) . 'J', \chr(11) => '£K', \chr(12) => \chr(128) . 'L', \chr(13) => \chr(128) . 'M', \chr(14) => \chr(128) . 'N', \chr(15) => \chr(128) . 'O', \chr(16) => \chr(128) . 'P', \chr(17) => \chr(128) . 'Q', \chr(18) => \chr(128) . 'R', \chr(19) => \chr(128) . 'S', \chr(20) => \chr(128) . 'T', \chr(21) => \chr(128) . 'U', \chr(22) => \chr(128) . 'V', \chr(23) => \chr(128) . 'W', \chr(24) => \chr(128) . 'X', \chr(25) => \chr(128) . 'Y', \chr(26) => \chr(128) . 'Z', \chr(27) => \chr(131) . 'A', \chr(28) => \chr(131) . 'B', \chr(29) => \chr(131) . 'C', \chr(30) => \chr(131) . 'D', \chr(31) => \chr(131) . 'E', \chr(32) => ' ', \chr(33) => \chr(129) . 'A', \chr(34) => \chr(129) . 'B', \chr(35) => \chr(129) . 'C', \chr(36) => \chr(129) . 'D', \chr(37) => \chr(129) . 'E', \chr(38) => \chr(129) . 'F', \chr(39) => \chr(129) . 'G', \chr(40) => \chr(129) . 'H', \chr(41) => \chr(129) . 'I', \chr(42) => \chr(129) . 'J', \chr(43) => \chr(129) . 'K', \chr(44) => \chr(129) . 'L', \chr(45) => '-', \chr(46) => '.', \chr(47) => \chr(129) . 'O', \chr(48) => '0', \chr(49) => '1', \chr(50) => '2', \chr(51) => '3', \chr(52) => '4', \chr(53) => '5', \chr(54) => '6', \chr(55) => '7', \chr(56) => '8', \chr(57) => '9', \chr(58) => \chr(129) . 'Z', \chr(59) => \chr(131) . 'F', \chr(60) => \chr(131) . 'G', \chr(61) => \chr(131) . 'H', \chr(62) => \chr(131) . 'I', \chr(63) => \chr(131) . 'J', \chr(64) => \chr(131) . 'V', \chr(65) => 'A', \chr(66) => 'B', \chr(67) => 'C', \chr(68) => 'D', \chr(69) => 'E', \chr(70) => 'F', \chr(71) => 'G', \chr(72) => 'H', \chr(73) => 'I', \chr(74) => 'J', \chr(75) => 'K', \chr(76) => 'L', \chr(77) => 'M', \chr(78) => 'N', \chr(79) => 'O', \chr(80) => 'P', \chr(81) => 'Q', \chr(82) => 'R', \chr(83) => 'S', \chr(84) => 'T', \chr(85) => 'U', \chr(86) => 'V', \chr(87) => 'W', \chr(88) => 'X', \chr(89) => 'Y', \chr(90) => 'Z', \chr(91) => \chr(131) . 'K', \chr(92) => \chr(131) . 'L', \chr(93) => \chr(131) . 'M', \chr(94) => \chr(131) . 'N', \chr(95) => \chr(131) . 'O', \chr(96) => \chr(131) . 'W', \chr(97) => \chr(130) . 'A', \chr(98) => \chr(130) . 'B', \chr(99) => \chr(130) . 'C', \chr(100) => \chr(130) . 'D', \chr(101) => \chr(130) . 'E', \chr(102) => \chr(130) . 'F', \chr(103) => \chr(130) . 'G', \chr(104) => \chr(130) . 'H', \chr(105) => \chr(130) . 'I', \chr(106) => \chr(130) . 'J', \chr(107) => \chr(130) . 'K', \chr(108) => \chr(130) . 'L', \chr(109) => \chr(130) . 'M', \chr(110) => \chr(130) . 'N', \chr(111) => \chr(130) . 'O', \chr(112) => \chr(130) . 'P', \chr(113) => \chr(130) . 'Q', \chr(114) => \chr(130) . 'R', \chr(115) => \chr(130) . 'S', \chr(116) => \chr(130) . 'T', \chr(117) => \chr(130) . 'U', \chr(118) => \chr(130) . 'V', \chr(119) => \chr(130) . 'W', \chr(120) => \chr(130) . 'X', \chr(121) => \chr(130) . 'Y', \chr(122) => \chr(130) . 'Z', \chr(123) => \chr(131) . 'P', \chr(124) => \chr(131) . 'Q', \chr(125) => \chr(131) . 'R', \chr(126) => \chr(131) . 'S', \chr(127) => \chr(131) . 'T');
630 $code_ext = '';
631 $clen = \strlen($code);
632 for ($i = 0; $i < $clen; ++$i) {
633 if (\ord($code[$i]) > 127) {
634 return \false;
635 }
636 $code_ext .= $encode[$code[$i]];
637 }
638 // checksum
639 $code_ext .= $this->checksum_code93($code_ext);
640 // add start and stop codes
641 $code = '*' . $code_ext . '*';
642 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
643 $k = 0;
644 $clen = \strlen($code);
645 for ($i = 0; $i < $clen; ++$i) {
646 $char = \ord($code[$i]);
647 if (!isset($chr[$char])) {
648 // invalid character
649 return \false;
650 }
651 for ($j = 0; $j < 6; ++$j) {
652 if ($j % 2 == 0) {
653 $t = \true;
654 // bar
655 } else {
656 $t = \false;
657 // space
658 }
659 $w = $chr[$char][$j];
660 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
661 $bararray['maxw'] += $w;
662 ++$k;
663 }
664 }
665 $bararray['bcode'][$k] = array('t' => \true, 'w' => 1, 'h' => 1, 'p' => 0);
666 $bararray['maxw'] += 1;
667 ++$k;
668 return $bararray;
669 }
670 /**
671 * Calculate CODE 93 checksum (modulo 47).
672 * @param string $code code to represent.
673 * @return string checksum code.
674 * @protected
675 */
676 protected function checksum_code93($code)
677 {
678 $chars = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', '<', '=', '>', '?');
679 // translate special characters
680 $code = \strtr($code, \chr(128) . \chr(131) . \chr(129) . \chr(130), '<=>?');
681 $len = \strlen($code);
682 // calculate check digit C
683 $p = 1;
684 $check = 0;
685 for ($i = $len - 1; $i >= 0; --$i) {
686 $k = \array_keys($chars, $code[$i]);
687 $check += $k[0] * $p;
688 ++$p;
689 if ($p > 20) {
690 $p = 1;
691 }
692 }
693 $check %= 47;
694 $c = $chars[$check];
695 $code .= $c;
696 // calculate check digit K
697 $p = 1;
698 $check = 0;
699 for ($i = $len; $i >= 0; --$i) {
700 $k = \array_keys($chars, $code[$i]);
701 $check += $k[0] * $p;
702 ++$p;
703 if ($p > 15) {
704 $p = 1;
705 }
706 }
707 $check %= 47;
708 $k = $chars[$check];
709 $checksum = $c . $k;
710 // resto respecial characters
711 $checksum = \strtr($checksum, '<=>?', \chr(128) . \chr(131) . \chr(129) . \chr(130));
712 return $checksum;
713 }
714 /**
715 * Checksum for standard 2 of 5 barcodes.
716 * @param string $code code to process.
717 * @return int checksum.
718 * @protected
719 */
720 protected function checksum_s25($code)
721 {
722 $len = \strlen($code);
723 $sum = 0;
724 for ($i = 0; $i < $len; $i += 2) {
725 $sum += $code[$i];
726 }
727 $sum *= 3;
728 for ($i = 1; $i < $len; $i += 2) {
729 $sum += $code[$i];
730 }
731 $r = $sum % 10;
732 if ($r > 0) {
733 $r = 10 - $r;
734 }
735 return $r;
736 }
737 /**
738 * MSI.
739 * Variation of Plessey code, with similar applications
740 * Contains digits (0 to 9) and encodes the data only in the width of bars.
741 * @param string $code code to represent.
742 * @param boolean $checksum if true add a checksum to the code (modulo 11)
743 * @return array barcode representation.
744 * @protected
745 */
746 protected function barcode_msi($code, $checksum = \false)
747 {
748 $chr['0'] = '100100100100';
749 $chr['1'] = '100100100110';
750 $chr['2'] = '100100110100';
751 $chr['3'] = '100100110110';
752 $chr['4'] = '100110100100';
753 $chr['5'] = '100110100110';
754 $chr['6'] = '100110110100';
755 $chr['7'] = '100110110110';
756 $chr['8'] = '110100100100';
757 $chr['9'] = '110100100110';
758 $chr['A'] = '110100110100';
759 $chr['B'] = '110100110110';
760 $chr['C'] = '110110100100';
761 $chr['D'] = '110110100110';
762 $chr['E'] = '110110110100';
763 $chr['F'] = '110110110110';
764 if ($checksum) {
765 // add checksum
766 $clen = \strlen($code);
767 $p = 2;
768 $check = 0;
769 for ($i = $clen - 1; $i >= 0; --$i) {
770 $check += \hexdec($code[$i]) * $p;
771 ++$p;
772 if ($p > 7) {
773 $p = 2;
774 }
775 }
776 $check %= 11;
777 if ($check > 0) {
778 $check = 11 - $check;
779 }
780 $code .= $check;
781 }
782 $seq = '110';
783 // left guard
784 $clen = \strlen($code);
785 for ($i = 0; $i < $clen; ++$i) {
786 $digit = $code[$i];
787 if (!isset($chr[$digit])) {
788 // invalid character
789 return \false;
790 }
791 $seq .= $chr[$digit];
792 }
793 $seq .= '1001';
794 // right guard
795 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
796 return $this->binseq_to_array($seq, $bararray);
797 }
798 /**
799 * Standard 2 of 5 barcodes.
800 * Used in airline ticket marking, photofinishing
801 * Contains digits (0 to 9) and encodes the data only in the width of bars.
802 * @param string $code code to represent.
803 * @param boolean $checksum if true add a checksum to the code
804 * @return array barcode representation.
805 * @protected
806 */
807 protected function barcode_s25($code, $checksum = \false)
808 {
809 $chr['0'] = '10101110111010';
810 $chr['1'] = '11101010101110';
811 $chr['2'] = '10111010101110';
812 $chr['3'] = '11101110101010';
813 $chr['4'] = '10101110101110';
814 $chr['5'] = '11101011101010';
815 $chr['6'] = '10111011101010';
816 $chr['7'] = '10101011101110';
817 $chr['8'] = '11101010111010';
818 $chr['9'] = '10111010111010';
819 if ($checksum) {
820 // add checksum
821 $code .= $this->checksum_s25($code);
822 }
823 if (\strlen($code) % 2 != 0) {
824 // add leading zero if code-length is odd
825 $code = '0' . $code;
826 }
827 $seq = '1110111010';
828 $clen = \strlen($code);
829 for ($i = 0; $i < $clen; ++$i) {
830 $digit = $code[$i];
831 if (!isset($chr[$digit])) {
832 // invalid character
833 return \false;
834 }
835 $seq .= $chr[$digit];
836 }
837 $seq .= '111010111';
838 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
839 return $this->binseq_to_array($seq, $bararray);
840 }
841 /**
842 * Convert binary barcode sequence to WarnockPDF barcode array.
843 * @param string $seq barcode as binary sequence.
844 * @param array $bararray barcode array to fill up
845 * @return array barcode representation.
846 * @protected
847 */
848 protected function binseq_to_array($seq, $bararray)
849 {
850 $len = \strlen($seq);
851 $w = 0;
852 $k = 0;
853 for ($i = 0; $i < $len; ++$i) {
854 $w += 1;
855 if ($i == $len - 1 or $i < $len - 1 and $seq[$i] != $seq[$i + 1]) {
856 if ($seq[$i] == '1') {
857 $t = \true;
858 // bar
859 } else {
860 $t = \false;
861 // space
862 }
863 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
864 $bararray['maxw'] += $w;
865 ++$k;
866 $w = 0;
867 }
868 }
869 return $bararray;
870 }
871 /**
872 * Interleaved 2 of 5 barcodes.
873 * Compact numeric code, widely used in industry, air cargo
874 * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
875 * @param string $code code to represent.
876 * @param boolean $checksum if true add a checksum to the code
877 * @return array barcode representation.
878 * @protected
879 */
880 protected function barcode_i25($code, $checksum = \false)
881 {
882 $chr['0'] = '11221';
883 $chr['1'] = '21112';
884 $chr['2'] = '12112';
885 $chr['3'] = '22111';
886 $chr['4'] = '11212';
887 $chr['5'] = '21211';
888 $chr['6'] = '12211';
889 $chr['7'] = '11122';
890 $chr['8'] = '21121';
891 $chr['9'] = '12121';
892 $chr['A'] = '11';
893 $chr['Z'] = '21';
894 if ($checksum) {
895 // add checksum
896 $code .= $this->checksum_s25($code);
897 }
898 if (\strlen($code) % 2 != 0) {
899 // add leading zero if code-length is odd
900 $code = '0' . $code;
901 }
902 // add start and stop codes
903 $code = 'AA' . \strtolower($code) . 'ZA';
904 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
905 $k = 0;
906 $clen = \strlen($code);
907 for ($i = 0; $i < $clen; $i = $i + 2) {
908 $char_bar = $code[$i];
909 $char_space = $code[$i + 1];
910 if (!isset($chr[$char_bar]) or !isset($chr[$char_space])) {
911 // invalid character
912 return \false;
913 }
914 // create a bar-space sequence
915 $seq = '';
916 $chrlen = \strlen($chr[$char_bar]);
917 for ($s = 0; $s < $chrlen; $s++) {
918 $seq .= $chr[$char_bar][$s] . $chr[$char_space][$s];
919 }
920 $seqlen = \strlen($seq);
921 for ($j = 0; $j < $seqlen; ++$j) {
922 if ($j % 2 == 0) {
923 $t = \true;
924 // bar
925 } else {
926 $t = \false;
927 // space
928 }
929 $w = (float) $seq[$j];
930 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
931 $bararray['maxw'] += $w;
932 ++$k;
933 }
934 }
935 return $bararray;
936 }
937 /**
938 * C128 barcodes.
939 * Very capable code, excellent density, high reliability; in very wide use world-wide
940 * @param string $code code to represent.
941 * @param string $type barcode type: A, B, C or empty for automatic switch (AUTO mode)
942 * @return array barcode representation.
943 * @protected
944 */
945 protected function barcode_c128($code, $type = '')
946 {
947 $chr = array(
948 '212222',
949 /* 00 */
950 '222122',
951 /* 01 */
952 '222221',
953 /* 02 */
954 '121223',
955 /* 03 */
956 '121322',
957 /* 04 */
958 '131222',
959 /* 05 */
960 '122213',
961 /* 06 */
962 '122312',
963 /* 07 */
964 '132212',
965 /* 08 */
966 '221213',
967 /* 09 */
968 '221312',
969 /* 10 */
970 '231212',
971 /* 11 */
972 '112232',
973 /* 12 */
974 '122132',
975 /* 13 */
976 '122231',
977 /* 14 */
978 '113222',
979 /* 15 */
980 '123122',
981 /* 16 */
982 '123221',
983 /* 17 */
984 '223211',
985 /* 18 */
986 '221132',
987 /* 19 */
988 '221231',
989 /* 20 */
990 '213212',
991 /* 21 */
992 '223112',
993 /* 22 */
994 '312131',
995 /* 23 */
996 '311222',
997 /* 24 */
998 '321122',
999 /* 25 */
1000 '321221',
1001 /* 26 */
1002 '312212',
1003 /* 27 */
1004 '322112',
1005 /* 28 */
1006 '322211',
1007 /* 29 */
1008 '212123',
1009 /* 30 */
1010 '212321',
1011 /* 31 */
1012 '232121',
1013 /* 32 */
1014 '111323',
1015 /* 33 */
1016 '131123',
1017 /* 34 */
1018 '131321',
1019 /* 35 */
1020 '112313',
1021 /* 36 */
1022 '132113',
1023 /* 37 */
1024 '132311',
1025 /* 38 */
1026 '211313',
1027 /* 39 */
1028 '231113',
1029 /* 40 */
1030 '231311',
1031 /* 41 */
1032 '112133',
1033 /* 42 */
1034 '112331',
1035 /* 43 */
1036 '132131',
1037 /* 44 */
1038 '113123',
1039 /* 45 */
1040 '113321',
1041 /* 46 */
1042 '133121',
1043 /* 47 */
1044 '313121',
1045 /* 48 */
1046 '211331',
1047 /* 49 */
1048 '231131',
1049 /* 50 */
1050 '213113',
1051 /* 51 */
1052 '213311',
1053 /* 52 */
1054 '213131',
1055 /* 53 */
1056 '311123',
1057 /* 54 */
1058 '311321',
1059 /* 55 */
1060 '331121',
1061 /* 56 */
1062 '312113',
1063 /* 57 */
1064 '312311',
1065 /* 58 */
1066 '332111',
1067 /* 59 */
1068 '314111',
1069 /* 60 */
1070 '221411',
1071 /* 61 */
1072 '431111',
1073 /* 62 */
1074 '111224',
1075 /* 63 */
1076 '111422',
1077 /* 64 */
1078 '121124',
1079 /* 65 */
1080 '121421',
1081 /* 66 */
1082 '141122',
1083 /* 67 */
1084 '141221',
1085 /* 68 */
1086 '112214',
1087 /* 69 */
1088 '112412',
1089 /* 70 */
1090 '122114',
1091 /* 71 */
1092 '122411',
1093 /* 72 */
1094 '142112',
1095 /* 73 */
1096 '142211',
1097 /* 74 */
1098 '241211',
1099 /* 75 */
1100 '221114',
1101 /* 76 */
1102 '413111',
1103 /* 77 */
1104 '241112',
1105 /* 78 */
1106 '134111',
1107 /* 79 */
1108 '111242',
1109 /* 80 */
1110 '121142',
1111 /* 81 */
1112 '121241',
1113 /* 82 */
1114 '114212',
1115 /* 83 */
1116 '124112',
1117 /* 84 */
1118 '124211',
1119 /* 85 */
1120 '411212',
1121 /* 86 */
1122 '421112',
1123 /* 87 */
1124 '421211',
1125 /* 88 */
1126 '212141',
1127 /* 89 */
1128 '214121',
1129 /* 90 */
1130 '412121',
1131 /* 91 */
1132 '111143',
1133 /* 92 */
1134 '111341',
1135 /* 93 */
1136 '131141',
1137 /* 94 */
1138 '114113',
1139 /* 95 */
1140 '114311',
1141 /* 96 */
1142 '411113',
1143 /* 97 */
1144 '411311',
1145 /* 98 */
1146 '113141',
1147 /* 99 */
1148 '114131',
1149 /* 100 */
1150 '311141',
1151 /* 101 */
1152 '411131',
1153 /* 102 */
1154 '211412',
1155 /* 103 START A */
1156 '211214',
1157 /* 104 START B */
1158 '211232',
1159 /* 105 START C */
1160 '233111',
1161 /* STOP */
1162 '200000',
1163 );
1164 // ASCII characters for code A (ASCII 00 - 95)
1165 $keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
1166 $keys_a .= \chr(0) . \chr(1) . \chr(2) . \chr(3) . \chr(4) . \chr(5) . \chr(6) . \chr(7) . \chr(8) . \chr(9);
1167 $keys_a .= \chr(10) . \chr(11) . \chr(12) . \chr(13) . \chr(14) . \chr(15) . \chr(16) . \chr(17) . \chr(18) . \chr(19);
1168 $keys_a .= \chr(20) . \chr(21) . \chr(22) . \chr(23) . \chr(24) . \chr(25) . \chr(26) . \chr(27) . \chr(28) . \chr(29);
1169 $keys_a .= \chr(30) . \chr(31);
1170 // ASCII characters for code B (ASCII 32 - 127)
1171 $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' . \chr(127);
1172 // special codes
1173 $fnc_a = array(241 => 102, 242 => 97, 243 => 96, 244 => 101);
1174 $fnc_b = array(241 => 102, 242 => 97, 243 => 96, 244 => 100);
1175 // array of symbols
1176 $code_data = array();
1177 // length of the code
1178 $len = \strlen($code);
1179 switch (\strtoupper($type)) {
1180 case 'A':
1181 // MODE A
1182 $startid = 103;
1183 for ($i = 0; $i < $len; ++$i) {
1184 $char = $code[$i];
1185 $char_id = \ord($char);
1186 if ($char_id >= 241 and $char_id <= 244) {
1187 $code_data[] = $fnc_a[$char_id];
1188 } elseif ($char_id >= 0 and $char_id <= 95) {
1189 $code_data[] = \strpos($keys_a, $char);
1190 } else {
1191 return \false;
1192 }
1193 }
1194 break;
1195 case 'B':
1196 // MODE B
1197 $startid = 104;
1198 for ($i = 0; $i < $len; ++$i) {
1199 $char = $code[$i];
1200 $char_id = \ord($char);
1201 if ($char_id >= 241 and $char_id <= 244) {
1202 $code_data[] = $fnc_b[$char_id];
1203 } elseif ($char_id >= 32 and $char_id <= 127) {
1204 $code_data[] = \strpos($keys_b, $char);
1205 } else {
1206 return \false;
1207 }
1208 }
1209 break;
1210 case 'C':
1211 // MODE C
1212 $startid = 105;
1213 if (\ord($code[0]) == 241) {
1214 $code_data[] = 102;
1215 $code = \substr($code, 1);
1216 --$len;
1217 }
1218 if ($len % 2 != 0) {
1219 // the length must be even
1220 return \false;
1221 }
1222 for ($i = 0; $i < $len; $i += 2) {
1223 $chrnum = $code[$i] . $code[$i + 1];
1224 if (\preg_match('/([0-9]{2})/', $chrnum) > 0) {
1225 $code_data[] = \intval($chrnum);
1226 } else {
1227 return \false;
1228 }
1229 }
1230 break;
1231 default:
1232 // MODE AUTO
1233 // split code into sequences
1234 $sequence = array();
1235 // get numeric sequences (if any)
1236 $numseq = array();
1237 \preg_match_all('/([0-9]{4,})/', $code, $numseq, \PREG_OFFSET_CAPTURE);
1238 if (isset($numseq[1]) and !empty($numseq[1])) {
1239 $end_offset = 0;
1240 foreach ($numseq[1] as $val) {
1241 $offset = $val[1];
1242 if ($offset > $end_offset) {
1243 // non numeric sequence
1244 $sequence = \array_merge($sequence, $this->get128ABsequence(\substr($code, $end_offset, $offset - $end_offset)));
1245 }
1246 // numeric sequence
1247 $slen = \strlen($val[0]);
1248 if ($slen % 2 != 0) {
1249 // the length must be even
1250 --$slen;
1251 }
1252 $sequence[] = array('C', \substr($code, $offset, $slen), $slen);
1253 $end_offset = $offset + $slen;
1254 }
1255 if ($end_offset < $len) {
1256 $sequence = \array_merge($sequence, $this->get128ABsequence(\substr($code, $end_offset)));
1257 }
1258 } else {
1259 // text code (non C mode)
1260 $sequence = \array_merge($sequence, $this->get128ABsequence($code));
1261 }
1262 // process the sequence
1263 foreach ($sequence as $key => $seq) {
1264 switch ($seq[0]) {
1265 case 'A':
1266 if ($key == 0) {
1267 $startid = 103;
1268 } elseif ($sequence[$key - 1][0] != 'A') {
1269 if ($seq[2] == 1 and $key > 0 and $sequence[$key - 1][0] == 'B' and !isset($sequence[$key - 1][3])) {
1270 // single character shift
1271 $code_data[] = 98;
1272 // mark shift
1273 $sequence[$key][3] = \true;
1274 } elseif (!isset($sequence[$key - 1][3])) {
1275 $code_data[] = 101;
1276 }
1277 }
1278 for ($i = 0; $i < $seq[2]; ++$i) {
1279 $char = $seq[1][$i];
1280 $char_id = \ord($char);
1281 if ($char_id >= 241 and $char_id <= 244) {
1282 $code_data[] = $fnc_a[$char_id];
1283 } else {
1284 $code_data[] = \strpos($keys_a, $char);
1285 }
1286 }
1287 break;
1288 case 'B':
1289 if ($key == 0) {
1290 $tmpchr = \ord($seq[1][0]);
1291 if ($seq[2] == 1 and $tmpchr >= 241 and $tmpchr <= 244 and isset($sequence[$key + 1]) and $sequence[$key + 1][0] != 'B') {
1292 switch ($sequence[$key + 1][0]) {
1293 case 'A':
1294 $startid = 103;
1295 $sequence[$key][0] = 'A';
1296 $code_data[] = $fnc_a[$tmpchr];
1297 break;
1298 case 'C':
1299 $startid = 105;
1300 $sequence[$key][0] = 'C';
1301 $code_data[] = $fnc_a[$tmpchr];
1302 break;
1303 }
1304 break;
1305 } else {
1306 $startid = 104;
1307 }
1308 } elseif ($sequence[$key - 1][0] != 'B') {
1309 if ($seq[2] == 1 and $key > 0 and $sequence[$key - 1][0] == 'A' and !isset($sequence[$key - 1][3])) {
1310 // single character shift
1311 $code_data[] = 98;
1312 // mark shift
1313 $sequence[$key][3] = \true;
1314 } elseif (!isset($sequence[$key - 1][3])) {
1315 $code_data[] = 100;
1316 }
1317 }
1318 for ($i = 0; $i < $seq[2]; ++$i) {
1319 $char = $seq[1][$i];
1320 $char_id = \ord($char);
1321 if ($char_id >= 241 and $char_id <= 244) {
1322 $code_data[] = $fnc_b[$char_id];
1323 } else {
1324 $code_data[] = \strpos($keys_b, $char);
1325 }
1326 }
1327 break;
1328 case 'C':
1329 if ($key == 0) {
1330 $startid = 105;
1331 } elseif ($sequence[$key - 1][0] != 'C') {
1332 $code_data[] = 99;
1333 }
1334 for ($i = 0; $i < $seq[2]; $i += 2) {
1335 $chrnum = $seq[1][$i] . $seq[1][$i + 1];
1336 $code_data[] = \intval($chrnum);
1337 }
1338 break;
1339 }
1340 }
1341 }
1342 // calculate check character
1343 $sum = $startid;
1344 foreach ($code_data as $key => $val) {
1345 $sum += $val * ($key + 1);
1346 }
1347 // add check character
1348 $code_data[] = $sum % 103;
1349 // add stop sequence
1350 $code_data[] = 106;
1351 $code_data[] = 107;
1352 // add start code at the beginning
1353 \array_unshift($code_data, $startid);
1354 // build barcode array
1355 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1356 foreach ($code_data as $val) {
1357 $seq = $chr[$val];
1358 for ($j = 0; $j < 6; ++$j) {
1359 if ($j % 2 == 0) {
1360 $t = \true;
1361 // bar
1362 } else {
1363 $t = \false;
1364 // space
1365 }
1366 $w = (float) $seq[$j];
1367 $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1368 $bararray['maxw'] += $w;
1369 }
1370 }
1371 return $bararray;
1372 }
1373 /**
1374 * Split text code in A/B sequence for 128 code
1375 * @param string $code code to split.
1376 * @return array sequence
1377 * @protected
1378 */
1379 protected function get128ABsequence($code)
1380 {
1381 $len = \strlen($code);
1382 $sequence = array();
1383 // get A sequences (if any)
1384 $numseq = array();
1385 \preg_match_all('/([\\0-\\31])/', $code, $numseq, \PREG_OFFSET_CAPTURE);
1386 if (isset($numseq[1]) and !empty($numseq[1])) {
1387 $end_offset = 0;
1388 foreach ($numseq[1] as $val) {
1389 $offset = $val[1];
1390 if ($offset > $end_offset) {
1391 // B sequence
1392 $sequence[] = array('B', \substr($code, $end_offset, $offset - $end_offset), $offset - $end_offset);
1393 }
1394 // A sequence
1395 $slen = \strlen($val[0]);
1396 $sequence[] = array('A', \substr($code, $offset, $slen), $slen);
1397 $end_offset = $offset + $slen;
1398 }
1399 if ($end_offset < $len) {
1400 $sequence[] = array('B', \substr($code, $end_offset), $len - $end_offset);
1401 }
1402 } else {
1403 // only B sequence
1404 $sequence[] = array('B', $code, $len);
1405 }
1406 return $sequence;
1407 }
1408 /**
1409 * EAN13 and UPC-A barcodes.
1410 * EAN13: European Article Numbering international retail product code
1411 * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
1412 * UPC-E: Short version of UPC symbol
1413 * @param string $code code to represent.
1414 * @param string $len barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
1415 * @return array barcode representation.
1416 * @protected
1417 */
1418 protected function barcode_eanupc($code, $len = 13)
1419 {
1420 $upce = \false;
1421 if ($len == 6) {
1422 $len = 12;
1423 // UPC-A
1424 $upce = \true;
1425 // UPC-E mode
1426 }
1427 $data_len = $len - 1;
1428 //Padding
1429 $code = \str_pad($code, $data_len, '0', \STR_PAD_LEFT);
1430 $code_len = \strlen($code);
1431 // calculate check digit
1432 $sum_a = 0;
1433 for ($i = 1; $i < $data_len; $i += 2) {
1434 $sum_a += $code[$i];
1435 }
1436 if ($len > 12) {
1437 $sum_a *= 3;
1438 }
1439 $sum_b = 0;
1440 for ($i = 0; $i < $data_len; $i += 2) {
1441 $sum_b += $code[$i];
1442 }
1443 if ($len < 13) {
1444 $sum_b *= 3;
1445 }
1446 $r = ($sum_a + $sum_b) % 10;
1447 if ($r > 0) {
1448 $r = 10 - $r;
1449 }
1450 if ($code_len == $data_len) {
1451 // add check digit
1452 $code .= $r;
1453 } elseif ($r !== \intval($code[$data_len])) {
1454 // wrong checkdigit
1455 return \false;
1456 }
1457 if ($len == 12) {
1458 // UPC-A
1459 $code = '0' . $code;
1460 ++$len;
1461 }
1462 if ($upce) {
1463 // convert UPC-A to UPC-E
1464 $tmp = \substr($code, 4, 3);
1465 if ($tmp == '000' or $tmp == '100' or $tmp == '200') {
1466 // manufacturer code ends in 000, 100, or 200
1467 $upce_code = \substr($code, 2, 2) . \substr($code, 9, 3) . \substr($code, 4, 1);
1468 } else {
1469 $tmp = \substr($code, 5, 2);
1470 if ($tmp == '00') {
1471 // manufacturer code ends in 00
1472 $upce_code = \substr($code, 2, 3) . \substr($code, 10, 2) . '3';
1473 } else {
1474 $tmp = \substr($code, 6, 1);
1475 if ($tmp == '0') {
1476 // manufacturer code ends in 0
1477 $upce_code = \substr($code, 2, 4) . \substr($code, 11, 1) . '4';
1478 } else {
1479 // manufacturer code does not end in zero
1480 $upce_code = \substr($code, 2, 5) . \substr($code, 11, 1);
1481 }
1482 }
1483 }
1484 }
1485 //Convert digits to bars
1486 $codes = array('A' => array(
1487 // left odd parity
1488 '0' => '0001101',
1489 '1' => '0011001',
1490 '2' => '0010011',
1491 '3' => '0111101',
1492 '4' => '0100011',
1493 '5' => '0110001',
1494 '6' => '0101111',
1495 '7' => '0111011',
1496 '8' => '0110111',
1497 '9' => '0001011',
1498 ), 'B' => array(
1499 // left even parity
1500 '0' => '0100111',
1501 '1' => '0110011',
1502 '2' => '0011011',
1503 '3' => '0100001',
1504 '4' => '0011101',
1505 '5' => '0111001',
1506 '6' => '0000101',
1507 '7' => '0010001',
1508 '8' => '0001001',
1509 '9' => '0010111',
1510 ), 'C' => array(
1511 // right
1512 '0' => '1110010',
1513 '1' => '1100110',
1514 '2' => '1101100',
1515 '3' => '1000010',
1516 '4' => '1011100',
1517 '5' => '1001110',
1518 '6' => '1010000',
1519 '7' => '1000100',
1520 '8' => '1001000',
1521 '9' => '1110100',
1522 ));
1523 $parities = array('0' => array('A', 'A', 'A', 'A', 'A', 'A'), '1' => array('A', 'A', 'B', 'A', 'B', 'B'), '2' => array('A', 'A', 'B', 'B', 'A', 'B'), '3' => array('A', 'A', 'B', 'B', 'B', 'A'), '4' => array('A', 'B', 'A', 'A', 'B', 'B'), '5' => array('A', 'B', 'B', 'A', 'A', 'B'), '6' => array('A', 'B', 'B', 'B', 'A', 'A'), '7' => array('A', 'B', 'A', 'B', 'A', 'B'), '8' => array('A', 'B', 'A', 'B', 'B', 'A'), '9' => array('A', 'B', 'B', 'A', 'B', 'A'));
1524 $upce_parities = array();
1525 $upce_parities[0] = array('0' => array('B', 'B', 'B', 'A', 'A', 'A'), '1' => array('B', 'B', 'A', 'B', 'A', 'A'), '2' => array('B', 'B', 'A', 'A', 'B', 'A'), '3' => array('B', 'B', 'A', 'A', 'A', 'B'), '4' => array('B', 'A', 'B', 'B', 'A', 'A'), '5' => array('B', 'A', 'A', 'B', 'B', 'A'), '6' => array('B', 'A', 'A', 'A', 'B', 'B'), '7' => array('B', 'A', 'B', 'A', 'B', 'A'), '8' => array('B', 'A', 'B', 'A', 'A', 'B'), '9' => array('B', 'A', 'A', 'B', 'A', 'B'));
1526 $upce_parities[1] = array('0' => array('A', 'A', 'A', 'B', 'B', 'B'), '1' => array('A', 'A', 'B', 'A', 'B', 'B'), '2' => array('A', 'A', 'B', 'B', 'A', 'B'), '3' => array('A', 'A', 'B', 'B', 'B', 'A'), '4' => array('A', 'B', 'A', 'A', 'B', 'B'), '5' => array('A', 'B', 'B', 'A', 'A', 'B'), '6' => array('A', 'B', 'B', 'B', 'A', 'A'), '7' => array('A', 'B', 'A', 'B', 'A', 'B'), '8' => array('A', 'B', 'A', 'B', 'B', 'A'), '9' => array('A', 'B', 'B', 'A', 'B', 'A'));
1527 $k = 0;
1528 $seq = '101';
1529 // left guard bar
1530 if ($upce) {
1531 $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1532 $p = $upce_parities[$code[1]][$r];
1533 for ($i = 0; $i < 6; ++$i) {
1534 $seq .= $codes[$p[$i]][$upce_code[$i]];
1535 }
1536 $seq .= '010101';
1537 // right guard bar
1538 } else {
1539 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1540 $half_len = \intval(\ceil($len / 2));
1541 if ($len == 8) {
1542 for ($i = 0; $i < $half_len; ++$i) {
1543 $seq .= $codes['A'][$code[$i]];
1544 }
1545 } else {
1546 $p = $parities[$code[0]];
1547 for ($i = 1; $i < $half_len; ++$i) {
1548 $seq .= $codes[$p[$i - 1]][$code[$i]];
1549 }
1550 }
1551 $seq .= '01010';
1552 // center guard bar
1553 for ($i = $half_len; $i < $len; ++$i) {
1554 $seq .= $codes['C'][$code[$i]];
1555 }
1556 $seq .= '101';
1557 // right guard bar
1558 }
1559 $clen = \strlen($seq);
1560 $w = 0;
1561 for ($i = 0; $i < $clen; ++$i) {
1562 $w += 1;
1563 if ($i == $clen - 1 or $i < $clen - 1 and $seq[$i] != $seq[$i + 1]) {
1564 if ($seq[$i] == '1') {
1565 $t = \true;
1566 // bar
1567 } else {
1568 $t = \false;
1569 // space
1570 }
1571 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1572 $bararray['maxw'] += $w;
1573 ++$k;
1574 $w = 0;
1575 }
1576 }
1577 return $bararray;
1578 }
1579 /**
1580 * UPC-Based Extensions
1581 * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
1582 * 5-Digit Ext.: Used to mark suggested retail price of books
1583 * @param string $code code to represent.
1584 * @param string $len barcode type: 2 = 2-Digit, 5 = 5-Digit
1585 * @return array barcode representation.
1586 * @protected
1587 */
1588 protected function barcode_eanext($code, $len = 5)
1589 {
1590 //Padding
1591 $code = \str_pad($code, $len, '0', \STR_PAD_LEFT);
1592 // calculate check digit
1593 if ($len == 2) {
1594 $r = $code % 4;
1595 } elseif ($len == 5) {
1596 $r = 3 * ($code[0] + $code[2] + $code[4]) + 9 * ($code[1] + $code[3]);
1597 $r %= 10;
1598 } else {
1599 return \false;
1600 }
1601 //Convert digits to bars
1602 $codes = array('A' => array(
1603 // left odd parity
1604 '0' => '0001101',
1605 '1' => '0011001',
1606 '2' => '0010011',
1607 '3' => '0111101',
1608 '4' => '0100011',
1609 '5' => '0110001',
1610 '6' => '0101111',
1611 '7' => '0111011',
1612 '8' => '0110111',
1613 '9' => '0001011',
1614 ), 'B' => array(
1615 // left even parity
1616 '0' => '0100111',
1617 '1' => '0110011',
1618 '2' => '0011011',
1619 '3' => '0100001',
1620 '4' => '0011101',
1621 '5' => '0111001',
1622 '6' => '0000101',
1623 '7' => '0010001',
1624 '8' => '0001001',
1625 '9' => '0010111',
1626 ));
1627 $parities = array();
1628 $parities[2] = array('0' => array('A', 'A'), '1' => array('A', 'B'), '2' => array('B', 'A'), '3' => array('B', 'B'));
1629 $parities[5] = array('0' => array('B', 'B', 'A', 'A', 'A'), '1' => array('B', 'A', 'B', 'A', 'A'), '2' => array('B', 'A', 'A', 'B', 'A'), '3' => array('B', 'A', 'A', 'A', 'B'), '4' => array('A', 'B', 'B', 'A', 'A'), '5' => array('A', 'A', 'B', 'B', 'A'), '6' => array('A', 'A', 'A', 'B', 'B'), '7' => array('A', 'B', 'A', 'B', 'A'), '8' => array('A', 'B', 'A', 'A', 'B'), '9' => array('A', 'A', 'B', 'A', 'B'));
1630 $p = $parities[$len][$r];
1631 $seq = '1011';
1632 // left guard bar
1633 $seq .= $codes[$p[0]][$code[0]];
1634 for ($i = 1; $i < $len; ++$i) {
1635 $seq .= '01';
1636 // separator
1637 $seq .= $codes[$p[$i]][$code[$i]];
1638 }
1639 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1640 return $this->binseq_to_array($seq, $bararray);
1641 }
1642 /**
1643 * POSTNET and PLANET barcodes.
1644 * Used by U.S. Postal Service for automated mail sorting
1645 * @param string $code zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
1646 * @param boolean $planet if true print the PLANET barcode, otherwise print POSTNET
1647 * @return array barcode representation.
1648 * @protected
1649 */
1650 protected function barcode_postnet($code, $planet = \false)
1651 {
1652 // bar length
1653 if ($planet) {
1654 $barlen = array(0 => array(1, 1, 2, 2, 2), 1 => array(2, 2, 2, 1, 1), 2 => array(2, 2, 1, 2, 1), 3 => array(2, 2, 1, 1, 2), 4 => array(2, 1, 2, 2, 1), 5 => array(2, 1, 2, 1, 2), 6 => array(2, 1, 1, 2, 2), 7 => array(1, 2, 2, 2, 1), 8 => array(1, 2, 2, 1, 2), 9 => array(1, 2, 1, 2, 2));
1655 } else {
1656 $barlen = array(0 => array(2, 2, 1, 1, 1), 1 => array(1, 1, 1, 2, 2), 2 => array(1, 1, 2, 1, 2), 3 => array(1, 1, 2, 2, 1), 4 => array(1, 2, 1, 1, 2), 5 => array(1, 2, 1, 2, 1), 6 => array(1, 2, 2, 1, 1), 7 => array(2, 1, 1, 1, 2), 8 => array(2, 1, 1, 2, 1), 9 => array(2, 1, 2, 1, 1));
1657 }
1658 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1659 $k = 0;
1660 $code = \str_replace('-', '', $code);
1661 $code = \str_replace(' ', '', $code);
1662 $len = \strlen($code);
1663 // calculate checksum
1664 $sum = 0;
1665 for ($i = 0; $i < $len; ++$i) {
1666 $sum += \intval($code[$i]);
1667 }
1668 $chkd = $sum % 10;
1669 if ($chkd > 0) {
1670 $chkd = 10 - $chkd;
1671 }
1672 $code .= $chkd;
1673 $len = \strlen($code);
1674 // start bar
1675 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1676 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1677 $bararray['maxw'] += 2;
1678 for ($i = 0; $i < $len; ++$i) {
1679 for ($j = 0; $j < 5; ++$j) {
1680 $h = $barlen[$code[$i]][$j];
1681 $p = \floor(1 / $h);
1682 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1683 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1684 $bararray['maxw'] += 2;
1685 }
1686 }
1687 // end bar
1688 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1689 $bararray['maxw'] += 1;
1690 return $bararray;
1691 }
1692 /**
1693 * RMS4CC - CBC - KIX
1694 * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
1695 * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
1696 * @param string $code code to print
1697 * @param boolean $kix if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the code.
1698 * @return array barcode representation.
1699 * @protected
1700 */
1701 protected function barcode_rms4cc($code, $kix = \false)
1702 {
1703 $notkix = !$kix;
1704 // bar mode
1705 // 1 = pos 1, length 2
1706 // 2 = pos 1, length 3
1707 // 3 = pos 2, length 1
1708 // 4 = pos 2, length 2
1709 $barmode = array('0' => array(3, 3, 2, 2), '1' => array(3, 4, 1, 2), '2' => array(3, 4, 2, 1), '3' => array(4, 3, 1, 2), '4' => array(4, 3, 2, 1), '5' => array(4, 4, 1, 1), '6' => array(3, 1, 4, 2), '7' => array(3, 2, 3, 2), '8' => array(3, 2, 4, 1), '9' => array(4, 1, 3, 2), 'A' => array(4, 1, 4, 1), 'B' => array(4, 2, 3, 1), 'C' => array(3, 1, 2, 4), 'D' => array(3, 2, 1, 4), 'E' => array(3, 2, 2, 3), 'F' => array(4, 1, 1, 4), 'G' => array(4, 1, 2, 3), 'H' => array(4, 2, 1, 3), 'I' => array(1, 3, 4, 2), 'J' => array(1, 4, 3, 2), 'K' => array(1, 4, 4, 1), 'L' => array(2, 3, 3, 2), 'M' => array(2, 3, 4, 1), 'N' => array(2, 4, 3, 1), 'O' => array(1, 3, 2, 4), 'P' => array(1, 4, 1, 4), 'Q' => array(1, 4, 2, 3), 'R' => array(2, 3, 1, 4), 'S' => array(2, 3, 2, 3), 'T' => array(2, 4, 1, 3), 'U' => array(1, 1, 4, 4), 'V' => array(1, 2, 3, 4), 'W' => array(1, 2, 4, 3), 'X' => array(2, 1, 3, 4), 'Y' => array(2, 1, 4, 3), 'Z' => array(2, 2, 3, 3));
1710 $code = \strtoupper($code);
1711 $len = \strlen($code);
1712 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
1713 if ($notkix) {
1714 // table for checksum calculation (row,col)
1715 $checktable = array('0' => array(1, 1), '1' => array(1, 2), '2' => array(1, 3), '3' => array(1, 4), '4' => array(1, 5), '5' => array(1, 0), '6' => array(2, 1), '7' => array(2, 2), '8' => array(2, 3), '9' => array(2, 4), 'A' => array(2, 5), 'B' => array(2, 0), 'C' => array(3, 1), 'D' => array(3, 2), 'E' => array(3, 3), 'F' => array(3, 4), 'G' => array(3, 5), 'H' => array(3, 0), 'I' => array(4, 1), 'J' => array(4, 2), 'K' => array(4, 3), 'L' => array(4, 4), 'M' => array(4, 5), 'N' => array(4, 0), 'O' => array(5, 1), 'P' => array(5, 2), 'Q' => array(5, 3), 'R' => array(5, 4), 'S' => array(5, 5), 'T' => array(5, 0), 'U' => array(0, 1), 'V' => array(0, 2), 'W' => array(0, 3), 'X' => array(0, 4), 'Y' => array(0, 5), 'Z' => array(0, 0));
1716 $row = 0;
1717 $col = 0;
1718 for ($i = 0; $i < $len; ++$i) {
1719 $row += $checktable[$code[$i]][0];
1720 $col += $checktable[$code[$i]][1];
1721 }
1722 $row %= 6;
1723 $col %= 6;
1724 $chk = \array_keys($checktable, array($row, $col));
1725 $code .= $chk[0];
1726 ++$len;
1727 }
1728 $k = 0;
1729 if ($notkix) {
1730 // start bar
1731 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1732 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1733 $bararray['maxw'] += 2;
1734 }
1735 for ($i = 0; $i < $len; ++$i) {
1736 for ($j = 0; $j < 4; ++$j) {
1737 switch ($barmode[$code[$i]][$j]) {
1738 case 1:
1739 $p = 0;
1740 $h = 2;
1741 break;
1742 case 2:
1743 $p = 0;
1744 $h = 3;
1745 break;
1746 case 3:
1747 $p = 1;
1748 $h = 1;
1749 break;
1750 case 4:
1751 $p = 1;
1752 $h = 2;
1753 break;
1754 }
1755 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1756 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1757 $bararray['maxw'] += 2;
1758 }
1759 }
1760 if ($notkix) {
1761 // stop bar
1762 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0);
1763 $bararray['maxw'] += 1;
1764 }
1765 return $bararray;
1766 }
1767 /**
1768 * CODABAR barcodes.
1769 * Older code often used in library systems, sometimes in blood banks
1770 * @param string $code code to represent.
1771 * @return array barcode representation.
1772 * @protected
1773 */
1774 protected function barcode_codabar($code)
1775 {
1776 $chr = array('0' => '11111221', '1' => '11112211', '2' => '11121121', '3' => '22111111', '4' => '11211211', '5' => '21111211', '6' => '12111121', '7' => '12112111', '8' => '12211111', '9' => '21121111', '-' => '11122111', '$' => '11221111', ':' => '21112121', '/' => '21211121', '.' => '21212111', '+' => '11222221', 'A' => '11221211', 'B' => '12121121', 'C' => '11121221', 'D' => '11122211');
1777 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1778 $k = 0;
1779 $w = 0;
1780 $seq = '';
1781 $code = 'A' . \strtoupper($code) . 'A';
1782 $len = \strlen($code);
1783 for ($i = 0; $i < $len; ++$i) {
1784 if (!isset($chr[$code[$i]])) {
1785 return \false;
1786 }
1787 $seq = $chr[$code[$i]];
1788 for ($j = 0; $j < 8; ++$j) {
1789 if ($j % 2 == 0) {
1790 $t = \true;
1791 // bar
1792 } else {
1793 $t = \false;
1794 // space
1795 }
1796 $w = (float) $seq[$j];
1797 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1798 $bararray['maxw'] += $w;
1799 ++$k;
1800 }
1801 }
1802 return $bararray;
1803 }
1804 /**
1805 * CODE11 barcodes.
1806 * Used primarily for labeling telecommunications equipment
1807 * @param string $code code to represent.
1808 * @return array barcode representation.
1809 * @protected
1810 */
1811 protected function barcode_code11($code)
1812 {
1813 $chr = array('0' => '111121', '1' => '211121', '2' => '121121', '3' => '221111', '4' => '112121', '5' => '212111', '6' => '122111', '7' => '111221', '8' => '211211', '9' => '211111', '-' => '112111', 'S' => '112211');
1814 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1815 $k = 0;
1816 $w = 0;
1817 $seq = '';
1818 $len = \strlen($code);
1819 // calculate check digit C
1820 $p = 1;
1821 $check = 0;
1822 for ($i = $len - 1; $i >= 0; --$i) {
1823 $digit = $code[$i];
1824 if ($digit == '-') {
1825 $dval = 10;
1826 } else {
1827 $dval = \intval($digit);
1828 }
1829 $check += $dval * $p;
1830 ++$p;
1831 if ($p > 10) {
1832 $p = 1;
1833 }
1834 }
1835 $check %= 11;
1836 if ($check == 10) {
1837 $check = '-';
1838 }
1839 $code .= $check;
1840 if ($len > 10) {
1841 // calculate check digit K
1842 $p = 1;
1843 $check = 0;
1844 for ($i = $len; $i >= 0; --$i) {
1845 $digit = $code[$i];
1846 if ($digit == '-') {
1847 $dval = 10;
1848 } else {
1849 $dval = \intval($digit);
1850 }
1851 $check += $dval * $p;
1852 ++$p;
1853 if ($p > 9) {
1854 $p = 1;
1855 }
1856 }
1857 $check %= 11;
1858 $code .= $check;
1859 ++$len;
1860 }
1861 $code = 'S' . $code . 'S';
1862 $len += 3;
1863 for ($i = 0; $i < $len; ++$i) {
1864 if (!isset($chr[$code[$i]])) {
1865 return \false;
1866 }
1867 $seq = $chr[$code[$i]];
1868 for ($j = 0; $j < 6; ++$j) {
1869 if ($j % 2 == 0) {
1870 $t = \true;
1871 // bar
1872 } else {
1873 $t = \false;
1874 // space
1875 }
1876 $w = (float) $seq[$j];
1877 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1878 $bararray['maxw'] += $w;
1879 ++$k;
1880 }
1881 }
1882 return $bararray;
1883 }
1884 /**
1885 * Pharmacode
1886 * Contains digits (0 to 9)
1887 * @param string $code code to represent.
1888 * @return array barcode representation.
1889 * @protected
1890 */
1891 protected function barcode_pharmacode($code)
1892 {
1893 $seq = '';
1894 $code = \intval($code);
1895 while ($code > 0) {
1896 if ($code % 2 == 0) {
1897 $seq .= '11100';
1898 $code -= 2;
1899 } else {
1900 $seq .= '100';
1901 $code -= 1;
1902 }
1903 $code /= 2;
1904 }
1905 $seq = \substr($seq, 0, -2);
1906 $seq = \strrev($seq);
1907 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1908 return $this->binseq_to_array($seq, $bararray);
1909 }
1910 /**
1911 * Pharmacode two-track
1912 * Contains digits (0 to 9)
1913 * @param string $code code to represent.
1914 * @return array barcode representation.
1915 * @protected
1916 */
1917 protected function barcode_pharmacode2t($code)
1918 {
1919 $seq = '';
1920 $code = \intval($code);
1921 do {
1922 switch ($code % 3) {
1923 case 0:
1924 $seq .= '3';
1925 $code = ($code - 3) / 3;
1926 break;
1927 case 1:
1928 $seq .= '1';
1929 $code = ($code - 1) / 3;
1930 break;
1931 case 2:
1932 $seq .= '2';
1933 $code = ($code - 2) / 3;
1934 break;
1935 }
1936 } while ($code != 0);
1937 $seq = \strrev($seq);
1938 $k = 0;
1939 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1940 $len = \strlen($seq);
1941 for ($i = 0; $i < $len; ++$i) {
1942 switch ($seq[$i]) {
1943 case '1':
1944 $p = 1;
1945 $h = 1;
1946 break;
1947 case '2':
1948 $p = 0;
1949 $h = 1;
1950 break;
1951 case '3':
1952 $p = 0;
1953 $h = 2;
1954 break;
1955 }
1956 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1957 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1958 $bararray['maxw'] += 2;
1959 }
1960 unset($bararray['bcode'][$k - 1]);
1961 --$bararray['maxw'];
1962 return $bararray;
1963 }
1964 /**
1965 * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
1966 * (requires PHP bcmath extension)
1967 * Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
1968 * 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>
1969 * @param string $code code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
1970 * @return array barcode representation.
1971 * @protected
1972 */
1973 protected function barcode_imb($code)
1974 {
1975 $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);
1976 $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);
1977 $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);
1978 $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);
1979 $code_arr = \explode('-', $code);
1980 $tracking_number = $code_arr[0];
1981 if (isset($code_arr[1])) {
1982 $routing_code = $code_arr[1];
1983 } else {
1984 $routing_code = '';
1985 }
1986 // Conversion of Routing Code
1987 switch (\strlen($routing_code)) {
1988 case 0:
1989 $binary_code = 0;
1990 break;
1991 case 5:
1992 $binary_code = \bcadd($routing_code, '1');
1993 break;
1994 case 9:
1995 $binary_code = \bcadd($routing_code, '100001');
1996 break;
1997 case 11:
1998 $binary_code = \bcadd($routing_code, '1000100001');
1999 break;
2000 default:
2001 return \false;
2002 break;
2003 }
2004 $binary_code = \bcmul($binary_code, 10);
2005 $binary_code = \bcadd($binary_code, $tracking_number[0]);
2006 $binary_code = \bcmul($binary_code, 5);
2007 $binary_code = \bcadd($binary_code, $tracking_number[1]);
2008 $binary_code .= \substr($tracking_number, 2, 18);
2009 // convert to hexadecimal
2010 $binary_code = $this->dec_to_hex($binary_code);
2011 // pad to get 13 bytes
2012 $binary_code = \str_pad($binary_code, 26, '0', \STR_PAD_LEFT);
2013 // convert string to array of bytes
2014 $binary_code_arr = \chunk_split($binary_code, 2, "\r");
2015 $binary_code_arr = \substr($binary_code_arr, 0, -1);
2016 $binary_code_arr = \explode("\r", $binary_code_arr);
2017 // calculate frame check sequence
2018 $fcs = $this->imb_crc11fcs($binary_code_arr);
2019 // exclude first 2 bits from first byte
2020 $first_byte = \sprintf('%2s', \dechex(\hexdec($binary_code_arr[0]) << 2 >> 2));
2021 $binary_code_102bit = $first_byte . \substr($binary_code, 2);
2022 // convert binary data to codewords
2023 $codewords = array();
2024 $data = $this->hex_to_dec($binary_code_102bit);
2025 $codewords[0] = \bcmod($data, 636) * 2;
2026 $data = \bcdiv($data, 636);
2027 for ($i = 1; $i < 9; ++$i) {
2028 $codewords[$i] = \bcmod($data, 1365);
2029 $data = \bcdiv($data, 1365);
2030 }
2031 $codewords[9] = $data;
2032 if ($fcs >> 10 == 1) {
2033 $codewords[9] += 659;
2034 }
2035 // generate lookup tables
2036 $table2of13 = $this->imb_tables(2, 78);
2037 $table5of13 = $this->imb_tables(5, 1287);
2038 // convert codewords to characters
2039 $characters = array();
2040 $bitmask = 512;
2041 foreach ($codewords as $k => $val) {
2042 if ($val <= 1286) {
2043 $chrcode = $table5of13[$val];
2044 } else {
2045 $chrcode = $table2of13[$val - 1287];
2046 }
2047 if (($fcs & $bitmask) > 0) {
2048 // bitwise invert
2049 $chrcode = ~$chrcode & 8191;
2050 }
2051 $characters[] = $chrcode;
2052 $bitmask /= 2;
2053 }
2054 $characters = \array_reverse($characters);
2055 // build bars
2056 $k = 0;
2057 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
2058 for ($i = 0; $i < 65; ++$i) {
2059 $asc = ($characters[$asc_chr[$i]] & \pow(2, $asc_pos[$i])) > 0;
2060 $dsc = ($characters[$dsc_chr[$i]] & \pow(2, $dsc_pos[$i])) > 0;
2061 if ($asc and $dsc) {
2062 // full bar (F)
2063 $p = 0;
2064 $h = 3;
2065 } elseif ($asc) {
2066 // ascender (A)
2067 $p = 0;
2068 $h = 2;
2069 } elseif ($dsc) {
2070 // descender (D)
2071 $p = 1;
2072 $h = 2;
2073 } else {
2074 // tracker (T)
2075 $p = 1;
2076 $h = 1;
2077 }
2078 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2079 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2080 $bararray['maxw'] += 2;
2081 }
2082 unset($bararray['bcode'][$k - 1]);
2083 --$bararray['maxw'];
2084 return $bararray;
2085 }
2086 /**
2087 * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
2088 *
2089 * @param string $code pre-formatted IMB barcode (65 chars "FADT")
2090 * @return array barcode representation.
2091 * @protected
2092 */
2093 protected function barcode_imb_pre($code)
2094 {
2095 if (!\preg_match('/^[fadtFADT]{65}$/', $code) == 1) {
2096 return \false;
2097 }
2098 $characters = \str_split(\strtolower($code), 1);
2099 // build bars
2100 $k = 0;
2101 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
2102 for ($i = 0; $i < 65; ++$i) {
2103 switch ($characters[$i]) {
2104 case 'f':
2105 // full bar
2106 $p = 0;
2107 $h = 3;
2108 break;
2109 case 'a':
2110 // ascender
2111 $p = 0;
2112 $h = 2;
2113 break;
2114 case 'd':
2115 // descender
2116 $p = 1;
2117 $h = 2;
2118 break;
2119 case 't':
2120 // tracker (short)
2121 $p = 1;
2122 $h = 1;
2123 break;
2124 }
2125 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2126 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2127 $bararray['maxw'] += 2;
2128 }
2129 unset($bararray['bcode'][$k - 1]);
2130 --$bararray['maxw'];
2131 return $bararray;
2132 }
2133 /**
2134 * Convert large integer number to hexadecimal representation.
2135 * (requires PHP bcmath extension)
2136 * @param string $number number to convert specified as a string
2137 * @return string hexadecimal representation
2138 */
2139 public function dec_to_hex($number)
2140 {
2141 $i = 0;
2142 $hex = array();
2143 if ($number == 0) {
2144 return '00';
2145 }
2146 while ($number > 0) {
2147 if ($number == 0) {
2148 \array_push($hex, '0');
2149 } else {
2150 \array_push($hex, \strtoupper(\dechex(\bcmod($number, '16'))));
2151 $number = \bcdiv($number, '16', 0);
2152 }
2153 }
2154 $hex = \array_reverse($hex);
2155 return \implode($hex);
2156 }
2157 /**
2158 * Convert large hexadecimal number to decimal representation (string).
2159 * (requires PHP bcmath extension)
2160 * @param string $hex hexadecimal number to convert specified as a string
2161 * @return string hexadecimal representation
2162 */
2163 public function hex_to_dec($hex)
2164 {
2165 $dec = 0;
2166 $bitval = 1;
2167 $len = \strlen($hex);
2168 for ($pos = $len - 1; $pos >= 0; --$pos) {
2169 $dec = \bcadd($dec, \bcmul(\hexdec($hex[$pos]), $bitval));
2170 $bitval = \bcmul($bitval, 16);
2171 }
2172 return $dec;
2173 }
2174 /**
2175 * Intelligent Mail Barcode calculation of Frame Check Sequence
2176 * @param string $code_arr array of hexadecimal values (13 bytes holding 102 bits right justified).
2177 * @return int 11 bit Frame Check Sequence as integer (decimal base)
2178 * @protected
2179 */
2180 protected function imb_crc11fcs($code_arr)
2181 {
2182 $genpoly = 0xf35;
2183 // generator polynomial
2184 $fcs = 0x7ff;
2185 // Frame Check Sequence
2186 // do most significant byte skipping the 2 most significant bits
2187 $data = \hexdec($code_arr[0]) << 5;
2188 for ($bit = 2; $bit < 8; ++$bit) {
2189 if (($fcs ^ $data) & 0x400) {
2190 $fcs = $fcs << 1 ^ $genpoly;
2191 } else {
2192 $fcs = $fcs << 1;
2193 }
2194 $fcs &= 0x7ff;
2195 $data <<= 1;
2196 }
2197 // do rest of bytes
2198 for ($byte = 1; $byte < 13; ++$byte) {
2199 $data = \hexdec($code_arr[$byte]) << 3;
2200 for ($bit = 0; $bit < 8; ++$bit) {
2201 if (($fcs ^ $data) & 0x400) {
2202 $fcs = $fcs << 1 ^ $genpoly;
2203 } else {
2204 $fcs = $fcs << 1;
2205 }
2206 $fcs &= 0x7ff;
2207 $data <<= 1;
2208 }
2209 }
2210 return $fcs;
2211 }
2212 /**
2213 * Reverse unsigned short value
2214 * @param int $num value to reversr
2215 * @return int reversed value
2216 * @protected
2217 */
2218 protected function imb_reverse_us($num)
2219 {
2220 $rev = 0;
2221 for ($i = 0; $i < 16; ++$i) {
2222 $rev <<= 1;
2223 $rev |= $num & 1;
2224 $num >>= 1;
2225 }
2226 return $rev;
2227 }
2228 /**
2229 * generate Nof13 tables used for Intelligent Mail Barcode
2230 * @param int $n is the type of table: 2 for 2of13 table, 5 for 5of13table
2231 * @param int $size size of table (78 for n=2 and 1287 for n=5)
2232 * @return array requested table
2233 * @protected
2234 */
2235 protected function imb_tables($n, $size)
2236 {
2237 $table = array();
2238 $lli = 0;
2239 // LUT lower index
2240 $lui = $size - 1;
2241 // LUT upper index
2242 for ($count = 0; $count < 8192; ++$count) {
2243 $bit_count = 0;
2244 for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
2245 $bit_count += \intval(($count & 1 << $bit_index) != 0);
2246 }
2247 // if we don't have the right number of bits on, go on to the next value
2248 if ($bit_count == $n) {
2249 $reverse = $this->imb_reverse_us($count) >> 3;
2250 // if the reverse is less than count, we have already visited this pair before
2251 if ($reverse >= $count) {
2252 // If count is symmetric, place it at the first free slot from the end of the list.
2253 // 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
2254 if ($reverse == $count) {
2255 $table[$lui] = $count;
2256 --$lui;
2257 } else {
2258 $table[$lli] = $count;
2259 ++$lli;
2260 $table[$lli] = $reverse;
2261 ++$lli;
2262 }
2263 }
2264 }
2265 }
2266 return $table;
2267 }
2268 }
2269 // end of class
2270 //============================================================+
2271 // END OF FILE
2272 //============================================================+
2273 }
2274