PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.4.2
WP 2FA – Two-factor authentication for WordPress v2.4.2
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 / vendor / endroid / qr-code / src / Writer / PngWriter.php
wp-2fa / vendor / endroid / qr-code / src / Writer Last commit date
AbstractWriter.php 3 years ago BinaryWriter.php 3 years ago DebugWriter.php 3 years ago EpsWriter.php 3 years ago FpdfWriter.php 3 years ago PngWriter.php 3 years ago SvgWriter.php 3 years ago WriterInterface.php 3 years ago
PngWriter.php
226 lines
1 <?php
2
3 declare (strict_types=1);
4 /*
5 * (c) Jeroen van den Enden <info@endroid.nl>
6 *
7 * This source file is subject to the MIT license that is bundled
8 * with this source code in the file LICENSE.
9 */
10 namespace WP2FA_Vendor\Endroid\QrCode\Writer;
11
12 use WP2FA_Vendor\Endroid\QrCode\Exception\GenerateImageException;
13 use WP2FA_Vendor\Endroid\QrCode\Exception\MissingFunctionException;
14 use WP2FA_Vendor\Endroid\QrCode\Exception\MissingLogoHeightException;
15 use WP2FA_Vendor\Endroid\QrCode\Exception\ValidationException;
16 use WP2FA_Vendor\Endroid\QrCode\LabelAlignment;
17 use WP2FA_Vendor\Endroid\QrCode\QrCodeInterface;
18 use WP2FA_Vendor\Zxing\QrReader;
19 class PngWriter extends AbstractWriter
20 {
21 public function writeString(QrCodeInterface $qrCode) : string
22 {
23 if (!\extension_loaded('gd')) {
24 throw new GenerateImageException('Unable to generate image: check your GD installation');
25 }
26 $image = $this->createImage($qrCode->getData(), $qrCode);
27 $logoPath = $qrCode->getLogoPath();
28 if (null !== $logoPath) {
29 $image = $this->addLogo($image, $logoPath, $qrCode->getLogoWidth(), $qrCode->getLogoHeight());
30 }
31 $label = $qrCode->getLabel();
32 if (null !== $label) {
33 $image = $this->addLabel($image, $label, $qrCode->getLabelFontPath(), $qrCode->getLabelFontSize(), $qrCode->getLabelAlignment(), $qrCode->getLabelMargin(), $qrCode->getForegroundColor(), $qrCode->getBackgroundColor());
34 }
35 $string = $this->imageToString($image);
36 if (\PHP_VERSION_ID < 80000) {
37 \imagedestroy($image);
38 }
39 if ($qrCode->getValidateResult()) {
40 $reader = new QrReader($string, QrReader::SOURCE_TYPE_BLOB);
41 if ($reader->text() !== $qrCode->getText()) {
42 throw new ValidationException('Built-in validation reader read "' . $reader->text() . '" instead of "' . $qrCode->getText() . '".
43 Adjust your parameters to increase readability or disable built-in validation.');
44 }
45 }
46 return $string;
47 }
48 /**
49 * @param array<mixed> $data
50 *
51 * @return mixed
52 */
53 private function createImage(array $data, QrCodeInterface $qrCode)
54 {
55 $baseSize = $qrCode->getRoundBlockSize() ? $data['block_size'] : 25;
56 $baseImage = $this->createBaseImage($baseSize, $data, $qrCode);
57 $interpolatedImage = $this->createInterpolatedImage($baseImage, $data, $qrCode);
58 if (\PHP_VERSION_ID < 80000) {
59 \imagedestroy($baseImage);
60 }
61 return $interpolatedImage;
62 }
63 /**
64 * @param array<mixed> $data
65 *
66 * @return mixed
67 */
68 private function createBaseImage(int $baseSize, array $data, QrCodeInterface $qrCode)
69 {
70 $image = \imagecreatetruecolor($data['block_count'] * $baseSize, $data['block_count'] * $baseSize);
71 if (!$image) {
72 throw new GenerateImageException('Unable to generate image: check your GD installation');
73 }
74 $foregroundColor = \imagecolorallocatealpha($image, $qrCode->getForegroundColor()['r'], $qrCode->getForegroundColor()['g'], $qrCode->getForegroundColor()['b'], $qrCode->getForegroundColor()['a']);
75 if (!\is_int($foregroundColor)) {
76 throw new GenerateImageException('Foreground color could not be allocated');
77 }
78 $backgroundColor = \imagecolorallocatealpha($image, $qrCode->getBackgroundColor()['r'], $qrCode->getBackgroundColor()['g'], $qrCode->getBackgroundColor()['b'], $qrCode->getBackgroundColor()['a']);
79 if (!\is_int($backgroundColor)) {
80 throw new GenerateImageException('Background color could not be allocated');
81 }
82 \imagefill($image, 0, 0, $backgroundColor);
83 foreach ($data['matrix'] as $row => $values) {
84 foreach ($values as $column => $value) {
85 if (1 === $value) {
86 \imagefilledrectangle($image, $column * $baseSize, $row * $baseSize, \intval(($column + 1) * $baseSize), \intval(($row + 1) * $baseSize), $foregroundColor);
87 }
88 }
89 }
90 return $image;
91 }
92 /**
93 * @param mixed $baseImage
94 * @param array<mixed> $data
95 *
96 * @return mixed
97 */
98 private function createInterpolatedImage($baseImage, array $data, QrCodeInterface $qrCode)
99 {
100 $image = \imagecreatetruecolor($data['outer_width'], $data['outer_height']);
101 if (!$image) {
102 throw new GenerateImageException('Unable to generate image: check your GD installation');
103 }
104 $backgroundColor = \imagecolorallocatealpha($image, $qrCode->getBackgroundColor()['r'], $qrCode->getBackgroundColor()['g'], $qrCode->getBackgroundColor()['b'], $qrCode->getBackgroundColor()['a']);
105 if (!\is_int($backgroundColor)) {
106 throw new GenerateImageException('Background color could not be allocated');
107 }
108 \imagefill($image, 0, 0, $backgroundColor);
109 \imagecopyresampled($image, $baseImage, (int) $data['margin_left'], (int) $data['margin_left'], 0, 0, (int) $data['inner_width'], (int) $data['inner_height'], \imagesx($baseImage), \imagesy($baseImage));
110 if ($qrCode->getBackgroundColor()['a'] > 0) {
111 \imagesavealpha($image, \true);
112 }
113 return $image;
114 }
115 /**
116 * @param mixed $sourceImage
117 *
118 * @return mixed
119 */
120 private function addLogo($sourceImage, string $logoPath, int $logoWidth = null, int $logoHeight = null)
121 {
122 $mimeType = $this->getMimeType($logoPath);
123 $logoImage = \imagecreatefromstring(\strval(\file_get_contents($logoPath)));
124 if ('image/svg+xml' === $mimeType && (null === $logoHeight || null === $logoWidth)) {
125 throw new MissingLogoHeightException('SVG Logos require an explicit height set via setLogoSize($width, $height)');
126 }
127 if (!$logoImage) {
128 throw new GenerateImageException('Unable to generate image: check your GD installation or logo path');
129 }
130 $logoSourceWidth = \imagesx($logoImage);
131 $logoSourceHeight = \imagesy($logoImage);
132 if (null === $logoWidth) {
133 $logoWidth = $logoSourceWidth;
134 }
135 if (null === $logoHeight) {
136 $aspectRatio = $logoWidth / $logoSourceWidth;
137 $logoHeight = \intval($logoSourceHeight * $aspectRatio);
138 }
139 $logoX = \imagesx($sourceImage) / 2 - $logoWidth / 2;
140 $logoY = \imagesy($sourceImage) / 2 - $logoHeight / 2;
141 \imagecopyresampled($sourceImage, $logoImage, \intval($logoX), \intval($logoY), 0, 0, $logoWidth, $logoHeight, $logoSourceWidth, $logoSourceHeight);
142 if (\PHP_VERSION_ID < 80000) {
143 \imagedestroy($logoImage);
144 }
145 return $sourceImage;
146 }
147 /**
148 * @param mixed $sourceImage
149 * @param array<int> $labelMargin
150 * @param array<int> $foregroundColor
151 * @param array<int> $backgroundColor
152 *
153 * @return mixed
154 */
155 private function addLabel($sourceImage, string $label, string $labelFontPath, int $labelFontSize, string $labelAlignment, array $labelMargin, array $foregroundColor, array $backgroundColor)
156 {
157 if (!\function_exists('imagettfbbox')) {
158 throw new MissingFunctionException('Missing function "imagettfbbox", please make sure you installed the FreeType library');
159 }
160 $labelBox = \imagettfbbox($labelFontSize, 0, $labelFontPath, $label);
161 if (!$labelBox) {
162 throw new GenerateImageException('Unable to add label: check your GD installation');
163 }
164 $labelBoxWidth = \intval($labelBox[2] - $labelBox[0]);
165 $labelBoxHeight = \intval($labelBox[0] - $labelBox[7]);
166 $sourceWidth = \imagesx($sourceImage);
167 $sourceHeight = \imagesy($sourceImage);
168 $targetWidth = $sourceWidth;
169 $targetHeight = $sourceHeight + $labelBoxHeight + $labelMargin['t'] + $labelMargin['b'];
170 // Create empty target image
171 $targetImage = \imagecreatetruecolor($targetWidth, $targetHeight);
172 if (!$targetImage) {
173 throw new GenerateImageException('Unable to generate image: check your GD installation');
174 }
175 $foregroundColor = \imagecolorallocate($targetImage, $foregroundColor['r'], $foregroundColor['g'], $foregroundColor['b']);
176 if (!\is_int($foregroundColor)) {
177 throw new GenerateImageException('Foreground color could not be allocated');
178 }
179 $backgroundColor = \imagecolorallocate($targetImage, $backgroundColor['r'], $backgroundColor['g'], $backgroundColor['b']);
180 if (!\is_int($backgroundColor)) {
181 throw new GenerateImageException('Background color could not be allocated');
182 }
183 \imagefill($targetImage, 0, 0, $backgroundColor);
184 // Copy source image to target image
185 \imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $sourceWidth, $sourceHeight, $sourceWidth, $sourceHeight);
186 if (\PHP_VERSION_ID < 80000) {
187 \imagedestroy($sourceImage);
188 }
189 switch ($labelAlignment) {
190 case LabelAlignment::LEFT:
191 $labelX = $labelMargin['l'];
192 break;
193 case LabelAlignment::RIGHT:
194 $labelX = $targetWidth - $labelBoxWidth - $labelMargin['r'];
195 break;
196 default:
197 $labelX = \intval($targetWidth / 2 - $labelBoxWidth / 2);
198 break;
199 }
200 $labelY = $targetHeight - $labelMargin['b'];
201 \imagettftext($targetImage, $labelFontSize, 0, $labelX, $labelY, $foregroundColor, $labelFontPath, $label);
202 return $targetImage;
203 }
204 /**
205 * @param mixed $image
206 */
207 private function imageToString($image) : string
208 {
209 \ob_start();
210 \imagepng($image);
211 return (string) \ob_get_clean();
212 }
213 public static function getContentType() : string
214 {
215 return 'image/png';
216 }
217 public static function getSupportedExtensions() : array
218 {
219 return ['png'];
220 }
221 public function getName() : string
222 {
223 return 'png';
224 }
225 }
226