PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.4
Booking for Appointments and Events Calendar – Amelia v2.4.4
2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / vendor / bacon / bacon-qr-code / src / Renderer / Image / EpsImageBackEnd.php
ameliabooking / vendor / bacon / bacon-qr-code / src / Renderer / Image Last commit date
EpsImageBackEnd.php 8 months ago ImageBackEndInterface.php 8 months ago ImagickImageBackEnd.php 8 months ago SvgImageBackEnd.php 8 months ago TransformationMatrix.php 8 months ago
EpsImageBackEnd.php
377 lines
1 <?php
2 declare(strict_types = 1);
3
4 namespace BaconQrCode\Renderer\Image;
5
6 use BaconQrCode\Exception\RuntimeException;
7 use BaconQrCode\Renderer\Color\Alpha;
8 use BaconQrCode\Renderer\Color\Cmyk;
9 use BaconQrCode\Renderer\Color\ColorInterface;
10 use BaconQrCode\Renderer\Color\Gray;
11 use BaconQrCode\Renderer\Color\Rgb;
12 use BaconQrCode\Renderer\Path\Close;
13 use BaconQrCode\Renderer\Path\Curve;
14 use BaconQrCode\Renderer\Path\EllipticArc;
15 use BaconQrCode\Renderer\Path\Line;
16 use BaconQrCode\Renderer\Path\Move;
17 use BaconQrCode\Renderer\Path\Path;
18 use BaconQrCode\Renderer\RendererStyle\Gradient;
19 use BaconQrCode\Renderer\RendererStyle\GradientType;
20
21 final class EpsImageBackEnd implements ImageBackEndInterface
22 {
23 private const PRECISION = 3;
24
25 /**
26 * @var string|null
27 */
28 private $eps;
29
30 public function new(int $size, ColorInterface $backgroundColor) : void
31 {
32 $this->eps = "%!PS-Adobe-3.0 EPSF-3.0\n"
33 . "%%Creator: BaconQrCode\n"
34 . sprintf("%%%%BoundingBox: 0 0 %d %d \n", $size, $size)
35 . "%%BeginProlog\n"
36 . "save\n"
37 . "50 dict begin\n"
38 . "/q { gsave } bind def\n"
39 . "/Q { grestore } bind def\n"
40 . "/s { scale } bind def\n"
41 . "/t { translate } bind def\n"
42 . "/r { rotate } bind def\n"
43 . "/n { newpath } bind def\n"
44 . "/m { moveto } bind def\n"
45 . "/l { lineto } bind def\n"
46 . "/c { curveto } bind def\n"
47 . "/z { closepath } bind def\n"
48 . "/f { eofill } bind def\n"
49 . "/rgb { setrgbcolor } bind def\n"
50 . "/cmyk { setcmykcolor } bind def\n"
51 . "/gray { setgray } bind def\n"
52 . "%%EndProlog\n"
53 . "1 -1 s\n"
54 . sprintf("0 -%d t\n", $size);
55
56 if ($backgroundColor instanceof Alpha && 0 === $backgroundColor->getAlpha()) {
57 return;
58 }
59
60 $this->eps .= wordwrap(
61 '0 0 m'
62 . sprintf(' %s 0 l', (string) $size)
63 . sprintf(' %s %s l', (string) $size, (string) $size)
64 . sprintf(' 0 %s l', (string) $size)
65 . ' z'
66 . ' ' .$this->getColorSetString($backgroundColor) . " f\n",
67 75,
68 "\n "
69 );
70 }
71
72 public function scale(float $size) : void
73 {
74 if (null === $this->eps) {
75 throw new RuntimeException('No image has been started');
76 }
77
78 $this->eps .= sprintf("%1\$s %1\$s s\n", round($size, self::PRECISION));
79 }
80
81 public function translate(float $x, float $y) : void
82 {
83 if (null === $this->eps) {
84 throw new RuntimeException('No image has been started');
85 }
86
87 $this->eps .= sprintf("%s %s t\n", round($x, self::PRECISION), round($y, self::PRECISION));
88 }
89
90 public function rotate(int $degrees) : void
91 {
92 if (null === $this->eps) {
93 throw new RuntimeException('No image has been started');
94 }
95
96 $this->eps .= sprintf("%d r\n", $degrees);
97 }
98
99 public function push() : void
100 {
101 if (null === $this->eps) {
102 throw new RuntimeException('No image has been started');
103 }
104
105 $this->eps .= "q\n";
106 }
107
108 public function pop() : void
109 {
110 if (null === $this->eps) {
111 throw new RuntimeException('No image has been started');
112 }
113
114 $this->eps .= "Q\n";
115 }
116
117 public function drawPathWithColor(Path $path, ColorInterface $color) : void
118 {
119 if (null === $this->eps) {
120 throw new RuntimeException('No image has been started');
121 }
122
123 $fromX = 0;
124 $fromY = 0;
125 $this->eps .= wordwrap(
126 'n '
127 . $this->drawPathOperations($path, $fromX, $fromY)
128 . ' ' . $this->getColorSetString($color) . " f\n",
129 75,
130 "\n "
131 );
132 }
133
134 public function drawPathWithGradient(
135 Path $path,
136 Gradient $gradient,
137 float $x,
138 float $y,
139 float $width,
140 float $height
141 ) : void {
142 if (null === $this->eps) {
143 throw new RuntimeException('No image has been started');
144 }
145
146 $fromX = 0;
147 $fromY = 0;
148 $this->eps .= wordwrap(
149 'q n ' . $this->drawPathOperations($path, $fromX, $fromY) . "\n",
150 75,
151 "\n "
152 );
153
154 $this->createGradientFill($gradient, $x, $y, $width, $height);
155 }
156
157 public function done() : string
158 {
159 if (null === $this->eps) {
160 throw new RuntimeException('No image has been started');
161 }
162
163 $this->eps .= "%%TRAILER\nend restore\n%%EOF";
164 $blob = $this->eps;
165 $this->eps = null;
166
167 return $blob;
168 }
169
170 private function drawPathOperations(Iterable $ops, &$fromX, &$fromY) : string
171 {
172 $pathData = [];
173
174 foreach ($ops as $op) {
175 switch (true) {
176 case $op instanceof Move:
177 $fromX = $toX = round($op->getX(), self::PRECISION);
178 $fromY = $toY = round($op->getY(), self::PRECISION);
179 $pathData[] = sprintf('%s %s m', $toX, $toY);
180 break;
181
182 case $op instanceof Line:
183 $fromX = $toX = round($op->getX(), self::PRECISION);
184 $fromY = $toY = round($op->getY(), self::PRECISION);
185 $pathData[] = sprintf('%s %s l', $toX, $toY);
186 break;
187
188 case $op instanceof EllipticArc:
189 $pathData[] = $this->drawPathOperations($op->toCurves($fromX, $fromY), $fromX, $fromY);
190 break;
191
192 case $op instanceof Curve:
193 $x1 = round($op->getX1(), self::PRECISION);
194 $y1 = round($op->getY1(), self::PRECISION);
195 $x2 = round($op->getX2(), self::PRECISION);
196 $y2 = round($op->getY2(), self::PRECISION);
197 $fromX = $x3 = round($op->getX3(), self::PRECISION);
198 $fromY = $y3 = round($op->getY3(), self::PRECISION);
199 $pathData[] = sprintf('%s %s %s %s %s %s c', $x1, $y1, $x2, $y2, $x3, $y3);
200 break;
201
202 case $op instanceof Close:
203 $pathData[] = 'z';
204 break;
205
206 default:
207 throw new RuntimeException('Unexpected draw operation: ' . get_class($op));
208 }
209 }
210
211 return implode(' ', $pathData);
212 }
213
214 private function createGradientFill(Gradient $gradient, float $x, float $y, float $width, float $height) : void
215 {
216 $startColor = $gradient->getStartColor();
217 $endColor = $gradient->getEndColor();
218
219 if ($startColor instanceof Alpha) {
220 $startColor = $startColor->getBaseColor();
221 }
222
223 $startColorType = get_class($startColor);
224
225 if (! in_array($startColorType, [Rgb::class, Cmyk::class, Gray::class])) {
226 $startColorType = Cmyk::class;
227 $startColor = $startColor->toCmyk();
228 }
229
230 if (get_class($endColor) !== $startColorType) {
231 switch ($startColorType) {
232 case Cmyk::class:
233 $endColor = $endColor->toCmyk();
234 break;
235
236 case Rgb::class:
237 $endColor = $endColor->toRgb();
238 break;
239
240 case Gray::class:
241 $endColor = $endColor->toGray();
242 break;
243 }
244 }
245
246 $this->eps .= "eoclip\n<<\n";
247
248 if ($gradient->getType() === GradientType::RADIAL()) {
249 $this->eps .= " /ShadingType 3\n";
250 } else {
251 $this->eps .= " /ShadingType 2\n";
252 }
253
254 $this->eps .= " /Extend [ true true ]\n"
255 . " /AntiAlias true\n";
256
257 switch ($startColorType) {
258 case Cmyk::class:
259 $this->eps .= " /ColorSpace /DeviceCMYK\n";
260 break;
261
262 case Rgb::class:
263 $this->eps .= " /ColorSpace /DeviceRGB\n";
264 break;
265
266 case Gray::class:
267 $this->eps .= " /ColorSpace /DeviceGray\n";
268 break;
269 }
270
271 switch ($gradient->getType()) {
272 case GradientType::HORIZONTAL():
273 $this->eps .= sprintf(
274 " /Coords [ %s %s %s %s ]\n",
275 round($x, self::PRECISION),
276 round($y, self::PRECISION),
277 round($x + $width, self::PRECISION),
278 round($y, self::PRECISION)
279 );
280 break;
281
282 case GradientType::VERTICAL():
283 $this->eps .= sprintf(
284 " /Coords [ %s %s %s %s ]\n",
285 round($x, self::PRECISION),
286 round($y, self::PRECISION),
287 round($x, self::PRECISION),
288 round($y + $height, self::PRECISION)
289 );
290 break;
291
292 case GradientType::DIAGONAL():
293 $this->eps .= sprintf(
294 " /Coords [ %s %s %s %s ]\n",
295 round($x, self::PRECISION),
296 round($y, self::PRECISION),
297 round($x + $width, self::PRECISION),
298 round($y + $height, self::PRECISION)
299 );
300 break;
301
302 case GradientType::INVERSE_DIAGONAL():
303 $this->eps .= sprintf(
304 " /Coords [ %s %s %s %s ]\n",
305 round($x, self::PRECISION),
306 round($y + $height, self::PRECISION),
307 round($x + $width, self::PRECISION),
308 round($y, self::PRECISION)
309 );
310 break;
311
312 case GradientType::RADIAL():
313 $centerX = ($x + $width) / 2;
314 $centerY = ($y + $height) / 2;
315
316 $this->eps .= sprintf(
317 " /Coords [ %s %s 0 %s %s %s ]\n",
318 round($centerX, self::PRECISION),
319 round($centerY, self::PRECISION),
320 round($centerX, self::PRECISION),
321 round($centerY, self::PRECISION),
322 round(max($width, $height) / 2, self::PRECISION)
323 );
324 break;
325 }
326
327 $this->eps .= " /Function\n"
328 . " <<\n"
329 . " /FunctionType 2\n"
330 . " /Domain [ 0 1 ]\n"
331 . sprintf(" /C0 [ %s ]\n", $this->getColorString($startColor))
332 . sprintf(" /C1 [ %s ]\n", $this->getColorString($endColor))
333 . " /N 1\n"
334 . " >>\n>>\nshfill\nQ\n";
335 }
336
337 private function getColorSetString(ColorInterface $color) : string
338 {
339 if ($color instanceof Rgb) {
340 return $this->getColorString($color) . ' rgb';
341 }
342
343 if ($color instanceof Cmyk) {
344 return $this->getColorString($color) . ' cmyk';
345 }
346
347 if ($color instanceof Gray) {
348 return $this->getColorString($color) . ' gray';
349 }
350
351 return $this->getColorSetString($color->toCmyk());
352 }
353
354 private function getColorString(ColorInterface $color) : string
355 {
356 if ($color instanceof Rgb) {
357 return sprintf('%s %s %s', $color->getRed() / 255, $color->getGreen() / 255, $color->getBlue() / 255);
358 }
359
360 if ($color instanceof Cmyk) {
361 return sprintf(
362 '%s %s %s %s',
363 $color->getCyan() / 100,
364 $color->getMagenta() / 100,
365 $color->getYellow() / 100,
366 $color->getBlack() / 100
367 );
368 }
369
370 if ($color instanceof Gray) {
371 return sprintf('%s', $color->getGray() / 100);
372 }
373
374 return $this->getColorString($color->toCmyk());
375 }
376 }
377