ImagickRenderer::getImageBlob()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
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
Bug introduced by
The call to ImagickDraw::pathMoveToAbsolute() 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 ignore-call  annotation

173
            $draw->/** @scrutinizer ignore-call */ 
174
                   pathMoveToAbsolute(...array_shift($ring));

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.

Loading history...
174
            foreach ($ring as $point) {
175
                $draw->pathLineToAbsolute(...$point);
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

175
                $draw->/** @scrutinizer ignore-call */ 
176
                       pathLineToAbsolute(...$point);

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.

Loading history...
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