Added suport for error correction level to QR codes

This commit is contained in:
Alejandro Celaya 2021-07-13 13:22:50 +02:00
parent 32f483c333
commit 5a2350bac1
2 changed files with 37 additions and 10 deletions

View File

@ -35,10 +35,7 @@
"required": false, "required": false,
"schema": { "schema": {
"type": "string", "type": "string",
"enum": [ "enum": ["png", "svg"]
"png",
"svg"
]
} }
}, },
{ {
@ -51,6 +48,16 @@
"minimum": 0, "minimum": 0,
"default": 0 "default": 0
} }
},
{
"name": "errorCorrection",
"in": "query",
"description": "The error correction level to apply to the the QR code: **[L]**ow, **[M]**edium, **[Q]**uartile or **[H]**igh. See [docs](https://www.qrcode.com/en/about/error_correction.html).",
"required": false,
"schema": {
"type": "string",
"enum": ["L", "M", "Q", "H"]
}
} }
], ],
"responses": { "responses": {

View File

@ -5,6 +5,11 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Action; namespace Shlinkio\Shlink\Core\Action;
use Endroid\QrCode\Builder\Builder; use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelInterface;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelLow;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelMedium;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelQuartile;
use Endroid\QrCode\Writer\SvgWriter; use Endroid\QrCode\Writer\SvgWriter;
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
@ -18,6 +23,9 @@ use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface; use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface; use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
use function strtoupper;
use function trim;
class QrCodeAction implements MiddlewareInterface class QrCodeAction implements MiddlewareInterface
{ {
private const DEFAULT_SIZE = 300; private const DEFAULT_SIZE = 300;
@ -46,17 +54,18 @@ class QrCodeAction implements MiddlewareInterface
} }
$query = $request->getQueryParams(); $query = $request->getQueryParams();
$qrCode = Builder::create() $qrCodeBuilder = Builder::create()
->data($this->stringifier->stringify($shortUrl)) ->data($this->stringifier->stringify($shortUrl))
->size($this->resolveSize($request, $query)) ->size($this->resolveSize($request, $query))
->margin($this->resolveMargin($query)); ->margin($this->resolveMargin($query))
->errorCorrectionLevel($this->resolveErrorCorrection($query));
$format = $query['format'] ?? 'png'; $format = $query['format'] ?? 'png';
if ($format === 'svg') { if ($format === 'svg') {
$qrCode->writer(new SvgWriter()); $qrCodeBuilder->writer(new SvgWriter());
} }
return new QrCodeResponse($qrCode->build()); return new QrCodeResponse($qrCodeBuilder->build());
} }
private function resolveSize(Request $request, array $query): int private function resolveSize(Request $request, array $query): int
@ -72,11 +81,11 @@ class QrCodeAction implements MiddlewareInterface
private function resolveMargin(array $query): int private function resolveMargin(array $query): int
{ {
if (! isset($query['margin'])) { $margin = $query['margin'] ?? null;
if ($margin === null) {
return 0; return 0;
} }
$margin = $query['margin'];
$intMargin = (int) $margin; $intMargin = (int) $margin;
if ($margin !== (string) $intMargin) { if ($margin !== (string) $intMargin) {
return 0; return 0;
@ -84,4 +93,15 @@ class QrCodeAction implements MiddlewareInterface
return $intMargin < 0 ? 0 : $intMargin; return $intMargin < 0 ? 0 : $intMargin;
} }
private function resolveErrorCorrection(array $query): ErrorCorrectionLevelInterface
{
$errorCorrectionLevel = strtoupper(trim($query['errorCorrection'] ?? ''));
return match ($errorCorrectionLevel) {
'H' => new ErrorCorrectionLevelHigh(),
'Q' => new ErrorCorrectionLevelQuartile(),
'M' => new ErrorCorrectionLevelMedium(),
default => new ErrorCorrectionLevelLow(), // 'L'
};
}
} }