Passed
Push — main ( c43715...22ad48 )
by smiley
12:03
created

QREps::module()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 3
eloc 6
nc 2
nop 2
dl 0
loc 13
rs 10
c 1
b 1
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 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
	protected function moduleValueIsValid($value):bool{
29
30
		if(!is_array($value) || count($value) < 3){
31
			return false;
32
		}
33
34
		// check the first 3 values of the array
35
		for($i = 0; $i < 3; $i++){
36
			if(!is_numeric($value[$i])){
37
				return false;
38
			}
39
		}
40
41
		return true;
42
	}
43
44
	/**
45
	 * @inheritDoc
46
	 */
47
	protected function getModuleValue($value):array{
48
		$val = [];
49
50
		for($i = 0; $i < 3; $i++){
51
			// clamp value and convert from 0-255 to 0-1 RGB range
52
			$val[] = round(max(0, min(255, $value[$i])) / 255, 6);
53
		}
54
55
		return $val;
56
	}
57
58
	/**
59
	 * @inheritDoc
60
	 */
61
	protected function getDefaultModuleValue(bool $isDark):array{
62
		return $isDark ? [0.0, 0.0, 0.0] : [1.0, 1.0, 1.0];
63
	}
64
65
	/**
66
	 * @inheritDoc
67
	 */
68
	public function dump(string $file = null):string{
69
		$file ??= $this->options->cachefile;
70
71
		$eps = [
72
			// main header
73
			'%!PS-Adobe-3.0 EPSF-3.0',
74
			'%%Creator: php-qrcode (https://github.com/chillerlan/php-qrcode)',
75
			'%%Title: QR Code',
76
			sprintf('%%%%CreationDate: %1$s', date('c')),
77
			'%%DocumentData: Clean7Bit',
78
			'%%LanguageLevel: 3',
79
			sprintf('%%%%BoundingBox: 0 0 %1$s %1$s', $this->length),
80
			'%%EndComments',
81
			// function definitions
82
			'%%BeginProlog',
83
			'/F { rectfill } def',
84
			'/S { setrgbcolor } def',
85
			'%%EndProlog'
86
		];
87
88
		// create the path elements
89
		$paths = $this->collectModules(fn(int $x, int $y):string => $this->module($x, $y));
90
91
		foreach($paths as $M_TYPE => $path){
92
93
			if(empty($path)){
94
				continue;
95
			}
96
97
			$eps[] = sprintf('%f %f %f S', ...$this->moduleValues[$M_TYPE]);
98
			$eps[] = implode("\n", $path);
99
		}
100
101
		// end file
102
		$eps[] = '%%EOF';
103
104
		$data = implode("\n", $eps);
105
106
		if($file !== null){
107
			$this->saveToFile($data, $file);
108
		}
109
110
		return $data;
111
	}
112
113
	/**
114
	 * returns a path segment for a single module
115
	 */
116
	protected function module(int $x, int $y):string{
117
118
		if(!$this->options->drawLightModules && !$this->matrix->check($x, $y)){
119
			return '';
120
		}
121
122
		$outputX = $x * $this->scale;
123
		// Actual size - one block = Topmost y pos.
124
		$top     = $this->length - $this->scale;
125
		// Apparently y-axis is inverted (y0 is at bottom and not top) in EPS so we have to switch the y-axis here
126
		$outputY = $top - ($y * $this->scale);
127
128
		return sprintf('%d %d %d %d F', $outputX, $outputY, $this->scale, $this->scale);
129
	}
130
131
}
132