Passed
Push — main ( 9e2681...b6777f )
by smiley
02:24
created

QROptionsTrait::set_logoSpaceHeight()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 2
rs 10
1
<?php
2
/**
3
 * Trait QROptionsTrait
4
 *
5
 * @created      10.03.2018
6
 * @author       smiley <[email protected]>
7
 * @copyright    2018 smiley
8
 * @license      MIT
9
 *
10
 * @noinspection PhpUnused
11
 */
12
13
namespace chillerlan\QRCode;
14
15
use chillerlan\QRCode\Common\EccLevel;
16
17
use chillerlan\QRCode\Decoder\{GDLuminanceSource, IMagickLuminanceSource};
18
use function array_values, count, extension_loaded, in_array, is_numeric, max, min, sprintf, strtolower;
19
20
/**
21
 * The QRCode plug-in settings & setter functionality
22
 */
23
trait QROptionsTrait{
24
25
	/**
26
	 * QR Code version number
27
	 *
28
	 * [1 ... 40] or QRCode::VERSION_AUTO
29
	 */
30
	protected int $version = QRCode::VERSION_AUTO;
31
32
	/**
33
	 * Minimum QR version
34
	 *
35
	 * if $version = QRCode::VERSION_AUTO
36
	 */
37
	protected int $versionMin = 1;
38
39
	/**
40
	 * Maximum QR version
41
	 */
42
	protected int $versionMax = 40;
43
44
	/**
45
	 * Error correct level
46
	 *
47
	 * QRCode::ECC_X where X is:
48
	 *
49
	 *   - L =>  7%
50
	 *   - M => 15%
51
	 *   - Q => 25%
52
	 *   - H => 30%
53
	 */
54
	protected int $eccLevel = EccLevel::L;
55
56
	/**
57
	 * Mask Pattern to use (no value in using, mostly for unit testing purposes)
58
	 *
59
	 * [0...7] or QRCode::MASK_PATTERN_AUTO
60
	 */
61
	protected int $maskPattern = QRCode::MASK_PATTERN_AUTO;
62
63
	/**
64
	 * Add a "quiet zone" (margin) according to the QR code spec
65
	 */
66
	protected bool $addQuietzone = true;
67
68
	/**
69
	 * Size of the quiet zone
70
	 *
71
	 * internally clamped to [0 ... $moduleCount / 2], defaults to 4 modules
72
	 */
73
	protected int $quietzoneSize = 4;
74
75
	/**
76
	 * The output type
77
	 *
78
	 *   - QRCode::OUTPUT_MARKUP_XXXX where XXXX = HTML, SVG
79
	 *   - QRCode::OUTPUT_IMAGE_XXX where XXX = PNG, GIF, JPG
80
	 *   - QRCode::OUTPUT_STRING_XXXX where XXXX = TEXT, JSON
81
	 *   - QRCode::OUTPUT_CUSTOM
82
	 */
83
	protected string $outputType = QRCode::OUTPUT_MARKUP_SVG;
84
85
	/**
86
	 * the FQCN of the custom QROutputInterface if $outputType is set to QRCode::OUTPUT_CUSTOM
87
	 */
88
	protected ?string $outputInterface = null;
89
90
	/**
91
	 * /path/to/cache.file
92
	 */
93
	protected ?string $cachefile = null;
94
95
	/**
96
	 * newline string [HTML, SVG, TEXT]
97
	 */
98
	protected string $eol = PHP_EOL;
99
100
	/**
101
	 * size of a QR code pixel [SVG, IMAGE_*], HTML via CSS
102
	 */
103
	protected int $scale = 5;
104
105
	/**
106
	 * a common css class
107
	 */
108
	protected string $cssClass = 'qrcode';
109
110
	/**
111
	 * SVG opacity
112
	 */
113
	protected float $svgOpacity = 1.0;
114
115
	/**
116
	 * anything between <defs>
117
	 *
118
	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
119
	 */
120
	protected string $svgDefs = '';
121
122
	/**
123
	 * SVG viewBox size. a single integer number which defines width/height of the viewBox attribute.
124
	 *
125
	 * viewBox="0 0 x x"
126
	 *
127
	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
128
	 * @see https://css-tricks.com/scale-svg/#article-header-id-3
129
	 */
130
	protected ?int $svgViewBoxSize = null;
131
132
	/**
133
	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio
134
	 */
135
	protected string $svgPreserveAspectRatio = 'xMidYMid';
136
137
	/**
138
	 * optional "width" attribute with the specified value (note that the value is not checked!)
139
	 *
140
	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width
141
	 */
142
	protected ?string $svgWidth = null;
143
144
	/**
145
	 * optional "height" attribute with the specified value (note that the value is not checked!)
146
	 *
147
	 * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height
148
	 */
149
	protected ?string $svgHeight = null;
150
151
	/**
152
	 * whether to connect the paths for the several module types to avoid weird glitches when using gradients etc.
153
	 *
154
	 * @see https://github.com/chillerlan/php-qrcode/issues/57
155
	 */
156
	protected bool $svgConnectPaths = false;
157
158
	/**
159
	 * specify which paths/patterns to exclude from connecting if $svgConnectPaths is set to true
160
	 */
161
	protected array $svgExcludeFromConnect = [];
162
163
	/**
164
	 * specify whether to draw the modules as filled circles
165
	 *
166
	 * @see https://github.com/chillerlan/php-qrcode/issues/23
167
	 */
168
	protected bool $drawCircularModules = false;
169
170
	/**
171
	 * specifies the radius of the modules when $svgDrawCircularModules is set to true
172
	 */
173
	protected float $circleRadius = 0.45;
174
175
	/**
176
	 * specifies which module types to exclude when $svgDrawCircularModules is set to true
177
	 */
178
	protected array $keepAsSquare = [];
179
180
	/**
181
	 * string substitute for dark
182
	 */
183
	protected string $textDark = '🔴';
184
185
	/**
186
	 * string substitute for light
187
	 */
188
	protected string $textLight = '⭕';
189
190
	/**
191
	 * markup substitute for dark (CSS value)
192
	 */
193
	protected string $markupDark = '#000';
194
195
	/**
196
	 * markup substitute for light (CSS value)
197
	 */
198
	protected string $markupLight = '#fff';
199
200
	/**
201
	 * Return the image resource instead of a render if applicable.
202
	 * This option overrides other output options, such as $cachefile and $imageBase64.
203
	 *
204
	 * Supported by the following modules:
205
	 *
206
	 * - QRImage:   resource (PHP < 8), GdImage
207
	 * - QRImagick: Imagick
208
	 * - QRFpdf:    FPDF
209
	 *
210
	 * @see \chillerlan\QRCode\Output\QROutputInterface::dump()
211
	 *
212
	 * @var bool
213
	 */
214
	protected bool $returnResource = false;
215
216
	/**
217
	 * toggle base64 or raw image data
218
	 */
219
	protected bool $imageBase64 = true;
220
221
	/**
222
	 * toggle transparency, not supported by jpg
223
	 */
224
	protected bool $imageTransparent = true;
225
226
	/**
227
	 * @see imagecolortransparent()
228
	 *
229
	 * [R, G, B]
230
	 */
231
	protected array $imageTransparencyBG = [255, 255, 255];
232
233
	/**
234
	 * @see imagepng()
235
	 */
236
	protected int $pngCompression = -1;
237
238
	/**
239
	 * @see imagejpeg()
240
	 */
241
	protected int $jpegQuality = 85;
242
243
	/**
244
	 * Imagick output format
245
	 *
246
	 * @see \Imagick::setImageFormat()
247
	 * @see https://www.imagemagick.org/script/formats.php
248
	 */
249
	protected string $imagickFormat = 'png32';
250
251
	/**
252
	 * Imagick background color (defaults to "transparent")
253
	 *
254
	 * @see \ImagickPixel::__construct()
255
	 */
256
	protected ?string $imagickBG = null;
257
258
	/**
259
	 * Measurement unit for FPDF output: pt, mm, cm, in (defaults to "pt")
260
	 *
261
	 * @see \FPDF::__construct()
262
	 */
263
	protected string $fpdfMeasureUnit = 'pt';
264
265
	/**
266
	 * Module values map
267
	 *
268
	 *   - HTML, IMAGICK: #ABCDEF, cssname, rgb(), rgba()...
269
	 *   - IMAGE: [63, 127, 255] // R, G, B
270
	 */
271
	protected ?array $moduleValues = null;
272
273
	/**
274
	 * use Imaagick (if available) when reading QR Codes
275
	 */
276
	protected bool $readerUseImagickIfAvailable = false;
277
278
	/**
279
	 * grayscale the image before reading
280
	 */
281
	protected bool $readerGrayscale = false;
282
283
	/**
284
	 * increase the contrast before reading
285
	 *
286
	 * note that applying contrast works different in GD and Imagick, so mileage may vary
287
	 */
288
	protected bool $readerIncreaseContrast = false;
289
290
	/**
291
	 * Toggles logo space creation
292
	 */
293
	protected bool $addLogoSpace = false;
294
295
	/**
296
	 * width of the logo space
297
	 */
298
	protected int $logoSpaceWidth = 0;
299
300
	/**
301
	 * height of the logo space
302
	 */
303
	protected int $logoSpaceHeight = 0;
304
305
	/**
306
	 * optional horizontal start position of the logo space (top left corner)
307
	 */
308
	protected ?int $logoSpaceStartX = null;
309
310
	/**
311
	 * optional vertical start position of the logo space (top left corner)
312
	 */
313
	protected ?int $logoSpaceStartY = null;
314
315
	/**
316
	 * clamp min/max version number
317
	 */
318
	protected function setMinMaxVersion(int $versionMin, int $versionMax):void{
319
		$min = max(1, min(40, $versionMin));
320
		$max = max(1, min(40, $versionMax));
321
322
		$this->versionMin = min($min, $max);
323
		$this->versionMax = max($min, $max);
324
	}
325
326
	/**
327
	 * sets the minimum version number
328
	 */
329
	protected function set_versionMin(int $version):void{
330
		$this->setMinMaxVersion($version, $this->versionMax);
331
	}
332
333
	/**
334
	 * sets the maximum version number
335
	 */
336
	protected function set_versionMax(int $version):void{
337
		$this->setMinMaxVersion($this->versionMin, $version);
338
	}
339
340
	/**
341
	 * sets the error correction level
342
	 *
343
	 * @throws \chillerlan\QRCode\QRCodeException
344
	 */
345
	protected function set_eccLevel(int $eccLevel):void{
346
347
		if(!in_array($eccLevel, [EccLevel::L, EccLevel::M, EccLevel::Q, EccLevel::H], true)){
348
			throw new QRCodeException(sprintf('Invalid error correct level: %s', $eccLevel));
349
		}
350
351
		$this->eccLevel = $eccLevel;
352
	}
353
354
	/**
355
	 * sets/clamps the mask pattern
356
	 */
357
	protected function set_maskPattern(int $maskPattern):void{
358
359
		if($maskPattern !== QRCode::MASK_PATTERN_AUTO){
360
			$this->maskPattern = max(0, min(7, $maskPattern));
361
		}
362
363
	}
364
365
	/**
366
	 * sets the transparency background color
367
	 *
368
	 * @throws \chillerlan\QRCode\QRCodeException
369
	 */
370
	protected function set_imageTransparencyBG(array $imageTransparencyBG):void{
371
372
		// invalid value - set to white as default
373
		if(count($imageTransparencyBG) < 3){
374
			$this->imageTransparencyBG = [255, 255, 255];
375
376
			return;
377
		}
378
379
		foreach($imageTransparencyBG as $k => $v){
380
381
			// cut off exceeding items
382
			if($k > 2){
383
				break;
384
			}
385
386
			if(!is_numeric($v)){
387
				throw new QRCodeException('Invalid RGB value.');
388
			}
389
390
			// clamp the values
391
			$this->imageTransparencyBG[$k] = max(0, min(255, (int)$v));
392
		}
393
394
		// use the array values to not run into errors with the spread operator (...$arr)
395
		$this->imageTransparencyBG = array_values($this->imageTransparencyBG);
396
	}
397
398
	/**
399
	 * sets/clamps the version number
400
	 */
401
	protected function set_version(int $version):void{
402
403
		if($version !== QRCode::VERSION_AUTO){
404
			$this->version = max(1, min(40, $version));
405
		}
406
407
	}
408
409
	/**
410
	 * sets the FPDF measurement unit
411
	 *
412
	 * @codeCoverageIgnore
413
	 */
414
	protected function set_fpdfMeasureUnit(string $unit):void{
415
		$unit = strtolower($unit);
416
417
		if(in_array($unit, ['cm', 'in', 'mm', 'pt'], true)){
418
			$this->fpdfMeasureUnit = $unit;
419
		}
420
421
		// @todo throw or ignore silently?
422
	}
423
424
	/**
425
	 * enables Imagick for the QR Code reader if the extension is available
426
	 */
427
	protected function set_readerUseImagickIfAvailable(bool $useImagickIfAvailable):void{
428
		$this->readerUseImagickIfAvailable = $useImagickIfAvailable && extension_loaded('imagick');
429
	}
430
431
	/**
432
	 * returns the FQCN of the luminance source class to use in the reader (GD or Imagick)
433
	 *
434
	 * @see \chillerlan\QRCode\Decoder\LuminanceSourceInterface
435
	 */
436
	public function getLuminanceSourceFQCN():string{
437
		// i still hate this
438
		return $this->readerUseImagickIfAvailable
439
			? IMagickLuminanceSource::class
440
			: GDLuminanceSource::class;
441
	}
442
443
	/**
444
	 * clamp the logo space values between 0 and maximum length (177 modules at version 40)
445
	 */
446
	protected function clampLogoSpaceValue(int $value):int{
447
		return (int)max(0, min(177, $value));
448
	}
449
450
	/**
451
	 * clamp/set logo space width
452
	 */
453
	protected function set_logoSpaceWidth(int $value):void{
454
		$this->logoSpaceWidth = $this->clampLogoSpaceValue($value);
455
	}
456
457
	/**
458
	 * clamp/set logo space height
459
	 */
460
	protected function set_logoSpaceHeight(int $value):void{
461
		$this->logoSpaceHeight = $this->clampLogoSpaceValue($value);
462
	}
463
464
	/**
465
	 * clamp/set horizontal logo space start
466
	 */
467
	protected function set_logoSpaceStartX(?int $value):void{
468
		$this->logoSpaceStartX = $value === null ? null : $this->clampLogoSpaceValue($value);
469
	}
470
471
	/**
472
	 * clamp/set vertical logo space start
473
	 */
474
	protected function set_logoSpaceStartY(?int $value):void{
475
		$this->logoSpaceStartY = $value === null ? null : $this->clampLogoSpaceValue($value);
476
	}
477
478
	/**
479
	 * clamp/set SVG circle radius
480
	 */
481
	protected function set_circleRadius(float $circleRadius):void{
482
		$this->circleRadius = max(0.1, min(0.75, $circleRadius));
483
	}
484
485
}
486