PluginProbe
E2Pdf – Export Pdf Tool for WordPress / 1.32.49
E2Pdf – Export Pdf Tool for WordPress v1.32.49
1.32.49 1.32.48 1.32.43 1.32.40 1.32.34 1.32.32 1.32.31 1.32.26 1.32.22 1.32.23 1.32.18 1.32.17 1.32.15 trunk 1.00.00 1.00.13 1.01.01 1.02.02 1.03.07 1.04.07 1.05.03 1.06.02 1.07.11 1.08.00 1.08.06 All 72 releases
e2pdf / classes / helper / e2pdf-qrcode.php

e2pdf-qrcode.php in E2Pdf – Export Pdf Tool for WordPress 1.32.49, at classes/helper/e2pdf-qrcode.php

3,453 lines 140.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 die('Access denied.');
5 }
6 /* * **************************************************************************\
7
8 barcode.php - Generate barcodes from a single PHP file. MIT license.
9
10 Copyright (c) 2016-2018 Kreative Software.
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in
20 all copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
29
30 \*************************************************************************** */
31
32 class Helper_E2pdf_Qrcode {
33
34 public function qrcode($data = '', $field = array()) {
35
36 if (!$data) {
37 return '';
38 }
39
40 $symbology = isset($field['properties']['precision']) && $field['properties']['precision'] ? $field['properties']['precision'] : 'qrl';
41 if (!in_array($symbology, array('qrl', 'qrm', 'qrq', 'qrh'))) {
42 $symbology = 'qrl';
43 }
44
45 $img = $this->render_svg($symbology, $data, $this->get_options('qrcode', $field));
46 return base64_encode($img);
47 }
48
49 public function barcode($data = '', $field = array()) {
50
51 if (!$data) {
52 return '';
53 }
54
55 $symbology = isset($field['properties']['format']) && $field['properties']['format'] ? $field['properties']['format'] : 'upc-a';
56
57 if (!in_array($symbology,
58 array('upc-a', 'upc-e', 'ean-8',
59 'ean-13', 'ean-13-pad', 'ean-13-nopad', ' ean-128',
60 'code-39', 'code-39-ascii', 'code-93', 'code-93-ascii',
61 'code-128', 'codabar', 'itf', 'dmtx', 'dmtx-s', 'dmtx-r',
62 'gs1-dmtx', 'gs1-dmtx-s', 'gs1-dmtx-r')
63 )) {
64 $symbology = 'upc-a';
65 }
66
67 $img = $this->render_svg($symbology, $data, $this->get_options('barcode', $field));
68 return base64_encode($img);
69 }
70
71 public function get_options($type, $field = array()) {
72 $options = array();
73
74 if ($type == 'barcode') {
75
76 $options['pt'] = isset($field['properties']['margin_top']) ? (int) $field['properties']['margin_top'] : '10';
77 $options['pl'] = isset($field['properties']['margin_left']) ? (int) $field['properties']['margin_left'] : '10';
78 $options['pr'] = isset($field['properties']['margin_right']) ? (int) $field['properties']['margin_right'] : '10';
79 $options['pb'] = isset($field['properties']['margin_bottom']) ? (int) $field['properties']['margin_bottom'] : '10';
80 $options['wq'] = isset($field['properties']['wq']) ? $field['properties']['wq'] : '1';
81
82 $text_font = isset($field['properties']['text_font']) && $field['properties']['text_font'] ? $field['properties']['text_font'] : '';
83 if ($text_font) {
84 $options['tf'] = $text_font;
85 }
86
87 $text_font_size = isset($field['properties']['text_font_size']) && $field['properties']['text_font_size'] ? $field['properties']['text_font_size'] : '';
88 if ($text_font_size) {
89 $options['ts'] = $text_font_size;
90 }
91
92 $text_line_height = isset($field['properties']['text_line_height']) && $field['properties']['text_line_height'] ? $field['properties']['text_line_height'] : '';
93 if ($text_line_height) {
94 $options['th'] = $text_line_height;
95 }
96
97 $scale = isset($field['properties']['scale']) ? $field['properties']['scale'] : '1';
98 if ($scale == '1') {
99 $options['w'] = $field['width'];
100 $options['h'] = $field['height'];
101 } elseif ($scale == '2') {
102 $options['w'] = $field['width'];
103 } elseif ($scale == '3') {
104 $options['h'] = $field['height'];
105 }
106
107 $color = isset($field['properties']['color']) && $field['properties']['color'] ? $field['properties']['color'] : false;
108 if ($color) {
109 $options['cm'] = $color;
110 }
111
112 $text_color = isset($field['properties']['text_color']) && $field['properties']['text_color'] ? $field['properties']['text_color'] : false;
113 if ($text_color) {
114 $options['tc'] = $text_color;
115 }
116
117 $background = isset($field['properties']['background']) && $field['properties']['background'] ? $field['properties']['background'] : false;
118 if ($background) {
119 $options['bc'] = $background;
120 $options['cs'] = $background;
121 }
122
123 $hide_label = isset($field['properties']['hl']) && $field['properties']['hl'] ? true : false;
124 if ($hide_label) {
125 $options['hl'] = true;
126 }
127 } elseif ($type == 'qrcode') {
128
129 $options['pt'] = isset($field['properties']['margin_top']) ? (int) $field['properties']['margin_top'] : '0';
130 $options['pl'] = isset($field['properties']['margin_left']) ? (int) $field['properties']['margin_left'] : '0';
131 $options['pr'] = isset($field['properties']['margin_right']) ? (int) $field['properties']['margin_right'] : '0';
132 $options['pb'] = isset($field['properties']['margin_bottom']) ? (int) $field['properties']['margin_bottom'] : '0';
133 $options['wq'] = isset($field['properties']['wq']) ? $field['properties']['wq'] : '1';
134
135 $color = isset($field['properties']['color']) && $field['properties']['color'] ? $field['properties']['color'] : false;
136 if ($color) {
137 $options['cm'] = $color;
138 }
139
140 $background = isset($field['properties']['background']) && $field['properties']['background'] ? $field['properties']['background'] : false;
141 if ($background) {
142 $options['bc'] = $background;
143 $options['cs'] = $background;
144 }
145 }
146
147 return $options;
148 }
149
150 public function render_image($symbology, $data, $options) {
151 list($code, $widths, $width, $height, $x, $y, $w, $h) = $this->encode_and_calculate_size($symbology, $data, $options);
152 $image = imagecreatetruecolor($width, $height);
153 imagesavealpha($image, true);
154 $bgcolor = (isset($options['bc']) ? $options['bc'] : '');
155 $bgcolor = $this->allocate_color($image, $bgcolor);
156 imagefill($image, 0, 0, $bgcolor);
157 $colors = array(
158 (isset($options['cs']) ? $options['cs'] : ''),
159 (isset($options['cm']) ? $options['cm'] : '000'),
160 (isset($options['c2']) ? $options['c2'] : 'F00'),
161 (isset($options['c3']) ? $options['c3'] : 'FF0'),
162 (isset($options['c4']) ? $options['c4'] : '0F0'),
163 (isset($options['c5']) ? $options['c5'] : '0FF'),
164 (isset($options['c6']) ? $options['c6'] : '00F'),
165 (isset($options['c7']) ? $options['c7'] : 'F0F'),
166 (isset($options['c8']) ? $options['c8'] : 'FFF'),
167 (isset($options['c9']) ? $options['c9'] : '000'),
168 );
169 foreach ($colors as $i => $color) {
170 $colors[$i] = $this->allocate_color($image, $color);
171 }
172 $this->dispatch_render_image(
173 $image, $code, $x, $y, $w, $h, $colors, $widths, $options
174 );
175 return $image;
176 }
177
178 public function render_svg($symbology, $data, $options) {
179 list($code, $widths, $width, $height, $x, $y, $w, $h) = $this->encode_and_calculate_size($symbology, $data, $options);
180 $svg = '<?xml version="1.0"?>';
181 $svg .= '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"';
182 $svg .= ' width="' . $width . '" height="' . $height . '"';
183 $svg .= ' viewBox="0 0 ' . $width . ' ' . $height . '"><g>';
184 $bgcolor = (isset($options['bc']) ? $options['bc'] : '');
185 if ($bgcolor) {
186 $svg .= '<rect x="0" y="0"';
187 $svg .= ' width="' . $width . '" height="' . $height . '"';
188 $svg .= ' fill="' . htmlspecialchars($bgcolor) . '"/>';
189 }
190 $colors = array(
191 (isset($options['cs']) ? $options['cs'] : ''),
192 (isset($options['cm']) ? $options['cm'] : 'black'),
193 (isset($options['c2']) ? $options['c2'] : '#FF0000'),
194 (isset($options['c3']) ? $options['c3'] : '#FFFF00'),
195 (isset($options['c4']) ? $options['c4'] : '#00FF00'),
196 (isset($options['c5']) ? $options['c5'] : '#00FFFF'),
197 (isset($options['c6']) ? $options['c6'] : '#0000FF'),
198 (isset($options['c7']) ? $options['c7'] : '#FF00FF'),
199 (isset($options['c8']) ? $options['c8'] : 'white'),
200 (isset($options['c9']) ? $options['c9'] : 'black'),
201 );
202 $svg .= $this->dispatch_render_svg(
203 $code, $x, $y, $w, $h, $colors, $widths, $options
204 );
205 $svg .= '</g></svg>';
206 return $svg;
207 }
208
209 /* - - - - INTERNAL FUNCTIONS - - - - */
210
211 private function encode_and_calculate_size($symbology, $data, $options) {
212 $code = $this->dispatch_encode($symbology, $data, $options);
213 $widths = array(
214 (isset($options['wq']) ? (int) $options['wq'] : 1),
215 (isset($options['wm']) ? (int) $options['wm'] : 1),
216 (isset($options['ww']) ? (int) $options['ww'] : 3),
217 (isset($options['wn']) ? (int) $options['wn'] : 1),
218 (isset($options['w4']) ? (int) $options['w4'] : 1),
219 (isset($options['w5']) ? (int) $options['w5'] : 1),
220 (isset($options['w6']) ? (int) $options['w6'] : 1),
221 (isset($options['w7']) ? (int) $options['w7'] : 1),
222 (isset($options['w8']) ? (int) $options['w8'] : 1),
223 (isset($options['w9']) ? (int) $options['w9'] : 1),
224 );
225 $size = $this->dispatch_calculate_size($code, $widths, $options);
226 $dscale = ($code && isset($code['g']) && $code['g'] == 'm') ? 4 : 1;
227 $scale = (isset($options['sf']) ? (float) $options['sf'] : $dscale);
228 $scalex = (isset($options['sx']) ? (float) $options['sx'] : $scale);
229 $scaley = (isset($options['sy']) ? (float) $options['sy'] : $scale);
230 $dpadding = ($code && isset($code['g']) && $code['g'] == 'm') ? 0 : 10;
231 $padding = (isset($options['p']) ? (int) $options['p'] : $dpadding);
232 $vert = (isset($options['pv']) ? (int) $options['pv'] : $padding);
233 $horiz = (isset($options['ph']) ? (int) $options['ph'] : $padding);
234 $top = (isset($options['pt']) ? (int) $options['pt'] : $vert);
235 $left = (isset($options['pl']) ? (int) $options['pl'] : $horiz);
236 $right = (isset($options['pr']) ? (int) $options['pr'] : $horiz);
237 $bottom = (isset($options['pb']) ? (int) $options['pb'] : $vert);
238 $dwidth = ceil($size[0] * $scalex) + $left + $right;
239 $dheight = ceil($size[1] * $scaley) + $top + $bottom;
240 $iwidth = (isset($options['w']) ? (int) $options['w'] : $dwidth);
241 $iheight = (isset($options['h']) ? (int) $options['h'] : $dheight);
242 $swidth = $iwidth - $left - $right;
243 $sheight = $iheight - $top - $bottom;
244 return array(
245 $code, $widths, $iwidth, $iheight,
246 $left, $top, $swidth, $sheight
247 );
248 }
249
250 private function allocate_color($image, $color) {
251 $color = preg_replace('/[^0-9A-Fa-f]/', '', $color);
252 switch (strlen($color)) {
253 case 1:
254 $v = hexdec($color) * 17;
255 return imagecolorallocate($image, $v, $v, $v);
256 case 2:
257 $v = hexdec($color);
258 return imagecolorallocate($image, $v, $v, $v);
259 case 3:
260 $r = hexdec(substr($color, 0, 1)) * 17;
261 $g = hexdec(substr($color, 1, 1)) * 17;
262 $b = hexdec(substr($color, 2, 1)) * 17;
263 return imagecolorallocate($image, $r, $g, $b);
264 case 4:
265 $a = hexdec(substr($color, 0, 1)) * 17;
266 $r = hexdec(substr($color, 1, 1)) * 17;
267 $g = hexdec(substr($color, 2, 1)) * 17;
268 $b = hexdec(substr($color, 3, 1)) * 17;
269 $a = round((255 - $a) * 127 / 255);
270 return imagecolorallocatealpha($image, $r, $g, $b, $a);
271 case 6:
272 $r = hexdec(substr($color, 0, 2));
273 $g = hexdec(substr($color, 2, 2));
274 $b = hexdec(substr($color, 4, 2));
275 return imagecolorallocate($image, $r, $g, $b);
276 case 8:
277 $a = hexdec(substr($color, 0, 2));
278 $r = hexdec(substr($color, 2, 2));
279 $g = hexdec(substr($color, 4, 2));
280 $b = hexdec(substr($color, 6, 2));
281 $a = round((255 - $a) * 127 / 255);
282 return imagecolorallocatealpha($image, $r, $g, $b, $a);
283 default:
284 return imagecolorallocatealpha($image, 0, 0, 0, 127);
285 }
286 }
287
288 /* - - - - DISPATCH - - - - */
289
290 private function dispatch_encode($symbology, $data, $options) {
291 switch (strtolower(preg_replace('/[^A-Za-z0-9]/', '', $symbology))) {
292 case 'upca' : return $this->upc_a_encode($data);
293 case 'upce' : return $this->upc_e_encode($data);
294 case 'ean13nopad' : return $this->ean_13_encode($data, ' ');
295 case 'ean13pad' : return $this->ean_13_encode($data, '>');
296 case 'ean13' : return $this->ean_13_encode($data, '>');
297 case 'ean8' : return $this->ean_8_encode($data);
298 case 'code39' : return $this->code_39_encode($data);
299 case 'code39ascii': return $this->code_39_ascii_encode($data);
300 case 'code93' : return $this->code_93_encode($data);
301 case 'code93ascii': return $this->code_93_ascii_encode($data);
302 case 'code128' : return $this->code_128_encode($data, 0, false);
303 case 'code128a' : return $this->code_128_encode($data, 1, false);
304 case 'code128b' : return $this->code_128_encode($data, 2, false);
305 case 'code128c' : return $this->code_128_encode($data, 3, false);
306 case 'code128ac' : return $this->code_128_encode($data, -1, false);
307 case 'code128bc' : return $this->code_128_encode($data, -2, false);
308 case 'ean128' : return $this->code_128_encode($data, 0, true);
309 case 'ean128a' : return $this->code_128_encode($data, 1, true);
310 case 'ean128b' : return $this->code_128_encode($data, 2, true);
311 case 'ean128c' : return $this->code_128_encode($data, 3, true);
312 case 'ean128ac' : return $this->code_128_encode($data, -1, true);
313 case 'ean128bc' : return $this->code_128_encode($data, -2, true);
314 case 'codabar' : return $this->codabar_encode($data);
315 case 'itf' : return $this->itf_encode($data);
316 case 'itf14' : return $this->itf_encode($data);
317 case 'qr' : return $this->qr_encode($data, 0);
318 case 'qrl' : return $this->qr_encode($data, 0);
319 case 'qrm' : return $this->qr_encode($data, 1);
320 case 'qrq' : return $this->qr_encode($data, 2);
321 case 'qrh' : return $this->qr_encode($data, 3);
322 case 'dmtx' : return $this->dmtx_encode($data, false, false);
323 case 'dmtxs' : return $this->dmtx_encode($data, false, false);
324 case 'dmtxr' : return $this->dmtx_encode($data, true, false);
325 case 'gs1dmtx' : return $this->dmtx_encode($data, false, true);
326 case 'gs1dmtxs' : return $this->dmtx_encode($data, false, true);
327 case 'gs1dmtxr' : return $this->dmtx_encode($data, true, true);
328 }
329 return null;
330 }
331
332 private function dispatch_calculate_size($code, $widths, $options) {
333 if ($code && isset($code['g']) && $code['g']) {
334 switch ($code['g']) {
335 case 'l':
336 return $this->linear_calculate_size($code, $widths);
337 case 'm':
338 return $this->matrix_calculate_size($code, $widths);
339 }
340 }
341 return array(0, 0);
342 }
343
344 private function dispatch_render_image(
345 $image, $code, $x, $y, $w, $h, $colors, $widths, $options
346 ) {
347 if ($code && isset($code['g']) && $code['g']) {
348 switch ($code['g']) {
349 case 'l':
350 $this->linear_render_image(
351 $image, $code, $x, $y, $w, $h,
352 $colors, $widths, $options
353 );
354 break;
355 case 'm':
356 $this->matrix_render_image(
357 $image, $code, $x, $y, $w, $h,
358 $colors, $widths, $options
359 );
360 break;
361 }
362 }
363 }
364
365 private function dispatch_render_svg(
366 $code, $x, $y, $w, $h, $colors, $widths, $options
367 ) {
368 if ($code && isset($code['g']) && $code['g']) {
369 switch ($code['g']) {
370 case 'l':
371 return $this->linear_render_svg(
372 $code, $x, $y, $w, $h,
373 $colors, $widths, $options
374 );
375 case 'm':
376 return $this->matrix_render_svg(
377 $code, $x, $y, $w, $h,
378 $colors, $widths, $options
379 );
380 }
381 }
382 return '';
383 }
384
385 /* - - - - LINEAR BARCODE RENDERER - - - - */
386
387 private function linear_calculate_size($code, $widths) {
388 $width = 0;
389 foreach ($code['b'] as $block) {
390 foreach ($block['m'] as $module) {
391 $width += $module[1] * $widths[$module[2]];
392 }
393 }
394 return array($width, 80);
395 }
396
397 private function linear_render_image(
398 $image, $code, $x, $y, $w, $h, $colors, $widths, $options
399 ) {
400 $textheight = (isset($options['th']) ? (int) $options['th'] : 10);
401 $textsize = (isset($options['ts']) ? (int) $options['ts'] : 1);
402 $textcolor = (isset($options['tc']) ? $options['tc'] : '000');
403 $textcolor = $this->allocate_color($image, $textcolor);
404 $width = 0;
405 foreach ($code['b'] as $block) {
406 foreach ($block['m'] as $module) {
407 $width += $module[1] * $widths[$module[2]];
408 }
409 }
410 if ($width) {
411 $scale = $w / $width;
412 $scale = (($scale > 1) ? floor($scale) : 1);
413 $x = floor($x + ($w - $width * $scale) / 2);
414 } else {
415 $scale = 1;
416 $x = floor($x + $w / 2);
417 }
418 foreach ($code['b'] as $block) {
419 if (isset($block['l'])) {
420 $label = $block['l'][0];
421 $ly = (isset($block['l'][1]) ? (float) $block['l'][1] : 1);
422 $lx = (isset($block['l'][2]) ? (float) $block['l'][2] : 0.5);
423 $my = round($y + min($h, $h + ($ly - 1) * $textheight));
424 $ly = ($y + $h + $ly * $textheight);
425 $ly = round($ly - imagefontheight($textsize));
426 } else {
427 $label = null;
428 $my = $y + $h;
429 }
430 $mx = $x;
431 foreach ($block['m'] as $module) {
432 $mc = $colors[$module[0]];
433 $mw = $mx + $module[1] * $widths[$module[2]] * $scale;
434 imagefilledrectangle($image, $mx, $y, $mw - 1, $my - 1, $mc);
435 $mx = $mw;
436 }
437 if (!is_null($label)) {
438 $lx = ($x + ($mx - $x) * $lx);
439 $lw = imagefontwidth($textsize) * strlen($label);
440 $lx = round($lx - $lw / 2);
441 imagestring($image, $textsize, $lx, $ly, $label, $textcolor);
442 }
443 $x = $mx;
444 }
445 }
446
447 private function linear_render_svg(
448 $code, $x, $y, $w, $h, $colors, $widths, $options
449 ) {
450 $textheight = (isset($options['th']) ? (int) $options['th'] : 10);
451 $textfont = (isset($options['tf']) ? $options['tf'] : 'monospace');
452 $textsize = (isset($options['ts']) ? (int) $options['ts'] : 8);
453 $textcolor = (isset($options['tc']) ? $options['tc'] : 'black');
454 $hidelabel = isset($options['hl']) && $options['hl'] ? true : false;
455
456 $width = 0;
457 foreach ($code['b'] as $block) {
458 foreach ($block['m'] as $module) {
459 $width += $module[1] * $widths[$module[2]];
460 }
461 }
462 if ($width) {
463 $scale = $w / $width;
464 if ($scale > 1) {
465 $scale = floor($scale);
466 $x = floor($x + ($w - $width * $scale) / 2);
467 }
468 } else {
469 $scale = 1;
470 $x = floor($x + $w / 2);
471 }
472 $tx = 'translate(' . $x . ' ' . $y . ')';
473 if ($scale != 1)
474 $tx .= ' scale(' . $scale . ' 1)';
475 $svg = '<g transform="' . htmlspecialchars($tx) . '">';
476 $x = 0;
477 foreach ($code['b'] as $block) {
478 if (isset($block['l'])) {
479 $label = $block['l'][0];
480 $ly = (isset($block['l'][1]) ? (float) $block['l'][1] : 1);
481 $lx = (isset($block['l'][2]) ? (float) $block['l'][2] : 0.5);
482 $mh = min($h, $h + ($ly - 1) * $textheight);
483 $ly = $h + $ly * $textheight;
484 } else {
485 $label = null;
486 $mh = $h;
487 }
488 $svg .= '<g>';
489 $mx = $x;
490 foreach ($block['m'] as $module) {
491 $mc = htmlspecialchars($colors[$module[0]]);
492 $mw = $module[1] * $widths[$module[2]];
493 if ($mc) {
494 $svg .= '<rect';
495 $svg .= ' x="' . $mx . '" y="0"';
496 $svg .= ' width="' . $mw . '"';
497 $svg .= ' height="' . $mh . '"';
498 $svg .= ' fill="' . $mc . '"/>';
499 }
500 $mx += $mw;
501 }
502 if (!is_null($label) && !$hidelabel) {
503 $lx = ($x + ($mx - $x) * $lx);
504 $svg .= '<text';
505 $svg .= ' x="' . $lx . '" y="' . $ly . '"';
506 $svg .= ' text-anchor="middle"';
507 $svg .= ' font-family="' . htmlspecialchars($textfont) . '"';
508 $svg .= ' font-size="' . htmlspecialchars($textsize) . '"';
509 $svg .= ' fill="' . htmlspecialchars($textcolor) . '">';
510 $svg .= htmlspecialchars($label);
511 $svg .= '</text>';
512 }
513 $svg .= '</g>';
514 $x = $mx;
515 }
516 return $svg . '</g>';
517 }
518
519 /* - - - - MATRIX BARCODE RENDERER - - - - */
520
521 private function matrix_calculate_size($code, $widths) {
522 $width = (
523 $code['q'][3] * $widths[0] +
524 $code['s'][0] * $widths[1] +
525 $code['q'][1] * $widths[0]
526 );
527 $height = (
528 $code['q'][0] * $widths[0] +
529 $code['s'][1] * $widths[1] +
530 $code['q'][2] * $widths[0]
531 );
532 return array($width, $height);
533 }
534
535 private function matrix_render_image(
536 $image, $code, $x, $y, $w, $h, $colors, $widths, $options
537 ) {
538 $shape = (isset($options['ms']) ? strtolower($options['ms']) : '');
539 $density = (isset($options['md']) ? (float) $options['md'] : 1);
540 list($width, $height) = $this->matrix_calculate_size($code, $widths);
541 if ($width && $height) {
542 $scale = min($w / $width, $h / $height);
543 $scale = (($scale > 1) ? floor($scale) : 1);
544 $x = floor($x + ($w - $width * $scale) / 2);
545 $y = floor($y + ($h - $height * $scale) / 2);
546 } else {
547 $scale = 1;
548 $x = floor($x + $w / 2);
549 $y = floor($y + $h / 2);
550 }
551 $x += $code['q'][3] * $widths[0] * $scale;
552 $y += $code['q'][0] * $widths[0] * $scale;
553 $wh = $widths[1] * $scale;
554 foreach ($code['b'] as $by => $row) {
555 $y1 = $y + $by * $wh;
556 foreach ($row as $bx => $color) {
557 $x1 = $x + $bx * $wh;
558 $mc = $colors[$color];
559 $this->matrix_dot_image(
560 $image, $x1, $y1, $wh, $wh, $mc, $shape, $density
561 );
562 }
563 }
564 }
565
566 private function matrix_render_svg(
567 $code, $x, $y, $w, $h, $colors, $widths, $options
568 ) {
569 $shape = (isset($options['ms']) ? strtolower($options['ms']) : '');
570 $density = (isset($options['md']) ? (float) $options['md'] : 1);
571 list($width, $height) = $this->matrix_calculate_size($code, $widths);
572 if ($width && $height) {
573 $scale = min($w / $width, $h / $height);
574 if ($scale > 1)
575 $scale = floor($scale);
576 $x = floor($x + ($w - $width * $scale) / 2);
577 $y = floor($y + ($h - $height * $scale) / 2);
578 } else {
579 $scale = 1;
580 $x = floor($x + $w / 2);
581 $y = floor($y + $h / 2);
582 }
583 $tx = 'translate(' . $x . ' ' . $y . ')';
584 if ($scale != 1)
585 $tx .= ' scale(' . $scale . ' ' . $scale . ')';
586 $svg = '<g transform="' . htmlspecialchars($tx) . '">';
587 $x = $code['q'][3] * $widths[0];
588 $y = $code['q'][0] * $widths[0];
589 $wh = $widths[1];
590 foreach ($code['b'] as $by => $row) {
591 $y1 = $y + $by * $wh;
592 foreach ($row as $bx => $color) {
593 $x1 = $x + $bx * $wh;
594 $mc = $colors[$color];
595 if ($mc) {
596 $svg .= $this->matrix_dot_svg(
597 $x1, $y1, $wh, $wh, $mc, $shape, $density
598 );
599 }
600 }
601 }
602 return $svg . '</g>';
603 }
604
605 private function matrix_dot_image($image, $x, $y, $w, $h, $mc, $ms, $md) {
606 switch ($ms) {
607 default:
608 $x = floor($x + (1 - $md) * $w / 2);
609 $y = floor($y + (1 - $md) * $h / 2);
610 $w = ceil($w * $md);
611 $h = ceil($h * $md);
612 imagefilledrectangle($image, $x, $y, $x + $w - 1, $y + $h - 1, $mc);
613 break;
614 case 'r':
615 $cx = floor($x + $w / 2);
616 $cy = floor($y + $h / 2);
617 $dx = ceil($w * $md);
618 $dy = ceil($h * $md);
619 imagefilledellipse($image, $cx, $cy, $dx, $dy, $mc);
620 break;
621 case 'x':
622 $x = floor($x + (1 - $md) * $w / 2);
623 $y = floor($y + (1 - $md) * $h / 2);
624 $w = ceil($w * $md);
625 $h = ceil($h * $md);
626 imageline($image, $x, $y, $x + $w - 1, $y + $h - 1, $mc);
627 imageline($image, $x, $y + $h - 1, $x + $w - 1, $y, $mc);
628 break;
629 }
630 }
631
632 private function matrix_dot_svg($x, $y, $w, $h, $mc, $ms, $md) {
633 switch ($ms) {
634 default:
635 $x += (1 - $md) * $w / 2;
636 $y += (1 - $md) * $h / 2;
637 $w *= $md;
638 $h *= $md;
639 $svg = '<rect x="' . $x . '" y="' . $y . '"';
640 $svg .= ' width="' . $w . '" height="' . $h . '"';
641 $svg .= ' fill="' . $mc . '"/>';
642 return $svg;
643 case 'r':
644 $cx = $x + $w / 2;
645 $cy = $y + $h / 2;
646 $rx = $w * $md / 2;
647 $ry = $h * $md / 2;
648 $svg = '<ellipse cx="' . $cx . '" cy="' . $cy . '"';
649 $svg .= ' rx="' . $rx . '" ry="' . $ry . '"';
650 $svg .= ' fill="' . $mc . '"/>';
651 return $svg;
652 case 'x':
653 $x1 = $x + (1 - $md) * $w / 2;
654 $y1 = $y + (1 - $md) * $h / 2;
655 $x2 = $x + $w - (1 - $md) * $w / 2;
656 $y2 = $y + $h - (1 - $md) * $h / 2;
657 $svg = '<line x1="' . $x1 . '" y1="' . $y1 . '"';
658 $svg .= ' x2="' . $x2 . '" y2="' . $y2 . '"';
659 $svg .= ' stroke="' . $mc . '"';
660 $svg .= ' stroke-width="' . ($md / 5) . '"/>';
661 $svg .= '<line x1="' . $x1 . '" y1="' . $y2 . '"';
662 $svg .= ' x2="' . $x2 . '" y2="' . $y1 . '"';
663 $svg .= ' stroke="' . $mc . '"';
664 $svg .= ' stroke-width="' . ($md / 5) . '"/>';
665 return '<g>' . $svg . '</g>';
666 }
667 }
668
669 /* - - - - UPC FAMILY ENCODER - - - - */
670
671 private function upc_a_encode($data) {
672 $data = $this->upc_a_normalize($data);
673 $blocks = array();
674 /* Quiet zone, start, first digit. */
675 $digit = substr($data, 0, 1);
676 $blocks[] = array(
677 'm' => array(array(0, 9, 0)),
678 'l' => array($digit, 0, 1 / 3)
679 );
680 $blocks[] = array(
681 'm' => array(
682 array(1, 1, 1),
683 array(0, 1, 1),
684 array(1, 1, 1),
685 )
686 );
687 $blocks[] = array(
688 'm' => array(
689 array(0, $this->upc_alphabet[$digit][0], 1),
690 array(1, $this->upc_alphabet[$digit][1], 1),
691 array(0, $this->upc_alphabet[$digit][2], 1),
692 array(1, $this->upc_alphabet[$digit][3], 1),
693 )
694 );
695 /* Left zone. */
696 for ($i = 1; $i < 6; $i++) {
697 $digit = substr($data, $i, 1);
698 $blocks[] = array(
699 'm' => array(
700 array(0, $this->upc_alphabet[$digit][0], 1),
701 array(1, $this->upc_alphabet[$digit][1], 1),
702 array(0, $this->upc_alphabet[$digit][2], 1),
703 array(1, $this->upc_alphabet[$digit][3], 1),
704 ),
705 'l' => array($digit, 0.5, (6 - $i) / 6)
706 );
707 }
708 /* Middle. */
709 $blocks[] = array(
710 'm' => array(
711 array(0, 1, 1),
712 array(1, 1, 1),
713 array(0, 1, 1),
714 array(1, 1, 1),
715 array(0, 1, 1),
716 )
717 );
718 /* Right zone. */
719 for ($i = 6; $i < 11; $i++) {
720 $digit = substr($data, $i, 1);
721 $blocks[] = array(
722 'm' => array(
723 array(1, $this->upc_alphabet[$digit][0], 1),
724 array(0, $this->upc_alphabet[$digit][1], 1),
725 array(1, $this->upc_alphabet[$digit][2], 1),
726 array(0, $this->upc_alphabet[$digit][3], 1),
727 ),
728 'l' => array($digit, 0.5, (11 - $i) / 6)
729 );
730 }
731 /* Last digit, end, quiet zone. */
732 $digit = substr($data, 11, 1);
733 $blocks[] = array(
734 'm' => array(
735 array(1, $this->upc_alphabet[$digit][0], 1),
736 array(0, $this->upc_alphabet[$digit][1], 1),
737 array(1, $this->upc_alphabet[$digit][2], 1),
738 array(0, $this->upc_alphabet[$digit][3], 1),
739 )
740 );
741 $blocks[] = array(
742 'm' => array(
743 array(1, 1, 1),
744 array(0, 1, 1),
745 array(1, 1, 1),
746 )
747 );
748 $blocks[] = array(
749 'm' => array(array(0, 9, 0)),
750 'l' => array($digit, 0, 2 / 3)
751 );
752 /* Return code. */
753 return array('g' => 'l', 'b' => $blocks);
754 }
755
756 private function upc_e_encode($data) {
757 $data = $this->upc_e_normalize($data);
758 $blocks = array();
759 /* Quiet zone, start. */
760 $blocks[] = array(
761 'm' => array(array(0, 9, 0))
762 );
763 $blocks[] = array(
764 'm' => array(
765 array(1, 1, 1),
766 array(0, 1, 1),
767 array(1, 1, 1),
768 )
769 );
770 /* Digits */
771 $system = substr($data, 0, 1) & 1;
772 $check = substr($data, 7, 1);
773 $pbits = $this->upc_parity[$check];
774 for ($i = 1; $i < 7; $i++) {
775 $digit = substr($data, $i, 1);
776 $pbit = $pbits[$i - 1] ^ $system;
777 $blocks[] = array(
778 'm' => array(
779 array(0, $this->upc_alphabet[$digit][$pbit ? 3 : 0], 1),
780 array(1, $this->upc_alphabet[$digit][$pbit ? 2 : 1], 1),
781 array(0, $this->upc_alphabet[$digit][$pbit ? 1 : 2], 1),
782 array(1, $this->upc_alphabet[$digit][$pbit ? 0 : 3], 1),
783 ),
784 'l' => array($digit, 0.5, (7 - $i) / 7)
785 );
786 }
787 /* End, quiet zone. */
788 $blocks[] = array(
789 'm' => array(
790 array(0, 1, 1),
791 array(1, 1, 1),
792 array(0, 1, 1),
793 array(1, 1, 1),
794 array(0, 1, 1),
795 array(1, 1, 1),
796 )
797 );
798 $blocks[] = array(
799 'm' => array(array(0, 9, 0))
800 );
801 /* Return code. */
802 return array('g' => 'l', 'b' => $blocks);
803 }
804
805 private function ean_13_encode($data, $pad) {
806 $data = $this->ean_13_normalize($data);
807 $blocks = array();
808 /* Quiet zone, start, first digit (as parity). */
809 $system = substr($data, 0, 1);
810 $pbits = (
811 (int) $system ?
812 $this->upc_parity[$system] :
813 array(1, 1, 1, 1, 1, 1)
814 );
815 $blocks[] = array(
816 'm' => array(array(0, 9, 0)),
817 'l' => array($system, 0.5, 1 / 3)
818 );
819 $blocks[] = array(
820 'm' => array(
821 array(1, 1, 1),
822 array(0, 1, 1),
823 array(1, 1, 1),
824 )
825 );
826 /* Left zone. */
827 for ($i = 1; $i < 7; $i++) {
828 $digit = substr($data, $i, 1);
829 $pbit = $pbits[$i - 1];
830 $blocks[] = array(
831 'm' => array(
832 array(0, $this->upc_alphabet[$digit][$pbit ? 0 : 3], 1),
833 array(1, $this->upc_alphabet[$digit][$pbit ? 1 : 2], 1),
834 array(0, $this->upc_alphabet[$digit][$pbit ? 2 : 1], 1),
835 array(1, $this->upc_alphabet[$digit][$pbit ? 3 : 0], 1),
836 ),
837 'l' => array($digit, 0.5, (7 - $i) / 7)
838 );
839 }
840 /* Middle. */
841 $blocks[] = array(
842 'm' => array(
843 array(0, 1, 1),
844 array(1, 1, 1),
845 array(0, 1, 1),
846 array(1, 1, 1),
847 array(0, 1, 1),
848 )
849 );
850 /* Right zone. */
851 for ($i = 7; $i < 13; $i++) {
852 $digit = substr($data, $i, 1);
853 $blocks[] = array(
854 'm' => array(
855 array(1, $this->upc_alphabet[$digit][0], 1),
856 array(0, $this->upc_alphabet[$digit][1], 1),
857 array(1, $this->upc_alphabet[$digit][2], 1),
858 array(0, $this->upc_alphabet[$digit][3], 1),
859 ),
860 'l' => array($digit, 0.5, (13 - $i) / 7)
861 );
862 }
863 /* End, quiet zone. */
864 $blocks[] = array(
865 'm' => array(
866 array(1, 1, 1),
867 array(0, 1, 1),
868 array(1, 1, 1),
869 )
870 );
871 $blocks[] = array(
872 'm' => array(array(0, 9, 0)),
873 'l' => array($pad, 0.5, 2 / 3)
874 );
875 /* Return code. */
876 return array('g' => 'l', 'b' => $blocks);
877 }
878
879 private function ean_8_encode($data) {
880 $data = $this->ean_8_normalize($data);
881 $blocks = array();
882 /* Quiet zone, start. */
883 $blocks[] = array(
884 'm' => array(array(0, 9, 0)),
885 'l' => array('<', 0.5, 1 / 3)
886 );
887 $blocks[] = array(
888 'm' => array(
889 array(1, 1, 1),
890 array(0, 1, 1),
891 array(1, 1, 1),
892 )
893 );
894 /* Left zone. */
895 for ($i = 0; $i < 4; $i++) {
896 $digit = substr($data, $i, 1);
897 $blocks[] = array(
898 'm' => array(
899 array(0, $this->upc_alphabet[$digit][0], 1),
900 array(1, $this->upc_alphabet[$digit][1], 1),
901 array(0, $this->upc_alphabet[$digit][2], 1),
902 array(1, $this->upc_alphabet[$digit][3], 1),
903 ),
904 'l' => array($digit, 0.5, (4 - $i) / 5)
905 );
906 }
907 /* Middle. */
908 $blocks[] = array(
909 'm' => array(
910 array(0, 1, 1),
911 array(1, 1, 1),
912 array(0, 1, 1),
913 array(1, 1, 1),
914 array(0, 1, 1),
915 )
916 );
917 /* Right zone. */
918 for ($i = 4; $i < 8; $i++) {
919 $digit = substr($data, $i, 1);
920 $blocks[] = array(
921 'm' => array(
922 array(1, $this->upc_alphabet[$digit][0], 1),
923 array(0, $this->upc_alphabet[$digit][1], 1),
924 array(1, $this->upc_alphabet[$digit][2], 1),
925 array(0, $this->upc_alphabet[$digit][3], 1),
926 ),
927 'l' => array($digit, 0.5, (8 - $i) / 5)
928 );
929 }
930 /* End, quiet zone. */
931 $blocks[] = array(
932 'm' => array(
933 array(1, 1, 1),
934 array(0, 1, 1),
935 array(1, 1, 1),
936 )
937 );
938 $blocks[] = array(
939 'm' => array(array(0, 9, 0)),
940 'l' => array('>', 0.5, 2 / 3)
941 );
942 /* Return code. */
943 return array('g' => 'l', 'b' => $blocks);
944 }
945
946 private function upc_a_normalize($data) {
947 $data = preg_replace('/[^0-9*]/', '', $data);
948 /* Set length to 12 digits. */
949 if (strlen($data) < 5) {
950 $data = str_repeat('0', 12);
951 } else if (strlen($data) < 12) {
952 $system = substr($data, 0, 1);
953 $edata = substr($data, 1, -2);
954 $epattern = (int) substr($data, -2, 1);
955 $check = substr($data, -1);
956 if ($epattern < 3) {
957 $left = $system . substr($edata, 0, 2) . $epattern;
958 $right = substr($edata, 2) . $check;
959 } else if ($epattern < strlen($edata)) {
960 $left = $system . substr($edata, 0, $epattern);
961 $right = substr($edata, $epattern) . $check;
962 } else {
963 $left = $system . $edata;
964 $right = $epattern . $check;
965 }
966 $center = str_repeat('0', 12 - strlen($left . $right));
967 $data = $left . $center . $right;
968 } else if (strlen($data) > 12) {
969 $left = substr($data, 0, 6);
970 $right = substr($data, -6);
971 $data = $left . $right;
972 }
973 /* Replace * with missing or check digit. */
974 while (($o = strrpos($data, '*')) !== false) {
975 $checksum = 0;
976 for ($i = 0; $i < 12; $i++) {
977 $digit = substr($data, $i, 1);
978 $checksum += (($i % 2) ? 1 : 3) * $digit;
979 }
980 $checksum *= (($o % 2) ? 9 : 3);
981 $left = substr($data, 0, $o);
982 $center = substr($checksum, -1);
983 $right = substr($data, $o + 1);
984 $data = $left . $center . $right;
985 }
986 return $data;
987 }
988
989 private function upc_e_normalize($data) {
990 $data = preg_replace('/[^0-9*]/', '', $data);
991 /* If exactly 8 digits, use verbatim even if check digit is wrong. */
992 if (preg_match(
993 '/^([01])([0-9][0-9][0-9][0-9][0-9][0-9])([0-9])$/',
994 $data, $m
995 )) {
996 return $data;
997 }
998 /* If unknown check digit, use verbatim but calculate check digit. */
999 if (preg_match(
1000 '/^([01])([0-9][0-9][0-9][0-9][0-9][0-9])([*])$/',
1001 $data, $m
1002 )) {
1003 $data = $this->upc_a_normalize($data);
1004 return $m[1] . $m[2] . substr($data, -1);
1005 }
1006 /* Otherwise normalize to UPC-A and convert back. */
1007 $data = $this->upc_a_normalize($data);
1008 if (preg_match(
1009 '/^([01])([0-9][0-9])([0-2])0000([0-9][0-9][0-9])([0-9])$/',
1010 $data, $m
1011 )) {
1012 return $m[1] . $m[2] . $m[4] . $m[3] . $m[5];
1013 }
1014 if (preg_match(
1015 '/^([01])([0-9][0-9][0-9])00000([0-9][0-9])([0-9])$/',
1016 $data, $m
1017 )) {
1018 return $m[1] . $m[2] . $m[3] . '3' . $m[4];
1019 }
1020 if (preg_match(
1021 '/^([01])([0-9][0-9][0-9][0-9])00000([0-9])([0-9])$/',
1022 $data, $m
1023 )) {
1024 return $m[1] . $m[2] . $m[3] . '4' . $m[4];
1025 }
1026 if (preg_match(
1027 '/^([01])([0-9][0-9][0-9][0-9][0-9])0000([5-9])([0-9])$/',
1028 $data, $m
1029 )) {
1030 return $m[1] . $m[2] . $m[3] . $m[4];
1031 }
1032 return str_repeat('0', 8);
1033 }
1034
1035 private function ean_13_normalize($data) {
1036 $data = preg_replace('/[^0-9*]/', '', $data);
1037 /* Set length to 13 digits. */
1038 if (strlen($data) < 13) {
1039 return '0' . $this->upc_a_normalize($data);
1040 } else if (strlen($data) > 13) {
1041 $left = substr($data, 0, 7);
1042 $right = substr($data, -6);
1043 $data = $left . $right;
1044 }
1045 /* Replace * with missing or check digit. */
1046 while (($o = strrpos($data, '*')) !== false) {
1047 $checksum = 0;
1048 for ($i = 0; $i < 13; $i++) {
1049 $digit = substr($data, $i, 1);
1050 $checksum += (($i % 2) ? 3 : 1) * $digit;
1051 }
1052 $checksum *= (($o % 2) ? 3 : 9);
1053 $left = substr($data, 0, $o);
1054 $center = substr($checksum, -1);
1055 $right = substr($data, $o + 1);
1056 $data = $left . $center . $right;
1057 }
1058 return $data;
1059 }
1060
1061 private function ean_8_normalize($data) {
1062 $data = preg_replace('/[^0-9*]/', '', $data);
1063 /* Set length to 8 digits. */
1064 if (strlen($data) < 8) {
1065 $midpoint = floor(strlen($data) / 2);
1066 $left = substr($data, 0, $midpoint);
1067 $center = str_repeat('0', 8 - strlen($data));
1068 $right = substr($data, $midpoint);
1069 $data = $left . $center . $right;
1070 } else if (strlen($data) > 8) {
1071 $left = substr($data, 0, 4);
1072 $right = substr($data, -4);
1073 $data = $left . $right;
1074 }
1075 /* Replace * with missing or check digit. */
1076 while (($o = strrpos($data, '*')) !== false) {
1077 $checksum = 0;
1078 for ($i = 0; $i < 8; $i++) {
1079 $digit = substr($data, $i, 1);
1080 $checksum += (($i % 2) ? 1 : 3) * $digit;
1081 }
1082 $checksum *= (($o % 2) ? 9 : 3);
1083 $left = substr($data, 0, $o);
1084 $center = substr($checksum, -1);
1085 $right = substr($data, $o + 1);
1086 $data = $left . $center . $right;
1087 }
1088 return $data;
1089 }
1090
1091 private $upc_alphabet = array(
1092 '0' => array(3, 2, 1, 1),
1093 '1' => array(2, 2, 2, 1),
1094 '2' => array(2, 1, 2, 2),
1095 '3' => array(1, 4, 1, 1),
1096 '4' => array(1, 1, 3, 2),
1097 '5' => array(1, 2, 3, 1),
1098 '6' => array(1, 1, 1, 4),
1099 '7' => array(1, 3, 1, 2),
1100 '8' => array(1, 2, 1, 3),
1101 '9' => array(3, 1, 1, 2),
1102 );
1103 private $upc_parity = array(
1104 '0' => array(1, 1, 1, 0, 0, 0),
1105 '1' => array(1, 1, 0, 1, 0, 0),
1106 '2' => array(1, 1, 0, 0, 1, 0),
1107 '3' => array(1, 1, 0, 0, 0, 1),
1108 '4' => array(1, 0, 1, 1, 0, 0),
1109 '5' => array(1, 0, 0, 1, 1, 0),
1110 '6' => array(1, 0, 0, 0, 1, 1),
1111 '7' => array(1, 0, 1, 0, 1, 0),
1112 '8' => array(1, 0, 1, 0, 0, 1),
1113 '9' => array(1, 0, 0, 1, 0, 1),
1114 );
1115
1116 /* - - - - CODE 39 FAMILY ENCODER - - - - */
1117
1118 private function code_39_encode($data) {
1119 $data = strtoupper(preg_replace('/[^0-9A-Za-z%$\/+ .-]/', '', $data));
1120 $blocks = array();
1121 /* Start */
1122 $blocks[] = array(
1123 'm' => array(
1124 array(1, 1, 1), array(0, 1, 2), array(1, 1, 1),
1125 array(0, 1, 1), array(1, 1, 2), array(0, 1, 1),
1126 array(1, 1, 2), array(0, 1, 1), array(1, 1, 1),
1127 ),
1128 'l' => array('*')
1129 );
1130 /* Data */
1131 for ($i = 0, $n = strlen($data); $i < $n; $i++) {
1132 $blocks[] = array(
1133 'm' => array(array(0, 1, 3))
1134 );
1135 $char = substr($data, $i, 1);
1136 $block = $this->code_39_alphabet[$char];
1137 $blocks[] = array(
1138 'm' => array(
1139 array(1, 1, $block[0]),
1140 array(0, 1, $block[1]),
1141 array(1, 1, $block[2]),
1142 array(0, 1, $block[3]),
1143 array(1, 1, $block[4]),
1144 array(0, 1, $block[5]),
1145 array(1, 1, $block[6]),
1146 array(0, 1, $block[7]),
1147 array(1, 1, $block[8]),
1148 ),
1149 'l' => array($char)
1150 );
1151 }
1152 $blocks[] = array(
1153 'm' => array(array(0, 1, 3))
1154 );
1155 /* End */
1156 $blocks[] = array(
1157 'm' => array(
1158 array(1, 1, 1), array(0, 1, 2), array(1, 1, 1),
1159 array(0, 1, 1), array(1, 1, 2), array(0, 1, 1),
1160 array(1, 1, 2), array(0, 1, 1), array(1, 1, 1),
1161 ),
1162 'l' => array('*')
1163 );
1164 /* Return */
1165 return array('g' => 'l', 'b' => $blocks);
1166 }
1167
1168 private function code_39_ascii_encode($data) {
1169 $modules = array();
1170 /* Start */
1171 $modules[] = array(1, 1, 1);
1172 $modules[] = array(0, 1, 2);
1173 $modules[] = array(1, 1, 1);
1174 $modules[] = array(0, 1, 1);
1175 $modules[] = array(1, 1, 2);
1176 $modules[] = array(0, 1, 1);
1177 $modules[] = array(1, 1, 2);
1178 $modules[] = array(0, 1, 1);
1179 $modules[] = array(1, 1, 1);
1180 /* Data */
1181 $label = '';
1182 for ($i = 0, $n = strlen($data); $i < $n; $i++) {
1183 $char = substr($data, $i, 1);
1184 $ch = ord($char);
1185 if ($ch < 128) {
1186 if ($ch < 32 || $ch >= 127) {
1187 $label .= ' ';
1188 } else {
1189 $label .= $char;
1190 }
1191 $ch = $this->code_39_asciibet[$ch];
1192 for ($j = 0, $m = strlen($ch); $j < $m; $j++) {
1193 $c = substr($ch, $j, 1);
1194 $b = $this->code_39_alphabet[$c];
1195 $modules[] = array(0, 1, 3);
1196 $modules[] = array(1, 1, $b[0]);
1197 $modules[] = array(0, 1, $b[1]);
1198 $modules[] = array(1, 1, $b[2]);
1199 $modules[] = array(0, 1, $b[3]);
1200 $modules[] = array(1, 1, $b[4]);
1201 $modules[] = array(0, 1, $b[5]);
1202 $modules[] = array(1, 1, $b[6]);
1203 $modules[] = array(0, 1, $b[7]);
1204 $modules[] = array(1, 1, $b[8]);
1205 }
1206 }
1207 }
1208 $modules[] = array(0, 1, 3);
1209 /* End */
1210 $modules[] = array(1, 1, 1);
1211 $modules[] = array(0, 1, 2);
1212 $modules[] = array(1, 1, 1);
1213 $modules[] = array(0, 1, 1);
1214 $modules[] = array(1, 1, 2);
1215 $modules[] = array(0, 1, 1);
1216 $modules[] = array(1, 1, 2);
1217 $modules[] = array(0, 1, 1);
1218 $modules[] = array(1, 1, 1);
1219 /* Return */
1220 $blocks = array(array('m' => $modules, 'l' => array($label)));
1221 return array('g' => 'l', 'b' => $blocks);
1222 }
1223
1224 private function code_93_encode($data) {
1225 $data = strtoupper(preg_replace('/[^0-9A-Za-z%+\/$ .-]/', '', $data));
1226 $modules = array();
1227 /* Start */
1228 $modules[] = array(1, 1, 1);
1229 $modules[] = array(0, 1, 1);
1230 $modules[] = array(1, 1, 1);
1231 $modules[] = array(0, 1, 1);
1232 $modules[] = array(1, 4, 1);
1233 $modules[] = array(0, 1, 1);
1234 /* Data */
1235 $values = array();
1236 for ($i = 0, $n = strlen($data); $i < $n; $i++) {
1237 $char = substr($data, $i, 1);
1238 $block = $this->code_93_alphabet[$char];
1239 $modules[] = array(1, $block[0], 1);
1240 $modules[] = array(0, $block[1], 1);
1241 $modules[] = array(1, $block[2], 1);
1242 $modules[] = array(0, $block[3], 1);
1243 $modules[] = array(1, $block[4], 1);
1244 $modules[] = array(0, $block[5], 1);
1245 $values[] = $block[6];
1246 }
1247 /* Check Digits */
1248 for ($i = 0; $i < 2; $i++) {
1249 $index = count($values);
1250 $weight = 0;
1251 $checksum = 0;
1252 while ($index) {
1253 $index--;
1254 $weight++;
1255 $checksum += $weight * $values[$index];
1256 $checksum %= 47;
1257 $weight %= ($i ? 15 : 20);
1258 }
1259 $values[] = $checksum;
1260 }
1261 $alphabet = array_values($this->code_93_alphabet);
1262 for ($i = count($values) - 2, $n = count($values); $i < $n; $i++) {
1263 $block = $alphabet[$values[$i]];
1264 $modules[] = array(1, $block[0], 1);
1265 $modules[] = array(0, $block[1], 1);
1266 $modules[] = array(1, $block[2], 1);
1267 $modules[] = array(0, $block[3], 1);
1268 $modules[] = array(1, $block[4], 1);
1269 $modules[] = array(0, $block[5], 1);
1270 }
1271 /* End */
1272 $modules[] = array(1, 1, 1);
1273 $modules[] = array(0, 1, 1);
1274 $modules[] = array(1, 1, 1);
1275 $modules[] = array(0, 1, 1);
1276 $modules[] = array(1, 4, 1);
1277 $modules[] = array(0, 1, 1);
1278 $modules[] = array(1, 1, 1);
1279 /* Return */
1280 $blocks = array(array('m' => $modules, 'l' => array($data)));
1281 return array('g' => 'l', 'b' => $blocks);
1282 }
1283
1284 private function code_93_ascii_encode($data) {
1285 $modules = array();
1286 /* Start */
1287 $modules[] = array(1, 1, 1);
1288 $modules[] = array(0, 1, 1);
1289 $modules[] = array(1, 1, 1);
1290 $modules[] = array(0, 1, 1);
1291 $modules[] = array(1, 4, 1);
1292 $modules[] = array(0, 1, 1);
1293 /* Data */
1294 $label = '';
1295 $values = array();
1296 for ($i = 0, $n = strlen($data); $i < $n; $i++) {
1297 $char = substr($data, $i, 1);
1298 $ch = ord($char);
1299 if ($ch < 128) {
1300 if ($ch < 32 || $ch >= 127) {
1301 $label .= ' ';
1302 } else {
1303 $label .= $char;
1304 }
1305 $ch = $this->code_93_asciibet[$ch];
1306 for ($j = 0, $m = strlen($ch); $j < $m; $j++) {
1307 $c = substr($ch, $j, 1);
1308 $b = $this->code_93_alphabet[$c];
1309 $modules[] = array(1, $b[0], 1);
1310 $modules[] = array(0, $b[1], 1);
1311 $modules[] = array(1, $b[2], 1);
1312 $modules[] = array(0, $b[3], 1);
1313 $modules[] = array(1, $b[4], 1);
1314 $modules[] = array(0, $b[5], 1);
1315 $values[] = $b[6];
1316 }
1317 }
1318 }
1319 /* Check Digits */
1320 for ($i = 0; $i < 2; $i++) {
1321 $index = count($values);
1322 $weight = 0;
1323 $checksum = 0;
1324 while ($index) {
1325 $index--;
1326 $weight++;
1327 $checksum += $weight * $values[$index];
1328 $checksum %= 47;
1329 $weight %= ($i ? 15 : 20);
1330 }
1331 $values[] = $checksum;
1332 }
1333 $alphabet = array_values($this->code_93_alphabet);
1334 for ($i = count($values) - 2, $n = count($values); $i < $n; $i++) {
1335 $block = $alphabet[$values[$i]];
1336 $modules[] = array(1, $block[0], 1);
1337 $modules[] = array(0, $block[1], 1);
1338 $modules[] = array(1, $block[2], 1);
1339 $modules[] = array(0, $block[3], 1);
1340 $modules[] = array(1, $block[4], 1);
1341 $modules[] = array(0, $block[5], 1);
1342 }
1343 /* End */
1344 $modules[] = array(1, 1, 1);
1345 $modules[] = array(0, 1, 1);
1346 $modules[] = array(1, 1, 1);
1347 $modules[] = array(0, 1, 1);
1348 $modules[] = array(1, 4, 1);
1349 $modules[] = array(0, 1, 1);
1350 $modules[] = array(1, 1, 1);
1351 /* Return */
1352 $blocks = array(array('m' => $modules, 'l' => array($label)));
1353 return array('g' => 'l', 'b' => $blocks);
1354 }
1355
1356 private $code_39_alphabet = array(
1357 '1' => array(2, 1, 1, 2, 1, 1, 1, 1, 2),
1358 '2' => array(1, 1, 2, 2, 1, 1, 1, 1, 2),
1359 '3' => array(2, 1, 2, 2, 1, 1, 1, 1, 1),
1360 '4' => array(1, 1, 1, 2, 2, 1, 1, 1, 2),
1361 '5' => array(2, 1, 1, 2, 2, 1, 1, 1, 1),
1362 '6' => array(1, 1, 2, 2, 2, 1, 1, 1, 1),
1363 '7' => array(1, 1, 1, 2, 1, 1, 2, 1, 2),
1364 '8' => array(2, 1, 1, 2, 1, 1, 2, 1, 1),
1365 '9' => array(1, 1, 2, 2, 1, 1, 2, 1, 1),
1366 '0' => array(1, 1, 1, 2, 2, 1, 2, 1, 1),
1367 'A' => array(2, 1, 1, 1, 1, 2, 1, 1, 2),
1368 'B' => array(1, 1, 2, 1, 1, 2, 1, 1, 2),
1369 'C' => array(2, 1, 2, 1, 1, 2, 1, 1, 1),
1370 'D' => array(1, 1, 1, 1, 2, 2, 1, 1, 2),
1371 'E' => array(2, 1, 1, 1, 2, 2, 1, 1, 1),
1372 'F' => array(1, 1, 2, 1, 2, 2, 1, 1, 1),
1373 'G' => array(1, 1, 1, 1, 1, 2, 2, 1, 2),
1374 'H' => array(2, 1, 1, 1, 1, 2, 2, 1, 1),
1375 'I' => array(1, 1, 2, 1, 1, 2, 2, 1, 1),
1376 'J' => array(1, 1, 1, 1, 2, 2, 2, 1, 1),
1377 'K' => array(2, 1, 1, 1, 1, 1, 1, 2, 2),
1378 'L' => array(1, 1, 2, 1, 1, 1, 1, 2, 2),
1379 'M' => array(2, 1, 2, 1, 1, 1, 1, 2, 1),
1380 'N' => array(1, 1, 1, 1, 2, 1, 1, 2, 2),
1381 'O' => array(2, 1, 1, 1, 2, 1, 1, 2, 1),
1382 'P' => array(1, 1, 2, 1, 2, 1, 1, 2, 1),
1383 'Q' => array(1, 1, 1, 1, 1, 1, 2, 2, 2),
1384 'R' => array(2, 1, 1, 1, 1, 1, 2, 2, 1),
1385 'S' => array(1, 1, 2, 1, 1, 1, 2, 2, 1),
1386 'T' => array(1, 1, 1, 1, 2, 1, 2, 2, 1),
1387 'U' => array(2, 2, 1, 1, 1, 1, 1, 1, 2),
1388 'V' => array(1, 2, 2, 1, 1, 1, 1, 1, 2),
1389 'W' => array(2, 2, 2, 1, 1, 1, 1, 1, 1),
1390 'X' => array(1, 2, 1, 1, 2, 1, 1, 1, 2),
1391 'Y' => array(2, 2, 1, 1, 2, 1, 1, 1, 1),
1392 'Z' => array(1, 2, 2, 1, 2, 1, 1, 1, 1),
1393 '-' => array(1, 2, 1, 1, 1, 1, 2, 1, 2),
1394 '.' => array(2, 2, 1, 1, 1, 1, 2, 1, 1),
1395 ' ' => array(1, 2, 2, 1, 1, 1, 2, 1, 1),
1396 '*' => array(1, 2, 1, 1, 2, 1, 2, 1, 1),
1397 '+' => array(1, 2, 1, 1, 1, 2, 1, 2, 1),
1398 '/' => array(1, 2, 1, 2, 1, 1, 1, 2, 1),
1399 '$' => array(1, 2, 1, 2, 1, 2, 1, 1, 1),
1400 '%' => array(1, 1, 1, 2, 1, 2, 1, 2, 1),
1401 );
1402 private $code_39_asciibet = array(
1403 '%U', '$A', '$B', '$C', '$D', '$E', '$F', '$G',
1404 '$H', '$I', '$J', '$K', '$L', '$M', '$N', '$O',
1405 '$P', '$Q', '$R', '$S', '$T', '$U', '$V', '$W',
1406 '$X', '$Y', '$Z', '%A', '%B', '%C', '%D', '%E',
1407 ' ', '/A', '/B', '/C', '/D', '/E', '/F', '/G',
1408 '/H', '/I', '/J', '/K', '/L', '-', '.', '/O',
1409 '0', '1', '2', '3', '4', '5', '6', '7',
1410 '8', '9', '/Z', '%F', '%G', '%H', '%I', '%J',
1411 '%V', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
1412 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1413 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
1414 'X', 'Y', 'Z', '%K', '%L', '%M', '%N', '%O',
1415 '%W', '+A', '+B', '+C', '+D', '+E', '+F', '+G',
1416 '+H', '+I', '+J', '+K', '+L', '+M', '+N', '+O',
1417 '+P', '+Q', '+R', '+S', '+T', '+U', '+V', '+W',
1418 '+X', '+Y', '+Z', '%P', '%Q', '%R', '%S', '%T',
1419 );
1420 private $code_93_alphabet = array(
1421 '0' => array(1, 3, 1, 1, 1, 2, 0),
1422 '1' => array(1, 1, 1, 2, 1, 3, 1),
1423 '2' => array(1, 1, 1, 3, 1, 2, 2),
1424 '3' => array(1, 1, 1, 4, 1, 1, 3),
1425 '4' => array(1, 2, 1, 1, 1, 3, 4),
1426 '5' => array(1, 2, 1, 2, 1, 2, 5),
1427 '6' => array(1, 2, 1, 3, 1, 1, 6),
1428 '7' => array(1, 1, 1, 1, 1, 4, 7),
1429 '8' => array(1, 3, 1, 2, 1, 1, 8),
1430 '9' => array(1, 4, 1, 1, 1, 1, 9),
1431 'A' => array(2, 1, 1, 1, 1, 3, 10),
1432 'B' => array(2, 1, 1, 2, 1, 2, 11),
1433 'C' => array(2, 1, 1, 3, 1, 1, 12),
1434 'D' => array(2, 2, 1, 1, 1, 2, 13),
1435 'E' => array(2, 2, 1, 2, 1, 1, 14),
1436 'F' => array(2, 3, 1, 1, 1, 1, 15),
1437 'G' => array(1, 1, 2, 1, 1, 3, 16),
1438 'H' => array(1, 1, 2, 2, 1, 2, 17),
1439 'I' => array(1, 1, 2, 3, 1, 1, 18),
1440 'J' => array(1, 2, 2, 1, 1, 2, 19),
1441 'K' => array(1, 3, 2, 1, 1, 1, 20),
1442 'L' => array(1, 1, 1, 1, 2, 3, 21),
1443 'M' => array(1, 1, 1, 2, 2, 2, 22),
1444 'N' => array(1, 1, 1, 3, 2, 1, 23),
1445 'O' => array(1, 2, 1, 1, 2, 2, 24),
1446 'P' => array(1, 3, 1, 1, 2, 1, 25),
1447 'Q' => array(2, 1, 2, 1, 1, 2, 26),
1448 'R' => array(2, 1, 2, 2, 1, 1, 27),
1449 'S' => array(2, 1, 1, 1, 2, 2, 28),
1450 'T' => array(2, 1, 1, 2, 2, 1, 29),
1451 'U' => array(2, 2, 1, 1, 2, 1, 30),
1452 'V' => array(2, 2, 2, 1, 1, 1, 31),
1453 'W' => array(1, 1, 2, 1, 2, 2, 32),
1454 'X' => array(1, 1, 2, 2, 2, 1, 33),
1455 'Y' => array(1, 2, 2, 1, 2, 1, 34),
1456 'Z' => array(1, 2, 3, 1, 1, 1, 35),
1457 '-' => array(1, 2, 1, 1, 3, 1, 36),
1458 '.' => array(3, 1, 1, 1, 1, 2, 37),
1459 ' ' => array(3, 1, 1, 2, 1, 1, 38),
1460 '$' => array(3, 2, 1, 1, 1, 1, 39),
1461 '/' => array(1, 1, 2, 1, 3, 1, 40),
1462 '+' => array(1, 1, 3, 1, 2, 1, 41),
1463 '%' => array(2, 1, 1, 1, 3, 1, 42),
1464 '#' => array(1, 2, 1, 2, 2, 1, 43), /* ($) */
1465 '&' => array(3, 1, 2, 1, 1, 1, 44), /* (%) */
1466 '|' => array(3, 1, 1, 1, 2, 1, 45), /* (/) */
1467 '=' => array(1, 2, 2, 2, 1, 1, 46), /* (+) */
1468 '*' => array(1, 1, 1, 1, 4, 1, 0),
1469 );
1470 private $code_93_asciibet = array(
1471 '&U', '#A', '#B', '#C', '#D', '#E', '#F', '#G',
1472 '#H', '#I', '#J', '#K', '#L', '#M', '#N', '#O',
1473 '#P', '#Q', '#R', '#S', '#T', '#U', '#V', '#W',
1474 '#X', '#Y', '#Z', '&A', '&B', '&C', '&D', '&E',
1475 ' ', '|A', '|B', '|C', '$', '%', '|F', '|G',
1476 '|H', '|I', '|J', '+', '|L', '-', '.', '/',
1477 '0', '1', '2', '3', '4', '5', '6', '7',
1478 '8', '9', '|Z', '&F', '&G', '&H', '&I', '&J',
1479 '&V', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
1480 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1481 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
1482 'X', 'Y', 'Z', '&K', '&L', '&M', '&N', '&O',
1483 '&W', '=A', '=B', '=C', '=D', '=E', '=F', '=G',
1484 '=H', '=I', '=J', '=K', '=L', '=M', '=N', '=O',
1485 '=P', '=Q', '=R', '=S', '=T', '=U', '=V', '=W',
1486 '=X', '=Y', '=Z', '&P', '&Q', '&R', '&S', '&T',
1487 );
1488
1489 /* - - - - CODE 128 ENCODER - - - - */
1490
1491 private function code_128_encode($data, $dstate, $fnc1) {
1492 $data = preg_replace('/[\x80-\xFF]/', '', $data);
1493 $label = preg_replace('/[\x00-\x1F\x7F]/', ' ', $data);
1494 $chars = $this->code_128_normalize($data, $dstate, $fnc1);
1495 $checksum = $chars[0] % 103;
1496 for ($i = 1, $n = count($chars); $i < $n; $i++) {
1497 $checksum += $i * $chars[$i];
1498 $checksum %= 103;
1499 }
1500 $chars[] = $checksum;
1501 $chars[] = 106;
1502 $modules = array();
1503 $modules[] = array(0, 10, 0);
1504 foreach ($chars as $char) {
1505 $block = $this->code_128_alphabet[$char];
1506 foreach ($block as $i => $module) {
1507 $modules[] = array(($i & 1) ^ 1, $module, 1);
1508 }
1509 }
1510 $modules[] = array(0, 10, 0);
1511 $blocks = array(array('m' => $modules, 'l' => array($label)));
1512 return array('g' => 'l', 'b' => $blocks);
1513 }
1514
1515 private function code_128_normalize($data, $dstate, $fnc1) {
1516 $detectcba = '/(^[0-9]{4,}|^[0-9]{2}$)|([\x60-\x7F])|([\x00-\x1F])/';
1517 $detectc = '/(^[0-9]{6,}|^[0-9]{4,}$)/';
1518 $detectba = '/([\x60-\x7F])|([\x00-\x1F])/';
1519 $consumec = '/(^[0-9]{2})/';
1520 $state = (($dstate > 0 && $dstate < 4) ? $dstate : 0);
1521 $abstate = ((abs($dstate) == 2) ? 2 : 1);
1522 $chars = array(102 + ($state ? $state : $abstate));
1523 if ($fnc1)
1524 $chars[] = 102;
1525 while (strlen($data)) {
1526 switch ($state) {
1527 case 0:
1528 if (preg_match($detectcba, $data, $m)) {
1529 if ($m[1]) {
1530 $state = 3;
1531 } else if ($m[2]) {
1532 $state = 2;
1533 } else {
1534 $state = 1;
1535 }
1536 } else {
1537 $state = $abstate;
1538 }
1539 $chars = array(102 + $state);
1540 if ($fnc1)
1541 $chars[] = 102;
1542 break;
1543 case 1:
1544 if ($dstate <= 0 && preg_match($detectc, $data, $m)) {
1545 if (strlen($m[0]) % 2) {
1546 $data = substr($data, 1);
1547 $chars[] = 16 + substr($m[0], 0, 1);
1548 }
1549 $state = 3;
1550 $chars[] = 99;
1551 } else {
1552 $ch = ord(substr($data, 0, 1));
1553 $data = substr($data, 1);
1554 if ($ch < 32) {
1555 $chars[] = $ch + 64;
1556 } else if ($ch < 96) {
1557 $chars[] = $ch - 32;
1558 } else {
1559 if (preg_match($detectba, $data, $m)) {
1560 if ($m[1]) {
1561 $state = 2;
1562 $chars[] = 100;
1563 } else {
1564 $chars[] = 98;
1565 }
1566 } else {
1567 $chars[] = 98;
1568 }
1569 $chars[] = $ch - 32;
1570 }
1571 }
1572 break;
1573 case 2:
1574 if ($dstate <= 0 && preg_match($detectc, $data, $m)) {
1575 if (strlen($m[0]) % 2) {
1576 $data = substr($data, 1);
1577 $chars[] = 16 + substr($m[0], 0, 1);
1578 }
1579 $state = 3;
1580 $chars[] = 99;
1581 } else {
1582 $ch = ord(substr($data, 0, 1));
1583 $data = substr($data, 1);
1584 if ($ch >= 32) {
1585 $chars[] = $ch - 32;
1586 } else {
1587 if (preg_match($detectba, $data, $m)) {
1588 if ($m[2]) {
1589 $state = 1;
1590 $chars[] = 101;
1591 } else {
1592 $chars[] = 98;
1593 }
1594 } else {
1595 $chars[] = 98;
1596 }
1597 $chars[] = $ch + 64;
1598 }
1599 }
1600 break;
1601 case 3:
1602 if (preg_match($consumec, $data, $m)) {
1603 $data = substr($data, 2);
1604 $chars[] = (int) $m[0];
1605 } else {
1606 if (preg_match($detectba, $data, $m)) {
1607 if ($m[1]) {
1608 $state = 2;
1609 } else {
1610 $state = 1;
1611 }
1612 } else {
1613 $state = $abstate;
1614 }
1615 $chars[] = 102 - $state;
1616 }
1617 break;
1618 }
1619 }
1620 return $chars;
1621 }
1622
1623 private $code_128_alphabet = array(
1624 array(2, 1, 2, 2, 2, 2), array(2, 2, 2, 1, 2, 2),
1625 array(2, 2, 2, 2, 2, 1), array(1, 2, 1, 2, 2, 3),
1626 array(1, 2, 1, 3, 2, 2), array(1, 3, 1, 2, 2, 2),
1627 array(1, 2, 2, 2, 1, 3), array(1, 2, 2, 3, 1, 2),
1628 array(1, 3, 2, 2, 1, 2), array(2, 2, 1, 2, 1, 3),
1629 array(2, 2, 1, 3, 1, 2), array(2, 3, 1, 2, 1, 2),
1630 array(1, 1, 2, 2, 3, 2), array(1, 2, 2, 1, 3, 2),
1631 array(1, 2, 2, 2, 3, 1), array(1, 1, 3, 2, 2, 2),
1632 array(1, 2, 3, 1, 2, 2), array(1, 2, 3, 2, 2, 1),
1633 array(2, 2, 3, 2, 1, 1), array(2, 2, 1, 1, 3, 2),
1634 array(2, 2, 1, 2, 3, 1), array(2, 1, 3, 2, 1, 2),
1635 array(2, 2, 3, 1, 1, 2), array(3, 1, 2, 1, 3, 1),
1636 array(3, 1, 1, 2, 2, 2), array(3, 2, 1, 1, 2, 2),
1637 array(3, 2, 1, 2, 2, 1), array(3, 1, 2, 2, 1, 2),
1638 array(3, 2, 2, 1, 1, 2), array(3, 2, 2, 2, 1, 1),
1639 array(2, 1, 2, 1, 2, 3), array(2, 1, 2, 3, 2, 1),
1640 array(2, 3, 2, 1, 2, 1), array(1, 1, 1, 3, 2, 3),
1641 array(1, 3, 1, 1, 2, 3), array(1, 3, 1, 3, 2, 1),
1642 array(1, 1, 2, 3, 1, 3), array(1, 3, 2, 1, 1, 3),
1643 array(1, 3, 2, 3, 1, 1), array(2, 1, 1, 3, 1, 3),
1644 array(2, 3, 1, 1, 1, 3), array(2, 3, 1, 3, 1, 1),
1645 array(1, 1, 2, 1, 3, 3), array(1, 1, 2, 3, 3, 1),
1646 array(1, 3, 2, 1, 3, 1), array(1, 1, 3, 1, 2, 3),
1647 array(1, 1, 3, 3, 2, 1), array(1, 3, 3, 1, 2, 1),
1648 array(3, 1, 3, 1, 2, 1), array(2, 1, 1, 3, 3, 1),
1649 array(2, 3, 1, 1, 3, 1), array(2, 1, 3, 1, 1, 3),
1650 array(2, 1, 3, 3, 1, 1), array(2, 1, 3, 1, 3, 1),
1651 array(3, 1, 1, 1, 2, 3), array(3, 1, 1, 3, 2, 1),
1652 array(3, 3, 1, 1, 2, 1), array(3, 1, 2, 1, 1, 3),
1653 array(3, 1, 2, 3, 1, 1), array(3, 3, 2, 1, 1, 1),
1654 array(3, 1, 4, 1, 1, 1), array(2, 2, 1, 4, 1, 1),
1655 array(4, 3, 1, 1, 1, 1), array(1, 1, 1, 2, 2, 4),
1656 array(1, 1, 1, 4, 2, 2), array(1, 2, 1, 1, 2, 4),
1657 array(1, 2, 1, 4, 2, 1), array(1, 4, 1, 1, 2, 2),
1658 array(1, 4, 1, 2, 2, 1), array(1, 1, 2, 2, 1, 4),
1659 array(1, 1, 2, 4, 1, 2), array(1, 2, 2, 1, 1, 4),
1660 array(1, 2, 2, 4, 1, 1), array(1, 4, 2, 1, 1, 2),
1661 array(1, 4, 2, 2, 1, 1), array(2, 4, 1, 2, 1, 1),
1662 array(2, 2, 1, 1, 1, 4), array(4, 1, 3, 1, 1, 1),
1663 array(2, 4, 1, 1, 1, 2), array(1, 3, 4, 1, 1, 1),
1664 array(1, 1, 1, 2, 4, 2), array(1, 2, 1, 1, 4, 2),
1665 array(1, 2, 1, 2, 4, 1), array(1, 1, 4, 2, 1, 2),
1666 array(1, 2, 4, 1, 1, 2), array(1, 2, 4, 2, 1, 1),
1667 array(4, 1, 1, 2, 1, 2), array(4, 2, 1, 1, 1, 2),
1668 array(4, 2, 1, 2, 1, 1), array(2, 1, 2, 1, 4, 1),
1669 array(2, 1, 4, 1, 2, 1), array(4, 1, 2, 1, 2, 1),
1670 array(1, 1, 1, 1, 4, 3), array(1, 1, 1, 3, 4, 1),
1671 array(1, 3, 1, 1, 4, 1), array(1, 1, 4, 1, 1, 3),
1672 array(1, 1, 4, 3, 1, 1), array(4, 1, 1, 1, 1, 3),
1673 array(4, 1, 1, 3, 1, 1), array(1, 1, 3, 1, 4, 1),
1674 array(1, 1, 4, 1, 3, 1), array(3, 1, 1, 1, 4, 1),
1675 array(4, 1, 1, 1, 3, 1), array(2, 1, 1, 4, 1, 2),
1676 array(2, 1, 1, 2, 1, 4), array(2, 1, 1, 2, 3, 2),
1677 array(2, 3, 3, 1, 1, 1, 2)
1678 );
1679
1680 /* - - - - CODABAR ENCODER - - - - */
1681
1682 private function codabar_encode($data) {
1683 $data = strtoupper(preg_replace(
1684 '/[^0-9ABCDENTabcdent*.\/:+$-]/', '', $data
1685 ));
1686 $blocks = array();
1687 for ($i = 0, $n = strlen($data); $i < $n; $i++) {
1688 if ($blocks) {
1689 $blocks[] = array(
1690 'm' => array(array(0, 1, 3))
1691 );
1692 }
1693 $char = substr($data, $i, 1);
1694 $block = $this->codabar_alphabet[$char];
1695 $blocks[] = array(
1696 'm' => array(
1697 array(1, 1, $block[0]),
1698 array(0, 1, $block[1]),
1699 array(1, 1, $block[2]),
1700 array(0, 1, $block[3]),
1701 array(1, 1, $block[4]),
1702 array(0, 1, $block[5]),
1703 array(1, 1, $block[6]),
1704 ),
1705 'l' => array($char)
1706 );
1707 }
1708 return array('g' => 'l', 'b' => $blocks);
1709 }
1710
1711 private $codabar_alphabet = array(
1712 '0' => array(1, 1, 1, 1, 1, 2, 2),
1713 '1' => array(1, 1, 1, 1, 2, 2, 1),
1714 '4' => array(1, 1, 2, 1, 1, 2, 1),
1715 '5' => array(2, 1, 1, 1, 1, 2, 1),
1716 '2' => array(1, 1, 1, 2, 1, 1, 2),
1717 '-' => array(1, 1, 1, 2, 2, 1, 1),
1718 '$' => array(1, 1, 2, 2, 1, 1, 1),
1719 '9' => array(2, 1, 1, 2, 1, 1, 1),
1720 '6' => array(1, 2, 1, 1, 1, 1, 2),
1721 '7' => array(1, 2, 1, 1, 2, 1, 1),
1722 '8' => array(1, 2, 2, 1, 1, 1, 1),
1723 '3' => array(2, 2, 1, 1, 1, 1, 1),
1724 'C' => array(1, 1, 1, 2, 1, 2, 2),
1725 'D' => array(1, 1, 1, 2, 2, 2, 1),
1726 'A' => array(1, 1, 2, 2, 1, 2, 1),
1727 'B' => array(1, 2, 1, 2, 1, 1, 2),
1728 '*' => array(1, 1, 1, 2, 1, 2, 2),
1729 'E' => array(1, 1, 1, 2, 2, 2, 1),
1730 'T' => array(1, 1, 2, 2, 1, 2, 1),
1731 'N' => array(1, 2, 1, 2, 1, 1, 2),
1732 '.' => array(2, 1, 2, 1, 2, 1, 1),
1733 '/' => array(2, 1, 2, 1, 1, 1, 2),
1734 ':' => array(2, 1, 1, 1, 2, 1, 2),
1735 '+' => array(1, 1, 2, 1, 2, 1, 2),
1736 );
1737
1738 /* - - - - ITF ENCODER - - - - */
1739
1740 private function itf_encode($data) {
1741 $data = preg_replace('/[^0-9]/', '', $data);
1742 if (strlen($data) % 2)
1743 $data = '0' . $data;
1744 $blocks = array();
1745 /* Quiet zone, start. */
1746 $blocks[] = array(
1747 'm' => array(array(0, 10, 0))
1748 );
1749 $blocks[] = array(
1750 'm' => array(
1751 array(1, 1, 1),
1752 array(0, 1, 1),
1753 array(1, 1, 1),
1754 array(0, 1, 1),
1755 )
1756 );
1757 /* Data. */
1758 for ($i = 0, $n = strlen($data); $i < $n; $i += 2) {
1759 $c1 = substr($data, $i, 1);
1760 $c2 = substr($data, $i + 1, 1);
1761 $b1 = $this->itf_alphabet[$c1];
1762 $b2 = $this->itf_alphabet[$c2];
1763 $blocks[] = array(
1764 'm' => array(
1765 array(1, 1, $b1[0]),
1766 array(0, 1, $b2[0]),
1767 array(1, 1, $b1[1]),
1768 array(0, 1, $b2[1]),
1769 array(1, 1, $b1[2]),
1770 array(0, 1, $b2[2]),
1771 array(1, 1, $b1[3]),
1772 array(0, 1, $b2[3]),
1773 array(1, 1, $b1[4]),
1774 array(0, 1, $b2[4]),
1775 ),
1776 'l' => array($c1 . $c2)
1777 );
1778 }
1779 /* End, quiet zone. */
1780 $blocks[] = array(
1781 'm' => array(
1782 array(1, 1, 2),
1783 array(0, 1, 1),
1784 array(1, 1, 1),
1785 )
1786 );
1787 $blocks[] = array(
1788 'm' => array(array(0, 10, 0))
1789 );
1790 /* Return code. */
1791 return array('g' => 'l', 'b' => $blocks);
1792 }
1793
1794 private $itf_alphabet = array(
1795 '0' => array(1, 1, 2, 2, 1),
1796 '1' => array(2, 1, 1, 1, 2),
1797 '2' => array(1, 2, 1, 1, 2),
1798 '3' => array(2, 2, 1, 1, 1),
1799 '4' => array(1, 1, 2, 1, 2),
1800 '5' => array(2, 1, 2, 1, 1),
1801 '6' => array(1, 2, 2, 1, 1),
1802 '7' => array(1, 1, 1, 2, 2),
1803 '8' => array(2, 1, 1, 2, 1),
1804 '9' => array(1, 2, 1, 2, 1),
1805 );
1806
1807 /* - - - - QR ENCODER - - - - */
1808
1809 private function qr_encode($data, $ecl) {
1810 list($mode, $vers, $ec, $data) = $this->qr_encode_data($data, $ecl);
1811 $data = $this->qr_encode_ec($data, $ec, $vers);
1812 list($size, $mtx) = $this->qr_create_matrix($vers, $data);
1813 list($mask, $mtx) = $this->qr_apply_best_mask($mtx, $size);
1814 $mtx = $this->qr_finalize_matrix($mtx, $size, $ecl, $mask, $vers);
1815 return array(
1816 'g' => 'm',
1817 'q' => array(4, 4, 4, 4),
1818 's' => array($size, $size),
1819 'b' => $mtx
1820 );
1821 }
1822
1823 private function qr_encode_data($data, $ecl) {
1824 $mode = $this->qr_detect_mode($data);
1825 $version = $this->qr_detect_version($data, $mode, $ecl);
1826 $version_group = (($version < 10) ? 0 : (($version < 27) ? 1 : 2));
1827 $ec_params = $this->qr_ec_params[($version - 1) * 4 + $ecl];
1828 /* Don't cut off mid-character if exceeding capacity. */
1829 $max_chars = $this->qr_capacity[$version - 1][$ecl][$mode];
1830 if ($mode == 3)
1831 $max_chars <<= 1;
1832 $data = substr($data, 0, $max_chars);
1833 /* Convert from character level to bit level. */
1834 switch ($mode) {
1835 case 0:
1836 $code = $this->qr_encode_numeric($data, $version_group);
1837 break;
1838 case 1:
1839 $code = $this->qr_encode_alphanumeric($data, $version_group);
1840 break;
1841 case 2:
1842 $code = $this->qr_encode_binary($data, $version_group);
1843 break;
1844 case 3:
1845 $code = $this->qr_encode_kanji($data, $version_group);
1846 break;
1847 }
1848 for ($i = 0; $i < 4; $i++)
1849 $code[] = 0;
1850 while (count($code) % 8)
1851 $code[] = 0;
1852 /* Convert from bit level to byte level. */
1853 $data = array();
1854 for ($i = 0, $n = count($code); $i < $n; $i += 8) {
1855 $byte = 0;
1856 if ($code[$i + 0])
1857 $byte |= 0x80;
1858 if ($code[$i + 1])
1859 $byte |= 0x40;
1860 if ($code[$i + 2])
1861 $byte |= 0x20;
1862 if ($code[$i + 3])
1863 $byte |= 0x10;
1864 if ($code[$i + 4])
1865 $byte |= 0x08;
1866 if ($code[$i + 5])
1867 $byte |= 0x04;
1868 if ($code[$i + 6])
1869 $byte |= 0x02;
1870 if ($code[$i + 7])
1871 $byte |= 0x01;
1872 $data[] = $byte;
1873 }
1874 for (
1875 $i = count($data), $a = 1, $n = $ec_params[0]; $i < $n; $i++, $a ^= 1
1876 ) {
1877 $data[] = $a ? 236 : 17;
1878 }
1879 /* Return. */
1880 return array($mode, $version, $ec_params, $data);
1881 }
1882
1883 private function qr_detect_mode($data) {
1884 $numeric = '/^[0-9]*$/';
1885 $alphanumeric = '/^[0-9A-Z .\/:$%*+-]*$/';
1886 $kanji = '/^([\x81-\x9F\xE0-\xEA][\x40-\xFC]|[\xEB][\x40-\xBF])*$/';
1887 if (preg_match($numeric, $data))
1888 return 0;
1889 if (preg_match($alphanumeric, $data))
1890 return 1;
1891 if (preg_match($kanji, $data))
1892 return 3;
1893 return 2;
1894 }
1895
1896 private function qr_detect_version($data, $mode, $ecl) {
1897 $length = strlen($data);
1898 if ($mode == 3)
1899 $length >>= 1;
1900 for ($v = 0; $v < 40; $v++) {
1901 if ($length <= $this->qr_capacity[$v][$ecl][$mode]) {
1902 return $v + 1;
1903 }
1904 }
1905 return 40;
1906 }
1907
1908 private function qr_encode_numeric($data, $version_group) {
1909 $code = array(0, 0, 0, 1);
1910 $length = strlen($data);
1911 switch ($version_group) {
1912 case 2: /* 27 - 40 */
1913 $code[] = $length & 0x2000;
1914 $code[] = $length & 0x1000;
1915 case 1: /* 10 - 26 */
1916 $code[] = $length & 0x0800;
1917 $code[] = $length & 0x0400;
1918 case 0: /* 1 - 9 */
1919 $code[] = $length & 0x0200;
1920 $code[] = $length & 0x0100;
1921 $code[] = $length & 0x0080;
1922 $code[] = $length & 0x0040;
1923 $code[] = $length & 0x0020;
1924 $code[] = $length & 0x0010;
1925 $code[] = $length & 0x0008;
1926 $code[] = $length & 0x0004;
1927 $code[] = $length & 0x0002;
1928 $code[] = $length & 0x0001;
1929 }
1930 for ($i = 0; $i < $length; $i += 3) {
1931 $group = substr($data, $i, 3);
1932 switch (strlen($group)) {
1933 case 3:
1934 $code[] = $group & 0x200;
1935 $code[] = $group & 0x100;
1936 $code[] = $group & 0x080;
1937 case 2:
1938 $code[] = $group & 0x040;
1939 $code[] = $group & 0x020;
1940 $code[] = $group & 0x010;
1941 case 1:
1942 $code[] = $group & 0x008;
1943 $code[] = $group & 0x004;
1944 $code[] = $group & 0x002;
1945 $code[] = $group & 0x001;
1946 }
1947 }
1948 return $code;
1949 }
1950
1951 private function qr_encode_alphanumeric($data, $version_group) {
1952 $alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
1953 $code = array(0, 0, 1, 0);
1954 $length = strlen($data);
1955 switch ($version_group) {
1956 case 2: /* 27 - 40 */
1957 $code[] = $length & 0x1000;
1958 $code[] = $length & 0x0800;
1959 case 1: /* 10 - 26 */
1960 $code[] = $length & 0x0400;
1961 $code[] = $length & 0x0200;
1962 case 0: /* 1 - 9 */
1963 $code[] = $length & 0x0100;
1964 $code[] = $length & 0x0080;
1965 $code[] = $length & 0x0040;
1966 $code[] = $length & 0x0020;
1967 $code[] = $length & 0x0010;
1968 $code[] = $length & 0x0008;
1969 $code[] = $length & 0x0004;
1970 $code[] = $length & 0x0002;
1971 $code[] = $length & 0x0001;
1972 }
1973 for ($i = 0; $i < $length; $i += 2) {
1974 $group = substr($data, $i, 2);
1975 if (strlen($group) > 1) {
1976 $c1 = strpos($alphabet, substr($group, 0, 1));
1977 $c2 = strpos($alphabet, substr($group, 1, 1));
1978 $ch = $c1 * 45 + $c2;
1979 $code[] = $ch & 0x400;
1980 $code[] = $ch & 0x200;
1981 $code[] = $ch & 0x100;
1982 $code[] = $ch & 0x080;
1983 $code[] = $ch & 0x040;
1984 $code[] = $ch & 0x020;
1985 $code[] = $ch & 0x010;
1986 $code[] = $ch & 0x008;
1987 $code[] = $ch & 0x004;
1988 $code[] = $ch & 0x002;
1989 $code[] = $ch & 0x001;
1990 } else {
1991 $ch = strpos($alphabet, $group);
1992 $code[] = $ch & 0x020;
1993 $code[] = $ch & 0x010;
1994 $code[] = $ch & 0x008;
1995 $code[] = $ch & 0x004;
1996 $code[] = $ch & 0x002;
1997 $code[] = $ch & 0x001;
1998 }
1999 }
2000 return $code;
2001 }
2002
2003 private function qr_encode_binary($data, $version_group) {
2004 $code = array(0, 1, 0, 0);
2005 $length = strlen($data);
2006 switch ($version_group) {
2007 case 2: /* 27 - 40 */
2008 case 1: /* 10 - 26 */
2009 $code[] = $length & 0x8000;
2010 $code[] = $length & 0x4000;
2011 $code[] = $length & 0x2000;
2012 $code[] = $length & 0x1000;
2013 $code[] = $length & 0x0800;
2014 $code[] = $length & 0x0400;
2015 $code[] = $length & 0x0200;
2016 $code[] = $length & 0x0100;
2017 case 0: /* 1 - 9 */
2018 $code[] = $length & 0x0080;
2019 $code[] = $length & 0x0040;
2020 $code[] = $length & 0x0020;
2021 $code[] = $length & 0x0010;
2022 $code[] = $length & 0x0008;
2023 $code[] = $length & 0x0004;
2024 $code[] = $length & 0x0002;
2025 $code[] = $length & 0x0001;
2026 }
2027 for ($i = 0; $i < $length; $i++) {
2028 $ch = ord(substr($data, $i, 1));
2029 $code[] = $ch & 0x80;
2030 $code[] = $ch & 0x40;
2031 $code[] = $ch & 0x20;
2032 $code[] = $ch & 0x10;
2033 $code[] = $ch & 0x08;
2034 $code[] = $ch & 0x04;
2035 $code[] = $ch & 0x02;
2036 $code[] = $ch & 0x01;
2037 }
2038 return $code;
2039 }
2040
2041 private function qr_encode_kanji($data, $version_group) {
2042 $code = array(1, 0, 0, 0);
2043 $length = strlen($data);
2044 switch ($version_group) {
2045 case 2: /* 27 - 40 */
2046 $code[] = $length & 0x1000;
2047 $code[] = $length & 0x0800;
2048 case 1: /* 10 - 26 */
2049 $code[] = $length & 0x0400;
2050 $code[] = $length & 0x0200;
2051 case 0: /* 1 - 9 */
2052 $code[] = $length & 0x0100;
2053 $code[] = $length & 0x0080;
2054 $code[] = $length & 0x0040;
2055 $code[] = $length & 0x0020;
2056 $code[] = $length & 0x0010;
2057 $code[] = $length & 0x0008;
2058 $code[] = $length & 0x0004;
2059 $code[] = $length & 0x0002;
2060 }
2061 for ($i = 0; $i < $length; $i += 2) {
2062 $group = substr($data, $i, 2);
2063 $c1 = ord(substr($group, 0, 1));
2064 $c2 = ord(substr($group, 1, 1));
2065 if ($c1 >= 0x81 && $c1 <= 0x9F && $c2 >= 0x40 && $c2 <= 0xFC) {
2066 $ch = ($c1 - 0x81) * 0xC0 + ($c2 - 0x40);
2067 } else if (
2068 ($c1 >= 0xE0 && $c1 <= 0xEA && $c2 >= 0x40 && $c2 <= 0xFC) ||
2069 ($c1 == 0xEB && $c2 >= 0x40 && $c2 <= 0xBF)
2070 ) {
2071 $ch = ($c1 - 0xC1) * 0xC0 + ($c2 - 0x40);
2072 } else {
2073 $ch = 0;
2074 }
2075 $code[] = $ch & 0x1000;
2076 $code[] = $ch & 0x0800;
2077 $code[] = $ch & 0x0400;
2078 $code[] = $ch & 0x0200;
2079 $code[] = $ch & 0x0100;
2080 $code[] = $ch & 0x0080;
2081 $code[] = $ch & 0x0040;
2082 $code[] = $ch & 0x0020;
2083 $code[] = $ch & 0x0010;
2084 $code[] = $ch & 0x0008;
2085 $code[] = $ch & 0x0004;
2086 $code[] = $ch & 0x0002;
2087 $code[] = $ch & 0x0001;
2088 }
2089 return $code;
2090 }
2091
2092 private function qr_encode_ec($data, $ec_params, $version) {
2093 $blocks = $this->qr_ec_split($data, $ec_params);
2094 $ec_blocks = array();
2095 for ($i = 0, $n = count($blocks); $i < $n; $i++) {
2096 $ec_blocks[] = $this->qr_ec_divide($blocks[$i], $ec_params);
2097 }
2098 $data = $this->qr_ec_interleave($blocks);
2099 $ec_data = $this->qr_ec_interleave($ec_blocks);
2100 $code = array();
2101 foreach ($data as $ch) {
2102 $code[] = $ch & 0x80;
2103 $code[] = $ch & 0x40;
2104 $code[] = $ch & 0x20;
2105 $code[] = $ch & 0x10;
2106 $code[] = $ch & 0x08;
2107 $code[] = $ch & 0x04;
2108 $code[] = $ch & 0x02;
2109 $code[] = $ch & 0x01;
2110 }
2111 foreach ($ec_data as $ch) {
2112 $code[] = $ch & 0x80;
2113 $code[] = $ch & 0x40;
2114 $code[] = $ch & 0x20;
2115 $code[] = $ch & 0x10;
2116 $code[] = $ch & 0x08;
2117 $code[] = $ch & 0x04;
2118 $code[] = $ch & 0x02;
2119 $code[] = $ch & 0x01;
2120 }
2121 for ($n = $this->qr_remainder_bits[$version - 1]; $n > 0; $n--) {
2122 $code[] = 0;
2123 }
2124 return $code;
2125 }
2126
2127 private function qr_ec_split($data, $ec_params) {
2128 $blocks = array();
2129 $offset = 0;
2130 for ($i = $ec_params[2], $length = $ec_params[3]; $i > 0; $i--) {
2131 $blocks[] = array_slice($data, $offset, $length);
2132 $offset += $length;
2133 }
2134 for ($i = $ec_params[4], $length = $ec_params[5]; $i > 0; $i--) {
2135 $blocks[] = array_slice($data, $offset, $length);
2136 $offset += $length;
2137 }
2138 return $blocks;
2139 }
2140
2141 private function qr_ec_divide($data, $ec_params) {
2142 $num_data = count($data);
2143 $num_error = $ec_params[1];
2144 $generator = $this->qr_ec_polynomials[$num_error];
2145 $message = $data;
2146 for ($i = 0; $i < $num_error; $i++) {
2147 $message[] = 0;
2148 }
2149 for ($i = 0; $i < $num_data; $i++) {
2150 if ($message[$i]) {
2151 $leadterm = $this->qr_log[$message[$i]];
2152 for ($j = 0; $j <= $num_error; $j++) {
2153 $term = ($generator[$j] + $leadterm) % 255;
2154 $message[$i + $j] ^= $this->qr_exp[$term];
2155 }
2156 }
2157 }
2158 return array_slice($message, $num_data, $num_error);
2159 }
2160
2161 private function qr_ec_interleave($blocks) {
2162 $data = array();
2163 $num_blocks = count($blocks);
2164 for ($offset = 0; true; $offset++) {
2165 $break = true;
2166 for ($i = 0; $i < $num_blocks; $i++) {
2167 if (isset($blocks[$i][$offset])) {
2168 $data[] = $blocks[$i][$offset];
2169 $break = false;
2170 }
2171 }
2172 if ($break)
2173 break;
2174 }
2175 return $data;
2176 }
2177
2178 private function qr_create_matrix($version, $data) {
2179 $size = $version * 4 + 17;
2180 $matrix = array();
2181 for ($i = 0; $i < $size; $i++) {
2182 $row = array();
2183 for ($j = 0; $j < $size; $j++) {
2184 $row[] = 0;
2185 }
2186 $matrix[] = $row;
2187 }
2188 /* Finder patterns. */
2189 for ($i = 0; $i < 8; $i++) {
2190 for ($j = 0; $j < 8; $j++) {
2191 $m = (($i == 7 || $j == 7) ? 2 :
2192 (($i == 0 || $j == 0 || $i == 6 || $j == 6) ? 3 :
2193 (($i == 1 || $j == 1 || $i == 5 || $j == 5) ? 2 : 3)));
2194 $matrix[$i][$j] = $m;
2195 $matrix[$size - $i - 1][$j] = $m;
2196 $matrix[$i][$size - $j - 1] = $m;
2197 }
2198 }
2199 /* Alignment patterns. */
2200 if ($version >= 2) {
2201 $alignment = $this->qr_alignment_patterns[$version - 2];
2202 foreach ($alignment as $i) {
2203 foreach ($alignment as $j) {
2204 if (!$matrix[$i][$j]) {
2205 for ($ii = -2; $ii <= 2; $ii++) {
2206 for ($jj = -2; $jj <= 2; $jj++) {
2207 $m = (max(abs($ii), abs($jj)) & 1) ^ 3;
2208 $matrix[$i + $ii][$j + $jj] = $m;
2209 }
2210 }
2211 }
2212 }
2213 }
2214 }
2215 /* Timing patterns. */
2216 for ($i = $size - 9; $i >= 8; $i--) {
2217 $matrix[$i][6] = ($i & 1) ^ 3;
2218 $matrix[6][$i] = ($i & 1) ^ 3;
2219 }
2220 /* Dark module. Such an ominous name for such an innocuous thing. */
2221 $matrix[$size - 8][8] = 3;
2222 /* Format information area. */
2223 for ($i = 0; $i <= 8; $i++) {
2224 if (!$matrix[$i][8])
2225 $matrix[$i][8] = 1;
2226 if (!$matrix[8][$i])
2227 $matrix[8][$i] = 1;
2228 if ($i && !$matrix[$size - $i][8])
2229 $matrix[$size - $i][8] = 1;
2230 if ($i && !$matrix[8][$size - $i])
2231 $matrix[8][$size - $i] = 1;
2232 }
2233 /* Version information area. */
2234 if ($version >= 7) {
2235 for ($i = 9; $i < 12; $i++) {
2236 for ($j = 0; $j < 6; $j++) {
2237 $matrix[$size - $i][$j] = 1;
2238 $matrix[$j][$size - $i] = 1;
2239 }
2240 }
2241 }
2242 /* Data. */
2243 $col = $size - 1;
2244 $row = $size - 1;
2245 $dir = -1;
2246 $offset = 0;
2247 $length = count($data);
2248 while ($col > 0 && $offset < $length) {
2249 if (!$matrix[$row][$col]) {
2250 $matrix[$row][$col] = $data[$offset] ? 5 : 4;
2251 $offset++;
2252 }
2253 if (!$matrix[$row][$col - 1]) {
2254 $matrix[$row][$col - 1] = $data[$offset] ? 5 : 4;
2255 $offset++;
2256 }
2257 $row += $dir;
2258 if ($row < 0 || $row >= $size) {
2259 $dir = -$dir;
2260 $row += $dir;
2261 $col -= 2;
2262 if ($col == 6)
2263 $col--;
2264 }
2265 }
2266 return array($size, $matrix);
2267 }
2268
2269 private function qr_apply_best_mask($matrix, $size) {
2270 $best_mask = 0;
2271 $best_matrix = $this->qr_apply_mask($matrix, $size, $best_mask);
2272 $best_penalty = $this->qr_penalty($best_matrix, $size);
2273 for ($test_mask = 1; $test_mask < 8; $test_mask++) {
2274 $test_matrix = $this->qr_apply_mask($matrix, $size, $test_mask);
2275 $test_penalty = $this->qr_penalty($test_matrix, $size);
2276 if ($test_penalty < $best_penalty) {
2277 $best_mask = $test_mask;
2278 $best_matrix = $test_matrix;
2279 $best_penalty = $test_penalty;
2280 }
2281 }
2282 return array($best_mask, $best_matrix);
2283 }
2284
2285 private function qr_apply_mask($matrix, $size, $mask) {
2286 for ($i = 0; $i < $size; $i++) {
2287 for ($j = 0; $j < $size; $j++) {
2288 if ($matrix[$i][$j] >= 4) {
2289 if ($this->qr_mask($mask, $i, $j)) {
2290 $matrix[$i][$j] ^= 1;
2291 }
2292 }
2293 }
2294 }
2295 return $matrix;
2296 }
2297
2298 private function qr_mask($mask, $r, $c) {
2299 switch ($mask) {
2300 case 0: return !( ($r + $c) % 2 );
2301 case 1: return !( ($r ) % 2 );
2302 case 2: return !( ( $c) % 3 );
2303 case 3: return !( ($r + $c) % 3 );
2304 case 4: return !( (floor(($r) / 2) + floor(($c) / 3)) % 2 );
2305 case 5: return !( ((($r * $c) % 2) + (($r * $c) % 3)) );
2306 case 6: return !( ((($r * $c) % 2) + (($r * $c) % 3)) % 2 );
2307 case 7: return !( ((($r + $c) % 2) + (($r * $c) % 3)) % 2 );
2308 }
2309 }
2310
2311 private function qr_penalty(&$matrix, $size) {
2312 $score = $this->qr_penalty_1($matrix, $size);
2313 $score += $this->qr_penalty_2($matrix, $size);
2314 $score += $this->qr_penalty_3($matrix, $size);
2315 $score += $this->qr_penalty_4($matrix, $size);
2316 return $score;
2317 }
2318
2319 private function qr_penalty_1(&$matrix, $size) {
2320 $score = 0;
2321 for ($i = 0; $i < $size; $i++) {
2322 $rowvalue = 0;
2323 $rowcount = 0;
2324 $colvalue = 0;
2325 $colcount = 0;
2326 for ($j = 0; $j < $size; $j++) {
2327 $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0;
2328 $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0;
2329 if ($rv == $rowvalue) {
2330 $rowcount++;
2331 } else {
2332 if ($rowcount >= 5)
2333 $score += $rowcount - 2;
2334 $rowvalue = $rv;
2335 $rowcount = 1;
2336 }
2337 if ($cv == $colvalue) {
2338 $colcount++;
2339 } else {
2340 if ($colcount >= 5)
2341 $score += $colcount - 2;
2342 $colvalue = $cv;
2343 $colcount = 1;
2344 }
2345 }
2346 if ($rowcount >= 5)
2347 $score += $rowcount - 2;
2348 if ($colcount >= 5)
2349 $score += $colcount - 2;
2350 }
2351 return $score;
2352 }
2353
2354 private function qr_penalty_2(&$matrix, $size) {
2355 $score = 0;
2356 for ($i = 1; $i < $size; $i++) {
2357 for ($j = 1; $j < $size; $j++) {
2358 $v1 = $matrix[$i - 1][$j - 1];
2359 $v2 = $matrix[$i - 1][$j];
2360 $v3 = $matrix[$i][$j - 1];
2361 $v4 = $matrix[$i][$j];
2362 $v1 = ($v1 == 5 || $v1 == 3) ? 1 : 0;
2363 $v2 = ($v2 == 5 || $v2 == 3) ? 1 : 0;
2364 $v3 = ($v3 == 5 || $v3 == 3) ? 1 : 0;
2365 $v4 = ($v4 == 5 || $v4 == 3) ? 1 : 0;
2366 if ($v1 == $v2 && $v2 == $v3 && $v3 == $v4)
2367 $score += 3;
2368 }
2369 }
2370 return $score;
2371 }
2372
2373 private function qr_penalty_3(&$matrix, $size) {
2374 $score = 0;
2375 for ($i = 0; $i < $size; $i++) {
2376 $rowvalue = 0;
2377 $colvalue = 0;
2378 for ($j = 0; $j < 11; $j++) {
2379 $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0;
2380 $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0;
2381 $rowvalue = (($rowvalue << 1) & 0x7FF) | $rv;
2382 $colvalue = (($colvalue << 1) & 0x7FF) | $cv;
2383 }
2384 if ($rowvalue == 0x5D0 || $rowvalue == 0x5D)
2385 $score += 40;
2386 if ($colvalue == 0x5D0 || $colvalue == 0x5D)
2387 $score += 40;
2388 for ($j = 11; $j < $size; $j++) {
2389 $rv = ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) ? 1 : 0;
2390 $cv = ($matrix[$j][$i] == 5 || $matrix[$j][$i] == 3) ? 1 : 0;
2391 $rowvalue = (($rowvalue << 1) & 0x7FF) | $rv;
2392 $colvalue = (($colvalue << 1) & 0x7FF) | $cv;
2393 if ($rowvalue == 0x5D0 || $rowvalue == 0x5D)
2394 $score += 40;
2395 if ($colvalue == 0x5D0 || $colvalue == 0x5D)
2396 $score += 40;
2397 }
2398 }
2399 return $score;
2400 }
2401
2402 private function qr_penalty_4(&$matrix, $size) {
2403 $dark = 0;
2404 for ($i = 0; $i < $size; $i++) {
2405 for ($j = 0; $j < $size; $j++) {
2406 if ($matrix[$i][$j] == 5 || $matrix[$i][$j] == 3) {
2407 $dark++;
2408 }
2409 }
2410 }
2411 $dark *= 20;
2412 $dark /= $size * $size;
2413 $a = abs(floor($dark) - 10);
2414 $b = abs(ceil($dark) - 10);
2415 return min($a, $b) * 10;
2416 }
2417
2418 private function qr_finalize_matrix(
2419 $matrix, $size, $ecl, $mask, $version
2420 ) {
2421 /* Format Info */
2422 $format = $this->qr_format_info[$ecl * 8 + $mask];
2423 $matrix[8][0] = $format[0];
2424 $matrix[8][1] = $format[1];
2425 $matrix[8][2] = $format[2];
2426 $matrix[8][3] = $format[3];
2427 $matrix[8][4] = $format[4];
2428 $matrix[8][5] = $format[5];
2429 $matrix[8][7] = $format[6];
2430 $matrix[8][8] = $format[7];
2431 $matrix[7][8] = $format[8];
2432 $matrix[5][8] = $format[9];
2433 $matrix[4][8] = $format[10];
2434 $matrix[3][8] = $format[11];
2435 $matrix[2][8] = $format[12];
2436 $matrix[1][8] = $format[13];
2437 $matrix[0][8] = $format[14];
2438 $matrix[$size - 1][8] = $format[0];
2439 $matrix[$size - 2][8] = $format[1];
2440 $matrix[$size - 3][8] = $format[2];
2441 $matrix[$size - 4][8] = $format[3];
2442 $matrix[$size - 5][8] = $format[4];
2443 $matrix[$size - 6][8] = $format[5];
2444 $matrix[$size - 7][8] = $format[6];
2445 $matrix[8][$size - 8] = $format[7];
2446 $matrix[8][$size - 7] = $format[8];
2447 $matrix[8][$size - 6] = $format[9];
2448 $matrix[8][$size - 5] = $format[10];
2449 $matrix[8][$size - 4] = $format[11];
2450 $matrix[8][$size - 3] = $format[12];
2451 $matrix[8][$size - 2] = $format[13];
2452 $matrix[8][$size - 1] = $format[14];
2453 /* Version Info */
2454 if ($version >= 7) {
2455 $version = $this->qr_version_info[$version - 7];
2456 for ($i = 0; $i < 18; $i++) {
2457 $r = $size - 9 - ($i % 3);
2458 $c = 5 - floor($i / 3);
2459 $matrix[$r][$c] = $version[$i];
2460 $matrix[$c][$r] = $version[$i];
2461 }
2462 }
2463 /* Patterns & Data */
2464 for ($i = 0; $i < $size; $i++) {
2465 for ($j = 0; $j < $size; $j++) {
2466 $matrix[$i][$j] &= 1;
2467 }
2468 }
2469 return $matrix;
2470 }
2471
2472 /* maximum encodable characters = $qr_capacity [ (version - 1) ] */
2473 /* [ (0 for L, 1 for M, 2 for Q, 3 for H) ] */
2474 /* [ (0 for numeric, 1 for alpha, 2 for binary, 3 for kanji) ] */
2475
2476 private $qr_capacity = array(
2477 array(array(41, 25, 17, 10), array(34, 20, 14, 8),
2478 array(27, 16, 11, 7), array(17, 10, 7, 4)),
2479 array(array(77, 47, 32, 20), array(63, 38, 26, 16),
2480 array(48, 29, 20, 12), array(34, 20, 14, 8)),
2481 array(array(127, 77, 53, 32), array(101, 61, 42, 26),
2482 array(77, 47, 32, 20), array(58, 35, 24, 15)),
2483 array(array(187, 114, 78, 48), array(149, 90, 62, 38),
2484 array(111, 67, 46, 28), array(82, 50, 34, 21)),
2485 array(array(255, 154, 106, 65), array(202, 122, 84, 52),
2486 array(144, 87, 60, 37), array(106, 64, 44, 27)),
2487 array(array(322, 195, 134, 82), array(255, 154, 106, 65),
2488 array(178, 108, 74, 45), array(139, 84, 58, 36)),
2489 array(array(370, 224, 154, 95), array(293, 178, 122, 75),
2490 array(207, 125, 86, 53), array(154, 93, 64, 39)),
2491 array(array(461, 279, 192, 118), array(365, 221, 152, 93),
2492 array(259, 157, 108, 66), array(202, 122, 84, 52)),
2493 array(array(552, 335, 230, 141), array(432, 262, 180, 111),
2494 array(312, 189, 130, 80), array(235, 143, 98, 60)),
2495 array(array(652, 395, 271, 167), array(513, 311, 213, 131),
2496 array(364, 221, 151, 93), array(288, 174, 119, 74)),
2497 array(array(772, 468, 321, 198), array(604, 366, 251, 155),
2498 array(427, 259, 177, 109), array(331, 200, 137, 85)),
2499 array(array(883, 535, 367, 226), array(691, 419, 287, 177),
2500 array(489, 296, 203, 125), array(374, 227, 155, 96)),
2501 array(array(1022, 619, 425, 262), array(796, 483, 331, 204),
2502 array(580, 352, 241, 149), array(427, 259, 177, 109)),
2503 array(array(1101, 667, 458, 282), array(871, 528, 362, 223),
2504 array(621, 376, 258, 159), array(468, 283, 194, 120)),
2505 array(array(1250, 758, 520, 320), array(991, 600, 412, 254),
2506 array(703, 426, 292, 180), array(530, 321, 220, 136)),
2507 array(array(1408, 854, 586, 361), array(1082, 656, 450, 277),
2508 array(775, 470, 322, 198), array(602, 365, 250, 154)),
2509 array(array(1548, 938, 644, 397), array(1212, 734, 504, 310),
2510 array(876, 531, 364, 224), array(674, 408, 280, 173)),
2511 array(array(1725, 1046, 718, 442), array(1346, 816, 560, 345),
2512 array(948, 574, 394, 243), array(746, 452, 310, 191)),
2513 array(array(1903, 1153, 792, 488), array(1500, 909, 624, 384),
2514 array(1063, 644, 442, 272), array(813, 493, 338, 208)),
2515 array(array(2061, 1249, 858, 528), array(1600, 970, 666, 410),
2516 array(1159, 702, 482, 297), array(919, 557, 382, 235)),
2517 array(array(2232, 1352, 929, 572), array(1708, 1035, 711, 438),
2518 array(1224, 742, 509, 314), array(969, 587, 403, 248)),
2519 array(array(2409, 1460, 1003, 618), array(1872, 1134, 779, 480),
2520 array(1358, 823, 565, 348), array(1056, 640, 439, 270)),
2521 array(array(2620, 1588, 1091, 672), array(2059, 1248, 857, 528),
2522 array(1468, 890, 611, 376), array(1108, 672, 461, 284)),
2523 array(array(2812, 1704, 1171, 721), array(2188, 1326, 911, 561),
2524 array(1588, 963, 661, 407), array(1228, 744, 511, 315)),
2525 array(array(3057, 1853, 1273, 784), array(2395, 1451, 997, 614),
2526 array(1718, 1041, 715, 440), array(1286, 779, 535, 330)),
2527 array(array(3283, 1990, 1367, 842), array(2544, 1542, 1059, 652),
2528 array(1804, 1094, 751, 462), array(1425, 864, 593, 365)),
2529 array(array(3517, 2132, 1465, 902), array(2701, 1637, 1125, 692),
2530 array(1933, 1172, 805, 496), array(1501, 910, 625, 385)),
2531 array(array(3669, 2223, 1528, 940), array(2857, 1732, 1190, 732),
2532 array(2085, 1263, 868, 534), array(1581, 958, 658, 405)),
2533 array(array(3909, 2369, 1628, 1002), array(3035, 1839, 1264, 778),
2534 array(2181, 1322, 908, 559), array(1677, 1016, 698, 430)),
2535 array(array(4158, 2520, 1732, 1066), array(3289, 1994, 1370, 843),
2536 array(2358, 1429, 982, 604), array(1782, 1080, 742, 457)),
2537 array(array(4417, 2677, 1840, 1132), array(3486, 2113, 1452, 894),
2538 array(2473, 1499, 1030, 634), array(1897, 1150, 790, 486)),
2539 array(array(4686, 2840, 1952, 1201), array(3693, 2238, 1538, 947),
2540 array(2670, 1618, 1112, 684), array(2022, 1226, 842, 518)),
2541 array(array(4965, 3009, 2068, 1273), array(3909, 2369, 1628, 1002),
2542 array(2805, 1700, 1168, 719), array(2157, 1307, 898, 553)),
2543 array(array(5253, 3183, 2188, 1347), array(4134, 2506, 1722, 1060),
2544 array(2949, 1787, 1228, 756), array(2301, 1394, 958, 590)),
2545 array(array(5529, 3351, 2303, 1417), array(4343, 2632, 1809, 1113),
2546 array(3081, 1867, 1283, 790), array(2361, 1431, 983, 605)),
2547 array(array(5836, 3537, 2431, 1496), array(4588, 2780, 1911, 1176),
2548 array(3244, 1966, 1351, 832), array(2524, 1530, 1051, 647)),
2549 array(array(6153, 3729, 2563, 1577), array(4775, 2894, 1989, 1224),
2550 array(3417, 2071, 1423, 876), array(2625, 1591, 1093, 673)),
2551 array(array(6479, 3927, 2699, 1661), array(5039, 3054, 2099, 1292),
2552 array(3599, 2181, 1499, 923), array(2735, 1658, 1139, 701)),
2553 array(array(6743, 4087, 2809, 1729), array(5313, 3220, 2213, 1362),
2554 array(3791, 2298, 1579, 972), array(2927, 1774, 1219, 750)),
2555 array(array(7089, 4296, 2953, 1817), array(5596, 3391, 2331, 1435),
2556 array(3993, 2420, 1663, 1024), array(3057, 1852, 1273, 784)),
2557 );
2558
2559 /* $qr_ec_params[ */
2560 /* 4 * (version - 1) + (0 for L, 1 for M, 2 for Q, 3 for H) */
2561 /* ] = array( */
2562 /* total number of data codewords, */
2563 /* number of error correction codewords per block, */
2564 /* number of blocks in first group, */
2565 /* number of data codewords per block in first group, */
2566 /* number of blocks in second group, */
2567 /* number of data codewords per block in second group */
2568 /* ); */
2569 private $qr_ec_params = array(
2570 array(19, 7, 1, 19, 0, 0),
2571 array(16, 10, 1, 16, 0, 0),
2572 array(13, 13, 1, 13, 0, 0),
2573 array(9, 17, 1, 9, 0, 0),
2574 array(34, 10, 1, 34, 0, 0),
2575 array(28, 16, 1, 28, 0, 0),
2576 array(22, 22, 1, 22, 0, 0),
2577 array(16, 28, 1, 16, 0, 0),
2578 array(55, 15, 1, 55, 0, 0),
2579 array(44, 26, 1, 44, 0, 0),
2580 array(34, 18, 2, 17, 0, 0),
2581 array(26, 22, 2, 13, 0, 0),
2582 array(80, 20, 1, 80, 0, 0),
2583 array(64, 18, 2, 32, 0, 0),
2584 array(48, 26, 2, 24, 0, 0),
2585 array(36, 16, 4, 9, 0, 0),
2586 array(108, 26, 1, 108, 0, 0),
2587 array(86, 24, 2, 43, 0, 0),
2588 array(62, 18, 2, 15, 2, 16),
2589 array(46, 22, 2, 11, 2, 12),
2590 array(136, 18, 2, 68, 0, 0),
2591 array(108, 16, 4, 27, 0, 0),
2592 array(76, 24, 4, 19, 0, 0),
2593 array(60, 28, 4, 15, 0, 0),
2594 array(156, 20, 2, 78, 0, 0),
2595 array(124, 18, 4, 31, 0, 0),
2596 array(88, 18, 2, 14, 4, 15),
2597 array(66, 26, 4, 13, 1, 14),
2598 array(194, 24, 2, 97, 0, 0),
2599 array(154, 22, 2, 38, 2, 39),
2600 array(110, 22, 4, 18, 2, 19),
2601 array(86, 26, 4, 14, 2, 15),
2602 array(232, 30, 2, 116, 0, 0),
2603 array(182, 22, 3, 36, 2, 37),
2604 array(132, 20, 4, 16, 4, 17),
2605 array(100, 24, 4, 12, 4, 13),
2606 array(274, 18, 2, 68, 2, 69),
2607 array(216, 26, 4, 43, 1, 44),
2608 array(154, 24, 6, 19, 2, 20),
2609 array(122, 28, 6, 15, 2, 16),
2610 array(324, 20, 4, 81, 0, 0),
2611 array(254, 30, 1, 50, 4, 51),
2612 array(180, 28, 4, 22, 4, 23),
2613 array(140, 24, 3, 12, 8, 13),
2614 array(370, 24, 2, 92, 2, 93),
2615 array(290, 22, 6, 36, 2, 37),
2616 array(206, 26, 4, 20, 6, 21),
2617 array(158, 28, 7, 14, 4, 15),
2618 array(428, 26, 4, 107, 0, 0),
2619 array(334, 22, 8, 37, 1, 38),
2620 array(244, 24, 8, 20, 4, 21),
2621 array(180, 22, 12, 11, 4, 12),
2622 array(461, 30, 3, 115, 1, 116),
2623 array(365, 24, 4, 40, 5, 41),
2624 array(261, 20, 11, 16, 5, 17),
2625 array(197, 24, 11, 12, 5, 13),
2626 array(523, 22, 5, 87, 1, 88),
2627 array(415, 24, 5, 41, 5, 42),
2628 array(295, 30, 5, 24, 7, 25),
2629 array(223, 24, 11, 12, 7, 13),
2630 array(589, 24, 5, 98, 1, 99),
2631 array(453, 28, 7, 45, 3, 46),
2632 array(325, 24, 15, 19, 2, 20),
2633 array(253, 30, 3, 15, 13, 16),
2634 array(647, 28, 1, 107, 5, 108),
2635 array(507, 28, 10, 46, 1, 47),
2636 array(367, 28, 1, 22, 15, 23),
2637 array(283, 28, 2, 14, 17, 15),
2638 array(721, 30, 5, 120, 1, 121),
2639 array(563, 26, 9, 43, 4, 44),
2640 array(397, 28, 17, 22, 1, 23),
2641 array(313, 28, 2, 14, 19, 15),
2642 array(795, 28, 3, 113, 4, 114),
2643 array(627, 26, 3, 44, 11, 45),
2644 array(445, 26, 17, 21, 4, 22),
2645 array(341, 26, 9, 13, 16, 14),
2646 array(861, 28, 3, 107, 5, 108),
2647 array(669, 26, 3, 41, 13, 42),
2648 array(485, 30, 15, 24, 5, 25),
2649 array(385, 28, 15, 15, 10, 16),
2650 array(932, 28, 4, 116, 4, 117),
2651 array(714, 26, 17, 42, 0, 0),
2652 array(512, 28, 17, 22, 6, 23),
2653 array(406, 30, 19, 16, 6, 17),
2654 array(1006, 28, 2, 111, 7, 112),
2655 array(782, 28, 17, 46, 0, 0),
2656 array(568, 30, 7, 24, 16, 25),
2657 array(442, 24, 34, 13, 0, 0),
2658 array(1094, 30, 4, 121, 5, 122),
2659 array(860, 28, 4, 47, 14, 48),
2660 array(614, 30, 11, 24, 14, 25),
2661 array(464, 30, 16, 15, 14, 16),
2662 array(1174, 30, 6, 117, 4, 118),
2663 array(914, 28, 6, 45, 14, 46),
2664 array(664, 30, 11, 24, 16, 25),
2665 array(514, 30, 30, 16, 2, 17),
2666 array(1276, 26, 8, 106, 4, 107),
2667 array(1000, 28, 8, 47, 13, 48),
2668 array(718, 30, 7, 24, 22, 25),
2669 array(538, 30, 22, 15, 13, 16),
2670 array(1370, 28, 10, 114, 2, 115),
2671 array(1062, 28, 19, 46, 4, 47),
2672 array(754, 28, 28, 22, 6, 23),
2673 array(596, 30, 33, 16, 4, 17),
2674 array(1468, 30, 8, 122, 4, 123),
2675 array(1128, 28, 22, 45, 3, 46),
2676 array(808, 30, 8, 23, 26, 24),
2677 array(628, 30, 12, 15, 28, 16),
2678 array(1531, 30, 3, 117, 10, 118),
2679 array(1193, 28, 3, 45, 23, 46),
2680 array(871, 30, 4, 24, 31, 25),
2681 array(661, 30, 11, 15, 31, 16),
2682 array(1631, 30, 7, 116, 7, 117),
2683 array(1267, 28, 21, 45, 7, 46),
2684 array(911, 30, 1, 23, 37, 24),
2685 array(701, 30, 19, 15, 26, 16),
2686 array(1735, 30, 5, 115, 10, 116),
2687 array(1373, 28, 19, 47, 10, 48),
2688 array(985, 30, 15, 24, 25, 25),
2689 array(745, 30, 23, 15, 25, 16),
2690 array(1843, 30, 13, 115, 3, 116),
2691 array(1455, 28, 2, 46, 29, 47),
2692 array(1033, 30, 42, 24, 1, 25),
2693 array(793, 30, 23, 15, 28, 16),
2694 array(1955, 30, 17, 115, 0, 0),
2695 array(1541, 28, 10, 46, 23, 47),
2696 array(1115, 30, 10, 24, 35, 25),
2697 array(845, 30, 19, 15, 35, 16),
2698 array(2071, 30, 17, 115, 1, 116),
2699 array(1631, 28, 14, 46, 21, 47),
2700 array(1171, 30, 29, 24, 19, 25),
2701 array(901, 30, 11, 15, 46, 16),
2702 array(2191, 30, 13, 115, 6, 116),
2703 array(1725, 28, 14, 46, 23, 47),
2704 array(1231, 30, 44, 24, 7, 25),
2705 array(961, 30, 59, 16, 1, 17),
2706 array(2306, 30, 12, 121, 7, 122),
2707 array(1812, 28, 12, 47, 26, 48),
2708 array(1286, 30, 39, 24, 14, 25),
2709 array(986, 30, 22, 15, 41, 16),
2710 array(2434, 30, 6, 121, 14, 122),
2711 array(1914, 28, 6, 47, 34, 48),
2712 array(1354, 30, 46, 24, 10, 25),
2713 array(1054, 30, 2, 15, 64, 16),
2714 array(2566, 30, 17, 122, 4, 123),
2715 array(1992, 28, 29, 46, 14, 47),
2716 array(1426, 30, 49, 24, 10, 25),
2717 array(1096, 30, 24, 15, 46, 16),
2718 array(2702, 30, 4, 122, 18, 123),
2719 array(2102, 28, 13, 46, 32, 47),
2720 array(1502, 30, 48, 24, 14, 25),
2721 array(1142, 30, 42, 15, 32, 16),
2722 array(2812, 30, 20, 117, 4, 118),
2723 array(2216, 28, 40, 47, 7, 48),
2724 array(1582, 30, 43, 24, 22, 25),
2725 array(1222, 30, 10, 15, 67, 16),
2726 array(2956, 30, 19, 118, 6, 119),
2727 array(2334, 28, 18, 47, 31, 48),
2728 array(1666, 30, 34, 24, 34, 25),
2729 array(1276, 30, 20, 15, 61, 16),
2730 );
2731 private $qr_ec_polynomials = array(
2732 7 => array(
2733 0, 87, 229, 146, 149, 238, 102, 21
2734 ),
2735 10 => array(
2736 0, 251, 67, 46, 61, 118, 70, 64, 94, 32, 45
2737 ),
2738 13 => array(
2739 0, 74, 152, 176, 100, 86, 100,
2740 106, 104, 130, 218, 206, 140, 78
2741 ),
2742 15 => array(
2743 0, 8, 183, 61, 91, 202, 37, 51,
2744 58, 58, 237, 140, 124, 5, 99, 105
2745 ),
2746 16 => array(
2747 0, 120, 104, 107, 109, 102, 161, 76, 3,
2748 91, 191, 147, 169, 182, 194, 225, 120
2749 ),
2750 17 => array(
2751 0, 43, 139, 206, 78, 43, 239, 123, 206,
2752 214, 147, 24, 99, 150, 39, 243, 163, 136
2753 ),
2754 18 => array(
2755 0, 215, 234, 158, 94, 184, 97, 118, 170, 79,
2756 187, 152, 148, 252, 179, 5, 98, 96, 153
2757 ),
2758 20 => array(
2759 0, 17, 60, 79, 50, 61, 163, 26, 187, 202, 180,
2760 221, 225, 83, 239, 156, 164, 212, 212, 188, 190
2761 ),
2762 22 => array(
2763 0, 210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200,
2764 74, 8, 172, 98, 80, 219, 134, 160, 105, 165, 231
2765 ),
2766 24 => array(
2767 0, 229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169,
2768 152, 192, 226, 228, 218, 111, 0, 117, 232, 87, 96, 227, 21
2769 ),
2770 26 => array(
2771 0, 173, 125, 158, 2, 103, 182, 118, 17,
2772 145, 201, 111, 28, 165, 53, 161, 21, 245,
2773 142, 13, 102, 48, 227, 153, 145, 218, 70
2774 ),
2775 28 => array(
2776 0, 168, 223, 200, 104, 224, 234, 108, 180,
2777 110, 190, 195, 147, 205, 27, 232, 201, 21, 43,
2778 245, 87, 42, 195, 212, 119, 242, 37, 9, 123
2779 ),
2780 30 => array(
2781 0, 41, 173, 145, 152, 216, 31, 179, 182, 50, 48,
2782 110, 86, 239, 96, 222, 125, 42, 173, 226, 193,
2783 224, 130, 156, 37, 251, 216, 238, 40, 192, 180
2784 ),
2785 );
2786 private $qr_log = array(
2787 0, 0, 1, 25, 2, 50, 26, 198,
2788 3, 223, 51, 238, 27, 104, 199, 75,
2789 4, 100, 224, 14, 52, 141, 239, 129,
2790 28, 193, 105, 248, 200, 8, 76, 113,
2791 5, 138, 101, 47, 225, 36, 15, 33,
2792 53, 147, 142, 218, 240, 18, 130, 69,
2793 29, 181, 194, 125, 106, 39, 249, 185,
2794 201, 154, 9, 120, 77, 228, 114, 166,
2795 6, 191, 139, 98, 102, 221, 48, 253,
2796 226, 152, 37, 179, 16, 145, 34, 136,
2797 54, 208, 148, 206, 143, 150, 219, 189,
2798 241, 210, 19, 92, 131, 56, 70, 64,
2799 30, 66, 182, 163, 195, 72, 126, 110,
2800 107, 58, 40, 84, 250, 133, 186, 61,
2801 202, 94, 155, 159, 10, 21, 121, 43,
2802 78, 212, 229, 172, 115, 243, 167, 87,
2803 7, 112, 192, 247, 140, 128, 99, 13,
2804 103, 74, 222, 237, 49, 197, 254, 24,
2805 227, 165, 153, 119, 38, 184, 180, 124,
2806 17, 68, 146, 217, 35, 32, 137, 46,
2807 55, 63, 209, 91, 149, 188, 207, 205,
2808 144, 135, 151, 178, 220, 252, 190, 97,
2809 242, 86, 211, 171, 20, 42, 93, 158,
2810 132, 60, 57, 83, 71, 109, 65, 162,
2811 31, 45, 67, 216, 183, 123, 164, 118,
2812 196, 23, 73, 236, 127, 12, 111, 246,
2813 108, 161, 59, 82, 41, 157, 85, 170,
2814 251, 96, 134, 177, 187, 204, 62, 90,
2815 203, 89, 95, 176, 156, 169, 160, 81,
2816 11, 245, 22, 235, 122, 117, 44, 215,
2817 79, 174, 213, 233, 230, 231, 173, 232,
2818 116, 214, 244, 234, 168, 80, 88, 175,
2819 );
2820 private $qr_exp = array(
2821 1, 2, 4, 8, 16, 32, 64, 128,
2822 29, 58, 116, 232, 205, 135, 19, 38,
2823 76, 152, 45, 90, 180, 117, 234, 201,
2824 143, 3, 6, 12, 24, 48, 96, 192,
2825 157, 39, 78, 156, 37, 74, 148, 53,
2826 106, 212, 181, 119, 238, 193, 159, 35,
2827 70, 140, 5, 10, 20, 40, 80, 160,
2828 93, 186, 105, 210, 185, 111, 222, 161,
2829 95, 190, 97, 194, 153, 47, 94, 188,
2830 101, 202, 137, 15, 30, 60, 120, 240,
2831 253, 231, 211, 187, 107, 214, 177, 127,
2832 254, 225, 223, 163, 91, 182, 113, 226,
2833 217, 175, 67, 134, 17, 34, 68, 136,
2834 13, 26, 52, 104, 208, 189, 103, 206,
2835 129, 31, 62, 124, 248, 237, 199, 147,
2836 59, 118, 236, 197, 151, 51, 102, 204,
2837 133, 23, 46, 92, 184, 109, 218, 169,
2838 79, 158, 33, 66, 132, 21, 42, 84,
2839 168, 77, 154, 41, 82, 164, 85, 170,
2840 73, 146, 57, 114, 228, 213, 183, 115,
2841 230, 209, 191, 99, 198, 145, 63, 126,
2842 252, 229, 215, 179, 123, 246, 241, 255,
2843 227, 219, 171, 75, 150, 49, 98, 196,
2844 149, 55, 110, 220, 165, 87, 174, 65,
2845 130, 25, 50, 100, 200, 141, 7, 14,
2846 28, 56, 112, 224, 221, 167, 83, 166,
2847 81, 162, 89, 178, 121, 242, 249, 239,
2848 195, 155, 43, 86, 172, 69, 138, 9,
2849 18, 36, 72, 144, 61, 122, 244, 245,
2850 247, 243, 251, 235, 203, 139, 11, 22,
2851 44, 88, 176, 125, 250, 233, 207, 131,
2852 27, 54, 108, 216, 173, 71, 142, 1,
2853 );
2854 private $qr_remainder_bits = array(
2855 0, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3,
2856 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
2857 );
2858 private $qr_alignment_patterns = array(
2859 array(6, 18),
2860 array(6, 22),
2861 array(6, 26),
2862 array(6, 30),
2863 array(6, 34),
2864 array(6, 22, 38),
2865 array(6, 24, 42),
2866 array(6, 26, 46),
2867 array(6, 28, 50),
2868 array(6, 30, 54),
2869 array(6, 32, 58),
2870 array(6, 34, 62),
2871 array(6, 26, 46, 66),
2872 array(6, 26, 48, 70),
2873 array(6, 26, 50, 74),
2874 array(6, 30, 54, 78),
2875 array(6, 30, 56, 82),
2876 array(6, 30, 58, 86),
2877 array(6, 34, 62, 90),
2878 array(6, 28, 50, 72, 94),
2879 array(6, 26, 50, 74, 98),
2880 array(6, 30, 54, 78, 102),
2881 array(6, 28, 54, 80, 106),
2882 array(6, 32, 58, 84, 110),
2883 array(6, 30, 58, 86, 114),
2884 array(6, 34, 62, 90, 118),
2885 array(6, 26, 50, 74, 98, 122),
2886 array(6, 30, 54, 78, 102, 126),
2887 array(6, 26, 52, 78, 104, 130),
2888 array(6, 30, 56, 82, 108, 134),
2889 array(6, 34, 60, 86, 112, 138),
2890 array(6, 30, 58, 86, 114, 142),
2891 array(6, 34, 62, 90, 118, 146),
2892 array(6, 30, 54, 78, 102, 126, 150),
2893 array(6, 24, 50, 76, 102, 128, 154),
2894 array(6, 28, 54, 80, 106, 132, 158),
2895 array(6, 32, 58, 84, 110, 136, 162),
2896 array(6, 26, 54, 82, 110, 138, 166),
2897 array(6, 30, 58, 86, 114, 142, 170),
2898 );
2899
2900 /* format info string = $qr_format_info[ */
2901 /* (0 for L, 8 for M, 16 for Q, 24 for H) + mask */
2902 /* ]; */
2903 private $qr_format_info = array(
2904 array(1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0),
2905 array(1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1),
2906 array(1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0),
2907 array(1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1),
2908 array(1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1),
2909 array(1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0),
2910 array(1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1),
2911 array(1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0),
2912 array(1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0),
2913 array(1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1),
2914 array(1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0),
2915 array(1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1),
2916 array(1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1),
2917 array(1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0),
2918 array(1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1),
2919 array(1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0),
2920 array(0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1),
2921 array(0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0),
2922 array(0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1),
2923 array(0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0),
2924 array(0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0),
2925 array(0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1),
2926 array(0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0),
2927 array(0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1),
2928 array(0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1),
2929 array(0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0),
2930 array(0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1),
2931 array(0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0),
2932 array(0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0),
2933 array(0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1),
2934 array(0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0),
2935 array(0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1),
2936 );
2937
2938 /* version info string = $qr_version_info[ (version - 7) ] */
2939 private $qr_version_info = array(
2940 array(0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0),
2941 array(0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0),
2942 array(0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1),
2943 array(0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1),
2944 array(0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0),
2945 array(0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0),
2946 array(0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1),
2947 array(0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1),
2948 array(0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0),
2949 array(0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0),
2950 array(0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1),
2951 array(0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1),
2952 array(0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0),
2953 array(0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0),
2954 array(0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1),
2955 array(0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1),
2956 array(0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0),
2957 array(0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0),
2958 array(0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1),
2959 array(0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1),
2960 array(0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0),
2961 array(0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0),
2962 array(0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1),
2963 array(0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1),
2964 array(0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0),
2965 array(1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1),
2966 array(1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0),
2967 array(1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0),
2968 array(1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1),
2969 array(1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1),
2970 array(1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0),
2971 array(1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0),
2972 array(1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1),
2973 array(1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1),
2974 );
2975
2976 /* - - - - DATA MATRIX ENCODER - - - - */
2977
2978 private function dmtx_encode($data, $rect, $fnc1) {
2979 list($data, $ec) = $this->dmtx_encode_data($data, $rect, $fnc1);
2980 $data = $this->dmtx_encode_ec($data, $ec);
2981 list($h, $w, $mtx) = $this->dmtx_create_matrix($ec, $data);
2982 return array(
2983 'g' => 'm',
2984 'q' => array(1, 1, 1, 1),
2985 's' => array($w, $h),
2986 'b' => $mtx
2987 );
2988 }
2989
2990 private function dmtx_encode_data($data, $rect, $fnc1) {
2991 /* Convert to data codewords. */
2992 $edata = ($fnc1 ? array(232) : array());
2993 $length = strlen($data);
2994 $offset = 0;
2995 while ($offset < $length) {
2996 $ch1 = ord(substr($data, $offset, 1));
2997 $offset++;
2998 if ($ch1 >= 0x30 && $ch1 <= 0x39) {
2999 $ch2 = ord(substr($data, $offset, 1));
3000 if ($ch2 >= 0x30 && $ch2 <= 0x39) {
3001 $offset++;
3002 $edata[] = (($ch1 - 0x30) * 10) + ($ch2 - 0x30) + 130;
3003 } else {
3004 $edata[] = $ch1 + 1;
3005 }
3006 } else if ($ch1 < 0x80) {
3007 $edata[] = $ch1 + 1;
3008 } else {
3009 $edata[] = 235;
3010 $edata[] = ($ch1 - 0x80) + 1;
3011 }
3012 }
3013 /* Add padding. */
3014 $length = count($edata);
3015 $ec_params = $this->dmtx_detect_version($length, $rect);
3016 if ($length > $ec_params[0]) {
3017 $length = $ec_params[0];
3018 $edata = array_slice($edata, 0, $length);
3019 if ($edata[$length - 1] == 235) {
3020 $edata[$length - 1] = 129;
3021 }
3022 } else if ($length < $ec_params[0]) {
3023 $length++;
3024 $edata[] = 129;
3025 while ($length < $ec_params[0]) {
3026 $length++;
3027 $r = (($length * 149) % 253) + 1;
3028 $edata[] = ($r + 129) % 254;
3029 }
3030 }
3031 /* Return. */
3032 return array($edata, $ec_params);
3033 }
3034
3035 private function dmtx_detect_version($length, $rect) {
3036 for ($i = ($rect ? 24 : 0), $j = ($rect ? 30 : 24); $i < $j; $i++) {
3037 if ($length <= $this->dmtx_ec_params[$i][0]) {
3038 return $this->dmtx_ec_params[$i];
3039 }
3040 }
3041 return $this->dmtx_ec_params[$j - 1];
3042 }
3043
3044 private function dmtx_encode_ec($data, $ec_params) {
3045 $blocks = $this->dmtx_ec_split($data, $ec_params);
3046 for ($i = 0, $n = count($blocks); $i < $n; $i++) {
3047 $ec_block = $this->dmtx_ec_divide($blocks[$i], $ec_params);
3048 $blocks[$i] = array_merge($blocks[$i], $ec_block);
3049 }
3050 return $this->dmtx_ec_interleave($blocks);
3051 }
3052
3053 private function dmtx_ec_split($data, $ec_params) {
3054 $blocks = array();
3055 $num_blocks = $ec_params[2] + $ec_params[4];
3056 for ($i = 0; $i < $num_blocks; $i++) {
3057 $blocks[$i] = array();
3058 }
3059 for ($i = 0, $length = count($data); $i < $length; $i++) {
3060 $blocks[$i % $num_blocks][] = $data[$i];
3061 }
3062 return $blocks;
3063 }
3064
3065 private function dmtx_ec_divide($data, $ec_params) {
3066 $num_data = count($data);
3067 $num_error = $ec_params[1];
3068 $generator = $this->dmtx_ec_polynomials[$num_error];
3069 $message = $data;
3070 for ($i = 0; $i < $num_error; $i++) {
3071 $message[] = 0;
3072 }
3073 for ($i = 0; $i < $num_data; $i++) {
3074 if ($message[$i]) {
3075 $leadterm = $this->dmtx_log[$message[$i]];
3076 for ($j = 0; $j <= $num_error; $j++) {
3077 $term = ($generator[$j] + $leadterm) % 255;
3078 $message[$i + $j] ^= $this->dmtx_exp[$term];
3079 }
3080 }
3081 }
3082 return array_slice($message, $num_data, $num_error);
3083 }
3084
3085 private function dmtx_ec_interleave($blocks) {
3086 $data = array();
3087 $num_blocks = count($blocks);
3088 for ($offset = 0; true; $offset++) {
3089 $break = true;
3090 for ($i = 0; $i < $num_blocks; $i++) {
3091 if (isset($blocks[$i][$offset])) {
3092 $data[] = $blocks[$i][$offset];
3093 $break = false;
3094 }
3095 }
3096 if ($break)
3097 break;
3098 }
3099 return $data;
3100 }
3101
3102 private function dmtx_create_matrix($ec_params, $data) {
3103 /* Create matrix. */
3104 $rheight = $ec_params[8] + 2;
3105 $rwidth = $ec_params[9] + 2;
3106 $height = $ec_params[6] * $rheight;
3107 $width = $ec_params[7] * $rwidth;
3108 $bitmap = array();
3109 for ($y = 0; $y < $height; $y++) {
3110 $row = array();
3111 for ($x = 0; $x < $width; $x++) {
3112 $row[] = ((
3113 ((($x + $y) % 2) == 0) ||
3114 (($x % $rwidth) == 0) ||
3115 (($y % $rheight) == ($rheight - 1))
3116 ) ? 1 : 0);
3117 }
3118 $bitmap[] = $row;
3119 }
3120 /* Create data region. */
3121 $rows = $ec_params[6] * $ec_params[8];
3122 $cols = $ec_params[7] * $ec_params[9];
3123 $matrix = array();
3124 for ($y = 0; $y < $rows; $y++) {
3125 $row = array();
3126 for ($x = 0; $x < $width; $x++) {
3127 $row[] = null;
3128 }
3129 $matrix[] = $row;
3130 }
3131 $this->dmtx_place_data($matrix, $rows, $cols, $data);
3132 /* Copy into matrix. */
3133 for ($yy = 0; $yy < $ec_params[6]; $yy++) {
3134 for ($xx = 0; $xx < $ec_params[7]; $xx++) {
3135 for ($y = 0; $y < $ec_params[8]; $y++) {
3136 for ($x = 0; $x < $ec_params[9]; $x++) {
3137 $row = $yy * $ec_params[8] + $y;
3138 $col = $xx * $ec_params[9] + $x;
3139 $b = $matrix[$row][$col];
3140 if (is_null($b))
3141 continue;
3142 $row = $yy * $rheight + $y + 1;
3143 $col = $xx * $rwidth + $x + 1;
3144 $bitmap[$row][$col] = $b;
3145 }
3146 }
3147 }
3148 }
3149 /* Return matrix. */
3150 return array($height, $width, $bitmap);
3151 }
3152
3153 private function dmtx_place_data(&$mtx, $rows, $cols, $data) {
3154 $row = 4;
3155 $col = 0;
3156 $offset = 0;
3157 $length = count($data);
3158 while (($row < $rows || $col < $cols) && $offset < $length) {
3159 /* Corner cases. Literally. */
3160 if ($row == $rows && $col == 0) {
3161 $this->dmtx_place_1($mtx, $rows, $cols, $data[$offset++]);
3162 } else if ($row == $rows - 2 && $col == 0 && $cols % 4 != 0) {
3163 $this->dmtx_place_2($mtx, $rows, $cols, $data[$offset++]);
3164 } else if ($row == $rows - 2 && $col == 0 && $cols % 8 == 4) {
3165 $this->dmtx_place_3($mtx, $rows, $cols, $data[$offset++]);
3166 } else if ($row == $rows + 4 && $col == 2 && $cols % 8 == 0) {
3167 $this->dmtx_place_4($mtx, $rows, $cols, $data[$offset++]);
3168 }
3169 /* Up and to the right. */
3170 while ($row >= 0 && $col < $cols && $offset < $length) {
3171 if ($row < $rows && $col >= 0 && is_null($mtx[$row][$col])) {
3172 $b = $data[$offset++];
3173 $this->dmtx_place_0($mtx, $rows, $cols, $row, $col, $b);
3174 }
3175 $row -= 2;
3176 $col += 2;
3177 }
3178 $row += 1;
3179 $col += 3;
3180 /* Down and to the left. */
3181 while ($row < $rows && $col >= 0 && $offset < $length) {
3182 if ($row >= 0 && $col < $cols && is_null($mtx[$row][$col])) {
3183 $b = $data[$offset++];
3184 $this->dmtx_place_0($mtx, $rows, $cols, $row, $col, $b);
3185 }
3186 $row += 2;
3187 $col -= 2;
3188 }
3189 $row += 3;
3190 $col += 1;
3191 }
3192 }
3193
3194 private function dmtx_place_1(&$matrix, $rows, $cols, $b) {
3195 $matrix[$rows - 1][0] = (($b & 0x80) ? 1 : 0);
3196 $matrix[$rows - 1][1] = (($b & 0x40) ? 1 : 0);
3197 $matrix[$rows - 1][2] = (($b & 0x20) ? 1 : 0);
3198 $matrix[0][$cols - 2] = (($b & 0x10) ? 1 : 0);
3199 $matrix[0][$cols - 1] = (($b & 0x08) ? 1 : 0);
3200 $matrix[1][$cols - 1] = (($b & 0x04) ? 1 : 0);
3201 $matrix[2][$cols - 1] = (($b & 0x02) ? 1 : 0);
3202 $matrix[3][$cols - 1] = (($b & 0x01) ? 1 : 0);
3203 }
3204
3205 private function dmtx_place_2(&$matrix, $rows, $cols, $b) {
3206 $matrix[$rows - 3][0] = (($b & 0x80) ? 1 : 0);
3207 $matrix[$rows - 2][0] = (($b & 0x40) ? 1 : 0);
3208 $matrix[$rows - 1][0] = (($b & 0x20) ? 1 : 0);
3209 $matrix[0][$cols - 4] = (($b & 0x10) ? 1 : 0);
3210 $matrix[0][$cols - 3] = (($b & 0x08) ? 1 : 0);
3211 $matrix[0][$cols - 2] = (($b & 0x04) ? 1 : 0);
3212 $matrix[0][$cols - 1] = (($b & 0x02) ? 1 : 0);
3213 $matrix[1][$cols - 1] = (($b & 0x01) ? 1 : 0);
3214 }
3215
3216 private function dmtx_place_3(&$matrix, $rows, $cols, $b) {
3217 $matrix[$rows - 3][0] = (($b & 0x80) ? 1 : 0);
3218 $matrix[$rows - 2][0] = (($b & 0x40) ? 1 : 0);
3219 $matrix[$rows - 1][0] = (($b & 0x20) ? 1 : 0);
3220 $matrix[0][$cols - 2] = (($b & 0x10) ? 1 : 0);
3221 $matrix[0][$cols - 1] = (($b & 0x08) ? 1 : 0);
3222 $matrix[1][$cols - 1] = (($b & 0x04) ? 1 : 0);
3223 $matrix[2][$cols - 1] = (($b & 0x02) ? 1 : 0);
3224 $matrix[3][$cols - 1] = (($b & 0x01) ? 1 : 0);
3225 }
3226
3227 private function dmtx_place_4(&$matrix, $rows, $cols, $b) {
3228 $matrix[$rows - 1][0] = (($b & 0x80) ? 1 : 0);
3229 $matrix[$rows - 1][$cols - 1] = (($b & 0x40) ? 1 : 0);
3230 $matrix[0][$cols - 3] = (($b & 0x20) ? 1 : 0);
3231 $matrix[0][$cols - 2] = (($b & 0x10) ? 1 : 0);
3232 $matrix[0][$cols - 1] = (($b & 0x08) ? 1 : 0);
3233 $matrix[1][$cols - 3] = (($b & 0x04) ? 1 : 0);
3234 $matrix[1][$cols - 2] = (($b & 0x02) ? 1 : 0);
3235 $matrix[1][$cols - 1] = (($b & 0x01) ? 1 : 0);
3236 }
3237
3238 private function dmtx_place_0(&$matrix, $rows, $cols, $row, $col, $b) {
3239 $this->dmtx_place_b($matrix, $rows, $cols, $row - 2, $col - 2, $b & 0x80);
3240 $this->dmtx_place_b($matrix, $rows, $cols, $row - 2, $col - 1, $b & 0x40);
3241 $this->dmtx_place_b($matrix, $rows, $cols, $row - 1, $col - 2, $b & 0x20);
3242 $this->dmtx_place_b($matrix, $rows, $cols, $row - 1, $col - 1, $b & 0x10);
3243 $this->dmtx_place_b($matrix, $rows, $cols, $row - 1, $col - 0, $b & 0x08);
3244 $this->dmtx_place_b($matrix, $rows, $cols, $row - 0, $col - 2, $b & 0x04);
3245 $this->dmtx_place_b($matrix, $rows, $cols, $row - 0, $col - 1, $b & 0x02);
3246 $this->dmtx_place_b($matrix, $rows, $cols, $row - 0, $col - 0, $b & 0x01);
3247 }
3248
3249 private function dmtx_place_b(&$matrix, $rows, $cols, $row, $col, $b) {
3250 if ($row < 0) {
3251 $row += $rows;
3252 $col += (4 - (($rows + 4) % 8));
3253 }
3254 if ($col < 0) {
3255 $col += $cols;
3256 $row += (4 - (($cols + 4) % 8));
3257 }
3258 $matrix[$row][$col] = ($b ? 1 : 0);
3259 }
3260
3261 /* $dmtx_ec_params[] = array( */
3262 /* total number of data codewords, */
3263 /* number of error correction codewords per block, */
3264 /* number of blocks in first group, */
3265 /* number of data codewords per block in first group, */
3266 /* number of blocks in second group, */
3267 /* number of data codewords per block in second group, */
3268 /* number of data regions (vertical), */
3269 /* number of data regions (horizontal), */
3270 /* number of rows per data region, */
3271 /* number of columns per data region */
3272 /* ); */
3273
3274 private $dmtx_ec_params = array(
3275 array(3, 5, 1, 3, 0, 0, 1, 1, 8, 8),
3276 array(5, 7, 1, 5, 0, 0, 1, 1, 10, 10),
3277 array(8, 10, 1, 8, 0, 0, 1, 1, 12, 12),
3278 array(12, 12, 1, 12, 0, 0, 1, 1, 14, 14),
3279 array(18, 14, 1, 18, 0, 0, 1, 1, 16, 16),
3280 array(22, 18, 1, 22, 0, 0, 1, 1, 18, 18),
3281 array(30, 20, 1, 30, 0, 0, 1, 1, 20, 20),
3282 array(36, 24, 1, 36, 0, 0, 1, 1, 22, 22),
3283 array(44, 28, 1, 44, 0, 0, 1, 1, 24, 24),
3284 array(62, 36, 1, 62, 0, 0, 2, 2, 14, 14),
3285 array(86, 42, 1, 86, 0, 0, 2, 2, 16, 16),
3286 array(114, 48, 1, 114, 0, 0, 2, 2, 18, 18),
3287 array(144, 56, 1, 144, 0, 0, 2, 2, 20, 20),
3288 array(174, 68, 1, 174, 0, 0, 2, 2, 22, 22),
3289 array(204, 42, 2, 102, 0, 0, 2, 2, 24, 24),
3290 array(280, 56, 2, 140, 0, 0, 4, 4, 14, 14),
3291 array(368, 36, 4, 92, 0, 0, 4, 4, 16, 16),
3292 array(456, 48, 4, 114, 0, 0, 4, 4, 18, 18),
3293 array(576, 56, 4, 144, 0, 0, 4, 4, 20, 20),
3294 array(696, 68, 4, 174, 0, 0, 4, 4, 22, 22),
3295 array(816, 56, 6, 136, 0, 0, 4, 4, 24, 24),
3296 array(1050, 68, 6, 175, 0, 0, 6, 6, 18, 18),
3297 array(1304, 62, 8, 163, 0, 0, 6, 6, 20, 20),
3298 array(1558, 62, 8, 156, 2, 155, 6, 6, 22, 22),
3299 array(5, 7, 1, 5, 0, 0, 1, 1, 6, 16),
3300 array(10, 11, 1, 10, 0, 0, 1, 2, 6, 14),
3301 array(16, 14, 1, 16, 0, 0, 1, 1, 10, 24),
3302 array(22, 18, 1, 22, 0, 0, 1, 2, 10, 16),
3303 array(32, 24, 1, 32, 0, 0, 1, 2, 14, 16),
3304 array(49, 28, 1, 49, 0, 0, 1, 2, 14, 22),
3305 );
3306 private $dmtx_ec_polynomials = array(
3307 5 => array(
3308 0, 235, 207, 210, 244, 15
3309 ),
3310 7 => array(
3311 0, 177, 30, 214, 218, 42, 197, 28
3312 ),
3313 10 => array(
3314 0, 199, 50, 150, 120, 237, 131, 172, 83, 243, 55
3315 ),
3316 11 => array(
3317 0, 213, 173, 212, 156, 103, 109, 174, 242, 215, 12, 66
3318 ),
3319 12 => array(
3320 0, 168, 142, 35, 173, 94, 185, 107, 199, 74, 194, 233, 78
3321 ),
3322 14 => array(
3323 0, 83, 171, 33, 39, 8, 12, 248,
3324 27, 38, 84, 93, 246, 173, 105
3325 ),
3326 18 => array(
3327 0, 164, 9, 244, 69, 177, 163, 161, 231, 94,
3328 250, 199, 220, 253, 164, 103, 142, 61, 171
3329 ),
3330 20 => array(
3331 0, 127, 33, 146, 23, 79, 25, 193, 122, 209, 233,
3332 230, 164, 1, 109, 184, 149, 38, 201, 61, 210
3333 ),
3334 24 => array(
3335 0, 65, 141, 245, 31, 183, 242, 236, 177, 127, 225, 106,
3336 22, 131, 20, 202, 22, 106, 137, 103, 231, 215, 136, 85, 45
3337 ),
3338 28 => array(
3339 0, 150, 32, 109, 149, 239, 213, 198, 48, 94,
3340 50, 12, 195, 167, 130, 196, 253, 99, 166, 239,
3341 222, 146, 190, 245, 184, 173, 125, 17, 151
3342 ),
3343 36 => array(
3344 0, 57, 86, 187, 69, 140, 153, 31, 66, 135, 67, 248, 84,
3345 90, 81, 219, 197, 2, 1, 39, 16, 75, 229, 20, 51, 252,
3346 108, 213, 181, 183, 87, 111, 77, 232, 168, 176, 156
3347 ),
3348 42 => array(
3349 0, 225, 38, 225, 148, 192, 254, 141, 11, 82, 237,
3350 81, 24, 13, 122, 0, 106, 167, 13, 207, 160, 88,
3351 203, 38, 142, 84, 66, 3, 168, 102, 156, 1, 200,
3352 88, 60, 233, 134, 115, 114, 234, 90, 65, 138
3353 ),
3354 48 => array(
3355 0, 114, 69, 122, 30, 94, 11, 66, 230, 132, 73, 145, 137,
3356 135, 79, 214, 33, 12, 220, 142, 213, 136, 124, 215, 166,
3357 9, 222, 28, 154, 132, 4, 100, 170, 145, 59, 164, 215, 17,
3358 249, 102, 249, 134, 128, 5, 245, 131, 127, 221, 156
3359 ),
3360 56 => array(
3361 0, 29, 179, 99, 149, 159, 72, 125, 22, 55, 60, 217,
3362 176, 156, 90, 43, 80, 251, 235, 128, 169, 254, 134,
3363 249, 42, 121, 118, 72, 128, 129, 232, 37, 15, 24, 221,
3364 143, 115, 131, 40, 113, 254, 19, 123, 246, 68, 166,
3365 66, 118, 142, 47, 51, 195, 242, 249, 131, 38, 66
3366 ),
3367 62 => array(
3368 0, 182, 133, 162, 126, 236, 58, 172, 163, 53, 121, 159, 2,
3369 166, 137, 234, 158, 195, 164, 77, 228, 226, 145, 91, 180,
3370 232, 23, 241, 132, 135, 206, 184, 14, 6, 66, 238, 83, 100,
3371 111, 85, 202, 91, 156, 68, 218, 57, 83, 222, 188, 25, 179,
3372 144, 169, 164, 82, 154, 103, 89, 42, 141, 175, 32, 168
3373 ),
3374 68 => array(
3375 0, 33, 79, 190, 245, 91, 221, 233, 25, 24, 6, 144,
3376 151, 121, 186, 140, 127, 45, 153, 250, 183, 70, 131,
3377 198, 17, 89, 245, 121, 51, 140, 252, 203, 82, 83, 233,
3378 152, 220, 155, 18, 230, 210, 94, 32, 200, 197, 192,
3379 194, 202, 129, 10, 237, 198, 94, 176, 36, 40, 139,
3380 201, 132, 219, 34, 56, 113, 52, 20, 34, 247, 15, 51
3381 ),
3382 );
3383 private $dmtx_log = array(
3384 0, 0, 1, 240, 2, 225, 241, 53,
3385 3, 38, 226, 133, 242, 43, 54, 210,
3386 4, 195, 39, 114, 227, 106, 134, 28,
3387 243, 140, 44, 23, 55, 118, 211, 234,
3388 5, 219, 196, 96, 40, 222, 115, 103,
3389 228, 78, 107, 125, 135, 8, 29, 162,
3390 244, 186, 141, 180, 45, 99, 24, 49,
3391 56, 13, 119, 153, 212, 199, 235, 91,
3392 6, 76, 220, 217, 197, 11, 97, 184,
3393 41, 36, 223, 253, 116, 138, 104, 193,
3394 229, 86, 79, 171, 108, 165, 126, 145,
3395 136, 34, 9, 74, 30, 32, 163, 84,
3396 245, 173, 187, 204, 142, 81, 181, 190,
3397 46, 88, 100, 159, 25, 231, 50, 207,
3398 57, 147, 14, 67, 120, 128, 154, 248,
3399 213, 167, 200, 63, 236, 110, 92, 176,
3400 7, 161, 77, 124, 221, 102, 218, 95,
3401 198, 90, 12, 152, 98, 48, 185, 179,
3402 42, 209, 37, 132, 224, 52, 254, 239,
3403 117, 233, 139, 22, 105, 27, 194, 113,
3404 230, 206, 87, 158, 80, 189, 172, 203,
3405 109, 175, 166, 62, 127, 247, 146, 66,
3406 137, 192, 35, 252, 10, 183, 75, 216,
3407 31, 83, 33, 73, 164, 144, 85, 170,
3408 246, 65, 174, 61, 188, 202, 205, 157,
3409 143, 169, 82, 72, 182, 215, 191, 251,
3410 47, 178, 89, 151, 101, 94, 160, 123,
3411 26, 112, 232, 21, 51, 238, 208, 131,
3412 58, 69, 148, 18, 15, 16, 68, 17,
3413 121, 149, 129, 19, 155, 59, 249, 70,
3414 214, 250, 168, 71, 201, 156, 64, 60,
3415 237, 130, 111, 20, 93, 122, 177, 150,
3416 );
3417 private $dmtx_exp = array(
3418 1, 2, 4, 8, 16, 32, 64, 128,
3419 45, 90, 180, 69, 138, 57, 114, 228,
3420 229, 231, 227, 235, 251, 219, 155, 27,
3421 54, 108, 216, 157, 23, 46, 92, 184,
3422 93, 186, 89, 178, 73, 146, 9, 18,
3423 36, 72, 144, 13, 26, 52, 104, 208,
3424 141, 55, 110, 220, 149, 7, 14, 28,
3425 56, 112, 224, 237, 247, 195, 171, 123,
3426 246, 193, 175, 115, 230, 225, 239, 243,
3427 203, 187, 91, 182, 65, 130, 41, 82,
3428 164, 101, 202, 185, 95, 190, 81, 162,
3429 105, 210, 137, 63, 126, 252, 213, 135,
3430 35, 70, 140, 53, 106, 212, 133, 39,
3431 78, 156, 21, 42, 84, 168, 125, 250,
3432 217, 159, 19, 38, 76, 152, 29, 58,
3433 116, 232, 253, 215, 131, 43, 86, 172,
3434 117, 234, 249, 223, 147, 11, 22, 44,
3435 88, 176, 77, 154, 25, 50, 100, 200,
3436 189, 87, 174, 113, 226, 233, 255, 211,
3437 139, 59, 118, 236, 245, 199, 163, 107,
3438 214, 129, 47, 94, 188, 85, 170, 121,
3439 242, 201, 191, 83, 166, 97, 194, 169,
3440 127, 254, 209, 143, 51, 102, 204, 181,
3441 71, 142, 49, 98, 196, 165, 103, 206,
3442 177, 79, 158, 17, 34, 68, 136, 61,
3443 122, 244, 197, 167, 99, 198, 161, 111,
3444 222, 145, 15, 30, 60, 120, 240, 205,
3445 183, 67, 134, 33, 66, 132, 37, 74,
3446 148, 5, 10, 20, 40, 80, 160, 109,
3447 218, 153, 31, 62, 124, 248, 221, 151,
3448 3, 6, 12, 24, 48, 96, 192, 173,
3449 119, 238, 241, 207, 179, 75, 150, 1,
3450 );
3451
3452 }
3453