diff --git a/README.md b/README.md index 2fc13db..62c12cc 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,15 @@ $ composer require endroid/qrcode use Endroid\QrCode\ErrorCorrectionLevel; use Endroid\QrCode\LabelAlignment; use Endroid\QrCode\QrCode; -use Endroid\QrCode\Writer\PngWriter; -use Endroid\QrCode\Writer\SvgWriter; use Symfony\Component\HttpFoundation\Response; -// Create a QR code +// Create a basic QR code $qrCode = new QrCode('Life is too short to be generating QR codes'); $qrCode->setSize(300); // Set advanced options $qrCode + ->setWriterByName('png') ->setMargin(10) ->setEncoding('UTF-8') ->setErrorCorrectionLevel(ErrorCorrectionLevel::HIGH) @@ -43,27 +42,19 @@ $qrCode ->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255]) ->setLabel('Scan the code', 16, __DIR__.'/../assets/noto_sans.otf', LabelAlignment::CENTER) ->setLogoPath(__DIR__.'/../assets/symfony.png') - ->setLogoSize(150) + ->setLogoWidth(150) ->setValidateResult(true) ; -// Output the QR code -header('Content-Type: '.$qrCode->getContentType(PngWriter::class)); -echo $qrCode->writeString(PngWriter::class); +// Directly output the QR code +header('Content-Type: '.$qrCode->getContentType()); +echo $qrCode->writeString(); -// Save it to a file (guesses writer by file extension) +// Save it to a file $qrCode->writeFile(__DIR__.'/qrcode.png'); // Create a response object -$response = new Response( - $qrCode->writeString(SvgWriter::class), - Response::HTTP_OK, - ['Content-Type' => $qrCode->getContentType(SvgWriter::class)]) -; - -// Work via the writer -$writer = new PngWriter($qrCode); -$pngData = $writer->writeString(); +$response = new Response($qrCode->writeString(), Response::HTTP_OK, ['Content-Type' => $qrCode->getContentType()]); ``` ![QR Code](http://endroid.nl/qrcode/Dit%20is%20een%20test.png) @@ -89,6 +80,7 @@ applied by the factory can optionally be overridden via the configuration. ```yaml endroid_qr_code: + writer: 'png' size: 300 margin: 10 foreground_color: { r: 0, g: 0, b: 0 } @@ -100,7 +92,7 @@ endroid_qr_code: label_alignment: left # left, center or right label_margin: { b: 20 } logo_path: '%kernel.root_dir%/../vendor/endroid/qrcode/assets/symfony.png' - logo_size: 150 + logo_width: 150 validate_result: true # checks if the result is readable ``` @@ -136,8 +128,8 @@ defaults defined by the bundle or set via your configuration. ``` twig - - + + ``` ## Versioning diff --git a/composer.json b/composer.json index 41933cf..d26b7d0 100755 --- a/composer.json +++ b/composer.json @@ -17,7 +17,6 @@ "ext-gd": "*", "symfony/options-resolver": "^2.7|^3.0", "bacon/bacon-qr-code": "^1.0", - "myclabs/php-enum": "^1.5", "khanamiryan/qrcode-detector-decoder": "^0.0.1", "symfony/property-access": "^2.7|^3.0" }, diff --git a/src/Bundle/Controller/QrCodeController.php b/src/Bundle/Controller/QrCodeController.php index be80b9e..b7774ee 100755 --- a/src/Bundle/Controller/QrCodeController.php +++ b/src/Bundle/Controller/QrCodeController.php @@ -11,6 +11,7 @@ use Endroid\QrCode\Factory\QrCodeFactory; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; @@ -33,25 +34,22 @@ public function generateAction(Request $request, $text, $extension) $options = $request->query->all(); $qrCode = $this->getQrCodeFactory()->create($text, $options); - $writer = $qrCode->getWriterByExtension($extension); + $qrCode->setWriterByExtension($extension); - return new Response( - $writer->writeString(), - Response::HTTP_OK, - ['Content-Type' => $writer->getContentType()] - ); + return new Response($qrCode->writeString(), Response::HTTP_OK, ['Content-Type' => $qrCode->getContentType()]); } /** * @Route("/twig", name="endroid_qrcode_twig_functions") + * @Template() * - * @return Response + * @return array */ public function twigFunctionsAction() { - return $this->render('twig_functions.html.twig', [ + return [ 'message' => 'QR Code' - ]); + ]; } /** diff --git a/src/Bundle/DependencyInjection/Compiler/WriterRegistryCompilerPass.php b/src/Bundle/DependencyInjection/Compiler/WriterRegistryCompilerPass.php new file mode 100644 index 0000000..3564b7d --- /dev/null +++ b/src/Bundle/DependencyInjection/Compiler/WriterRegistryCompilerPass.php @@ -0,0 +1,42 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Bundle\DependencyInjection\Compiler; + +use Endroid\QrCode\ErrorCorrectionLevel; +use Endroid\QrCode\LabelAlignment; +use Endroid\QrCode\QrCode; +use Predis\Response\Error; +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +class WriterRegistryCompilerPass implements CompilerPassInterface +{ + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->has('endroid.qrcode.writer_registry')) { + return; + } + + $writerRegistryDefinition = $container->findDefinition('endroid.qrcode.writer_registry'); + + $taggedServices = $container->findTaggedServiceIds('endroid.qrcode.writer'); + foreach ($taggedServices as $id => $tags) { + foreach ($tags as $attributes) { + $writerRegistryDefinition->addMethodCall('addWriter', [new Reference($id), isset($attributes['set_as_default']) && $attributes['set_as_default']]); + } + } + } +} diff --git a/src/Bundle/DependencyInjection/Configuration.php b/src/Bundle/DependencyInjection/Configuration.php index b0706e9..2bf60ff 100755 --- a/src/Bundle/DependencyInjection/Configuration.php +++ b/src/Bundle/DependencyInjection/Configuration.php @@ -25,6 +25,7 @@ public function getConfigTreeBuilder() $treeBuilder ->root('endroid_qr_code') ->children() + ->scalarNode('writer')->end() ->integerNode('size')->min(0)->end() ->integerNode('margin')->min(0)->end() ->scalarNode('encoding')->defaultValue('UTF-8')->end() @@ -48,6 +49,8 @@ public function getConfigTreeBuilder() ->scalarNode('b')->isRequired()->end() ->end() ->end() + ->scalarNode('logo_path')->end() + ->integerNode('logo_width')->end() ->scalarNode('label')->end() ->integerNode('label_font_size')->end() ->scalarNode('label_font_path')->end() @@ -65,8 +68,6 @@ public function getConfigTreeBuilder() ->scalarNode('l')->end() ->end() ->end() - ->scalarNode('logo_path')->end() - ->integerNode('logo_size')->end() ->booleanNode('validate_result')->end() ->end() ->end() diff --git a/src/Bundle/DependencyInjection/EndroidQrCodeExtension.php b/src/Bundle/DependencyInjection/EndroidQrCodeExtension.php index 31b3d98..5f06877 100644 --- a/src/Bundle/DependencyInjection/EndroidQrCodeExtension.php +++ b/src/Bundle/DependencyInjection/EndroidQrCodeExtension.php @@ -29,6 +29,6 @@ public function load(array $configs, ContainerBuilder $container) $loader->load('services.yml'); $factoryDefinition = $container->getDefinition('endroid.qrcode.factory'); - $factoryDefinition->setArguments([$config]); + $factoryDefinition->replaceArgument(0, $config); } } diff --git a/src/Bundle/EndroidQrCodeBundle.php b/src/Bundle/EndroidQrCodeBundle.php index 01a0e94..b23c035 100644 --- a/src/Bundle/EndroidQrCodeBundle.php +++ b/src/Bundle/EndroidQrCodeBundle.php @@ -9,8 +9,17 @@ namespace Endroid\QrCode\Bundle; +use Endroid\QrCode\Bundle\DependencyInjection\Compiler\WriterRegistryCompilerPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; class EndroidQrCodeBundle extends Bundle { + /** + * {@inheritdoc} + */ + public function build(ContainerBuilder $container) + { + $container->addCompilerPass(new WriterRegistryCompilerPass()); + } } diff --git a/src/Bundle/Resources/config/services.yml b/src/Bundle/Resources/config/services.yml index 3449c55..cbb4d6a 100755 --- a/src/Bundle/Resources/config/services.yml +++ b/src/Bundle/Resources/config/services.yml @@ -1,9 +1,31 @@ services: endroid.qrcode.factory: class: Endroid\QrCode\Factory\QrCodeFactory - + arguments: [ null, '@endroid.qrcode.writer_registry' ] endroid.qrcode.twig.extension: class: Endroid\QrCode\Twig\Extension\QrCodeExtension arguments: [ '@endroid.qrcode.factory', '@router'] tags: - { name: twig.extension } + endroid.qrcode.writer_registry: + class: Endroid\QrCode\WriterRegistry + endroid.qrcode.writer.binary_writer: + class: Endroid\QrCode\Writer\BinaryWriter + tags: + - { name: endroid.qrcode.writer } + endroid.qrcode.writer.debug_writer: + class: Endroid\QrCode\Writer\DebugWriter + tags: + - { name: endroid.qrcode.writer } + endroid.qrcode.writer.eps_writer: + class: Endroid\QrCode\Writer\EpsWriter + tags: + - { name: endroid.qrcode.writer } + endroid.qrcode.writer.png_writer: + class: Endroid\QrCode\Writer\PngWriter + tags: + - { name: endroid.qrcode.writer, set_as_default: true } + endroid.qrcode.writer.svg_writer: + class: Endroid\QrCode\Writer\SvgWriter + tags: + - { name: endroid.qrcode.writer } \ No newline at end of file diff --git a/src/Bundle/Resources/views/QrCode/twigFunctions.html.twig b/src/Bundle/Resources/views/QrCode/twigFunctions.html.twig new file mode 100644 index 0000000..ff448c1 --- /dev/null +++ b/src/Bundle/Resources/views/QrCode/twigFunctions.html.twig @@ -0,0 +1,3 @@ + + + diff --git a/src/Factory/QrCodeFactory.php b/src/Factory/QrCodeFactory.php index 5c76cf1..2eca79e 100644 --- a/src/Factory/QrCodeFactory.php +++ b/src/Factory/QrCodeFactory.php @@ -9,10 +9,8 @@ namespace Endroid\QrCode\Factory; -use Endroid\QrCode\ErrorCorrectionLevel; -use Endroid\QrCode\LabelAlignment; use Endroid\QrCode\QrCode; -use Symfony\Component\OptionsResolver\Options; +use Endroid\QrCode\WriterRegistryInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\PropertyAccess\PropertyAccess; @@ -22,19 +20,20 @@ class QrCodeFactory * @var array */ protected $definedOptions = [ + 'writer', 'size', 'margin', 'foreground_color', 'background_color', 'encoding', 'error_correction_level', + 'logo_path', + 'logo_width', 'label', 'label_font_size', 'label_font_path', 'label_alignment', 'label_margin', - 'logo_path', - 'logo_size', 'validate_result' ]; @@ -43,6 +42,11 @@ class QrCodeFactory */ protected $defaultOptions; + /** + * @var WriterRegistryInterface + */ + protected $writerRegistry; + /** * @var OptionsResolver */ @@ -50,10 +54,12 @@ class QrCodeFactory /** * @param array $defaultOptions + * @param WriterRegistryInterface $writerRegistry */ - public function __construct(array $defaultOptions = []) + public function __construct(array $defaultOptions = [], WriterRegistryInterface $writerRegistry = null) { $this->defaultOptions = $defaultOptions; + $this->writerRegistry = $writerRegistry; } /** @@ -67,8 +73,17 @@ public function create($text = '', array $options = []) $accessor = PropertyAccess::createPropertyAccessor(); $qrCode = new QrCode($text); + + if ($this->writerRegistry instanceof WriterRegistryInterface) { + $qrCode->setWriterRegistry($this->writerRegistry); + } + foreach ($this->definedOptions as $option) { if (isset($options[$option])) { + if ($option === 'writer') { + $options['writer_by_name'] = $options[$option]; + $option = 'writer_by_name'; + } $accessor->setValue($qrCode, $option, $options[$option]); } } diff --git a/src/QrCode.php b/src/QrCode.php index 78365f7..9dbef3a 100644 --- a/src/QrCode.php +++ b/src/QrCode.php @@ -12,23 +12,12 @@ use Endroid\QrCode\Exception\InvalidPathException; use Endroid\QrCode\Exception\InvalidWriterException; use Endroid\QrCode\Exception\UnsupportedExtensionException; -use Endroid\QrCode\Writer\BinaryWriter; -use Endroid\QrCode\Writer\EpsWriter; -use Endroid\QrCode\Writer\PngDataUriWriter; -use Endroid\QrCode\Writer\PngWriter; -use Endroid\QrCode\Writer\SvgDataUriWriter; -use Endroid\QrCode\Writer\SvgWriter; use Endroid\QrCode\Writer\WriterInterface; -class QrCode +class QrCode implements QrCodeInterface { const LABEL_FONT_PATH_DEFAULT = __DIR__ . '/../assets/noto_sans.otf'; - /** - * @var WriterInterface[] - */ - protected $writers; - /** * @var string */ @@ -72,6 +61,16 @@ class QrCode */ protected $errorCorrectionLevel; + /** + * @var string + */ + protected $logoPath; + + /** + * @var int + */ + protected $logoWidth; + /** * @var string */ @@ -103,14 +102,14 @@ class QrCode ]; /** - * @var string + * @var WriterRegistryInterface */ - protected $logoPath; + protected $writerRegistry; /** - * @var int + * @var WriterInterface */ - protected $logoSize; + protected $writer; /** * @var bool @@ -122,43 +121,12 @@ class QrCode */ public function __construct($text = '') { - $this->writers = []; - $this->writersByExtension = []; - $this->text = $text; $this->errorCorrectionLevel = new ErrorCorrectionLevel(ErrorCorrectionLevel::LOW); $this->labelAlignment = new LabelAlignment(LabelAlignment::CENTER); - $this->registerBuiltInWriters(); - } - - protected function registerBuiltInWriters() - { - $this->registerWriter(new BinaryWriter($this)); - $this->registerWriter(new EpsWriter($this)); - $this->registerWriter(new PngDataUriWriter($this)); - $this->registerWriter(new PngWriter($this)); - $this->registerWriter(new SvgDataUriWriter($this)); - $this->registerWriter(new SvgWriter($this)); - } - - /** - * @param WriterInterface $writer - */ - public function registerWriter(WriterInterface $writer) - { - if (!isset($this->writers[get_class($writer)])) { - $this->writers[get_class($writer)] = $writer; - } - } - - /** - * @return WriterInterface[] - */ - public function getRegisteredWriters() - { - return $this->writers; + $this->writerRegistry = new StaticWriterRegistry(); } /** @@ -173,7 +141,7 @@ public function setText($text) } /** - * @return string + * {@inheritdoc} */ public function getText() { @@ -192,7 +160,7 @@ public function setSize($size) } /** - * @return int + * {@inheritdoc} */ public function getSize() { @@ -211,7 +179,7 @@ public function setMargin($margin) } /** - * @return int + * {@inheritdoc} */ public function getMargin() { @@ -230,7 +198,7 @@ public function setForegroundColor($foregroundColor) } /** - * @return array + * {@inheritdoc} */ public function getForegroundColor() { @@ -249,7 +217,7 @@ public function setBackgroundColor($backgroundColor) } /** - * @return array + * {@inheritdoc} */ public function getBackgroundColor() { @@ -268,7 +236,7 @@ public function setEncoding($encoding) } /** - * @return string + * {@inheritdoc} */ public function getEncoding() { @@ -287,13 +255,58 @@ public function setErrorCorrectionLevel($errorCorrectionLevel) } /** - * @return string + * {@inheritdoc} */ public function getErrorCorrectionLevel() { return $this->errorCorrectionLevel->getValue(); } + /** + * @param string $logoPath + * @return $this + * @throws InvalidPathException + */ + public function setLogoPath($logoPath) + { + $logoPath = realpath($logoPath); + + if (!is_file($logoPath)) { + throw new InvalidPathException('Invalid logo path: ' . $logoPath); + } + + $this->logoPath = $logoPath; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getLogoPath() + { + return $this->logoPath; + } + + /** + * @param int $logoWidth + * @return $this + */ + public function setLogoWidth($logoWidth) + { + $this->logoWidth = $logoWidth; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getLogoWidth() + { + return $this->logoWidth; + } + /** * @param string $label * @param int $labelFontSize @@ -326,7 +339,7 @@ public function setLabel($label, $labelFontSize = null, $labelFontPath = null, $ } /** - * @return string + * {@inheritdoc} */ public function getLabel() { @@ -345,7 +358,7 @@ public function setLabelFontSize($labelFontSize) } /** - * @return int + * {@inheritdoc} */ public function getLabelFontSize() { @@ -371,7 +384,7 @@ public function setLabelFontPath($labelFontPath) } /** - * @return string + * {@inheritdoc} */ public function getLabelFontPath() { @@ -390,7 +403,7 @@ public function setLabelAlignment($labelAlignment) } /** - * @return string + * {@inheritdoc} */ public function getLabelAlignment() { @@ -398,7 +411,7 @@ public function getLabelAlignment() } /** - * @param array $labelMargin + * @param int[] $labelMargin * @return $this */ public function setLabelMargin(array $labelMargin) @@ -409,7 +422,7 @@ public function setLabelMargin(array $labelMargin) } /** - * @return array + * {@inheritdoc} */ public function getLabelMargin() { @@ -417,143 +430,137 @@ public function getLabelMargin() } /** - * @param string $logoPath + * @param WriterRegistryInterface $writerRegistry * @return $this - * @throws InvalidPathException */ - public function setLogoPath($logoPath) + public function setWriterRegistry(WriterRegistryInterface $writerRegistry) { - $logoPath = realpath($logoPath); - - if (!is_file($logoPath)) { - throw new InvalidPathException('Invalid logo path: ' . $logoPath); - } - - $this->logoPath = $logoPath; + $this->writerRegistry = $writerRegistry; return $this; } /** - * @return string + * @param WriterInterface $writer + * @return $this */ - public function getLogoPath() + public function setWriter(WriterInterface $writer) { - return $this->logoPath; + $this->writer = $writer; + + return $this; } /** - * @param int $logoSize - * @return $this + * @param WriterInterface $name + * @return WriterInterface */ - public function setLogoSize($logoSize) + public function getWriter($name = null) { - $this->logoSize = $logoSize; + if (!is_null($name)) { + return $this->writerRegistry->getWriter($name); + } - return $this; + if ($this->writer instanceof WriterInterface) { + return $this->writer; + } + + return $this->writerRegistry->getDefaultWriter(); } /** - * @return int + * @param string $name + * @return $this + * @throws InvalidWriterException */ - public function getLogoSize() + public function setWriterByName($name) { - return $this->logoSize; + $this->writer = $this->writerRegistry->getWriter($name); + + return $this; } /** - * @param bool $validateResult + * @param string $path * @return $this */ - public function setValidateResult($validateResult) + public function setWriterByPath($path) { - $this->validateResult = $validateResult; + $extension = pathinfo($path, PATHINFO_EXTENSION); + + $this->setWriterByExtension($extension); return $this; } /** - * @return bool + * @param string $extension + * @return $this + * @throws UnsupportedExtensionException */ - public function getValidateResult() + public function setWriterByExtension($extension) { - return $this->validateResult; + foreach ($this->writerRegistry->getWriters() as $writer) { + if ($writer->supportsExtension($extension)) { + $this->writer = $writer; + return $this; + } + } + + die; + + throw new UnsupportedExtensionException('Missing writer for extension "'.$extension.'"'); } /** - * @param string $writerClass - * @return string - * @throws InvalidWriterException + * @param bool $validateResult + * @return $this */ - public function getContentType($writerClass) + public function setValidateResult($validateResult) { - $this->assertValidWriterClass($writerClass); + $this->validateResult = $validateResult; - return $this->writers[$writerClass]->getContentType(); + return $this; } /** - * @param string $writerClass - * @throws InvalidWriterException + * {@inheritdoc} */ - protected function assertValidWriterClass($writerClass) + public function getValidateResult() { - if (!isset($this->writers[$writerClass])) { - throw new InvalidWriterException('Invalid writer "'.$writerClass.'"'); - } + return $this->validateResult; } /** - * @param string $writerClass * @return string */ - public function writeString($writerClass) + public function writeString() { - $this->assertValidWriterClass($writerClass); - - return $this->writers[$writerClass]->writeString(); + return $this->getWriter()->writeString($this); } /** - * @param string $path - * @param string $writerClass + * @return string */ - public function writeFile($path, $writerClass = null) + public function writeDataUri() { - $writer = $this->getWriterByPath($path); - - if ($writerClass !== null) { - $this->assertValidWriterClass($writerClass); - $writer = $this->writers[$writerClass]; - } - - return $writer->writeFile($path); + return $this->getWriter()->writeDataUri($this); } /** * @param string $path - * @return WriterInterface */ - public function getWriterByPath($path) + public function writeFile($path) { - $extension = pathinfo($path, PATHINFO_EXTENSION); - - return $this->getWriterByExtension($extension); + return $this->getWriter()->writeFile($this, $path); } /** - * @param string $extension - * @return WriterInterface - * @throws UnsupportedExtensionException + * @return string + * @throws InvalidWriterException */ - public function getWriterByExtension($extension) + public function getContentType() { - foreach ($this->writers as $writer) { - if ($writer->supportsExtension($extension)) { - return $writer; - } - } - - throw new UnsupportedExtensionException('Missing writer for extension "'.$extension.'"'); + return $this->getWriter()->getContentType(); } } diff --git a/src/QrCodeInterface.php b/src/QrCodeInterface.php new file mode 100644 index 0000000..8f9c6cf --- /dev/null +++ b/src/QrCodeInterface.php @@ -0,0 +1,94 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +interface QrCodeInterface +{ + /** + * @return string + */ + public function getText(); + + /** + * @return int + */ + public function getSize(); + + /** + * @return int + */ + public function getMargin(); + + /** + * @return int[] + */ + public function getForegroundColor(); + + /** + * @return int[] + */ + public function getBackgroundColor(); + + /** + * @return string + */ + public function getEncoding(); + + /** + * @return string + */ + public function getErrorCorrectionLevel(); + + /** + * @return string + */ + public function getLogoPath(); + + /** + * @return int + */ + public function getLogoWidth(); + + /** + * @return string + */ + public function getLabel(); + + /** + * @return string + */ + public function getLabelFontPath(); + + /** + * @return int + */ + public function getLabelFontSize(); + + /** + * @return string + */ + public function getLabelAlignment(); + + /** + * @return int[] + */ + public function getLabelMargin(); + + /** + * @return bool + */ + public function getValidateResult(); + + /** + * @param WriterRegistryInterface $writerRegistry + * @return mixed + */ + public function setWriterRegistry(WriterRegistryInterface $writerRegistry); +} diff --git a/src/StaticWriterRegistry.php b/src/StaticWriterRegistry.php new file mode 100644 index 0000000..3b1a54c --- /dev/null +++ b/src/StaticWriterRegistry.php @@ -0,0 +1,43 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +use Endroid\QrCode\Writer\BinaryWriter; +use Endroid\QrCode\Writer\DebugWriter; +use Endroid\QrCode\Writer\EpsWriter; +use Endroid\QrCode\Writer\PngWriter; +use Endroid\QrCode\Writer\SvgWriter; +use Endroid\QrCode\Writer\WriterInterface; + +class StaticWriterRegistry extends WriterRegistry +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(); + + $this->loadWriters(); + } + + protected function loadWriters() + { + if (count($this->writers) > 0) { + return; + } + + $this->addWriter(new BinaryWriter()); + $this->addWriter(new DebugWriter()); + $this->addWriter(new EpsWriter()); + $this->addWriter(new PngWriter(), true); + $this->addWriter(new SvgWriter()); + } +} diff --git a/src/Twig/Extension/QrCodeExtension.php b/src/Twig/Extension/QrCodeExtension.php index 8570aa6..e5a57db 100755 --- a/src/Twig/Extension/QrCodeExtension.php +++ b/src/Twig/Extension/QrCodeExtension.php @@ -13,7 +13,9 @@ use Endroid\QrCode\Factory\QrCodeFactory; use Endroid\QrCode\Writer\AbstractDataUriWriter; use Endroid\QrCode\Writer\PngDataUriWriter; +use Endroid\QrCode\Writer\PngWriter; use Endroid\QrCode\Writer\SvgDataUriWriter; +use Endroid\QrCode\WriterRegistryInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RouterInterface; use Twig_Extension; @@ -34,6 +36,7 @@ class QrCodeExtension extends Twig_Extension /** * @param QrCodeFactory $qrCodeFactory * @param RouterInterface $router + * @param WriterRegistryInterface $writerRegistry */ public function __construct(QrCodeFactory $qrCodeFactory, RouterInterface $router) { @@ -82,11 +85,11 @@ public function qrCodePathFunction($text, array $options = []) */ public function getQrCodeReference($text, array $options = [], $referenceType) { - $options['text'] = $text; + $qrCode = $this->qrCodeFactory->create($text, $options); + $supportedExtensions = $qrCode->getWriter()->getSupportedExtensions(); - if (!isset($options['extension'])) { - $options['extension'] = 'png'; - } + $options['text'] = $text; + $options['extension'] = current($supportedExtensions); return $this->router->generate('endroid_qrcode_generate', $options, $referenceType); } @@ -99,24 +102,14 @@ public function getQrCodeReference($text, array $options = [], $referenceType) */ public function qrcodeDataUriFunction($text, array $options = []) { - $extension = 'png'; - if (isset($options['extension'])) { - $extension = $options['extension']; - unset($options['extension']); - } - $qrCode = $this->qrCodeFactory->create($text, $options); - $internalWriter = $qrCode->getWriterByExtension($extension); - foreach ($qrCode->getRegisteredWriters() as $writer) { - if ($writer instanceof AbstractDataUriWriter && $writer->getInternalWriterClass() == get_class($internalWriter)) { - return $writer->writeString(); - } - } - - throw new UnsupportedExtensionException('Extenstion '.$extension.' is not supported by any of the writers'); + return $qrCode->writeDataUri(); } + /** + * @return string + */ public function getName() { return 'qrcode'; diff --git a/src/Writer/AbstractDataUriWriter.php b/src/Writer/AbstractDataUriWriter.php deleted file mode 100644 index 0c82fbf..0000000 --- a/src/Writer/AbstractDataUriWriter.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Endroid\QrCode\Writer; - -abstract class AbstractDataUriWriter extends AbstractWriter -{ - /** - * {@inheritdoc} - */ - public function writeString() - { - $string = $this->qrCode->writeString($this->getInternalWriterClass()); - $string = 'data:'.$this->qrCode->getContentType($this->getInternalWriterClass()).';base64,'.base64_encode($string); - - return $string; - } - - /** - * {@inheritdoc} - */ - public function getContentType() - { - return 'text/plain'; - } - - /** - * {@inheritdoc} - */ - protected function getSupportedExtensions() - { - return []; - } - - /** - * @return WriterInterface - */ - abstract public function getInternalWriterClass(); -} diff --git a/src/Writer/AbstractWriter.php b/src/Writer/AbstractWriter.php index fac0a6f..27c564c 100644 --- a/src/Writer/AbstractWriter.php +++ b/src/Writer/AbstractWriter.php @@ -9,56 +9,55 @@ namespace Endroid\QrCode\Writer; -use Endroid\QrCode\QrCode; +use Endroid\QrCode\QrCodeInterface; +use ReflectionClass; abstract class AbstractWriter implements WriterInterface { - /** - * @var QrCode - */ - protected $qrCode; - /** * {@inheritdoc} */ - public function __construct(QrCode $qrCode) + public function writeDataUri(QrCodeInterface $qrCode) { - $this->qrCode = $qrCode; - } + $dataUri = 'data:'.$this->getContentType().';base64,'.base64_encode($this->writeString($qrCode)); - /** - * {@inheritdoc} - */ - abstract public function writeString(); + return $dataUri; + } /** * {@inheritdoc} */ - public function writeFile($path) + public function writeFile(QrCodeInterface $qrCode, $path) { - $string = $this->writeString(); + $string = $this->writeString($qrCode); file_put_contents($path, $string); } /** * {@inheritdoc} */ - abstract public function getContentType(); + public static function supportsExtension($extension) + { + return in_array($extension, static::getSupportedExtensions()); + } /** - * @param string $extension - * @return bool + * {@inheritdoc} */ - public function supportsExtension($extension) + public static function getSupportedExtensions() { - return in_array($extension, $this->getSupportedExtensions()); + return []; } /** - * @return array + * {@inheritdoc} */ - protected function getSupportedExtensions() + public function getName() { - return []; + $reflectionClass = new ReflectionClass($this); + $className = $reflectionClass->getShortName(); + $name = strtolower(preg_replace('/(? + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode\Writer; + +use Endroid\QrCode\QrCodeInterface; +use ReflectionClass; +use Exception; + +class DebugWriter extends AbstractWriter +{ + /** + * {@inheritdoc} + */ + public function writeString(QrCodeInterface $qrCode) + { + $data = []; + + $reflectionClass = new ReflectionClass($qrCode); + foreach ($reflectionClass->getMethods() as $method) { + $methodName = $method->getShortName(); + if (strpos($methodName, 'get') === 0 && $method->getNumberOfParameters() == 0) { + $value = $qrCode->{$methodName}(); + if (is_array($value) && !is_object(current($value))) { + $value = '['.implode(', ', $value).']'; + } elseif (is_bool($value)) { + $value = $value ? 'true' : 'false'; + } elseif (is_string($value)) { + $value = '"'.$value.'"'; + } elseif (is_null($value)) { + $value = 'null'; + } + try { + $data[] = $methodName . ': ' . $value; + } catch (Exception $exception) { + } + } + } + + $string = implode(" \n", $data); + + return $string; + } + + /** + * {@inheritdoc} + */ + public static function getContentType() + { + return 'text/plain'; + } +} diff --git a/src/Writer/EpsWriter.php b/src/Writer/EpsWriter.php index f40abf8..41dce56 100644 --- a/src/Writer/EpsWriter.php +++ b/src/Writer/EpsWriter.php @@ -9,68 +9,65 @@ namespace Endroid\QrCode\Writer; -use BaconQrCode\Renderer\Color\Rgb; use BaconQrCode\Renderer\Image\Eps; use BaconQrCode\Writer; +use Endroid\QrCode\QrCodeInterface; class EpsWriter extends AbstractBaconWriter { /** * {@inheritdoc} */ - public function writeString() + public function writeString(QrCodeInterface $qrCode) { $renderer = new Eps(); - $renderer->setWidth($this->qrCode->getSize()); - $renderer->setHeight($this->qrCode->getSize()); + $renderer->setWidth($qrCode->getSize()); + $renderer->setHeight($qrCode->getSize()); $renderer->setMargin(0); - $renderer->setForegroundColor($this->convertColor($this->qrCode->getForegroundColor())); - $renderer->setBackgroundColor($this->convertColor($this->qrCode->getBackgroundColor())); + $renderer->setForegroundColor($this->convertColor($qrCode->getForegroundColor())); + $renderer->setBackgroundColor($this->convertColor($qrCode->getBackgroundColor())); $writer = new Writer($renderer); - $string = $writer->writeString( - $this->qrCode->getText(), - $this->qrCode->getEncoding(), - $this->convertErrorCorrectionLevel($this->qrCode->getErrorCorrectionLevel()) - ); + $string = $writer->writeString($qrCode->getText(), $qrCode->getEncoding(), $this->convertErrorCorrectionLevel($qrCode->getErrorCorrectionLevel())); - $string = $this->addMargin($string); + $string = $this->addMargin($string, $qrCode); return $string; } /** * @param string $string + * @param QrCodeInterface $qrCode * @return string */ - protected function addMargin($string) + protected function addMargin($string, QrCodeInterface $qrCode) { - $targetSize = $this->qrCode->getSize() + $this->qrCode->getMargin() * 2; + $targetSize = $qrCode->getSize() + $qrCode->getMargin() * 2; $lines = explode("\n", $string); $sourceBlockSize = 0; - $additionalWhitespace = $this->qrCode->getSize(); + $additionalWhitespace = $qrCode->getSize(); foreach ($lines as $line) { - if (preg_match('#[0-9]+ [0-9]+ [0-9]+ [0-9]+ F#i', $line) && strpos($line, $this->qrCode->getSize().' '.$this->qrCode->getSize().' F') === false) { + if (preg_match('#[0-9]+ [0-9]+ [0-9]+ [0-9]+ F#i', $line) && strpos($line, $qrCode->getSize().' '.$qrCode->getSize().' F') === false) { $parts = explode(' ', $line); $sourceBlockSize = $parts[2]; $additionalWhitespace = min($additionalWhitespace, $parts[0]); } } - $blockCount = ($this->qrCode->getSize() - 2 * $additionalWhitespace) / $sourceBlockSize; - $targetBlockSize = $this->qrCode->getSize() / $blockCount; + $blockCount = ($qrCode->getSize() - 2 * $additionalWhitespace) / $sourceBlockSize; + $targetBlockSize = $qrCode->getSize() / $blockCount; foreach ($lines as &$line) { if (strpos($line, 'BoundingBox') !== false) { $line = '%%BoundingBox: 0 0 '.$targetSize.' '.$targetSize; - } elseif (strpos($line, $this->qrCode->getSize().' '.$this->qrCode->getSize().' F') !== false) { + } elseif (strpos($line, $qrCode->getSize().' '.$qrCode->getSize().' F') !== false) { $line = '0 0 '.$targetSize.' '.$targetSize.' F'; } elseif (preg_match('#[0-9]+ [0-9]+ [0-9]+ [0-9]+ F#i', $line)) { $parts = explode(' ', $line); - $parts[0] = $this->qrCode->getMargin() + $targetBlockSize * ($parts[0] - $additionalWhitespace) / $sourceBlockSize; - $parts[1] = $this->qrCode->getMargin() + $targetBlockSize * ($parts[1] - $sourceBlockSize - $additionalWhitespace) / $sourceBlockSize; + $parts[0] = $qrCode->getMargin() + $targetBlockSize * ($parts[0] - $additionalWhitespace) / $sourceBlockSize; + $parts[1] = $qrCode->getMargin() + $targetBlockSize * ($parts[1] - $sourceBlockSize - $additionalWhitespace) / $sourceBlockSize; $parts[2] = $targetBlockSize; $parts[3] = $targetBlockSize; $line = implode(' ', $parts); @@ -85,7 +82,7 @@ protected function addMargin($string) /** * {@inheritdoc} */ - public function getContentType() + public static function getContentType() { return 'image/eps'; } @@ -93,7 +90,7 @@ public function getContentType() /** * {@inheritdoc} */ - protected function getSupportedExtensions() + public static function getSupportedExtensions() { return ['eps']; } diff --git a/src/Writer/PngDataUriWriter.php b/src/Writer/PngDataUriWriter.php deleted file mode 100644 index 315c4b3..0000000 --- a/src/Writer/PngDataUriWriter.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Endroid\QrCode\Writer; - -class PngDataUriWriter extends AbstractDataUriWriter -{ - /** - * {@inheritdoc} - */ - public function getInternalWriterClass() - { - return PngWriter::class; - } -} diff --git a/src/Writer/PngWriter.php b/src/Writer/PngWriter.php index 62233a3..fa0cb41 100644 --- a/src/Writer/PngWriter.php +++ b/src/Writer/PngWriter.php @@ -11,9 +11,12 @@ use BaconQrCode\Renderer\Image\Png; use BaconQrCode\Writer; +use Endroid\QrCode\ColorableQrCodeInterface; use Endroid\QrCode\Exception\MissingFunctionException; use Endroid\QrCode\Exception\ValidationException; use Endroid\QrCode\LabelAlignment; +use Endroid\QrCode\QrCodeInterface; +use Endroid\QrCode\ValidateableQrCodeInterface; use QrReader; class PngWriter extends AbstractBaconWriter @@ -21,33 +24,36 @@ class PngWriter extends AbstractBaconWriter /** * {@inheritdoc} */ - public function writeString() + public function writeString(QrCodeInterface $qrCode) { $renderer = new Png(); - $renderer->setWidth($this->qrCode->getSize()); - $renderer->setHeight($this->qrCode->getSize()); + $renderer->setWidth($qrCode->getSize()); + $renderer->setHeight($qrCode->getSize()); $renderer->setMargin(0); - $renderer->setForegroundColor($this->convertColor($this->qrCode->getForegroundColor())); - $renderer->setBackgroundColor($this->convertColor($this->qrCode->getBackgroundColor())); + $renderer->setForegroundColor($this->convertColor($qrCode->getForegroundColor())); + $renderer->setBackgroundColor($this->convertColor($qrCode->getBackgroundColor())); $writer = new Writer($renderer); - $string = $writer->writeString( - $this->qrCode->getText(), - $this->qrCode->getEncoding(), - $this->convertErrorCorrectionLevel($this->qrCode->getErrorCorrectionLevel()) - ); + $string = $writer->writeString($qrCode->getText(), $qrCode->getEncoding(), $this->convertErrorCorrectionLevel($qrCode->getErrorCorrectionLevel())); $image = imagecreatefromstring($string); - $image = $this->addMargin($image); - $image = $this->addLogo($image); - $image = $this->addLabel($image); + $image = $this->addMargin($image, $qrCode->getMargin(), $qrCode->getSize(), $qrCode->getForegroundColor(), $qrCode->getBackgroundColor()); + + if ($qrCode->getLogoPath()) { + $image = $this->addLogo($image, $qrCode->getLogoPath(), $qrCode->getLogoWidth()); + } + + if ($qrCode->getLabel()) { + $image = $this->addLabel($image, $qrCode->getLabel(), $qrCode->getLabelFontPath(), $qrCode->getLabelFontSize(), $qrCode->getLabelAlignment(), $qrCode->getLabelMargin(), $qrCode->getForegroundColor(), $qrCode->getBackgroundColor()); + } + $string = $this->imageToString($image); - if ($this->qrCode->getValidateResult()) { + if ($qrCode->getValidateResult()) { $reader = new QrReader($string, QrReader::SOURCE_TYPE_BLOB); - if ($reader->text() !== $this->qrCode->getText()) { + if ($reader->text() !== $qrCode->getText()) { throw new ValidationException( - 'Built-in validation reader read "'.$reader->text().'" instead of "'.$this->qrCode->getText().'". + 'Built-in validation reader read "'.$reader->text().'" instead of "'.$qrCode->getText().'". Adjust your parameters to increase readability or disable built-in validation.'); } } @@ -57,34 +63,38 @@ public function writeString() /** * @param resource $sourceImage + * @param int $margin + * @param int $size + * @param int[] $foregroundColor + * @param int[] $backgroundColor * @return resource */ - protected function addMargin($sourceImage) + protected function addMargin($sourceImage, $margin, $size, array $foregroundColor, array $backgroundColor) { - $additionalWhitespace = $this->calculateAdditionalWhiteSpace($sourceImage); + $additionalWhitespace = $this->calculateAdditionalWhiteSpace($sourceImage, $foregroundColor); - if ($additionalWhitespace == 0 && $this->qrCode->getMargin() == 0) { + if ($additionalWhitespace == 0 && $margin == 0) { return $sourceImage; } - $targetImage = imagecreatetruecolor($this->qrCode->getSize() + $this->qrCode->getMargin() * 2, $this->qrCode->getSize() + $this->qrCode->getMargin() * 2); - $backgroundColor = imagecolorallocate($targetImage, $this->qrCode->getBackgroundColor()['r'], $this->qrCode->getBackgroundColor()['g'], $this->qrCode->getBackgroundColor()['b']); + $targetImage = imagecreatetruecolor($size + $margin * 2, $size + $margin * 2); + $backgroundColor = imagecolorallocate($targetImage, $backgroundColor['r'], $backgroundColor['g'], $backgroundColor['b']); imagefill($targetImage, 0, 0, $backgroundColor); - imagecopyresampled($targetImage, $sourceImage, $this->qrCode->getMargin(), $this->qrCode->getMargin(), $additionalWhitespace, $additionalWhitespace, $this->qrCode->getSize(), $this->qrCode->getSize(), $this->qrCode->getSize() - 2 * $additionalWhitespace, $this->qrCode->getSize() - 2 * $additionalWhitespace); + imagecopyresampled($targetImage, $sourceImage, $margin, $margin, $additionalWhitespace, $additionalWhitespace, $size, $size, $size - 2 * $additionalWhitespace, $size - 2 * $additionalWhitespace); return $targetImage; } /** * @param resource $image + * @param int[] $foregroundColor * @return int */ - protected function calculateAdditionalWhiteSpace($image) + protected function calculateAdditionalWhiteSpace($image, array $foregroundColor) { $width = imagesx($image); $height = imagesy($image); - $foregroundColor = $this->qrCode->getForegroundColor(); $foregroundColor = imagecolorallocate($image, $foregroundColor['r'], $foregroundColor['g'], $foregroundColor['b']); $whitespace = $width; @@ -103,18 +113,16 @@ protected function calculateAdditionalWhiteSpace($image) /** * @param resource $sourceImage + * @param string $logoPath + * @param int $logoWidth * @return resource */ - protected function addLogo($sourceImage) + protected function addLogo($sourceImage, $logoPath, $logoWidth = null) { - if ($this->qrCode->getLogoPath() === null) { - return $sourceImage; - } - - $logoImage = imagecreatefromstring(file_get_contents($this->qrCode->getLogoPath())); + $logoImage = imagecreatefromstring(file_get_contents($logoPath)); $logoSourceWidth = imagesx($logoImage); $logoSourceHeight = imagesy($logoImage); - $logoTargetWidth = $this->qrCode->getLogoSize(); + $logoTargetWidth = $logoWidth; if ($logoTargetWidth === null) { $logoTargetWidth = $logoSourceWidth; @@ -133,23 +141,25 @@ protected function addLogo($sourceImage) /** * @param resource $sourceImage + * @param string $label + * @param string $labelFontPath + * @param int $labelFontSize + * @param string $labelAlignment + * @param int[] $labelMargin + * @param int[] $foregroundColor + * @param int[] $backgroundColor * @return resource * @throws MissingFunctionException */ - protected function addLabel($sourceImage) + protected function addLabel($sourceImage, $label, $labelFontPath, $labelFontSize, $labelAlignment, $labelMargin, array $foregroundColor, array $backgroundColor) { - if ($this->qrCode->getLabel() === null) { - return $sourceImage; - } - if (!function_exists('imagettfbbox')) { throw new MissingFunctionException('Missing function "imagettfbbox". Did you install the FreeType library?'); } - $labelBox = imagettfbbox($this->qrCode->getLabelFontSize(), 0, $this->qrCode->getLabelFontPath(), $this->qrCode->getLabel()); + $labelBox = imagettfbbox($labelFontSize, 0, $labelFontPath, $label); $labelBoxWidth = intval($labelBox[2] - $labelBox[0]); $labelBoxHeight = intval($labelBox[0] - $labelBox[7]); - $labelMargin = $this->qrCode->getLabelMargin(); $sourceWidth = imagesx($sourceImage); $sourceHeight = imagesy($sourceImage); @@ -158,14 +168,14 @@ protected function addLabel($sourceImage) // Create empty target image $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); - $foregroundColor = imagecolorallocate($targetImage, $this->qrCode->getForegroundColor()['r'], $this->qrCode->getForegroundColor()['g'], $this->qrCode->getForegroundColor()['b']); - $backgroundColor = imagecolorallocate($targetImage, $this->qrCode->getBackgroundColor()['r'], $this->qrCode->getBackgroundColor()['g'], $this->qrCode->getBackgroundColor()['b']); + $foregroundColor = imagecolorallocate($targetImage, $foregroundColor['r'], $foregroundColor['g'], $foregroundColor['b']); + $backgroundColor = imagecolorallocate($targetImage, $backgroundColor['r'], $backgroundColor['g'], $backgroundColor['b']); imagefill($targetImage, 0, 0, $backgroundColor); // Copy source image to target image imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $sourceWidth, $sourceHeight, $sourceWidth, $sourceHeight); - switch ($this->qrCode->getLabelAlignment()) { + switch ($labelAlignment) { case LabelAlignment::LEFT: $labelX = $labelMargin['l']; break; @@ -178,7 +188,7 @@ protected function addLabel($sourceImage) } $labelY = $targetHeight - $labelMargin['b']; - imagettftext($targetImage, $this->qrCode->getLabelFontSize(), 0, $labelX, $labelY, $foregroundColor, $this->qrCode->getLabelFontPath(), $this->qrCode->getLabel()); + imagettftext($targetImage, $labelFontSize, 0, $labelX, $labelY, $foregroundColor, $labelFontPath, $label); return $targetImage; } @@ -199,7 +209,7 @@ protected function imageToString($image) /** * {@inheritdoc} */ - public function getContentType() + public static function getContentType() { return 'image/png'; } @@ -207,7 +217,7 @@ public function getContentType() /** * {@inheritdoc} */ - protected function getSupportedExtensions() + public static function getSupportedExtensions() { return ['png']; } diff --git a/src/Writer/SvgDataUriWriter.php b/src/Writer/SvgDataUriWriter.php deleted file mode 100644 index 50120e0..0000000 --- a/src/Writer/SvgDataUriWriter.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Endroid\QrCode\Writer; - -class SvgDataUriWriter extends AbstractDataUriWriter -{ - /** - * {@inheritdoc} - */ - public function getInternalWriterClass() - { - return SvgWriter::class; - } -} diff --git a/src/Writer/SvgWriter.php b/src/Writer/SvgWriter.php index a0cad8f..d6b3ff5 100644 --- a/src/Writer/SvgWriter.php +++ b/src/Writer/SvgWriter.php @@ -11,6 +11,7 @@ use BaconQrCode\Renderer\Image\Svg; use BaconQrCode\Writer; +use Endroid\QrCode\QrCodeInterface; use SimpleXMLElement; class SvgWriter extends AbstractBaconWriter @@ -18,34 +19,32 @@ class SvgWriter extends AbstractBaconWriter /** * {@inheritdoc} */ - public function writeString() + public function writeString(QrCodeInterface $qrCode) { $renderer = new Svg(); - $renderer->setWidth($this->qrCode->getSize()); - $renderer->setHeight($this->qrCode->getSize()); + $renderer->setWidth($qrCode->getSize()); + $renderer->setHeight($qrCode->getSize()); $renderer->setMargin(0); - $renderer->setForegroundColor($this->convertColor($this->qrCode->getForegroundColor())); - $renderer->setBackgroundColor($this->convertColor($this->qrCode->getBackgroundColor())); + $renderer->setForegroundColor($this->convertColor($qrCode->getForegroundColor())); + $renderer->setBackgroundColor($this->convertColor($qrCode->getBackgroundColor())); $writer = new Writer($renderer); - $string = $writer->writeString( - $this->qrCode->getText(), - $this->qrCode->getEncoding(), - $this->convertErrorCorrectionLevel($this->qrCode->getErrorCorrectionLevel()) - ); + $string = $writer->writeString($qrCode->getText(), $qrCode->getEncoding(), $this->convertErrorCorrectionLevel($qrCode->getErrorCorrectionLevel())); - $string = $this->addMargin($string); + $string = $this->addMargin($string, $qrCode->getMargin(), $qrCode->getSize()); return $string; } /** * @param string $string + * @param int $margin + * @param int $size * @return string */ - protected function addMargin($string) + protected function addMargin($string, $margin, $size) { - $targetSize = $this->qrCode->getSize() + $this->qrCode->getMargin() * 2; + $targetSize = $size + $margin * 2; $xml = new SimpleXMLElement($string); $xml['width'] = $targetSize; @@ -60,15 +59,15 @@ protected function addMargin($string) } $sourceBlockSize = (int) $xml->defs->rect['width']; - $blockCount = ($this->qrCode->getSize() - 2 * $additionalWhitespace) / $sourceBlockSize; - $targetBlockSize = $this->qrCode->getSize() / $blockCount; + $blockCount = ($size - 2 * $additionalWhitespace) / $sourceBlockSize; + $targetBlockSize = $size / $blockCount; $xml->defs->rect['width'] = $targetBlockSize; $xml->defs->rect['height'] = $targetBlockSize; foreach ($xml->use as $block) { - $block['x'] = $this->qrCode->getMargin() + $targetBlockSize * ($block['x'] - $additionalWhitespace) / $sourceBlockSize; - $block['y'] = $this->qrCode->getMargin() + $targetBlockSize * ($block['y'] - $additionalWhitespace) / $sourceBlockSize; + $block['x'] = $margin + $targetBlockSize * ($block['x'] - $additionalWhitespace) / $sourceBlockSize; + $block['y'] = $margin + $targetBlockSize * ($block['y'] - $additionalWhitespace) / $sourceBlockSize; } return $xml->asXML(); @@ -77,7 +76,7 @@ protected function addMargin($string) /** * {@inheritdoc} */ - public function getContentType() + public static function getContentType() { return 'image/svg+xml'; } @@ -85,7 +84,7 @@ public function getContentType() /** * {@inheritdoc} */ - protected function getSupportedExtensions() + public static function getSupportedExtensions() { return ['svg']; } diff --git a/src/Writer/WriterInterface.php b/src/Writer/WriterInterface.php index 0399120..2f9e498 100644 --- a/src/Writer/WriterInterface.php +++ b/src/Writer/WriterInterface.php @@ -9,33 +9,46 @@ namespace Endroid\QrCode\Writer; -use Endroid\QrCode\QrCode; +use Endroid\QrCode\QrCodeInterface; interface WriterInterface { /** - * @param QrCode $qrCode + * @param QrCodeInterface $qrCode + * @return string */ - public function __construct(QrCode $qrCode); + public function writeString(QrCodeInterface $qrCode); /** + * @param QrCodeInterface $qrCode * @return string */ - public function writeString(); + public function writeDataUri(QrCodeInterface $qrCode); /** + * @param QrCodeInterface $qrCode * @param string $path */ - public function writeFile($path); + public function writeFile(QrCodeInterface $qrCode, $path); /** * @return string */ - public function getContentType(); + public static function getContentType(); /** * @param string $extension * @return bool */ - public function supportsExtension($extension); + public static function supportsExtension($extension); + + /** + * @return string[] + */ + public static function getSupportedExtensions(); + + /** + * @return string + */ + public function getName(); } diff --git a/src/WriterRegistry.php b/src/WriterRegistry.php new file mode 100644 index 0000000..032c92f --- /dev/null +++ b/src/WriterRegistry.php @@ -0,0 +1,86 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +use Endroid\QrCode\Exception\InvalidWriterException; +use Endroid\QrCode\Writer\WriterInterface; + +class WriterRegistry implements WriterRegistryInterface +{ + /** + * @var WriterInterface[] + */ + protected $writers; + + /** + * @var WriterInterface + */ + protected $defaultWriter; + + public function __construct() + { + $this->writers = []; + } + + /** + * {@inheritdoc} + */ + public function addWriter(WriterInterface $writer, $setAsDefault = false) + { + $this->writers[$writer->getName()] = $writer; + + if ($setAsDefault || count($this->writers) === 1) { + $this->defaultWriter = $writer; + } + } + + /** + * @param $name + * @return WriterInterface + */ + public function getWriter($name) + { + $this->assertValidWriter($name); + + return $this->writers[$name]; + } + + /** + * @return WriterInterface + * @throws InvalidWriterException + */ + public function getDefaultWriter() + { + if ($this->defaultWriter instanceof WriterInterface) { + return $this->defaultWriter; + } + + throw new InvalidWriterException('Please set the default writer via the second argument of addWriter'); + } + + /** + * @return WriterInterface[] + */ + public function getWriters() + { + return $this->writers; + } + + /** + * @param string $writer + * @throws InvalidWriterException + */ + protected function assertValidWriter($writer) + { + if (!isset($this->writers[$writer])) { + throw new InvalidWriterException('Invalid writer "'.$writer.'"'); + } + } +} diff --git a/src/WriterRegistryInterface.php b/src/WriterRegistryInterface.php new file mode 100644 index 0000000..87cca6a --- /dev/null +++ b/src/WriterRegistryInterface.php @@ -0,0 +1,32 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Endroid\QrCode; + +use Endroid\QrCode\Writer\WriterInterface; + +interface WriterRegistryInterface +{ + /** + * @param WriterInterface $writer + * @return $this + */ + public function addWriter(WriterInterface $writer); + + /** + * @param $name + * @return WriterInterface + */ + public function getWriter($name); + + /** + * @return WriterInterface[] + */ + public function getWriters(); +} diff --git a/tests/Bundle/app/Resources/views/twig_functions.html.twig b/tests/Bundle/app/Resources/views/twig_functions.html.twig deleted file mode 100644 index beba79f..0000000 --- a/tests/Bundle/app/Resources/views/twig_functions.html.twig +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tests/Bundle/app/config/config.yml b/tests/Bundle/app/config/config.yml index 22a3061..09d86dd 100644 --- a/tests/Bundle/app/config/config.yml +++ b/tests/Bundle/app/config/config.yml @@ -5,8 +5,4 @@ framework: engines: ['twig'] router: resource: "%kernel.root_dir%/config/routing.yml" - strict_requirements: ~ - -twig: - paths: - '%kernel.root_dir%/Resources/views': __main__ \ No newline at end of file + strict_requirements: ~ \ No newline at end of file diff --git a/tests/QrCodeTest.php b/tests/QrCodeTest.php index 4dab83a..33f0738 100755 --- a/tests/QrCodeTest.php +++ b/tests/QrCodeTest.php @@ -9,12 +9,12 @@ namespace Endroid\QrCode\Tests; +use Endroid\QrCode\Factory\QrCodeFactory; use Endroid\QrCode\QrCode; use Endroid\QrCode\Writer\BinaryWriter; +use Endroid\QrCode\Writer\DebugWriter; use Endroid\QrCode\Writer\EpsWriter; -use Endroid\QrCode\Writer\PngDataUriWriter; use Endroid\QrCode\Writer\PngWriter; -use Endroid\QrCode\Writer\SvgDataUriWriter; use Endroid\QrCode\Writer\SvgWriter; use PHPUnit\Framework\TestCase; @@ -25,7 +25,9 @@ public function testReadable() $messages = [ 'Tiny', 'This one has spaces', + 'd2llMS9uU01BVmlvalM2YU9BUFBPTTdQMmJabHpqdndt', 'http://this.is.an/url?with=query&string=attached', + '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', '{"i":"serialized.data","v":1,"t":1,"d":"4AEPc9XuIQ0OjsZoSRWp9DRWlN6UyDvuMlyOYy8XjOw="}', 'Spëci&al ch@ract3rs', '有限公司' @@ -35,32 +37,51 @@ public function testReadable() $qrCode = new QrCode($message); $qrCode->setSize(300); $qrCode->setValidateResult(true); - $pngData = $qrCode->writeString(PngWriter::class); + $pngData = $qrCode->writeString(); $this->assertTrue(is_string($pngData)); } } + public function testFactory() + { + $qrCodeFactory = new QrCodeFactory(); + $qrCode = $qrCodeFactory->create('QR Code', [ + 'writer' => 'png', + 'size' => 300, + 'margin' => 10 + ]); + + $pngData = $qrCode->writeString(); + $this->assertTrue(is_string($pngData)); + } + public function testWriteQrCode() { $qrCode = new QrCode('QrCode'); - $binData = $qrCode->writeString(BinaryWriter::class); + $qrCode->setWriterByName('binary'); + $binData = $qrCode->writeString(); $this->assertTrue(is_string($binData)); - $epsData = $qrCode->writeString(EpsWriter::class); - $this->assertTrue(is_string($epsData)); + $qrCode->setWriterByName('debug'); + $debugData = $qrCode->writeString(); + $this->assertTrue(is_string($debugData)); - $pngDataUriData = $qrCode->writeString(PngDataUriWriter::class); - $this->assertTrue(strpos($pngDataUriData, 'data:image/png;base64') === 0); + $qrCode->setWriterByName('eps'); + $epsData = $qrCode->writeString(); + $this->assertTrue(is_string($epsData)); - $pngData = $qrCode->writeString(PngWriter::class); + $qrCode->setWriterByName('png'); + $pngData = $qrCode->writeString(); $this->assertTrue(is_string($pngData)); + $pngDataUriData = $qrCode->writeDataUri(); + $this->assertTrue(strpos($pngDataUriData, 'data:image/png;base64') === 0); - $svgDataUriData = $qrCode->writeString(SvgDataUriWriter::class); - $this->assertTrue(strpos($svgDataUriData, 'data:image/svg+xml;base64') === 0); - - $svgData = $qrCode->writeString(SvgWriter::class); + $qrCode->setWriterByName('svg'); + $svgData = $qrCode->writeString(); $this->assertTrue(is_string($svgData)); + $svgDataUriData = $qrCode->writeDataUri(); + $this->assertTrue(strpos($svgDataUriData, 'data:image/svg+xml;base64') === 0); } public function testSetSize() @@ -72,7 +93,7 @@ public function testSetSize() $qrCode->setSize($size); $qrCode->setMargin($margin); - $pngData = $qrCode->writeString(PngWriter::class); + $pngData = $qrCode->writeString(); $image = imagecreatefromstring($pngData); $this->assertTrue(imagesx($image) === $size + 2 * $margin); @@ -87,7 +108,7 @@ public function testSetLabel() ->setLabel('Scan the code', 15) ; - $pngData = $qrCode->writeString(PngWriter::class); + $pngData = $qrCode->writeString(); $this->assertTrue(is_string($pngData)); } @@ -97,11 +118,11 @@ public function testSetLogo() $qrCode ->setSize(400) ->setLogoPath(__DIR__.'/../assets/symfony.png') - ->setLogoSize(150) + ->setLogoWidth(150) ->setValidateResult(true); ; - $pngData = $qrCode->writeString(PngWriter::class); + $pngData = $qrCode->writeString(); $this->assertTrue(is_string($pngData)); } }