添加网站文件

This commit is contained in:
2025-12-22 13:59:40 +08:00
commit 117aaf83d1
19468 changed files with 2111999 additions and 0 deletions

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();
}