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 }