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