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