|
4 | 4 |
|
5 | 5 | namespace Endroid\QrCode\Writer; |
6 | 6 |
|
7 | | -use Endroid\QrCode\Bacon\MatrixFactory; |
8 | | -use Endroid\QrCode\Exception\ValidationException; |
9 | | -use Endroid\QrCode\ImageData\LabelImageData; |
10 | | -use Endroid\QrCode\ImageData\LogoImageData; |
11 | | -use Endroid\QrCode\Label\LabelAlignment; |
12 | 7 | use Endroid\QrCode\Label\LabelInterface; |
13 | 8 | use Endroid\QrCode\Logo\LogoInterface; |
14 | | -use Endroid\QrCode\Matrix\MatrixInterface; |
15 | 9 | use Endroid\QrCode\QrCodeInterface; |
16 | | -use Endroid\QrCode\RoundBlockSizeMode; |
17 | 10 | use Endroid\QrCode\Writer\Result\GdResult; |
18 | 11 | use Endroid\QrCode\Writer\Result\ResultInterface; |
19 | | -use Zxing\QrReader; |
20 | 12 |
|
| 13 | +/** |
| 14 | + * @deprecated since 6.0, use GdWriter instead. This class will be removed in 7.0. |
| 15 | + */ |
21 | 16 | abstract class AbstractGdWriter implements WriterInterface, ValidatingWriterInterface |
22 | 17 | { |
23 | | - protected function getMatrix(QrCodeInterface $qrCode): MatrixInterface |
24 | | - { |
25 | | - $matrixFactory = new MatrixFactory(); |
26 | | - |
27 | | - return $matrixFactory->create($qrCode); |
28 | | - } |
29 | | - |
30 | | - public function write(QrCodeInterface $qrCode, ?LogoInterface $logo = null, ?LabelInterface $label = null, array $options = []): ResultInterface |
31 | | - { |
32 | | - if (!extension_loaded('gd')) { |
33 | | - throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly'); |
34 | | - } |
35 | | - |
36 | | - $matrix = $this->getMatrix($qrCode); |
37 | | - |
38 | | - $baseBlockSize = RoundBlockSizeMode::None === $qrCode->getRoundBlockSizeMode() ? 10 : intval($matrix->getBlockSize()); |
39 | | - /** @var int<1, max> $baseImageSize */ |
40 | | - $baseImageSize = $matrix->getBlockCount() * $baseBlockSize; |
41 | | - $baseImage = imagecreatetruecolor($baseImageSize, $baseImageSize); |
42 | | - |
43 | | - if (!$baseImage) { |
44 | | - throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly'); |
45 | | - } |
46 | | - |
47 | | - $foregroundColor = imagecolorallocatealpha( |
48 | | - $baseImage, |
49 | | - $qrCode->getForegroundColor()->getRed(), |
50 | | - $qrCode->getForegroundColor()->getGreen(), |
51 | | - $qrCode->getForegroundColor()->getBlue(), |
52 | | - $qrCode->getForegroundColor()->getAlpha() |
53 | | - ); |
54 | | - |
55 | | - if (false === $foregroundColor) { |
56 | | - throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly'); |
57 | | - } |
58 | | - |
59 | | - $transparentColor = imagecolorallocatealpha($baseImage, 255, 255, 255, 127); |
60 | | - |
61 | | - if (false === $transparentColor) { |
62 | | - throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly'); |
63 | | - } |
64 | | - |
65 | | - imagefill($baseImage, 0, 0, $transparentColor); |
66 | | - |
67 | | - for ($rowIndex = 0; $rowIndex < $matrix->getBlockCount(); ++$rowIndex) { |
68 | | - for ($columnIndex = 0; $columnIndex < $matrix->getBlockCount(); ++$columnIndex) { |
69 | | - if (1 === $matrix->getBlockValue($rowIndex, $columnIndex)) { |
70 | | - imagefilledrectangle( |
71 | | - $baseImage, |
72 | | - $columnIndex * $baseBlockSize, |
73 | | - $rowIndex * $baseBlockSize, |
74 | | - ($columnIndex + 1) * $baseBlockSize - 1, |
75 | | - ($rowIndex + 1) * $baseBlockSize - 1, |
76 | | - $foregroundColor |
77 | | - ); |
78 | | - } |
79 | | - } |
80 | | - } |
81 | | - |
82 | | - /** @var int<1, max> $targetWidth */ |
83 | | - $targetWidth = $matrix->getOuterSize(); |
84 | | - /** @var int<1, max> $targetHeight */ |
85 | | - $targetHeight = $matrix->getOuterSize(); |
86 | | - |
87 | | - if ($label instanceof LabelInterface) { |
88 | | - $labelImageData = LabelImageData::createForLabel($label); |
89 | | - $targetHeight += $labelImageData->getHeight() + $label->getMargin()->getTop() + $label->getMargin()->getBottom(); |
90 | | - } |
91 | | - |
92 | | - /** @var int<1, max> $targetHeight */ |
93 | | - $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); |
94 | | - |
95 | | - if (!$targetImage) { |
96 | | - throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly'); |
97 | | - } |
98 | | - |
99 | | - $backgroundColor = imagecolorallocatealpha( |
100 | | - $targetImage, |
101 | | - $qrCode->getBackgroundColor()->getRed(), |
102 | | - $qrCode->getBackgroundColor()->getGreen(), |
103 | | - $qrCode->getBackgroundColor()->getBlue(), |
104 | | - $qrCode->getBackgroundColor()->getAlpha() |
105 | | - ); |
106 | | - |
107 | | - if (false === $backgroundColor) { |
108 | | - throw new \Exception('Unable to generate image: please check if the GD extension is enabled and configured correctly'); |
109 | | - } |
110 | | - |
111 | | - imagefill($targetImage, 0, 0, $backgroundColor); |
112 | | - |
113 | | - imagecopyresampled( |
114 | | - $targetImage, |
115 | | - $baseImage, |
116 | | - $matrix->getMarginLeft(), |
117 | | - $matrix->getMarginLeft(), |
118 | | - 0, |
119 | | - 0, |
120 | | - $matrix->getInnerSize(), |
121 | | - $matrix->getInnerSize(), |
122 | | - imagesx($baseImage), |
123 | | - imagesy($baseImage) |
124 | | - ); |
| 18 | + private GdWriter $gdWriter; |
125 | 19 |
|
126 | | - if ($qrCode->getBackgroundColor()->getAlpha() > 0) { |
127 | | - imagesavealpha($targetImage, true); |
128 | | - } |
129 | | - |
130 | | - $result = new GdResult($matrix, $targetImage); |
131 | | - |
132 | | - if ($logo instanceof LogoInterface) { |
133 | | - $result = $this->addLogo($logo, $result); |
134 | | - } |
135 | | - |
136 | | - if ($label instanceof LabelInterface) { |
137 | | - $result = $this->addLabel($label, $result); |
138 | | - } |
139 | | - |
140 | | - return $result; |
141 | | - } |
142 | | - |
143 | | - private function addLogo(LogoInterface $logo, GdResult $result): GdResult |
| 20 | + public function __construct() |
144 | 21 | { |
145 | | - $logoImageData = LogoImageData::createForLogo($logo); |
146 | | - |
147 | | - if ('image/svg+xml' === $logoImageData->getMimeType()) { |
148 | | - throw new \Exception('PNG Writer does not support SVG logo'); |
149 | | - } |
150 | | - |
151 | | - $targetImage = $result->getImage(); |
152 | | - $matrix = $result->getMatrix(); |
153 | | - |
154 | | - if ($logoImageData->getPunchoutBackground()) { |
155 | | - $transparent = imagecolorallocatealpha($targetImage, 255, 255, 255, 127); |
156 | | - |
157 | | - if (false === $transparent) { |
158 | | - throw new \Exception('Unable to allocate color: please check if the GD extension is enabled and configured correctly'); |
159 | | - } |
160 | | - |
161 | | - imagealphablending($targetImage, false); |
162 | | - $xOffsetStart = intval($matrix->getOuterSize() / 2 - $logoImageData->getWidth() / 2); |
163 | | - $yOffsetStart = intval($matrix->getOuterSize() / 2 - $logoImageData->getHeight() / 2); |
164 | | - for ($xOffset = $xOffsetStart; $xOffset < $xOffsetStart + $logoImageData->getWidth(); ++$xOffset) { |
165 | | - for ($yOffset = $yOffsetStart; $yOffset < $yOffsetStart + $logoImageData->getHeight(); ++$yOffset) { |
166 | | - imagesetpixel($targetImage, $xOffset, $yOffset, $transparent); |
167 | | - } |
168 | | - } |
169 | | - } |
170 | | - |
171 | | - imagecopyresampled( |
172 | | - $targetImage, |
173 | | - $logoImageData->getImage(), |
174 | | - intval($matrix->getOuterSize() / 2 - $logoImageData->getWidth() / 2), |
175 | | - intval($matrix->getOuterSize() / 2 - $logoImageData->getHeight() / 2), |
176 | | - 0, |
177 | | - 0, |
178 | | - $logoImageData->getWidth(), |
179 | | - $logoImageData->getHeight(), |
180 | | - imagesx($logoImageData->getImage()), |
181 | | - imagesy($logoImageData->getImage()) |
182 | | - ); |
183 | | - |
184 | | - return new GdResult($matrix, $targetImage); |
| 22 | + $this->gdWriter = new GdWriter(); |
185 | 23 | } |
186 | 24 |
|
187 | | - private function addLabel(LabelInterface $label, GdResult $result): GdResult |
| 25 | + public function write(QrCodeInterface $qrCode, ?LogoInterface $logo = null, ?LabelInterface $label = null, array $options = []): GdResult |
188 | 26 | { |
189 | | - $targetImage = $result->getImage(); |
190 | | - |
191 | | - $labelImageData = LabelImageData::createForLabel($label); |
192 | | - |
193 | | - $textColor = imagecolorallocatealpha( |
194 | | - $targetImage, |
195 | | - $label->getTextColor()->getRed(), |
196 | | - $label->getTextColor()->getGreen(), |
197 | | - $label->getTextColor()->getBlue(), |
198 | | - $label->getTextColor()->getAlpha() |
199 | | - ); |
200 | | - |
201 | | - if (false === $textColor) { |
202 | | - throw new \Exception('Unable to allocate color: please check if the GD extension is enabled and configured correctly'); |
203 | | - } |
204 | | - |
205 | | - $x = intval(imagesx($targetImage) / 2 - $labelImageData->getWidth() / 2); |
206 | | - $y = imagesy($targetImage) - $label->getMargin()->getBottom(); |
207 | | - |
208 | | - if (LabelAlignment::Left === $label->getAlignment()) { |
209 | | - $x = $label->getMargin()->getLeft(); |
210 | | - } elseif (LabelAlignment::Right === $label->getAlignment()) { |
211 | | - $x = imagesx($targetImage) - $labelImageData->getWidth() - $label->getMargin()->getRight(); |
212 | | - } |
213 | | - |
214 | | - imagettftext($targetImage, $label->getFont()->getSize(), 0, $x, $y, $textColor, $label->getFont()->getPath(), $label->getText()); |
215 | | - |
216 | | - return new GdResult($result->getMatrix(), $targetImage); |
| 27 | + return $this->gdWriter->write($qrCode, $logo, $label, $options); |
217 | 28 | } |
218 | 29 |
|
219 | 30 | public function validateResult(ResultInterface $result, string $expectedData): void |
220 | 31 | { |
221 | | - $string = $result->getString(); |
222 | | - |
223 | | - if (!class_exists(QrReader::class)) { |
224 | | - throw ValidationException::createForMissingPackage('khanamiryan/qrcode-detector-decoder'); |
225 | | - } |
226 | | - |
227 | | - $reader = new QrReader($string, QrReader::SOURCE_TYPE_BLOB); |
228 | | - if ($reader->text() !== $expectedData) { |
229 | | - throw ValidationException::createForInvalidData($expectedData, strval($reader->text())); |
230 | | - } |
| 32 | + $this->gdWriter->validateResult($result, $expectedData); |
231 | 33 | } |
232 | 34 | } |
0 commit comments