Passed
Push — main ( 6c3421...547c31 )
by smiley
02:24
created

QROptionsTrait::set_fpdfMeasureUnit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 5
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
	protected bool $svgDrawCircularModules = false;
167
168
	/**
169
	 * specifies the radius of the modules when $svgDrawCircularModules is set to true
170
	 */
171
	protected float $svgCircleRadius = 0.45;
172
173
	/**
174
	 * specifies which module types to exclude when $svgDrawCircularModules is set to true
175
	 */
176
	protected array $svgKeepAsSquare = [];
177
178
	/**
179
	 * string substitute for dark
180
	 */
181
	protected string $textDark = '🔴';
182
183
	/**
184
	 * string substitute for light
185
	 */
186
	protected string $textLight = '⭕';
187
188
	/**
189
	 * markup substitute for dark (CSS value)
190
	 */
191
	protected string $markupDark = '#000';
192
193
	/**
194
	 * markup substitute for light (CSS value)
195
	 */
196
	protected string $markupLight = '#fff';
197
198
	/**
199
	 * Return the image resource instead of a render if applicable.
200
	 * This option overrides other output options, such as $cachefile and $imageBase64.
201
	 *
202
	 * Supported by the following modules:
203
	 *
204
	 * - QRImage:   resource (PHP < 8), GdImage
205
	 * - QRImagick: Imagick
206
	 * - QRFpdf:    FPDF
207
	 *
208
	 * @see \chillerlan\QRCode\Output\QROutputInterface::dump()
209
	 *
210
	 * @var bool
211
	 */
212
	protected bool $returnResource = false;
213
214
	/**
215
	 * toggle base64 or raw image data
216
	 */
217
	protected bool $imageBase64 = true;
218
219
	/**
220
	 * toggle transparency, not supported by jpg
221
	 */
222
	protected bool $imageTransparent = true;
223
224
	/**
225
	 * @see imagecolortransparent()
226
	 *
227
	 * [R, G, B]
228
	 */
229
	protected array $imageTransparencyBG = [255, 255, 255];
230
231
	/**
232
	 * @see imagepng()
233
	 */
234
	protected int $pngCompression = -1;
235
236
	/**
237
	 * @see imagejpeg()
238
	 */
239
	protected int $jpegQuality = 85;
240
241
	/**
242
	 * Imagick output format
243
	 *
244
	 * @see \Imagick::setType()
245
	 */
246
	protected string $imagickFormat = 'png';
247
248
	/**
249
	 * Imagick background color (defaults to "transparent")
250
	 *
251
	 * @see \ImagickPixel::__construct()
252
	 */
253
	protected ?string $imagickBG = null;
254
255
	/**
256
	 * Measurement unit for FPDF output: pt, mm, cm, in (defaults to "pt")
257
	 *
258
	 * @see \FPDF::__construct()
259
	 */
260
	protected string $fpdfMeasureUnit = 'pt';
261
262
	/**
263
	 * Module values map
264
	 *
265
	 *   - HTML, IMAGICK: #ABCDEF, cssname, rgb(), rgba()...
266
	 *   - IMAGE: [63, 127, 255] // R, G, B
267
	 */
268
	protected ?array $moduleValues = null;
269
270
	/**
271
	 * use Imaagick (if available) when reading QR Codes
272
	 */
273
	protected bool $readerUseImagickIfAvailable = false;
274
275
	/**
276
	 * grayscale the image before reading
277
	 */
278
	protected bool $readerGrayscale = false;
279
280
	/**
281
	 * increase the contrast before reading
282
	 *
283
	 * note that applying contrast works different in GD and Imagick, so mileage may vary
284
	 */
285
	protected bool $readerIncreaseContrast = false;
286
287
	/**
288
	 * clamp min/max version number
289
	 */
290
	protected function setMinMaxVersion(int $versionMin, int $versionMax):void{
291
		$min = max(1, min(40, $versionMin));
292
		$max = max(1, min(40, $versionMax));
293
294
		$this->versionMin = min($min, $max);
295
		$this->versionMax = max($min, $max);
296
	}
297
298
	/**
299
	 * sets the minimum version number
300
	 */
301
	protected function set_versionMin(int $version):void{
302
		$this->setMinMaxVersion($version, $this->versionMax);
303
	}
304
305
	/**
306
	 * sets the maximum version number
307
	 */
308
	protected function set_versionMax(int $version):void{
309
		$this->setMinMaxVersion($this->versionMin, $version);
310
	}
311
312
	/**
313
	 * sets the error correction level
314
	 *
315
	 * @throws \chillerlan\QRCode\QRCodeException
316
	 */
317
	protected function set_eccLevel(int $eccLevel):void{
318
319
		if(!in_array($eccLevel, [EccLevel::L, EccLevel::M, EccLevel::Q, EccLevel::H], true)){
320
			throw new QRCodeException(sprintf('Invalid error correct level: %s', $eccLevel));
321
		}
322
323
		$this->eccLevel = $eccLevel;
324
	}
325
326
	/**
327
	 * sets/clamps the mask pattern
328
	 */
329
	protected function set_maskPattern(int $maskPattern):void{
330
331
		if($maskPattern !== QRCode::MASK_PATTERN_AUTO){
332
			$this->maskPattern = max(0, min(7, $maskPattern));
333
		}
334
335
	}
336
337
	/**
338
	 * sets the transparency background color
339
	 *
340
	 * @throws \chillerlan\QRCode\QRCodeException
341
	 */
342
	protected function set_imageTransparencyBG(array $imageTransparencyBG):void{
343
344
		// invalid value - set to white as default
345
		if(count($imageTransparencyBG) < 3){
346
			$this->imageTransparencyBG = [255, 255, 255];
347
348
			return;
349
		}
350
351
		foreach($imageTransparencyBG as $k => $v){
352
353
			// cut off exceeding items
354
			if($k > 2){
355
				break;
356
			}
357
358
			if(!is_numeric($v)){
359
				throw new QRCodeException('Invalid RGB value.');
360
			}
361
362
			// clamp the values
363
			$this->imageTransparencyBG[$k] = max(0, min(255, (int)$v));
364
		}
365
366
		// use the array values to not run into errors with the spread operator (...$arr)
367
		$this->imageTransparencyBG = array_values($this->imageTransparencyBG);
368
	}
369
370
	/**
371
	 * sets/clamps the version number
372
	 */
373
	protected function set_version(int $version):void{
374
375
		if($version !== QRCode::VERSION_AUTO){
376
			$this->version = max(1, min(40, $version));
377
		}
378
379
	}
380
381
	/**
382
	 * sets the FPDF measurement unit
383
	 *
384
	 * @codeCoverageIgnore
385
	 */
386
	protected function set_fpdfMeasureUnit(string $unit):void{
387
		$unit = strtolower($unit);
388
389
		if(in_array($unit, ['cm', 'in', 'mm', 'pt'], true)){
390
			$this->fpdfMeasureUnit = $unit;
391
		}
392
393
		// @todo throw or ignore silently?
394
	}
395
396
	/**
397
	 * enables Imagick for the QR Code reader if the extension is available
398
	 */
399
	protected function set_readerUseImagickIfAvailable(bool $useImagickIfAvailable):void{
400
		$this->readerUseImagickIfAvailable = $useImagickIfAvailable && extension_loaded('imagick');
401
	}
402
403
	/**
404
	 * returns the FQCN of the luminance source class to use in the reader (GD or Imagick)
405
	 *
406
	 * @see \chillerlan\QRCode\Decoder\LuminanceSourceInterface
407
	 */
408
	public function getLuminanceSourceFQCN():string{
409
		// i still hate this
410
		return $this->readerUseImagickIfAvailable
411
			? IMagickLuminanceSource::class
412
			: GDLuminanceSource::class;
413
	}
414
415
}
416