tileserver-gl-light 4.5.2 → 4.6.0

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.
package/LICENSE.md CHANGED
@@ -1416,6 +1416,38 @@ modification, are permitted provided that the following conditions are met:
1416
1416
  this list of conditions and the following disclaimer in the documentation
1417
1417
  and/or other materials provided with the distribution.
1418
1418
 
1419
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1420
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1421
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1422
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1423
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1424
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1425
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1426
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1427
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1428
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1429
+ ```
1430
+ ---
1431
+
1432
+ ### [PMTiles](https://github.com/protomaps/pmtiles)
1433
+ ```
1434
+ BSD 3-Clause License
1435
+ Copyright 2021 Protomaps LLC
1436
+
1437
+ Redistribution and use in source and binary forms, with or without
1438
+ modification, are permitted provided that the following conditions are met:
1439
+
1440
+ 1. Redistributions of source code must retain the above copyright notice, this
1441
+ list of conditions and the following disclaimer.
1442
+
1443
+ 2. Redistributions in binary form must reproduce the above copyright notice,
1444
+ this list of conditions and the following disclaimer in the documentation
1445
+ and/or other materials provided with the distribution.
1446
+
1447
+ 3. Neither the name of the copyright holder nor the names of its contributors
1448
+ may be used to endorse or promote products derived from this software
1449
+ without specific prior written permission.
1450
+
1419
1451
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1420
1452
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1421
1453
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
package/docs/config.rst CHANGED
@@ -16,7 +16,8 @@ Example:
16
16
  "sprites": "sprites",
17
17
  "icons": "icons",
18
18
  "styles": "styles",
19
- "mbtiles": ""
19
+ "mbtiles": "data",
20
+ "pmtiles": "data"
20
21
  },
21
22
  "domains": [
22
23
  "localhost:8080",
@@ -180,11 +181,27 @@ Each item in this object defines one style (map). It can have the following opti
180
181
  ``data``
181
182
  ========
182
183
 
183
- Each item specifies one data source which should be made accessible by the server. It has the following options:
184
+ Each item specifies one data source which should be made accessible by the server. It has to have one of the following options:
184
185
 
185
- * ``mbtiles`` -- name of the mbtiles file [required]
186
+ * ``mbtiles`` -- name of the mbtiles file
187
+ * ``pmtiles`` -- name of the pmtiles file or url.
186
188
 
187
- The mbtiles file does not need to be specified here unless you explicitly want to serve the raw data.
189
+ For example::
190
+
191
+ "data": {
192
+ "source1": {
193
+ "mbtiles": "source1.mbtiles"
194
+ },
195
+ "source2": {
196
+ "pmtiles": "source2.pmtiles"
197
+ },
198
+ "source3": {
199
+ "pmtiles": "https://foo.lan/source3.pmtiles"
200
+ }
201
+ }
202
+
203
+
204
+ The data source does not need to be specified here unless you explicitly want to serve the raw data.
188
205
 
189
206
  Referencing local files from style JSON
190
207
  =======================================
@@ -194,21 +211,46 @@ You can link various data sources from the style JSON (for example even remote T
194
211
  MBTiles
195
212
  -------
196
213
 
197
- To specify that you want to use local mbtiles, use to following syntax: ``mbtiles://switzerland.mbtiles``.
198
- The TileServer-GL will try to find the file ``switzerland.mbtiles`` in ``root`` + ``mbtiles`` path.
214
+ To specify that you want to use local mbtiles, use to following syntax: ``mbtiles://source1.mbtiles``.
215
+ TileServer-GL will try to find the file ``source1.mbtiles`` in ``root`` + ``mbtiles`` path.
199
216
 
200
217
  For example::
201
218
 
202
219
  "sources": {
203
220
  "source1": {
204
- "url": "mbtiles://switzerland.mbtiles",
221
+ "url": "mbtiles://source1.mbtiles",
205
222
  "type": "vector"
206
223
  }
207
224
  }
208
225
 
209
- Alternatively, you can use ``mbtiles://{zurich-vector}`` to reference existing data object from the config.
210
- In this case, the server will look into the ``config.json`` to determine what mbtiles file to use.
211
- For the config above, this is equivalent to ``mbtiles://zurich.mbtiles``.
226
+ Alternatively, you can use ``mbtiles://{source1}`` to reference existing data object from the config.
227
+ In this case, the server will look into the ``config.json`` to determine what file to use by data id.
228
+ For the config above, this is equivalent to ``mbtiles://source1.mbtiles``.
229
+
230
+ PMTiles
231
+ -------
232
+
233
+ To specify that you want to use local pmtiles, use to following syntax: ``pmtiles://source2.pmtiles``.
234
+ TileServer-GL will try to find the file ``source2.pmtiles`` in ``root`` + ``pmtiles`` path.
235
+
236
+ To specify that you want to use a url based pmtiles, use to following syntax: ``pmtiles://https://foo.lan/source3.pmtiles``.
237
+
238
+ For example::
239
+
240
+ "sources": {
241
+ "source2": {
242
+ "url": "pmtiles://source2.pmtiles",
243
+ "type": "vector"
244
+ },
245
+ "source3": {
246
+ "url": "pmtiles://https://foo.lan/source3.pmtiles",
247
+ "type": "vector"
248
+ },
249
+ }
250
+
251
+ Alternatively, you can use ``pmtiles://{source2}`` to reference existing data object from the config.
252
+ In this case, the server will look into the ``config.json`` to determine what file to use by data id.
253
+ For the config above, this is equivalent to ``pmtiles://source2.mbtiles``.
212
254
 
213
255
  Sprites
214
256
  -------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tileserver-gl-light",
3
- "version": "4.5.2",
3
+ "version": "4.6.0",
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",
@@ -23,6 +23,7 @@
23
23
  "@mapbox/sphericalmercator": "1.2.0",
24
24
  "@mapbox/vector-tile": "1.3.1",
25
25
  "@maplibre/maplibre-gl-style-spec": "18.0.0",
26
+ "@sindresorhus/fnv1a": "3.0.0",
26
27
  "advanced-pool": "0.3.3",
27
28
  "chokidar": "3.5.3",
28
29
  "clone": "2.1.2",
@@ -34,6 +35,7 @@
34
35
  "http-shutdown": "1.2.2",
35
36
  "morgan": "1.10.0",
36
37
  "pbf": "3.2.1",
38
+ "pmtiles": "2.11.0",
37
39
  "proj4": "2.9.1",
38
40
  "request": "2.88.2",
39
41
  "sanitize-filename": "1.6.3",
@@ -77,8 +77,9 @@
77
77
  <img src="{{public_url}}images/placeholder.png{{&key_query}}" alt="{{name}} preview" />
78
78
  {{/if}}
79
79
  <div class="details">
80
- <h3>{{name}}</h3>
81
- <p class="identifier">identifier: {{@key}}{{#if formatted_filesize}} | size: {{formatted_filesize}}{{/if}} | type: {{#is_vector}}vector{{/is_vector}}{{^is_vector}}raster{{/is_vector}} data</p>
80
+ <h3>{{tileJSON.name}}</h3>
81
+ <div class="identifier">identifier: {{@key}}{{#if formatted_filesize}} | size: {{formatted_filesize}}{{/if}}</div>
82
+ <div class="identifier">type: {{#is_vector}}vector{{/is_vector}}{{^is_vector}}raster{{/is_vector}} data {{#if source_type}} | ext: {{source_type}}{{/if}}</div>
82
83
  <p class="services">
83
84
  services: <a href="{{public_url}}data/{{@key}}.json{{&../key_query}}">TileJSON</a>
84
85
  {{#if wmts_link}}
package/src/main.js CHANGED
@@ -7,8 +7,9 @@ import path from 'path';
7
7
  import { fileURLToPath } from 'url';
8
8
  import request from 'request';
9
9
  import { server } from './server.js';
10
-
11
10
  import MBTiles from '@mapbox/mbtiles';
11
+ import { isValidHttpUrl } from './utils.js';
12
+ import { PMtilesOpen, GetPMtilesInfo } from './pmtiles_adapter.js';
12
13
 
13
14
  const __filename = fileURLToPath(import.meta.url);
14
15
  const __dirname = path.dirname(__filename);
@@ -25,9 +26,15 @@ import { program } from 'commander';
25
26
  program
26
27
  .description('tileserver-gl startup options')
27
28
  .usage('tileserver-gl [mbtiles] [options]')
29
+ .option(
30
+ '--file <file>',
31
+ 'MBTiles or PMTiles file\n' +
32
+ '\t ignored if the configuration file is also specified',
33
+ )
28
34
  .option(
29
35
  '--mbtiles <file>',
30
- 'MBTiles file (uses demo configuration);\n' +
36
+ '(DEPRECIATED) MBTiles file\n' +
37
+ '\t ignored if file is also specified' +
31
38
  '\t ignored if the configuration file is also specified',
32
39
  )
33
40
  .option(
@@ -55,7 +62,7 @@ const opts = program.opts();
55
62
 
56
63
  console.log(`Starting ${packageJson.name} v${packageJson.version}`);
57
64
 
58
- const startServer = (configPath, config) => {
65
+ const StartServer = (configPath, config) => {
59
66
  let publicUrl = opts.public_url;
60
67
  if (publicUrl && publicUrl.lastIndexOf('/') !== publicUrl.length - 1) {
61
68
  publicUrl += '/';
@@ -74,135 +81,205 @@ const startServer = (configPath, config) => {
74
81
  });
75
82
  };
76
83
 
77
- const startWithMBTiles = (mbtilesFile) => {
78
- console.log(`[INFO] Automatically creating config file for ${mbtilesFile}`);
84
+ const StartWithInputFile = async (inputFile) => {
85
+ console.log(`[INFO] Automatically creating config file for ${inputFile}`);
79
86
  console.log(`[INFO] Only a basic preview style will be used.`);
80
87
  console.log(
81
88
  `[INFO] See documentation to learn how to create config.json file.`,
82
89
  );
83
90
 
84
- mbtilesFile = path.resolve(process.cwd(), mbtilesFile);
91
+ let inputFilePath;
92
+ if (isValidHttpUrl(inputFile)) {
93
+ inputFilePath = process.cwd();
94
+ } else {
95
+ inputFile = path.resolve(process.cwd(), inputFile);
96
+ inputFilePath = path.dirname(inputFile);
85
97
 
86
- const mbtilesStats = fs.statSync(mbtilesFile);
87
- if (!mbtilesStats.isFile() || mbtilesStats.size === 0) {
88
- console.log(`ERROR: Not valid MBTiles file: ${mbtilesFile}`);
89
- process.exit(1);
90
- }
91
- const instance = new MBTiles(mbtilesFile + '?mode=ro', (err) => {
92
- if (err) {
93
- console.log('ERROR: Unable to open MBTiles.');
94
- console.log(`Make sure ${path.basename(mbtilesFile)} is valid MBTiles.`);
98
+ const inputFileStats = fs.statSync(inputFile);
99
+ if (!inputFileStats.isFile() || inputFileStats.size === 0) {
100
+ console.log(`ERROR: Not a valid input file: `);
95
101
  process.exit(1);
96
102
  }
103
+ }
97
104
 
98
- instance.getInfo((err, info) => {
99
- if (err || !info) {
100
- console.log('ERROR: Metadata missing in the MBTiles.');
101
- console.log(
102
- `Make sure ${path.basename(mbtilesFile)} is valid MBTiles.`,
103
- );
104
- process.exit(1);
105
- }
106
- const bounds = info.bounds;
105
+ const styleDir = path.resolve(
106
+ __dirname,
107
+ '../node_modules/tileserver-gl-styles/',
108
+ );
107
109
 
108
- const styleDir = path.resolve(
109
- __dirname,
110
- '../node_modules/tileserver-gl-styles/',
111
- );
110
+ const config = {
111
+ options: {
112
+ paths: {
113
+ root: styleDir,
114
+ fonts: 'fonts',
115
+ styles: 'styles',
116
+ mbtiles: inputFilePath,
117
+ pmtiles: inputFilePath,
118
+ },
119
+ },
120
+ styles: {},
121
+ data: {},
122
+ };
112
123
 
113
- const config = {
114
- options: {
115
- paths: {
116
- root: styleDir,
117
- fonts: 'fonts',
118
- styles: 'styles',
119
- mbtiles: path.dirname(mbtilesFile),
120
- },
121
- },
122
- styles: {},
123
- data: {},
124
- };
125
-
126
- if (
127
- info.format === 'pbf' &&
128
- info.name.toLowerCase().indexOf('openmaptiles') > -1
129
- ) {
124
+ const extension = inputFile.split('.').pop().toLowerCase();
125
+ if (extension === 'pmtiles') {
126
+ let FileOpenInfo = PMtilesOpen(inputFile);
127
+ const metadata = await GetPMtilesInfo(FileOpenInfo);
128
+
129
+ if (
130
+ metadata.format === 'pbf' &&
131
+ metadata.name.toLowerCase().indexOf('openmaptiles') > -1
132
+ ) {
133
+ if (isValidHttpUrl(inputFile)) {
130
134
  config['data'][`v3`] = {
131
- mbtiles: path.basename(mbtilesFile),
135
+ pmtiles: inputFile,
132
136
  };
137
+ } else {
138
+ config['data'][`v3`] = {
139
+ pmtiles: path.basename(inputFile),
140
+ };
141
+ }
133
142
 
134
- const styles = fs.readdirSync(path.resolve(styleDir, 'styles'));
135
- for (const styleName of styles) {
136
- const styleFileRel = styleName + '/style.json';
137
- const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
138
- if (fs.existsSync(styleFile)) {
139
- config['styles'][styleName] = {
140
- style: styleFileRel,
141
- tilejson: {
142
- bounds: bounds,
143
- },
144
- };
145
- }
143
+ const styles = fs.readdirSync(path.resolve(styleDir, 'styles'));
144
+ for (const styleName of styles) {
145
+ const styleFileRel = styleName + '/style.json';
146
+ const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
147
+ if (fs.existsSync(styleFile)) {
148
+ config['styles'][styleName] = {
149
+ style: styleFileRel,
150
+ tilejson: {
151
+ bounds: metadata.bounds,
152
+ },
153
+ };
146
154
  }
155
+ }
156
+ } else {
157
+ console.log(
158
+ `WARN: PMTiles not in "openmaptiles" format. Serving raw data only...`,
159
+ );
160
+ if (isValidHttpUrl(inputFile)) {
161
+ config['data'][(metadata.id || 'pmtiles').replace(/[?/:]/g, '_')] = {
162
+ pmtiles: inputFile,
163
+ };
147
164
  } else {
148
- console.log(
149
- `WARN: MBTiles not in "openmaptiles" format. Serving raw data only...`,
150
- );
151
- config['data'][
152
- (info.id || 'mbtiles')
153
- .replace(/\//g, '_')
154
- .replace(/:/g, '_')
155
- .replace(/\?/g, '_')
156
- ] = {
157
- mbtiles: path.basename(mbtilesFile),
165
+ config['data'][(metadata.id || 'pmtiles').replace(/[?/:]/g, '_')] = {
166
+ pmtiles: path.basename(inputFile),
158
167
  };
159
168
  }
169
+ }
160
170
 
161
- if (opts.verbose) {
162
- console.log(JSON.stringify(config, undefined, 2));
163
- } else {
164
- console.log('Run with --verbose to see the config file here.');
171
+ if (opts.verbose) {
172
+ console.log(JSON.stringify(config, undefined, 2));
173
+ } else {
174
+ console.log('Run with --verbose to see the config file here.');
175
+ }
176
+
177
+ return StartServer(null, config);
178
+ } else {
179
+ if (isValidHttpUrl(inputFile)) {
180
+ console.log(
181
+ `ERROR: MBTiles does not support web based files. "${inputFile}" is not a valid data file.`,
182
+ );
183
+ process.exit(1);
184
+ }
185
+ const instance = new MBTiles(inputFile + '?mode=ro', (err) => {
186
+ if (err) {
187
+ console.log('ERROR: Unable to open MBTiles.');
188
+ console.log(`Make sure ${path.basename(inputFile)} is valid MBTiles.`);
189
+ process.exit(1);
165
190
  }
166
191
 
167
- return startServer(null, config);
192
+ instance.getInfo((err, info) => {
193
+ if (err || !info) {
194
+ console.log('ERROR: Metadata missing in the MBTiles.');
195
+ console.log(
196
+ `Make sure ${path.basename(inputFile)} is valid MBTiles.`,
197
+ );
198
+ process.exit(1);
199
+ }
200
+ const bounds = info.bounds;
201
+
202
+ if (
203
+ info.format === 'pbf' &&
204
+ info.name.toLowerCase().indexOf('openmaptiles') > -1
205
+ ) {
206
+ config['data'][`v3`] = {
207
+ mbtiles: path.basename(inputFile),
208
+ };
209
+
210
+ const styles = fs.readdirSync(path.resolve(styleDir, 'styles'));
211
+ for (const styleName of styles) {
212
+ const styleFileRel = styleName + '/style.json';
213
+ const styleFile = path.resolve(styleDir, 'styles', styleFileRel);
214
+ if (fs.existsSync(styleFile)) {
215
+ config['styles'][styleName] = {
216
+ style: styleFileRel,
217
+ tilejson: {
218
+ bounds: bounds,
219
+ },
220
+ };
221
+ }
222
+ }
223
+ } else {
224
+ console.log(
225
+ `WARN: MBTiles not in "openmaptiles" format. Serving raw data only...`,
226
+ );
227
+ config['data'][(info.id || 'mbtiles').replace(/[?/:]/g, '_')] = {
228
+ mbtiles: path.basename(inputFile),
229
+ };
230
+ }
231
+
232
+ if (opts.verbose) {
233
+ console.log(JSON.stringify(config, undefined, 2));
234
+ } else {
235
+ console.log('Run with --verbose to see the config file here.');
236
+ }
237
+
238
+ return StartServer(null, config);
239
+ });
168
240
  });
169
- });
241
+ }
170
242
  };
171
243
 
172
244
  fs.stat(path.resolve(opts.config), (err, stats) => {
173
245
  if (err || !stats.isFile() || stats.size === 0) {
174
- let mbtiles = opts.mbtiles;
175
- if (!mbtiles) {
246
+ let inputFile;
247
+ if (opts.file) {
248
+ inputFile = opts.file;
249
+ } else if (opts.mbtiles) {
250
+ inputFile = opts.mbtiles;
251
+ }
252
+
253
+ if (inputFile) {
254
+ return StartWithInputFile(inputFile);
255
+ } else {
176
256
  // try to find in the cwd
177
257
  const files = fs.readdirSync(process.cwd());
178
258
  for (const filename of files) {
179
- if (filename.endsWith('.mbtiles')) {
180
- const mbTilesStats = fs.statSync(filename);
181
- if (mbTilesStats.isFile() && mbTilesStats.size > 0) {
182
- mbtiles = filename;
259
+ if (filename.endsWith('.mbtiles') || filename.endsWith('.pmtiles')) {
260
+ const inputFilesStats = fs.statSync(filename);
261
+ if (inputFilesStats.isFile() && inputFilesStats.size > 0) {
262
+ inputFile = filename;
183
263
  break;
184
264
  }
185
265
  }
186
266
  }
187
- if (mbtiles) {
188
- console.log(`No MBTiles specified, using ${mbtiles}`);
189
- return startWithMBTiles(mbtiles);
267
+ if (inputFile) {
268
+ console.log(`No input file specified, using ${inputFile}`);
269
+ return StartWithInputFile(inputFile);
190
270
  } else {
191
271
  const url =
192
272
  'https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/zurich_switzerland.mbtiles';
193
273
  const filename = 'zurich_switzerland.mbtiles';
194
274
  const stream = fs.createWriteStream(filename);
195
- console.log(`No MBTiles found`);
275
+ console.log(`No input file found`);
196
276
  console.log(`[DEMO] Downloading sample data (${filename}) from ${url}`);
197
- stream.on('finish', () => startWithMBTiles(filename));
277
+ stream.on('finish', () => StartWithInputFile(filename));
198
278
  return request.get(url).pipe(stream);
199
279
  }
200
280
  }
201
- if (mbtiles) {
202
- return startWithMBTiles(mbtiles);
203
- }
204
281
  } else {
205
282
  console.log(`Using specified config file from ${opts.config}`);
206
- return startServer(opts.config, null);
283
+ return StartServer(opts.config, null);
207
284
  }
208
285
  });
@@ -0,0 +1,151 @@
1
+ import fs from 'node:fs';
2
+ import PMTiles from 'pmtiles';
3
+ import { isValidHttpUrl } from './utils.js';
4
+
5
+ class PMTilesFileSource {
6
+ constructor(fd) {
7
+ this.fd = fd;
8
+ }
9
+ getKey() {
10
+ return this.fd;
11
+ }
12
+ async getBytes(offset, length) {
13
+ const buffer = Buffer.alloc(length);
14
+ await ReadFileBytes(this.fd, buffer, offset);
15
+ const ab = buffer.buffer.slice(
16
+ buffer.byteOffset,
17
+ buffer.byteOffset + buffer.byteLength,
18
+ );
19
+ return { data: ab };
20
+ }
21
+ }
22
+
23
+ /**
24
+ *
25
+ * @param fd
26
+ * @param buffer
27
+ * @param offset
28
+ */
29
+ async function ReadFileBytes(fd, buffer, offset) {
30
+ return new Promise((resolve, reject) => {
31
+ fs.read(fd, buffer, 0, buffer.length, offset, (err) => {
32
+ if (err) {
33
+ return reject(err);
34
+ }
35
+ resolve();
36
+ });
37
+ });
38
+ }
39
+
40
+ /**
41
+ *
42
+ * @param FilePath
43
+ */
44
+ export function PMtilesOpen(FilePath) {
45
+ let pmtiles = undefined;
46
+
47
+ if (isValidHttpUrl(FilePath)) {
48
+ const source = new PMTiles.FetchSource(FilePath);
49
+ pmtiles = new PMTiles.PMTiles(source);
50
+ } else {
51
+ const fd = fs.openSync(FilePath, 'r');
52
+ const source = new PMTilesFileSource(fd);
53
+ pmtiles = new PMTiles.PMTiles(source);
54
+ }
55
+ return pmtiles;
56
+ }
57
+
58
+ /**
59
+ *
60
+ * @param pmtiles
61
+ */
62
+ export async function GetPMtilesInfo(pmtiles) {
63
+ const header = await pmtiles.getHeader();
64
+ const metadata = await pmtiles.getMetadata();
65
+
66
+ //Add missing metadata from header
67
+ metadata['format'] = GetPmtilesTileType(header.tileType).type;
68
+ metadata['minzoom'] = header.minZoom;
69
+ metadata['maxzoom'] = header.maxZoom;
70
+
71
+ if (header.minLon && header.minLat && header.maxLon && header.maxLat) {
72
+ metadata['bounds'] = [
73
+ header.minLon,
74
+ header.minLat,
75
+ header.maxLon,
76
+ header.maxLat,
77
+ ];
78
+ } else {
79
+ metadata['bounds'] = [-180, -85.05112877980659, 180, 85.0511287798066];
80
+ }
81
+
82
+ if (header.centerZoom) {
83
+ metadata['center'] = [
84
+ header.centerLon,
85
+ header.centerLat,
86
+ header.centerZoom,
87
+ ];
88
+ } else {
89
+ metadata['center'] = [
90
+ header.centerLon,
91
+ header.centerLat,
92
+ parseInt(metadata['maxzoom']) / 2,
93
+ ];
94
+ }
95
+
96
+ return metadata;
97
+ }
98
+
99
+ /**
100
+ *
101
+ * @param pmtiles
102
+ * @param z
103
+ * @param x
104
+ * @param y
105
+ */
106
+ export async function GetPMtilesTile(pmtiles, z, x, y) {
107
+ const header = await pmtiles.getHeader();
108
+ const TileType = GetPmtilesTileType(header.tileType);
109
+ let zxyTile = await pmtiles.getZxy(z, x, y);
110
+ if (zxyTile && zxyTile.data) {
111
+ zxyTile = Buffer.from(zxyTile.data);
112
+ } else {
113
+ zxyTile = undefined;
114
+ }
115
+ return { data: zxyTile, header: TileType.header };
116
+ }
117
+
118
+ /**
119
+ *
120
+ * @param typenum
121
+ */
122
+ function GetPmtilesTileType(typenum) {
123
+ let head = {};
124
+ let tileType;
125
+ switch (typenum) {
126
+ case 0:
127
+ tileType = 'Unknown';
128
+ break;
129
+ case 1:
130
+ tileType = 'pbf';
131
+ head['Content-Type'] = 'application/x-protobuf';
132
+ break;
133
+ case 2:
134
+ tileType = 'png';
135
+ head['Content-Type'] = 'image/png';
136
+ break;
137
+ case 3:
138
+ tileType = 'jpeg';
139
+ head['Content-Type'] = 'image/jpeg';
140
+ break;
141
+ case 4:
142
+ tileType = 'webp';
143
+ head['Content-Type'] = 'image/webp';
144
+ break;
145
+ case 5:
146
+ tileType = 'avif';
147
+ head['Content-Type'] = 'image/avif';
148
+ break;
149
+ }
150
+ return { type: tileType, header: head };
151
+ }