UNPKG

@arcgis/core

Version:

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

6 lines (5 loc) 9.54 kB
/* All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://js.arcgis.com/4.32/esri/copyright.txt for details. */ import{_ as e}from"../../../chunks/tslib.es6.js";import{isSome as t}from"../../../core/arrayUtils.js";import r from"../../../core/Error.js";import i from"../../../core/Logger.js";import{property as s}from"../../../core/accessorSupport/decorators/property.js";import"../../../core/has.js";import{subclass as a}from"../../../core/accessorSupport/decorators/subclass.js";import n from"../../../geometry/Extent.js";import o from"../../../geometry/Point.js";import f from"../../../geometry/SpatialReference.js";import l from"../RasterInfo.js";import u from"../RasterStorageInfo.js";import p from"./BaseRaster.js";import c from"./DBFParser.js";import{parsePAMInfo as h,parseSpatialReference as m}from"./pamParser.js";import{parseSignature as d,getPyramidIFDs as y,getMaskIFDs as g,parseIFD as x,parseFieldValues as T,isBSQConfig as I,getImageInfo as w}from"../rasterFormats/TiffDecoder.js";import R from"../rasterFormats/TiffTags.js";import{estimateStatisticsFromHistograms as b}from"../rasterFunctions/stretchUtils.js";import E from"../rasterTransforms/PolynomialTransform.js";import S from"../../../rest/support/FeatureSet.js";const _=(e,t)=>e.get(t)?.values,F=(e,t)=>e.get(t)?.values?.[0];let v=class extends p{constructor(){super(...arguments),this._files=null,this._headerInfo=null,this._bufferSize=1048576,this.datasetFormat="TIFF"}async fetchRawTile(e,t,r,i={}){if(!this._headerInfo?.isSupported||this.isBlockOutside(e,t,r))return null;const s=await this._fetchRawTiffTile(e,t,r,!1,i);if(null!=s&&this._headerInfo.hasMaskBand){const a=await this._fetchRawTiffTile(e,t,r,!0,i);null!=a&&a.pixels[0]instanceof Uint8Array&&(s.mask=a.pixels[0])}return s}async _open(e){const t=e?e.signal:null,{data:s}=await this.request(this.url,{range:{from:0,to:this._bufferSize},responseType:"array-buffer",signal:t});if(!s)throw new r("tiffraster:open","failed to open url "+this.url);this.datasetName=this.url.slice(this.url.lastIndexOf("/")+1,this.url.lastIndexOf("."));const{littleEndian:a,firstIFDPos:n,isBigTiff:o}=d(s),f=[];await this._readIFDs(f,s,a,n,0,o?8:4,t);const{imageInfo:l,rasterInfo:u}=k(f),p=y(f),c=g(f);if(this._headerInfo={littleEndian:a,isBigTiff:o,ifds:f,pyramidIFDs:p,maskIFDs:c,...l},this._set("rasterInfo",u),!l.isSupported)throw new r("tiffraster:open","this tiff is not supported: "+l.message);if(!l.tileWidth)throw new r("tiffraster:open","none-tiled tiff is not optimized for access, convert to COG and retry.");u.isPseudoSpatialReference&&i.getLogger(this).warn("The spatial reference for this tiff is unsupported. Only EPSG spatial reference codes and Esri WKTs are supported.");const h=f[0].get("PREDICTOR")?.values?.[0],m=f[0].get("SAMPLEFORMAT")?.values?.[0];if(3===m&&2===h)throw new r("tiffraster:open","unsupported horizontal difference encoding. Predictor=3 is supported for floating point data");const{skipMapInfo:x,skipExtensions:T=[]}=this.ioConfig;if(!T.includes("aux.xml")&&!x){const t=await this._fetchAuxiliaryMetaData(e);null!=t&&P(t,u)}T.includes("vat.dbf")||1!==u.bandCount||"u8"!==u.pixelType||x||(u.attributeTable=await this._fetchAuxiliaryTable(e),null!=u.attributeTable&&(u.keyProperties.DataType="thematic")),x&&this.updateImageSpaceRasterInfo(u),this.updateTileInfo()}async _readIFDs(e,t,r,i,s,a=4,n){if(!i)return null;if(i>=t.byteLength||i<0){t=(await this.request(this.url,{range:{from:i+s,to:i+s+this._bufferSize},responseType:"array-buffer",signal:n})).data,s=i+s,i=0}const o=await this._readIFD(t,r,i,s,R.tiffTags,a,n);if(e.push(o.ifd),!o.nextIFD)return null;await this._readIFDs(e,t,r,o.nextIFD-s,s,a,n)}async _readIFD(e,r,i,s,a=R.tiffTags,n=4,o){if(!e)return null;const f=x(e,r,i,s,a,n);if(f.success){const i=[];if(f.ifd?.forEach((e=>{e.values||i.push(e)})),i.length>0){const a=i.map((e=>e.offlineOffsetSize)).filter(t),n=Math.min.apply(null,a.map((e=>e[0])));if(Math.min.apply(null,a.map((e=>e[0]+e[1])))-n<=this._bufferSize){const{data:t}=await this.request(this.url,{range:{from:n,to:n+this._bufferSize},responseType:"array-buffer",signal:o});e=t,s=n,i.forEach((t=>T(e,r,t,s)))}}if(f.ifd?.has("GEOKEYDIRECTORY")){const t=f.ifd.get("GEOKEYDIRECTORY"),i=t?.values;if(i&&i.length>4){const a=i[0]+"."+i[1]+"."+i[2],n=await this._readIFD(e,r,t.valueOffset+6-s,s,R.geoKeys,2,o);t.data=n.ifd,t.data&&t.data.set("GEOTIFFVersion",{id:0,type:2,valueCount:1,valueOffset:null,values:[a]})}}return f}if(f.requiredBufferSize&&f.requiredBufferSize!==e.byteLength){const t=await this.request(this.url,{range:{from:s,to:s+f.requiredBufferSize+4},responseType:"array-buffer",signal:o});return(e=t.data).byteLength<f.requiredBufferSize?null:this._readIFD(e,r,0,s,R.tiffTags,4,o)}}async _fetchRawTiffTile(e,t,r,i,s={}){const a=this._getTileLocation(e,t,r,i);if(!a)return null;const{ranges:n,actualTileWidth:o,actualTileHeight:f,ifd:l}=a,u=n.map((e=>this.request(this.url,{range:e,responseType:"array-buffer",signal:s.signal}))),p=await Promise.all(u),c=p.map((e=>e.data.byteLength)).reduce(((e,t)=>e+t)),h=1===p.length?p[0].data:new ArrayBuffer(c),m=[0],d=[0];if(p.length>1){const e=new Uint8Array(h);for(let t=0,r=0;t<p.length;t++){const i=p[t].data;e.set(new Uint8Array(i),r),m[t]=r,r+=i.byteLength,d[t]=i.byteLength}}const{blockWidth:y,blockHeight:g}=this.getBlockWidthHeight(e),x=await this.decodePixelBlock(h,{format:"tiff",customOptions:{headerInfo:this._headerInfo,ifd:l,offsets:m,sizes:d},width:y,height:g,planes:null,pixelType:null});if(null==x)return null;let T,I,w;if(o!==y||f!==g){let e=x.mask;if(e)for(T=0;T<g;T++)if(w=T*y,T<f)for(I=o;I<y;I++)e[w+I]=0;else for(I=0;I<y;I++)e[w+I]=0;else for(e=new Uint8Array(y*g),x.mask=e,T=0;T<f;T++)for(w=T*y,I=0;I<o;I++)e[w+I]=1}return x}_getTileLocation(e,t,r,i=!1){const{firstPyramidLevel:s,blockBoundary:a}=this.rasterInfo.storageInfo,n=0===e?0:e-(s-1),{_headerInfo:o}=this;if(!o)return null;const f=i?o.maskIFDs[n]:0===n?o?.ifds[0]:o?.pyramidIFDs[n-1];if(!f)return null;const l=I(f,o),u=_(f,"TILEOFFSETS");if(void 0===u)return null;const p=_(f,"TILEBYTECOUNTS"),{minRow:c,minCol:h,maxRow:m,maxCol:d}=a[n];if(t>m||r>d||t<c||r<h)return null;const y=F(f,"IMAGEWIDTH"),g=F(f,"IMAGELENGTH"),x=F(f,"TILEWIDTH"),T=F(f,"TILELENGTH"),w=[];if(l){const{bandCount:e}=this.rasterInfo;for(let i=0;i<e;i++){const e=i*(m+1)*(d+1)+t*(d+1)+r;w[i]={from:u[e],to:u[e]+p[e]-1}}}else{const e=t*(d+1)+r;w.push({from:u[e],to:u[e]+p[e]-1})}for(let I=0;I<w.length;I++)if(null==w[I].from||!w[I].to||w[I].to<0)return null;return{ranges:w,ifd:f,actualTileWidth:r===d&&y%x||x,actualTileHeight:t===m&&g%T||T}}async _fetchAuxiliaryMetaData(e){try{const{data:t}=await this.request(this.url+".aux.xml",{responseType:"xml",signal:e?.signal});return h(t)}catch{return null}}async _fetchAuxiliaryTable(e){try{const{data:t}=await this.request(this.url+".vat.dbf",{responseType:"array-buffer",signal:e?.signal}),r=c.parse(t);return r?.recordSet?S.fromJSON(r.recordSet):null}catch{return null}}};function k(e){const t=w(e),{width:r,height:i,tileWidth:s,tileHeight:a,planes:p,pixelType:c,compression:h,firstPyramidLevel:d,maximumPyramidLevel:y,pyramidBlockWidth:g,pyramidBlockHeight:x,pyramidResolutions:T,tileBoundary:I,affine:R,metadata:b}=t,S=t.extent.spatialReference?.wkt||t.extent.spatialReference?.wkid;let v=m(S),k=!!t.isPseudoGeographic;null==v&&(k=!0,v=new f({wkid:3857}));const P=new n({...t.extent,spatialReference:v}),D=new o(P?{x:P.xmin,y:P.ymax,spatialReference:v}:{x:0,y:0}),O=new u({blockWidth:s,blockHeight:a,pyramidBlockWidth:g,pyramidBlockHeight:x,compression:h,origin:D,firstPyramidLevel:d,maximumPyramidLevel:y,pyramidResolutions:T,blockBoundary:I}),L=new o({x:(P.xmax-P.xmin)/r,y:(P.ymax-P.ymin)/i,spatialReference:v}),B=b?{BandProperties:b.bandProperties,DataType:b.dataType}:{};let j=null;const z=F(e[0],"PHOTOMETRICINTERPRETATION"),A=_(e[0],"COLORMAP");if(z<=3&&A?.length>3&&A.length%3==0){j=[];const e=A.length/3;for(let t=0;t<e;t++)j.push([t,A[t]>>>8,A[t+e]>>>8,A[t+2*e]>>>8])}const C=new l({width:r,height:i,bandCount:p,pixelType:c,pixelSize:L,storageInfo:O,spatialReference:v,isPseudoSpatialReference:k,keyProperties:B,extent:P,colormap:j,statistics:b?b.statistics:null});if(R?.length&&(C.nativeExtent=new n({xmin:-.5,ymin:.5-i,xmax:r-.5,ymax:.5,spatialReference:v}),C.transform=new E({polynomialOrder:1,forwardCoefficients:[R[2]+R[0]/2,R[5]-R[3]/2,R[0],R[3],-R[1],-R[4]]}),C.extent=C.transform.forwardTransform(C.nativeExtent),C.pixelSize=new o({x:(P.xmax-P.xmin)/r,y:(P.ymax-P.ymin)/i,spatialReference:v}),O.origin.x=-.5,O.origin.y=.5),T){const{x:e,y:t}=C.pixelSize;T.forEach((r=>{r.x*=e,r.y*=t}))}return{imageInfo:t,rasterInfo:C}}function P(e,t){if(t.statistics=e.statistics??t.statistics,t.histograms=e.histograms,e.histograms&&null==t.statistics&&(t.statistics=b(e.histograms)),e.transform&&null==t.transform){t.transform=e.transform,t.nativeExtent=t.extent;const r=t.transform.forwardTransform(t.nativeExtent);t.pixelSize=new o({x:(r.xmax-r.xmin)/t.width,y:(r.ymax-r.ymin)/t.height,spatialReference:t.spatialReference}),t.extent=r}t.isPseudoSpatialReference&&e.spatialReference&&(t.spatialReference=e.spatialReference,t.extent.spatialReference=t.nativeExtent.spatialReference=t.storageInfo.origin.spatialReference=t.spatialReference)}e([s()],v.prototype,"_files",void 0),e([s()],v.prototype,"_headerInfo",void 0),e([s()],v.prototype,"_bufferSize",void 0),e([s({type:String,json:{write:!0}})],v.prototype,"datasetFormat",void 0),v=e([a("esri.layers.support.rasterDatasets.TIFFRaster")],v);const D=v;export{D as default};