@@ -32,7 +32,8 @@ class QRMatrix{
32
32
public const M_FORMAT = 0x0e ;
33
33
public const M_VERSION = 0x10 ;
34
34
public const M_QUIETZONE = 0x12 ;
35
- # public const M_LOGO = 0x14; // @todo
35
+ public const M_LOGO = 0x14 ;
36
+ public const M_FINDER_DOT = 0x16 ;
36
37
37
38
public const M_TEST = 0xff ;
38
39
@@ -352,12 +353,18 @@ public function setFinderPattern():QRMatrix{
352
353
foreach ($ pos as $ c ){
353
354
for ($ y = 0 ; $ y < 7 ; $ y ++){
354
355
for ($ x = 0 ; $ x < 7 ; $ x ++){
355
- $ this ->set (
356
- $ c [0 ] + $ y ,
357
- $ c [1 ] + $ x ,
358
- !(($ x > 0 && $ x < 6 && ($ y === 1 || $ y === 5 )) || ($ y > 0 && $ y < 6 && ($ x === 1 || $ x === 5 ))),
359
- $ this ::M_FINDER
360
- );
356
+ // outer (dark) 7*7 square
357
+ if ($ x === 0 || $ x === 6 || $ y === 0 || $ y === 6 ){
358
+ $ this ->set ($ c [0 ] + $ y , $ c [1 ] + $ x , true , $ this ::M_FINDER );
359
+ }
360
+ // inner (light) 5*5 square
361
+ elseif ($ x === 1 || $ x === 5 || $ y === 1 || $ y === 5 ){
362
+ $ this ->set ($ c [0 ] + $ y , $ c [1 ] + $ x , false , $ this ::M_FINDER );
363
+ }
364
+ // 3*3 dot
365
+ else {
366
+ $ this ->set ($ c [0 ] + $ y , $ c [1 ] + $ x , true , $ this ::M_FINDER_DOT );
367
+ }
361
368
}
362
369
}
363
370
}
@@ -551,6 +558,82 @@ public function setQuietZone(int $size = null):QRMatrix{
551
558
return $ this ;
552
559
}
553
560
561
+ /**
562
+ * Clears a space of $width * $height in order to add a logo or text.
563
+ *
564
+ * Additionally, the logo space can be positioned within the QR Code - respecting the main functional patterns -
565
+ * using $startX and $startY. If either of these are null, the logo space will be centered in that direction.
566
+ * ECC level "H" (30%) is required.
567
+ *
568
+ * Please note that adding a logo space minimizes the error correction capacity of the QR Code and
569
+ * created images may become unreadable, especially when printed with a chance to receive damage.
570
+ * Please test thoroughly before using this feature in production.
571
+ *
572
+ * This method should be called from within an output module (after the matrix has been filled with data).
573
+ * Note that there is no restiction on how many times this method could be called on the same matrix instance.
574
+ *
575
+ * @link https://github.com/chillerlan/php-qrcode/issues/52
576
+ *
577
+ * @param int $width
578
+ * @param int $height
579
+ * @param int|null $startX
580
+ * @param int|null $startY
581
+ *
582
+ * @return \chillerlan\QRCode\Data\QRMatrix
583
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
584
+ */
585
+ public function setLogoSpace (int $ width , int $ height , int $ startX = null , int $ startY = null ):QRMatrix {
586
+
587
+ // for logos we operate in ECC H (30%) only
588
+ if ($ this ->eclevel !== 0b10 ){
589
+ throw new QRCodeDataException ('ECC level "H" required to add logo space ' );
590
+ }
591
+
592
+ // we need uneven sizes, adjust if needed
593
+ if (($ width % 2 ) === 0 ){
594
+ $ width ++;
595
+ }
596
+
597
+ if (($ height % 2 ) === 0 ){
598
+ $ height ++;
599
+ }
600
+
601
+ // $this->moduleCount includes the quiet zone (if created), we need the QR size here
602
+ $ length = $ this ->version * 4 + 17 ;
603
+
604
+ // throw if the logo space exceeds the maximum error correction capacity
605
+ if ($ width * $ height > floor ($ length * $ length * 0.2 )){
606
+ throw new QRCodeDataException ('logo space exceeds the maximum error correction capacity ' );
607
+ }
608
+
609
+ // quiet zone size
610
+ $ qz = ($ this ->moduleCount - $ length ) / 2 ;
611
+ // skip quiet zone and the first 9 rows/columns (finder-, mode-, version- and timing patterns)
612
+ $ start = $ qz + 9 ;
613
+ // skip quiet zone
614
+ $ end = $ this ->moduleCount - $ qz ;
615
+
616
+ // determine start coordinates
617
+ $ startX = ($ startX !== null ? $ startX : ($ length - $ width ) / 2 ) + $ qz ;
618
+ $ startY = ($ startY !== null ? $ startY : ($ length - $ height ) / 2 ) + $ qz ;
619
+
620
+ // clear the space
621
+ foreach ($ this ->matrix as $ y => $ row ){
622
+ foreach ($ row as $ x => $ val ){
623
+ // out of bounds, skip
624
+ if ($ x < $ start || $ y < $ start ||$ x >= $ end || $ y >= $ end ){
625
+ continue ;
626
+ }
627
+ // a match
628
+ if ($ x >= $ startX && $ x < ($ startX + $ width ) && $ y >= $ startY && $ y < ($ startY + $ height )){
629
+ $ this ->set ($ x , $ y , false , $ this ::M_LOGO );
630
+ }
631
+ }
632
+ }
633
+
634
+ return $ this ;
635
+ }
636
+
554
637
/**
555
638
* Maps the binary $data array from QRDataInterface::maskECC() on the matrix, using $maskPattern
556
639
*
0 commit comments