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