aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/chillerlan/php-qrcode/src/Output/QRImagick.php')
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QRImagick.php206
1 files changed, 161 insertions, 45 deletions
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php b/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php
index 49516d30e..214311a93 100644
--- a/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php
+++ b/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php
@@ -2,9 +2,7 @@
/**
* Class QRImagick
*
- * @filesource QRImagick.php
* @created 04.07.2018
- * @package chillerlan\QRCode\Output
* @author smiley <smiley@chillerlan.net>
* @copyright 2018 smiley
* @license MIT
@@ -15,51 +13,98 @@
namespace chillerlan\QRCode\Output;
use chillerlan\QRCode\Data\QRMatrix;
-use chillerlan\QRCode\QRCodeException;
use chillerlan\Settings\SettingsContainerInterface;
-use Imagick, ImagickDraw, ImagickPixel;
-
-use function extension_loaded, is_string;
+use finfo, Imagick, ImagickDraw, ImagickPixel;
+use function extension_loaded, in_array, is_string, max, min, preg_match, strlen;
+use const FILEINFO_MIME_TYPE;
/**
* ImageMagick output module (requires ext-imagick)
*
- * @see http://php.net/manual/book.imagick.php
- * @see http://phpimagick.com
+ * @see https://php.net/manual/book.imagick.php
+ * @see https://phpimagick.com
*/
class QRImagick extends QROutputAbstract{
+ /**
+ * The main image instance
+ */
protected Imagick $imagick;
/**
+ * The main draw instance
+ */
+ protected ImagickDraw $imagickDraw;
+
+ /**
+ * The allocated background color
+ */
+ protected ImagickPixel $backgroundColor;
+
+ /**
* @inheritDoc
+ *
+ * @throws \chillerlan\QRCode\Output\QRCodeOutputException
*/
public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){
- if(!extension_loaded('imagick')){
- throw new QRCodeException('ext-imagick not loaded'); // @codeCoverageIgnore
+ foreach(['fileinfo', 'imagick'] as $ext){
+ if(!extension_loaded($ext)){
+ throw new QRCodeOutputException(sprintf('ext-%s not loaded', $ext)); // @codeCoverageIgnore
+ }
}
parent::__construct($options, $matrix);
}
/**
+ * note: we're not necessarily validating the several values, just checking the general syntax
+ *
+ * @see https://www.php.net/manual/imagickpixel.construct.php
* @inheritDoc
*/
- protected function setModuleValues():void{
+ public static function moduleValueIsValid($value):bool{
- foreach($this::DEFAULT_MODULE_VALUES as $type => $defaultValue){
- $v = $this->options->moduleValues[$type] ?? null;
+ if(!is_string($value)){
+ return false;
+ }
- if(!is_string($v)){
- $this->moduleValues[$type] = $defaultValue
- ? new ImagickPixel($this->options->markupDark)
- : new ImagickPixel($this->options->markupLight);
- }
- else{
- $this->moduleValues[$type] = new ImagickPixel($v);
- }
+ $value = trim($value);
+
+ // hex notation
+ // #rgb(a)
+ // #rrggbb(aa)
+ // #rrrrggggbbbb(aaaa)
+ // ...
+ if(preg_match('/^#[a-f\d]+$/i', $value) && in_array((strlen($value) - 1), [3, 4, 6, 8, 9, 12, 16, 24, 32], true)){
+ return true;
+ }
+
+ // css (-like) func(...values)
+ if(preg_match('#^(graya?|hs(b|la?)|rgba?)\([\d .,%]+\)$#i', $value)){
+ return true;
}
+
+ // predefined css color
+ if(preg_match('/^[a-z]+$/i', $value)){
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function prepareModuleValue($value):ImagickPixel{
+ return new ImagickPixel($value);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getDefaultModuleValue(bool $isDark):ImagickPixel{
+ return $this->prepareModuleValue(($isDark) ? '#000' : '#fff');
}
/**
@@ -67,18 +112,14 @@ class QRImagick extends QROutputAbstract{
*
* @return string|\Imagick
*/
- public function dump(string $file = null){
- $file ??= $this->options->cachefile;
- $this->imagick = new Imagick;
-
- $this->imagick->newImage(
- $this->length,
- $this->length,
- new ImagickPixel($this->options->imagickBG ?? 'transparent'),
- $this->options->imagickFormat
- );
+ public function dump(?string $file = null){
+ $this->setBgColor();
+
+ $this->imagick = $this->createImage();
$this->drawImage();
+ // set transparency color after all operations
+ $this->setTransparencyColor();
if($this->options->returnResource){
return $this->imagick;
@@ -86,34 +127,109 @@ class QRImagick extends QROutputAbstract{
$imageData = $this->imagick->getImageBlob();
- if($file !== null){
- $this->saveToFile($imageData, $file);
+ $this->imagick->destroy();
+
+ $this->saveToFile($imageData, $file);
+
+ if($this->options->outputBase64){
+ $imageData = $this->toBase64DataURI($imageData, (new finfo(FILEINFO_MIME_TYPE))->buffer($imageData));
}
return $imageData;
}
/**
+ * Sets the background color
+ */
+ protected function setBgColor():void{
+
+ if($this::moduleValueIsValid($this->options->bgColor)){
+ $this->backgroundColor = $this->prepareModuleValue($this->options->bgColor);
+
+ return;
+ }
+
+ $this->backgroundColor = $this->prepareModuleValue('white');
+ }
+
+ /**
+ * Creates a new Imagick instance
+ */
+ protected function createImage():Imagick{
+ $imagick = new Imagick;
+ [$width, $height] = $this->getOutputDimensions();
+
+ $imagick->newImage($width, $height, $this->backgroundColor, $this->options->imagickFormat);
+
+ if($this->options->quality > -1){
+ $imagick->setImageCompressionQuality(max(0, min(100, $this->options->quality)));
+ }
+
+ return $imagick;
+ }
+
+ /**
+ * Sets the transparency color
+ */
+ protected function setTransparencyColor():void{
+
+ if(!$this->options->imageTransparent){
+ return;
+ }
+
+ $transparencyColor = $this->backgroundColor;
+
+ if($this::moduleValueIsValid($this->options->transparencyColor)){
+ $transparencyColor = $this->prepareModuleValue($this->options->transparencyColor);
+ }
+
+ $this->imagick->transparentPaintImage($transparencyColor, 0.0, 10, false);
+ }
+
+ /**
* Creates the QR image via ImagickDraw
*/
protected function drawImage():void{
- $draw = new ImagickDraw;
+ $this->imagickDraw = new ImagickDraw;
+ $this->imagickDraw->setStrokeWidth(0);
- foreach($this->matrix->matrix() as $y => $row){
+ foreach($this->matrix->getMatrix() as $y => $row){
foreach($row as $x => $M_TYPE){
- $draw->setStrokeColor($this->moduleValues[$M_TYPE]);
- $draw->setFillColor($this->moduleValues[$M_TYPE]);
- $draw->rectangle(
- $x * $this->scale,
- $y * $this->scale,
- ($x + 1) * $this->scale,
- ($y + 1) * $this->scale
- );
-
+ $this->module($x, $y, $M_TYPE);
}
}
- $this->imagick->drawImage($draw);
+ $this->imagick->drawImage($this->imagickDraw);
+ }
+
+ /**
+ * draws a single pixel at the given position
+ */
+ protected function module(int $x, int $y, int $M_TYPE):void{
+
+ if(!$this->drawLightModules && !$this->matrix->isDark($M_TYPE)){
+ return;
+ }
+
+ $this->imagickDraw->setFillColor($this->getModuleValue($M_TYPE));
+
+ if($this->drawCircularModules && !$this->matrix->checkTypeIn($x, $y, $this->keepAsSquare)){
+ $this->imagickDraw->circle(
+ (($x + 0.5) * $this->scale),
+ (($y + 0.5) * $this->scale),
+ (($x + 0.5 + $this->circleRadius) * $this->scale),
+ (($y + 0.5) * $this->scale)
+ );
+
+ return;
+ }
+
+ $this->imagickDraw->rectangle(
+ ($x * $this->scale),
+ ($y * $this->scale),
+ ((($x + 1) * $this->scale) - 1),
+ ((($y + 1) * $this->scale) - 1)
+ );
}
}