diff --git a/docs/swagger/paths/{shortCode}_qr-code.json b/docs/swagger/paths/{shortCode}_qr-code.json index 00502ad5..43c1d38a 100644 --- a/docs/swagger/paths/{shortCode}_qr-code.json +++ b/docs/swagger/paths/{shortCode}_qr-code.json @@ -35,10 +35,7 @@ "required": false, "schema": { "type": "string", - "enum": [ - "png", - "svg" - ] + "enum": ["png", "svg"] } }, { @@ -51,6 +48,16 @@ "minimum": 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": { diff --git a/module/Core/src/Action/QrCodeAction.php b/module/Core/src/Action/QrCodeAction.php index 177d90fc..a8dee3fd 100644 --- a/module/Core/src/Action/QrCodeAction.php +++ b/module/Core/src/Action/QrCodeAction.php @@ -5,6 +5,11 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Core\Action; 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 Psr\Http\Message\ResponseInterface as Response; 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\ShortUrl\Helper\ShortUrlStringifierInterface; +use function strtoupper; +use function trim; + class QrCodeAction implements MiddlewareInterface { private const DEFAULT_SIZE = 300; @@ -46,17 +54,18 @@ class QrCodeAction implements MiddlewareInterface } $query = $request->getQueryParams(); - $qrCode = Builder::create() + $qrCodeBuilder = Builder::create() ->data($this->stringifier->stringify($shortUrl)) ->size($this->resolveSize($request, $query)) - ->margin($this->resolveMargin($query)); + ->margin($this->resolveMargin($query)) + ->errorCorrectionLevel($this->resolveErrorCorrection($query)); $format = $query['format'] ?? 'png'; 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 @@ -72,11 +81,11 @@ class QrCodeAction implements MiddlewareInterface private function resolveMargin(array $query): int { - if (! isset($query['margin'])) { + $margin = $query['margin'] ?? null; + if ($margin === null) { return 0; } - $margin = $query['margin']; $intMargin = (int) $margin; if ($margin !== (string) $intMargin) { return 0; @@ -84,4 +93,15 @@ class QrCodeAction implements MiddlewareInterface 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' + }; + } }