diff --git a/examples/imagick.php b/examples/imagick.php new file mode 100644 index 000000000..7f1b42724 --- /dev/null +++ b/examples/imagick.php @@ -0,0 +1,60 @@ + + * @copyright 2017 Smiley + * @license MIT + */ + +namespace chillerlan\QRCodeExamples; + +use chillerlan\QRCode\{QRCode, QROptions}; + +require_once __DIR__.'/../vendor/autoload.php'; + +$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s'; + +$options = new QROptions([ + 'version' => 7, + 'outputType' => QRCode::OUTPUT_IMAGICK, + 'eccLevel' => QRCode::ECC_L, + 'scale' => 5, + 'imageBase64' => false, + 'moduleValues' => [ + // finder + 1536 => '#A71111', // dark (true) + 6 => '#FFBFBF', // light (false) + // alignment + 2560 => '#A70364', + 10 => '#FFC9C9', + // timing + 3072 => '#98005D', + 12 => '#FFB8E9', + // format + 3584 => '#003804', + 14 => '#00FB12', + // version + 4096 => '#650098', + 16 => '#E0B8FF', + // data + 1024 => '#4A6000', + 4 => '#ECF9BE', + // darkmodule + 512 => '#080063', + // separator + 8 => '#DDDDDD', + // quietzone + 18 => '#DDDDDD', + ], +]); + +header('Content-type: image/png'); + +echo (new QRCode($options))->render($data); + + + + + diff --git a/src/Output/QRImagick.php b/src/Output/QRImagick.php new file mode 100644 index 000000000..259963b7d --- /dev/null +++ b/src/Output/QRImagick.php @@ -0,0 +1,97 @@ + + * @copyright 2018 smiley + * @license MIT + */ + +namespace chillerlan\QRCode\Output; + +use Imagick, ImagickDraw, ImagickPixel; + +/** + * ImageMagick output module + * requires ext-imagick + * @link http://php.net/manual/book.imagick.php + * @link http://phpimagick.com + */ +class QRImagick extends QROutputAbstract{ + + /** + * @return void + */ + protected function setModuleValues():void{ + + foreach($this::DEFAULT_MODULE_VALUES as $type => $defaultValue){ + $v = $this->options->moduleValues[$type] ?? null; + + 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); + } + } + } + + /** + * @param string|null $file + * + * @return string + * @throws \chillerlan\QRCode\Output\QRCodeOutputException + */ + public function dump(string $file = null):string{ + $file = $file ?? $this->options->cachefile; + $imagick = new Imagick; + + $imagick->newImage( + $this->length, + $this->length, + new ImagickPixel($this->options->imagickBG ?? 'transparent'), + $this->options->imagickFormat + ); + + $imageData = $this->drawImage($imagick); + + if($file !== null){ + $this->saveToFile($imageData, $file); + } + + return $imageData; + } + + /** + * @param \Imagick $imagick + * + * @return string + */ + protected function drawImage(Imagick $imagick):string{ + $draw = new ImagickDraw; + + foreach($this->matrix->matrix() 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 + ); + + } + } + + $imagick->drawImage($draw); + + return (string)$imagick; + } + +} diff --git a/src/QRCode.php b/src/QRCode.php index 8664f1eea..fd44a4713 100755 --- a/src/QRCode.php +++ b/src/QRCode.php @@ -16,7 +16,7 @@ use chillerlan\QRCode\Data\{ AlphaNum, Byte, Kanji, MaskPatternTester, Number, QRCodeDataException, QRDataInterface, QRMatrix }; use chillerlan\QRCode\Output\{ - QRCodeOutputException, QRImage, QRMarkup, QROutputInterface, QRString + QRCodeOutputException, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString }; use chillerlan\Settings\SettingsContainerInterface; @@ -44,6 +44,8 @@ class QRCode{ const OUTPUT_STRING_JSON = 'json'; const OUTPUT_STRING_TEXT = 'text'; + const OUTPUT_IMAGICK = 'imagick'; + const OUTPUT_CUSTOM = 'custom'; const VERSION_AUTO = -1; @@ -87,7 +89,10 @@ class QRCode{ QRString::class => [ self::OUTPUT_STRING_JSON, self::OUTPUT_STRING_TEXT, - ] + ], + QRImagick::class => [ + self::OUTPUT_IMAGICK, + ], ]; /** diff --git a/src/QROptions.php b/src/QROptions.php index f19b7a1f4..170e02be2 100644 --- a/src/QROptions.php +++ b/src/QROptions.php @@ -46,6 +46,9 @@ use chillerlan\Settings\SettingsContainerAbstract; * @property int $pngCompression * @property int $jpegQuality * + * @property string $imagickFormat + * @property string $imagickBG + * * @property array $moduleValues */ class QROptions extends SettingsContainerAbstract{ diff --git a/src/QROptionsTrait.php b/src/QROptionsTrait.php index 8994eb247..e86a65e3b 100644 --- a/src/QROptionsTrait.php +++ b/src/QROptionsTrait.php @@ -200,10 +200,28 @@ trait QROptionsTrait{ */ protected $jpegQuality = 85; + /** + * Imagick output format + * + * @see Imagick::setType() + * + * @var string + */ + protected $imagickFormat = 'png'; + + /** + * Imagick background color (defaults to "transparent") + * + * @see \ImagickPixel::__construct() + * + * @var string + */ + protected $imagickBG; + /** * Module values map * - * HTML : #ABCDEF, cssname, rgb(), rgba()... + * HTML, IMAGICK: #ABCDEF, cssname, rgb(), rgba()... * IMAGE: [63, 127, 255] // R, G, B * * @var array diff --git a/tests/Output/QRImagickTest.php b/tests/Output/QRImagickTest.php new file mode 100644 index 000000000..1184db3f5 --- /dev/null +++ b/tests/Output/QRImagickTest.php @@ -0,0 +1,32 @@ + + * @copyright 2018 smiley + * @license MIT + */ + +namespace chillerlan\QRCodeTest\Output; + +use chillerlan\QRCode\{QRCode, Output\QRImagick}; + +class QRImagickTest extends QROutputTestAbstract{ + + protected $FQCN = QRImagick::class; + + public function testImageOutput(){ + $type = QRCode::OUTPUT_IMAGICK; + + $this->options->outputType = $type; + $this->setOutputInterface(); + $this->outputInterface->dump($this::cachefile.$type); + $img = $this->outputInterface->dump(); + + $this->assertSame($img, file_get_contents($this::cachefile.$type)); + } + +}