Skip to content

Commit c525713

Browse files
authored
Merge pull request #258 from sprain/round-block-size-modes
Add mode options for roundBlockSize
2 parents 3762623 + c60537f commit c525713

File tree

3 files changed

+94
-6
lines changed

3 files changed

+94
-6
lines changed

README.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use Endroid\QrCode\Response\QrCodeResponse;
4545
// Create a basic QR code
4646
$qrCode = new QrCode('Life is too short to be generating QR codes');
4747
$qrCode->setSize(300);
48+
$qrCode->setMargin(10);
4849

4950
// Set advanced options
5051
$qrCode->setWriterByName('png');
@@ -57,10 +58,11 @@ $qrCode->setLogoPath(__DIR__.'/../assets/images/symfony.png');
5758
$qrCode->setLogoSize(150, 200);
5859
$qrCode->setValidateResult(false);
5960

60-
// Apply a margin and round block sizes to improve readability
61-
// Please note that rounding block sizes can result in additional margin
62-
$qrCode->setRoundBlockSize(true);
63-
$qrCode->setMargin(10);
61+
// Round block sizes to improve readability and make the blocks sharper in pixel based outputs (like png).
62+
// There are three approaches:
63+
$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)
64+
$qrCode->setRoundBlockSize(true, QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE); // The size of the qr code and the final image is enlarged, if necessary
65+
$qrCode->setRoundBlockSize(true, QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK); // The size of the qr code and the final image is shrinked, if necessary
6466

6567
// Set additional writer options (SvgWriter example)
6668
$qrCode->setWriterOptions(['exclude_xml_declaration' => true]);

src/QrCode.php

+22-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ class QrCode implements QrCodeInterface
2020
{
2121
const LABEL_FONT_PATH_DEFAULT = __DIR__.'/../assets/fonts/noto_sans.otf';
2222

23+
const ROUND_BLOCK_SIZE_MODE_MARGIN = 'margin';
24+
const ROUND_BLOCK_SIZE_MODE_SHRINK = 'shrink';
25+
const ROUND_BLOCK_SIZE_MODE_ENLARGE = 'enlarge';
26+
2327
private $text;
2428

2529
/** @var int */
@@ -50,6 +54,9 @@ class QrCode implements QrCodeInterface
5054
/** @var bool */
5155
private $roundBlockSize = true;
5256

57+
/** @var string */
58+
private $roundBlockSizeMode = self::ROUND_BLOCK_SIZE_MODE_MARGIN;
59+
5360
private $errorCorrectionLevel;
5461

5562
/** @var string */
@@ -178,9 +185,10 @@ public function getEncoding(): string
178185
return $this->encoding;
179186
}
180187

181-
public function setRoundBlockSize(bool $roundBlockSize): void
188+
public function setRoundBlockSize(bool $roundBlockSize, string $mode = self::ROUND_BLOCK_SIZE_MODE_MARGIN): void
182189
{
183190
$this->roundBlockSize = $roundBlockSize;
191+
$this->roundBlockSizeMode = $mode;
184192
}
185193

186194
public function getRoundBlockSize(): bool
@@ -422,7 +430,19 @@ public function getData(): array
422430
$data['block_count'] = count($matrix[0]);
423431
$data['block_size'] = $this->size / $data['block_count'];
424432
if ($this->roundBlockSize) {
425-
$data['block_size'] = intval(floor($data['block_size']));
433+
switch($this->roundBlockSizeMode) {
434+
case self::ROUND_BLOCK_SIZE_MODE_ENLARGE:
435+
$data['block_size'] = intval(ceil($data['block_size']));
436+
$this->size = $data['block_size'] * $data['block_count'];
437+
break;
438+
case self::ROUND_BLOCK_SIZE_MODE_SHRINK:
439+
$data['block_size'] = intval(floor($data['block_size']));
440+
$this->size = $data['block_size'] * $data['block_count'];
441+
break;
442+
case self::ROUND_BLOCK_SIZE_MODE_MARGIN:
443+
default:
444+
$data['block_size'] = intval(floor($data['block_size']));
445+
}
426446
}
427447
$data['inner_width'] = $data['block_size'] * $data['block_count'];
428448
$data['inner_height'] = $data['block_size'] * $data['block_count'];

tests/QrCodeTest.php

+66
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,72 @@ public function testSetSize(): void
147147
$this->assertTrue(imagesy($image) === $size + 2 * $margin);
148148
}
149149

150+
/**
151+
* @testdox Size and margin are handled correctly with rounded blocks
152+
* @dataProvider roundedSizeProvider
153+
*/
154+
public function testSetSizeRounded($size, $margin, $round, $mode, $expectedSize): void
155+
{
156+
$qrCode = new QrCode('QR Code contents with some length to have some data');
157+
$qrCode->setRoundBlockSize($round, $mode);
158+
$qrCode->setSize($size);
159+
$qrCode->setMargin($margin);
160+
161+
$pngData = $qrCode->writeString();
162+
$image = imagecreatefromstring($pngData);
163+
164+
$this->assertTrue(imagesx($image) === $expectedSize);
165+
$this->assertTrue(imagesy($image) === $expectedSize);
166+
}
167+
168+
public function roundedSizeProvider()
169+
{
170+
return [
171+
[
172+
'size' => 400,
173+
'margin' => 0,
174+
'round' => true,
175+
'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE,
176+
'expectedSize' => 406
177+
],
178+
[
179+
'size' => 400,
180+
'margin' => 5,
181+
'round' => true,
182+
'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_ENLARGE,
183+
'expectedSize' => 416
184+
],
185+
[
186+
'size' => 400,
187+
'margin' => 0,
188+
'round' => true,
189+
'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN,
190+
'expectedSize' => 400
191+
],
192+
[
193+
'size' => 400,
194+
'margin' => 5,
195+
'round' => true,
196+
'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_MARGIN,
197+
'expectedSize' => 410
198+
],
199+
[
200+
'size' => 400,
201+
'margin' => 0,
202+
'round' => true,
203+
'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK,
204+
'expectedSize' => 377
205+
],
206+
[
207+
'size' => 400,
208+
'margin' => 5,
209+
'round' => true,
210+
'mode' => QrCode::ROUND_BLOCK_SIZE_MODE_SHRINK,
211+
'expectedSize' => 387
212+
],
213+
];
214+
}
215+
150216
/**
151217
* @testdox Label can be added and QR code is still readable
152218
*/

0 commit comments

Comments
 (0)