PluginProbe
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin / 1.7.9
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin v1.7.9
trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 All 71 releases
pdf-print / mpdf / classes / barcode.php

barcode.php in PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin 1.7.9, at mpdf/classes/barcode.php

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