Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 //============================================================+ 3 // File name : datamatrix.php 4 // Version : 1.0.008 5 // Begin : 2010-06-07 6 // Last Update : 2014-05-06 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-2014 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.008 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.004 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 characters 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 string $code 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 ((($params[11] - $nd) > 1) AND ($cw[($nd - 1)] != 254)) { 260 if ($this->last_enc == ENC_EDF) { 261 // switch to ASCII encoding 262 $cw[] = 124; 263 ++$nd; 264 } elseif (($this->last_enc != ENC_ASCII) AND ($this->last_enc != ENC_BASE256)) { 265 // switch to ASCII encoding 266 $cw[] = 254; 267 ++$nd; 268 } 269 } 270 if ($params[11] > $nd) { 271 // add first pad 272 $cw[] = 129; 273 ++$nd; 274 // add remaining pads 275 for ($i = $nd; $i < $params[11]; ++$i) { 276 $cw[] = $this->get253StateCodeword(129, $i); 277 } 278 } 279 } 280 // add error correction codewords 281 $cw = $this->getErrorCorrection($cw, $params[13], $params[14], $params[15]); 282 // initialize empty arrays 283 $grid = array_fill(0, ($params[2] * $params[3]), 0); 284 // get placement map 285 $places = $this->getPlacementMap($params[2], $params[3]); 286 // fill the grid with data 287 $grid = array(); 288 $i = 0; 289 // region data row max index 290 $rdri = ($params[4] - 1); 291 // region data column max index 292 $rdci = ($params[5] - 1); 293 // for each vertical region 294 for ($vr = 0; $vr < $params[9]; ++$vr) { 295 // for each row on region 296 for ($r = 0; $r < $params[4]; ++$r) { 297 // get row 298 $row = (($vr * $params[4]) + $r); 299 // for each horizontal region 300 for ($hr = 0; $hr < $params[8]; ++$hr) { 301 // for each column on region 302 for ($c = 0; $c < $params[5]; ++$c) { 303 // get column 304 $col = (($hr * $params[5]) + $c); 305 // braw bits by case 306 if ($r == 0) { 307 // top finder pattern 308 if ($c % 2) { 309 $grid[$row][$col] = 0; 310 } else { 311 $grid[$row][$col] = 1; 312 } 313 } elseif ($r == $rdri) { 314 // bottom finder pattern 315 $grid[$row][$col] = 1; 316 } elseif ($c == 0) { 317 // left finder pattern 318 $grid[$row][$col] = 1; 319 } elseif ($c == $rdci) { 320 // right finder pattern 321 if ($r % 2) { 322 $grid[$row][$col] = 1; 323 } else { 324 $grid[$row][$col] = 0; 325 } 326 } else { // data bit 327 if ($places[$i] < 2) { 328 $grid[$row][$col] = $places[$i]; 329 } else { 330 // codeword ID 331 $cw_id = (floor($places[$i] / 10) - 1); 332 // codeword BIT mask 333 $cw_bit = pow(2, (8 - ($places[$i] % 10))); 334 $grid[$row][$col] = (($cw[$cw_id] & $cw_bit) == 0) ? 0 : 1; 335 } 336 ++$i; 337 } 338 } 339 } 340 } 341 } 342 $this->barcode_array['num_rows'] = $params[0]; 343 $this->barcode_array['num_cols'] = $params[1]; 344 $this->barcode_array['bcode'] = $grid; 345 } 346 347 /** 348 * Returns a barcode array which is readable by TCPDF 349 * @return array barcode array readable by TCPDF; 350 * @public 351 */ 352 public function getBarcodeArray() { 353 return $this->barcode_array; 354 } 355 356 /** 357 * Product of two numbers in a Power-of-Two Galois Field 358 * @param int $a first number to multiply. 359 * @param int $b second number to multiply. 360 * @param array $log Log table. 361 * @param array $alog Anti-Log table. 362 * @param int $gf Number of Factors of the Reed-Solomon polynomial. 363 * @return int product 364 * @protected 365 */ 366 protected function getGFProduct($a, $b, $log, $alog, $gf) { 367 if (($a == 0) OR ($b == 0)) { 368 return 0; 369 } 370 return ($alog[($log[$a] + $log[$b]) % ($gf - 1)]); 371 } 372 373 /** 374 * Add error correction codewords to data codewords array (ANNEX E). 375 * @param array $wd Array of datacodewords. 376 * @param int $nb Number of blocks. 377 * @param int $nd Number of data codewords per block. 378 * @param int $nc Number of correction codewords per block. 379 * @param int $gf numner of fields on log/antilog table (power of 2). 380 * @param int $pp The value of its prime modulus polynomial (301 for ECC200). 381 * @return array data codewords + error codewords 382 * @protected 383 */ 384 protected function getErrorCorrection($wd, $nb, $nd, $nc, $gf=256, $pp=301) { 385 // generate the log ($log) and antilog ($alog) tables 386 $log[0] = 0; 387 $alog[0] = 1; 388 for ($i = 1; $i < $gf; ++$i) { 389 $alog[$i] = ($alog[($i - 1)] * 2); 390 if ($alog[$i] >= $gf) { 391 $alog[$i] ^= $pp; 392 } 393 $log[$alog[$i]] = $i; 394 } 395 ksort($log); 396 // generate the polynomial coefficients (c) 397 $c = array_fill(0, ($nc + 1), 0); 398 $c[0] = 1; 399 for ($i = 1; $i <= $nc; ++$i) { 400 $c[$i] = $c[($i-1)]; 401 for ($j = ($i - 1); $j >= 1; --$j) { 402 $c[$j] = $c[($j - 1)] ^ $this->getGFProduct($c[$j], $alog[$i], $log, $alog, $gf); 403 } 404 $c[0] = $this->getGFProduct($c[0], $alog[$i], $log, $alog, $gf); 405 } 406 ksort($c); 407 // total number of data codewords 408 $num_wd = ($nb * $nd); 409 // total number of error codewords 410 $num_we = ($nb * $nc); 411 // for each block 412 for ($b = 0; $b < $nb; ++$b) { 413 // create interleaved data block 414 $block = array(); 415 for ($n = $b; $n < $num_wd; $n += $nb) { 416 $block[] = $wd[$n]; 417 } 418 // initialize error codewords 419 $we = array_fill(0, ($nc + 1), 0); 420 // calculate error correction codewords for this block 421 for ($i = 0; $i < $nd; ++$i) { 422 $k = ($we[0] ^ $block[$i]); 423 for ($j = 0; $j < $nc; ++$j) { 424 $we[$j] = ($we[($j + 1)] ^ $this->getGFProduct($k, $c[($nc - $j - 1)], $log, $alog, $gf)); 425 } 426 } 427 // add error codewords at the end of data codewords 428 $j = 0; 429 for ($i = $b; $i < $num_we; $i += $nb) { 430 $wd[($num_wd + $i)] = $we[$j]; 431 ++$j; 432 } 433 } 434 // reorder codewords 435 ksort($wd); 436 return $wd; 437 } 438 439 /** 440 * Return the 253-state codeword 441 * @param int $cwpad Pad codeword. 442 * @param int $cwpos Number of data codewords from the beginning of encoded data. 443 * @return int pad codeword 444 * @protected 445 */ 446 protected function get253StateCodeword($cwpad, $cwpos) { 447 $pad = ($cwpad + (((149 * $cwpos) % 253) + 1)); 448 if ($pad > 254) { 449 $pad -= 254; 450 } 451 return $pad; 452 } 453 454 /** 455 * Return the 255-state codeword 456 * @param int $cwpad Pad codeword. 457 * @param int $cwpos Number of data codewords from the beginning of encoded data. 458 * @return int pad codeword 459 * @protected 460 */ 461 protected function get255StateCodeword($cwpad, $cwpos) { 462 $pad = ($cwpad + (((149 * $cwpos) % 255) + 1)); 463 if ($pad > 255) { 464 $pad -= 256; 465 } 466 return $pad; 467 } 468 469 /** 470 * Returns true if the char belongs to the selected mode 471 * @param int $chr Character (byte) to check. 472 * @param int $mode Current encoding mode. 473 * @return boolean true if the char is of the selected mode. 474 * @protected 475 */ 476 protected function isCharMode($chr, $mode) { 477 $status = false; 478 switch ($mode) { 479 case ENC_ASCII: { // ASCII character 0 to 127 480 $status = (($chr >= 0) AND ($chr <= 127)); 481 break; 482 } 483 case ENC_C40: { // Upper-case alphanumeric 484 $status = (($chr == 32) OR (($chr >= 48) AND ($chr <= 57)) OR (($chr >= 65) AND ($chr <= 90))); 485 break; 486 } 487 case ENC_TXT: { // Lower-case alphanumeric 488 $status = (($chr == 32) OR (($chr >= 48) AND ($chr <= 57)) OR (($chr >= 97) AND ($chr <= 122))); 489 break; 490 } 491 case ENC_X12: { // ANSI X12 492 $status = (($chr == 13) OR ($chr == 42) OR ($chr == 62)); 493 break; 494 } 495 case ENC_EDF: { // ASCII character 32 to 94 496 $status = (($chr >= 32) AND ($chr <= 94)); 497 break; 498 } 499 case ENC_BASE256: { // Function character (FNC1, Structured Append, Reader Program, or Code Page) 500 $status = (($chr == 232) OR ($chr == 233) OR ($chr == 234) OR ($chr == 241)); 501 break; 502 } 503 case ENC_ASCII_EXT: { // ASCII character 128 to 255 504 $status = (($chr >= 128) AND ($chr <= 255)); 505 break; 506 } 507 case ENC_ASCII_NUM: { // ASCII digits 508 $status = (($chr >= 48) AND ($chr <= 57)); 509 break; 510 } 511 } 512 return $status; 513 } 514 515 /** 516 * The look-ahead test scans the data to be encoded to find the best mode (Annex P - steps from J to S). 517 * @param string $data data to encode 518 * @param int $pos current position 519 * @param int $mode current encoding mode 520 * @return int encoding mode 521 * @protected 522 */ 523 protected function lookAheadTest($data, $pos, $mode) { 524 $data_length = strlen($data); 525 if ($pos >= $data_length) { 526 return $mode; 527 } 528 $charscount = 0; // count processed chars 529 // STEP J 530 if ($mode == ENC_ASCII) { 531 $numch = array(0, 1, 1, 1, 1, 1.25); 532 } else { 533 $numch = array(1, 2, 2, 2, 2, 2.25); 534 $numch[$mode] = 0; 535 } 536 while (true) { 537 // STEP K 538 if (($pos + $charscount) == $data_length) { 539 if ($numch[ENC_ASCII] <= ceil(min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256]))) { 540 return ENC_ASCII; 541 } 542 if ($numch[ENC_BASE256] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF]))) { 543 return ENC_BASE256; 544 } 545 if ($numch[ENC_EDF] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_BASE256]))) { 546 return ENC_EDF; 547 } 548 if ($numch[ENC_TXT] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256]))) { 549 return ENC_TXT; 550 } 551 if ($numch[ENC_X12] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256]))) { 552 return ENC_X12; 553 } 554 return ENC_C40; 555 } 556 // get char 557 $chr = ord($data[$pos + $charscount]); 558 $charscount++; 559 // STEP L 560 if ($this->isCharMode($chr, ENC_ASCII_NUM)) { 561 $numch[ENC_ASCII] += (1 / 2); 562 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) { 563 $numch[ENC_ASCII] = ceil($numch[ENC_ASCII]); 564 $numch[ENC_ASCII] += 2; 565 } else { 566 $numch[ENC_ASCII] = ceil($numch[ENC_ASCII]); 567 $numch[ENC_ASCII] += 1; 568 } 569 // STEP M 570 if ($this->isCharMode($chr, ENC_C40)) { 571 $numch[ENC_C40] += (2 / 3); 572 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) { 573 $numch[ENC_C40] += (8 / 3); 574 } else { 575 $numch[ENC_C40] += (4 / 3); 576 } 577 // STEP N 578 if ($this->isCharMode($chr, ENC_TXT)) { 579 $numch[ENC_TXT] += (2 / 3); 580 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) { 581 $numch[ENC_TXT] += (8 / 3); 582 } else { 583 $numch[ENC_TXT] += (4 / 3); 584 } 585 // STEP O 586 if ($this->isCharMode($chr, ENC_X12) OR $this->isCharMode($chr, ENC_C40)) { 587 $numch[ENC_X12] += (2 / 3); 588 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) { 589 $numch[ENC_X12] += (13 / 3); 590 } else { 591 $numch[ENC_X12] += (10 / 3); 592 } 593 // STEP P 594 if ($this->isCharMode($chr, ENC_EDF)) { 595 $numch[ENC_EDF] += (3 / 4); 596 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) { 597 $numch[ENC_EDF] += (17 / 4); 598 } else { 599 $numch[ENC_EDF] += (13 / 4); 600 } 601 // STEP Q 602 if ($this->isCharMode($chr, ENC_BASE256)) { 603 $numch[ENC_BASE256] += 4; 604 } else { 605 $numch[ENC_BASE256] += 1; 606 } 607 // STEP R 608 if ($charscount >= 4) { 609 if (($numch[ENC_ASCII] + 1) <= min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256])) { 610 return ENC_ASCII; 611 } 612 if ((($numch[ENC_BASE256] + 1) <= $numch[ENC_ASCII]) 613 OR (($numch[ENC_BASE256] + 1) < min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF]))) { 614 return ENC_BASE256; 615 } 616 if (($numch[ENC_EDF] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_BASE256])) { 617 return ENC_EDF; 618 } 619 if (($numch[ENC_TXT] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256])) { 620 return ENC_TXT; 621 } 622 if (($numch[ENC_X12] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256])) { 623 return ENC_X12; 624 } 625 if (($numch[ENC_C40] + 1) < min($numch[ENC_ASCII], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256])) { 626 if ($numch[ENC_C40] < $numch[ENC_X12]) { 627 return ENC_C40; 628 } 629 if ($numch[ENC_C40] == $numch[ENC_X12]) { 630 $k = ($pos + $charscount + 1); 631 while ($k < $data_length) { 632 $tmpchr = ord($data[$k]); 633 if ($this->isCharMode($tmpchr, ENC_X12)) { 634 return ENC_X12; 635 } elseif (!($this->isCharMode($tmpchr, ENC_X12) OR $this->isCharMode($tmpchr, ENC_C40))) { 636 break; 637 } 638 ++$k; 639 } 640 return ENC_C40; 641 } 642 } 643 } 644 } // end of while 645 } 646 647 /** 648 * Get the switching codeword to a new encoding mode (latch codeword) 649 * @param int $mode New encoding mode. 650 * @return int Switch codeword. 651 * @protected 652 */ 653 protected function getSwitchEncodingCodeword($mode) { 654 switch ($mode) { 655 case ENC_ASCII: { // ASCII character 0 to 127 656 $cw = 254; 657 if ($this->last_enc == ENC_EDF) { 658 $cw = 124; 659 } 660 break; 661 } 662 case ENC_C40: { // Upper-case alphanumeric 663 $cw = 230; 664 break; 665 } 666 case ENC_TXT: { // Lower-case alphanumeric 667 $cw = 239; 668 break; 669 } 670 case ENC_X12: { // ANSI X12 671 $cw = 238; 672 break; 673 } 674 case ENC_EDF: { // ASCII character 32 to 94 675 $cw = 240; 676 break; 677 } 678 case ENC_BASE256: { // Function character (FNC1, Structured Append, Reader Program, or Code Page) 679 $cw = 231; 680 break; 681 } 682 } 683 return $cw; 684 } 685 686 /** 687 * Choose the minimum matrix size and return the max number of data codewords. 688 * @param int $numcw Number of current codewords. 689 * @return int number of data codewords in matrix 690 * @protected 691 */ 692 protected function getMaxDataCodewords($numcw) { 693 foreach ($this->symbattr as $key => $matrix) { 694 if ($matrix[11] >= $numcw) { 695 return $matrix[11]; 696 } 697 } 698 return 0; 699 } 700 701 /** 702 * Get high level encoding using the minimum symbol data characters for ECC 200 703 * @param string $data data to encode 704 * @return array of codewords 705 * @protected 706 */ 707 protected function getHighLevelEncoding($data) { 708 // STEP A. Start in ASCII encodation. 709 $enc = ENC_ASCII; // current encoding mode 710 $pos = 0; // current position 711 $cw = array(); // array of codewords to be returned 712 $cw_num = 0; // number of data codewords 713 $data_length = strlen($data); // number of chars 714 while ($pos < $data_length) { 715 // set last used encoding 716 $this->last_enc = $enc; 717 switch ($enc) { 718 case ENC_ASCII: { // STEP B. While in ASCII encodation 719 if (($data_length > 1) AND ($pos < ($data_length - 1)) AND ($this->isCharMode(ord($data[$pos]), ENC_ASCII_NUM) AND $this->isCharMode(ord($data[$pos + 1]), ENC_ASCII_NUM))) { 720 // 1. If the next data sequence is at least 2 consecutive digits, encode the next two digits as a double digit in ASCII mode. 721 $cw[] = (intval(substr($data, $pos, 2)) + 130); 722 ++$cw_num; 723 $pos += 2; 724 } else { 725 // 2. If the look-ahead test (starting at step J) indicates another mode, switch to that mode. 726 $newenc = $this->lookAheadTest($data, $pos, $enc); 727 if ($newenc != $enc) { 728 // switch to new encoding 729 $enc = $newenc; 730 $cw[] = $this->getSwitchEncodingCodeword($enc); 731 ++$cw_num; 732 } else { 733 // get new byte 734 $chr = ord($data[$pos]); 735 ++$pos; 736 if ($this->isCharMode($chr, ENC_ASCII_EXT)) { 737 // 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. 738 $cw[] = 235; 739 $cw[] = ($chr - 127); 740 $cw_num += 2; 741 } else { 742 // 4. Otherwise process the next data character in ASCII encodation. 743 $cw[] = ($chr + 1); 744 ++$cw_num; 745 } 746 } 747 } 748 break; 749 } 750 case ENC_C40 : // Upper-case alphanumeric 751 case ENC_TXT : // Lower-case alphanumeric 752 case ENC_X12 : { // ANSI X12 753 $temp_cw = array(); 754 $p = 0; 755 $epos = $pos; 756 // get charset ID 757 $set_id = $this->chset_id[$enc]; 758 // get basic charset for current encoding 759 $charset = $this->chset[$set_id]; 760 do { 761 // 2. process the next character in C40 encodation. 762 $chr = ord($data[$epos]); 763 ++$epos; 764 // check for extended character 765 if ($chr & 0x80) { 766 if ($enc == ENC_X12) { 767 return false; 768 } 769 $chr = ($chr & 0x7f); 770 $temp_cw[] = 1; // shift 2 771 $temp_cw[] = 30; // upper shift 772 $p += 2; 773 } 774 if (isset($charset[$chr])) { 775 $temp_cw[] = $charset[$chr]; 776 ++$p; 777 } else { 778 if (isset($this->chset['SH1'][$chr])) { 779 $temp_cw[] = 0; // shift 1 780 $shiftset = $this->chset['SH1']; 781 } elseif (isset($this->chset['SH2'][$chr])) { 782 $temp_cw[] = 1; // shift 2 783 $shiftset = $this->chset['SH2']; 784 } elseif (($enc == ENC_C40) AND isset($this->chset['S3C'][$chr])) { 785 $temp_cw[] = 2; // shift 3 786 $shiftset = $this->chset['S3C']; 787 } elseif (($enc == ENC_TXT) AND isset($this->chset['S3T'][$chr])) { 788 $temp_cw[] = 2; // shift 3 789 $shiftset = $this->chset['S3T']; 790 } else { 791 return false; 792 } 793 $temp_cw[] = $shiftset[$chr]; 794 $p += 2; 795 } 796 if ($p >= 3) { 797 $c1 = array_shift($temp_cw); 798 $c2 = array_shift($temp_cw); 799 $c3 = array_shift($temp_cw); 800 $p -= 3; 801 $tmp = ((1600 * $c1) + (40 * $c2) + $c3 + 1); 802 $cw[] = ($tmp >> 8); 803 $cw[] = ($tmp % 256); 804 $cw_num += 2; 805 $pos = $epos; 806 // 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. 807 $newenc = $this->lookAheadTest($data, $pos, $enc); 808 if ($newenc != $enc) { 809 // switch to new encoding 810 $enc = $newenc; 811 if ($enc != ENC_ASCII) { 812 // set unlatch character 813 $cw[] = $this->getSwitchEncodingCodeword(ENC_ASCII); 814 ++$cw_num; 815 } 816 $cw[] = $this->getSwitchEncodingCodeword($enc); 817 ++$cw_num; 818 $pos -= $p; 819 $p = 0; 820 break; 821 } 822 } 823 } while (($p > 0) AND ($epos < $data_length)); 824 // process last data (if any) 825 if ($p > 0) { 826 // get remaining number of data symbols 827 $cwr = ($this->getMaxDataCodewords($cw_num) - $cw_num); 828 if (($cwr == 1) AND ($p == 1)) { 829 // d. If one symbol character remains and one C40 value (data character) remains to be encoded 830 $c1 = array_shift($temp_cw); 831 --$p; 832 $cw[] = ($chr + 1); 833 ++$cw_num; 834 $pos = $epos; 835 $enc = ENC_ASCII; 836 $this->last_enc = $enc; 837 } elseif (($cwr == 2) AND ($p == 1)) { 838 // c. If two symbol characters remain and only one C40 value (data character) remains to be encoded 839 $c1 = array_shift($temp_cw); 840 --$p; 841 $cw[] = 254; 842 $cw[] = ($chr + 1); 843 $cw_num += 2; 844 $pos = $epos; 845 $enc = ENC_ASCII; 846 $this->last_enc = $enc; 847 } elseif (($cwr == 2) AND ($p == 2)) { 848 // b. If two symbol characters remain and two C40 values remain to be encoded 849 $c1 = array_shift($temp_cw); 850 $c2 = array_shift($temp_cw); 851 $p -= 2; 852 $tmp = ((1600 * $c1) + (40 * $c2) + 1); 853 $cw[] = ($tmp >> 8); 854 $cw[] = ($tmp % 256); 855 $cw_num += 2; 856 $pos = $epos; 857 $enc = ENC_ASCII; 858 $this->last_enc = $enc; 859 } else { 860 // switch to ASCII encoding 861 if ($enc != ENC_ASCII) { 862 $enc = ENC_ASCII; 863 $this->last_enc = $enc; 864 $cw[] = $this->getSwitchEncodingCodeword($enc); 865 ++$cw_num; 866 $pos = ($epos - $p); 867 } 868 } 869 } 870 break; 871 } 872 case ENC_EDF: { // F. While in EDIFACT (EDF) encodation 873 // initialize temporary array with 0 length 874 $temp_cw = array(); 875 $epos = $pos; 876 $field_length = 0; 877 $newenc = $enc; 878 do { 879 // 2. process the next character in EDIFACT encodation. 880 $chr = ord($data[$epos]); 881 if ($this->isCharMode($chr, ENC_EDF)) { 882 ++$epos; 883 $temp_cw[] = $chr; 884 ++$field_length; 885 } 886 if (($field_length == 4) OR ($epos == $data_length) OR !$this->isCharMode($chr, ENC_EDF)) { 887 if (($epos == $data_length) AND ($field_length < 3)) { 888 $enc = ENC_ASCII; 889 $cw[] = $this->getSwitchEncodingCodeword($enc); 890 ++$cw_num; 891 break; 892 } 893 if ($field_length < 4) { 894 // set unlatch character 895 $temp_cw[] = 0x1f; 896 ++$field_length; 897 // fill empty characters 898 for ($i = $field_length; $i < 4; ++$i) { 899 $temp_cw[] = 0; 900 } 901 $enc = ENC_ASCII; 902 $this->last_enc = $enc; 903 } 904 // encodes four data characters in three codewords 905 $tcw = (($temp_cw[0] & 0x3F) << 2) + (($temp_cw[1] & 0x30) >> 4); 906 if ($tcw > 0) { 907 $cw[] = $tcw; 908 $cw_num++; 909 } 910 $tcw= (($temp_cw[1] & 0x0F) << 4) + (($temp_cw[2] & 0x3C) >> 2); 911 if ($tcw > 0) { 912 $cw[] = $tcw; 913 $cw_num++; 914 } 915 $tcw = (($temp_cw[2] & 0x03) << 6) + ($temp_cw[3] & 0x3F); 916 if ($tcw > 0) { 917 $cw[] = $tcw; 918 $cw_num++; 919 } 920 $temp_cw = array(); 921 $pos = $epos; 922 $field_length = 0; 923 if ($enc == ENC_ASCII) { 924 break; // exit from EDIFACT mode 925 } 926 } 927 } while ($epos < $data_length); 928 break; 929 } 930 case ENC_BASE256: { // G. While in Base 256 (B256) encodation 931 // initialize temporary array with 0 length 932 $temp_cw = array(); 933 $field_length = 0; 934 while (($pos < $data_length) AND ($field_length <= 1555)) { 935 $newenc = $this->lookAheadTest($data, $pos, $enc); 936 if ($newenc != $enc) { 937 // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode. 938 $enc = $newenc; 939 break; // exit from B256 mode 940 } else { 941 // 2. Otherwise, process the next character in Base 256 encodation. 942 $chr = ord($data[$pos]); 943 ++$pos; 944 $temp_cw[] = $chr; 945 ++$field_length; 946 } 947 } 948 // set field length 949 if ($field_length <= 249) { 950 $cw[] = $this->get255StateCodeword($field_length, ($cw_num + 1)); 951 ++$cw_num; 952 } else { 953 $cw[] = $this->get255StateCodeword((floor($field_length / 250) + 249), ($cw_num + 1)); 954 $cw[] = $this->get255StateCodeword(($field_length % 250), ($cw_num + 2)); 955 $cw_num += 2; 956 } 957 if (!empty($temp_cw)) { 958 // add B256 field 959 foreach ($temp_cw as $p => $cht) { 960 $cw[] = $this->get255StateCodeword($cht, ($cw_num + $p + 1)); 961 } 962 } 963 break; 964 } 965 } // end of switch enc 966 } // end of while 967 return $cw; 968 } 969 970 /** 971 * Places "chr+bit" with appropriate wrapping within array[]. 972 * (Annex F - ECC 200 symbol character placement) 973 * @param array $marr Array of symbols. 974 * @param int $nrow Number of rows. 975 * @param int $ncol Number of columns. 976 * @param int $row Row number. 977 * @param int $col Column number. 978 * @param int $chr Char byte. 979 * @param int $bit Bit. 980 * @return array 981 * @protected 982 */ 983 protected function placeModule($marr, $nrow, $ncol, $row, $col, $chr, $bit) { 984 if ($row < 0) { 985 $row += $nrow; 986 $col += (4 - (($nrow + 4) % 8)); 987 } 988 if ($col < 0) { 989 $col += $ncol; 990 $row += (4 - (($ncol + 4) % 8)); 991 } 992 $marr[(($row * $ncol) + $col)] = ((10 * $chr) + $bit); 993 return $marr; 994 } 995 996 /** 997 * Places the 8 bits of a utah-shaped symbol character. 998 * (Annex F - ECC 200 symbol character placement) 999 * @param array $marr Array of symbols. 1000 * @param int $nrow Number of rows. 1001 * @param int $ncol Number of columns. 1002 * @param int $row Row number. 1003 * @param int $col Column number. 1004 * @param int $chr Char byte. 1005 * @return array 1006 * @protected 1007 */ 1008 protected function placeUtah($marr, $nrow, $ncol, $row, $col, $chr) { 1009 $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-2, $chr, 1); 1010 $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-1, $chr, 2); 1011 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-2, $chr, 3); 1012 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-1, $chr, 4); 1013 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col, $chr, 5); 1014 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-2, $chr, 6); 1015 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-1, $chr, 7); 1016 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col, $chr, 8); 1017 return $marr; 1018 } 1019 1020 /** 1021 * Places the 8 bits of the first special corner case. 1022 * (Annex F - ECC 200 symbol character placement) 1023 * @param array $marr Array of symbols. 1024 * @param int $nrow Number of rows. 1025 * @param int $ncol Number of columns. 1026 * @param int $chr Char byte. 1027 * @return array 1028 * @protected 1029 */ 1030 protected function placeCornerA($marr, $nrow, $ncol, $chr) { 1031 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1); 1032 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 1, $chr, 2); 1033 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 2, $chr, 3); 1034 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); 1035 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); 1036 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6); 1037 $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7); 1038 $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8); 1039 return $marr; 1040 } 1041 1042 /** 1043 * Places the 8 bits of the second special corner case. 1044 * (Annex F - ECC 200 symbol character placement) 1045 * @param array $marr Array of symbols. 1046 * @param int $nrow Number of rows. 1047 * @param int $ncol Number of columns. 1048 * @param int $chr Char byte. 1049 * @return array 1050 * @protected 1051 */ 1052 protected function placeCornerB($marr, $nrow, $ncol, $chr) { 1053 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1); 1054 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2); 1055 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3); 1056 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-4, $chr, 4); 1057 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 5); 1058 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 6); 1059 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 7); 1060 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8); 1061 return $marr; 1062 } 1063 1064 /** 1065 * Places the 8 bits of the third special corner case. 1066 * (Annex F - ECC 200 symbol character placement) 1067 * @param array $marr Array of symbols. 1068 * @param int $nrow Number of rows. 1069 * @param int $ncol Number of columns. 1070 * @param int $chr Char byte. 1071 * @return array 1072 * @protected 1073 */ 1074 protected function placeCornerC($marr, $nrow, $ncol, $chr) { 1075 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1); 1076 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2); 1077 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3); 1078 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); 1079 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); 1080 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6); 1081 $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7); 1082 $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8); 1083 return $marr; 1084 } 1085 1086 /** 1087 * Places the 8 bits of the fourth special corner case. 1088 * (Annex F - ECC 200 symbol character placement) 1089 * @param array $marr Array of symbols. 1090 * @param int $nrow Number of rows. 1091 * @param int $ncol Number of columns. 1092 * @param int $chr Char byte. 1093 * @return array 1094 * @protected 1095 */ 1096 protected function placeCornerD($marr, $nrow, $ncol, $chr) { 1097 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1); 1098 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, $ncol-1, $chr, 2); 1099 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 3); 1100 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4); 1101 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5); 1102 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-3, $chr, 6); 1103 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-2, $chr, 7); 1104 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8); 1105 return $marr; 1106 } 1107 1108 /** 1109 * Build a placement map. 1110 * (Annex F - ECC 200 symbol character placement) 1111 * @param int $nrow Number of rows. 1112 * @param int $ncol Number of columns. 1113 * @return array 1114 * @protected 1115 */ 1116 protected function getPlacementMap($nrow, $ncol) { 1117 // initialize array with zeros 1118 $marr = array_fill(0, ($nrow * $ncol), 0); 1119 // set starting values 1120 $chr = 1; 1121 $row = 4; 1122 $col = 0; 1123 do { 1124 // repeatedly first check for one of the special corner cases, then 1125 if (($row == $nrow) AND ($col == 0)) { 1126 $marr = $this->placeCornerA($marr, $nrow, $ncol, $chr); 1127 ++$chr; 1128 } 1129 if (($row == ($nrow - 2)) AND ($col == 0) AND ($ncol % 4)) { 1130 $marr = $this->placeCornerB($marr, $nrow, $ncol, $chr); 1131 ++$chr; 1132 } 1133 if (($row == ($nrow - 2)) AND ($col == 0) AND (($ncol % 8) == 4)) { 1134 $marr = $this->placeCornerC($marr, $nrow, $ncol, $chr); 1135 ++$chr; 1136 } 1137 if (($row == ($nrow + 4)) AND ($col == 2) AND (!($ncol % 8))) { 1138 $marr = $this->placeCornerD($marr, $nrow, $ncol, $chr); 1139 ++$chr; 1140 } 1141 // sweep upward diagonally, inserting successive characters, 1142 do { 1143 if (($row < $nrow) AND ($col >= 0) AND (!$marr[(($row * $ncol) + $col)])) { 1144 $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr); 1145 ++$chr; 1146 } 1147 $row -= 2; 1148 $col += 2; 1149 } while (($row >= 0) AND ($col < $ncol)); 1150 ++$row; 1151 $col += 3; 1152 // & then sweep downward diagonally, inserting successive characters,... 1153 do { 1154 if (($row >= 0) AND ($col < $ncol) AND (!$marr[(($row * $ncol) + $col)])) { 1155 $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr); 1156 ++$chr; 1157 } 1158 $row += 2; 1159 $col -= 2; 1160 } while (($row < $nrow) AND ($col >= 0)); 1161 $row += 3; 1162 ++$col; 1163 // ... until the entire array is scanned 1164 } while (($row < $nrow) OR ($col < $ncol)); 1165 // lastly, if the lower righthand corner is untouched, fill in fixed pattern 1166 if (!$marr[(($nrow * $ncol) - 1)]) { 1167 $marr[(($nrow * $ncol) - 1)] = 1; 1168 $marr[(($nrow * $ncol) - $ncol - 2)] = 1; 1169 } 1170 return $marr; 1171 } 1172 1173 } // end DataMatrix class 1174 //============================================================+ 1175 // END OF FILE 1176 //============================================================+
title
Description
Body
title
Description
Body
title
Description
Body
title
Body