mirror of
https://github.com/elyby/accounts.git
synced 2024-12-23 13:50:06 +05:30
Реализация генератора QR-кодов с логотипом Ely.by
This commit is contained in:
parent
c15361ddbe
commit
bb1fd1a960
@ -1,4 +1,4 @@
|
||||
FROM registry.ely.by/elyby/accounts-php:1.2.0
|
||||
FROM registry.ely.by/elyby/accounts-php:1.3.0
|
||||
|
||||
# Вносим конфигурации для крона и воркеров
|
||||
COPY docker/cron/* /etc/cron.d/
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM registry.ely.by/elyby/accounts-php:1.2.0-dev
|
||||
FROM registry.ely.by/elyby/accounts-php:1.3.0-dev
|
||||
|
||||
# Вносим конфигурации для крона и воркеров
|
||||
COPY docker/cron/* /etc/cron.d/
|
||||
|
116
common/components/Qr/ElyDecorator.php
Normal file
116
common/components/Qr/ElyDecorator.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
namespace common\components\Qr;
|
||||
|
||||
use BaconQrCode\Common\ErrorCorrectionLevel;
|
||||
use BaconQrCode\Encoder\QrCode;
|
||||
use BaconQrCode\Renderer\Image\Decorator\DecoratorInterface;
|
||||
use BaconQrCode\Renderer\Image\RendererInterface;
|
||||
use BaconQrCode\Renderer\Image\Svg;
|
||||
use Imagick;
|
||||
use InvalidArgumentException;
|
||||
use ReflectionClass;
|
||||
|
||||
class ElyDecorator implements DecoratorInterface {
|
||||
|
||||
private const LOGO = __DIR__ . '/resources/logo.svg';
|
||||
|
||||
private const CORRECTION_MAP = [
|
||||
ErrorCorrectionLevel::L => 7,
|
||||
ErrorCorrectionLevel::M => 15,
|
||||
ErrorCorrectionLevel::Q => 25,
|
||||
ErrorCorrectionLevel::H => 30,
|
||||
];
|
||||
|
||||
public function preProcess(
|
||||
QrCode $qrCode,
|
||||
RendererInterface $renderer,
|
||||
$outputWidth,
|
||||
$outputHeight,
|
||||
$leftPadding,
|
||||
$topPadding,
|
||||
$multiple
|
||||
) {
|
||||
if (!$renderer instanceof Svg) {
|
||||
throw new InvalidArgumentException('$renderer must by instance of ' . Svg::class);
|
||||
}
|
||||
|
||||
$correctionLevel = self::CORRECTION_MAP[$qrCode->getErrorCorrectionLevel()->get()];
|
||||
$sizeMultiplier = $correctionLevel + floor($correctionLevel / 3);
|
||||
$count = $qrCode->getMatrix()->getWidth();
|
||||
|
||||
$countToRemoveX = floor($count * $sizeMultiplier / 100);
|
||||
$countToRemoveY = floor($count * $sizeMultiplier / 100);
|
||||
|
||||
$startX = $leftPadding + round(($count - $countToRemoveX) / 2 * $multiple);
|
||||
$startY = $topPadding + round(($count - $countToRemoveY) / 2 * $multiple);
|
||||
$width = $countToRemoveX * $multiple;
|
||||
$height = $countToRemoveY * $multiple;
|
||||
|
||||
$reflection = new ReflectionClass($renderer);
|
||||
$property = $reflection->getProperty('svg');
|
||||
$property->setAccessible(true);
|
||||
/** @var \SimpleXMLElement $svg */
|
||||
$svg = $property->getValue($renderer);
|
||||
|
||||
$image = $svg->addChild('image');
|
||||
$image->addAttribute('x', $startX);
|
||||
$image->addAttribute('y', $startY);
|
||||
$image->addAttribute('width', $width);
|
||||
$image->addAttribute('height', $height);
|
||||
$image->addAttribute('xlink:href', $this->encodeSvgToBase64(self::LOGO));
|
||||
|
||||
$logo = new Imagick();
|
||||
$logo->readImage(self::LOGO);
|
||||
$logo->scaleImage($width, $height);
|
||||
|
||||
$foundedPixels = [];
|
||||
foreach ($logo->getPixelIterator() as $row => $pixels) {
|
||||
/** @var \ImagickPixel[] $pixels */
|
||||
foreach ($pixels as $column => $pixel) {
|
||||
$color = $pixel->getColorAsString();
|
||||
if ($color !== 'srgb(255,255,255)') {
|
||||
$foundedPixels[] = [(int)($startX + $column), (int)($startY + $row)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$logo->clear();
|
||||
$logo->destroy();
|
||||
|
||||
$padding = $multiple - 2;
|
||||
if ($padding < 0) {
|
||||
$padding = 1;
|
||||
}
|
||||
|
||||
foreach ($foundedPixels as $coordinates) {
|
||||
[$x, $y] = $coordinates;
|
||||
$x -= $leftPadding;
|
||||
$y -= $topPadding;
|
||||
|
||||
for ($i = $x - $padding; $i <= $x + $padding; $i++) {
|
||||
for ($j = $y - $padding; $j <= $y + $padding; $j++) {
|
||||
$matrixX = floor($i / $multiple);
|
||||
$matrixY = floor($j / $multiple);
|
||||
$qrCode->getMatrix()->set($matrixX, $matrixY, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function postProcess(
|
||||
QrCode $qrCode,
|
||||
RendererInterface $renderer,
|
||||
$outputWidth,
|
||||
$outputHeight,
|
||||
$leftPadding,
|
||||
$topPadding,
|
||||
$multiple
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
private function encodeSvgToBase64(string $filePath): string {
|
||||
return 'data:image/svg+xml;base64,' . base64_encode(file_get_contents($filePath));
|
||||
}
|
||||
|
||||
}
|
6
common/components/Qr/resources/logo.svg
Normal file
6
common/components/Qr/resources/logo.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 389 365.16" style="fill:#207e5c">
|
||||
<polygon points="130 161 37 161 37 257 145 257 145 285 0 285 0 19 144 19 144 47 37 47 37 133 130 133 130 161 130 161" />
|
||||
<polygon points="213 285 177 285 177 0 213 0 213 285 213 285" />
|
||||
<path d="M319,246.42l34-142h42l-66,227c-5.07,17.07-10.54,30.61-20,39.49S291.1,382.58,279,382.58c-4.67,0-13.89-1.65-21-3.16l4.11-27s18.89,1.78,22.69-4.37c4.54-4.26,8.71-13.46,12.21-24.48l6-23.16-58-196h41l33,142h0Z" transform="translate(-6 -17.42)" />
|
||||
</svg>
|
After Width: | Height: | Size: 582 B |
@ -28,7 +28,9 @@
|
||||
"ely/email-renderer": "dev-master#ef1cb3f7a13196524b97ca5aa0a2d5867f2d9207",
|
||||
"predis/predis": "^1.0",
|
||||
"mito/yii2-sentry": "dev-fix_init#27f00805cb906f73b2c6f8181c1c655decb9be70",
|
||||
"minime/annotations": "~3.0"
|
||||
"minime/annotations": "~3.0",
|
||||
"spomky-labs/otphp": "^8.3",
|
||||
"bacon/bacon-qr-code": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"yiisoft/yii2-codeception": "*",
|
||||
|
Loading…
Reference in New Issue
Block a user