tileserver-gl-light 4.5.1 → 4.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ # Read the Docs configuration file for Sphinx projects
2
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3
+
4
+ # Required
5
+ version: 2
6
+
7
+ # Set the version of Python and other tools you might need
8
+ build:
9
+ os: ubuntu-22.04
10
+ tools:
11
+ python: "3.11"
12
+
13
+ # Build documentation in the doc/help/ directory with Sphinx
14
+ sphinx:
15
+ configuration: docs/conf.py
16
+
17
+ formats:
18
+ - pdf
package/docs/config.rst CHANGED
@@ -33,6 +33,8 @@ Example:
33
33
  "serveAllStyles": false,
34
34
  "serveStaticMaps": true,
35
35
  "allowRemoteMarkerIcons": true,
36
+ "allowInlineMarkerImages": true,
37
+ "staticAttributionText": "© OpenMapTiles © OpenStreetMaps",
36
38
  "tileMargin": 0
37
39
  },
38
40
  "styles": {
@@ -140,7 +142,13 @@ It is recommended to also use the ``serveAllFonts`` option when using this optio
140
142
  -----------
141
143
 
142
144
  Optional string to be rendered into the raster tiles (and static maps) as watermark (bottom-left corner).
143
- Can be used for hard-coding attributions etc. (can also be specified per-style).
145
+ Not used by default.
146
+
147
+ ``staticAttributionText``
148
+ -----------
149
+
150
+ Optional string to be rendered in the static images endpoint. Text will be rendered in the bottom-right corner,
151
+ and styled similar to attribution on web-based maps (text only, links not supported).
144
152
  Not used by default.
145
153
 
146
154
  ``allowRemoteMarkerIcons``
@@ -150,6 +158,13 @@ Allows the rendering of marker icons fetched via http(s) hyperlinks.
150
158
  For security reasons only allow this if you can control the origins from where the markers are fetched!
151
159
  Default is to disallow fetching of icons from remote sources.
152
160
 
161
+ ``allowInlineMarkerImages``
162
+ --------------
163
+ Allows the rendering of inline marker icons or base64 urls.
164
+ For security reasons only allow this if you can control the origins from where the markers are fetched!
165
+ Not used by default.
166
+
167
+
153
168
  ``styles``
154
169
  ==========
155
170
 
@@ -35,14 +35,23 @@ Static images
35
35
 
36
36
  * All the static image endpoints additionally support following query parameters:
37
37
 
38
- * ``path``
39
- * can be provided multiple times
40
- * syntax
41
- * comma-separated ``lng,lat``, pipe-separated pairs
42
- * e.g. ``path=5.9,45.8|5.9,47.8|10.5,47.8|10.5,45.8|5.9,45.8``
43
- * Match pattern with options ``((fill|stroke|width)\:[^\|]+\|)*((enc:.+)|((-?\d+\.?\d*,-?\d+\.?\d*\|)+(-?\d+\.?\d*,-?\d+\.?\d*)))``
44
- * e.g. ``path=stroke:yellow|width:2|fill:green|5.9,45.8|5.9,47.8|10.5,47.8|10.5,45.8|5.9,45.8`` or ``stroke:blue|enc:_p~iF~ps|U_ulLnnqC_mqNvxq`@``
45
- * 'enc:' is specified in `Google Encoded Polyline Format <https://developers.google.com/maps/documentation/utilities/polylinealgorithm>`. If used, the rest of the path parameter is considered to be part of the encoded polyline string -- do not specify the coordinate pairs.
38
+ * ``path`` - ``((fill|stroke|width)\:[^\|]+\|)*(enc:.+|-?\d+(\.\d*)?,-?\d+(\.\d*)?(\|-?\d+(\.\d*)?,-?\d+(\.\d*)?)+)``
39
+
40
+ * comma-separated ``lng,lat``, pipe-separated pairs
41
+
42
+ * e.g. ``path=5.9,45.8|5.9,47.8|10.5,47.8|10.5,45.8|5.9,45.8``
43
+
44
+ * `Google Encoded Polyline Format <https://developers.google.com/maps/documentation/utilities/polylinealgorithm>`_
45
+
46
+ * e.g. ``path=enc:_p~iF~ps|U_ulLnnqC_mqNvxq`@``
47
+ * If 'enc:' is used, the rest of the path parameter is considered to be part of the encoded polyline string -- do not specify the coordinate pairs.
48
+
49
+ * With options (fill|stroke|width)
50
+
51
+ * e.g. ``path=stroke:yellow|width:2|fill:green|5.9,45.8|5.9,47.8|10.5,47.8|10.5,45.8|5.9,45.8`` or ``path=stroke:blue|width:1|fill:yellow|enc:_p~iF~ps|U_ulLnnqC_mqNvxq`@``
52
+
53
+ * can be provided multiple times
54
+
46
55
  * ``latlng`` - indicates coordinates are in ``lat,lng`` order rather than the usual ``lng,lat``
47
56
  * ``fill`` - color to use as the fill (e.g. ``red``, ``rgba(255,255,255,0.5)``, ``#0000ff``)
48
57
  * ``stroke`` - color of the path stroke
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tileserver-gl-light",
3
- "version": "4.5.1",
3
+ "version": "4.5.2",
4
4
  "description": "Map tile server for JSON GL styles - serving vector tiles",
5
5
  "main": "src/main.js",
6
6
  "bin": "src/main.js",
@@ -27,14 +27,14 @@
27
27
  "chokidar": "3.5.3",
28
28
  "clone": "2.1.2",
29
29
  "color": "4.2.3",
30
- "commander": "11.0.0",
30
+ "commander": "11.1.0",
31
31
  "cors": "2.8.5",
32
32
  "express": "4.18.2",
33
33
  "handlebars": "4.7.8",
34
34
  "http-shutdown": "1.2.2",
35
35
  "morgan": "1.10.0",
36
36
  "pbf": "3.2.1",
37
- "proj4": "2.9.0",
37
+ "proj4": "2.9.1",
38
38
  "request": "2.88.2",
39
39
  "sanitize-filename": "1.6.3",
40
40
  "tileserver-gl-styles": "2.0.0"
@@ -22,8 +22,8 @@ import { getFontsPbf, getTileUrls, fixTileJSONCenter } from './utils.js';
22
22
 
23
23
  const FLOAT_PATTERN = '[+-]?(?:\\d+|\\d+.?\\d+)';
24
24
  const PATH_PATTERN =
25
- /^((fill|stroke|width)\:[^\|]+\|)*((enc:.+)|((-?\d+\.?\d*,-?\d+\.?\d*\|)+(-?\d+\.?\d*,-?\d+\.?\d*)))/;
26
- const httpTester = /^(http(s)?:)?\/\//;
25
+ /^((fill|stroke|width)\:[^\|]+\|)*(enc:.+|-?\d+(\.\d*)?,-?\d+(\.\d*)?(\|-?\d+(\.\d*)?,-?\d+(\.\d*)?)+)/;
26
+ const httpTester = /^\/\//;
27
27
 
28
28
  const mercator = new SphericalMercator();
29
29
  const getScale = (scale) => (scale || '@1x').slice(1, 2) | 0;
@@ -158,10 +158,7 @@ const extractPathsFromQuery = (query, transformer) => {
158
158
  // Iterate through paths, parse and validate them
159
159
  for (const providedPath of providedPaths) {
160
160
  // Logic for pushing coords to path when path includes google polyline
161
- if (
162
- providedPath.includes('enc:') &&
163
- PATH_PATTERN.test(decodeURIComponent(providedPath))
164
- ) {
161
+ if (providedPath.includes('enc:') && PATH_PATTERN.test(providedPath)) {
165
162
  // +4 because 'enc:' is 4 characters, everything after 'enc:' is considered to be part of the polyline
166
163
  const encIndex = providedPath.indexOf('enc:') + 4;
167
164
  const coords = polyline
@@ -279,7 +276,10 @@ const extractMarkersFromQuery = (query, options, transformer) => {
279
276
  let iconURI = markerParts[1];
280
277
  // Check if icon is served via http otherwise marker icons are expected to
281
278
  // be provided as filepaths relative to configured icon path
282
- if (!(iconURI.startsWith('http://') || iconURI.startsWith('https://'))) {
279
+ const isRemoteURL =
280
+ iconURI.startsWith('http://') || iconURI.startsWith('https://');
281
+ const isDataURL = iconURI.startsWith('data:');
282
+ if (!(isRemoteURL || isDataURL)) {
283
283
  // Sanitize URI with sanitize-filename
284
284
  // https://www.npmjs.com/package/sanitize-filename#details
285
285
  iconURI = sanitize(iconURI);
@@ -292,7 +292,9 @@ const extractMarkersFromQuery = (query, options, transformer) => {
292
292
  iconURI = path.resolve(options.paths.icons, iconURI);
293
293
 
294
294
  // When we encounter a remote icon check if the configuration explicitly allows them.
295
- } else if (options.allowRemoteMarkerIcons !== true) {
295
+ } else if (isRemoteURL && options.allowRemoteMarkerIcons !== true) {
296
+ continue;
297
+ } else if (isDataURL && options.allowInlineMarkerImages !== true) {
296
298
  continue;
297
299
  }
298
300
 
@@ -427,7 +429,7 @@ const drawMarkers = async (ctx, markers, z) => {
427
429
  * @param {number} z Map zoom level.
428
430
  */
429
431
  const drawPath = (ctx, path, query, pathQuery, z) => {
430
- const splitPaths = decodeURIComponent(pathQuery).split('|');
432
+ const splitPaths = pathQuery.split('|');
431
433
 
432
434
  if (!path || path.length < 2) {
433
435
  return null;
@@ -771,6 +773,35 @@ export const serve_rendered = {
771
773
  composite_array.push({ input: canvas.toBuffer() });
772
774
  }
773
775
 
776
+ if (opt_mode === 'static' && item.staticAttributionText) {
777
+ const canvas = createCanvas(scale * width, scale * height);
778
+ const ctx = canvas.getContext('2d');
779
+ ctx.scale(scale, scale);
780
+
781
+ ctx.font = '10px sans-serif';
782
+ const text = item.staticAttributionText;
783
+ const textMetrics = ctx.measureText(text);
784
+ const textWidth = textMetrics.width;
785
+ const textHeight = 14;
786
+
787
+ const padding = 6;
788
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
789
+ ctx.fillRect(
790
+ width - textWidth - padding,
791
+ height - textHeight - padding,
792
+ textWidth + padding,
793
+ textHeight + padding,
794
+ );
795
+ ctx.fillStyle = 'rgba(0,0,0,.8)';
796
+ ctx.fillText(
797
+ item.staticAttributionText,
798
+ width - textWidth - padding / 2,
799
+ height - textHeight + 8,
800
+ );
801
+
802
+ composite_array.push({ input: canvas.toBuffer() });
803
+ }
804
+
774
805
  if (composite_array.length > 0) {
775
806
  image.composite(composite_array);
776
807
  }
@@ -1378,6 +1409,8 @@ export const serve_rendered = {
1378
1409
  dataProjWGStoInternalWGS: null,
1379
1410
  lastModified: new Date().toUTCString(),
1380
1411
  watermark: params.watermark || options.watermark,
1412
+ staticAttributionText:
1413
+ params.staticAttributionText || options.staticAttributionText,
1381
1414
  };
1382
1415
  repo[id] = repoobj;
1383
1416
 
@@ -9,7 +9,7 @@ import { validate } from '@maplibre/maplibre-gl-style-spec';
9
9
 
10
10
  import { getPublicUrl } from './utils.js';
11
11
 
12
- const httpTester = /^(http(s)?:)?\/\//;
12
+ const httpTester = /^\/\//;
13
13
 
14
14
  const fixUrl = (req, url, publicUrl, opt_nokey) => {
15
15
  if (!url || typeof url !== 'string' || url.indexOf('local://') !== 0) {
package/test/static.js CHANGED
@@ -180,7 +180,7 @@ describe('Static endpoints', function () {
180
180
  200,
181
181
  2,
182
182
  /image\/png/,
183
- '?path=' + decodeURIComponent('enc:{{biGwvyGoUi@s_A|{@'),
183
+ '?path=' + encodeURIComponent('enc:{{biGwvyGoUi@s_A|{@'),
184
184
  );
185
185
  });
186
186
  });