UNPKG

@arcgis/core

Version:

ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API

3 lines (2 loc) 8.01 kB
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.19/LICENSE.txt */ import{__decorate as t}from"tslib";import e from"../../../core/Error.js";import{property as r,subclass as s}from"../../../core/accessorSupport/decorators.js";import i from"../../../geometry/Extent.js";import o from"../../../geometry/Point.js";import a from"../../../geometry/SpatialReference.js";import n from"./BaseRaster.js";import{parseSpatialReference as l,parsePAMInfo as f}from"./pamParser.js";import{getElement as u,getElementValue as h}from"./xmlUtilities.js";import{isPlatformLittleEndian as c}from"../formats/utils.js";import{estimateStatisticsFromHistograms as p}from"../functions/stretchUtils.js";import m from"../../support/PixelBlock.js";import g from"../../support/RasterInfo.js";import d from"../../support/RasterStorageInfo.js";const x=new Map([["byte","u8"],["signedbyte","s8"],["int8","s8"],["uint8","u8"],["int16","s16"],["uint16","u16"],["int32","s32"],["uint32","u32"],["float32","f32"],["float64","f64"],["double64","f64"]]),y=new Map;y.set("none",{blobExtension:".til",isOneSegment:!0,decoderFormat:"bip"}),y.set("lerc",{blobExtension:".lrc",isOneSegment:!1,decoderFormat:"lerc"}),y.set("deflate",{blobExtension:".pzp",isOneSegment:!0,decoderFormat:"deflate"}),y.set("jpeg",{blobExtension:".pjg",isOneSegment:!0,decoderFormat:"jpg"}),y.set("qb3",{blobExtension:".pq3",isOneSegment:!0,decoderFormat:"qb3"});let b=class extends n{constructor(){super(...arguments),this._files=null,this._storageIndex=null,this.datasetFormat="MRF"}async fetchRawTile(t,e,r,s={}){const{blockWidth:i,blockHeight:o,blockBoundary:a}=this.rasterInfo.storageInfo,n=a[t];if(!n||n.maxRow<e||n.maxCol<r||n.minRow>e||n.minCol>r)return null;const{bandCount:l,pixelType:f}=this.rasterInfo,{ranges:u,actualTileWidth:h,actualTileHeight:c}=this._getTileLocation(t,e,r);if(!u||0===u.length)return null;if(u.some(t=>t.from>t.to)){const t=new Uint8Array(i*o);return new m({width:i,height:o,pixels:void 0,mask:t,validPixelCount:0})}const{bandIds:p}=this.ioConfig,g=this._getBandSegmentCount(),d=[];let x=0;for(x=0;x<g;x++)p&&!p.includes(x)||d.push(this.request(this._files.data,{range:{from:u[x].from,to:u[x].to},responseType:"array-buffer",signal:s.signal}));const b=await Promise.all(d),w=b.map(t=>t.data.byteLength).reduce((t,e)=>t+e),I=new Uint8Array(w),A=[];let F=0;for(x=0;x<g;x++)A.push(F),I.set(new Uint8Array(b[x].data),F),F+=b[x].data.byteLength;const R=y.get(this.rasterInfo.storageInfo.compression).decoderFormat,_=await this.decodePixelBlock(I.buffer,{width:i,height:o,format:R,planes:p?.length||l,offsets:A,pixelType:f}).catch(()=>null);if(null==_)return null;let{noDataValue:S}=this.rasterInfo;if(null!=S&&"lerc"!==R&&!_.mask&&(S=S[0],null!=S)){const t=_.width*_.height,e=new Uint8Array(t);if(Math.abs(S)>1e24)for(x=0;x<t;x++)Math.abs((_.pixels[0][x]-S)/S)>1e-6&&(e[x]=1);else for(x=0;x<t;x++)_.pixels[0][x]!==S&&(e[x]=1);_.mask=e}let M=0,k=0;if(h!==i||c!==o){let t=_.mask;if(t)for(x=0;x<o;x++)if(k=x*i,x<c)for(M=h;M<i;M++)t[k+M]=0;else for(M=0;M<i;M++)t[k+M]=0;else for(t=new Uint8Array(i*o),_.mask=t,x=0;x<c;x++)for(k=x*i,M=0;M<h;M++)t[k+M]=1}return _}async _open(t){this.datasetName=this.url.slice(this.url.lastIndexOf("/")+1);const e=t?t.signal:null,r=await this.request(this.url,{responseType:"xml",signal:e}),{rasterInfo:s,files:i}=this._parseHeader(r.data),{skipMapInfo:o,skipExtensions:a=[]}=this.ioConfig;if(!a.includes("aux.xml")&&!o){const e=await this._fetchAuxiliaryData(t);null!=e&&(s.statistics=e.statistics??s.statistics,s.histograms=e.histograms,e.histograms&&null==s.statistics&&(s.statistics=p(e.histograms)))}o&&this.updateImageSpaceRasterInfo(s),this._set("rasterInfo",s),this._files=i;const n=await this.request(i.index,{responseType:"array-buffer",signal:e});this._storageIndex=w(n.data);const{blockWidth:l,blockHeight:f}=this.rasterInfo.storageInfo,u=this.rasterInfo.storageInfo.pyramidScalingFactor,{width:h,height:c}=this.rasterInfo,m=[],g=this._getBandSegmentCount();let d=0,x=-1;for(;d<this._storageIndex.length;){x++;const t=Math.ceil(h/l/u**x)-1,e=Math.ceil(c/f/u**x)-1;d+=(t+1)*(e+1)*g*4,m.push({maxRow:e,maxCol:t,minCol:0,minRow:0})}this.rasterInfo.storageInfo.blockBoundary=m,x>0&&(this.rasterInfo.storageInfo.firstPyramidLevel=1,this.rasterInfo.storageInfo.maximumPyramidLevel=x),this.updateTileInfo()}_getBandSegmentCount(){return y.get(this.rasterInfo.storageInfo.compression).isOneSegment?1:this.rasterInfo.bandCount}_getTileLocation(t,e,r){const{blockWidth:s,blockHeight:i,pyramidScalingFactor:o}=this.rasterInfo.storageInfo,{width:a,height:n}=this.rasterInfo,l=this._getBandSegmentCount();let f,u,h,c=0,p=0;for(h=0;h<t;h++)p=o**h,f=Math.ceil(a/s/p),u=Math.ceil(n/i/p),c+=f*u;p=o**t,f=Math.ceil(a/s/p),u=Math.ceil(n/i/p),c+=e*f+r,c*=4*l;const m=this._storageIndex.subarray(c,c+4*l);let g=0,d=0;const x=[];for(let y=0;y<l;y++)g=m[4*y]*2**32+m[4*y+1],d=g+m[4*y+2]*2**32+m[4*y+3]-1,x.push({from:g,to:d});return{ranges:x,actualTileWidth:r<f-1?s:Math.ceil(a/p)-s*(f-1),actualTileHeight:e<u-1?i:Math.ceil(n/p)-i*(u-1)}}_parseHeader(t){const r=u(t,"MRF_META/Raster");if(!r)throw new e("mrf:open","not a valid MRF format");const s=u(r,"Size"),n=parseInt(s.getAttribute("x"),10),f=parseInt(s.getAttribute("y"),10),c=parseInt(s.getAttribute("c"),10),p=(h(r,"Compression")||"none").toLowerCase();if(!y.has(p))throw new e("mrf:open","currently does not support compression "+p);const m=h(r,"DataType")||"UInt8",b=x.get(m.toLowerCase());if(null==b)throw new e("mrf:open","currently does not support pixel type "+m);const w=u(r,"PageSize"),I=parseInt(w.getAttribute("x"),10),A=parseInt(w.getAttribute("y"),10),F=u(r,"DataValues");let R,_;F&&(_=F.getAttribute("NoData"),null!=_&&(R=_.trim().split(" ").map(t=>parseFloat(t))));if(u(t,"MRF_META/CachedSource"))throw new e("mrf:open","currently does not support MRF referencing other data files");const S=u(t,"MRF_META/GeoTags"),M=u(S,"BoundingBox");let k,C=!1;if(null!=M){const t=parseFloat(M.getAttribute("minx")),e=parseFloat(M.getAttribute("miny")),r=parseFloat(M.getAttribute("maxx")),s=parseFloat(M.getAttribute("maxy")),o=h(S,"Projection")||"";let n=a.WGS84;if("LOCAL_CS[]"!==o)if(o.toLowerCase().startsWith("epsg:")){const t=Number(o.slice(5));isNaN(t)||0===t||(n=new a({wkid:t}))}else n=l(o)??a.WGS84;else C=!0,n=new a({wkid:3857});k=new i(t,e,r,s),k.spatialReference=n}else C=!0,k=new i({xmin:-.5,ymin:.5-f,xmax:n-.5,ymax:.5,spatialReference:new a({wkid:3857})});const T=u(t,"MRF_META/Rsets"),j=parseInt(T?.getAttribute("scale")||"2",10),L=k.spatialReference,B=new d({origin:new o({x:k.xmin,y:k.ymax,spatialReference:L}),blockWidth:I,blockHeight:A,pyramidBlockWidth:I,pyramidBlockHeight:A,compression:p,pyramidScalingFactor:j}),E=new o({x:k.width/n,y:k.height/f,spatialReference:L}),P=new g({width:n,height:f,extent:k,isPseudoSpatialReference:C,spatialReference:L,bandCount:c,pixelType:b,pixelSize:E,noDataValue:R,storageInfo:B}),U=this._getAuxFullPath(h(r,"DataFile")),W=this._getAuxFullPath(h(r,"IndexFile"));return{rasterInfo:P,files:{mrf:this.url,index:W||this.url.replace(".mrf",".idx"),data:U||this.url.replace(".mrf",y.get(p).blobExtension)}}}_getAuxFullPath(t){if(!t)return null;if(t.includes("\\"))return null;if(t.includes("/"))return t.startsWith(new URL(this.url).origin)?t:null;return`${this.url.slice(0,this.url.lastIndexOf("/"))}/${t}`}async _fetchAuxiliaryData(t){try{const{data:e}=await this.request(this.url+".aux.xml",{responseType:"xml",signal:t?.signal});return f(e)}catch{return null}}};function w(t){if(t.byteLength%16>0)throw new Error("invalid array buffer must be multiples of 16");let e,r,s,i,o,a;if(c){for(r=new Uint8Array(t),i=new ArrayBuffer(t.byteLength),s=new Uint8Array(i),o=0;o<t.byteLength/4;o++)for(a=0;a<4;a++)s[4*o+a]=r[4*o+3-a];e=new Uint32Array(i)}else e=new Uint32Array(t);return e}t([r()],b.prototype,"_files",void 0),t([r()],b.prototype,"_storageIndex",void 0),t([r({type:String,json:{write:!0}})],b.prototype,"datasetFormat",void 0),b=t([s("esri.layers.raster.datasets.MRFRaster")],b);const I=b;export{I as default};