diff --git a/src/pmtiles_adapter.js b/src/pmtiles_adapter.js index 7358bde..723b916 100644 --- a/src/pmtiles_adapter.js +++ b/src/pmtiles_adapter.js @@ -1,24 +1,24 @@ import fs from 'node:fs'; -import zlib from 'zlib'; import PMTiles from 'pmtiles'; -export const GetPMtilesHeader = async (pmtilesFile) => { - var buffer = await ReadBytes(pmtilesFile, 0, 127); - const header = PMTiles.bytesToHeader(buffer, undefined); - return header; +var PMTilesLocalSource = class { + constructor(file) { + this.file = file; + } + getKey() { + return this.file.name; + } + async getBytes(offset, length) { + const blob = await ReadFileBytes(this.file, offset, length); + return { data: blob }; + } }; export const GetPMtilesInfo = async (pmtilesFile) => { - //Get metadata from pmtiles file - var header = await GetPMtilesHeader(pmtilesFile); - const metadataBytes = await ReadBytes( - pmtilesFile, - header.jsonMetadataOffset, - header.jsonMetadataLength, - ); - const metadataDecomp = await GetPMtilesDecompress(header, metadataBytes); - const dec = new TextDecoder('utf-8'); - const metadata = JSON.parse(dec.decode(metadataDecomp)); + const source = new PMTilesLocalSource(pmtilesFile); + const pmtiles = new PMTiles.PMTiles(source); + const header = await pmtiles.getHeader(); + const metadata = await pmtiles.getMetadata() //Add missing metadata from header const bounds = [header.minLon, header.minLat, header.maxLon, header.maxLat]; @@ -34,45 +34,13 @@ export const GetPMtilesInfo = async (pmtilesFile) => { }; export const GetPMtilesTile = async (pmtilesFile, z, x, y) => { - const tile_id = PMTiles.zxyToTileId(z, x, y); - const header = await GetPMtilesHeader(pmtilesFile); - - if (z < header.minZoom || z > header.maxZoom) { - return undefined; - } - - let rootDirectoryOffset = header.rootDirectoryOffset; - let rootDirectoryLength = header.rootDirectoryLength; - for (let depth = 0; depth <= 3; depth++) { - const RootDirectoryBytes = await ReadBytes( - pmtilesFile, - rootDirectoryOffset, - rootDirectoryLength, - ); - const RootDirectoryBytesaDecomp = await GetPMtilesDecompress( - header, - RootDirectoryBytes, - ); - const Directory = deserializeIndex(RootDirectoryBytesaDecomp); - const entry = PMTiles.findTile(Directory, tile_id); - if (entry) { - if (entry.runLength > 0) { - const EntryBytesArrayBuff = await ReadBytes( - pmtilesFile, - header.tileDataOffset + entry.offset, - entry.length, - ); - const EntryBytes = ArrayBufferToBuffer(EntryBytesArrayBuff); - const EntryTileType = GetPmtilesTileType(header.tileType); - return { data: EntryBytes, header: EntryTileType.header }; - } else { - rootDirectoryOffset = header.leafDirectoryOffset + entry.offset; - rootDirectoryLength = entry.length; - } - } else { - return undefined; - } - } + const source = new PMTilesLocalSource(pmtilesFile); + const pmtiles = new PMTiles.PMTiles(source); + const header = await pmtiles.getHeader(); + const TileType = GetPmtilesTileType(header.tileType); + let zxyTile = await pmtiles.getZxy(z, x, y); + if(zxyTile.data !== undefined){zxyTile = ArrayBufferToBuffer(zxyTile.data);} else {zxyTile = undefined} + return { data: zxyTile, header: TileType.header }; }; /** @@ -126,16 +94,16 @@ function BufferToArrayBuffer(buffer) { * * @param ab */ -function ArrayBufferToBuffer(ab) { - var buffer = Buffer.alloc(ab.byteLength); - var view = new Uint8Array(ab); +function ArrayBufferToBuffer(array_buffer) { + var buffer = Buffer.alloc(array_buffer.byteLength); + var view = new Uint8Array(array_buffer); for (var i = 0; i < buffer.length; ++i) { buffer[i] = view[i]; } return buffer; } -const ReadBytes = async (filePath, offset, size) => { +const ReadFileBytes = async (filePath, offset, size) => { const sharedBuffer = Buffer.alloc(size); const fd = fs.openSync(filePath); // file descriptor const stats = fs.fstatSync(fd); // file details @@ -143,7 +111,7 @@ const ReadBytes = async (filePath, offset, size) => { for (let i = 0; i < size; i++) { let postion = offset + i; - await ReadFileBytes(fd, sharedBuffer, postion); + await ReadBytes(fd, sharedBuffer, postion); bytesRead = (i + 1) * size; if (bytesRead > stats.size) { // When we reach the end of file, @@ -165,7 +133,7 @@ const ReadBytes = async (filePath, offset, size) => { * @param sharedBuffer * @param offset */ -function ReadFileBytes(fd, sharedBuffer, offset) { +function ReadBytes(fd, sharedBuffer, offset) { return new Promise((resolve, reject) => { fs.read(fd, sharedBuffer, 0, sharedBuffer.length, offset, (err) => { if (err) { @@ -175,121 +143,3 @@ function ReadFileBytes(fd, sharedBuffer, offset) { }); }); } - -export const GetPMtilesDecompress = async (header, buffer) => { - const compression = header.internalCompression; - var decompressed; - if ( - compression === PMTiles.Compression.None || - compression === PMTiles.Compression.Unknown - ) { - decompressed = buffer; - } else if (compression === PMTiles.Compression.Gzip) { - decompressed = zlib.unzipSync(buffer); - } else { - throw Error('Compression method not supported'); - } - - return decompressed; -}; - -/** - * - * @param low - * @param high - */ -function toNum(low, high) { - return (high >>> 0) * 0x100000000 + (low >>> 0); -} - -/** - * - * @param l - * @param p - */ -function readVarintRemainder(l, p) { - const buf = p.buf; - let h, b; - b = buf[p.pos++]; - h = (b & 0x70) >> 4; - if (b < 0x80) return toNum(l, h); - b = buf[p.pos++]; - h |= (b & 0x7f) << 3; - if (b < 0x80) return toNum(l, h); - b = buf[p.pos++]; - h |= (b & 0x7f) << 10; - if (b < 0x80) return toNum(l, h); - b = buf[p.pos++]; - h |= (b & 0x7f) << 17; - if (b < 0x80) return toNum(l, h); - b = buf[p.pos++]; - h |= (b & 0x7f) << 24; - if (b < 0x80) return toNum(l, h); - b = buf[p.pos++]; - h |= (b & 0x01) << 31; - if (b < 0x80) return toNum(l, h); - throw new Error('Expected varint not more than 10 bytes'); -} - -/** - * - * @param p - */ -export function readVarint(p) { - const buf = p.buf; - let val, b; - - b = buf[p.pos++]; - val = b & 0x7f; - if (b < 0x80) return val; - b = buf[p.pos++]; - val |= (b & 0x7f) << 7; - if (b < 0x80) return val; - b = buf[p.pos++]; - val |= (b & 0x7f) << 14; - if (b < 0x80) return val; - b = buf[p.pos++]; - val |= (b & 0x7f) << 21; - if (b < 0x80) return val; - b = buf[p.pos]; - val |= (b & 0x0f) << 28; - - return readVarintRemainder(val, p); -} - -/** - * - * @param buffer - */ -function deserializeIndex(buffer) { - const p = { buf: new Uint8Array(buffer), pos: 0 }; - const numEntries = readVarint(p); - - var entries = []; - - let lastId = 0; - for (let i = 0; i < numEntries; i++) { - const v = readVarint(p); - entries.push({ tileId: lastId + v, offset: 0, length: 0, runLength: 1 }); - lastId += v; - } - - for (let i = 0; i < numEntries; i++) { - entries[i].runLength = readVarint(p); - } - - for (let i = 0; i < numEntries; i++) { - entries[i].length = readVarint(p); - } - - for (let i = 0; i < numEntries; i++) { - const v = readVarint(p); - if (v === 0 && i > 0) { - entries[i].offset = entries[i - 1].offset + entries[i - 1].length; - } else { - entries[i].offset = v - 1; - } - } - - return entries; -}