PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 4.0.0
WP 2FA – Two-factor authentication for WordPress v4.0.0
4.0.0 1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / includes / classes / bacon / bacon-qr-code / src / Renderer / Image / ImagickImageBackEnd.php
wp-2fa / includes / classes / bacon / bacon-qr-code / src / Renderer / Image Last commit date
EpsImageBackEnd.php 1 week ago ImageBackEndInterface.php 1 week ago ImagickImageBackEnd.php 1 week ago SvgImageBackEnd.php 1 week ago TransformationMatrix.php 1 week ago index.php 1 week ago
ImagickImageBackEnd.php
224 lines
1 <?php
2
3 declare (strict_types=1);
4 namespace WP2FA_Vendor\BaconQrCode\Renderer\Image;
5
6 use WP2FA_Vendor\BaconQrCode\Exception\RuntimeException;
7 use WP2FA_Vendor\BaconQrCode\Renderer\Color\Alpha;
8 use WP2FA_Vendor\BaconQrCode\Renderer\Color\Cmyk;
9 use WP2FA_Vendor\BaconQrCode\Renderer\Color\ColorInterface;
10 use WP2FA_Vendor\BaconQrCode\Renderer\Color\Gray;
11 use WP2FA_Vendor\BaconQrCode\Renderer\Color\Rgb;
12 use WP2FA_Vendor\BaconQrCode\Renderer\Path\Close;
13 use WP2FA_Vendor\BaconQrCode\Renderer\Path\Curve;
14 use WP2FA_Vendor\BaconQrCode\Renderer\Path\EllipticArc;
15 use WP2FA_Vendor\BaconQrCode\Renderer\Path\Line;
16 use WP2FA_Vendor\BaconQrCode\Renderer\Path\Move;
17 use WP2FA_Vendor\BaconQrCode\Renderer\Path\Path;
18 use WP2FA_Vendor\BaconQrCode\Renderer\RendererStyle\Gradient;
19 use WP2FA_Vendor\BaconQrCode\Renderer\RendererStyle\GradientType;
20 use Imagick;
21 use ImagickDraw;
22 use ImagickPixel;
23 final class ImagickImageBackEnd implements ImageBackEndInterface
24 {
25 /**
26 * @var string
27 */
28 private $imageFormat;
29 /**
30 * @var int
31 */
32 private $compressionQuality;
33 /**
34 * @var Imagick|null
35 */
36 private $image;
37 /**
38 * @var ImagickDraw|null
39 */
40 private $draw;
41 /**
42 * @var int|null
43 */
44 private $gradientCount;
45 /**
46 * @var TransformationMatrix[]|null
47 */
48 private $matrices;
49 /**
50 * @var int|null
51 */
52 private $matrixIndex;
53 public function __construct(string $imageFormat = 'png', int $compressionQuality = 100)
54 {
55 if (!\class_exists(Imagick::class)) {
56 throw new RuntimeException('You need to install the imagick extension to use this back end');
57 }
58 $this->imageFormat = $imageFormat;
59 $this->compressionQuality = $compressionQuality;
60 }
61 public function new(int $size, ColorInterface $backgroundColor) : void
62 {
63 $this->image = new Imagick();
64 $this->image->newImage($size, $size, $this->getColorPixel($backgroundColor));
65 $this->image->setImageFormat($this->imageFormat);
66 $this->image->setCompressionQuality($this->compressionQuality);
67 $this->draw = new ImagickDraw();
68 $this->gradientCount = 0;
69 $this->matrices = [new TransformationMatrix()];
70 $this->matrixIndex = 0;
71 }
72 public function scale(float $size) : void
73 {
74 if (null === $this->draw) {
75 throw new RuntimeException('No image has been started');
76 }
77 $this->draw->scale($size, $size);
78 $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex]->multiply(TransformationMatrix::scale($size));
79 }
80 public function translate(float $x, float $y) : void
81 {
82 if (null === $this->draw) {
83 throw new RuntimeException('No image has been started');
84 }
85 $this->draw->translate($x, $y);
86 $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex]->multiply(TransformationMatrix::translate($x, $y));
87 }
88 public function rotate(int $degrees) : void
89 {
90 if (null === $this->draw) {
91 throw new RuntimeException('No image has been started');
92 }
93 $this->draw->rotate($degrees);
94 $this->matrices[$this->matrixIndex] = $this->matrices[$this->matrixIndex]->multiply(TransformationMatrix::rotate($degrees));
95 }
96 public function push() : void
97 {
98 if (null === $this->draw) {
99 throw new RuntimeException('No image has been started');
100 }
101 $this->draw->push();
102 $this->matrices[++$this->matrixIndex] = $this->matrices[$this->matrixIndex - 1];
103 }
104 public function pop() : void
105 {
106 if (null === $this->draw) {
107 throw new RuntimeException('No image has been started');
108 }
109 $this->draw->pop();
110 unset($this->matrices[$this->matrixIndex--]);
111 }
112 public function drawPathWithColor(Path $path, ColorInterface $color) : void
113 {
114 if (null === $this->draw) {
115 throw new RuntimeException('No image has been started');
116 }
117 $this->draw->setFillColor($this->getColorPixel($color));
118 $this->drawPath($path);
119 }
120 public function drawPathWithGradient(Path $path, Gradient $gradient, float $x, float $y, float $width, float $height) : void
121 {
122 if (null === $this->draw) {
123 throw new RuntimeException('No image has been started');
124 }
125 $this->draw->setFillPatternURL('#' . $this->createGradientFill($gradient, $x, $y, $width, $height));
126 $this->drawPath($path);
127 }
128 public function done() : string
129 {
130 if (null === $this->draw) {
131 throw new RuntimeException('No image has been started');
132 }
133 $this->image->drawImage($this->draw);
134 $blob = $this->image->getImageBlob();
135 $this->draw->clear();
136 $this->image->clear();
137 $this->draw = null;
138 $this->image = null;
139 $this->gradientCount = null;
140 return $blob;
141 }
142 private function drawPath(Path $path) : void
143 {
144 $this->draw->pathStart();
145 foreach ($path as $op) {
146 switch (\true) {
147 case $op instanceof Move:
148 $this->draw->pathMoveToAbsolute($op->getX(), $op->getY());
149 break;
150 case $op instanceof Line:
151 $this->draw->pathLineToAbsolute($op->getX(), $op->getY());
152 break;
153 case $op instanceof EllipticArc:
154 $this->draw->pathEllipticArcAbsolute($op->getXRadius(), $op->getYRadius(), $op->getXAxisAngle(), $op->isLargeArc(), $op->isSweep(), $op->getX(), $op->getY());
155 break;
156 case $op instanceof Curve:
157 $this->draw->pathCurveToAbsolute($op->getX1(), $op->getY1(), $op->getX2(), $op->getY2(), $op->getX3(), $op->getY3());
158 break;
159 case $op instanceof Close:
160 $this->draw->pathClose();
161 break;
162 default:
163 throw new RuntimeException('Unexpected draw operation: ' . \get_class($op));
164 }
165 }
166 $this->draw->pathFinish();
167 }
168 private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : string
169 {
170 list($width, $height) = $this->matrices[$this->matrixIndex]->apply($width, $height);
171 $startColor = $this->getColorPixel($gradient->getStartColor())->getColorAsString();
172 $endColor = $this->getColorPixel($gradient->getEndColor())->getColorAsString();
173 $gradientImage = new Imagick();
174 switch ($gradient->getType()) {
175 case GradientType::HORIZONTAL():
176 $gradientImage->newPseudoImage((int) $height, (int) $width, \sprintf('gradient:%s-%s', $startColor, $endColor));
177 $gradientImage->rotateImage('transparent', -90);
178 break;
179 case GradientType::VERTICAL():
180 $gradientImage->newPseudoImage((int) $width, (int) $height, \sprintf('gradient:%s-%s', $startColor, $endColor));
181 break;
182 case GradientType::DIAGONAL():
183 case GradientType::INVERSE_DIAGONAL():
184 $gradientImage->newPseudoImage((int) ($width * \sqrt(2)), (int) ($height * \sqrt(2)), \sprintf('gradient:%s-%s', $startColor, $endColor));
185 if (GradientType::DIAGONAL() === $gradient->getType()) {
186 $gradientImage->rotateImage('transparent', -45);
187 } else {
188 $gradientImage->rotateImage('transparent', -135);
189 }
190 $rotatedWidth = $gradientImage->getImageWidth();
191 $rotatedHeight = $gradientImage->getImageHeight();
192 $gradientImage->setImagePage($rotatedWidth, $rotatedHeight, 0, 0);
193 $gradientImage->cropImage(\intdiv($rotatedWidth, 2) - 2, \intdiv($rotatedHeight, 2) - 2, \intdiv($rotatedWidth, 4) + 1, \intdiv($rotatedWidth, 4) + 1);
194 break;
195 case GradientType::RADIAL():
196 $gradientImage->newPseudoImage((int) $width, (int) $height, \sprintf('radial-gradient:%s-%s', $startColor, $endColor));
197 break;
198 }
199 $id = \sprintf('g%d', ++$this->gradientCount);
200 $this->draw->pushPattern($id, 0, 0, $width, $height);
201 $this->draw->composite(Imagick::COMPOSITE_COPY, 0, 0, $width, $height, $gradientImage);
202 $this->draw->popPattern();
203 return $id;
204 }
205 private function getColorPixel(ColorInterface $color) : ImagickPixel
206 {
207 $alpha = 100;
208 if ($color instanceof Alpha) {
209 $alpha = $color->getAlpha();
210 $color = $color->getBaseColor();
211 }
212 if ($color instanceof Rgb) {
213 return new ImagickPixel(\sprintf('rgba(%d, %d, %d, %F)', $color->getRed(), $color->getGreen(), $color->getBlue(), $alpha / 100));
214 }
215 if ($color instanceof Cmyk) {
216 return new ImagickPixel(\sprintf('cmyka(%d, %d, %d, %d, %F)', $color->getCyan(), $color->getMagenta(), $color->getYellow(), $color->getBlack(), $alpha / 100));
217 }
218 if ($color instanceof Gray) {
219 return new ImagickPixel(\sprintf('graya(%d%%, %F)', $color->getGray(), $alpha / 100));
220 }
221 return $this->getColorPixel(new Alpha($alpha, $color->toRgb()));
222 }
223 }
224