QREps::prepareModuleValue()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 1
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Class QREps
4
 *
5
 * @created      09.05.2022
6
 * @author       smiley <[email protected]>
7
 * @copyright    2022 smiley
8
 * @license      MIT
9
 */
10
11
namespace chillerlan\QRCode\Output;
12
13
use function array_values, count, date, implode, is_array, is_numeric, max, min, round, sprintf;
14
15
/**
16
 * Encapsulated Postscript (EPS) output
17
 *
18
 * @see https://github.com/t0k4rt/phpqrcode/blob/bb29e6eb77e0a2a85bb0eb62725e0adc11ff5a90/qrvect.php#L52-L137
19
 * @see https://web.archive.org/web/20170818010030/http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/postscript/pdfs/5002.EPSF_Spec.pdf
20
 * @see https://web.archive.org/web/20210419003859/https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf
21
 * @see https://github.com/chillerlan/php-qrcode/discussions/148
22
 */
23
class QREps extends QROutputAbstract{
24
25
	/**
26
	 * @inheritDoc
27
	 */
28
	public static function moduleValueIsValid($value):bool{
29
30
		if(!is_array($value) || count($value) < 3){
31
			return false;
32
		}
33
34
		// check the first values of the array
35
		foreach(array_values($value) as $i => $val){
36
37
			if($i > 3){
38
				break;
39
			}
40
41
			if(!is_numeric($val)){
42
				return false;
43
			}
44
45
		}
46
47
		return true;
48
	}
49
50
	/**
51
	 * @param array $value
52
	 *
53
	 * @inheritDoc
54
	 */
55
	protected function prepareModuleValue($value):array{
56
		$values = [];
57
58
		foreach(array_values($value) as $i => $val){
59
60
			if($i > 3){
61
				break;
62
			}
63
64
			// clamp value and convert from int 0-255 to float 0-1 RGB/CMYK range
65
			$values[] = round((max(0, min(255, intval($val))) / 255), 6);
66
		}
67
68
		return $values;
69
	}
70
71
	/**
72
	 * @inheritDoc
73
	 */
74
	protected function getDefaultModuleValue(bool $isDark):array{
75
		return ($isDark) ? [0.0, 0.0, 0.0] : [1.0, 1.0, 1.0];
76
	}
77
78
	/**
79
	 * @inheritDoc
80
	 */
81
	public function dump(string $file = null):string{
82
83
		$eps = [
84
			// main header
85
			'%!PS-Adobe-3.0 EPSF-3.0',
86
			'%%Creator: php-qrcode (https://github.com/chillerlan/php-qrcode)',
87
			'%%Title: QR Code',
88
			sprintf('%%%%CreationDate: %1$s', date('c')),
89
			'%%DocumentData: Clean7Bit',
90
			'%%LanguageLevel: 3',
91
			sprintf('%%%%BoundingBox: 0 0 %1$s %1$s', $this->length),
92
			'%%EndComments',
93
			// function definitions
94
			'%%BeginProlog',
95
			'/F { rectfill } def',
96
			'/R { setrgbcolor } def',
97
			'/C { setcmykcolor } def',
98
			'%%EndProlog',
99
		];
100
101
		// create the path elements
102
		$paths = $this->collectModules(fn(int $x, int $y):string => $this->module($x, $y));
103
104
		foreach($paths as $M_TYPE => $path){
105
106
			if(empty($path)){
107
				continue;
108
			}
109
110
			// 4 values will be interpreted as CMYK, 3 as RGB
111
			$val    = $this->getModuleValue($M_TYPE);
112
			$format = (count($val) === 4) ? '%f %f %f %f C' : '%f %f %f R';
0 ignored issues
show
Bug introduced by
It seems like $val can also be of type null; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

112
			$format = (count(/** @scrutinizer ignore-type */ $val) === 4) ? '%f %f %f %f C' : '%f %f %f R';
Loading history...
113
			$eps[]  = sprintf($format, ...$val);
114
			$eps[]  = implode("\n", $path);
115
		}
116
117
		// end file
118
		$eps[] = '%%EOF';
119
120
		$data = implode("\n", $eps);
121
122
		$this->saveToFile($data, $file);
123
124
		return $data;
125
	}
126
127
	/**
128
	 * returns a path segment for a single module
129
	 */
130
	protected function module(int $x, int $y):string{
131
132
		if(!$this->options->drawLightModules && !$this->matrix->check($x, $y)){
133
			return '';
134
		}
135
136
		$outputX = ($x * $this->scale);
137
		// Actual size - one block = Topmost y pos.
138
		$top     = ($this->length - $this->scale);
139
		// Apparently y-axis is inverted (y0 is at bottom and not top) in EPS, so we have to switch the y-axis here
140
		$outputY = ($top - ($y * $this->scale));
141
142
		return sprintf('%d %d %d %d F', $outputX, $outputY, $this->scale, $this->scale);
143
	}
144
145
}
146