diff --git a/src/QRCodeReader.php b/src/QRCodeReader.php index 8e50eb1b0..41e5f323f 100644 --- a/src/QRCodeReader.php +++ b/src/QRCodeReader.php @@ -13,6 +13,7 @@ namespace chillerlan\QRCode; +use chillerlan\Settings\SettingsContainerInterface; use Imagick, InvalidArgumentException; use chillerlan\QRCode\Decoder\{Decoder, DecoderResult, GDLuminanceSource, IMagickLuminanceSource}; use function extension_loaded, file_exists, file_get_contents, imagecreatefromstring, is_file, is_readable; @@ -22,13 +23,18 @@ use function extension_loaded, file_exists, file_get_contents, imagecreatefromst */ final class QRCodeReader{ - private bool $useImagickIfAvailable; + /** + * The settings container + * + * @var \chillerlan\QRCode\QROptions|\chillerlan\Settings\SettingsContainerInterface + */ + private SettingsContainerInterface $options; /** * */ - public function __construct(bool $useImagickIfAvailable = true){ - $this->useImagickIfAvailable = $useImagickIfAvailable && extension_loaded('imagick'); + public function __construct(SettingsContainerInterface $options = null){ + $this->options = $options ?? new QROptions; } /** @@ -38,7 +44,7 @@ final class QRCodeReader{ */ private function decode($im):DecoderResult{ - $source = $this->useImagickIfAvailable + $source = $this->options->useImagickIfAvailable ? new IMagickLuminanceSource($im) : new GDLuminanceSource($im); @@ -56,7 +62,7 @@ final class QRCodeReader{ throw new InvalidArgumentException('invalid file: '.$imgFilePath); } - $im = $this->useImagickIfAvailable + $im = $this->options->useImagickIfAvailable ? new Imagick($imgFilePath) : imagecreatefromstring(file_get_contents($imgFilePath)); @@ -70,7 +76,7 @@ final class QRCodeReader{ */ public function readBlob(string $imgBlob):DecoderResult{ - if($this->useImagickIfAvailable){ + if($this->options->useImagickIfAvailable){ $im = new Imagick; $im->readImageBlob($imgBlob); } diff --git a/src/QROptions.php b/src/QROptions.php index ca7fac3d5..540efc176 100644 --- a/src/QROptions.php +++ b/src/QROptions.php @@ -45,6 +45,7 @@ use chillerlan\Settings\SettingsContainerAbstract; * @property string|null $imagickBG * @property string $fpdfMeasureUnit * @property array|null $moduleValues + * @property bool $useImagickIfAvailable */ class QROptions extends SettingsContainerAbstract{ use QROptionsTrait; diff --git a/src/QROptionsTrait.php b/src/QROptionsTrait.php index 7b68f7436..b009024ed 100644 --- a/src/QROptionsTrait.php +++ b/src/QROptionsTrait.php @@ -14,7 +14,7 @@ namespace chillerlan\QRCode; use chillerlan\QRCode\Common\EccLevel; -use function array_values, count, in_array, is_numeric, max, min, sprintf, strtolower; +use function array_values, count, extension_loaded, in_array, is_numeric, max, min, sprintf, strtolower; /** * The QRCode plug-in settings & setter functionality @@ -219,6 +219,11 @@ trait QROptionsTrait{ */ protected ?array $moduleValues = null; + /** + * use Imaagick (if available) when reading QR Codes + */ + protected bool $useImagickIfAvailable = false; + /** * clamp min/max version number */ @@ -328,4 +333,13 @@ trait QROptionsTrait{ // @todo throw or ignore silently? } + /** + * enables Imagick for the QR Code reader if the extension is available + * + * @codeCoverageIgnore + */ + protected function set_useImagickIfAvailable(bool $useImagickIfAvailable):void{ + $this->useImagickIfAvailable = $useImagickIfAvailable && extension_loaded('imagick'); + } + } diff --git a/tests/QRCodeReaderTest.php b/tests/QRCodeReaderTest.php index 4965d8599..d5230b2e4 100644 --- a/tests/QRCodeReaderTest.php +++ b/tests/QRCodeReaderTest.php @@ -12,6 +12,7 @@ namespace chillerlan\QRCodeTest; +use chillerlan\Settings\SettingsContainerInterface; use Exception; use chillerlan\QRCode\Common\{EccLevel, Mode, Version}; use chillerlan\QRCode\{QRCode, QROptions, QRCodeReader}; @@ -32,6 +33,12 @@ class QRCodeReaderTest extends TestCase{ .'They say everything looks better with odd numbers of things. But sometimes I put even numbers—just ' .'to upset the critics. We\'ll lay all these little funky little things in there. '; + private SettingsContainerInterface $options; + + protected function setUp():void{ + $this->options = new QROptions; + } + public function qrCodeProvider():array{ return [ 'helloworld' => ['hello_world.png', 'Hello world!'], @@ -55,7 +62,9 @@ class QRCodeReaderTest extends TestCase{ * @dataProvider qrCodeProvider */ public function testReaderGD(string $img, string $expected):void{ - $reader = new QRCodeReader(false); + $this->options->useImagickIfAvailable = false; + + $reader = new QRCodeReader($this->options); $this::assertSame($expected, (string)$reader->readFile(__DIR__.'/qrcodes/'.$img)); } @@ -69,7 +78,9 @@ class QRCodeReaderTest extends TestCase{ $this::markTestSkipped('imagick not installed'); } - $reader = new QRCodeReader(true); + $this->options->useImagickIfAvailable = true; + + $reader = new QRCodeReader($this->options); $this::assertSame($expected, (string)$reader->readFile(__DIR__.'/qrcodes/'.$img)); } @@ -100,16 +111,17 @@ class QRCodeReaderTest extends TestCase{ * @dataProvider dataTestProvider */ public function testReadData(Version $version, EccLevel $ecc, string $expected):void{ - $options = new QROptions; -# $options->imageTransparent = false; - $options->eccLevel = $ecc->getLevel(); - $options->version = $version->getVersionNumber(); - $options->imageBase64 = false; - $options->scale = 1; // what's interesting is that a smaller scale seems to produce fewer reader errors??? + +# $this->options->imageTransparent = false; + $this->options->eccLevel = $ecc->getLevel(); + $this->options->version = $version->getVersionNumber(); + $this->options->imageBase64 = false; + $this->options->scale = 1; // what's interesting is that a smaller scale seems to produce fewer reader errors??? + $this->options->useImagickIfAvailable = true; try{ - $imagedata = (new QRCode($options))->render($expected); - $result = (new QRCodeReader(true))->readBlob($imagedata); + $imagedata = (new QRCode($this->options))->render($expected); + $result = (new QRCodeReader($this->options))->readBlob($imagedata); } catch(Exception $e){ $this::markTestSkipped($version.$ecc.': '.$e->getMessage());