Skip to content

Commit

Permalink
Merge pull request #258 from sprain/round-block-size-modes
Browse files Browse the repository at this point in the history
Add mode options for roundBlockSize
  • Loading branch information
endroid authored Jul 10, 2020
2 parents 3762623 + c60537f commit c525713
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 6 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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]);
Expand Down
24 changes: 22 additions & 2 deletions src/QrCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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'];
Expand Down
66 changes: 66 additions & 0 deletions tests/QrCodeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,72 @@ public function testSetSize(): void
$this->assertTrue(imagesy($image) === $size + 2 * $margin);
}

/**
* @testdox Size and margin are handled correctly with rounded blocks
* @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
*/
Expand Down

0 comments on commit c525713

Please sign in to comment.