1 | <?php |
||||||
2 | |||||||
3 | namespace Smindel\GIS\Service; |
||||||
4 | |||||||
5 | use SilverStripe\Core\Injector\Injectable; |
||||||
6 | use SilverStripe\Core\Config\Configurable; |
||||||
7 | use Imagick; |
||||||
8 | use ImagickDraw; |
||||||
9 | use ImagickPixel; |
||||||
10 | |||||||
11 | // @todo: extending imagick makes it a hard dependency, so don't |
||||||
12 | |||||||
13 | class ImagickRenderer |
||||||
14 | { |
||||||
15 | use Injectable; |
||||||
16 | |||||||
17 | use Configurable; |
||||||
18 | |||||||
19 | const LIB_NAME = 'Imagick'; |
||||||
20 | |||||||
21 | protected $width; |
||||||
22 | |||||||
23 | protected $height; |
||||||
24 | |||||||
25 | protected $list; |
||||||
26 | |||||||
27 | protected $image; |
||||||
28 | |||||||
29 | protected $defaultStyle; |
||||||
30 | |||||||
31 | public function __construct($width, $height, $defaultStyle = []) |
||||||
32 | { |
||||||
33 | $this->width = $width; |
||||||
34 | $this->height = $height; |
||||||
35 | $this->defaultStyle = $defaultStyle['imagick']; |
||||||
36 | |||||||
37 | $this->image = new Imagick(); |
||||||
38 | |||||||
39 | $this->image->newImage($this->width, $this->height, new ImagickPixel('rgba(0,0,0,0)')); |
||||||
40 | $this->image->setImageFormat('png'); |
||||||
41 | |||||||
42 | if ($this->defaultStyle['marker'] ?? 0) { |
||||||
43 | switch ($this->defaultStyle['marker']['offset'][0] ?? 0) { |
||||||
44 | case 'left': $this->defaultStyle['marker_offset_x'] = 0; break; |
||||||
45 | case 'center': $this->defaultStyle['marker_offset_x'] = getimagesize($this->defaultStyle['marker']['image'])[0] / 2; break; |
||||||
46 | case 'right': $this->defaultStyle['marker_offset_x'] = getimagesize($this->defaultStyle['marker']['image'])[0]; break; |
||||||
47 | default: $this->defaultStyle['marker_offset_x'] = $this->defaultStyle['marker']['offset'][0] ?? 0; |
||||||
48 | } |
||||||
49 | switch ($this->defaultStyle['marker']['offset'][1] ?? 0) { |
||||||
50 | case 'top': $this->defaultStyle['marker_offset_y'] = 0; break; |
||||||
51 | case 'middle': $this->defaultStyle['marker_offset_y'] = getimagesize($this->defaultStyle['marker']['image'])[1] / 2; break; |
||||||
52 | case 'bottom': $this->defaultStyle['marker_offset_y'] = getimagesize($this->defaultStyle['marker']['image'])[1]; break; |
||||||
53 | default: $this->defaultStyle['marker_offset_y'] = $this->defaultStyle['marker']['offset'][0] ?? 0; |
||||||
54 | } |
||||||
55 | |||||||
56 | $this->defaultStyle['marker_image'] = new Imagick(); |
||||||
57 | $this->defaultStyle['marker_image']->readImage($this->defaultStyle['marker']['image']); |
||||||
58 | } |
||||||
59 | } |
||||||
60 | |||||||
61 | public function debug($text) |
||||||
62 | { |
||||||
63 | $draw = new ImagickDraw(); |
||||||
64 | $draw->setStrokeOpacity(1); |
||||||
65 | $draw->setStrokeColor(new ImagickPixel('rgb(92,92,255)')); |
||||||
66 | $draw->setFillColor(new ImagickPixel('rgba(92,92,255,0)')); |
||||||
67 | $draw->setStrokeDashArray([5, 5]); |
||||||
68 | $draw->setStrokeWidth(1); |
||||||
69 | |||||||
70 | $draw->polyline([ |
||||||
71 | ['x' => 0, 'y' => 255], |
||||||
72 | ['x' => 0, 'y' => 0], |
||||||
73 | ['x' => 255, 'y' => 0], |
||||||
74 | ]); |
||||||
75 | |||||||
76 | $draw->setStrokeDashArray([0]); |
||||||
77 | $draw->setFont('DejaVu-Sans'); |
||||||
78 | $draw->setFontSize(15); |
||||||
79 | $draw->setFontWeight(700); |
||||||
80 | $draw->setStrokeAntialias(true); |
||||||
81 | $draw->setTextAntialias(true); |
||||||
82 | |||||||
83 | $draw->annotation(5, 15, $text); |
||||||
84 | |||||||
85 | $this->image->drawImage($draw); |
||||||
86 | } |
||||||
87 | |||||||
88 | public function getContentType() |
||||||
89 | { |
||||||
90 | return 'image/png'; |
||||||
91 | } |
||||||
92 | |||||||
93 | public function getDraw(&$style) |
||||||
94 | { |
||||||
95 | if ($style instanceof ImagickDraw) { |
||||||
96 | return $style; |
||||||
97 | } |
||||||
98 | |||||||
99 | $style = array_merge($this->defaultStyle, $style); |
||||||
100 | |||||||
101 | $draw = new ImagickDraw(); |
||||||
102 | |||||||
103 | foreach ($style as $key => $value) { |
||||||
104 | if (substr($key, -5) == 'Color') { |
||||||
105 | $value = new ImagickPixel($value); |
||||||
106 | } |
||||||
107 | |||||||
108 | if ($value !== null) { |
||||||
109 | if (!is_array($value)) { |
||||||
110 | $value = [$value]; |
||||||
111 | } |
||||||
112 | if (method_exists($draw, $key)) { |
||||||
113 | $draw->$key(...$value); |
||||||
114 | } elseif (method_exists($draw, 'set' . $key)) { |
||||||
115 | $draw->{'set' . $key}(...$value); |
||||||
116 | } |
||||||
117 | } |
||||||
118 | } |
||||||
119 | |||||||
120 | return $draw; |
||||||
121 | } |
||||||
122 | |||||||
123 | public function drawMarker($coordinates, $style = []) |
||||||
124 | { |
||||||
125 | if (!count($style)) { |
||||||
126 | $this->getDraw($style); |
||||||
127 | } |
||||||
128 | |||||||
129 | $this->image->compositeImage($style['marker_image'], imagick::COMPOSITE_OVER, $coordinates[0] - $style['marker_offset_x'], $coordinates[1] - $style['marker_offset_y']); |
||||||
130 | } |
||||||
131 | |||||||
132 | public function drawCircle($coordinates, $style = []) |
||||||
133 | { |
||||||
134 | $draw = $this->getDraw($style); |
||||||
135 | |||||||
136 | list($x, $y) = $coordinates; |
||||||
137 | $draw->circle($x, $y, $x + $style['PointRadius'], $y + $style['PointRadius']); |
||||||
138 | |||||||
139 | $this->image->drawImage($draw); |
||||||
140 | } |
||||||
141 | |||||||
142 | public function drawPoint($coordinates, $style = []) |
||||||
143 | { |
||||||
144 | $this->getDraw($style); |
||||||
145 | |||||||
146 | if (isset($style['marker_image'])) { |
||||||
147 | $this->drawMarker($coordinates, $style); |
||||||
148 | } else { |
||||||
149 | $this->drawCircle($coordinates, $style); |
||||||
150 | } |
||||||
151 | } |
||||||
152 | |||||||
153 | public function drawLineString($coordinates, $style = []) |
||||||
154 | { |
||||||
155 | $draw = $this->getDraw($style); |
||||||
156 | |||||||
157 | $points = []; |
||||||
158 | foreach ($coordinates as $j => $coordinate) { |
||||||
159 | $points[$j] = ['x' => $coordinate[0], 'y' => $coordinate[1]]; |
||||||
160 | } |
||||||
161 | |||||||
162 | $draw->polyline($points); |
||||||
163 | |||||||
164 | $this->image->drawImage($draw); |
||||||
165 | } |
||||||
166 | |||||||
167 | public function drawPolygon($coordinates, $style = []) |
||||||
168 | { |
||||||
169 | $draw = $this->getDraw($style); |
||||||
170 | |||||||
171 | $draw->pathStart(); |
||||||
172 | foreach ($coordinates as $ring) { |
||||||
173 | $draw->pathMoveToAbsolute(...array_shift($ring)); |
||||||
0 ignored issues
–
show
|
|||||||
174 | foreach ($ring as $point) { |
||||||
175 | $draw->pathLineToAbsolute(...$point); |
||||||
0 ignored issues
–
show
The call to
ImagickDraw::pathLineToAbsolute() has too few arguments starting with y .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
176 | } |
||||||
177 | $draw->pathclose(); |
||||||
178 | } |
||||||
179 | $draw->pathFinish(); |
||||||
180 | $this->image->drawImage($draw); |
||||||
181 | } |
||||||
182 | |||||||
183 | public function drawMultipoint($multiCoordinates, $style = []) |
||||||
184 | { |
||||||
185 | foreach ($multiCoordinates as $coordinates) { |
||||||
186 | $this->drawPoint($coordinates, $style); |
||||||
187 | } |
||||||
188 | } |
||||||
189 | |||||||
190 | public function drawMultilinestring($multiCoordinates, $style = []) |
||||||
191 | { |
||||||
192 | foreach ($multiCoordinates as $coordinates) { |
||||||
193 | $this->drawLinestring($coordinates, $style); |
||||||
194 | } |
||||||
195 | } |
||||||
196 | |||||||
197 | public function drawMultipolygon($multiCoordinates, $style = []) |
||||||
198 | { |
||||||
199 | foreach ($multiCoordinates as $coordinates) { |
||||||
200 | $this->drawPolygon($coordinates, $style); |
||||||
201 | } |
||||||
202 | } |
||||||
203 | |||||||
204 | public function getImageBlob() |
||||||
205 | { |
||||||
206 | return $this->image->getImageBlob(); |
||||||
207 | } |
||||||
208 | } |
||||||
209 |
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.