From 1b6fdfac6cf049553cc5ad77e8416669d97748fe Mon Sep 17 00:00:00 2001 From: Manuel Reinhard Date: Sun, 28 Jun 2020 15:19:15 +0200 Subject: [PATCH 1/2] Add mode options for roundBlockSize --- README.md | 10 ++++--- src/QrCode.php | 24 ++++++++++++++-- tests/QrCodeTest.php | 66 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4976633..f089d03 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ use Endroid\QrCode\Response\QrCodeResponse; // Create a basic QR code $qrCode = new QrCode('Life is too short to be generating QR codes'); $qrCode->setSize(300); +$qrCode->setMargin(10); // Set advanced options $qrCode->setWriterByName('png'); @@ -57,10 +58,11 @@ $qrCode->setLogoPath(__DIR__.'/../assets/images/symfony.png'); $qrCode->setLogoSize(150, 200); $qrCode->setValidateResult(false); -// Apply a margin and round block sizes to improve readability -// Please note that rounding block sizes can result in additional margin -$qrCode->setRoundBlockSize(true); -$qrCode->setMargin(10); +// Round block sizes to improve readability and make the blocks sharper in pixel based outputs (like png). +// There are three approaches: +$qrCode->setRoundBlockSize(true, QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN); // The size of the qr code is shrinked, if necessary, but the size of the final image remains unchanged due to additional margin being added (default) +$qrCode->setRoundBlockSize(true, QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE); // The size of the qr code and the final image is enlarged, if necessary +$qrCode->setRoundBlockSize(true, QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK); // The size of the qr code and the final image is shrinked, if necessary // Set additional writer options (SvgWriter example) $qrCode->setWriterOptions(['exclude_xml_declaration' => true]); diff --git a/src/QrCode.php b/src/QrCode.php index 088c0a5..b249f03 100644 --- a/src/QrCode.php +++ b/src/QrCode.php @@ -20,6 +20,10 @@ class QrCode implements QrCodeInterface { const LABEL_FONT_PATH_DEFAULT = __DIR__.'/../assets/fonts/noto_sans.otf'; + const ROUND_BLOCK_SIZE_MODE_MARGIN = 'margin'; + const ROUND_BLOCK_SIZE_MODE_SHRINK = 'shrink'; + const ROUND_BLOCK_SIZE_MODE_ENLARGE = 'enlarge'; + private $text; /** @var int */ @@ -50,6 +54,9 @@ class QrCode implements QrCodeInterface /** @var bool */ private $roundBlockSize = true; + /** @var string */ + private $roundBlockSizeMode = self::ROUND_BLOCK_SIZE_MODE_MARGIN; + private $errorCorrectionLevel; /** @var string */ @@ -178,9 +185,10 @@ public function getEncoding(): string return $this->encoding; } - public function setRoundBlockSize(bool $roundBlockSize): void + public function setRoundBlockSize(bool $roundBlockSize, string $mode = self::ROUND_BLOCK_SIZE_MODE_MARGIN): void { $this->roundBlockSize = $roundBlockSize; + $this->roundBlockSizeMode = $mode; } public function getRoundBlockSize(): bool @@ -422,7 +430,19 @@ public function getData(): array $data['block_count'] = count($matrix[0]); $data['block_size'] = $this->size / $data['block_count']; if ($this->roundBlockSize) { - $data['block_size'] = intval(floor($data['block_size'])); + switch($this->roundBlockSizeMode) { + case self::ROUND_BLOCK_SIZE_MODE_ENLARGE: + $data['block_size'] = intval(ceil($data['block_size'])); + $this->size = $data['block_size'] * $data['block_count']; + break; + case self::ROUND_BLOCK_SIZE_MODE_SHRINK: + $data['block_size'] = intval(floor($data['block_size'])); + $this->size = $data['block_size'] * $data['block_count']; + break; + case self::ROUND_BLOCK_SIZE_MODE_MARGIN: + default: + $data['block_size'] = intval(floor($data['block_size'])); + } } $data['inner_width'] = $data['block_size'] * $data['block_count']; $data['inner_height'] = $data['block_size'] * $data['block_count']; diff --git a/tests/QrCodeTest.php b/tests/QrCodeTest.php index 6b4c001..7392b18 100644 --- a/tests/QrCodeTest.php +++ b/tests/QrCodeTest.php @@ -147,6 +147,72 @@ public function testSetSize(): void $this->assertTrue(imagesy($image) === $size + 2 * $margin); } + /** + * @testdox Size and margin are handled correctly + * @dataProvider roundedSizeProvider + */ + public function testSetSizeRounded($size, $margin, $round, $mode, $expectedSize): void + { + $qrCode = new QrCode('QR Code contents with some length to have some data'); + $qrCode->setRoundBlockSize($round, $mode); + $qrCode->setSize($size); + $qrCode->setMargin($margin); + + $pngData = $qrCode->writeString(); + $image = imagecreatefromstring($pngData); + + $this->assertTrue(imagesx($image) === $expectedSize); + $this->assertTrue(imagesy($image) === $expectedSize); + } + + public function roundedSizeProvider() + { + return [ + [ + 'size' => 400, + 'margin' => 0, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE, + 'expectedSize' => 406 + ], + [ + 'size' => 400, + 'margin' => 5, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE, + 'expectedSize' => 416 + ], + [ + 'size' => 400, + 'margin' => 0, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN, + 'expectedSize' => 400 + ], + [ + 'size' => 400, + 'margin' => 5, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN, + 'expectedSize' => 410 + ], + [ + 'size' => 400, + 'margin' => 0, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK, + 'expectedSize' => 377 + ], + [ + 'size' => 400, + 'margin' => 5, + 'round' => true, + 'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK, + 'expectedSize' => 387 + ], + ]; + } + /** * @testdox Label can be added and QR code is still readable */ From c60537fd996483c81487670c01c1b80215d956b1 Mon Sep 17 00:00:00 2001 From: Manuel Reinhard Date: Sun, 28 Jun 2020 15:27:25 +0200 Subject: [PATCH 2/2] Fix comment in tests --- tests/QrCodeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/QrCodeTest.php b/tests/QrCodeTest.php index 7392b18..67da0a7 100644 --- a/tests/QrCodeTest.php +++ b/tests/QrCodeTest.php @@ -148,7 +148,7 @@ public function testSetSize(): void } /** - * @testdox Size and margin are handled correctly + * @testdox Size and margin are handled correctly with rounded blocks * @dataProvider roundedSizeProvider */ public function testSetSizeRounded($size, $margin, $round, $mode, $expectedSize): void