This commit is contained in:
Xes
2025-08-14 22:41:49 +02:00
parent 2de81ccc46
commit 8ce45119b6
39774 changed files with 4309466 additions and 0 deletions

5
vendor/endroid/qr-code/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/bin
/composer.lock
/composer.phar
/phpunit.xml
/vendor

18
vendor/endroid/qr-code/.travis.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
language: php
php:
- 5.6
- 7.0
- 7.1
matrix:
fast_finish: true
before_install:
- phpenv config-rm xdebug.ini
- composer self-update && composer install --no-interaction
script: bin/phpunit
notifications:
email: info@endroid.nl

View File

19
vendor/endroid/qr-code/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) Jeroen van den Enden
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

159
vendor/endroid/qr-code/README.md vendored Normal file
View File

@@ -0,0 +1,159 @@
QR Code
=======
*By [endroid](http://endroid.nl/)*
[![Latest Stable Version](http://img.shields.io/packagist/v/endroid/qrcode.svg)](https://packagist.org/packages/endroid/qrcode)
[![Build Status](http://img.shields.io/travis/endroid/QrCode.svg)](http://travis-ci.org/endroid/QrCode)
[![Total Downloads](http://img.shields.io/packagist/dt/endroid/qrcode.svg)](https://packagist.org/packages/endroid/qrcode)
[![Monthly Downloads](http://img.shields.io/packagist/dm/endroid/qrcode.svg)](https://packagist.org/packages/endroid/qrcode)
[![License](http://img.shields.io/packagist/l/endroid/qrcode.svg)](https://packagist.org/packages/endroid/qrcode)
This library helps you generate QR codes in an easy way and provides a Symfony
bundle for rapid integration in your project.
## Installation
Use [Composer](https://getcomposer.org/) to install the library.
``` bash
$ composer require endroid/qrcode
```
## Basic usage
```php
use Endroid\QrCode\QrCode;
$qrCode = new QrCode('Life is too short to be generating QR codes');
header('Content-Type: '.$qrCode->getContentType());
echo $qrCode->writeString();
```
## Advanced usage
```php
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\LabelAlignment;
use Endroid\QrCode\QrCode;
use Symfony\Component\HttpFoundation\Response;
// 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)
->setForegroundColor(['r' => 0, 'g' => 0, 'b' => 0])
->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255])
->setLabel('Scan the code', 16, __DIR__.'/../assets/noto_sans.otf', LabelAlignment::CENTER)
->setLogoPath(__DIR__.'/../assets/symfony.png')
->setLogoWidth(150)
->setValidateResult(false)
;
// Directly output the QR code
header('Content-Type: '.$qrCode->getContentType());
echo $qrCode->writeString();
// Save it to a file
$qrCode->writeFile(__DIR__.'/qrcode.png');
// Create a response object
$response = new Response($qrCode->writeString(), Response::HTTP_OK, ['Content-Type' => $qrCode->getContentType()]);
```
![QR Code](http://endroid.nl/qrcode/Dit%20is%20een%20test.png)
## Symfony integration
When you use Symfony Flex, the bundle is automatically registered and the
configuration and routes are automatically created when you installed the
package. In other scenarios you can register the bundle as follows.
```php
// app/AppKernel.php
public function registerBundles()
{
$bundles = [
// ...
new Endroid\QrCode\Bundle\QrCodeBundle\EndroidQrCodeBundle(),
];
}
```
The bundle makes use of a factory to create QR codes. The default parameters
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 }
background_color: { r: 255, g: 255, b: 255 }
error_correction_level: low # low, medium, quartile or high
encoding: UTF-8
label: Scan the code
label_font_size: 20
label_alignment: left # left, center or right
label_margin: { b: 20 }
logo_path: '%kernel.root_dir%/../vendor/endroid/qrcode/assets/symfony.png'
logo_width: 150
validate_result: false # checks if the result is readable
```
The readability of a QR code is primarily determined by the size, the input
length, the error correction level and any possible logo over the image. The
`validate_result` option uses a built-in reader to validate the resulting
image. This does not guarantee that the code will be readable by all readers
but this helps you provide a minimum level of quality. Take note that the
validator can consume quite an amount of resources and is disabled by default.
Now you can retrieve the factory from the service container and create a QR
code. For instance in your controller this would look like this.
```php
$qrCode = $this->get('endroid.qrcode.factory')->create('QR Code', ['size' => 200]);
```
Add the following section to your routing to be able to handle QR code URLs.
This step can be skipped if you only use data URIs to display your images.
``` yml
EndroidQrCodeBundle:
resource: "@EndroidQrCodeBundle/Resources/config/routing.yml"
prefix: /qrcode
```
After installation and configuration, QR codes can be generated by appending
the QR code text to the url followed by any of the supported extensions.
## Twig extension
The bundle provides a Twig extension for generating a QR code URL, path or data
URI. You can use the second argument of any of these functions to override any
defaults defined by the bundle or set via your configuration.
``` twig
<img src="{{ qrcode_path(message) }}" />
<img src="{{ qrcode_url(message, { writer: 'eps' }) }}" />
<img src="{{ qrcode_data_uri(message, { writer: 'svg', size: 150 }) }}" />
```
## Versioning
Version numbers follow the MAJOR.MINOR.PATCH scheme. Backwards compatibility
breaking changes will be kept to a minimum but be aware that these can occur.
Lock your dependencies for production and test your code when upgrading.
## License
This bundle is under the MIT license. For the full copyright and license
information please view the LICENSE file that was distributed with this source code.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

53
vendor/endroid/qr-code/composer.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"name": "endroid/qrcode",
"description": "Endroid QR Code",
"keywords": ["endroid", "qrcode", "qr", "code", "bundle", "symfony", "flex"],
"homepage": "https://github.com/endroid/QrCode",
"type": "symfony-bundle",
"license": "MIT",
"authors": [
{
"name": "Jeroen van den Enden",
"email": "info@endroid.nl",
"homepage": "http://endroid.nl/"
}
],
"require": {
"php": ">=5.6",
"ext-gd": "*",
"symfony/options-resolver": "^2.7",
"bacon/bacon-qr-code": "^1.0.3",
"khanamiryan/qrcode-detector-decoder": "1",
"symfony/property-access": "^2.7",
"myclabs/php-enum": "^1.5"
},
"require-dev": {
"symfony/asset": "^2.7",
"symfony/browser-kit": "^2.7",
"symfony/finder": "^2.7",
"symfony/framework-bundle": "^2.7",
"symfony/http-kernel": "^2.7",
"symfony/templating": "^2.7",
"symfony/twig-bundle": "^2.7",
"symfony/yaml": "^2.7",
"phpunit/phpunit": "^5.7"
},
"autoload": {
"psr-4": {
"Endroid\\QrCode\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Endroid\\QrCode\\Tests\\": "tests/"
}
},
"config": {
"bin-dir": "bin"
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
}
}

11
vendor/endroid/qr-code/phpunit.xml.dist vendored Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/Bundle/app/bootstrap.php" colors="true">
<testsuites>
<testsuite>
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>
<php>
<server name="KERNEL_DIR" value="tests/Bundle/app" />
</php>
</phpunit>

View File

@@ -0,0 +1,64 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Bundle\QrCodeBundle\Controller;
use Endroid\QrCode\Factory\QrCodeFactory;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
/**
* QR code controller.
*/
class QrCodeController extends Controller
{
/**
* @param Request $request
* @param string $text
* @param string $extension
*
* @return Response
*/
public function generateAction(Request $request, $text, $extension)
{
$options = $request->query->all();
$qrCode = $this->getQrCodeFactory()->create($text, $options);
$qrCode->setWriterByExtension($extension);
return new Response($qrCode->writeString(), Response::HTTP_OK, ['Content-Type' => $qrCode->getContentType()]);
}
/**
* @return Response
*/
public function twigFunctionsAction()
{
if (!$this->has('twig')) {
throw new \LogicException('You can not use the "@Template" annotation if the Twig Bundle is not available.');
}
$param = [
'message' => 'QR Code',
];
$renderedView = $this->get('twig')->render('@EndroidQrCode/QrCode/twigFunctions.html.twig', $param);
return new Response($renderedView, Response::HTTP_OK);
}
/**
* @return QrCodeFactory
*/
protected function getQrCodeFactory()
{
return $this->get('endroid.qrcode.factory');
}
}

View File

@@ -0,0 +1,36 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Bundle\QrCodeBundle\DependencyInjection\Compiler;
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']]);
}
}
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Bundle\QrCodeBundle\DependencyInjection;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\LabelAlignment;
use Predis\Response\Error;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$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()
->scalarNode('error_correction_level')
->validate()
->ifNotInArray(ErrorCorrectionLevel::toArray())
->thenInvalid('Invalid error correction level %s')
->end()
->end()
->arrayNode('foreground_color')
->children()
->scalarNode('r')->isRequired()->end()
->scalarNode('g')->isRequired()->end()
->scalarNode('b')->isRequired()->end()
->end()
->end()
->arrayNode('background_color')
->children()
->scalarNode('r')->isRequired()->end()
->scalarNode('g')->isRequired()->end()
->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()
->scalarNode('label_alignment')
->validate()
->ifNotInArray(LabelAlignment::toArray())
->thenInvalid('Invalid label alignment %s')
->end()
->end()
->arrayNode('label_margin')
->children()
->scalarNode('t')->end()
->scalarNode('r')->end()
->scalarNode('b')->end()
->scalarNode('l')->end()
->end()
->end()
->booleanNode('validate_result')->end()
->end()
->end()
;
return $treeBuilder;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Bundle\QrCodeBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\Config\FileLocator;
class EndroidQrCodeExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$processor = new Processor();
$config = $processor->processConfiguration(new Configuration(), $configs);
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
$factoryDefinition = $container->getDefinition('endroid.qrcode.factory');
$factoryDefinition->replaceArgument(0, $config);
}
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Bundle\QrCodeBundle;
use Endroid\QrCode\Bundle\QrCodeBundle\DependencyInjection\Compiler\WriterRegistryCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class EndroidQrCodeBundle extends Bundle
{
/**
* {@inheritdoc}
*/
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new WriterRegistryCompilerPass());
}
}

View File

@@ -0,0 +1,11 @@
endroid_qrcode_generate:
path: /{text}.{extension}
requirements:
text: "[\\w\\W]+"
defaults:
_controller: EndroidQrCodeBundle:QrCode:generate
endroid_qrcode_twig_functions:
path: /twig
defaults:
_controller: EndroidQrCodeBundle:QrCode:twigFunctions

View File

@@ -0,0 +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 }

View File

@@ -0,0 +1,3 @@
<img src="{{ qrcode_path(message) }}" />
<img src="{{ qrcode_url(message, { writer: 'svg' }) }}" />
<img src="{{ qrcode_data_uri(message, { writer: 'svg', size: 150 }) }}" />

View File

@@ -0,0 +1,20 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode;
use MyCLabs\Enum\Enum;
class ErrorCorrectionLevel extends Enum
{
const LOW = 'low';
const MEDIUM = 'medium';
const QUARTILE = 'quartile';
const HIGH = 'high';
}

View File

@@ -0,0 +1,14 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Exception;
class InvalidPathException extends QrCodeException
{
}

View File

@@ -0,0 +1,14 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Exception;
class InvalidWriterException extends QrCodeException
{
}

View File

@@ -0,0 +1,14 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Exception;
class MissingFunctionException extends QrCodeException
{
}

View File

@@ -0,0 +1,16 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Exception;
use Exception;
abstract class QrCodeException extends Exception
{
}

View File

@@ -0,0 +1,14 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Exception;
class UnsupportedExtensionException extends QrCodeException
{
}

View File

@@ -0,0 +1,14 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Exception;
class ValidationException extends QrCodeException
{
}

View File

@@ -0,0 +1,120 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Factory;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\WriterRegistryInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\PropertyAccess\PropertyAccess;
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',
'validate_result',
];
/**
* @var array
*/
protected $defaultOptions;
/**
* @var WriterRegistryInterface
*/
protected $writerRegistry;
/**
* @var OptionsResolver
*/
protected $optionsResolver;
/**
* @param array $defaultOptions
* @param WriterRegistryInterface $writerRegistry
*/
public function __construct(array $defaultOptions = [], WriterRegistryInterface $writerRegistry = null)
{
$this->defaultOptions = $defaultOptions;
$this->writerRegistry = $writerRegistry;
}
/**
* @param string $text
* @param array $options
*
* @return QrCode
*/
public function create($text = '', array $options = [])
{
$options = $this->getOptionsResolver()->resolve($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 ('writer' === $option) {
$options['writer_by_name'] = $options[$option];
$option = 'writer_by_name';
}
$accessor->setValue($qrCode, $option, $options[$option]);
}
}
return $qrCode;
}
/**
* @return OptionsResolver
*/
protected function getOptionsResolver()
{
if (!$this->optionsResolver instanceof OptionsResolver) {
$this->optionsResolver = $this->createOptionsResolver();
}
return $this->optionsResolver;
}
/**
* @return OptionsResolver
*/
protected function createOptionsResolver()
{
$optionsResolver = new OptionsResolver();
$optionsResolver
->setDefaults($this->defaultOptions)
->setDefined($this->definedOptions)
;
return $optionsResolver;
}
}

View File

@@ -0,0 +1,19 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode;
use MyCLabs\Enum\Enum;
class LabelAlignment extends Enum
{
const LEFT = 'left';
const CENTER = 'center';
const RIGHT = 'right';
}

591
vendor/endroid/qr-code/src/QrCode.php vendored Normal file
View File

@@ -0,0 +1,591 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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\InvalidPathException;
use Endroid\QrCode\Exception\InvalidWriterException;
use Endroid\QrCode\Exception\UnsupportedExtensionException;
use Endroid\QrCode\Writer\WriterInterface;
class QrCode implements QrCodeInterface
{
const LABEL_FONT_PATH_DEFAULT = __DIR__.'/../assets/noto_sans.otf';
/**
* @var string
*/
protected $text;
/**
* @var int
*/
protected $size = 300;
/**
* @var int
*/
protected $margin = 10;
/**
* @var array
*/
protected $foregroundColor = [
'r' => 0,
'g' => 0,
'b' => 0,
];
/**
* @var array
*/
protected $backgroundColor = [
'r' => 255,
'g' => 255,
'b' => 255,
];
/**
* @var string
*/
protected $encoding = 'UTF-8';
/**
* @var ErrorCorrectionLevel
*/
protected $errorCorrectionLevel;
/**
* @var string
*/
protected $logoPath;
/**
* @var int
*/
protected $logoWidth;
/**
* @var string
*/
protected $label;
/**
* @var int
*/
protected $labelFontSize = 16;
/**
* @var string
*/
protected $labelFontPath = self::LABEL_FONT_PATH_DEFAULT;
/**
* @var LabelAlignment
*/
protected $labelAlignment;
/**
* @var array
*/
protected $labelMargin = [
't' => 0,
'r' => 10,
'b' => 10,
'l' => 10,
];
/**
* @var WriterRegistryInterface
*/
protected $writerRegistry;
/**
* @var WriterInterface
*/
protected $writer;
/**
* @var bool
*/
protected $validateResult = false;
/**
* @param string $text
*/
public function __construct($text = '')
{
$this->text = $text;
$this->errorCorrectionLevel = new ErrorCorrectionLevel(ErrorCorrectionLevel::LOW);
$this->labelAlignment = new LabelAlignment(LabelAlignment::CENTER);
$this->writerRegistry = new StaticWriterRegistry();
}
/**
* @param string $text
*
* @return $this
*/
public function setText($text)
{
$this->text = $text;
return $this;
}
/**
* {@inheritdoc}
*/
public function getText()
{
return $this->text;
}
/**
* @param int $size
*
* @return $this
*/
public function setSize($size)
{
$this->size = $size;
return $this;
}
/**
* {@inheritdoc}
*/
public function getSize()
{
return $this->size;
}
/**
* @param int $margin
*
* @return $this
*/
public function setMargin($margin)
{
$this->margin = $margin;
return $this;
}
/**
* {@inheritdoc}
*/
public function getMargin()
{
return $this->margin;
}
/**
* @param array $foregroundColor
*
* @return $this
*/
public function setForegroundColor($foregroundColor)
{
$this->foregroundColor = $foregroundColor;
return $this;
}
/**
* {@inheritdoc}
*/
public function getForegroundColor()
{
return $this->foregroundColor;
}
/**
* @param array $backgroundColor
*
* @return $this
*/
public function setBackgroundColor($backgroundColor)
{
$this->backgroundColor = $backgroundColor;
return $this;
}
/**
* {@inheritdoc}
*/
public function getBackgroundColor()
{
return $this->backgroundColor;
}
/**
* @param string $encoding
*
* @return $this
*/
public function setEncoding($encoding)
{
$this->encoding = $encoding;
return $this;
}
/**
* {@inheritdoc}
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* @param string $errorCorrectionLevel
*
* @return $this
*/
public function setErrorCorrectionLevel($errorCorrectionLevel)
{
$this->errorCorrectionLevel = new ErrorCorrectionLevel($errorCorrectionLevel);
return $this;
}
/**
* {@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
* @param string $labelFontPath
* @param string $labelAlignment
* @param array $labelMargin
*
* @return $this
*/
public function setLabel($label, $labelFontSize = null, $labelFontPath = null, $labelAlignment = null, $labelMargin = null)
{
$this->label = $label;
if (null !== $labelFontSize) {
$this->setLabelFontSize($labelFontSize);
}
if (null !== $labelFontPath) {
$this->setLabelFontPath($labelFontPath);
}
if (null !== $labelAlignment) {
$this->setLabelAlignment($labelAlignment);
}
if (null !== $labelMargin) {
$this->setLabelMargin($labelMargin);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getLabel()
{
return $this->label;
}
/**
* @param int $labelFontSize
*
* @return $this
*/
public function setLabelFontSize($labelFontSize)
{
$this->labelFontSize = $labelFontSize;
return $this;
}
/**
* {@inheritdoc}
*/
public function getLabelFontSize()
{
return $this->labelFontSize;
}
/**
* @param string $labelFontPath
*
* @return $this
*
* @throws InvalidPathException
*/
public function setLabelFontPath($labelFontPath)
{
$labelFontPath = realpath($labelFontPath);
if (!is_file($labelFontPath)) {
throw new InvalidPathException('Invalid label font path: '.$labelFontPath);
}
$this->labelFontPath = $labelFontPath;
return $this;
}
/**
* {@inheritdoc}
*/
public function getLabelFontPath()
{
return $this->labelFontPath;
}
/**
* @param string $labelAlignment
*
* @return $this
*/
public function setLabelAlignment($labelAlignment)
{
$this->labelAlignment = new LabelAlignment($labelAlignment);
return $this;
}
/**
* {@inheritdoc}
*/
public function getLabelAlignment()
{
return $this->labelAlignment->getValue();
}
/**
* @param int[] $labelMargin
*
* @return $this
*/
public function setLabelMargin(array $labelMargin)
{
$this->labelMargin = array_merge($this->labelMargin, $labelMargin);
return $this;
}
/**
* {@inheritdoc}
*/
public function getLabelMargin()
{
return $this->labelMargin;
}
/**
* @param WriterRegistryInterface $writerRegistry
*
* @return $this
*/
public function setWriterRegistry(WriterRegistryInterface $writerRegistry)
{
$this->writerRegistry = $writerRegistry;
return $this;
}
/**
* @param WriterInterface $writer
*
* @return $this
*/
public function setWriter(WriterInterface $writer)
{
$this->writer = $writer;
return $this;
}
/**
* @param WriterInterface $name
*
* @return WriterInterface
*/
public function getWriter($name = null)
{
if (!is_null($name)) {
return $this->writerRegistry->getWriter($name);
}
if ($this->writer instanceof WriterInterface) {
return $this->writer;
}
return $this->writerRegistry->getDefaultWriter();
}
/**
* @param string $name
*
* @return $this
*
* @throws InvalidWriterException
*/
public function setWriterByName($name)
{
$this->writer = $this->writerRegistry->getWriter($name);
return $this;
}
/**
* @param string $path
*
* @return $this
*/
public function setWriterByPath($path)
{
$extension = pathinfo($path, PATHINFO_EXTENSION);
$this->setWriterByExtension($extension);
return $this;
}
/**
* @param string $extension
*
* @return $this
*
* @throws UnsupportedExtensionException
*/
public function setWriterByExtension($extension)
{
foreach ($this->writerRegistry->getWriters() as $writer) {
if ($writer->supportsExtension($extension)) {
$this->writer = $writer;
return $this;
}
}
throw new UnsupportedExtensionException('Missing writer for extension "'.$extension.'"');
}
/**
* @param bool $validateResult
*
* @return $this
*/
public function setValidateResult($validateResult)
{
$this->validateResult = $validateResult;
return $this;
}
/**
* {@inheritdoc}
*/
public function getValidateResult()
{
return $this->validateResult;
}
/**
* @return string
*/
public function writeString()
{
return $this->getWriter()->writeString($this);
}
/**
* @return string
*/
public function writeDataUri()
{
return $this->getWriter()->writeDataUri($this);
}
/**
* @param string $path
*/
public function writeFile($path)
{
return $this->getWriter()->writeFile($this, $path);
}
/**
* @return string
*
* @throws InvalidWriterException
*/
public function getContentType()
{
return $this->getWriter()->getContentType();
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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);
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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;
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());
}
}

View File

@@ -0,0 +1,117 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Twig\Extension;
use Endroid\QrCode\Exception\UnsupportedExtensionException;
use Endroid\QrCode\Factory\QrCodeFactory;
use Endroid\QrCode\WriterRegistryInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Twig_Extension;
use Twig_SimpleFunction;
class QrCodeExtension extends Twig_Extension
{
/**
* @var QrCodeFactory
*/
protected $qrCodeFactory;
/**
* @var RouterInterface
*/
protected $router;
/**
* @param QrCodeFactory $qrCodeFactory
* @param RouterInterface $router
* @param WriterRegistryInterface $writerRegistry
*/
public function __construct(QrCodeFactory $qrCodeFactory, RouterInterface $router)
{
$this->qrCodeFactory = $qrCodeFactory;
$this->router = $router;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return [
new Twig_SimpleFunction('qrcode_path', [$this, 'qrCodePathFunction']),
new Twig_SimpleFunction('qrcode_url', [$this, 'qrCodeUrlFunction']),
new Twig_SimpleFunction('qrcode_data_uri', [$this, 'qrCodeDataUriFunction']),
];
}
/**
* @param string $text
* @param array $options
*
* @return string
*/
public function qrcodeUrlFunction($text, array $options = [])
{
return $this->getQrCodeReference($text, $options, UrlGeneratorInterface::ABSOLUTE_URL);
}
/**
* @param string $text
* @param array $options
*
* @return string
*/
public function qrCodePathFunction($text, array $options = [])
{
return $this->getQrCodeReference($text, $options, UrlGeneratorInterface::ABSOLUTE_PATH);
}
/**
* @param string $text
* @param array $options
* @param int $referenceType
*
* @return string
*/
public function getQrCodeReference($text, array $options = [], $referenceType)
{
$qrCode = $this->qrCodeFactory->create($text, $options);
$supportedExtensions = $qrCode->getWriter()->getSupportedExtensions();
$options['text'] = $text;
$options['extension'] = current($supportedExtensions);
return $this->router->generate('endroid_qrcode_generate', $options, $referenceType);
}
/**
* @param string $text
* @param array $options
*
* @return string
*
* @throws UnsupportedExtensionException
*/
public function qrcodeDataUriFunction($text, array $options = [])
{
$qrCode = $this->qrCodeFactory->create($text, $options);
return $qrCode->writeDataUri();
}
/**
* @return string
*/
public function getName()
{
return 'qrcode';
}
}

View File

@@ -0,0 +1,40 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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 BaconQrCode\Renderer\Color\Rgb;
abstract class AbstractBaconWriter extends AbstractWriter
{
/**
* @param array $color
*
* @return Rgb
*/
protected function convertColor(array $color)
{
$color = new Rgb($color['r'], $color['g'], $color['b']);
return $color;
}
/**
* @param string $errorCorrectionLevel
*
* @return string
*/
protected function convertErrorCorrectionLevel($errorCorrectionLevel)
{
$name = strtoupper(substr($errorCorrectionLevel, 0, 1));
$errorCorrectionLevel = constant('BaconQrCode\Common\ErrorCorrectionLevel::'.$name);
return $errorCorrectionLevel;
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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;
abstract class AbstractWriter implements WriterInterface
{
/**
* {@inheritdoc}
*/
public function writeDataUri(QrCodeInterface $qrCode)
{
$dataUri = 'data:'.$this->getContentType().';base64,'.base64_encode($this->writeString($qrCode));
return $dataUri;
}
/**
* {@inheritdoc}
*/
public function writeFile(QrCodeInterface $qrCode, $path)
{
$string = $this->writeString($qrCode);
file_put_contents($path, $string);
}
/**
* {@inheritdoc}
*/
public static function supportsExtension($extension)
{
return in_array($extension, static::getSupportedExtensions());
}
/**
* {@inheritdoc}
*/
public static function getSupportedExtensions()
{
return [];
}
/**
* {@inheritdoc}
*/
public function getName()
{
$reflectionClass = new ReflectionClass($this);
$className = $reflectionClass->getShortName();
$name = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', str_replace('Writer', '', $className)));
return $name;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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;
class BinaryWriter extends AbstractWriter
{
/**
* {@inheritdoc}
*/
public function writeString(QrCodeInterface $qrCode)
{
$string = '
0001010101
0001010101
1000101010
0001010101
0101010101
0001010101
0001010101
0001010101
0001010101
1000101010
';
return $string;
}
/**
* {@inheritdoc}
*/
public static function getContentType()
{
return 'text/plain';
}
/**
* {@inheritdoc}
*/
public static function getSupportedExtensions()
{
return ['bin', 'txt'];
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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 (0 === strpos($methodName, 'get') && 0 == $method->getNumberOfParameters()) {
$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';
}
}

View File

@@ -0,0 +1,98 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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 BaconQrCode\Renderer\Image\Eps;
use BaconQrCode\Writer;
use Endroid\QrCode\QrCodeInterface;
class EpsWriter extends AbstractBaconWriter
{
/**
* {@inheritdoc}
*/
public function writeString(QrCodeInterface $qrCode)
{
$renderer = new Eps();
$renderer->setWidth($qrCode->getSize());
$renderer->setHeight($qrCode->getSize());
$renderer->setMargin(0);
$renderer->setForegroundColor($this->convertColor($qrCode->getForegroundColor()));
$renderer->setBackgroundColor($this->convertColor($qrCode->getBackgroundColor()));
$writer = new Writer($renderer);
$string = $writer->writeString($qrCode->getText(), $qrCode->getEncoding(), $this->convertErrorCorrectionLevel($qrCode->getErrorCorrectionLevel()));
$string = $this->addMargin($string, $qrCode);
return $string;
}
/**
* @param string $string
* @param QrCodeInterface $qrCode
*
* @return string
*/
protected function addMargin($string, QrCodeInterface $qrCode)
{
$targetSize = $qrCode->getSize() + $qrCode->getMargin() * 2;
$lines = explode("\n", $string);
$sourceBlockSize = 0;
$additionalWhitespace = $qrCode->getSize();
foreach ($lines as $line) {
if (preg_match('#[0-9]+ [0-9]+ [0-9]+ [0-9]+ F#i', $line) && false === strpos($line, $qrCode->getSize().' '.$qrCode->getSize().' F')) {
$parts = explode(' ', $line);
$sourceBlockSize = $parts[2];
$additionalWhitespace = min($additionalWhitespace, $parts[0]);
}
}
$blockCount = ($qrCode->getSize() - 2 * $additionalWhitespace) / $sourceBlockSize;
$targetBlockSize = $qrCode->getSize() / $blockCount;
foreach ($lines as &$line) {
if (false !== strpos($line, 'BoundingBox')) {
$line = '%%BoundingBox: 0 0 '.$targetSize.' '.$targetSize;
} elseif (false !== strpos($line, $qrCode->getSize().' '.$qrCode->getSize().' F')) {
$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] = $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);
}
}
$string = implode("\n", $lines);
return $string;
}
/**
* {@inheritdoc}
*/
public static function getContentType()
{
return 'image/eps';
}
/**
* {@inheritdoc}
*/
public static function getSupportedExtensions()
{
return ['eps'];
}
}

View File

@@ -0,0 +1,228 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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 BaconQrCode\Renderer\Image\Png;
use BaconQrCode\Writer;
use Endroid\QrCode\Exception\MissingFunctionException;
use Endroid\QrCode\Exception\ValidationException;
use Endroid\QrCode\LabelAlignment;
use Endroid\QrCode\QrCodeInterface;
use QrReader;
class PngWriter extends AbstractBaconWriter
{
/**
* {@inheritdoc}
*/
public function writeString(QrCodeInterface $qrCode)
{
$renderer = new Png();
$renderer->setWidth($qrCode->getSize());
$renderer->setHeight($qrCode->getSize());
$renderer->setMargin(0);
$renderer->setForegroundColor($this->convertColor($qrCode->getForegroundColor()));
$renderer->setBackgroundColor($this->convertColor($qrCode->getBackgroundColor()));
$writer = new Writer($renderer);
$string = $writer->writeString($qrCode->getText(), $qrCode->getEncoding(), $this->convertErrorCorrectionLevel($qrCode->getErrorCorrectionLevel()));
$image = imagecreatefromstring($string);
$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 ($qrCode->getValidateResult()) {
$reader = new QrReader($string, QrReader::SOURCE_TYPE_BLOB);
if ($reader->text() !== $qrCode->getText()) {
throw new ValidationException(
'Built-in validation reader read "'.$reader->text().'" instead of "'.$qrCode->getText().'".
Adjust your parameters to increase readability or disable built-in validation.');
}
}
return $string;
}
/**
* @param resource $sourceImage
* @param int $margin
* @param int $size
* @param int[] $foregroundColor
* @param int[] $backgroundColor
*
* @return resource
*/
protected function addMargin($sourceImage, $margin, $size, array $foregroundColor, array $backgroundColor)
{
$additionalWhitespace = $this->calculateAdditionalWhiteSpace($sourceImage, $foregroundColor);
if (0 == $additionalWhitespace && 0 == $margin) {
return $sourceImage;
}
$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, $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, array $foregroundColor)
{
$width = imagesx($image);
$height = imagesy($image);
$foregroundColor = imagecolorallocate($image, $foregroundColor['r'], $foregroundColor['g'], $foregroundColor['b']);
$whitespace = $width;
for ($y = 0; $y < $height; ++$y) {
for ($x = 0; $x < $width; ++$x) {
$color = imagecolorat($image, $x, $y);
if ($color == $foregroundColor || $x == $whitespace) {
$whitespace = min($whitespace, $x);
break;
}
}
}
return $whitespace;
}
/**
* @param resource $sourceImage
* @param string $logoPath
* @param int $logoWidth
*
* @return resource
*/
protected function addLogo($sourceImage, $logoPath, $logoWidth = null)
{
$logoImage = imagecreatefromstring(file_get_contents($logoPath));
$logoSourceWidth = imagesx($logoImage);
$logoSourceHeight = imagesy($logoImage);
$logoTargetWidth = $logoWidth;
if (null === $logoTargetWidth) {
$logoTargetWidth = $logoSourceWidth;
$logoTargetHeight = $logoSourceHeight;
} else {
$scale = $logoTargetWidth / $logoSourceWidth;
$logoTargetHeight = intval($scale * imagesy($logoImage));
}
$logoX = imagesx($sourceImage) / 2 - $logoTargetWidth / 2;
$logoY = imagesy($sourceImage) / 2 - $logoTargetHeight / 2;
imagecopyresampled($sourceImage, $logoImage, $logoX, $logoY, 0, 0, $logoTargetWidth, $logoTargetHeight, $logoSourceWidth, $logoSourceHeight);
return $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, $label, $labelFontPath, $labelFontSize, $labelAlignment, $labelMargin, array $foregroundColor, array $backgroundColor)
{
if (!function_exists('imagettfbbox')) {
throw new MissingFunctionException('Missing function "imagettfbbox". Did you install the FreeType library?');
}
$labelBox = imagettfbbox($labelFontSize, 0, $labelFontPath, $label);
$labelBoxWidth = intval($labelBox[2] - $labelBox[0]);
$labelBoxHeight = intval($labelBox[0] - $labelBox[7]);
$sourceWidth = imagesx($sourceImage);
$sourceHeight = imagesy($sourceImage);
$targetWidth = $sourceWidth;
$targetHeight = $sourceHeight + $labelBoxHeight + $labelMargin['t'] + $labelMargin['b'];
// Create empty target image
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
$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 ($labelAlignment) {
case LabelAlignment::LEFT:
$labelX = $labelMargin['l'];
break;
case LabelAlignment::RIGHT:
$labelX = $targetWidth - $labelBoxWidth - $labelMargin['r'];
break;
default:
$labelX = intval($targetWidth / 2 - $labelBoxWidth / 2);
break;
}
$labelY = $targetHeight - $labelMargin['b'];
imagettftext($targetImage, $labelFontSize, 0, $labelX, $labelY, $foregroundColor, $labelFontPath, $label);
return $targetImage;
}
/**
* @param resource $image
*
* @return string
*/
protected function imageToString($image)
{
ob_start();
imagepng($image);
$string = ob_get_clean();
return $string;
}
/**
* {@inheritdoc}
*/
public static function getContentType()
{
return 'image/png';
}
/**
* {@inheritdoc}
*/
public static function getSupportedExtensions()
{
return ['png'];
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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 BaconQrCode\Renderer\Image\Svg;
use BaconQrCode\Writer;
use Endroid\QrCode\QrCodeInterface;
use SimpleXMLElement;
class SvgWriter extends AbstractBaconWriter
{
/**
* {@inheritdoc}
*/
public function writeString(QrCodeInterface $qrCode)
{
$renderer = new Svg();
$renderer->setWidth($qrCode->getSize());
$renderer->setHeight($qrCode->getSize());
$renderer->setMargin(0);
$renderer->setForegroundColor($this->convertColor($qrCode->getForegroundColor()));
$renderer->setBackgroundColor($this->convertColor($qrCode->getBackgroundColor()));
$writer = new Writer($renderer);
$string = $writer->writeString($qrCode->getText(), $qrCode->getEncoding(), $this->convertErrorCorrectionLevel($qrCode->getErrorCorrectionLevel()));
$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, $margin, $size)
{
$targetSize = $size + $margin * 2;
$xml = new SimpleXMLElement($string);
$xml['width'] = $targetSize;
$xml['height'] = $targetSize;
$xml['viewBox'] = '0 0 '.$targetSize.' '.$targetSize;
$xml->rect['width'] = $targetSize;
$xml->rect['height'] = $targetSize;
$additionalWhitespace = $targetSize;
foreach ($xml->use as $block) {
$additionalWhitespace = min($additionalWhitespace, (int) $block['x']);
}
$sourceBlockSize = (int) $xml->defs->rect['width'];
$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'] = $margin + $targetBlockSize * ($block['x'] - $additionalWhitespace) / $sourceBlockSize;
$block['y'] = $margin + $targetBlockSize * ($block['y'] - $additionalWhitespace) / $sourceBlockSize;
}
return $xml->asXML();
}
/**
* {@inheritdoc}
*/
public static function getContentType()
{
return 'image/svg+xml';
}
/**
* {@inheritdoc}
*/
public static function getSupportedExtensions()
{
return ['svg'];
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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;
interface WriterInterface
{
/**
* @param QrCodeInterface $qrCode
*
* @return string
*/
public function writeString(QrCodeInterface $qrCode);
/**
* @param QrCodeInterface $qrCode
*
* @return string
*/
public function writeDataUri(QrCodeInterface $qrCode);
/**
* @param QrCodeInterface $qrCode
* @param string $path
*/
public function writeFile(QrCodeInterface $qrCode, $path);
/**
* @return string
*/
public static function getContentType();
/**
* @param string $extension
*
* @return bool
*/
public static function supportsExtension($extension);
/**
* @return string[]
*/
public static function getSupportedExtensions();
/**
* @return string
*/
public function getName();
}

View File

@@ -0,0 +1,89 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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 || 1 === count($this->writers)) {
$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.'"');
}
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* 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();
}

View File

@@ -0,0 +1,45 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Tests\Bundle\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Response;
class QrCodeControllerTest extends WebTestCase
{
public function testGenerateAction()
{
$client = static::createClient();
$client->request('GET', $client->getContainer()->get('router')->generate('endroid_qrcode_generate', [
'text' => 'Life is too short to be generating QR codes',
'extension' => 'png',
'size' => 200,
'margin' => 10,
'label' => 'Scan the code',
'label_font_size' => 16,
]));
$response = $client->getResponse();
$image = imagecreatefromstring($response->getContent());
$this->assertTrue(220 == imagesx($image));
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
}
public function testTwigFunctionsAction()
{
$client = static::createClient();
$client->request('GET', $client->getContainer()->get('router')->generate('endroid_qrcode_twig_functions'));
$response = $client->getResponse();
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
}
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Tests\Bundle;
use PHPUnit\Framework\TestCase;
class EndroidQrCodeBundleTest extends TestCase
{
public function testNoTestsYet()
{
$this->assertTrue(true);
}
}

View File

@@ -0,0 +1,2 @@
/cache
/logs

View File

@@ -0,0 +1,36 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;
class AppKernel extends Kernel
{
/**
* {@inheritdoc}
*/
public function registerBundles()
{
$bundles = [
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Endroid\QrCode\Bundle\QrCodeBundle\EndroidQrCodeBundle(),
];
return $bundles;
}
/**
* {@inheritdoc}
*/
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config.yml');
}
}

View File

@@ -0,0 +1,3 @@
<?php
$loader = require __DIR__.'/../../../vendor/autoload.php';

View File

@@ -0,0 +1,8 @@
framework:
test: ~
secret: ThisTokenIsNotSoSecretChangeIt
templating:
engines: ['twig']
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~

View File

@@ -0,0 +1,3 @@
EndroidQrCodeBundle:
resource: "@EndroidQrCodeBundle/Resources/config/routing.yml"
prefix: /qrcode

View File

@@ -0,0 +1,122 @@
<?php
/*
* (c) Jeroen van den Enden <info@endroid.nl>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Endroid\QrCode\Tests;
use Endroid\QrCode\Factory\QrCodeFactory;
use Endroid\QrCode\QrCode;
use PHPUnit\Framework\TestCase;
class QrCodeTest extends TestCase
{
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',
'有限公司',
];
foreach ($messages as $message) {
$qrCode = new QrCode($message);
$qrCode->setSize(300);
$qrCode->setValidateResult(true);
$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');
$qrCode->setWriterByName('binary');
$binData = $qrCode->writeString();
$this->assertTrue(is_string($binData));
$qrCode->setWriterByName('debug');
$debugData = $qrCode->writeString();
$this->assertTrue(is_string($debugData));
$qrCode->setWriterByName('eps');
$epsData = $qrCode->writeString();
$this->assertTrue(is_string($epsData));
$qrCode->setWriterByName('png');
$pngData = $qrCode->writeString();
$this->assertTrue(is_string($pngData));
$pngDataUriData = $qrCode->writeDataUri();
$this->assertTrue(0 === strpos($pngDataUriData, 'data:image/png;base64'));
$qrCode->setWriterByName('svg');
$svgData = $qrCode->writeString();
$this->assertTrue(is_string($svgData));
$svgDataUriData = $qrCode->writeDataUri();
$this->assertTrue(0 === strpos($svgDataUriData, 'data:image/svg+xml;base64'));
}
public function testSetSize()
{
$size = 400;
$margin = 10;
$qrCode = new QrCode('QrCode');
$qrCode->setSize($size);
$qrCode->setMargin($margin);
$pngData = $qrCode->writeString();
$image = imagecreatefromstring($pngData);
$this->assertTrue(imagesx($image) === $size + 2 * $margin);
$this->assertTrue(imagesy($image) === $size + 2 * $margin);
}
public function testSetLabel()
{
$qrCode = new QrCode('QrCode');
$qrCode
->setSize(300)
->setLabel('Scan the code', 15)
;
$pngData = $qrCode->writeString();
$this->assertTrue(is_string($pngData));
}
public function testSetLogo()
{
$qrCode = new QrCode('QrCode');
$qrCode
->setSize(400)
->setLogoPath(__DIR__.'/../assets/symfony.png')
->setLogoWidth(150)
->setValidateResult(true);
$pngData = $qrCode->writeString();
$this->assertTrue(is_string($pngData));
}
}