@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
6 lines (5 loc) • 7.93 kB
JavaScript
/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.33/esri/copyright.txt for details.
*/
import{_ as t}from"../../../chunks/tslib.es6.js";import e from"../../../core/Error.js";import{property as r}from"../../../core/accessorSupport/decorators/property.js";import"../../../core/has.js";import"../../../core/Logger.js";import"../../../core/RandomLCG.js";import{subclass as s}from"../../../core/accessorSupport/decorators/subclass.js";import o from"../../../geometry/Extent.js";import a from"../../../geometry/Point.js";import i from"../../../geometry/SpatialReference.js";import n from"../PixelBlock.js";import l from"../RasterInfo.js";import f from"../RasterStorageInfo.js";import c from"./BaseRaster.js";import{parseSpatialReference as p,parsePAMInfo as m}from"./pamParser.js";import{getElement as h,getElementValue as u}from"./xmlUtilities.js";import{isPlatformLittleEndian as g}from"../rasterFormats/utils.js";import{estimateStatisticsFromHistograms as d}from"../rasterFunctions/stretchUtils.js";const y=new Map;y.set("Int8","s8"),y.set("UInt8","u8"),y.set("Int16","s16"),y.set("UInt16","u16"),y.set("Int32","s32"),y.set("UInt32","u32"),y.set("Float32","f32"),y.set("Float64","f32"),y.set("Double64","f32");const x=new Map;x.set("none",{blobExtension:".til",isOneSegment:!0,decoderFormat:"bip"}),x.set("lerc",{blobExtension:".lrc",isOneSegment:!1,decoderFormat:"lerc"}),x.set("deflate",{blobExtension:".pzp",isOneSegment:!0,decoderFormat:"deflate"}),x.set("jpeg",{blobExtension:".pjg",isOneSegment:!0,decoderFormat:"jpg"});let w=class extends c{constructor(){super(...arguments),this._files=null,this._storageIndex=null,this.datasetFormat="MRF"}async fetchRawTile(t,e,r,s={}){const{blockWidth:o,blockHeight:a,blockBoundary:i}=this.rasterInfo.storageInfo,l=i[t];if(!l||l.maxRow<e||l.maxCol<r||l.minRow>e||l.minCol>r)return null;const{bandCount:f,pixelType:c}=this.rasterInfo,{ranges:p,actualTileWidth:m,actualTileHeight:h}=this._getTileLocation(t,e,r);if(!p||0===p.length)return null;if(0===p[0].from&&0===p[0].to){const t=new Uint8Array(o*a);return new n({width:o,height:a,pixels:void 0,mask:t,validPixelCount:0})}const{bandIds:u}=this.ioConfig,g=this._getBandSegmentCount(),d=[];let y=0;for(y=0;y<g;y++)u&&!u.includes(y)||d.push(this.request(this._files.data,{range:{from:p[y].from,to:p[y].to},responseType:"array-buffer",signal:s.signal}));const w=await Promise.all(d),I=w.map((t=>t.data.byteLength)).reduce(((t,e)=>t+e)),b=new Uint8Array(I),R=[];let A=0;for(y=0;y<g;y++)R.push(A),b.set(new Uint8Array(w[y].data),A),A+=w[y].data.byteLength;const F=x.get(this.rasterInfo.storageInfo.compression).decoderFormat,_=await this.decodePixelBlock(b.buffer,{width:o,height:a,format:F,planes:u?.length||f,offsets:R,pixelType:c});if(null==_)return null;let{noDataValue:S}=this.rasterInfo;if(null!=S&&"lerc"!==F&&!_.mask&&(S=S[0],null!=S)){const t=_.width*_.height,e=new Uint8Array(t);if(Math.abs(S)>1e24)for(y=0;y<t;y++)Math.abs((_.pixels[0][y]-S)/S)>1e-6&&(e[y]=1);else for(y=0;y<t;y++)_.pixels[0][y]!==S&&(e[y]=1);_.mask=e}let k=0,M=0;if(m!==o||h!==a){let t=_.mask;if(t)for(y=0;y<a;y++)if(M=y*o,y<h)for(k=m;k<o;k++)t[M+k]=0;else for(k=0;k<o;k++)t[M+k]=0;else for(t=new Uint8Array(o*a),_.mask=t,y=0;y<h;y++)for(M=y*o,k=0;k<m;k++)t[M+k]=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:o}=this._parseHeader(r.data),{skipMapInfo:a,skipExtensions:i=[]}=this.ioConfig;if(!i.includes("aux.xml")&&!a){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=d(e.histograms)))}a&&this.updateImageSpaceRasterInfo(s),this._set("rasterInfo",s),this._files=o;const n=await this.request(o.index,{responseType:"array-buffer",signal:e});this._storageIndex=I(n.data);const{blockWidth:l,blockHeight:f}=this.rasterInfo.storageInfo,c=this.rasterInfo.storageInfo.pyramidScalingFactor,{width:p,height:m}=this.rasterInfo,h=[],u=this._getBandSegmentCount();let g=0,y=-1;for(;g<this._storageIndex.length;){y++;const t=Math.ceil(p/l/c**y)-1,e=Math.ceil(m/f/c**y)-1;g+=(t+1)*(e+1)*u*4,h.push({maxRow:e,maxCol:t,minCol:0,minRow:0})}this.rasterInfo.storageInfo.blockBoundary=h,y>0&&(this.rasterInfo.storageInfo.firstPyramidLevel=1,this.rasterInfo.storageInfo.maximumPyramidLevel=y),this.updateTileInfo()}_getBandSegmentCount(){return x.get(this.rasterInfo.storageInfo.compression).isOneSegment?1:this.rasterInfo.bandCount}_getTileLocation(t,e,r){const{blockWidth:s,blockHeight:o,pyramidScalingFactor:a}=this.rasterInfo.storageInfo,{width:i,height:n}=this.rasterInfo,l=this._getBandSegmentCount();let f,c,p,m=0,h=0;for(p=0;p<t;p++)h=a**p,f=Math.ceil(i/s/h),c=Math.ceil(n/o/h),m+=f*c;h=a**t,f=Math.ceil(i/s/h),c=Math.ceil(n/o/h),m+=e*f+r,m*=4*l;const u=this._storageIndex.subarray(m,m+4*l);let g=0,d=0;const y=[];for(let x=0;x<l;x++)g=u[4*x]*2**32+u[4*x+1],d=g+u[4*x+2]*2**32+u[4*x+3],y.push({from:g,to:d});return{ranges:y,actualTileWidth:r<f-1?s:Math.ceil(i/h)-s*(f-1),actualTileHeight:e<c-1?o:Math.ceil(n/h)-o*(c-1)}}_parseHeader(t){const r=h(t,"MRF_META/Raster");if(!r)throw new e("mrf:open","not a valid MRF format");const s=h(r,"Size"),n=parseInt(s.getAttribute("x"),10),c=parseInt(s.getAttribute("y"),10),m=parseInt(s.getAttribute("c"),10),g=(u(r,"Compression")||"none").toLowerCase();if(!x.has(g))throw new e("mrf:open","currently does not support compression "+g);const d=u(r,"DataType")||"UInt8",w=y.get(d);if(null==w)throw new e("mrf:open","currently does not support pixel type "+d);const I=h(r,"PageSize"),b=parseInt(I.getAttribute("x"),10),R=parseInt(I.getAttribute("y"),10),A=h(r,"DataValues");let F,_;A&&(_=A.getAttribute("NoData"),null!=_&&(F=_.trim().split(" ").map((t=>parseFloat(t)))));if(h(t,"MRF_META/CachedSource"))throw new e("mrf:open","currently does not support MRF referencing other data files");const S=h(t,"MRF_META/GeoTags"),k=h(S,"BoundingBox");let M,j=!1;if(null!=k){const t=parseFloat(k.getAttribute("minx")),e=parseFloat(k.getAttribute("miny")),r=parseFloat(k.getAttribute("maxx")),s=parseFloat(k.getAttribute("maxy")),a=u(S,"Projection")||"";let n=i.WGS84;if("LOCAL_CS[]"!==a)if(a.toLowerCase().startsWith("epsg:")){const t=Number(a.slice(5));isNaN(t)||0===t||(n=new i({wkid:t}))}else n=p(a)??i.WGS84;else j=!0,n=new i({wkid:3857});M=new o(t,e,r,s),M.spatialReference=n}else j=!0,M=new o({xmin:-.5,ymin:.5-c,xmax:n-.5,ymax:.5,spatialReference:new i({wkid:3857})});const C=h(t,"MRF_META/Rsets"),T=parseInt(C?.getAttribute("scale")||"2",10),L=M.spatialReference,U=new f({origin:new a({x:M.xmin,y:M.ymax,spatialReference:L}),blockWidth:b,blockHeight:R,pyramidBlockWidth:b,pyramidBlockHeight:R,compression:g,pyramidScalingFactor:T}),B=new a({x:M.width/n,y:M.height/c,spatialReference:L}),E=new l({width:n,height:c,extent:M,isPseudoSpatialReference:j,spatialReference:L,bandCount:m,pixelType:w,pixelSize:B,noDataValue:F,storageInfo:U}),P=u(t,"datafile"),W=u(t,"IndexFile");return{rasterInfo:E,files:{mrf:this.url,index:W||this.url.replace(".mrf",".idx"),data:P||this.url.replace(".mrf",x.get(g).blobExtension)}}}async _fetchAuxiliaryData(t){try{const{data:e}=await this.request(this.url+".aux.xml",{responseType:"xml",signal:t?.signal});return m(e)}catch{return null}}};function I(t){if(t.byteLength%16>0)throw new Error("invalid array buffer must be multiples of 16");let e,r,s,o,a,i;if(g){for(r=new Uint8Array(t),o=new ArrayBuffer(t.byteLength),s=new Uint8Array(o),a=0;a<t.byteLength/4;a++)for(i=0;i<4;i++)s[4*a+i]=r[4*a+3-i];e=new Uint32Array(o)}else e=new Uint32Array(t);return e}t([r()],w.prototype,"_files",void 0),t([r()],w.prototype,"_storageIndex",void 0),t([r({type:String,json:{write:!0}})],w.prototype,"datasetFormat",void 0),w=t([s("esri.layers.support.rasterDatasets.MRFRaster")],w);const b=w;export{b as default};