diff --git a/examples/Readme.md b/examples/Readme.md index a8dbdaee9..7b1370adc 100644 --- a/examples/Readme.md +++ b/examples/Readme.md @@ -18,6 +18,7 @@ - [Custom output](./custom_output.php): a simple example that demonstrates the usage of custom output classes - [GD Image with logo](./imageWithLogo.php): a logo on top of the QR Code - [GD image with text](./imageWithText.php): description text under the QR Code ([#35](https://github.com/chillerlan/php-qrcode/issues/35)) +- [ImageMagick with logo](./imagickWithLogo.php): a logo on top of the QR Code - [SVG with logo](./svgWithLogo.php): an SVG QR Code with embedded logo (that is also SVG) - [SVG with "melted" modules](./svgMeltedModules.php): an effect where the matrix appears to be like melted wax ([#127](https://github.com/chillerlan/php-qrcode/issues/127)) - [SVG with randomly colored modules](./svgRandomColoredDots.php): a visual effect using multiple colors for the matrix modules ([#136](https://github.com/chillerlan/php-qrcode/discussions/136)) diff --git a/examples/imagickWithLogo.php b/examples/imagickWithLogo.php new file mode 100644 index 000000000..5b1bb9d38 --- /dev/null +++ b/examples/imagickWithLogo.php @@ -0,0 +1,121 @@ + + * @copyright 2023 Smiley + * @license MIT + * + * @noinspection PhpComposerExtensionStubsInspection + */ + +use chillerlan\QRCode\{QRCode, QRCodeException, QROptions}; +use chillerlan\QRCode\Common\EccLevel; +use chillerlan\QRCode\Output\QRImagick; +use chillerlan\QRCode\Data\QRMatrix; +use chillerlan\QRCode\Output\QROutputInterface; + +require_once __DIR__.'/../vendor/autoload.php'; + + +/* + * Class definition + */ + +class QRImagickWithLogo extends QRImagick{ + + /** + * @inheritDoc + * @throws \chillerlan\QRCode\Output\QRCodeOutputException + */ + public function dump(string $file = null):string{ + // set returnResource to true to skip further processing for now + $this->options->returnResource = true; + + // there's no need to save the result of dump() into $this->imagick here + parent::dump($file); + + // set new logo size, leave a border of 1 module (no proportional resize/centering) + $size = ($this->options->logoSpaceWidth - 2) * $this->options->scale; + + // logo position: the top left corner of the logo space + $pos = ($this->moduleCount * $this->options->scale - $size) / 2; + + // invoke logo instance + $imLogo = new Imagick($this->options->pngLogo); + $imLogo->resizeImage($size, $size, Imagick::FILTER_LANCZOS, 0.85, true); + + // add the logo to the qrcode + $this->imagick->compositeImage($imLogo, Imagick::COMPOSITE_ATOP, $pos, $pos); + + // output (retain functionality of the parent class) + $imageData = $this->imagick->getImageBlob(); + + $this->imagick->destroy(); + $this->saveToFile($imageData, $file); + + if($this->options->imageBase64){ + $imageData = $this->toBase64DataURI($imageData, (new finfo(FILEINFO_MIME_TYPE))->buffer($imageData)); + } + + return $imageData; + } + +} + +/** + * augment the QROptions class + */ +class ImagickWithLogoOptions extends QROptions{ + + protected string $pngLogo; + + /** + * check logo + * + * of course we could accept other formats too. + * we're not checking for the file type either for simplicity reasons (assuming PNG) + */ + protected function set_pngLogo(string $pngLogo):void{ + + if(!file_exists($pngLogo) || !is_file($pngLogo) || !is_readable($pngLogo)){ + throw new QRCodeException('invalid png logo'); + } + + // @todo: validate png + + $this->pngLogo = $pngLogo; + } + +} + + +/* + * Runtime + */ + +$options = new ImagickWithLogoOptions([ + 'pngLogo' => __DIR__.'/octocat.png', // setting from the augmented options + 'version' => 5, + 'outputType' => QROutputInterface::CUSTOM, + 'outputInterface' => QRImagickWithLogo::class, // use the custom output class + 'eccLevel' => EccLevel::H, + 'imageBase64' => false, + 'addLogoSpace' => true, + 'logoSpaceWidth' => 15, + 'logoSpaceHeight' => 15, + 'bgColor' => '#eee', + 'imageTransparent' => true, + 'scale' => 20, + 'drawLightModules' => false, + 'drawCircularModules' => true, + 'circleRadius' => 0.4, + 'keepAsSquare' => [QRMatrix::M_FINDER|QRMatrix::IS_DARK, QRMatrix::M_FINDER_DOT, QRMatrix::M_ALIGNMENT|QRMatrix::IS_DARK], +]); + + +header('Content-type: image/png'); + +// dump the output, with an additional logo +echo (new QRCode($options))->render('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); + +exit;