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