PluginProbe
Welcart e-Commerce / 1.4.0
Welcart e-Commerce v1.4.0
2.12.4 2.12.3 2.11.35 2.12.2 2.12.1 2.11.34 2.11.33 2.11.32 2.11.31 2.11.30 1.3.16 1.3.17 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 All 292 releases
usc-e-shop / pdf / tcpdf / datamatrix.php

datamatrix.php in Welcart e-Commerce 1.4.0, at pdf/tcpdf/datamatrix.php

1,149 lines 41.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 //============================================================+
3 // File name : datamatrix.php
4 // Version : 1.0.001
5 // Begin : 2010-06-07
6 // Last Update : 2011-09-14
7 // Author : Nicola Asuni - Tecnick.com LTD - Manor Coach House, Church Hill, Aldershot, Hants, GU12 4RQ, UK - 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
36 /**
37 * @file
38 * Class to create DataMatrix ECC 200 barcode arrays for TCPDF class.
39 * DataMatrix (ISO/IEC 16022:2006) is a 2-dimensional bar code.
40 *
41 * @package com.tecnick.tcpdf
42 * @author Nicola Asuni
43 * @version 1.0.001
44 */
45
46 // custom definitions
47 if (!defined('DATAMATRIXDEFS')) {
48
49 /**
50 * Indicate that definitions for this class are set
51 */
52 define('DATAMATRIXDEFS', true);
53
54 // -----------------------------------------------------
55
56 } // end of custom definitions
57
58 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
59
60
61 /**
62 * ASCII encoding: ASCII character 0 to 127 (1 byte per CW)
63 */
64 define('ENC_ASCII', 0);
65
66 /**
67 * C40 encoding: Upper-case alphanumeric (3/2 bytes per CW)
68 */
69 define('ENC_C40', 1);
70
71 /**
72 * TEXT encoding: Lower-case alphanumeric (3/2 bytes per CW)
73 */
74 define('ENC_TXT', 2);
75
76 /**
77 * X12 encoding: ANSI X12 (3/2 byte per CW)
78 */
79 define('ENC_X12', 3);
80
81 /**
82 * EDIFACT encoding: ASCII character 32 to 94 (4/3 bytes per CW)
83 */
84 define('ENC_EDF', 4);
85
86 /**
87 * BASE 256 encoding: ASCII character 0 to 255 (1 byte per CW)
88 */
89 define('ENC_BASE256', 5);
90
91 /**
92 * ASCII extended encoding: ASCII character 128 to 255 (1/2 byte per CW)
93 */
94 define('ENC_ASCII_EXT', 6);
95
96 /**
97 * ASCII number encoding: ASCII digits (2 bytes per CW)
98 */
99 define('ENC_ASCII_NUM', 7);
100
101 /**
102 * @class Datamatrix
103 * Class to create DataMatrix ECC 200 barcode arrays for TCPDF class.
104 * DataMatrix (ISO/IEC 16022:2006) is a 2-dimensional bar code.
105 *
106 * @package com.tecnick.tcpdf
107 * @author Nicola Asuni
108 * @version 1.0.001
109 */
110 class Datamatrix {
111
112 /**
113 * Barcode array to be returned which is readable by TCPDF.
114 * @protected
115 */
116 protected $barcode_array = array();
117
118 /**
119 * Store last used encoding for data codewords.
120 * @protected
121 */
122 protected $last_enc = ENC_ASCII;
123
124 /**
125 * Table of Data Matrix ECC 200 Symbol Attributes:<ul>
126 * <li>total matrix rows (including finder pattern)</li>
127 * <li>total matrix cols (including finder pattern)</li>
128 * <li>total matrix rows (without finder pattern)</li>
129 * <li>total matrix cols (without finder pattern)</li>
130 * <li>region data rows (with finder pattern)</li>
131 * <li>region data col (with finder pattern)</li>
132 * <li>region data rows (without finder pattern)</li>
133 * <li>region data col (without finder pattern)</li>
134 * <li>horizontal regions</li>
135 * <li>vertical regions</li>
136 * <li>regions</li>
137 * <li>data codewords</li>
138 * <li>error codewords</li>
139 * <li>blocks</li>
140 * <li>data codewords per block</li>
141 * <li>error codewords per block</li>
142 * </ul>
143 * @protected
144 */
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
180 /**
181 * Map encodation modes whit character sets.
182 * @protected
183 */
184 protected $chset_id = array(ENC_C40 => 'C40', ENC_TXT => 'TXT', ENC_X12 =>'X12');
185
186 /**
187 * Basic set of charactes for each encodation mode.
188 * @protected
189 */
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
229 /**
230 * This is the class constructor.
231 * Creates a datamatrix object
232 * @param $code (string) Code to represent using Datamatrix.
233 * @public
234 */
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->getPlacemetMap($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
345 /**
346 * Returns a barcode array which is readable by TCPDF
347 * @return array barcode array readable by TCPDF;
348 * @public
349 */
350 public function getBarcodeArray() {
351 return $this->barcode_array;
352 }
353
354 /**
355 * Product of two numbers in a Power-of-Two Galois Field
356 * @param $a (int) first number to multiply.
357 * @param $b (int) second number to multiply.
358 * @param $log (array) Log table.
359 * @param $alog (array) Anti-Log table.
360 * @param $gf (array) Number of Factors of the Reed-Solomon polynomial.
361 * @return int product
362 * @protected
363 */
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
371 /**
372 * Add error correction codewords to data codewords array (ANNEX E).
373 * @param $wd (array) Array of datacodewords.
374 * @param $nb (int) Number of blocks.
375 * @param $nd (int) Number of data codewords per block.
376 * @param $nc (int) Number of correction codewords per block.
377 * @param $gf (int) numner of fields on log/antilog table (power of 2).
378 * @param $pp (int) The value of its prime modulus polynomial (301 for ECC200).
379 * @return array data codewords + error codewords
380 * @protected
381 */
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
437 /**
438 * Return the 253-state codeword
439 * @param $cwpad (int) Pad codeword.
440 * @param $cwpos (int) Number of data codewords from the beginning of encoded data.
441 * @return pad codeword
442 * @protected
443 */
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
452 /**
453 * Return the 255-state codeword
454 * @param $cwpad (int) Pad codeword.
455 * @param $cwpos (int) Number of data codewords from the beginning of encoded data.
456 * @return pad codeword
457 * @protected
458 */
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
467 /**
468 * Returns true if the char belongs to the selected mode
469 * @param $chr (int) Character (byte) to check.
470 * @param $mode (int) Current encoding mode.
471 * @return boolean true if the char is of the selected mode.
472 * @protected
473 */
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
513 /**
514 * The look-ahead test scans the data to be encoded to find the best mode (Annex P - steps from J to S).
515 * @param $data (string) data to encode
516 * @param $pos (int) current position
517 * @param $mode (int) current encoding mode
518 * @return int encoding mode
519 * @protected
520 */
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
645 /**
646 * Get the switching codeword to a new encoding mode (latch codeword)
647 * @param $mode (int) New encoding mode.
648 * @return (int) Switch codeword.
649 * @protected
650 */
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
681 /**
682 * Choose the minimum matrix size and return the max number of data codewords.
683 * @param $numcw (int) Number of current codewords.
684 * @return number of data codewords in matrix
685 * @protected
686 */
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
696 /**
697 * Get high level encoding using the minimum symbol data characters for ECC 200
698 * @param $data (string) data to encode
699 * @return array of codewords
700 * @protected
701 */
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 break;
806 }
807 }
808 } while (($p > 0) AND ($epos < $data_lenght));
809 // process last data (if any)
810 if ($p > 0) {
811 // get remaining number of data symbols
812 $cwr = ($this->getMaxDataCodewords($cw_num + 2) - $cw_num);
813 if (($cwr == 1) AND ($p == 1)) {
814 // d. If one symbol character remains and one C40 value (data character) remains to be encoded
815 $c1 = array_shift($temp_cw);
816 --$p;
817 $cw[] = ($c1 + 1);
818 ++$cw_num;
819 } elseif (($cwr == 2) AND ($p == 1)) {
820 // c. If two symbol characters remain and only one C40 value (data character) remains to be encoded
821 $c1 = array_shift($temp_cw);
822 --$p;
823 $cw[] = 254;
824 $cw[] = ($c1 + 1);
825 $cw_num += 2;
826 } elseif (($cwr == 2) AND ($p == 2)) {
827 // b. If two symbol characters remain and two C40 values remain to be encoded
828 $c1 = array_shift($temp_cw);
829 $c2 = array_shift($temp_cw);
830 $p -= 2;
831 $tmp = ((1600 * $c1) + (40 * $c2) + 1);
832 $cw[] = ($tmp >> 8);
833 $cw[] = ($tmp % 256);
834 $cw_num += 2;
835 } else {
836 // switch to ASCII encoding
837 $enc = ENC_ASCII;
838 $cw[] = $this->getSwitchEncodingCodeword($enc);
839 ++$cw_num;
840 }
841 }
842 break;
843 }
844 case ENC_EDF: { // F. While in EDIFACT (EDF) encodation
845 // initialize temporary array with 0 lenght
846 $temp_cw = array();
847 $epos = $pos;
848 $field_lenght = 0;
849 while ($epos < $data_lenght) {
850 // 2. process the next character in EDIFACT encodation.
851 $chr = ord($data{($epos)});
852 ++$epos;
853 $temp_cw[] = $chr;
854 ++$field_lenght;
855 if (($field_lenght == 4) OR ($epos == $data_lenght)) {
856 if ($field_lenght < 4) {
857 // set unlatch character
858 $temp_cw[] = 0x1f;
859 ++$field_lenght;
860 $enc = ENC_ASCII;
861 // fill empty characters
862 for ($i = $field_lenght; $i < 4; ++$i) {
863 $temp_cw[] = 0;
864 }
865 }
866 // encodes four data characters in three codewords
867 $cw[] = (($temp_cw[0] & 0x3F) << 2) + (($temp_cw[1] & 0x30) >> 4);
868 $cw[] = (($temp_cw[1] & 0x0F) << 4) + (($temp_cw[2] & 0x3C) >> 2);
869 $cw[] = (($temp_cw[2] & 0x03) << 6) + ($temp_cw[3] & 0x3F);
870 $cw_num += 3;
871 $temp_cw = array();
872 $pos = $epos;
873 $field_lenght = 0;
874 }
875 // 1. If the EDIFACT encoding is at the point of starting a new triple symbol character and if the look-ahead test (starting at step J) indicates another mode, switch to that mode.
876 if ($field_lenght == 0) {
877 // get remaining number of data symbols
878 $cwr = ($this->getMaxDataCodewords($cw_num + 2) - $cw_num);
879 if ($cwr < 3) {
880 // return to ascii without unlatch
881 $enc = ENC_ASCII;
882 break; // exit from EDIFACT mode
883 } else {
884 $newenc = $this->lookAheadTest($data, $pos, $enc);
885 if ($newenc != $enc) {
886 // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode.
887 $enc = $newenc;
888 $cw[] = $this->getSwitchEncodingCodeword($enc);
889 ++$cw_num;
890 break; // exit from EDIFACT mode
891 }
892 }
893 }
894 }
895 break;
896 }
897 case ENC_BASE256: { // G. While in Base 256 (B256) encodation
898 // initialize temporary array with 0 lenght
899 $temp_cw = array();
900 $field_lenght = 0;
901 while (($pos < $data_lenght) AND ($field_lenght <= 1555)) {
902 $newenc = $this->lookAheadTest($data, $pos, $enc);
903 if ($newenc != $enc) {
904 // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode.
905 $enc = $newenc;
906 $cw[] = $this->getSwitchEncodingCodeword($enc);
907 ++$cw_num;
908 break; // exit from B256 mode
909 } else {
910 // 2. Otherwise, process the next character in Base 256 encodation.
911 $chr = ord($data{($pos)});
912 ++$pos;
913 $temp_cw[] = $chr;
914 ++$field_lenght;
915 }
916 }
917 // set field lenght
918 if ($field_lenght <= 249) {
919 $cw[] = $field_lenght;
920 ++$cw_num;
921 } else {
922 $cw[] = (floor($field_lenght / 250) + 249);
923 $cw[] = ($field_lenght % 250);
924 $cw_num += 2;
925 }
926 if (!empty($temp_cw)) {
927 // add B256 field
928 foreach ($temp_cw as $p => $cht) {
929 $cw[] = $this->get255StateCodeword($chr, ($cw_num + $p));
930 }
931 }
932 break;
933 }
934 } // end of switch enc
935 } // end of while
936 // set last used encoding
937 $this->last_enc = $enc;
938 return $cw;
939 }
940
941 /**
942 * Places "chr+bit" with appropriate wrapping within array[].
943 * (Annex F - ECC 200 symbol character placement)
944 * @param $marr (array) Array of symbols.
945 * @param $nrow (int) Number of rows.
946 * @param $ncol (int) Number of columns.
947 * @param $row (int) Row number.
948 * @param $col (int) Column number.
949 * @param $chr (int) Char byte.
950 * @param $bit (int) Bit.
951 * @return array
952 * @protected
953 */
954 protected function placeModule($marr, $nrow, $ncol, $row, $col, $chr, $bit) {
955 if ($row < 0) {
956 $row += $nrow;
957 $col += (4 - (($nrow + 4) % 8));
958 }
959 if ($col < 0) {
960 $col += $ncol;
961 $row += (4 - (($ncol + 4) % 8));
962 }
963 $marr[(($row * $ncol) + $col)] = ((10 * $chr) + $bit);
964 return $marr;
965 }
966
967 /**
968 * Places the 8 bits of a utah-shaped symbol character.
969 * (Annex F - ECC 200 symbol character placement)
970 * @param $marr (array) Array of symbols.
971 * @param $nrow (int) Number of rows.
972 * @param $ncol (int) Number of columns.
973 * @param $row (int) Row number.
974 * @param $col (int) Column number.
975 * @param $chr (int) Char byte.
976 * @return array
977 * @protected
978 */
979 protected function placeUtah($marr, $nrow, $ncol, $row, $col, $chr) {
980 $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-2, $chr, 1);
981 $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-1, $chr, 2);
982 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-2, $chr, 3);
983 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-1, $chr, 4);
984 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col, $chr, 5);
985 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-2, $chr, 6);
986 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-1, $chr, 7);
987 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col, $chr, 8);
988 return $marr;
989 }
990
991 /**
992 * Places the 8 bits of the first special corner case.
993 * (Annex F - ECC 200 symbol character placement)
994 * @param $marr (array) Array of symbols.
995 * @param $nrow (int) Number of rows.
996 * @param $ncol (int) Number of columns.
997 * @param $chr (int) Char byte.
998 * @return array
999 * @protected
1000 */
1001 protected function placeCornerA($marr, $nrow, $ncol, $chr) {
1002 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1);
1003 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 1, $chr, 2);
1004 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 2, $chr, 3);
1005 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1006 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1007 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6);
1008 $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7);
1009 $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8);
1010 return $marr;
1011 }
1012
1013 /**
1014 * Places the 8 bits of the second special corner case.
1015 * (Annex F - ECC 200 symbol character placement)
1016 * @param $marr (array) Array of symbols.
1017 * @param $nrow (int) Number of rows.
1018 * @param $ncol (int) Number of columns.
1019 * @param $chr (int) Char byte.
1020 * @return array
1021 * @protected
1022 */
1023 protected function placeCornerB($marr, $nrow, $ncol, $chr) {
1024 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1);
1025 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2);
1026 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3);
1027 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-4, $chr, 4);
1028 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 5);
1029 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 6);
1030 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 7);
1031 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8);
1032 return $marr;
1033 }
1034
1035 /**
1036 * Places the 8 bits of the third special corner case.
1037 * (Annex F - ECC 200 symbol character placement)
1038 * @param $marr (array) Array of symbols.
1039 * @param $nrow (int) Number of rows.
1040 * @param $ncol (int) Number of columns.
1041 * @param $chr (int) Char byte.
1042 * @return array
1043 * @protected
1044 */
1045 protected function placeCornerC($marr, $nrow, $ncol, $chr) {
1046 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1);
1047 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2);
1048 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3);
1049 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1050 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1051 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6);
1052 $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7);
1053 $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8);
1054 return $marr;
1055 }
1056
1057 /**
1058 * Places the 8 bits of the fourth special corner case.
1059 * (Annex F - ECC 200 symbol character placement)
1060 * @param $marr (array) Array of symbols.
1061 * @param $nrow (int) Number of rows.
1062 * @param $ncol (int) Number of columns.
1063 * @param $chr (int) Char byte.
1064 * @return array
1065 * @protected
1066 */
1067 protected function placeCornerD($marr, $nrow, $ncol, $chr) {
1068 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1);
1069 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, $ncol-1, $chr, 2);
1070 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 3);
1071 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1072 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1073 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-3, $chr, 6);
1074 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-2, $chr, 7);
1075 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8);
1076 return $marr;
1077 }
1078
1079
1080 /**
1081 * Build a placement map.
1082 * (Annex F - ECC 200 symbol character placement)
1083 * @param $nrow (int) Number of rows.
1084 * @param $ncol (int) Number of columns.
1085 * @return array
1086 * @protected
1087 */
1088 protected function getPlacemetMap($nrow, $ncol) {
1089 // initialize array with zeros
1090 $marr = array_fill(0, ($nrow * $ncol), 0);
1091 // set starting values
1092 $chr = 1;
1093 $row = 4;
1094 $col = 0;
1095 do {
1096 // repeatedly first check for one of the special corner cases, then
1097 if (($row == $nrow) AND ($col == 0)) {
1098 $marr = $this->placeCornerA($marr, $nrow, $ncol, $chr);
1099 ++$chr;
1100 }
1101 if (($row == ($nrow - 2)) AND ($col == 0) AND ($ncol % 4)) {
1102 $marr = $this->placeCornerB($marr, $nrow, $ncol, $chr);
1103 ++$chr;
1104 }
1105 if (($row == ($nrow - 2)) AND ($col == 0) AND (($ncol % 8) == 4)) {
1106 $marr = $this->placeCornerC($marr, $nrow, $ncol, $chr);
1107 ++$chr;
1108 }
1109 if (($row == ($nrow + 4)) AND ($col == 2) AND (!($ncol % 8))) {
1110 $marr = $this->placeCornerD($marr, $nrow, $ncol, $chr);
1111 ++$chr;
1112 }
1113 // sweep upward diagonally, inserting successive characters,
1114 do {
1115 if (($row < $nrow) AND ($col >= 0) AND (!$marr[(($row * $ncol) + $col)])) {
1116 $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr);
1117 ++$chr;
1118 }
1119 $row -= 2;
1120 $col += 2;
1121 } while (($row >= 0) AND ($col < $ncol));
1122 ++$row;
1123 $col += 3;
1124 // & then sweep downward diagonally, inserting successive characters,...
1125 do {
1126 if (($row >= 0) AND ($col < $ncol) AND (!$marr[(($row * $ncol) + $col)])) {
1127 $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr);
1128 ++$chr;
1129 }
1130 $row += 2;
1131 $col -= 2;
1132 } while (($row < $nrow) AND ($col >= 0));
1133 $row += 3;
1134 ++$col;
1135 // ... until the entire array is scanned
1136 } while (($row < $nrow) OR ($col < $ncol));
1137 // lastly, if the lower righthand corner is untouched, fill in fixed pattern
1138 if (!$marr[(($nrow * $ncol) - 1)]) {
1139 $marr[(($nrow * $ncol) - 1)] = 1;
1140 $marr[(($nrow * $ncol) - $ncol - 2)] = 1;
1141 }
1142 return $marr;
1143 }
1144
1145 } // end DataMatrix class
1146 //============================================================+
1147 // END OF FILE
1148 //============================================================+
1149