Completed
Push — master ( 3e13e1...ba9fdc )
by Mark
17s queued 13s
created

StaticMap::placeMarkers()   C

Complexity

Conditions 12
Paths 17

Size

Total Lines 100
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 12
eloc 68
c 4
b 1
f 0
nc 17
nop 0
dl 0
loc 100
rs 6.2714

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * Copyright (c) 2012-2022 Mark C. Prins <[email protected]>
4
 *
5
 * In part based on staticMapLite 0.03 available at http://staticmaplite.svn.sourceforge.net/viewvc/staticmaplite/
6
 *
7
 * Copyright (c) 2009 Gerhard Koch <gerhard.koch AT ymail.com>
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
namespace dokuwiki\plugin\openlayersmap;
22
23
use geoPHP\Geometry\Geometry;
0 ignored issues
show
Bug introduced by
The type geoPHP\Geometry\Geometry was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use geoPHP\Geometry\GeometryCollection;
0 ignored issues
show
Bug introduced by
The type geoPHP\Geometry\GeometryCollection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use geoPHP\Geometry\LineString;
0 ignored issues
show
Bug introduced by
The type geoPHP\Geometry\LineString was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use geoPHP\Geometry\Point;
0 ignored issues
show
Bug introduced by
The type geoPHP\Geometry\Point was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use geoPHP\Geometry\Polygon;
0 ignored issues
show
Bug introduced by
The type geoPHP\Geometry\Polygon was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
use geoPHP\geoPHP;
0 ignored issues
show
Bug introduced by
The type geoPHP\geoPHP was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
30
/**
31
 *
32
 * @author Mark C. Prins <[email protected]>
33
 * @author Gerhard Koch <gerhard.koch AT ymail.com>
34
 *
35
 */
36
class StaticMap {
37
38
    // the final output
39
    private $tileSize = 256;
40
    private $tileInfo = array(
41
        // OSM sources
42
        'openstreetmap' => array(
43
            'txt'  => '(c) OpenStreetMap data/ODbl',
44
            'logo' => 'osm_logo.png',
45
            'url'  => 'https://tile.openstreetmap.org/{Z}/{X}/{Y}.png'
46
        ),
47
        // OpenTopoMap sources
48
        'opentopomap' => array(
49
            'txt'  => '(c) OpenStreetMap data/ODbl, SRTM | style: (c) OpenTopoMap',
50
            'logo' => 'osm_logo.png',
51
            'url'  => 'https:/tile.opentopomap.org/{Z}/{X}/{Y}.png'
52
        ),
53
        // OCM sources
54
        'cycle'         => array(
55
            'txt'  => '(c) Thunderforest maps',
56
            'logo' => 'tf_logo.png',
57
            'url'  => 'https://tile.thunderforest.com/cycle/{Z}/{X}/{Y}.png'
58
        ),
59
        'transport'     => array(
60
            'txt'  => '(c) Thunderforest maps',
61
            'logo' => 'tf_logo.png',
62
            'url'  => 'https://tile.thunderforest.com/transport/{Z}/{X}/{Y}.png'
63
        ),
64
        'landscape'     => array(
65
            'txt'  => '(c) Thunderforest maps',
66
            'logo' => 'tf_logo.png',
67
            'url'  => 'https://tile.thunderforest.com/landscape/{Z}/{X}/{Y}.png'
68
        ),
69
        'outdoors'      => array(
70
            'txt'  => '(c) Thunderforest maps',
71
            'logo' => 'tf_logo.png',
72
            'url'  => 'https://tile.thunderforest.com/outdoors/{Z}/{X}/{Y}.png'
73
        ),
74
        'toner-lite'    => array(
75
            'txt'  => 'Stamen tiles',
76
            'logo' => 'stamen.png',
77
            'url'  => 'https://stamen-tiles.a.ssl.fastly.net/toner/{Z}/{X}/{Y}.png'
78
        ),
79
        'terrain'       => array(
80
            'txt'  => 'Stamen tiles',
81
            'logo' => 'stamen.png',
82
            'url'  => 'https://stamen-tiles.a.ssl.fastly.net/terrain/{Z}/{X}/{Y}.jpg'
83
        )
84
        //,
85
        // 'piste'=>array(
86
        // 'txt'=>'OpenPisteMap tiles',
87
        // 'logo'=>'piste_logo.png',
88
        // 'url'=>''),
89
        // 'sea'=>array(
90
        // 'txt'=>'OpenSeaMap tiles',
91
        // 'logo'=>'sea_logo.png',
92
        // 'url'=>''),
93
        // H&B sources
94
        //          'hikeandbike' => array (
95
        //                  'txt' => 'Hike & Bike Map',
96
        //                  'logo' => 'hnb_logo.png',
97
        //                  //'url' => 'http://toolserver.org/tiles/hikebike/{Z}/{X}/{Y}.png'
98
        //                  //moved to: https://www.toolserver.org/tiles/hikebike/12/2105/1388.png
99
        //                  'url' => 'http://c.tiles.wmflabs.org/hikebike/{Z}/{X}/{Y}.png'
100
        //          )
101
    );
102
    private $tileDefaultSrc = 'openstreetmap';
103
104
    // set up markers
105
    private $markerPrototypes = array(
106
        // found at http://www.mapito.net/map-marker-icons.html
107
        // these are 17x19 px with a pointer at the bottom left
108
        'lightblue' => array(
109
            'regex'        => '/^lightblue([0-9]+)$/',
110
            'extension'    => '.png',
111
            'shadow'       => false,
112
            'offsetImage'  => '0,-19',
113
            'offsetShadow' => false
114
        ),
115
        // openlayers std markers are 21x25px with shadow
116
        'ol-marker' => array(
117
            'regex'        => '/^marker(|-blue|-gold|-green|-red)+$/',
118
            'extension'    => '.png',
119
            'shadow'       => 'marker_shadow.png',
120
            'offsetImage'  => '-10,-25',
121
            'offsetShadow' => '-1,-13'
122
        ),
123
        // these are 16x16 px
124
        'ww_icon'   => array(
125
            'regex'        => '/ww_\S+$/',
126
            'extension'    => '.png',
127
            'shadow'       => false,
128
            'offsetImage'  => '-8,-8',
129
            'offsetShadow' => false
130
        ),
131
        // assume these are 16x16 px
132
        'rest'      => array(
133
            'regex'        => '/^(?!lightblue([0-9]+)$)(?!(ww_\S+$))(?!marker(|-blue|-gold|-green|-red)+$)(.*)/',
134
            'extension'    => '.png',
135
            'shadow'       => 'marker_shadow.png',
136
            'offsetImage'  => '-8,-8',
137
            'offsetShadow' => '-1,-1'
138
        )
139
    );
140
    private $centerX;
141
    private $centerY;
142
    private $offsetX;
143
    private $offsetY;
144
    private $image;
145
    private $zoom;
146
    private $lat;
147
    private $lon;
148
    private $width;
149
    private $height;
150
    private $markers;
151
    private $maptype;
152
    private $kmlFileName;
153
    private $gpxFileName;
154
    private $geojsonFileName;
155
    private $autoZoomExtent;
156
    private $apikey;
157
    private $tileCacheBaseDir;
158
    private $mapCacheBaseDir;
159
    private $mediaBaseDir;
160
    private $useTileCache;
161
    private $mapCacheID = '';
162
    private $mapCacheFile = '';
163
    private $mapCacheExtension = 'png';
164
165
    /**
166
     * Constructor.
167
     *
168
     * @param float  $lat
169
     *            Latitude (x) of center of map
170
     * @param float  $lon
171
     *            Longitude (y) of center of map
172
     * @param int    $zoom
173
     *            Zoomlevel
174
     * @param int    $width
175
     *            Width in pixels
176
     * @param int    $height
177
     *            Height in pixels
178
     * @param string $maptype
179
     *            Name of the map
180
     * @param array  $markers
181
     *            array of markers
182
     * @param string $gpx
183
     *            GPX filename
184
     * @param string $kml
185
     *            KML filename
186
     * @param string $geojson
187
     * @param string $mediaDir
188
     *            Directory to store/cache maps
189
     * @param string $tileCacheBaseDir
190
     *            Directory to cache map tiles
191
     * @param bool   $autoZoomExtent
192
     *            Wheter or not to override zoom/lat/lon and zoom to the extent of gpx/kml and markers
193
     * @param string $apikey
194
     */
195
    public function __construct(
196
        float $lat,
197
        float $lon,
198
        int $zoom,
199
        int $width,
200
        int $height,
201
        string $maptype,
202
        array $markers,
203
        string $gpx,
204
        string $kml,
205
        string $geojson,
206
        string $mediaDir,
207
        string $tileCacheBaseDir,
208
        bool $autoZoomExtent = true,
209
        string $apikey = ''
210
    ) {
211
        $this->zoom   = $zoom;
212
        $this->lat    = $lat;
213
        $this->lon    = $lon;
214
        $this->width  = $width;
215
        $this->height = $height;
216
        // validate + set maptype
217
        $this->maptype = $this->tileDefaultSrc;
218
        if(array_key_exists($maptype, $this->tileInfo)) {
219
            $this->maptype = $maptype;
220
        }
221
        $this->markers          = $markers;
222
        $this->kmlFileName      = $kml;
223
        $this->gpxFileName      = $gpx;
224
        $this->geojsonFileName  = $geojson;
225
        $this->mediaBaseDir     = $mediaDir;
226
        $this->tileCacheBaseDir = $tileCacheBaseDir . '/olmaptiles';
227
        $this->useTileCache     = $this->tileCacheBaseDir !== '';
228
        $this->mapCacheBaseDir  = $mediaDir . '/olmapmaps';
229
        $this->autoZoomExtent   = $autoZoomExtent;
230
        $this->apikey           = $apikey;
231
    }
232
233
    /**
234
     * get the map, this may return a reference to a cached copy.
235
     *
236
     * @return string url relative to media dir
237
     */
238
    public function getMap(): string {
239
        try {
240
            if($this->autoZoomExtent) {
241
                $this->autoZoom();
242
            }
243
        } catch(Exception $e) {
0 ignored issues
show
Bug introduced by
The type dokuwiki\plugin\openlayersmap\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
244
            dbglog($e);
0 ignored issues
show
Bug introduced by
The function dbglog was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

244
            /** @scrutinizer ignore-call */ 
245
            dbglog($e);
Loading history...
245
        }
246
247
        // use map cache, so check cache for map
248
        if(!$this->checkMapCache()) {
249
            // map is not in cache, needs to be build
250
            $this->makeMap();
251
            $this->mkdirRecursive(dirname($this->mapCacheIDToFilename()), 0777);
252
            imagepng($this->image, $this->mapCacheIDToFilename(), 9);
253
        }
254
        $doc = $this->mapCacheIDToFilename();
255
        // make url relative to media dir
256
        return str_replace($this->mediaBaseDir, '', $doc);
257
    }
258
259
    /**
260
     * Calculate the lat/lon/zoom values to make sure that all of the markers and gpx/kml are on the map.
261
     *
262
     * @param float $paddingFactor
263
     *            buffer constant to enlarge (>1.0) the zoom level
264
     * @throws Exception if non-geometries are found in the collection
265
     */
266
    private function autoZoom(float $paddingFactor = 1.0): void {
267
        $geoms    = array();
268
        $geoms [] = new Point ($this->lon, $this->lat);
269
        if(!empty ($this->markers)) {
270
            foreach($this->markers as $marker) {
271
                $geoms [] = new Point ($marker ['lon'], $marker ['lat']);
272
            }
273
        }
274
        if(file_exists($this->kmlFileName)) {
275
            $g = geoPHP::load(file_get_contents($this->kmlFileName), 'kml');
276
            if($g !== false) {
277
                $geoms [] = $g;
278
            }
279
        }
280
        if(file_exists($this->gpxFileName)) {
281
            $g = geoPHP::load(file_get_contents($this->gpxFileName), 'gpx');
282
            if($g !== false) {
283
                $geoms [] = $g;
284
            }
285
        }
286
        if(file_exists($this->geojsonFileName)) {
287
            $g = geoPHP::load(file_get_contents($this->geojsonFileName), 'geojson');
288
            if($g !== false) {
289
                $geoms [] = $g;
290
            }
291
        }
292
293
        if(count($geoms) <= 1) {
294
            dbglog($geoms, "StaticMap::autoZoom: Skip setting autozoom options");
0 ignored issues
show
Bug introduced by
The function dbglog was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

294
            /** @scrutinizer ignore-call */ 
295
            dbglog($geoms, "StaticMap::autoZoom: Skip setting autozoom options");
Loading history...
295
            return;
296
        }
297
298
        $geom     = new GeometryCollection ($geoms);
299
        $centroid = $geom->centroid();
300
        $bbox     = $geom->getBBox();
301
302
        // determine vertical resolution, this depends on the distance from the equator
303
        // $vy00 = log(tan(M_PI*(0.25 + $centroid->getY()/360)));
304
        $vy0 = log(tan(M_PI * (0.25 + $bbox ['miny'] / 360)));
305
        $vy1 = log(tan(M_PI * (0.25 + $bbox ['maxy'] / 360)));
306
        dbglog("StaticMap::autoZoom: vertical resolution: $vy0, $vy1");
307
        if ($vy1 - $vy0 === 0.0){
308
            $resolutionVertical = 0;
309
            dbglog("StaticMap::autoZoom: using $resolutionVertical");
310
        } else {
311
            $zoomFactorPowered  = ($this->height / 2) / (40.7436654315252 * ($vy1 - $vy0));
312
            $resolutionVertical = 360 / ($zoomFactorPowered * $this->tileSize);
313
        }
314
        // determine horizontal resolution
315
        $resolutionHorizontal = ($bbox ['maxx'] - $bbox ['minx']) / $this->width;
316
        dbglog("StaticMap::autoZoom: using $resolutionHorizontal");
317
        $resolution           = max($resolutionHorizontal, $resolutionVertical) * $paddingFactor;
318
        $zoom                 = $this->zoom;
319
        if ($resolution > 0){
320
            $zoom             = log(360 / ($resolution * $this->tileSize), 2);
321
        }
322
323
        if(is_finite($zoom) && $zoom < 15 && $zoom > 2) {
324
            $this->zoom = floor($zoom);
325
        }
326
        $this->lon = $centroid->getX();
327
        $this->lat = $centroid->getY();
328
        dbglog("StaticMap::autoZoom: Set autozoom options to: z: $this->zoom, lon: $this->lon, lat: $this->lat");
329
    }
330
331
    public function checkMapCache(): bool {
332
        // side effect: set the mapCacheID
333
        $this->mapCacheID = md5($this->serializeParams());
334
        $filename         = $this->mapCacheIDToFilename();
335
        return file_exists($filename);
336
    }
337
338
    public function serializeParams(): string {
339
        return implode(
340
            "&", array(
341
                   $this->zoom,
342
                   $this->lat,
343
                   $this->lon,
344
                   $this->width,
345
                   $this->height,
346
                   serialize($this->markers),
347
                   $this->maptype,
348
                   $this->kmlFileName,
349
                   $this->gpxFileName,
350
                   $this->geojsonFileName
351
               )
352
        );
353
    }
354
355
    public function mapCacheIDToFilename(): string {
356
        if(!$this->mapCacheFile) {
357
            $this->mapCacheFile = $this->mapCacheBaseDir . "/" . $this->maptype . "/" . $this->zoom . "/cache_"
0 ignored issues
show
Bug introduced by
Are you sure $this->maptype of type mixed|string can be used in concatenation? ( Ignorable by Annotation )

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

357
            $this->mapCacheFile = $this->mapCacheBaseDir . "/" . /** @scrutinizer ignore-type */ $this->maptype . "/" . $this->zoom . "/cache_"
Loading history...
358
                . substr($this->mapCacheID, 0, 2) . "/" . substr($this->mapCacheID, 2, 2)
359
                . "/" . substr($this->mapCacheID, 4);
360
        }
361
        return $this->mapCacheFile . "." . $this->mapCacheExtension;
362
    }
363
364
    /**
365
     * make the map.
366
     */
367
    public function makeMap(): void {
368
        $this->initCoords();
369
        $this->createBaseMap();
370
        if(!empty ($this->markers)) {
371
            $this->placeMarkers();
372
        }
373
        if (file_exists($this->kmlFileName)) {
374
            try {
375
                $this->drawKML();
376
            } catch (exception $e) {
0 ignored issues
show
Bug introduced by
The type dokuwiki\plugin\openlayersmap\exception was not found. Did you mean exception? If so, make sure to prefix the type with \.
Loading history...
377
                dbglog('failed to load KML file', $e);
0 ignored issues
show
Bug introduced by
The function dbglog was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

377
                /** @scrutinizer ignore-call */ 
378
                dbglog('failed to load KML file', $e);
Loading history...
378
            }
379
        }
380
        if (file_exists($this->gpxFileName)) {
381
            try {
382
                $this->drawGPX();
383
            } catch (exception $e) {
384
                dbglog('failed to load GPX file', $e);
385
            }
386
        }
387
        if (file_exists($this->geojsonFileName)) {
388
            try {
389
                $this->drawGeojson();
390
            } catch (exception $e) {
391
                dbglog('failed to load GeoJSON file', $e);
392
            }
393
        }
394
395
        $this->drawCopyright();
396
    }
397
398
    /**
399
     */
400
    public function initCoords(): void {
401
        $this->centerX = $this->lonToTile($this->lon, $this->zoom);
402
        $this->centerY = $this->latToTile($this->lat, $this->zoom);
403
        $this->offsetX = floor((floor($this->centerX) - $this->centerX) * $this->tileSize);
404
        $this->offsetY = floor((floor($this->centerY) - $this->centerY) * $this->tileSize);
405
    }
406
407
    /**
408
     *
409
     * @param float $long
410
     * @param int   $zoom
411
     * @return float|int
412
     */
413
    public function lonToTile(float $long, int $zoom) {
414
        return (($long + 180) / 360) * pow(2, $zoom);
415
    }
416
417
    /**
418
     *
419
     * @param float $lat
420
     * @param int   $zoom
421
     * @return float|int
422
     */
423
    public function latToTile(float $lat, int $zoom) {
424
        return (1 - log(tan($lat * pi() / 180) + 1 / cos($lat * M_PI / 180)) / M_PI) / 2 * pow(2, $zoom);
425
    }
426
427
    /**
428
     * make basemap image.
429
     */
430
    public function createBaseMap(): void {
431
        $this->image   = imagecreatetruecolor($this->width, $this->height);
432
        $startX        = floor($this->centerX - ($this->width / $this->tileSize) / 2);
433
        $startY        = floor($this->centerY - ($this->height / $this->tileSize) / 2);
434
        $endX          = ceil($this->centerX + ($this->width / $this->tileSize) / 2);
435
        $endY          = ceil($this->centerY + ($this->height / $this->tileSize) / 2);
436
        $this->offsetX = -floor(($this->centerX - floor($this->centerX)) * $this->tileSize);
437
        $this->offsetY = -floor(($this->centerY - floor($this->centerY)) * $this->tileSize);
438
        $this->offsetX += floor($this->width / 2);
439
        $this->offsetY += floor($this->height / 2);
440
        $this->offsetX += floor($startX - floor($this->centerX)) * $this->tileSize;
441
        $this->offsetY += floor($startY - floor($this->centerY)) * $this->tileSize;
442
443
        for($x = $startX; $x <= $endX; $x++) {
444
            for($y = $startY; $y <= $endY; $y++) {
445
                $url = str_replace(
446
                    array(
447
                        '{Z}',
448
                        '{X}',
449
                        '{Y}'
450
                    ), array(
451
                        $this->zoom,
452
                        $x,
453
                        $y
454
                    ), $this->tileInfo [$this->maptype] ['url']
455
                );
456
457
                $tileData = $this->fetchTile($url);
458
                if($tileData) {
459
                    $tileImage = imagecreatefromstring($tileData);
0 ignored issues
show
Bug introduced by
It seems like $tileData can also be of type true; however, parameter $image of imagecreatefromstring() does only seem to accept string, 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

459
                    $tileImage = imagecreatefromstring(/** @scrutinizer ignore-type */ $tileData);
Loading history...
460
                } else {
461
                    $tileImage = imagecreate($this->tileSize, $this->tileSize);
462
                    $color     = imagecolorallocate($tileImage, 255, 255, 255);
463
                    @imagestring($tileImage, 1, 127, 127, 'err', $color);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for imagestring(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

463
                    /** @scrutinizer ignore-unhandled */ @imagestring($tileImage, 1, 127, 127, 'err', $color);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
464
                }
465
                $destX = ($x - $startX) * $this->tileSize + $this->offsetX;
466
                $destY = ($y - $startY) * $this->tileSize + $this->offsetY;
467
                dbglog($this->tileSize, "imagecopy tile into image: $destX, $destY");
0 ignored issues
show
Bug introduced by
The function dbglog was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

467
                /** @scrutinizer ignore-call */ 
468
                dbglog($this->tileSize, "imagecopy tile into image: $destX, $destY");
Loading history...
468
                imagecopy(
469
                    $this->image, $tileImage, $destX, $destY, 0, 0, $this->tileSize,
0 ignored issues
show
Bug introduced by
$destY of type double is incompatible with the type integer expected by parameter $dst_y of imagecopy(). ( Ignorable by Annotation )

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

469
                    $this->image, $tileImage, $destX, /** @scrutinizer ignore-type */ $destY, 0, 0, $this->tileSize,
Loading history...
Bug introduced by
$destX of type double is incompatible with the type integer expected by parameter $dst_x of imagecopy(). ( Ignorable by Annotation )

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

469
                    $this->image, $tileImage, /** @scrutinizer ignore-type */ $destX, $destY, 0, 0, $this->tileSize,
Loading history...
470
                    $this->tileSize
471
                );
472
            }
473
        }
474
    }
475
476
    /**
477
     * Fetch a tile and (if configured) store it in the cache.
478
     * @param string $url
479
     * @return bool|string
480
     * @todo refactor this to use dokuwiki\HTTP\HTTPClient or dokuwiki\HTTP\DokuHTTPClient
481
     *          for better proxy handling...
482
     */
483
    public function fetchTile(string $url) {
484
        if($this->useTileCache && ($cached = $this->checkTileCache($url)))
485
            return $cached;
486
487
        $_UA = 'Mozilla/4.0 (compatible; DokuWikiSpatial HTTP Client; ' . PHP_OS . ')';
488
        if(function_exists("curl_init")) {
489
            // use cUrl
490
            $ch = curl_init();
491
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
492
            curl_setopt($ch, CURLOPT_USERAGENT, $_UA);
493
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
494
            curl_setopt($ch, CURLOPT_URL, $url . $this->apikey);
495
            dbglog("StaticMap::fetchTile: getting: $url using curl_exec");
0 ignored issues
show
Bug introduced by
The function dbglog was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

495
            /** @scrutinizer ignore-call */ 
496
            dbglog("StaticMap::fetchTile: getting: $url using curl_exec");
Loading history...
496
            $tile = curl_exec($ch);
497
            curl_close($ch);
498
        } else {
499
            // use file_get_contents
500
            global $conf;
501
            $opts = array(
502
                'http' => array(
503
                    'method'          => "GET",
504
                    'header'          => "Accept-language: en\r\n" . "User-Agent: $_UA\r\n" . "accept: image/png\r\n",
505
                    'request_fulluri' => true
506
                )
507
            );
508
            if(isset($conf['proxy']['host'], $conf['proxy']['port'])
509
                && $conf['proxy']['host'] !== ''
510
                && $conf['proxy']['port'] !== '') {
511
                $opts['http'] += ['proxy' => "tcp://" . $conf['proxy']['host'] . ":" . $conf['proxy']['port']];
512
            }
513
514
            $context = stream_context_create($opts);
515
            dbglog("StaticMap::fetchTile: getting: $url . $this->apikey using file_get_contents and options $opts");
516
            $tile = file_get_contents($url . $this->apikey, false, $context);
517
        }
518
        if($tile && $this->useTileCache) {
519
            $this->writeTileToCache($url, $tile);
520
        }
521
        return $tile;
522
    }
523
524
    /**
525
     *
526
     * @param string $url
527
     * @return string|false
528
     */
529
    public function checkTileCache(string $url) {
530
        $filename = $this->tileUrlToFilename($url);
531
        if(file_exists($filename)) {
532
            return file_get_contents($filename);
533
        }
534
        return false;
535
    }
536
537
    /**
538
     *
539
     * @param string $url
540
     * @return string
541
     */
542
    public function tileUrlToFilename(string $url): string {
543
        return $this->tileCacheBaseDir . "/" . substr($url, strpos($url, '/') + 1);
544
    }
545
546
    /**
547
     * Write a tile into the cache.
548
     *
549
     * @param string $url
550
     * @param mixed  $data
551
     */
552
    public function writeTileToCache($url, $data): void {
553
        $filename = $this->tileUrlToFilename($url);
554
        $this->mkdirRecursive(dirname($filename), 0777);
555
        file_put_contents($filename, $data);
556
    }
557
558
    /**
559
     * Recursively create the directory.
560
     *
561
     * @param string $pathname
562
     *            The directory path.
563
     * @param int    $mode
564
     *            File access mode. For more information on modes, read the details on the chmod manpage.
565
     */
566
    public function mkdirRecursive(string $pathname, int $mode): bool {
567
        is_dir(dirname($pathname)) || $this->mkdirRecursive(dirname($pathname), $mode);
568
        return is_dir($pathname) || mkdir($pathname, $mode) || is_dir($pathname);
569
    }
570
571
    /**
572
     * Place markers on the map and number them in the same order as they are listed in the html.
573
     */
574
    public function placeMarkers(): void {
575
        $count         = 0;
576
        $color         = imagecolorallocate($this->image, 0, 0, 0);
577
        $bgcolor       = imagecolorallocate($this->image, 200, 200, 200);
578
        $markerBaseDir = __DIR__ . '/icons';
579
        $markerImageOffsetX  = 0;
580
        $markerImageOffsetY  = 0;
581
        $markerShadowOffsetX = 0;
582
        $markerShadowOffsetY = 0;
583
        $markerShadowImg     = null;
584
        // loop thru marker array
585
        foreach($this->markers as $marker) {
586
            // set some local variables
587
            $markerLat  = $marker ['lat'];
588
            $markerLon  = $marker ['lon'];
589
            $markerType = $marker ['type'];
590
            // clear variables from previous loops
591
            $markerFilename = '';
592
            $markerShadow   = '';
593
            $matches        = false;
594
            // check for marker type, get settings from markerPrototypes
595
            if($markerType) {
596
                foreach($this->markerPrototypes as $markerPrototype) {
597
                    if(preg_match($markerPrototype ['regex'], $markerType, $matches)) {
0 ignored issues
show
Bug introduced by
$matches of type false is incompatible with the type string[] expected by parameter $matches of preg_match(). ( Ignorable by Annotation )

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

597
                    if(preg_match($markerPrototype ['regex'], $markerType, /** @scrutinizer ignore-type */ $matches)) {
Loading history...
598
                        $markerFilename = $matches [0] . $markerPrototype ['extension'];
599
                        if($markerPrototype ['offsetImage']) {
600
                            list ($markerImageOffsetX, $markerImageOffsetY) = explode(
601
                                ",",
602
                                $markerPrototype ['offsetImage']
603
                            );
604
                        }
605
                        $markerShadow = $markerPrototype ['shadow'];
606
                        if($markerShadow) {
607
                            list ($markerShadowOffsetX, $markerShadowOffsetY) = explode(
608
                                ",",
609
                                $markerPrototype ['offsetShadow']
610
                            );
611
                        }
612
                    }
613
                }
614
            }
615
            // create img resource
616
            if(file_exists($markerBaseDir . '/' . $markerFilename)) {
617
                $markerImg = imagecreatefrompng($markerBaseDir . '/' . $markerFilename);
618
            } else {
619
                $markerImg = imagecreatefrompng($markerBaseDir . '/marker.png');
620
            }
621
            // check for shadow + create shadow recource
622
            if($markerShadow && file_exists($markerBaseDir . '/' . $markerShadow)) {
623
                $markerShadowImg = imagecreatefrompng($markerBaseDir . '/' . $markerShadow);
624
            }
625
            // calc position
626
            $destX = floor(
627
                ($this->width / 2) -
628
                $this->tileSize * ($this->centerX - $this->lonToTile($markerLon, $this->zoom))
629
            );
630
            $destY = floor(
631
                ($this->height / 2) -
632
                $this->tileSize * ($this->centerY - $this->latToTile($markerLat, $this->zoom))
633
            );
634
            // copy shadow on basemap
635
            if($markerShadow && $markerShadowImg) {
636
                imagecopy(
637
                    $this->image,
638
                    $markerShadowImg,
639
                    $destX + (int) $markerShadowOffsetX,
0 ignored issues
show
Bug introduced by
$destX + (int)$markerShadowOffsetX of type double is incompatible with the type integer expected by parameter $dst_x of imagecopy(). ( Ignorable by Annotation )

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

639
                    /** @scrutinizer ignore-type */ $destX + (int) $markerShadowOffsetX,
Loading history...
640
                    $destY + (int) $markerShadowOffsetY,
0 ignored issues
show
Bug introduced by
$destY + (int)$markerShadowOffsetY of type double is incompatible with the type integer expected by parameter $dst_y of imagecopy(). ( Ignorable by Annotation )

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

640
                    /** @scrutinizer ignore-type */ $destY + (int) $markerShadowOffsetY,
Loading history...
641
                    0,
642
                    0,
643
                    imagesx($markerShadowImg),
644
                    imagesy($markerShadowImg)
645
                );
646
            }
647
            // copy marker on basemap above shadow
648
            imagecopy(
649
                $this->image,
650
                $markerImg,
651
                $destX + (int) $markerImageOffsetX,
652
                $destY + (int) $markerImageOffsetY,
653
                0,
654
                0,
655
                imagesx($markerImg),
656
                imagesy($markerImg)
657
            );
658
            // add label
659
            imagestring(
660
                $this->image,
661
                3,
662
                $destX - imagesx($markerImg) + 1,
0 ignored issues
show
Bug introduced by
$destX - imagesx($markerImg) + 1 of type double is incompatible with the type integer expected by parameter $x of imagestring(). ( Ignorable by Annotation )

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

662
                /** @scrutinizer ignore-type */ $destX - imagesx($markerImg) + 1,
Loading history...
663
                $destY + (int) $markerImageOffsetY + 1,
0 ignored issues
show
Bug introduced by
$destY + (int)$markerImageOffsetY + 1 of type double is incompatible with the type integer expected by parameter $y of imagestring(). ( Ignorable by Annotation )

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

663
                /** @scrutinizer ignore-type */ $destY + (int) $markerImageOffsetY + 1,
Loading history...
664
                ++$count,
665
                $bgcolor
666
            );
667
            imagestring(
668
                $this->image,
669
                3,
670
                $destX - imagesx($markerImg),
671
                $destY + (int) $markerImageOffsetY,
672
                $count,
673
                $color
674
            );
675
        }
676
    }
677
678
    /**
679
     * Draw kml trace on the map.
680
     * @throws exception when loading the KML fails
681
     */
682
    public function drawKML(): void {
683
        // TODO get colour from kml node (not currently supported in geoPHP)
684
        $col     = imagecolorallocatealpha($this->image, 255, 0, 0, .4 * 127);
0 ignored issues
show
Bug introduced by
0.4 * 127 of type double is incompatible with the type integer expected by parameter $alpha of imagecolorallocatealpha(). ( Ignorable by Annotation )

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

684
        $col     = imagecolorallocatealpha($this->image, 255, 0, 0, /** @scrutinizer ignore-type */ .4 * 127);
Loading history...
685
        $kmlgeom = geoPHP::load(file_get_contents($this->kmlFileName), 'kml');
686
        $this->drawGeometry($kmlgeom, $col);
687
    }
688
689
    /**
690
     * Draw geometry or geometry collection on the map.
691
     *
692
     * @param Geometry $geom
693
     * @param int      $colour
694
     *            drawing colour
695
     */
696
    private function drawGeometry(Geometry $geom, int $colour): void {
697
        if(empty($geom)) {
698
            return;
699
        }
700
701
        switch($geom->geometryType()) {
702
            case 'GeometryCollection' :
703
                // recursively draw part of the collection
704
                for($i = 1; $i < $geom->numGeometries() + 1; $i++) {
705
                    $_geom = $geom->geometryN($i);
706
                    $this->drawGeometry($_geom, $colour);
707
                }
708
                break;
709
            case 'MultiPolygon' :
710
            case 'MultiLineString' :
711
            case 'MultiPoint' :
712
                // TODO implement / do nothing
713
                break;
714
            case 'Polygon' :
715
                $this->drawPolygon($geom, $colour);
716
                break;
717
            case 'LineString' :
718
                $this->drawLineString($geom, $colour);
719
                break;
720
            case 'Point' :
721
                $this->drawPoint($geom, $colour);
722
                break;
723
            default :
724
                // draw nothing
725
                break;
726
        }
727
    }
728
729
    /**
730
     * Draw a polygon on the map.
731
     *
732
     * @param Polygon $polygon
733
     * @param int     $colour
734
     *            drawing colour
735
     */
736
    private function drawPolygon($polygon, int $colour) {
737
        // TODO implementation of drawing holes,
738
        // maybe draw the polygon to an in-memory image and use imagecopy, draw polygon in col., draw holes in bgcol?
739
740
        // print_r('Polygon:<br />');
741
        // print_r($polygon);
742
        $extPoints = array();
743
        // extring is a linestring actually..
744
        $extRing = $polygon->exteriorRing();
745
746
        for($i = 1; $i < $extRing->numGeometries(); $i++) {
747
            $p1           = $extRing->geometryN($i);
748
            $x            = floor(
749
                ($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p1->x(), $this->zoom))
750
            );
751
            $y            = floor(
752
                ($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p1->y(), $this->zoom))
753
            );
754
            $extPoints [] = $x;
755
            $extPoints [] = $y;
756
        }
757
        // print_r('points:('.($i-1).')<br />');
758
        // print_r($extPoints);
759
        // imagepolygon ($this->image, $extPoints, $i-1, $colour );
760
        imagefilledpolygon($this->image, $extPoints, $i - 1, $colour);
761
    }
762
763
    /**
764
     * Draw a line on the map.
765
     *
766
     * @param LineString $line
767
     * @param int        $colour
768
     *            drawing colour
769
     */
770
    private function drawLineString($line, $colour) {
771
        imagesetthickness($this->image, 2);
772
        for($p = 1; $p < $line->numGeometries(); $p++) {
773
            // get first pair of points
774
            $p1 = $line->geometryN($p);
775
            $p2 = $line->geometryN($p + 1);
776
            // translate to paper space
777
            $x1 = floor(
778
                ($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p1->x(), $this->zoom))
779
            );
780
            $y1 = floor(
781
                ($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p1->y(), $this->zoom))
782
            );
783
            $x2 = floor(
784
                ($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($p2->x(), $this->zoom))
785
            );
786
            $y2 = floor(
787
                ($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($p2->y(), $this->zoom))
788
            );
789
            // draw to image
790
            imageline($this->image, $x1, $y1, $x2, $y2, $colour);
0 ignored issues
show
Bug introduced by
$x2 of type double is incompatible with the type integer expected by parameter $x2 of imageline(). ( Ignorable by Annotation )

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

790
            imageline($this->image, $x1, $y1, /** @scrutinizer ignore-type */ $x2, $y2, $colour);
Loading history...
Bug introduced by
$x1 of type double is incompatible with the type integer expected by parameter $x1 of imageline(). ( Ignorable by Annotation )

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

790
            imageline($this->image, /** @scrutinizer ignore-type */ $x1, $y1, $x2, $y2, $colour);
Loading history...
Bug introduced by
$y2 of type double is incompatible with the type integer expected by parameter $y2 of imageline(). ( Ignorable by Annotation )

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

790
            imageline($this->image, $x1, $y1, $x2, /** @scrutinizer ignore-type */ $y2, $colour);
Loading history...
Bug introduced by
$y1 of type double is incompatible with the type integer expected by parameter $y1 of imageline(). ( Ignorable by Annotation )

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

790
            imageline($this->image, $x1, /** @scrutinizer ignore-type */ $y1, $x2, $y2, $colour);
Loading history...
791
        }
792
        imagesetthickness($this->image, 1);
793
    }
794
795
    /**
796
     * Draw a point on the map.
797
     *
798
     * @param Point $point
799
     * @param int   $colour
800
     *            drawing colour
801
     */
802
    private function drawPoint($point, $colour) {
803
        imagesetthickness($this->image, 2);
804
        // translate to paper space
805
        $cx = floor(
806
            ($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($point->x(), $this->zoom))
807
        );
808
        $cy = floor(
809
            ($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($point->y(), $this->zoom))
810
        );
811
        $r  = 5;
812
        // draw to image
813
        // imageellipse($this->image, $cx, $cy,$r, $r, $colour);
814
        imagefilledellipse($this->image, $cx, $cy, $r, $r, $colour);
0 ignored issues
show
Bug introduced by
$cx of type double is incompatible with the type integer expected by parameter $cx of imagefilledellipse(). ( Ignorable by Annotation )

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

814
        imagefilledellipse($this->image, /** @scrutinizer ignore-type */ $cx, $cy, $r, $r, $colour);
Loading history...
Bug introduced by
$cy of type double is incompatible with the type integer expected by parameter $cy of imagefilledellipse(). ( Ignorable by Annotation )

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

814
        imagefilledellipse($this->image, $cx, /** @scrutinizer ignore-type */ $cy, $r, $r, $colour);
Loading history...
815
        // don't use imageellipse because the imagesetthickness function has
816
        // no effect. So the better workaround is to use imagearc.
817
        imagearc($this->image, $cx, $cy, $r, $r, 0, 359, $colour);
0 ignored issues
show
Bug introduced by
$cx of type double is incompatible with the type integer expected by parameter $cx of imagearc(). ( Ignorable by Annotation )

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

817
        imagearc($this->image, /** @scrutinizer ignore-type */ $cx, $cy, $r, $r, 0, 359, $colour);
Loading history...
Bug introduced by
$cy of type double is incompatible with the type integer expected by parameter $cy of imagearc(). ( Ignorable by Annotation )

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

817
        imagearc($this->image, $cx, /** @scrutinizer ignore-type */ $cy, $r, $r, 0, 359, $colour);
Loading history...
818
        imagesetthickness($this->image, 1);
819
    }
820
821
    /**
822
     * Draw gpx trace on the map.
823
     * @throws exception when loading the GPX fails
824
     */
825
    public function drawGPX() {
826
        $col     = imagecolorallocatealpha($this->image, 0, 0, 255, .4 * 127);
0 ignored issues
show
Bug introduced by
0.4 * 127 of type double is incompatible with the type integer expected by parameter $alpha of imagecolorallocatealpha(). ( Ignorable by Annotation )

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

826
        $col     = imagecolorallocatealpha($this->image, 0, 0, 255, /** @scrutinizer ignore-type */ .4 * 127);
Loading history...
827
        $gpxgeom = geoPHP::load(file_get_contents($this->gpxFileName), 'gpx');
828
        $this->drawGeometry($gpxgeom, $col);
829
    }
830
831
    /**
832
     * Draw geojson on the map.
833
     * @throws exception when loading the JSON fails
834
     */
835
    public function drawGeojson() {
836
        $col     = imagecolorallocatealpha($this->image, 255, 0, 255, .4 * 127);
0 ignored issues
show
Bug introduced by
0.4 * 127 of type double is incompatible with the type integer expected by parameter $alpha of imagecolorallocatealpha(). ( Ignorable by Annotation )

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

836
        $col     = imagecolorallocatealpha($this->image, 255, 0, 255, /** @scrutinizer ignore-type */ .4 * 127);
Loading history...
837
        $gpxgeom = geoPHP::load(file_get_contents($this->geojsonFileName), 'json');
838
        $this->drawGeometry($gpxgeom, $col);
839
    }
840
841
    /**
842
     * add copyright and origin notice and icons to the map.
843
     */
844
    public function drawCopyright() {
845
        $logoBaseDir = dirname(__FILE__) . '/' . 'logo/';
846
        $logoImg     = imagecreatefrompng($logoBaseDir . $this->tileInfo ['openstreetmap'] ['logo']);
847
        $textcolor   = imagecolorallocate($this->image, 0, 0, 0);
848
        $bgcolor     = imagecolorallocate($this->image, 200, 200, 200);
849
850
        imagecopy(
851
            $this->image,
852
            $logoImg,
853
            0,
854
            imagesy($this->image) - imagesy($logoImg),
855
            0,
856
            0,
857
            imagesx($logoImg),
858
            imagesy($logoImg)
859
        );
860
        imagestring(
861
            $this->image,
862
            1,
863
            imagesx($logoImg) + 2,
864
            imagesy($this->image) - imagesy($logoImg) + 1,
865
            $this->tileInfo ['openstreetmap'] ['txt'],
866
            $bgcolor
867
        );
868
        imagestring(
869
            $this->image,
870
            1,
871
            imagesx($logoImg) + 1,
872
            imagesy($this->image) - imagesy($logoImg),
873
            $this->tileInfo ['openstreetmap'] ['txt'],
874
            $textcolor
875
        );
876
877
        // additional tile source info, ie. who created/hosted the tiles
878
        $xIconOffset = 0;
879
        if($this->maptype === 'openstreetmap') {
880
            $mapAuthor = "(c) OpenStreetMap maps/CC BY-SA";
881
        } else {
882
            $mapAuthor   = $this->tileInfo [$this->maptype] ['txt'];
883
            $iconImg     = imagecreatefrompng($logoBaseDir . $this->tileInfo [$this->maptype] ['logo']);
884
            $xIconOffset = imagesx($iconImg);
885
            imagecopy(
886
                $this->image,
887
                $iconImg, imagesx($logoImg) + 1,
888
                imagesy($this->image) - imagesy($iconImg),
889
                0,
890
                0,
891
                imagesx($iconImg), imagesy($iconImg)
892
            );
893
        }
894
        imagestring(
895
            $this->image,
896
            1, imagesx($logoImg) + $xIconOffset + 4,
897
            imagesy($this->image) - ceil(imagesy($logoImg) / 2) + 1,
0 ignored issues
show
Bug introduced by
imagesy($this->image) - ...gesy($logoImg) / 2) + 1 of type double is incompatible with the type integer expected by parameter $y of imagestring(). ( Ignorable by Annotation )

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

897
            /** @scrutinizer ignore-type */ imagesy($this->image) - ceil(imagesy($logoImg) / 2) + 1,
Loading history...
898
            $mapAuthor,
899
            $bgcolor
900
        );
901
        imagestring(
902
            $this->image,
903
            1, imagesx($logoImg) + $xIconOffset + 3,
904
            imagesy($this->image) - ceil(imagesy($logoImg) / 2),
905
            $mapAuthor,
906
            $textcolor
907
        );
908
909
    }
910
}
911