Mercurial > hg > rc1
comparison vendor/endroid/qrcode/src/QrCode.php @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
author | Charlie Root |
---|---|
date | Thu, 04 Jan 2018 15:50:29 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e000243b222 |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * (c) Jeroen van den Enden <info@endroid.nl> | |
5 * | |
6 * This source file is subject to the MIT license that is bundled | |
7 * with this source code in the file LICENSE. | |
8 */ | |
9 | |
10 namespace Endroid\QrCode; | |
11 | |
12 use Endroid\QrCode\Exceptions\DataDoesntExistsException; | |
13 use Endroid\QrCode\Exceptions\FreeTypeLibraryMissingException; | |
14 use Endroid\QrCode\Exceptions\ImageFunctionFailedException; | |
15 use Endroid\QrCode\Exceptions\VersionTooLargeException; | |
16 use Endroid\QrCode\Exceptions\ImageSizeTooLargeException; | |
17 use Endroid\QrCode\Exceptions\ImageFunctionUnknownException; | |
18 use ReflectionFunction; | |
19 | |
20 /** | |
21 * Generate QR Code. | |
22 */ | |
23 class QrCode | |
24 { | |
25 /** @const int Error Correction Level Low (7%) */ | |
26 const LEVEL_LOW = 1; | |
27 | |
28 /** @const int Error Correction Level Medium (15%) */ | |
29 const LEVEL_MEDIUM = 0; | |
30 | |
31 /** @const int Error Correction Level Quartile (25%) */ | |
32 const LEVEL_QUARTILE = 3; | |
33 | |
34 /** @const int Error Correction Level High (30%) */ | |
35 const LEVEL_HIGH = 2; | |
36 | |
37 /** @const string Image type png */ | |
38 const IMAGE_TYPE_PNG = 'png'; | |
39 | |
40 /** @const string Image type gif */ | |
41 const IMAGE_TYPE_GIF = 'gif'; | |
42 | |
43 /** @const string Image type jpeg */ | |
44 const IMAGE_TYPE_JPEG = 'jpeg'; | |
45 | |
46 /** @const string Image type wbmp */ | |
47 const IMAGE_TYPE_WBMP = 'wbmp'; | |
48 | |
49 /** @const int Horizontal label alignment to the center of image */ | |
50 const LABEL_HALIGN_CENTER = 0; | |
51 | |
52 /** @const int Horizontal label alignment to the left side of image */ | |
53 const LABEL_HALIGN_LEFT = 1; | |
54 | |
55 /** @const int Horizontal label alignment to the left border of QR Code */ | |
56 const LABEL_HALIGN_LEFT_BORDER = 2; | |
57 | |
58 /** @const int Horizontal label alignment to the left side of QR Code */ | |
59 const LABEL_HALIGN_LEFT_CODE = 3; | |
60 | |
61 /** @const int Horizontal label alignment to the right side of image */ | |
62 const LABEL_HALIGN_RIGHT = 4; | |
63 | |
64 /** @const int Horizontal label alignment to the right border of QR Code */ | |
65 const LABEL_HALIGN_RIGHT_BORDER = 5; | |
66 | |
67 /** @const int Horizontal label alignment to the right side of QR Code */ | |
68 const LABEL_HALIGN_RIGHT_CODE = 6; | |
69 | |
70 /** @const int Vertical label alignment to the top */ | |
71 const LABEL_VALIGN_TOP = 1; | |
72 | |
73 /** @const int Vertical label alignment to the top and hide border */ | |
74 const LABEL_VALIGN_TOP_NO_BORDER = 2; | |
75 | |
76 /** @const int Vertical label alignment to the middle*/ | |
77 const LABEL_VALIGN_MIDDLE = 3; | |
78 | |
79 /** @const int Vertical label alignment to the bottom */ | |
80 const LABEL_VALIGN_BOTTOM = 4; | |
81 | |
82 /** @var string */ | |
83 protected $logo = null; | |
84 | |
85 protected $logo_size = 48; | |
86 | |
87 /** @var string */ | |
88 protected $text = ''; | |
89 | |
90 /** @var int */ | |
91 protected $size = 0; | |
92 | |
93 /** @var int */ | |
94 protected $padding = 16; | |
95 | |
96 /** @var bool */ | |
97 protected $draw_quiet_zone = false; | |
98 | |
99 /** @var bool */ | |
100 protected $draw_border = false; | |
101 | |
102 /** @var array */ | |
103 protected $color_foreground = array('r' => 0, 'g' => 0, 'b' => 0, 'a' => 0); | |
104 | |
105 /** @var array */ | |
106 protected $color_background = array('r' => 255, 'g' => 255, 'b' => 255, 'a' => 0); | |
107 | |
108 /** @var string */ | |
109 protected $label = ''; | |
110 | |
111 /** @var int */ | |
112 protected $label_font_size = 16; | |
113 | |
114 /** @var string */ | |
115 protected $label_font_path = ''; | |
116 | |
117 /** @var int */ | |
118 protected $label_halign = self::LABEL_HALIGN_CENTER; | |
119 | |
120 /** @var int */ | |
121 protected $label_valign = self::LABEL_VALIGN_MIDDLE; | |
122 | |
123 /** @var resource */ | |
124 protected $image = null; | |
125 | |
126 /** @var int */ | |
127 protected $version; | |
128 | |
129 /** @var int */ | |
130 protected $error_correction = self::LEVEL_MEDIUM; | |
131 | |
132 /** @var array */ | |
133 protected $error_corrections_available = array( | |
134 self::LEVEL_LOW, | |
135 self::LEVEL_MEDIUM, | |
136 self::LEVEL_QUARTILE, | |
137 self::LEVEL_HIGH, | |
138 ); | |
139 | |
140 /** @var int */ | |
141 protected $module_size; | |
142 | |
143 /** @var string */ | |
144 protected $image_type = self::IMAGE_TYPE_PNG; | |
145 | |
146 /** @var array */ | |
147 protected $image_types_available = array( | |
148 self::IMAGE_TYPE_GIF, | |
149 self::IMAGE_TYPE_PNG, | |
150 self::IMAGE_TYPE_JPEG, | |
151 self::IMAGE_TYPE_WBMP, | |
152 ); | |
153 | |
154 /** @var string */ | |
155 protected $image_path; | |
156 | |
157 /** @var string */ | |
158 protected $path; | |
159 | |
160 /** @var int */ | |
161 protected $structure_append_n; | |
162 | |
163 /** @var int */ | |
164 protected $structure_append_m; | |
165 | |
166 /** @var int */ | |
167 protected $structure_append_parity; | |
168 | |
169 /** @var string */ | |
170 protected $structure_append_original_data; | |
171 | |
172 /** | |
173 * Class constructor. | |
174 * | |
175 * @param string $text | |
176 */ | |
177 public function __construct($text = '') | |
178 { | |
179 $this->setPath(__DIR__.'/../assets/data'); | |
180 $this->setImagePath(__DIR__.'/../assets/image'); | |
181 $this->setLabelFontPath(__DIR__.'/../assets/font/opensans.ttf'); | |
182 $this->setText($text); | |
183 } | |
184 | |
185 /** | |
186 * Set structure append. | |
187 * | |
188 * @param int $n | |
189 * @param int $m | |
190 * @param int $parity Parity | |
191 * @param string $original_data Original data | |
192 * | |
193 * @return QrCode | |
194 */ | |
195 public function setStructureAppend($n, $m, $parity, $original_data) | |
196 { | |
197 $this->structure_append_n = $n; | |
198 $this->structure_append_m = $m; | |
199 $this->structure_append_parity = $parity; | |
200 $this->structure_append_original_data = $original_data; | |
201 | |
202 return $this; | |
203 } | |
204 | |
205 /** | |
206 * Set QR Code version. | |
207 * | |
208 * @param int $version QR Code version | |
209 * | |
210 * @return QrCode | |
211 */ | |
212 public function setVersion($version) | |
213 { | |
214 if ($version <= 40 && $version >= 0) { | |
215 $this->version = $version; | |
216 } | |
217 | |
218 return $this; | |
219 } | |
220 | |
221 /** | |
222 * Return QR Code version. | |
223 * | |
224 * @return int | |
225 */ | |
226 public function getVersion() | |
227 { | |
228 return $this->version; | |
229 } | |
230 | |
231 /** | |
232 * Set QR Code error correction level. | |
233 * | |
234 * @param mixed $error_correction Error Correction Level | |
235 * | |
236 * @return QrCode | |
237 */ | |
238 public function setErrorCorrection($error_correction) | |
239 { | |
240 if (!is_numeric($error_correction)) { | |
241 $level_constant = 'Endroid\QrCode\QrCode::LEVEL_'.strtoupper($error_correction); | |
242 $error_correction = constant($level_constant); | |
243 } | |
244 | |
245 if (in_array($error_correction, $this->error_corrections_available)) { | |
246 $this->error_correction = $error_correction; | |
247 } | |
248 | |
249 return $this; | |
250 } | |
251 | |
252 /** | |
253 * Return QR Code error correction level. | |
254 * | |
255 * @return int | |
256 */ | |
257 public function getErrorCorrection() | |
258 { | |
259 return $this->error_correction; | |
260 } | |
261 | |
262 /** | |
263 * Set QR Code module size. | |
264 * | |
265 * @param int $module_size Module size | |
266 * | |
267 * @return QrCode | |
268 */ | |
269 public function setModuleSize($module_size) | |
270 { | |
271 $this->module_size = $module_size; | |
272 | |
273 return $this; | |
274 } | |
275 | |
276 /** | |
277 * Return QR Code module size. | |
278 * | |
279 * @return int | |
280 */ | |
281 public function getModuleSize() | |
282 { | |
283 return $this->module_size; | |
284 } | |
285 | |
286 /** | |
287 * Set image type for rendering. | |
288 * | |
289 * @param string $image_type Image type | |
290 * | |
291 * @return QrCode | |
292 */ | |
293 public function setImageType($image_type) | |
294 { | |
295 if (in_array($image_type, $this->image_types_available)) { | |
296 $this->image_type = $image_type; | |
297 } | |
298 | |
299 return $this; | |
300 } | |
301 | |
302 /** | |
303 * Return image type for rendering. | |
304 * | |
305 * @return string | |
306 */ | |
307 public function getImageType() | |
308 { | |
309 return $this->image_type; | |
310 } | |
311 | |
312 /** | |
313 * Set image type for rendering via extension. | |
314 * | |
315 * @param string $extension Image extension | |
316 * | |
317 * @return QrCode | |
318 */ | |
319 public function setExtension($extension) | |
320 { | |
321 if ($extension == 'jpg') { | |
322 $this->setImageType('jpeg'); | |
323 } else { | |
324 $this->setImageType($extension); | |
325 } | |
326 | |
327 return $this; | |
328 } | |
329 | |
330 /** | |
331 * Set path to the images directory. | |
332 * | |
333 * @param string $image_path Image directory | |
334 * | |
335 * @return QrCode | |
336 */ | |
337 public function setImagePath($image_path) | |
338 { | |
339 $this->image_path = $image_path; | |
340 | |
341 return $this; | |
342 } | |
343 | |
344 /** | |
345 * Return path to the images directory. | |
346 * | |
347 * @return string | |
348 */ | |
349 public function getImagePath() | |
350 { | |
351 return $this->image_path; | |
352 } | |
353 | |
354 /** | |
355 * Set path to the data directory. | |
356 * | |
357 * @param string $path Data directory | |
358 * | |
359 * @return QrCode | |
360 */ | |
361 public function setPath($path) | |
362 { | |
363 $this->path = $path; | |
364 | |
365 return $this; | |
366 } | |
367 | |
368 /** | |
369 * Return path to the data directory. | |
370 * | |
371 * @return string | |
372 */ | |
373 public function getPath() | |
374 { | |
375 return $this->path; | |
376 } | |
377 | |
378 /** | |
379 * Set logo in QR Code. | |
380 * | |
381 * @param string $logo Logo Path | |
382 * | |
383 * @throws Exceptions\DataDoesntExistsException | |
384 * | |
385 * @return QrCode | |
386 */ | |
387 public function setLogo($logo) | |
388 { | |
389 if (!file_exists($logo)) { | |
390 throw new DataDoesntExistsException("$logo file does not exist"); | |
391 } | |
392 | |
393 $this->logo = $logo; | |
394 | |
395 return $this; | |
396 } | |
397 | |
398 /** | |
399 * Set logo size in QR Code(default 48). | |
400 * | |
401 * @param int $logo_size Logo Size | |
402 * | |
403 * @return QrCode | |
404 */ | |
405 public function setLogoSize($logo_size) | |
406 { | |
407 $this->logo_size = $logo_size; | |
408 | |
409 return $this; | |
410 } | |
411 | |
412 /** | |
413 * Set text to hide in QR Code. | |
414 * | |
415 * @param string $text Text to hide | |
416 * | |
417 * @return QrCode | |
418 */ | |
419 public function setText($text) | |
420 { | |
421 $this->text = $text; | |
422 | |
423 return $this; | |
424 } | |
425 | |
426 /** | |
427 * Return text that will be hid in QR Code. | |
428 * | |
429 * @return string | |
430 */ | |
431 public function getText() | |
432 { | |
433 return $this->text; | |
434 } | |
435 | |
436 /** | |
437 * Set QR Code size (width). | |
438 * | |
439 * @param int $size Width of the QR Code | |
440 * | |
441 * @return QrCode | |
442 */ | |
443 public function setSize($size) | |
444 { | |
445 $this->size = $size; | |
446 | |
447 return $this; | |
448 } | |
449 | |
450 /** | |
451 * Return QR Code size (width). | |
452 * | |
453 * @return int | |
454 */ | |
455 public function getSize() | |
456 { | |
457 return $this->size; | |
458 } | |
459 | |
460 /** | |
461 * Set padding around the QR Code. | |
462 * | |
463 * @param int $padding Padding around QR Code | |
464 * | |
465 * @return QrCode | |
466 */ | |
467 public function setPadding($padding) | |
468 { | |
469 $this->padding = $padding; | |
470 | |
471 return $this; | |
472 } | |
473 | |
474 /** | |
475 * Return padding around the QR Code. | |
476 * | |
477 * @return int | |
478 */ | |
479 public function getPadding() | |
480 { | |
481 return $this->padding; | |
482 } | |
483 | |
484 /** | |
485 * Set draw required four-module wide margin. | |
486 * | |
487 * @param bool $draw_quiet_zone State of required four-module wide margin drawing | |
488 * | |
489 * @return QrCode | |
490 */ | |
491 public function setDrawQuietZone($draw_quiet_zone) | |
492 { | |
493 $this->draw_quiet_zone = $draw_quiet_zone; | |
494 | |
495 return $this; | |
496 } | |
497 | |
498 /** | |
499 * Return draw required four-module wide margin. | |
500 * | |
501 * @return bool | |
502 */ | |
503 public function getDrawQuietZone() | |
504 { | |
505 return $this->draw_quiet_zone; | |
506 } | |
507 | |
508 /** | |
509 * Set draw border around QR Code. | |
510 * | |
511 * @param bool $draw_border State of border drawing | |
512 * | |
513 * @return QrCode | |
514 */ | |
515 public function setDrawBorder($draw_border) | |
516 { | |
517 $this->draw_border = $draw_border; | |
518 | |
519 return $this; | |
520 } | |
521 | |
522 /** | |
523 * Return draw border around QR Code. | |
524 * | |
525 * @return bool | |
526 */ | |
527 public function getDrawBorder() | |
528 { | |
529 return $this->draw_border; | |
530 } | |
531 | |
532 /** | |
533 * Set QR Code label (text). | |
534 * | |
535 * @param int|string $label Label to print under QR code | |
536 * | |
537 * @return QrCode | |
538 */ | |
539 public function setLabel($label) | |
540 { | |
541 $this->label = $label; | |
542 | |
543 return $this; | |
544 } | |
545 | |
546 /** | |
547 * Return QR Code label (text). | |
548 * | |
549 * @return string | |
550 */ | |
551 public function getLabel() | |
552 { | |
553 return $this->label; | |
554 } | |
555 | |
556 /** | |
557 * Set QR Code label font size. | |
558 * | |
559 * @param int $label_font_size Font size of the QR code label | |
560 * | |
561 * @return QrCode | |
562 */ | |
563 public function setLabelFontSize($label_font_size) | |
564 { | |
565 $this->label_font_size = $label_font_size; | |
566 | |
567 return $this; | |
568 } | |
569 | |
570 /** | |
571 * Return QR Code label font size. | |
572 * | |
573 * @return int | |
574 */ | |
575 public function getLabelFontSize() | |
576 { | |
577 return $this->label_font_size; | |
578 } | |
579 | |
580 /** | |
581 * Set QR Code label font path. | |
582 * | |
583 * @param int $label_font_path Path to the QR Code label's TTF font file | |
584 * | |
585 * @return QrCode | |
586 */ | |
587 public function setLabelFontPath($label_font_path) | |
588 { | |
589 $this->label_font_path = $label_font_path; | |
590 | |
591 return $this; | |
592 } | |
593 | |
594 /** | |
595 * Return path to the QR Code label's TTF font file. | |
596 * | |
597 * @return string | |
598 */ | |
599 public function getLabelFontPath() | |
600 { | |
601 return $this->label_font_path; | |
602 } | |
603 | |
604 /** | |
605 * Set label horizontal alignment. | |
606 * | |
607 * @param int $label_halign Label horizontal alignment | |
608 * | |
609 * @return QrCode | |
610 */ | |
611 public function setLabelHalign($label_halign) | |
612 { | |
613 $this->label_halign = $label_halign; | |
614 | |
615 return $this; | |
616 } | |
617 | |
618 /** | |
619 * Return label horizontal alignment. | |
620 * | |
621 * @return int | |
622 */ | |
623 public function getLabelHalign() | |
624 { | |
625 return $this->label_halign; | |
626 } | |
627 | |
628 /** | |
629 * Set label vertical alignment. | |
630 * | |
631 * @param int $label_valign Label vertical alignment | |
632 * | |
633 * @return QrCode | |
634 */ | |
635 public function setLabelValign($label_valign) | |
636 { | |
637 $this->label_valign = $label_valign; | |
638 | |
639 return $this; | |
640 } | |
641 | |
642 /** | |
643 * Return label vertical alignment. | |
644 * | |
645 * @return int | |
646 */ | |
647 public function getLabelValign() | |
648 { | |
649 return $this->label_valign; | |
650 } | |
651 | |
652 /** | |
653 * Set foreground color of the QR Code. | |
654 * | |
655 * @param array $color_foreground RGB color | |
656 * | |
657 * @return QrCode | |
658 */ | |
659 public function setForegroundColor($color_foreground) | |
660 { | |
661 if (!isset($color_foreground['a'])) { | |
662 $color_foreground['a'] = 0; | |
663 } | |
664 | |
665 $this->color_foreground = $color_foreground; | |
666 | |
667 return $this; | |
668 } | |
669 | |
670 /** | |
671 * Return foreground color of the QR Code. | |
672 * | |
673 * @return array | |
674 */ | |
675 public function getForegroundColor() | |
676 { | |
677 return $this->color_foreground; | |
678 } | |
679 | |
680 /** | |
681 * Set background color of the QR Code. | |
682 * | |
683 * @param array $color_background RGB color | |
684 * | |
685 * @return QrCode | |
686 */ | |
687 public function setBackgroundColor($color_background) | |
688 { | |
689 if (!isset($color_background['a'])) { | |
690 $color_background['a'] = 0; | |
691 } | |
692 | |
693 $this->color_background = $color_background; | |
694 | |
695 return $this; | |
696 } | |
697 | |
698 /** | |
699 * Return background color of the QR Code. | |
700 * | |
701 * @return array | |
702 */ | |
703 public function getBackgroundColor() | |
704 { | |
705 return $this->color_background; | |
706 } | |
707 | |
708 /** | |
709 * Return the image resource. | |
710 * | |
711 * @return resource | |
712 */ | |
713 public function getImage() | |
714 { | |
715 if (empty($this->image)) { | |
716 $this->create(); | |
717 } | |
718 | |
719 return $this->image; | |
720 } | |
721 | |
722 /** | |
723 * Return the data URI. | |
724 * | |
725 * @return string | |
726 */ | |
727 public function getDataUri() | |
728 { | |
729 if (empty($this->image)) { | |
730 $this->create(); | |
731 } | |
732 | |
733 ob_start(); | |
734 call_user_func('image'.$this->image_type, $this->image); | |
735 $contents = ob_get_clean(); | |
736 | |
737 return 'data:image/'.$this->image_type.';base64,'.base64_encode($contents); | |
738 } | |
739 | |
740 /** | |
741 * Render the QR Code then save it to given file name. | |
742 * | |
743 * @param string $filename File name of the QR Code | |
744 * | |
745 * @return QrCode | |
746 */ | |
747 public function save($filename) | |
748 { | |
749 $this->render($filename); | |
750 | |
751 return $this; | |
752 } | |
753 | |
754 /** | |
755 * Render the QR Code then save it to given file name or | |
756 * output it to the browser when file name omitted. | |
757 * | |
758 * @param null|string $filename File name of the QR Code | |
759 * @param null|string $format Format of the file (png, jpeg, jpg, gif, wbmp) | |
760 * | |
761 * @throws ImageFunctionUnknownException | |
762 * @throws ImageFunctionFailedException | |
763 * | |
764 * @return QrCode | |
765 */ | |
766 public function render($filename = null, $format = 'png') | |
767 { | |
768 $this->create(); | |
769 | |
770 if ($format == 'jpg') { | |
771 $format = 'jpeg'; | |
772 } | |
773 | |
774 if (!in_array($format, $this->image_types_available)) { | |
775 $format = $this->image_type; | |
776 } | |
777 | |
778 if (!function_exists('image'.$format)) { | |
779 throw new ImageFunctionUnknownException('QRCode: function image'.$format.' does not exists.'); | |
780 } | |
781 | |
782 if ($filename === null) { | |
783 $success = call_user_func('image'.$format, $this->image); | |
784 } else { | |
785 $success = call_user_func_array('image'.$format, array($this->image, $filename)); | |
786 } | |
787 | |
788 if ($success === false) { | |
789 throw new ImageFunctionFailedException('QRCode: function image'.$format.' failed.'); | |
790 } | |
791 | |
792 return $this; | |
793 } | |
794 | |
795 /** | |
796 * Create QR Code and return its content. | |
797 * | |
798 * @param string|null $format Image type (gif, png, wbmp, jpeg) | |
799 * | |
800 * @throws ImageFunctionUnknownException | |
801 * @throws ImageFunctionFailedException | |
802 * | |
803 * @return string | |
804 */ | |
805 public function get($format = null) | |
806 { | |
807 $this->create(); | |
808 | |
809 if ($format == 'jpg') { | |
810 $format = 'jpeg'; | |
811 } | |
812 | |
813 if (!in_array($format, $this->image_types_available)) { | |
814 $format = $this->image_type; | |
815 } | |
816 | |
817 if (!function_exists('image'.$format)) { | |
818 throw new ImageFunctionUnknownException('QRCode: function image'.$format.' does not exists.'); | |
819 } | |
820 | |
821 ob_start(); | |
822 $success = call_user_func('image'.$format, $this->image); | |
823 | |
824 if ($success === false) { | |
825 throw new ImageFunctionFailedException('QRCode: function image'.$format.' failed.'); | |
826 } | |
827 | |
828 $content = ob_get_clean(); | |
829 | |
830 return $content; | |
831 } | |
832 | |
833 /** | |
834 * Create the image. | |
835 * | |
836 * @throws Exceptions\DataDoesntExistsException | |
837 * @throws Exceptions\VersionTooLargeException | |
838 * @throws Exceptions\ImageSizeTooLargeException | |
839 * @throws \OverflowException | |
840 */ | |
841 public function create() | |
842 { | |
843 $image_path = $this->image_path; | |
844 $path = $this->path; | |
845 | |
846 $version_ul = 40; | |
847 | |
848 $qrcode_data_string = $this->text;//Previously from $_GET["d"]; | |
849 | |
850 $qrcode_error_correct = $this->error_correction;//Previously from $_GET["e"]; | |
851 $qrcode_module_size = $this->module_size;//Previously from $_GET["s"]; | |
852 $qrcode_version = $this->version;//Previously from $_GET["v"]; | |
853 $qrcode_image_type = $this->image_type;//Previously from $_GET["t"]; | |
854 | |
855 $qrcode_structureappend_n = $this->structure_append_n;//Previously from $_GET["n"]; | |
856 $qrcode_structureappend_m = $this->structure_append_m;//Previously from $_GET["m"]; | |
857 $qrcode_structureappend_parity = $this->structure_append_parity;//Previously from $_GET["p"]; | |
858 $qrcode_structureappend_originaldata = $this->structure_append_original_data;//Previously from $_GET["o"]; | |
859 | |
860 if ($qrcode_module_size > 0) { | |
861 } else { | |
862 if ($qrcode_image_type == 'jpeg') { | |
863 $qrcode_module_size = 8; | |
864 } else { | |
865 $qrcode_module_size = 4; | |
866 } | |
867 } | |
868 $data_length = strlen($qrcode_data_string); | |
869 if ($data_length <= 0) { | |
870 throw new DataDoesntExistsException('QRCode: data does not exist.'); | |
871 } | |
872 $data_counter = 0; | |
873 if ($qrcode_structureappend_n > 1 | |
874 && $qrcode_structureappend_n <= 16 | |
875 && $qrcode_structureappend_m > 0 | |
876 && $qrcode_structureappend_m <= 16) { | |
877 $data_value[0] = 3; | |
878 $data_bits[0] = 4; | |
879 | |
880 $data_value[1] = $qrcode_structureappend_m - 1; | |
881 $data_bits[1] = 4; | |
882 | |
883 $data_value[2] = $qrcode_structureappend_n - 1; | |
884 $data_bits[2] = 4; | |
885 | |
886 $originaldata_length = strlen($qrcode_structureappend_originaldata); | |
887 if ($originaldata_length > 1) { | |
888 $qrcode_structureappend_parity = 0; | |
889 $i = 0; | |
890 while ($i < $originaldata_length) { | |
891 $qrcode_structureappend_parity = ($qrcode_structureappend_parity ^ ord(substr($qrcode_structureappend_originaldata, $i, 1))); | |
892 ++$i; | |
893 } | |
894 } | |
895 | |
896 $data_value[3] = $qrcode_structureappend_parity; | |
897 $data_bits[3] = 8; | |
898 | |
899 $data_counter = 4; | |
900 } | |
901 | |
902 $data_bits[$data_counter] = 4; | |
903 | |
904 /* --- determine encode mode */ | |
905 | |
906 if (preg_match('/[^0-9]/', $qrcode_data_string) != 0) { | |
907 if (preg_match("/[^0-9A-Z \$\*\%\+\.\/\:\-]/", $qrcode_data_string) != 0) { | |
908 /* --- 8bit byte mode */ | |
909 | |
910 $codeword_num_plus = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
911 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |
912 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, ); | |
913 | |
914 $data_value[$data_counter] = 4; | |
915 ++$data_counter; | |
916 $data_value[$data_counter] = $data_length; | |
917 $data_bits[$data_counter] = 8; /* #version 1-9 */ | |
918 $codeword_num_counter_value = $data_counter; | |
919 | |
920 ++$data_counter; | |
921 $i = 0; | |
922 while ($i < $data_length) { | |
923 $data_value[$data_counter] = ord(substr($qrcode_data_string, $i, 1)); | |
924 $data_bits[$data_counter] = 8; | |
925 ++$data_counter; | |
926 ++$i; | |
927 } | |
928 } else { | |
929 /* ---- alphanumeric mode */ | |
930 | |
931 $codeword_num_plus = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
932 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
933 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ); | |
934 | |
935 $data_value[$data_counter] = 2; | |
936 ++$data_counter; | |
937 $data_value[$data_counter] = $data_length; | |
938 $data_bits[$data_counter] = 9; /* #version 1-9 */ | |
939 $codeword_num_counter_value = $data_counter; | |
940 | |
941 $alphanumeric_character_hash = array('0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, | |
942 '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, | |
943 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, 'L' => 21, 'M' => 22, 'N' => 23, | |
944 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, 'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31, | |
945 'W' => 32, 'X' => 33, 'Y' => 34, 'Z' => 35, ' ' => 36, '$' => 37, '%' => 38, '*' => 39, | |
946 '+' => 40, '-' => 41, '.' => 42, '/' => 43, ':' => 44, ); | |
947 | |
948 $i = 0; | |
949 ++$data_counter; | |
950 while ($i < $data_length) { | |
951 if (($i % 2) == 0) { | |
952 $data_value[$data_counter] = $alphanumeric_character_hash[substr($qrcode_data_string, $i, 1)]; | |
953 $data_bits[$data_counter] = 6; | |
954 } else { | |
955 $data_value[$data_counter] = $data_value[$data_counter] * 45 + $alphanumeric_character_hash[substr($qrcode_data_string, $i, 1)]; | |
956 $data_bits[$data_counter] = 11; | |
957 ++$data_counter; | |
958 } | |
959 ++$i; | |
960 } | |
961 } | |
962 } else { | |
963 /* ---- numeric mode */ | |
964 | |
965 $codeword_num_plus = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
966 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
967 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ); | |
968 | |
969 $data_value[$data_counter] = 1; | |
970 ++$data_counter; | |
971 $data_value[$data_counter] = $data_length; | |
972 $data_bits[$data_counter] = 10; /* #version 1-9 */ | |
973 $codeword_num_counter_value = $data_counter; | |
974 | |
975 $i = 0; | |
976 ++$data_counter; | |
977 while ($i < $data_length) { | |
978 if (($i % 3) == 0) { | |
979 $data_value[$data_counter] = substr($qrcode_data_string, $i, 1); | |
980 $data_bits[$data_counter] = 4; | |
981 } else { | |
982 $data_value[$data_counter] = $data_value[$data_counter] * 10 + substr($qrcode_data_string, $i, 1); | |
983 if (($i % 3) == 1) { | |
984 $data_bits[$data_counter] = 7; | |
985 } else { | |
986 $data_bits[$data_counter] = 10; | |
987 ++$data_counter; | |
988 } | |
989 } | |
990 ++$i; | |
991 } | |
992 } | |
993 if (array_key_exists($data_counter, $data_bits) && $data_bits[$data_counter] > 0) { | |
994 ++$data_counter; | |
995 } | |
996 $i = 0; | |
997 $total_data_bits = 0; | |
998 while ($i < $data_counter) { | |
999 $total_data_bits += $data_bits[$i]; | |
1000 ++$i; | |
1001 } | |
1002 | |
1003 $ecc_character_hash = array('L' => '1', | |
1004 'l' => '1', | |
1005 'M' => '0', | |
1006 'm' => '0', | |
1007 'Q' => '3', | |
1008 'q' => '3', | |
1009 'H' => '2', | |
1010 'h' => '2', ); | |
1011 | |
1012 if (!is_numeric($qrcode_error_correct)) { | |
1013 $ec = @$ecc_character_hash[$qrcode_error_correct]; | |
1014 } else { | |
1015 $ec = $qrcode_error_correct; | |
1016 } | |
1017 | |
1018 if (!$ec) { | |
1019 $ec = 0; | |
1020 } | |
1021 | |
1022 $max_data_bits = 0; | |
1023 | |
1024 $max_data_bits_array = array( | |
1025 0, 128, 224, 352, 512, 688, 864, 992, 1232, 1456, 1728, | |
1026 2032, 2320, 2672, 2920, 3320, 3624, 4056, 4504, 5016, 5352, | |
1027 5712, 6256, 6880, 7312, 8000, 8496, 9024, 9544, 10136, 10984, | |
1028 11640, 12328, 13048, 13800, 14496, 15312, 15936, 16816, 17728, 18672, | |
1029 | |
1030 152, 272, 440, 640, 864, 1088, 1248, 1552, 1856, 2192, | |
1031 2592, 2960, 3424, 3688, 4184, 4712, 5176, 5768, 6360, 6888, | |
1032 7456, 8048, 8752, 9392, 10208, 10960, 11744, 12248, 13048, 13880, | |
1033 14744, 15640, 16568, 17528, 18448, 19472, 20528, 21616, 22496, 23648, | |
1034 | |
1035 72, 128, 208, 288, 368, 480, 528, 688, 800, 976, | |
1036 1120, 1264, 1440, 1576, 1784, 2024, 2264, 2504, 2728, 3080, | |
1037 3248, 3536, 3712, 4112, 4304, 4768, 5024, 5288, 5608, 5960, | |
1038 6344, 6760, 7208, 7688, 7888, 8432, 8768, 9136, 9776, 10208, | |
1039 | |
1040 104, 176, 272, 384, 496, 608, 704, 880, 1056, 1232, | |
1041 1440, 1648, 1952, 2088, 2360, 2600, 2936, 3176, 3560, 3880, | |
1042 4096, 4544, 4912, 5312, 5744, 6032, 6464, 6968, 7288, 7880, | |
1043 8264, 8920, 9368, 9848, 10288, 10832, 11408, 12016, 12656, 13328, | |
1044 ); | |
1045 if (!is_numeric($qrcode_version)) { | |
1046 $qrcode_version = 0; | |
1047 } | |
1048 if (!$qrcode_version) { | |
1049 /* #--- auto version select */ | |
1050 $i = 1 + 40 * $ec; | |
1051 $j = $i + 39; | |
1052 $qrcode_version = 1; | |
1053 while ($i <= $j) { | |
1054 if (($max_data_bits_array[$i]) >= $total_data_bits + $codeword_num_plus[$qrcode_version]) { | |
1055 $max_data_bits = $max_data_bits_array[$i]; | |
1056 break; | |
1057 } | |
1058 ++$i; | |
1059 ++$qrcode_version; | |
1060 } | |
1061 } else { | |
1062 $max_data_bits = $max_data_bits_array[$qrcode_version + 40 * $ec]; | |
1063 } | |
1064 if ($qrcode_version > $version_ul) { | |
1065 throw new VersionTooLargeException('QRCode : version too large'); | |
1066 } | |
1067 | |
1068 $total_data_bits += $codeword_num_plus[$qrcode_version]; | |
1069 $data_bits[$codeword_num_counter_value] += $codeword_num_plus[$qrcode_version]; | |
1070 | |
1071 $max_codewords_array = array(0, 26, 44, 70, 100, 134, 172, 196, 242, | |
1072 292, 346, 404, 466, 532, 581, 655, 733, 815, 901, 991, 1085, 1156, | |
1073 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051, 2185, 2323, 2465, | |
1074 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706, ); | |
1075 | |
1076 $max_codewords = $max_codewords_array[$qrcode_version]; | |
1077 $max_modules_1side = 17 + ($qrcode_version << 2); | |
1078 | |
1079 $matrix_remain_bit = array(0, 0, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, | |
1080 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, ); | |
1081 | |
1082 /* ---- read version ECC data file */ | |
1083 | |
1084 $byte_num = $matrix_remain_bit[$qrcode_version] + ($max_codewords << 3); | |
1085 $filename = $path.'/qrv'.$qrcode_version.'_'.$ec.'.dat'; | |
1086 $fp1 = fopen($filename, 'rb'); | |
1087 $matx = fread($fp1, $byte_num); | |
1088 $maty = fread($fp1, $byte_num); | |
1089 $masks = fread($fp1, $byte_num); | |
1090 $fi_x = fread($fp1, 15); | |
1091 $fi_y = fread($fp1, 15); | |
1092 $rs_ecc_codewords = ord(fread($fp1, 1)); | |
1093 $rso = fread($fp1, 128); | |
1094 fclose($fp1); | |
1095 | |
1096 $matrix_x_array = unpack('C*', $matx); | |
1097 $matrix_y_array = unpack('C*', $maty); | |
1098 $mask_array = unpack('C*', $masks); | |
1099 | |
1100 $rs_block_order = unpack('C*', $rso); | |
1101 | |
1102 $format_information_x2 = unpack('C*', $fi_x); | |
1103 $format_information_y2 = unpack('C*', $fi_y); | |
1104 | |
1105 $format_information_x1 = array(0, 1, 2, 3, 4, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8); | |
1106 $format_information_y1 = array(8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 4, 3, 2, 1, 0); | |
1107 | |
1108 $max_data_codewords = ($max_data_bits >> 3); | |
1109 | |
1110 $filename = $path.'/rsc'.$rs_ecc_codewords.'.dat'; | |
1111 $fp0 = fopen($filename, 'rb'); | |
1112 $i = 0; | |
1113 $rs_cal_table_array = array(); | |
1114 while ($i < 256) { | |
1115 $rs_cal_table_array[$i] = fread($fp0, $rs_ecc_codewords); | |
1116 ++$i; | |
1117 } | |
1118 fclose($fp0); | |
1119 | |
1120 /* --- set terminator */ | |
1121 | |
1122 if ($total_data_bits <= $max_data_bits - 4) { | |
1123 $data_value[$data_counter] = 0; | |
1124 $data_bits[$data_counter] = 4; | |
1125 } else { | |
1126 if ($total_data_bits < $max_data_bits) { | |
1127 $data_value[$data_counter] = 0; | |
1128 $data_bits[$data_counter] = $max_data_bits - $total_data_bits; | |
1129 } else { | |
1130 if ($total_data_bits > $max_data_bits) { | |
1131 throw new \OverflowException('QRCode: overflow error'); | |
1132 } | |
1133 } | |
1134 } | |
1135 | |
1136 /* ----divide data by 8bit */ | |
1137 | |
1138 $i = 0; | |
1139 $codewords_counter = 0; | |
1140 $codewords[0] = 0; | |
1141 $remaining_bits = 8; | |
1142 | |
1143 while ($i <= $data_counter) { | |
1144 $buffer = @$data_value[$i]; | |
1145 $buffer_bits = @$data_bits[$i]; | |
1146 | |
1147 $flag = 1; | |
1148 while ($flag) { | |
1149 if ($remaining_bits > $buffer_bits) { | |
1150 $codewords[$codewords_counter] = ((@$codewords[$codewords_counter] << $buffer_bits) | $buffer); | |
1151 $remaining_bits -= $buffer_bits; | |
1152 $flag = 0; | |
1153 } else { | |
1154 $buffer_bits -= $remaining_bits; | |
1155 $codewords[$codewords_counter] = (($codewords[$codewords_counter] << $remaining_bits) | ($buffer >> $buffer_bits)); | |
1156 | |
1157 if ($buffer_bits == 0) { | |
1158 $flag = 0; | |
1159 } else { | |
1160 $buffer = ($buffer & ((1 << $buffer_bits) - 1)); | |
1161 $flag = 1; | |
1162 } | |
1163 | |
1164 ++$codewords_counter; | |
1165 if ($codewords_counter < $max_data_codewords - 1) { | |
1166 $codewords[$codewords_counter] = 0; | |
1167 } | |
1168 $remaining_bits = 8; | |
1169 } | |
1170 } | |
1171 ++$i; | |
1172 } | |
1173 if ($remaining_bits != 8) { | |
1174 $codewords[$codewords_counter] = $codewords[$codewords_counter] << $remaining_bits; | |
1175 } else { | |
1176 --$codewords_counter; | |
1177 } | |
1178 | |
1179 /* ---- set padding character */ | |
1180 | |
1181 if ($codewords_counter < $max_data_codewords - 1) { | |
1182 $flag = 1; | |
1183 while ($codewords_counter < $max_data_codewords - 1) { | |
1184 ++$codewords_counter; | |
1185 if ($flag == 1) { | |
1186 $codewords[$codewords_counter] = 236; | |
1187 } else { | |
1188 $codewords[$codewords_counter] = 17; | |
1189 } | |
1190 $flag = $flag * (-1); | |
1191 } | |
1192 } | |
1193 | |
1194 /* ---- RS-ECC prepare */ | |
1195 | |
1196 $i = 0; | |
1197 $j = 0; | |
1198 $rs_block_number = 0; | |
1199 $rs_temp[0] = ''; | |
1200 | |
1201 while ($i < $max_data_codewords) { | |
1202 $rs_temp[$rs_block_number] .= chr($codewords[$i]); | |
1203 ++$j; | |
1204 | |
1205 if ($j >= $rs_block_order[$rs_block_number + 1] - $rs_ecc_codewords) { | |
1206 $j = 0; | |
1207 ++$rs_block_number; | |
1208 $rs_temp[$rs_block_number] = ''; | |
1209 } | |
1210 ++$i; | |
1211 } | |
1212 | |
1213 /* | |
1214 # | |
1215 # RS-ECC main | |
1216 # | |
1217 */ | |
1218 | |
1219 $rs_block_number = 0; | |
1220 $rs_block_order_num = count($rs_block_order); | |
1221 | |
1222 while ($rs_block_number < $rs_block_order_num) { | |
1223 $rs_codewords = $rs_block_order[$rs_block_number + 1]; | |
1224 $rs_data_codewords = $rs_codewords - $rs_ecc_codewords; | |
1225 | |
1226 $rstemp = $rs_temp[$rs_block_number].str_repeat(chr(0), $rs_ecc_codewords); | |
1227 $padding_data = str_repeat(chr(0), $rs_data_codewords); | |
1228 | |
1229 $j = $rs_data_codewords; | |
1230 while ($j > 0) { | |
1231 $first = ord(substr($rstemp, 0, 1)); | |
1232 | |
1233 if ($first) { | |
1234 $left_chr = substr($rstemp, 1); | |
1235 $cal = $rs_cal_table_array[$first].$padding_data; | |
1236 $rstemp = $left_chr ^ $cal; | |
1237 } else { | |
1238 $rstemp = substr($rstemp, 1); | |
1239 } | |
1240 | |
1241 --$j; | |
1242 } | |
1243 | |
1244 $codewords = array_merge($codewords, unpack('C*', $rstemp)); | |
1245 | |
1246 ++$rs_block_number; | |
1247 } | |
1248 | |
1249 /* ---- flash matrix */ | |
1250 $matrix_content = array(); | |
1251 $i = 0; | |
1252 while ($i < $max_modules_1side) { | |
1253 $j = 0; | |
1254 while ($j < $max_modules_1side) { | |
1255 $matrix_content[$j][$i] = 0; | |
1256 ++$j; | |
1257 } | |
1258 ++$i; | |
1259 } | |
1260 | |
1261 /* --- attach data */ | |
1262 | |
1263 $i = 0; | |
1264 while ($i < $max_codewords) { | |
1265 $codeword_i = $codewords[$i]; | |
1266 $j = 8; | |
1267 while ($j >= 1) { | |
1268 $codeword_bits_number = ($i << 3) + $j; | |
1269 $matrix_content[ $matrix_x_array[$codeword_bits_number] ][ $matrix_y_array[$codeword_bits_number] ] = ((255 * ($codeword_i & 1)) ^ $mask_array[$codeword_bits_number]); | |
1270 $codeword_i = $codeword_i >> 1; | |
1271 --$j; | |
1272 } | |
1273 ++$i; | |
1274 } | |
1275 | |
1276 $matrix_remain = $matrix_remain_bit[$qrcode_version]; | |
1277 while ($matrix_remain) { | |
1278 $remain_bit_temp = $matrix_remain + ($max_codewords << 3); | |
1279 $matrix_content[ $matrix_x_array[$remain_bit_temp] ][ $matrix_y_array[$remain_bit_temp] ] = (255 ^ $mask_array[$remain_bit_temp]); | |
1280 --$matrix_remain; | |
1281 } | |
1282 | |
1283 #--- mask select | |
1284 | |
1285 $min_demerit_score = 0; | |
1286 $hor_master = ''; | |
1287 $ver_master = ''; | |
1288 $k = 0; | |
1289 while ($k < $max_modules_1side) { | |
1290 $l = 0; | |
1291 while ($l < $max_modules_1side) { | |
1292 $hor_master = $hor_master.chr($matrix_content[$l][$k]); | |
1293 $ver_master = $ver_master.chr($matrix_content[$k][$l]); | |
1294 ++$l; | |
1295 } | |
1296 ++$k; | |
1297 } | |
1298 $i = 0; | |
1299 $all_matrix = $max_modules_1side * $max_modules_1side; | |
1300 $mask_number = 0; | |
1301 while ($i < 8) { | |
1302 $demerit_n1 = 0; | |
1303 $ptn_temp = array(); | |
1304 $bit = 1 << $i; | |
1305 $bit_r = (~$bit) & 255; | |
1306 $bit_mask = str_repeat(chr($bit), $all_matrix); | |
1307 $hor = $hor_master & $bit_mask; | |
1308 $ver = $ver_master & $bit_mask; | |
1309 | |
1310 $ver_shift1 = $ver.str_repeat(chr(170), $max_modules_1side); | |
1311 $ver_shift2 = str_repeat(chr(170), $max_modules_1side).$ver; | |
1312 $ver_shift1_0 = $ver.str_repeat(chr(0), $max_modules_1side); | |
1313 $ver_shift2_0 = str_repeat(chr(0), $max_modules_1side).$ver; | |
1314 $ver_or = chunk_split(~($ver_shift1 | $ver_shift2), $max_modules_1side, chr(170)); | |
1315 $ver_and = chunk_split(~($ver_shift1_0 & $ver_shift2_0), $max_modules_1side, chr(170)); | |
1316 | |
1317 $hor = chunk_split(~$hor, $max_modules_1side, chr(170)); | |
1318 $ver = chunk_split(~$ver, $max_modules_1side, chr(170)); | |
1319 $hor = $hor.chr(170).$ver; | |
1320 | |
1321 $n1_search = '/'.str_repeat(chr(255), 5).'+|'.str_repeat(chr($bit_r), 5).'+/'; | |
1322 $n3_search = chr($bit_r).chr(255).chr($bit_r).chr($bit_r).chr($bit_r).chr(255).chr($bit_r); | |
1323 | |
1324 $demerit_n3 = substr_count($hor, $n3_search) * 40; | |
1325 $demerit_n4 = floor(abs(((100 * (substr_count($ver, chr($bit_r)) / ($byte_num))) - 50) / 5)) * 10; | |
1326 | |
1327 $n2_search1 = '/'.chr($bit_r).chr($bit_r).'+/'; | |
1328 $n2_search2 = '/'.chr(255).chr(255).'+/'; | |
1329 $demerit_n2 = 0; | |
1330 preg_match_all($n2_search1, $ver_and, $ptn_temp); | |
1331 foreach ($ptn_temp[0] as $str_temp) { | |
1332 $demerit_n2 += (strlen($str_temp) - 1); | |
1333 } | |
1334 $ptn_temp = array(); | |
1335 preg_match_all($n2_search2, $ver_or, $ptn_temp); | |
1336 foreach ($ptn_temp[0] as $str_temp) { | |
1337 $demerit_n2 += (strlen($str_temp) - 1); | |
1338 } | |
1339 $demerit_n2 *= 3; | |
1340 | |
1341 $ptn_temp = array(); | |
1342 | |
1343 preg_match_all($n1_search, $hor, $ptn_temp); | |
1344 foreach ($ptn_temp[0] as $str_temp) { | |
1345 $demerit_n1 += (strlen($str_temp) - 2); | |
1346 } | |
1347 | |
1348 $demerit_score = $demerit_n1 + $demerit_n2 + $demerit_n3 + $demerit_n4; | |
1349 | |
1350 if ($demerit_score <= $min_demerit_score || $i == 0) { | |
1351 $mask_number = $i; | |
1352 $min_demerit_score = $demerit_score; | |
1353 } | |
1354 | |
1355 ++$i; | |
1356 } | |
1357 | |
1358 $mask_content = 1 << $mask_number; | |
1359 | |
1360 # --- format information | |
1361 | |
1362 $format_information_value = (($ec << 3) | $mask_number); | |
1363 $format_information_array = array('101010000010010', '101000100100101', | |
1364 '101111001111100', '101101101001011', '100010111111001', '100000011001110', | |
1365 '100111110010111', '100101010100000', '111011111000100', '111001011110011', | |
1366 '111110110101010', '111100010011101', '110011000101111', '110001100011000', | |
1367 '110110001000001', '110100101110110', '001011010001001', '001001110111110', | |
1368 '001110011100111', '001100111010000', '000011101100010', '000001001010101', | |
1369 '000110100001100', '000100000111011', '011010101011111', '011000001101000', | |
1370 '011111100110001', '011101000000110', '010010010110100', '010000110000011', | |
1371 '010111011011010', '010101111101101', ); | |
1372 $i = 0; | |
1373 while ($i < 15) { | |
1374 $content = substr($format_information_array[$format_information_value], $i, 1); | |
1375 | |
1376 $matrix_content[$format_information_x1[$i]][$format_information_y1[$i]] = $content * 255; | |
1377 $matrix_content[$format_information_x2[$i + 1]][$format_information_y2[$i + 1]] = $content * 255; | |
1378 ++$i; | |
1379 } | |
1380 | |
1381 $mib = $max_modules_1side + 8; | |
1382 | |
1383 if ($this->size == 0) { | |
1384 $this->size = $mib * $qrcode_module_size; | |
1385 if ($this->size > 1480) { | |
1386 throw new ImageSizeTooLargeException('QRCode: image size too large'); | |
1387 } | |
1388 } | |
1389 | |
1390 $image_width = $this->size + $this->padding * 2; | |
1391 $image_height = $this->size + $this->padding * 2; | |
1392 | |
1393 if (!empty($this->label)) { | |
1394 if (!function_exists('imagettfbbox')) { | |
1395 throw new FreeTypeLibraryMissingException('QRCode: missing function "imagettfbbox". Did you install the FreeType library?'); | |
1396 } | |
1397 $font_box = imagettfbbox($this->label_font_size, 0, $this->label_font_path, $this->label); | |
1398 $label_width = (int) $font_box[2] - (int) $font_box[0]; | |
1399 $label_height = (int) $font_box[0] - (int) $font_box[7]; | |
1400 | |
1401 if ($this->label_valign == self::LABEL_VALIGN_MIDDLE) { | |
1402 $image_height += $label_height + $this->padding; | |
1403 } else { | |
1404 $image_height += $label_height; | |
1405 } | |
1406 } | |
1407 | |
1408 $output_image = imagecreate($image_width, $image_height); | |
1409 imagecolorallocate($output_image, 255, 255, 255); | |
1410 | |
1411 $image_path = $image_path.'/qrv'.$qrcode_version.'.png'; | |
1412 | |
1413 $base_image = imagecreatefrompng($image_path); | |
1414 $code_size = $this->size; | |
1415 $module_size = function ($size = 1) use ($code_size, $base_image) { | |
1416 return round($code_size / imagesx($base_image) * $size); | |
1417 }; | |
1418 | |
1419 $col[1] = imagecolorallocate($base_image, 0, 0, 0); | |
1420 $col[0] = imagecolorallocate($base_image, 255, 255, 255); | |
1421 | |
1422 $i = 4; | |
1423 $mxe = 4 + $max_modules_1side; | |
1424 $ii = 0; | |
1425 while ($i < $mxe) { | |
1426 $j = 4; | |
1427 $jj = 0; | |
1428 while ($j < $mxe) { | |
1429 if ($matrix_content[$ii][$jj] & $mask_content) { | |
1430 imagesetpixel($base_image, $i, $j, $col[1]); | |
1431 } | |
1432 ++$j; | |
1433 ++$jj; | |
1434 } | |
1435 ++$i; | |
1436 ++$ii; | |
1437 } | |
1438 | |
1439 if ($this->draw_quiet_zone == true) { | |
1440 imagecopyresampled($output_image, $base_image, $this->padding, $this->padding, 0, 0, $this->size, $this->size, $mib, $mib); | |
1441 } else { | |
1442 imagecopyresampled($output_image, $base_image, $this->padding, $this->padding, 4, 4, $this->size, $this->size, $mib - 8, $mib - 8); | |
1443 } | |
1444 | |
1445 if ($this->draw_border == true) { | |
1446 $border_width = $this->padding; | |
1447 $border_height = $this->size + $this->padding - 1; | |
1448 $border_color = imagecolorallocate($output_image, 0, 0, 0); | |
1449 imagerectangle($output_image, $border_width, $border_width, $border_height, $border_height, $border_color); | |
1450 } | |
1451 | |
1452 if (!empty($this->label)) { | |
1453 // Label horizontal alignment | |
1454 switch ($this->label_halign) { | |
1455 case self::LABEL_HALIGN_LEFT: | |
1456 $font_x = 0; | |
1457 break; | |
1458 | |
1459 case self::LABEL_HALIGN_LEFT_BORDER: | |
1460 $font_x = $this->padding; | |
1461 break; | |
1462 | |
1463 case self::LABEL_HALIGN_LEFT_CODE: | |
1464 if ($this->draw_quiet_zone == true) { | |
1465 $font_x = $this->padding + $module_size(4); | |
1466 } else { | |
1467 $font_x = $this->padding; | |
1468 } | |
1469 break; | |
1470 | |
1471 case self::LABEL_HALIGN_RIGHT: | |
1472 $font_x = $this->size + ($this->padding * 2) - $label_width; | |
1473 break; | |
1474 | |
1475 case self::LABEL_HALIGN_RIGHT_BORDER: | |
1476 $font_x = $this->size + $this->padding - $label_width; | |
1477 break; | |
1478 | |
1479 case self::LABEL_HALIGN_RIGHT_CODE: | |
1480 if ($this->draw_quiet_zone == true) { | |
1481 $font_x = $this->size + $this->padding - $label_width - $module_size(4); | |
1482 } else { | |
1483 $font_x = $this->size + $this->padding - $label_width; | |
1484 } | |
1485 break; | |
1486 | |
1487 default: | |
1488 $font_x = floor($image_width - $label_width) / 2; | |
1489 } | |
1490 | |
1491 // Label vertical alignment | |
1492 switch ($this->label_valign) { | |
1493 case self::LABEL_VALIGN_TOP_NO_BORDER: | |
1494 $font_y = $image_height - $this->padding - 1; | |
1495 break; | |
1496 | |
1497 case self::LABEL_VALIGN_BOTTOM: | |
1498 $font_y = $image_height; | |
1499 break; | |
1500 | |
1501 default: | |
1502 $font_y = $image_height - $this->padding; | |
1503 } | |
1504 | |
1505 $label_bg_x1 = $font_x - $module_size(2); | |
1506 $label_bg_y1 = $font_y - $label_height; | |
1507 $label_bg_x2 = $font_x + $label_width + $module_size(2); | |
1508 $label_bg_y2 = $font_y; | |
1509 | |
1510 $color = imagecolorallocate($output_image, 0, 0, 0); | |
1511 $label_bg_color = imagecolorallocate($output_image, 255, 255, 255); | |
1512 | |
1513 imagefilledrectangle($output_image, $label_bg_x1, $label_bg_y1, $label_bg_x2, $label_bg_y2, $label_bg_color); | |
1514 imagettftext($output_image, $this->label_font_size, 0, $font_x, $font_y, $color, $this->label_font_path, $this->label); | |
1515 } | |
1516 | |
1517 $imagecolorset_function = new ReflectionFunction('imagecolorset'); | |
1518 $allow_alpha = $imagecolorset_function->getNumberOfParameters() == 6; | |
1519 | |
1520 if ($this->color_background != null) { | |
1521 $index = imagecolorclosest($output_image, 255, 255, 255); | |
1522 if ($allow_alpha) { | |
1523 imagecolorset($output_image, $index, $this->color_background['r'], $this->color_background['g'], $this->color_background['b'], $this->color_background['a']); | |
1524 } else { | |
1525 imagecolorset($output_image, $index, $this->color_background['r'], $this->color_background['g'], $this->color_background['b']); | |
1526 } | |
1527 } | |
1528 | |
1529 if ($this->color_foreground != null) { | |
1530 $index = imagecolorclosest($output_image, 0, 0, 0); | |
1531 if ($allow_alpha) { | |
1532 imagecolorset($output_image, $index, $this->color_foreground['r'], $this->color_foreground['g'], $this->color_foreground['b'], $this->color_foreground['a']); | |
1533 } else { | |
1534 imagecolorset($output_image, $index, $this->color_foreground['r'], $this->color_foreground['g'], $this->color_foreground['b']); | |
1535 } | |
1536 } | |
1537 | |
1538 if (!empty($this->logo)) { | |
1539 $output_image_org = $output_image; | |
1540 $output_image = imagecreatetruecolor($image_width, $image_height); | |
1541 imagecopy($output_image, $output_image_org, 0, 0, 0, 0, $image_width, $image_height); | |
1542 | |
1543 $logo_image = call_user_func('imagecreatefrom'.$this->image_type, $this->logo); | |
1544 if (!$logo_image) { | |
1545 throw new ImageFunctionFailedException('imagecreatefrom'.$this->image_type.' '.$this->logo.' failed'); | |
1546 } | |
1547 $src_w = imagesx($logo_image); | |
1548 $src_h = imagesy($logo_image); | |
1549 | |
1550 $dst_x = ($image_width - $this->logo_size) / 2; | |
1551 $dst_y = ($this->size + $this->padding * 2 - $this->logo_size) / 2; | |
1552 | |
1553 $successful = imagecopyresampled($output_image, $logo_image, $dst_x, $dst_y, 0, 0, $this->logo_size, $this->logo_size, $src_w, $src_h); | |
1554 if (!$successful) { | |
1555 throw new ImageFunctionFailedException('add logo [image'.$this->format.'] failed.'); | |
1556 } | |
1557 imagedestroy($logo_image); | |
1558 } | |
1559 $this->image = $output_image; | |
1560 } | |
1561 } |