include/barcodes/datamatrix.php Quellcode

datamatrix.php
gehe zur Dokumentation dieser Datei
1 <?php
2 //============================================================+
3 // File name : datamatrix.php
4 // Version : 1.0.004
5 // Begin : 2010-06-07
6 // Last Update : 2013-12-12
7 // Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8 // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9 // -------------------------------------------------------------------
10 // Copyright (C) 2010-2012 Nicola Asuni - Tecnick.com LTD
11 //
12 // This file is part of TCPDF software library.
13 //
14 // TCPDF is free software: you can redistribute it and/or modify it
15 // under the terms of the GNU Lesser General Public License as
16 // published by the Free Software Foundation, either version 3 of the
17 // License, or (at your option) any later version.
18 //
19 // TCPDF is distributed in the hope that it will be useful, but
20 // WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 // See the GNU Lesser General Public License for more details.
23 //
24 // You should have received a copy of the GNU Lesser General Public License
25 // along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26 //
27 // See LICENSE.TXT file for more information.
28 // -------------------------------------------------------------------
29 //
30 // DESCRIPTION :
31 //
32 // Class to create DataMatrix ECC 200 barcode arrays for TCPDF class.
33 // DataMatrix (ISO/IEC 16022:2006) is a 2-dimensional bar code.
34 //============================================================+
35 
46 // custom definitions
47 if (!defined('DATAMATRIXDEFS')) {
48 
52  define('DATAMATRIXDEFS', true);
53 
54  // -----------------------------------------------------
55 
56 } // end of custom definitions
57 
58 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
59 
60 
64 define('ENC_ASCII', 0);
65 
69 define('ENC_C40', 1);
70 
74 define('ENC_TXT', 2);
75 
79 define('ENC_X12', 3);
80 
84 define('ENC_EDF', 4);
85 
89 define('ENC_BASE256', 5);
90 
94 define('ENC_ASCII_EXT', 6);
95 
99 define('ENC_ASCII_NUM', 7);
100 
110 class Datamatrix {
111 
116  protected $barcode_array = array();
117 
122  protected $last_enc = ENC_ASCII;
123 
145  protected $symbattr = array(
146  // square form ---------------------------------------------------------------------------------------
147  array(0x00a,0x00a,0x008,0x008,0x00a,0x00a,0x008,0x008,0x001,0x001,0x001,0x003,0x005,0x001,0x003,0x005), // 10x10
148  array(0x00c,0x00c,0x00a,0x00a,0x00c,0x00c,0x00a,0x00a,0x001,0x001,0x001,0x005,0x007,0x001,0x005,0x007), // 12x12
149  array(0x00e,0x00e,0x00c,0x00c,0x00e,0x00e,0x00c,0x00c,0x001,0x001,0x001,0x008,0x00a,0x001,0x008,0x00a), // 14x14
150  array(0x010,0x010,0x00e,0x00e,0x010,0x010,0x00e,0x00e,0x001,0x001,0x001,0x00c,0x00c,0x001,0x00c,0x00c), // 16x16
151  array(0x012,0x012,0x010,0x010,0x012,0x012,0x010,0x010,0x001,0x001,0x001,0x012,0x00e,0x001,0x012,0x00e), // 18x18
152  array(0x014,0x014,0x012,0x012,0x014,0x014,0x012,0x012,0x001,0x001,0x001,0x016,0x012,0x001,0x016,0x012), // 20x20
153  array(0x016,0x016,0x014,0x014,0x016,0x016,0x014,0x014,0x001,0x001,0x001,0x01e,0x014,0x001,0x01e,0x014), // 22x22
154  array(0x018,0x018,0x016,0x016,0x018,0x018,0x016,0x016,0x001,0x001,0x001,0x024,0x018,0x001,0x024,0x018), // 24x24
155  array(0x01a,0x01a,0x018,0x018,0x01a,0x01a,0x018,0x018,0x001,0x001,0x001,0x02c,0x01c,0x001,0x02c,0x01c), // 26x26
156  array(0x020,0x020,0x01c,0x01c,0x010,0x010,0x00e,0x00e,0x002,0x002,0x004,0x03e,0x024,0x001,0x03e,0x024), // 32x32
157  array(0x024,0x024,0x020,0x020,0x012,0x012,0x010,0x010,0x002,0x002,0x004,0x056,0x02a,0x001,0x056,0x02a), // 36x36
158  array(0x028,0x028,0x024,0x024,0x014,0x014,0x012,0x012,0x002,0x002,0x004,0x072,0x030,0x001,0x072,0x030), // 40x40
159  array(0x02c,0x02c,0x028,0x028,0x016,0x016,0x014,0x014,0x002,0x002,0x004,0x090,0x038,0x001,0x090,0x038), // 44x44
160  array(0x030,0x030,0x02c,0x02c,0x018,0x018,0x016,0x016,0x002,0x002,0x004,0x0ae,0x044,0x001,0x0ae,0x044), // 48x48
161  array(0x034,0x034,0x030,0x030,0x01a,0x01a,0x018,0x018,0x002,0x002,0x004,0x0cc,0x054,0x002,0x066,0x02a), // 52x52
162  array(0x040,0x040,0x038,0x038,0x010,0x010,0x00e,0x00e,0x004,0x004,0x010,0x118,0x070,0x002,0x08c,0x038), // 64x64
163  array(0x048,0x048,0x040,0x040,0x012,0x012,0x010,0x010,0x004,0x004,0x010,0x170,0x090,0x004,0x05c,0x024), // 72x72
164  array(0x050,0x050,0x048,0x048,0x014,0x014,0x012,0x012,0x004,0x004,0x010,0x1c8,0x0c0,0x004,0x072,0x030), // 80x80
165  array(0x058,0x058,0x050,0x050,0x016,0x016,0x014,0x014,0x004,0x004,0x010,0x240,0x0e0,0x004,0x090,0x038), // 88x88
166  array(0x060,0x060,0x058,0x058,0x018,0x018,0x016,0x016,0x004,0x004,0x010,0x2b8,0x110,0x004,0x0ae,0x044), // 96x96
167  array(0x068,0x068,0x060,0x060,0x01a,0x01a,0x018,0x018,0x004,0x004,0x010,0x330,0x150,0x006,0x088,0x038), // 104x104
168  array(0x078,0x078,0x06c,0x06c,0x014,0x014,0x012,0x012,0x006,0x006,0x024,0x41a,0x198,0x006,0x0af,0x044), // 120x120
169  array(0x084,0x084,0x078,0x078,0x016,0x016,0x014,0x014,0x006,0x006,0x024,0x518,0x1f0,0x008,0x0a3,0x03e), // 132x132
170  array(0x090,0x090,0x084,0x084,0x018,0x018,0x016,0x016,0x006,0x006,0x024,0x616,0x26c,0x00a,0x09c,0x03e), // 144x144
171  // rectangular form (currently unused) ---------------------------------------------------------------------------
172  array(0x008,0x012,0x006,0x010,0x008,0x012,0x006,0x010,0x001,0x001,0x001,0x005,0x007,0x001,0x005,0x007), // 8x18
173  array(0x008,0x020,0x006,0x01c,0x008,0x010,0x006,0x00e,0x001,0x002,0x002,0x00a,0x00b,0x001,0x00a,0x00b), // 8x32
174  array(0x00c,0x01a,0x00a,0x018,0x00c,0x01a,0x00a,0x018,0x001,0x001,0x001,0x010,0x00e,0x001,0x010,0x00e), // 12x26
175  array(0x00c,0x024,0x00a,0x020,0x00c,0x012,0x00a,0x010,0x001,0x002,0x002,0x00c,0x012,0x001,0x00c,0x012), // 12x36
176  array(0x010,0x024,0x00e,0x020,0x010,0x012,0x00e,0x010,0x001,0x002,0x002,0x020,0x018,0x001,0x020,0x018), // 16x36
177  array(0x010,0x030,0x00e,0x02c,0x010,0x018,0x00e,0x016,0x001,0x002,0x002,0x031,0x01c,0x001,0x031,0x01c) // 16x48
178  );
179 
184  protected $chset_id = array(ENC_C40 => 'C40', ENC_TXT => 'TXT', ENC_X12 =>'X12');
185 
190  protected $chset = array(
191  'C40' => array( // Basic set for C40 ----------------------------------------------------------------------------
192  'S1'=>0x00,'S2'=>0x01,'S3'=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, //
193  0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x41=>0x0e,0x42=>0x0f,0x43=>0x10,0x44=>0x11,0x45=>0x12,0x46=>0x13, //
194  0x47=>0x14,0x48=>0x15,0x49=>0x16,0x4a=>0x17,0x4b=>0x18,0x4c=>0x19,0x4d=>0x1a,0x4e=>0x1b,0x4f=>0x1c,0x50=>0x1d, //
195  0x51=>0x1e,0x52=>0x1f,0x53=>0x20,0x54=>0x21,0x55=>0x22,0x56=>0x23,0x57=>0x24,0x58=>0x25,0x59=>0x26,0x5a=>0x27),//
196  'TXT' => array( // Basic set for TEXT ---------------------------------------------------------------------------
197  'S1'=>0x00,'S2'=>0x01,'S3'=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, //
198  0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x61=>0x0e,0x62=>0x0f,0x63=>0x10,0x64=>0x11,0x65=>0x12,0x66=>0x13, //
199  0x67=>0x14,0x68=>0x15,0x69=>0x16,0x6a=>0x17,0x6b=>0x18,0x6c=>0x19,0x6d=>0x1a,0x6e=>0x1b,0x6f=>0x1c,0x70=>0x1d, //
200  0x71=>0x1e,0x72=>0x1f,0x73=>0x20,0x74=>0x21,0x75=>0x22,0x76=>0x23,0x77=>0x24,0x78=>0x25,0x79=>0x26,0x7a=>0x27),//
201  'SH1' => array( // Shift 1 set ----------------------------------------------------------------------------------
202  0x00=>0x00,0x01=>0x01,0x02=>0x02,0x03=>0x03,0x04=>0x04,0x05=>0x05,0x06=>0x06,0x07=>0x07,0x08=>0x08,0x09=>0x09, //
203  0x0a=>0x0a,0x0b=>0x0b,0x0c=>0x0c,0x0d=>0x0d,0x0e=>0x0e,0x0f=>0x0f,0x10=>0x10,0x11=>0x11,0x12=>0x12,0x13=>0x13, //
204  0x14=>0x14,0x15=>0x15,0x16=>0x16,0x17=>0x17,0x18=>0x18,0x19=>0x19,0x1a=>0x1a,0x1b=>0x1b,0x1c=>0x1c,0x1d=>0x1d, //
205  0x1e=>0x1e,0x1f=>0x1f), //
206  'SH2' => array( // Shift 2 set ----------------------------------------------------------------------------------
207  0x21=>0x00,0x22=>0x01,0x23=>0x02,0x24=>0x03,0x25=>0x04,0x26=>0x05,0x27=>0x06,0x28=>0x07,0x29=>0x08,0x2a=>0x09, //
208  0x2b=>0x0a,0x2c=>0x0b,0x2d=>0x0c,0x2e=>0x0d,0x2f=>0x0e,0x3a=>0x0f,0x3b=>0x10,0x3c=>0x11,0x3d=>0x12,0x3e=>0x13, //
209  0x3f=>0x14,0x40=>0x15,0x5b=>0x16,0x5c=>0x17,0x5d=>0x18,0x5e=>0x19,0x5f=>0x1a,'F1'=>0x1b,'US'=>0x1e), //
210  'S3C' => array( // Shift 3 set for C40 --------------------------------------------------------------------------
211  0x60=>0x00,0x61=>0x01,0x62=>0x02,0x63=>0x03,0x64=>0x04,0x65=>0x05,0x66=>0x06,0x67=>0x07,0x68=>0x08,0x69=>0x09, //
212  0x6a=>0x0a,0x6b=>0x0b,0x6c=>0x0c,0x6d=>0x0d,0x6e=>0x0e,0x6f=>0x0f,0x70=>0x10,0x71=>0x11,0x72=>0x12,0x73=>0x13, //
213  0x74=>0x14,0x75=>0x15,0x76=>0x16,0x77=>0x17,0x78=>0x18,0x79=>0x19,0x7a=>0x1a,0x7b=>0x1b,0x7c=>0x1c,0x7d=>0x1d, //
214  0x7e=>0x1e,0x7f=>0x1f),
215  'S3T' => array( // Shift 3 set for TEXT -------------------------------------------------------------------------
216  0x60=>0x00,0x41=>0x01,0x42=>0x02,0x43=>0x03,0x44=>0x04,0x45=>0x05,0x46=>0x06,0x47=>0x07,0x48=>0x08,0x49=>0x09, //
217  0x4a=>0x0a,0x4b=>0x0b,0x4c=>0x0c,0x4d=>0x0d,0x4e=>0x0e,0x4f=>0x0f,0x50=>0x10,0x51=>0x11,0x52=>0x12,0x53=>0x13, //
218  0x54=>0x14,0x55=>0x15,0x56=>0x16,0x57=>0x17,0x58=>0x18,0x59=>0x19,0x5a=>0x1a,0x7b=>0x1b,0x7c=>0x1c,0x7d=>0x1d, //
219  0x7e=>0x1e,0x7f=>0x1f), //
220  'X12' => array( // Set for X12 ----------------------------------------------------------------------------------
221  0x0d=>0x00,0x2a=>0x01,0x3e=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, //
222  0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x41=>0x0e,0x42=>0x0f,0x43=>0x10,0x44=>0x11,0x45=>0x12,0x46=>0x13, //
223  0x47=>0x14,0x48=>0x15,0x49=>0x16,0x4a=>0x17,0x4b=>0x18,0x4c=>0x19,0x4d=>0x1a,0x4e=>0x1b,0x4f=>0x1c,0x50=>0x1d, //
224  0x51=>0x1e,0x52=>0x1f,0x53=>0x20,0x54=>0x21,0x55=>0x22,0x56=>0x23,0x57=>0x24,0x58=>0x25,0x59=>0x26,0x5a=>0x27) //
225  );
226 
227 // -----------------------------------------------------------------------------
228 
235  public function __construct($code) {
236  $barcode_array = array();
237  if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
238  return false;
239  }
240  // get data codewords
241  $cw = $this->getHighLevelEncoding($code);
242  // number of data codewords
243  $nd = count($cw);
244  // check size
245  if ($nd > 1558) {
246  return false;
247  }
248  // get minimum required matrix size.
249  foreach ($this->symbattr as $params) {
250  if ($params[11] >= $nd) {
251  break;
252  }
253  }
254  if ($params[11] < $nd) {
255  // too much data
256  return false;
257  } elseif ($params[11] > $nd) {
258  // add padding
259  if ($this->last_enc == ENC_EDF) {
260  // switch to ASCII encoding
261  $cw[] = 124;
262  ++$nd;
263  } elseif (($this->last_enc != ENC_ASCII) AND ($this->last_enc != ENC_BASE256)) {
264  // switch to ASCII encoding
265  $cw[] = 254;
266  ++$nd;
267  }
268  if ($params[11] > $nd) {
269  // add first pad
270  $cw[] = 129;
271  ++$nd;
272  // add remaining pads
273  for ($i = $nd; $i < $params[11]; ++$i) {
274  $cw[] = $this->get253StateCodeword(129, $i);
275  }
276  }
277  }
278  // add error correction codewords
279  $cw = $this->getErrorCorrection($cw, $params[13], $params[14], $params[15]);
280  // initialize empty arrays
281  $grid = array_fill(0, ($params[2] * $params[3]), 0);
282  // get placement map
283  $places = $this->getPlacementMap($params[2], $params[3]);
284  // fill the grid with data
285  $grid = array();
286  $i = 0;
287  // region data row max index
288  $rdri = ($params[4] - 1);
289  // region data column max index
290  $rdci = ($params[5] - 1);
291  // for each vertical region
292  for ($vr = 0; $vr < $params[9]; ++$vr) {
293  // for each row on region
294  for ($r = 0; $r < $params[4]; ++$r) {
295  // get row
296  $row = (($vr * $params[4]) + $r);
297  // for each horizontal region
298  for ($hr = 0; $hr < $params[8]; ++$hr) {
299  // for each column on region
300  for ($c = 0; $c < $params[5]; ++$c) {
301  // get column
302  $col = (($hr * $params[5]) + $c);
303  // braw bits by case
304  if ($r == 0) {
305  // top finder pattern
306  if ($c % 2) {
307  $grid[$row][$col] = 0;
308  } else {
309  $grid[$row][$col] = 1;
310  }
311  } elseif ($r == $rdri) {
312  // bottom finder pattern
313  $grid[$row][$col] = 1;
314  } elseif ($c == 0) {
315  // left finder pattern
316  $grid[$row][$col] = 1;
317  } elseif ($c == $rdci) {
318  // right finder pattern
319  if ($r % 2) {
320  $grid[$row][$col] = 1;
321  } else {
322  $grid[$row][$col] = 0;
323  }
324  } else { // data bit
325  if ($places[$i] < 2) {
326  $grid[$row][$col] = $places[$i];
327  } else {
328  // codeword ID
329  $cw_id = (floor($places[$i] / 10) - 1);
330  // codeword BIT mask
331  $cw_bit = pow(2, (8 - ($places[$i] % 10)));
332  $grid[$row][$col] = (($cw[$cw_id] & $cw_bit) == 0) ? 0 : 1;
333  }
334  ++$i;
335  }
336  }
337  }
338  }
339  }
340  $this->barcode_array['num_rows'] = $params[0];
341  $this->barcode_array['num_cols'] = $params[1];
342  $this->barcode_array['bcode'] = $grid;
343  }
344 
350  public function getBarcodeArray() {
351  return $this->barcode_array;
352  }
353 
364  protected function getGFProduct($a, $b, $log, $alog, $gf) {
365  if (($a == 0) OR ($b == 0)) {
366  return 0;
367  }
368  return ($alog[($log[$a] + $log[$b]) % ($gf - 1)]);
369  }
370 
382  protected function getErrorCorrection($wd, $nb, $nd, $nc, $gf=256, $pp=301) {
383  // generate the log ($log) and antilog ($alog) tables
384  $log[0] = 0;
385  $alog[0] = 1;
386  for ($i = 1; $i < $gf; ++$i) {
387  $alog[$i] = ($alog[($i - 1)] * 2);
388  if ($alog[$i] >= $gf) {
389  $alog[$i] ^= $pp;
390  }
391  $log[$alog[$i]] = $i;
392  }
393  ksort($log);
394  // generate the polynomial coefficients (c)
395  $c = array_fill(0, ($nc + 1), 0);
396  $c[0] = 1;
397  for ($i = 1; $i <= $nc; ++$i) {
398  $c[$i] = $c[($i-1)];
399  for ($j = ($i - 1); $j >= 1; --$j) {
400  $c[$j] = $c[($j - 1)] ^ $this->getGFProduct($c[$j], $alog[$i], $log, $alog, $gf);
401  }
402  $c[0] = $this->getGFProduct($c[0], $alog[$i], $log, $alog, $gf);
403  }
404  ksort($c);
405  // total number of data codewords
406  $num_wd = ($nb * $nd);
407  // total number of error codewords
408  $num_we = ($nb * $nc);
409  // for each block
410  for ($b = 0; $b < $nb; ++$b) {
411  // create interleaved data block
412  $block = array();
413  for ($n = $b; $n < $num_wd; $n += $nb) {
414  $block[] = $wd[$n];
415  }
416  // initialize error codewords
417  $we = array_fill(0, ($nc + 1), 0);
418  // calculate error correction codewords for this block
419  for ($i = 0; $i < $nd; ++$i) {
420  $k = ($we[0] ^ $block[$i]);
421  for ($j = 0; $j < $nc; ++$j) {
422  $we[$j] = ($we[($j + 1)] ^ $this->getGFProduct($k, $c[($nc - $j - 1)], $log, $alog, $gf));
423  }
424  }
425  // add error codewords at the end of data codewords
426  $j = 0;
427  for ($i = $b; $i < $num_we; $i += $nb) {
428  $wd[($num_wd + $i)] = $we[$j];
429  ++$j;
430  }
431  }
432  // reorder codewords
433  ksort($wd);
434  return $wd;
435  }
436 
444  protected function get253StateCodeword($cwpad, $cwpos) {
445  $pad = ($cwpad + (((149 * $cwpos) % 253) + 1));
446  if ($pad > 254) {
447  $pad -= 254;
448  }
449  return $pad;
450  }
451 
459  protected function get255StateCodeword($cwpad, $cwpos) {
460  $pad = ($cwpad + (((149 * $cwpos) % 255) + 1));
461  if ($pad > 255) {
462  $pad -= 256;
463  }
464  return $pad;
465  }
466 
474  protected function isCharMode($chr, $mode) {
475  $status = false;
476  switch ($mode) {
477  case ENC_ASCII: { // ASCII character 0 to 127
478  $status = (($chr >= 0) AND ($chr <= 127));
479  break;
480  }
481  case ENC_C40: { // Upper-case alphanumeric
482  $status = (($chr == 32) OR (($chr >= 48) AND ($chr <= 57)) OR (($chr >= 65) AND ($chr <= 90)));
483  break;
484  }
485  case ENC_TXT: { // Lower-case alphanumeric
486  $status = (($chr == 32) OR (($chr >= 48) AND ($chr <= 57)) OR (($chr >= 97) AND ($chr <= 122)));
487  break;
488  }
489  case ENC_X12: { // ANSI X12
490  $status = (($chr == 13) OR ($chr == 42) OR ($chr == 62));
491  break;
492  }
493  case ENC_EDF: { // ASCII character 32 to 94
494  $status = (($chr >= 32) AND ($chr <= 94));
495  break;
496  }
497  case ENC_BASE256: { // Function character (FNC1, Structured Append, Reader Program, or Code Page)
498  $status = (($chr == 232) OR ($chr == 233) OR ($chr == 234) OR ($chr == 241));
499  break;
500  }
501  case ENC_ASCII_EXT: { // ASCII character 128 to 255
502  $status = (($chr >= 128) AND ($chr <= 255));
503  break;
504  }
505  case ENC_ASCII_NUM: { // ASCII digits
506  $status = (($chr >= 48) AND ($chr <= 57));
507  break;
508  }
509  }
510  return $status;
511  }
512 
521  protected function lookAheadTest($data, $pos, $mode) {
522  $data_length = strlen($data);
523  if ($pos >= $data_length) {
524  return $mode;
525  }
526  $charscount = 0; // count processed chars
527  // STEP J
528  if ($mode == ENC_ASCII) {
529  $numch = array(0, 1, 1, 1, 1, 1.25);
530  } else {
531  $numch = array(1, 2, 2, 2, 2, 2.25);
532  $numch[$mode] = 0;
533  }
534  while (true) {
535  // STEP K
536  if (($pos + $charscount) == $data_length) {
537  if ($numch[ENC_ASCII] <= ceil(min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256]))) {
538  return ENC_ASCII;
539  }
540  if ($numch[ENC_BASE256] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF]))) {
541  return ENC_BASE256;
542  }
543  if ($numch[ENC_EDF] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_BASE256]))) {
544  return ENC_EDF;
545  }
546  if ($numch[ENC_TXT] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256]))) {
547  return ENC_TXT;
548  }
549  if ($numch[ENC_X12] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256]))) {
550  return ENC_X12;
551  }
552  return ENC_C40;
553  }
554  // get char
555  $chr = ord($data[$pos + $charscount]);
556  $charscount++;
557  // STEP L
558  if ($this->isCharMode($chr, ENC_ASCII_NUM)) {
559  $numch[ENC_ASCII] += (1 / 2);
560  } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
561  $numch[ENC_ASCII] = ceil($numch[ENC_ASCII]);
562  $numch[ENC_ASCII] += 2;
563  } else {
564  $numch[ENC_ASCII] = ceil($numch[ENC_ASCII]);
565  $numch[ENC_ASCII] += 1;
566  }
567  // STEP M
568  if ($this->isCharMode($chr, ENC_C40)) {
569  $numch[ENC_C40] += (2 / 3);
570  } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
571  $numch[ENC_C40] += (8 / 3);
572  } else {
573  $numch[ENC_C40] += (4 / 3);
574  }
575  // STEP N
576  if ($this->isCharMode($chr, ENC_TXT)) {
577  $numch[ENC_TXT] += (2 / 3);
578  } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
579  $numch[ENC_TXT] += (8 / 3);
580  } else {
581  $numch[ENC_TXT] += (4 / 3);
582  }
583  // STEP O
584  if ($this->isCharMode($chr, ENC_X12) OR $this->isCharMode($chr, ENC_C40)) {
585  $numch[ENC_X12] += (2 / 3);
586  } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
587  $numch[ENC_X12] += (13 / 3);
588  } else {
589  $numch[ENC_X12] += (10 / 3);
590  }
591  // STEP P
592  if ($this->isCharMode($chr, ENC_EDF)) {
593  $numch[ENC_EDF] += (3 / 4);
594  } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
595  $numch[ENC_EDF] += (17 / 4);
596  } else {
597  $numch[ENC_EDF] += (13 / 4);
598  }
599  // STEP Q
600  if ($this->isCharMode($chr, ENC_BASE256)) {
601  $numch[ENC_BASE256] += 4;
602  } else {
603  $numch[ENC_BASE256] += 1;
604  }
605  // STEP R
606  if ($charscount >= 4) {
607  if (($numch[ENC_ASCII] + 1) <= min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256])) {
608  return ENC_ASCII;
609  }
610  if ((($numch[ENC_BASE256] + 1) <= $numch[ENC_ASCII])
611  OR (($numch[ENC_BASE256] + 1) < min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF]))) {
612  return ENC_BASE256;
613  }
614  if (($numch[ENC_EDF] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_BASE256])) {
615  return ENC_EDF;
616  }
617  if (($numch[ENC_TXT] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256])) {
618  return ENC_TXT;
619  }
620  if (($numch[ENC_X12] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256])) {
621  return ENC_X12;
622  }
623  if (($numch[ENC_C40] + 1) < min($numch[ENC_ASCII], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256])) {
624  if ($numch[ENC_C40] < $numch[ENC_X12]) {
625  return ENC_C40;
626  }
627  if ($numch[ENC_C40] == $numch[ENC_X12]) {
628  $k = ($pos + $charscount + 1);
629  while ($k < $data_length) {
630  $tmpchr = ord($data{$k});
631  if ($this->isCharMode($tmpchr, ENC_X12)) {
632  return ENC_X12;
633  } elseif (!($this->isCharMode($tmpchr, ENC_X12) OR $this->isCharMode($tmpchr, ENC_C40))) {
634  break;
635  }
636  ++$k;
637  }
638  return ENC_C40;
639  }
640  }
641  }
642  } // end of while
643  }
644 
651  protected function getSwitchEncodingCodeword($mode) {
652  switch ($mode) {
653  case ENC_ASCII: { // ASCII character 0 to 127
654  $cw = 254;
655  break;
656  }
657  case ENC_C40: { // Upper-case alphanumeric
658  $cw = 230;
659  break;
660  }
661  case ENC_TXT: { // Lower-case alphanumeric
662  $cw = 239;
663  break;
664  }
665  case ENC_X12: { // ANSI X12
666  $cw = 238;
667  break;
668  }
669  case ENC_EDF: { // ASCII character 32 to 94
670  $cw = 240;
671  break;
672  }
673  case ENC_BASE256: { // Function character (FNC1, Structured Append, Reader Program, or Code Page)
674  $cw = 231;
675  break;
676  }
677  }
678  return $cw;
679  }
680 
687  protected function getMaxDataCodewords($numcw) {
688  foreach ($this->symbattr as $key => $matrix) {
689  if ($matrix[11] >= $numcw) {
690  return $matrix[11];
691  }
692  }
693  return 0;
694  }
695 
702  protected function getHighLevelEncoding($data) {
703  // STEP A. Start in ASCII encodation.
704  $enc = ENC_ASCII; // current encoding mode
705  $pos = 0; // current position
706  $cw = array(); // array of codewords to be returned
707  $cw_num = 0; // number of data codewords
708  $data_lenght = strlen($data); // number of chars
709  while ($pos < $data_lenght) {
710  switch ($enc) {
711  case ENC_ASCII: { // STEP B. While in ASCII encodation
712  if (($data_lenght > 1) AND ($pos < ($data_lenght - 1)) AND ($this->isCharMode(ord($data[$pos]), ENC_ASCII_NUM) AND $this->isCharMode(ord($data[$pos + 1]), ENC_ASCII_NUM))) {
713  // 1. If the next data sequence is at least 2 consecutive digits, encode the next two digits as a double digit in ASCII mode.
714  $cw[] = (intval(substr($data, $pos, 2)) + 130);
715  ++$cw_num;
716  $pos += 2;
717  } else {
718  // 2. If the look-ahead test (starting at step J) indicates another mode, switch to that mode.
719  $newenc = $this->lookAheadTest($data, $pos, $enc);
720  if ($newenc != $enc) {
721  // switch to new encoding
722  $enc = $newenc;
723  $cw[] = $this->getSwitchEncodingCodeword($enc);
724  ++$cw_num;
725  } else {
726  // get new byte
727  $chr = ord($data[$pos]);
728  ++$pos;
729  if ($this->isCharMode($chr, ENC_ASCII_EXT)) {
730  // 3. If the next data character is extended ASCII (greater than 127) encode it in ASCII mode first using the Upper Shift (value 235) character.
731  $cw[] = 235;
732  $cw[] = ($chr - 127);
733  $cw_num += 2;
734  } else {
735  // 4. Otherwise process the next data character in ASCII encodation.
736  $cw[] = ($chr + 1);
737  ++$cw_num;
738  }
739  }
740  }
741  break;
742  }
743  case ENC_C40 : // Upper-case alphanumeric
744  case ENC_TXT : // Lower-case alphanumeric
745  case ENC_X12 : { // ANSI X12
746  $temp_cw = array();
747  $p = 0;
748  $epos = $pos;
749  // get charset ID
750  $set_id = $this->chset_id[$enc];
751  // get basic charset for current encoding
752  $charset = $this->chset[$set_id];
753  do {
754  // 2. process the next character in C40 encodation.
755  $chr = ord($data[$epos]);
756  ++$epos;
757  // check for extended character
758  if ($chr & 0x80) {
759  if ($enc == ENC_X12) {
760  return false;
761  }
762  $chr = ($chr & 0x7f);
763  $temp_cw[] = 1; // shift 2
764  $temp_cw[] = 30; // upper shift
765  $p += 2;
766  }
767  if (isset($charset[$chr])) {
768  $temp_cw[] = $charset[$chr];
769  ++$p;
770  } else {
771  if (isset($this->chset['SH1'][$chr])) {
772  $temp_cw[] = 0; // shift 1
773  $shiftset = $this->chset['SH1'];
774  } elseif (isset($chr, $this->chset['SH2'][$chr])) {
775  $temp_cw[] = 1; // shift 2
776  $shiftset = $this->chset['SH2'];
777  } elseif (($enc == ENC_C40) AND isset($this->chset['S3C'][$chr])) {
778  $temp_cw[] = 2; // shift 3
779  $shiftset = $this->chset['S3C'];
780  } elseif (($enc == ENC_TXT) AND isset($this->chset['S3T'][$chr])) {
781  $temp_cw[] = 2; // shift 3
782  $shiftset = $this->chset['S3T'];
783  } else {
784  return false;
785  }
786  $temp_cw[] = $shiftset[$chr];
787  $p += 2;
788  }
789  if ($p >= 3) {
790  $c1 = array_shift($temp_cw);
791  $c2 = array_shift($temp_cw);
792  $c3 = array_shift($temp_cw);
793  $p -= 3;
794  $tmp = ((1600 * $c1) + (40 * $c2) + $c3 + 1);
795  $cw[] = ($tmp >> 8);
796  $cw[] = ($tmp % 256);
797  $cw_num += 2;
798  $pos = $epos;
799  // 1. If the C40 encoding is at the point of starting a new double symbol character and if the look-ahead test (starting at step J) indicates another mode, switch to that mode.
800  $newenc = $this->lookAheadTest($data, $pos, $enc);
801  if ($newenc != $enc) {
802  $enc = $newenc;
803  $cw[] = $this->getSwitchEncodingCodeword($enc);
804  ++$cw_num;
805  $pos -= $p;
806  $p = 0;
807  break;
808  }
809  }
810  } while (($p > 0) AND ($epos < $data_lenght));
811  // process last data (if any)
812  if ($p > 0) {
813  // get remaining number of data symbols
814  $cwr = ($this->getMaxDataCodewords($cw_num + 2) - $cw_num);
815  if (($cwr == 1) AND ($p == 1)) {
816  // d. If one symbol character remains and one C40 value (data character) remains to be encoded
817  $c1 = array_shift($temp_cw);
818  --$p;
819  $cw[] = ($c1 + 1);
820  ++$cw_num;
821  } elseif (($cwr == 2) AND ($p == 1)) {
822  // c. If two symbol characters remain and only one C40 value (data character) remains to be encoded
823  $c1 = array_shift($temp_cw);
824  --$p;
825  $cw[] = 254;
826  $cw[] = ($c1 + 1);
827  $cw_num += 2;
828  } elseif (($cwr == 2) AND ($p == 2)) {
829  // b. If two symbol characters remain and two C40 values remain to be encoded
830  $c1 = array_shift($temp_cw);
831  $c2 = array_shift($temp_cw);
832  $p -= 2;
833  $tmp = ((1600 * $c1) + (40 * $c2) + 1);
834  $cw[] = ($tmp >> 8);
835  $cw[] = ($tmp % 256);
836  $cw_num += 2;
837  } else {
838  // switch to ASCII encoding
839  if ($enc != ENC_ASCII) {
840  $enc = ENC_ASCII;
841  $cw[] = $this->getSwitchEncodingCodeword($enc);
842  ++$cw_num;
843  }
844  }
845  }
846  break;
847  }
848  case ENC_EDF: { // F. While in EDIFACT (EDF) encodation
849  // initialize temporary array with 0 lenght
850  $temp_cw = array();
851  $epos = $pos;
852  $field_lenght = 0;
853  $newenc = $enc;
854  do {
855  // 2. process the next character in EDIFACT encodation.
856  $chr = ord($data[$epos]);
857  if ($this->isCharMode($chr, ENC_EDF)) {
858  ++$epos;
859  $temp_cw[] = $chr;
860  ++$field_lenght;
861  }
862  if (($field_lenght == 4) OR ($epos == $data_lenght) OR !$this->isCharMode($chr, ENC_EDF)) {
863  if (($epos == $data_lenght) AND ($field_lenght < 3)) {
864  $enc = ENC_ASCII;
865  break;
866  }
867  if ($field_lenght < 4) {
868  // set unlatch character
869  $temp_cw[] = 0x1f;
870  ++$field_lenght;
871  // fill empty characters
872  for ($i = $field_lenght; $i < 4; ++$i) {
873  $temp_cw[] = 0;
874  }
875  $enc = ENC_ASCII;
876  }
877  // encodes four data characters in three codewords
878  $tcw = (($temp_cw[0] & 0x3F) << 2) + (($temp_cw[1] & 0x30) >> 4);
879  if ($tcw > 0) {
880  $cw[] = $tcw;
881  $cw_num++;
882  }
883  $tcw= (($temp_cw[1] & 0x0F) << 4) + (($temp_cw[2] & 0x3C) >> 2);
884  if ($tcw > 0) {
885  $cw[] = $tcw;
886  $cw_num++;
887  }
888  $tcw = (($temp_cw[2] & 0x03) << 6) + ($temp_cw[3] & 0x3F);
889  if ($tcw > 0) {
890  $cw[] = $tcw;
891  $cw_num++;
892  }
893  $temp_cw = array();
894  $pos = $epos;
895  $field_lenght = 0;
896  if ($enc == ENC_ASCII) {
897  break; // exit from EDIFACT mode
898  }
899  }
900  } while ($epos < $data_lenght);
901  break;
902  }
903  case ENC_BASE256: { // G. While in Base 256 (B256) encodation
904  // initialize temporary array with 0 lenght
905  $temp_cw = array();
906  $field_lenght = 0;
907  while (($pos < $data_lenght) AND ($field_lenght <= 1555)) {
908  $newenc = $this->lookAheadTest($data, $pos, $enc);
909  if ($newenc != $enc) {
910  // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode.
911  $enc = $newenc;
912  $cw[] = $this->getSwitchEncodingCodeword($enc);
913  ++$cw_num;
914  break; // exit from B256 mode
915  } else {
916  // 2. Otherwise, process the next character in Base 256 encodation.
917  $chr = ord($data[$pos]);
918  ++$pos;
919  $temp_cw[] = $chr;
920  ++$field_lenght;
921  }
922  }
923  // set field lenght
924  if ($field_lenght <= 249) {
925  $cw[] = $field_lenght;
926  ++$cw_num;
927  } else {
928  $cw[] = (floor($field_lenght / 250) + 249);
929  $cw[] = ($field_lenght % 250);
930  $cw_num += 2;
931  }
932  if (!empty($temp_cw)) {
933  // add B256 field
934  foreach ($temp_cw as $p => $cht) {
935  $cw[] = $this->get255StateCodeword($chr, ($cw_num + $p));
936  }
937  }
938  break;
939  }
940  } // end of switch enc
941  } // end of while
942  // set last used encoding
943  $this->last_enc = $enc;
944  return $cw;
945  }
946 
960  protected function placeModule($marr, $nrow, $ncol, $row, $col, $chr, $bit) {
961  if ($row < 0) {
962  $row += $nrow;
963  $col += (4 - (($nrow + 4) % 8));
964  }
965  if ($col < 0) {
966  $col += $ncol;
967  $row += (4 - (($ncol + 4) % 8));
968  }
969  $marr[(($row * $ncol) + $col)] = ((10 * $chr) + $bit);
970  return $marr;
971  }
972 
985  protected function placeUtah($marr, $nrow, $ncol, $row, $col, $chr) {
986  $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-2, $chr, 1);
987  $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-1, $chr, 2);
988  $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-2, $chr, 3);
989  $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-1, $chr, 4);
990  $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col, $chr, 5);
991  $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-2, $chr, 6);
992  $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-1, $chr, 7);
993  $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col, $chr, 8);
994  return $marr;
995  }
996 
1007  protected function placeCornerA($marr, $nrow, $ncol, $chr) {
1008  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1);
1009  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 1, $chr, 2);
1010  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 2, $chr, 3);
1011  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1012  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1013  $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6);
1014  $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7);
1015  $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8);
1016  return $marr;
1017  }
1018 
1029  protected function placeCornerB($marr, $nrow, $ncol, $chr) {
1030  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1);
1031  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2);
1032  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3);
1033  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-4, $chr, 4);
1034  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 5);
1035  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 6);
1036  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 7);
1037  $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8);
1038  return $marr;
1039  }
1040 
1051  protected function placeCornerC($marr, $nrow, $ncol, $chr) {
1052  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1);
1053  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2);
1054  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3);
1055  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1056  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1057  $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6);
1058  $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7);
1059  $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8);
1060  return $marr;
1061  }
1062 
1073  protected function placeCornerD($marr, $nrow, $ncol, $chr) {
1074  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1);
1075  $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, $ncol-1, $chr, 2);
1076  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 3);
1077  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1078  $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1079  $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-3, $chr, 6);
1080  $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-2, $chr, 7);
1081  $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8);
1082  return $marr;
1083  }
1084 
1093  protected function getPlacementMap($nrow, $ncol) {
1094  // initialize array with zeros
1095  $marr = array_fill(0, ($nrow * $ncol), 0);
1096  // set starting values
1097  $chr = 1;
1098  $row = 4;
1099  $col = 0;
1100  do {
1101  // repeatedly first check for one of the special corner cases, then
1102  if (($row == $nrow) AND ($col == 0)) {
1103  $marr = $this->placeCornerA($marr, $nrow, $ncol, $chr);
1104  ++$chr;
1105  }
1106  if (($row == ($nrow - 2)) AND ($col == 0) AND ($ncol % 4)) {
1107  $marr = $this->placeCornerB($marr, $nrow, $ncol, $chr);
1108  ++$chr;
1109  }
1110  if (($row == ($nrow - 2)) AND ($col == 0) AND (($ncol % 8) == 4)) {
1111  $marr = $this->placeCornerC($marr, $nrow, $ncol, $chr);
1112  ++$chr;
1113  }
1114  if (($row == ($nrow + 4)) AND ($col == 2) AND (!($ncol % 8))) {
1115  $marr = $this->placeCornerD($marr, $nrow, $ncol, $chr);
1116  ++$chr;
1117  }
1118  // sweep upward diagonally, inserting successive characters,
1119  do {
1120  if (($row < $nrow) AND ($col >= 0) AND (!$marr[(($row * $ncol) + $col)])) {
1121  $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr);
1122  ++$chr;
1123  }
1124  $row -= 2;
1125  $col += 2;
1126  } while (($row >= 0) AND ($col < $ncol));
1127  ++$row;
1128  $col += 3;
1129  // & then sweep downward diagonally, inserting successive characters,...
1130  do {
1131  if (($row >= 0) AND ($col < $ncol) AND (!$marr[(($row * $ncol) + $col)])) {
1132  $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr);
1133  ++$chr;
1134  }
1135  $row += 2;
1136  $col -= 2;
1137  } while (($row < $nrow) AND ($col >= 0));
1138  $row += 3;
1139  ++$col;
1140  // ... until the entire array is scanned
1141  } while (($row < $nrow) OR ($col < $ncol));
1142  // lastly, if the lower righthand corner is untouched, fill in fixed pattern
1143  if (!$marr[(($nrow * $ncol) - 1)]) {
1144  $marr[(($nrow * $ncol) - 1)] = 1;
1145  $marr[(($nrow * $ncol) - $ncol - 2)] = 1;
1146  }
1147  return $marr;
1148  }
1149 
1150 } // end DataMatrix class
1151 //============================================================+
1152 // END OF FILE
1153 //============================================================+




Korrekturen, Hinweise und Ergänzungen

Bitte scheuen Sie sich nicht und melden Sie, was auf dieser Seite sachlich falsch oder irreführend ist, was ergänzt werden sollte, was fehlt usw. Dazu bitte oben aus dem Menü Seite den Eintrag Support Forum wählen. Es ist eine kostenlose Anmeldung erforderlich, um Anmerkungen zu posten. Unpassende Postings, Spam usw. werden kommentarlos entfernt.