UNPKG

s2tiles

Version:

S2Tiles is a single-file archive format for tiled data that works for both WM and S2 projections. The goal is to be a "cloud optimized tile store" for vector/raster/grid data.

4 lines (2 loc) 4.22 kB
import{promisify as $} from"util";import{brotliCompress as T,brotliDecompress as w,gunzip as N,gzip as D} from"zlib";import{existsSync as Z,openSync as B,read as A,write as O,writeSync as l} from"fs";var u=function(j,q){const{min:F,pow:G}=Math;let H=0,J=F(q-j,5);do H+=G(1<<J,2);while(J--!==0);return H*V},L=function(j,q=0){return j.readUint32LE(2+q)*(1<<16)+j.readUint16LE(q)},y=function(j,q,F=0){const G=q&65535,H=q/(1<<16);j.writeUInt16LE(G,F),j.writeUInt32LE(H,F+2)};function z(j,q,F){const{max:G,pow:H}=Math,J=[];while(j>=5)J.push([5,q&31,F&31]),q>>=5,F>>=5,j=G(j-5,0);return J.push([j,q,F]),J.map(([K,Q,X])=>{let W=0;W+=X*(1<<K)+Q;while(K--!==0)W+=H(1<<K,2);return W})}async function R(j,q){if(q===Y.None)return j;else if(q===Y.Gzip)return new Uint8Array((await _(j)).buffer);else if(q===Y.Brotli)return new Uint8Array((await I(j)).buffer);else throw new Error("Decompression type not supported")}async function b(j,q){if(q===Y.None)return j;else if(q===Y.Gzip)return new Uint8Array((await h(j)).buffer);else if(q===Y.Brotli)return new Uint8Array((await x(j)).buffer);else throw new Error("Compression type not supported")}var _=$(N),I=$(w),h=$(D),x=$(T),k=$(A),M=$(O),Y={Unknown:0,None:1,Gzip:2,Brotli:3,Zstd:4},V=10,g=1365*V,v=131072,S=g*6,U=v+S;class E{j;file;#q=!1;offset=U;maxzoom=0;version=1;compression;metadata;decoder=new TextDecoder;encoder=new TextEncoder;constructor(j,q,F){this.path=j;if(this.maxzoom=q??0,this.compression=F??Y.Gzip,!Z(j))l(B(j,"w"),new Uint8Array(new ArrayBuffer(U)));this.file=B(j,"r+")}async getMetadata(){if(this.metadata!==void 0)return this.metadata;return await this.setup(),this.metadata}async setup(){if(this.#q)return;this.#q=!0;const j=Buffer.alloc(U);await k(this.file,j,0,U,0);const q=new DataView(j.buffer,0,U);if(q.getUint16(0,!0)!==12883)throw new Error(`Bad metadata from ${this.path}`);this.version=q.getUint16(2,!0),this.maxzoom=q.getUint8(4),this.compression=q.getUint8(5);const F=q.getUint32(6,!0);if(F===0)throw new Error(`Failed to extrapolate ${this.path} metadata`);const G=await R(j.subarray(10,10+F),this.compression);this.metadata=JSON.parse(this.decoder.decode(G))}async hasTileWM(j,q,F){return await this.hasTileS2(0,j,q,F)}async hasTileS2(j,q,F,G){await this.setup();const H=await this.#j(j,q,F,G,!1);if(H===void 0)return!1;const J=Buffer.alloc(V);await k(this.file,J,0,V,H);const[K,Q]=[L(J),J.readUInt32LE(6)];return K!==0&&Q!==0}async getTileWM(j,q,F){return await this.setup(),await this.getTileS2(0,j,q,F)}async getTileS2(j,q,F,G){await this.setup();const{compression:H}=this,J=await this.#j(j,q,F,G,!1);if(J===void 0)return;const K=Buffer.alloc(V);await k(this.file,K,0,V,J);const[Q,X]=[L(K),K.readUint32LE(6)],W=new Uint8Array(new ArrayBuffer(X));return await k(this.file,W,0,X,Q),await R(W,H)}async writeTileWM(j,q,F,G){await this.putTile(0,j,q,F,G)}async writeTileS2(j,q,F,G,H){await this.putTile(j,q,F,G,H)}async commit(j,q){const F=Buffer.alloc(10);F.writeUint8(83,0),F.writeUint8(50,1),F.writeUint16LE(this.version,2),F.writeUint8(this.maxzoom,4),F.writeUint8(q??this.compression,5);let G=this.encoder.encode(JSON.stringify(j));if(G=await b(G,this.compression),G.byteLength>v-10)throw new Error("Metadata too large for S2Tiles");F.writeUint32LE(G.byteLength,6),await M(this.file,F,0,10,0),await M(this.file,G,0,G.byteLength,10)}async putTile(j,q,F,G,H){const J=H.byteLength,K=[this.offset,J];H=await b(H,this.compression),await M(this.file,H,0,J,this.offset),this.offset+=J,await this.#G(j,q,F,G,K)}async#G(j,q,F,G,H){const J=await this.#j(j,q,F,G,!0);await this.#F(J,H)}async#j(j,q,F,G,H){const{maxzoom:J}=this,K=Buffer.alloc(V);let Q=v+j*g,X,W=0;const P=z(q,F,G);while(P.length!==0){const C=P.shift()??0;if(W++,Q+=C*V,P.length!==0){if(J%5===0&&P.length===1&&q===J&&P[0]===0)return Q;if(await k(this.file,K,0,V,Q),X=L(K),X===0)if(H)Q=await this.#H(Q,W*5);else return 0;else Q=X}}return Q}async#H(j,q){const F=u(q,this.maxzoom),G=this.offset,H=[G,F];return await M(this.file,Buffer.alloc(F),0,F,G),this.offset+=F,await this.#F(j,H),G}async#F(j,q){const[F,G]=q,H=Buffer.alloc(V);y(H,F),H.writeUint32LE(G,6),await M(this.file,H,0,V,j)}}export{z as getS2TilePath,E as S2TilesStore,Y as Compression}; //# debugId=71C545172E8894B664756e2164756e21