From fb4badfa217de967ca19e845a68e2ca156285ccb Mon Sep 17 00:00:00 2001 From: gregoire maillet Date: Tue, 28 Jan 2020 14:15:38 +0100 Subject: [PATCH 1/7] version initiale --- examples/js/plugins/COGSource.js | 209 ++++++++++++++++++++++++++++++ examples/js/plugins/TIFFParser.js | 2 +- examples/source_file_cog.html | 64 +++++++++ 3 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 examples/js/plugins/COGSource.js create mode 100644 examples/source_file_cog.html diff --git a/examples/js/plugins/COGSource.js b/examples/js/plugins/COGSource.js new file mode 100644 index 0000000000..f612c291ee --- /dev/null +++ b/examples/js/plugins/COGSource.js @@ -0,0 +1,209 @@ + +/** + * @classdesc + * An object defining the source of resources to get from a [COG]{@link + * https://www.cogeo.org/} file. It + * inherits from {@link Source}. + * + * @extends Source + * + * @property {boolean} isCOGSource - Used to checkout whether this source is a + * COGSource. Default is true. You should not change this, as it is used + * internally for optimisation. + * @property {boolean} isInverted - The isInverted property is to be set to the + * correct value, true or false (default being false) if the computation of the + * coordinates needs to be inverted to match the same scheme as OSM, Google Maps + * or other system. See [this link]{@link + * https://alastaira.wordpress.com/2011/07/06/converting-tms-tile-coordinates-to-googlebingosm-tile-coordinates/} + * for more information. + * @property {string} tileMatrixSet - Tile matrix set of the layer, used in the + * generation of the coordinates to build the url. Default value is 'WGS84'. + * @property {Object} zoom - Object containing the minimum and maximum values of + * the level, to zoom in the source. + * @property {number} zoom.min - The minimum level of the source. Default value + * is computed from the COG file. + * @property {number} zoom.max - The maximum level of the source. Default value + * is computed from the COG file. + * + * @example + * // Create the source + * const cogSource = new itowns.COGSource({ + * url: 'http://osm.io/styles/${z}/${x}/${y}.png', + * tileMatrixSet: 'PM', + * parser: TIFFParser.parse, + * fetcher: itowns.Fetcher.arrayBuffer, + * }); + * + * // Create the layer + * const colorLayer = new itowns.ColorLayer('COG', { + * source: cogSource, + * }); + * + * // Add the layer + * view.addLayer(colorLayer); + */ +class COGSource extends itowns.Source { + /** + * @param {Object} source - An object that can contain all properties of a + * COGSource and {@link Source}. Only `url` is mandatory. + * + * @constructor + */ + constructor(source) { + if (!source.projection) { + throw new Error('New COGSource: projection is required'); + } + super(source); + + this.isCOGSource = true; + + if (source.zoom) { + this.zoom = source.zoom; + } + + this.isInverted = source.isInverted || false; + this.format = this.format || 'image/png'; + this.url = source.url; + + if (source.projection) { + this.projection = itowns.CRS.formatToTms(source.projection); + } + + this.tileMatrixSetLimits = source.tileMatrixSetLimits; + + // Header + // default is 16ko block read + this.whenReady = fetch(this.url, { + headers: { + 'content-type': 'multipart/byteranges', + 'range': 'bytes=0-16000', + }, + }).then((response) => { + if (response.ok) { + return response.arrayBuffer(); + } + }).then((response) => { + this.ifds = UTIF.decode(response); + console.log(this.ifds); + // Georef + this.modelTiepointTag = this.ifds[0].t33922; + this.modelPixelScaleTag = this.ifds[0].t33550; + this.geoKeyDirectoryTag = this.ifds[0].t34735; + this.geoDoubleParamsTag = this.ifds[0].t34736; + this.geoAsciiParamsTag = this.ifds[0].t34737; + + if ((this.geoKeyDirectoryTag) && !(source.projection)) { + // Spec in http://geotiff.maptools.org/spec/geotiff2.4.html + var nbKeys = this.geoKeyDirectoryTag[3]; + for (let i = 0; i < nbKeys; ++i) { + if (this.geoKeyDirectoryTag[(i + 1) * 4] == 3072) { + const epsg_code = this.geoKeyDirectoryTag[(i + 1) * 4 + 3]; + this.projection = CRS.formatToTms(`EPSG:${epsg_code}`); + console.log(this.projection); + } + } + } + + this.tileSize = this.ifds[0].t322[0]; + this.width = this.ifds[0].t256[0]; + this.height = this.ifds[0].t257[0]; + this.zoomMax = Math.ceil(Math.log2(Math.max(this.width, this.height) / this.tileSize)); + console.log('zoomMax : ', this.zoomMax); + if (!this.zoom) { + + this.zoom = { + min: this.zoomMax - this.ifds.length + 1, + max: this.zoomMax, + }; + console.log(this.zoom); + } + var tileMaxtrixSetLimits = {}; + var level = this.zoom.max; + this.ifds.forEach((ifd) => { + // Format Image + // var bitsPerSample = ifd.t258; + // var sampleFormat = ifd.t339; + // console.log('Nombre de canaux : ', bitsPerSample.length); + const width = ifd.t256[0]; + const height = ifd.t257[0]; + // var tileOffsets = ifd.t324; + // var tileByteCounts = ifd.t325; + const tileWidth = ifd.t322[0]; + const tileHeight = ifd.t323[0]; + ifd.nbTileX = Math.ceil(width / tileWidth); + ifd.nbTileY = Math.ceil(height / tileHeight); + tileMaxtrixSetLimits[level] = { + "minTileRow": 0, + "maxTileRow": ifd.nbTileY, + "minTileCol": 0, + "maxTileCol": ifd.nbTileX, + } + if ((this.tileSize != tileHeight) || (this.tileSize != tileWidth)) { + console.warn('all tiles must have same dimensions'); + } + level -= 1; + }); + if (!this.tileMaxtrixSetLimits) { + this.tileMaxtrixSetLimits = tileMaxtrixSetLimits; + } + }); + // if (!this.zoom) { + // if (this.tileMatrixSetLimits) { + // const arrayLimits = Object.keys(this.tileMatrixSetLimits); + // const size = arrayLimits.length; + // const maxZoom = Number(arrayLimits[size - 1]); + // const minZoom = maxZoom - size + 1; + + // this.zoom = { + // min: minZoom, + // max: maxZoom, + // }; + // } else { + // this.zoom = { min: 0, max: 20 }; + // } + // } + } + + urlFromExtent(extent) { + // Copy Ifd and add if to extent (for the parser) + const ifdNum = this.zoomMax - extent.zoom; + extent.ifd = JSON.parse(JSON.stringify(this.ifds[ifdNum])); + // get the offset/byteCount for the tile + const numTile = extent.col + extent.row * extent.ifd.nbTileX; + const offset = extent.ifd.t324[numTile]; + const byteCounts = extent.ifd.t325[numTile]; + // custom the networkOptions as a range request for this specific tile + this.networkOptions.headers = { + 'content-type': 'multipart/byteranges', + 'range': `bytes=${offset}-${offset + byteCounts}`, + }; + // update the ifd copy for the TIFFParser + // width/heigth from the tile size + extent.ifd.t256[0] = extent.ifd.t322[0]; + extent.ifd.t257[0] = extent.ifd.t323[0]; + // offset and byteCounts + extent.ifd.t324 = [0]; + extent.ifd.t325 = [byteCounts]; + return this.url; + } + + handlingError(err) { + console.warn(`err ${this.url}`, err); + } + + extentInsideLimit(extent) { + // This layer provides data starting at level = layer.source.zoom.min + // (the zoom.max property is used when building the url to make + // sure we don't use invalid levels) + return extent.zoom >= this.zoom.min && extent.zoom <= this.zoom.max && + (this.tileMatrixSetLimits == undefined || + (extent.row >= this.tileMatrixSetLimits[extent.zoom].minTileRow && + extent.row <= this.tileMatrixSetLimits[extent.zoom].maxTileRow && + extent.col >= this.tileMatrixSetLimits[extent.zoom].minTileCol && + extent.col <= this.tileMatrixSetLimits[extent.zoom].maxTileCol)); + } +} + +if (typeof module != 'undefined' && module.exports) { + module.exports = COGSource; +} diff --git a/examples/js/plugins/TIFFParser.js b/examples/js/plugins/TIFFParser.js index eac9aa8771..38ca8d1bb4 100644 --- a/examples/js/plugins/TIFFParser.js +++ b/examples/js/plugins/TIFFParser.js @@ -36,7 +36,7 @@ var TIFFParser = (function _() { * @memberof module:TIFFParser */ parse: function _(data) { - var IFD = UTIF.decode(data)[0]; + var IFD = data.extent.ifd || UTIF.decode(data)[0]; UTIF.decodeImage(data, IFD); IFD.data = UTIF.toRGBA8(IFD); diff --git a/examples/source_file_cog.html b/examples/source_file_cog.html new file mode 100644 index 0000000000..8beeb4675a --- /dev/null +++ b/examples/source_file_cog.html @@ -0,0 +1,64 @@ + + + Cloud Optimized GeoTiff + + + + + + + + +
+ + + + + + + + + + From 5a305b518cec9cbdc519f9fb6d1d7c1892422bc7 Mon Sep 17 00:00:00 2001 From: gregoire maillet Date: Wed, 29 Jan 2020 17:48:23 +0100 Subject: [PATCH 2/7] using cog from itowns.ign.fr and compute extent from GeoTiff --- examples/js/plugins/COGSource.js | 44 ++++++------------------------- examples/source_file_cog.html | 45 ++++++++++---------------------- 2 files changed, 22 insertions(+), 67 deletions(-) diff --git a/examples/js/plugins/COGSource.js b/examples/js/plugins/COGSource.js index f612c291ee..f6fdee3d30 100644 --- a/examples/js/plugins/COGSource.js +++ b/examples/js/plugins/COGSource.js @@ -73,15 +73,10 @@ class COGSource extends itowns.Source { // Header // default is 16ko block read - this.whenReady = fetch(this.url, { + this.whenReady = itowns.Fetcher.arrayBuffer(this.url, { headers: { - 'content-type': 'multipart/byteranges', 'range': 'bytes=0-16000', }, - }).then((response) => { - if (response.ok) { - return response.arrayBuffer(); - } }).then((response) => { this.ifds = UTIF.decode(response); console.log(this.ifds); @@ -91,26 +86,19 @@ class COGSource extends itowns.Source { this.geoKeyDirectoryTag = this.ifds[0].t34735; this.geoDoubleParamsTag = this.ifds[0].t34736; this.geoAsciiParamsTag = this.ifds[0].t34737; + this.width = this.ifds[0].t256[0]; + this.height = this.ifds[0].t257[0]; - if ((this.geoKeyDirectoryTag) && !(source.projection)) { - // Spec in http://geotiff.maptools.org/spec/geotiff2.4.html - var nbKeys = this.geoKeyDirectoryTag[3]; - for (let i = 0; i < nbKeys; ++i) { - if (this.geoKeyDirectoryTag[(i + 1) * 4] == 3072) { - const epsg_code = this.geoKeyDirectoryTag[(i + 1) * 4 + 3]; - this.projection = CRS.formatToTms(`EPSG:${epsg_code}`); - console.log(this.projection); - } - } - } + // Compute extent from GeoTiff Tag + this.extent = new itowns.Extent( + source.projection, + this.modelTiepointTag[3], this.modelTiepointTag[3] + this.width * this.modelPixelScaleTag[0], + this.modelTiepointTag[4] - this.height * this.modelPixelScaleTag[1], this.modelTiepointTag[4]); this.tileSize = this.ifds[0].t322[0]; - this.width = this.ifds[0].t256[0]; - this.height = this.ifds[0].t257[0]; this.zoomMax = Math.ceil(Math.log2(Math.max(this.width, this.height) / this.tileSize)); console.log('zoomMax : ', this.zoomMax); if (!this.zoom) { - this.zoom = { min: this.zoomMax - this.ifds.length + 1, max: this.zoomMax, @@ -147,21 +135,6 @@ class COGSource extends itowns.Source { this.tileMaxtrixSetLimits = tileMaxtrixSetLimits; } }); - // if (!this.zoom) { - // if (this.tileMatrixSetLimits) { - // const arrayLimits = Object.keys(this.tileMatrixSetLimits); - // const size = arrayLimits.length; - // const maxZoom = Number(arrayLimits[size - 1]); - // const minZoom = maxZoom - size + 1; - - // this.zoom = { - // min: minZoom, - // max: maxZoom, - // }; - // } else { - // this.zoom = { min: 0, max: 20 }; - // } - // } } urlFromExtent(extent) { @@ -174,7 +147,6 @@ class COGSource extends itowns.Source { const byteCounts = extent.ifd.t325[numTile]; // custom the networkOptions as a range request for this specific tile this.networkOptions.headers = { - 'content-type': 'multipart/byteranges', 'range': `bytes=${offset}-${offset + byteCounts}`, }; // update the ifd copy for the TIFFParser diff --git a/examples/source_file_cog.html b/examples/source_file_cog.html index 8beeb4675a..4e253fd15d 100644 --- a/examples/source_file_cog.html +++ b/examples/source_file_cog.html @@ -21,44 +21,27 @@ itowns.proj4.defs('EPSG:2154', '+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'); - // // # Simple Planar viewer - - // // Define geographic extent: CRS, min/max X, min/max Y - // // Upper Left ( 884000.000, 6461000.000) ( 5d20'41.10"E, 45d13'25.46"N) - // // Lower Left ( 884000.000, 6459000.000) ( 5d20'38.38"E, 45d12'20.66"N) - // // Upper Right ( 886000.000, 6461000.000) ( 5d22'12.80"E, 45d13'23.53"N) - // // Lower Right ( 886000.000, 6459000.000) ( 5d22'10.05"E, 45d12'18.73"N) - // // Center ( 885000.000, 6460000.000) ( 5d21'25.58"E, 45d12'52.10"N) - - var extent = new itowns.Extent( - 'EPSG:2154', - 884000, 886000, - 6459000, 6461000); - - // // `viewerDiv` will contain iTowns' rendering area (``) var viewerDiv = document.getElementById('viewerDiv'); - - // // Instanciate iTowns PlanarView* - var view = new itowns.PlanarView(viewerDiv, extent, { disableSkirt: true, maxSubdivisionLevel: 10, placement: { tilt: 90 } }); - - setupLoadingScreen(viewerDiv, view); - new itowns.PlanarControls(view, {}); - - // // Add one imagery layer to the scene, read from TIFFs. + + // create a source from a Cloud Optimized GeoTiff var cogSource = new COGSource({ - url: '/cogeo.tif', + url: 'https://itowns.ign.fr/demos/public/cogeo.tif', tileMatrixSet: 'PM', projection: 'EPSG:2154', parser: TIFFParser.parse, fetcher: itowns.Fetcher.arrayBuffer, }); - - var cogLayer = new itowns.ColorLayer('cog', { - source: cogSource, - }); - - view.addLayer(cogLayer); - + cogSource.whenReady.then(() => { + console.log(cogSource.extent); + var view = new itowns.PlanarView(viewerDiv, cogSource.extent, { disableSkirt: true, maxSubdivisionLevel: 10, placement: { tilt: 90 } }); + setupLoadingScreen(viewerDiv, view); + new itowns.PlanarControls(view, {}); + var cogLayer = new itowns.ColorLayer('cog', { + source: cogSource, + }); + view.addLayer(cogLayer); + } + ); From 79a64bb7d2447e7e020048e39d3a6591f2cfe322 Mon Sep 17 00:00:00 2001 From: gregoire maillet Date: Wed, 29 Jan 2020 17:51:35 +0100 Subject: [PATCH 3/7] mbredif fix on range --- examples/js/plugins/COGSource.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/js/plugins/COGSource.js b/examples/js/plugins/COGSource.js index f6fdee3d30..169170e6c0 100644 --- a/examples/js/plugins/COGSource.js +++ b/examples/js/plugins/COGSource.js @@ -147,7 +147,7 @@ class COGSource extends itowns.Source { const byteCounts = extent.ifd.t325[numTile]; // custom the networkOptions as a range request for this specific tile this.networkOptions.headers = { - 'range': `bytes=${offset}-${offset + byteCounts}`, + 'range': `bytes=${offset}-${offset + byteCounts - 1}`, }; // update the ifd copy for the TIFFParser // width/heigth from the tile size From 774905015a6328db5556889f4d7e018781f380f2 Mon Sep 17 00:00:00 2001 From: gregoire maillet Date: Fri, 31 Jan 2020 17:41:45 +0100 Subject: [PATCH 4/7] WIP: BigTIFF --- examples/js/plugins/COGSource.js | 3 +- examples/js/plugins/UTIF.js | 1290 +++++++++++++++++++++++++++ examples/source_file_cog.html | 3 +- examples/source_file_cog_multi.html | 64 ++ 4 files changed, 1358 insertions(+), 2 deletions(-) create mode 100644 examples/js/plugins/UTIF.js create mode 100644 examples/source_file_cog_multi.html diff --git a/examples/js/plugins/COGSource.js b/examples/js/plugins/COGSource.js index 169170e6c0..f34ebccc6f 100644 --- a/examples/js/plugins/COGSource.js +++ b/examples/js/plugins/COGSource.js @@ -75,7 +75,7 @@ class COGSource extends itowns.Source { // default is 16ko block read this.whenReady = itowns.Fetcher.arrayBuffer(this.url, { headers: { - 'range': 'bytes=0-16000', + 'range': 'bytes=0-300000', }, }).then((response) => { this.ifds = UTIF.decode(response); @@ -138,6 +138,7 @@ class COGSource extends itowns.Source { } urlFromExtent(extent) { + console.log(extent); // Copy Ifd and add if to extent (for the parser) const ifdNum = this.zoomMax - extent.zoom; extent.ifd = JSON.parse(JSON.stringify(this.ifds[ifdNum])); diff --git a/examples/js/plugins/UTIF.js b/examples/js/plugins/UTIF.js new file mode 100644 index 0000000000..b45f0849fb --- /dev/null +++ b/examples/js/plugins/UTIF.js @@ -0,0 +1,1290 @@ + + + + +;(function(){ +var UTIF = {}; + +// Make available for import by `require()` +if (typeof module == "object") {module.exports = UTIF;} +else {self.UTIF = UTIF;} + +var pako = (typeof require === "function") ? require("pako") : self.pako; + +function log() { if (typeof process=="undefined" || process.env.NODE_ENV=="development") console.log.apply(console, arguments); } + +(function(UTIF, pako){ + +// Following lines add a JPEG decoder to UTIF.JpegDecoder +(function(){var V="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(g){return typeof g}:function(g){return g&&"function"===typeof Symbol&&g.constructor===Symbol&&g!==Symbol.prototype?"symbol":typeof g},D=function(){function g(g){this.message="JPEG error: "+g}g.prototype=Error();g.prototype.name="JpegError";return g.constructor=g}(),P=function(){function g(g,D){this.message=g;this.g=D}g.prototype=Error();g.prototype.name="DNLMarkerError";return g.constructor=g}();(function(){function g(){this.M= +null;this.B=-1}function W(a,d){for(var f=0,e=[],b,B,k=16;0>x&1;z=a[d++];if(255=== +z){var c=a[d++];if(c){if(220===c&&g){d+=2;var b=a[d++]<<8|a[d++];if(0>>7}function q(a){for(;;){a=a[n()];if("number"===typeof a)return a;if("object"!==("undefined"===typeof a?"undefined":V(a)))throw new D("invalid huffman sequence");}}function h(a){for(var c=0;0= +1<d;){var h=q(a.o),k=h&15;h>>=4;if(0===k){if(15>h)break;d+=16}else d+=h,a.a[b+J[d]]=c(k),d++}}function w(a,d){var b=q(a.D);b=0===b?0:c(b)<>=4;if(0===f){if(15>e){A=h(e)+(1<a.a[f]? +-1:1;switch(E){case 0:e=q(a.o);f=e&15;e>>=4;if(0===f)15>e?(A=h(e)+(1<=y)throw new D("marker was not found"); +if(65488<=y&&65495>=y)d+=2;else break}(y=N(a,d))&&y.f&&((0,_util.warn)("decodeScan - unexpected Scan data, current marker is: "+y.f),d=y.offset);return d-v}function Y(a,d){for(var f=d.c,e=d.l,b=new Int16Array(64),B=0;Bh;h+=8){var c=q[l+h];var C=q[l+h+1];var w=q[l+h+2];var p=q[l+h+3];var m=q[l+h+4];var t=q[l+h+5];var g=q[l+h+6];var u=q[l+h+7];c*=n[h];if(0===(C| +w|p|m|t|g|u))c=5793*c+512>>10,r[h]=c,r[h+1]=c,r[h+2]=c,r[h+3]=c,r[h+4]=c,r[h+5]=c,r[h+6]=c,r[h+7]=c;else{C*=n[h+1];w*=n[h+2];p*=n[h+3];m*=n[h+4];t*=n[h+5];g*=n[h+6];u*=n[h+7];var v=5793*c+128>>8;var z=5793*m+128>>8;var x=w;var A=g;m=2896*(C-u)+128>>8;u=2896*(C+u)+128>>8;p<<=4;t<<=4;v=v+z+1>>1;z=v-z;c=3784*x+1567*A+128>>8;x=1567*x-3784*A+128>>8;A=c;m=m+t+1>>1;t=m-t;u=u+p+1>>1;p=u-p;v=v+A+1>>1;A=v-A;z=z+x+1>>1;x=z-x;c=2276*m+3406*u+2048>>12;m=3406*m-2276*u+2048>>12;u=c;c=799*p+4017*t+2048>>12;p=4017* +p-799*t+2048>>12;t=c;r[h]=v+u;r[h+7]=v-u;r[h+1]=z+t;r[h+6]=z-t;r[h+2]=x+p;r[h+5]=x-p;r[h+3]=A+m;r[h+4]=A-m}}for(n=0;8>n;++n)c=r[n],C=r[n+8],w=r[n+16],p=r[n+24],m=r[n+32],t=r[n+40],g=r[n+48],u=r[n+56],0===(C|w|p|m|t|g|u)?(c=5793*c+8192>>14,c=-2040>c?0:2024<=c?255:c+2056>>4,q[l+n]=c,q[l+n+8]=c,q[l+n+16]=c,q[l+n+24]=c,q[l+n+32]=c,q[l+n+40]=c,q[l+n+48]=c,q[l+n+56]=c):(v=5793*c+2048>>12,z=5793*m+2048>>12,x=w,A=g,m=2896*(C-u)+2048>>12,u=2896*(C+u)+2048>>12,v=(v+z+1>>1)+4112,z=v-z,c=3784*x+1567*A+2048>> +12,x=1567*x-3784*A+2048>>12,A=c,m=m+t+1>>1,t=m-t,u=u+p+1>>1,p=u-p,v=v+A+1>>1,A=v-A,z=z+x+1>>1,x=z-x,c=2276*m+3406*u+2048>>12,m=3406*m-2276*u+2048>>12,u=c,c=799*p+4017*t+2048>>12,p=4017*p-799*t+2048>>12,t=c,c=v+u,u=v-u,C=z+t,g=z-t,w=x+p,t=x-p,p=A+m,m=A-m,c=16>c?0:4080<=c?255:c>>4,C=16>C?0:4080<=C?255:C>>4,w=16>w?0:4080<=w?255:w>>4,p=16>p?0:4080<=p?255:p>>4,m=16>m?0:4080<=m?255:m>>4,t=16>t?0:4080<=t?255:t>>4,g=16>g?0:4080<=g?255:g>>4,u=16>u?0:4080<=u?255:u>>4,q[l+n]=c,q[l+n+8]=C,q[l+n+16]=w,q[l+n+24]= +p,q[l+n+32]=m,q[l+n+40]=t,q[l+n+48]=g,q[l+n+56]=u)}return d.a}function N(a,d){var f=2=e)return null;var b=a[d]<<8|a[d+1];if(65472<=b&&65534>=b)return{f:null,F:b,offset:d};for(var B=a[f]<<8|a[f+1];!(65472<=B&&65534>=B);){if(++f>=e)return null;B=a[f]<<8|a[f+1]}return{f:b.toString(16),F:B,offset:f}}var J=new Uint8Array([0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56, +57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63]);g.prototype={parse:function(a){function d(){var d=a[k]<<8|a[k+1];k+=2;return d}function f(){var b=d();b=k+b-2;var c=N(a,b,k);c&&c.f&&((0,_util.warn)("readDataBlock - incorrect length, current marker is: "+c.f),b=c.offset);b=a.subarray(k,b);k+=b.length;return b}function e(a){for(var b=Math.ceil(a.v/8/a.s),c=Math.ceil(a.g/8/a.u),d=0;d>4)for(c=0;64>c;c++)g=J[c],p[g]=a[k++];else if(1===w>>4)for(c=0;64>c;c++)g=J[c],p[g]=d();else throw new D("DQT - invalid table spec");b[w&15]=p}break;case 65472:case 65473:case 65474:if(m)throw new D("Only single frame JPEGs supported");d();var m={};m.X=65473===h;m.S=65474===h;m.precision=a[k++];h=d();m.g= +B||h;m.v=d();m.b=[];m.C={};c=a[k++];for(h=p=w=0;h>4;var H=a[k+1]&15;wc;c++,k++)t+=p[c]=a[k];H=new Uint8Array(t);for(c=0;c>4?q:n)[w&15]=W(p,H)}break;case 65501:d();var u=d();break;case 65498:c=1===++r&&!B;d();w=a[k++];g=[];for(h=0;h>4];v.o=n[p&15];g.push(v)}h=a[k++];w=a[k++];p=a[k++];try{var z=X(a,k,m,g,u,h,w,p>>4,p&15,c);k+=z}catch(x){if(x instanceof P)return(0,_util.warn)('Attempting to re-parse JPEG image using "scanLines" parameter found in DNL marker (0xFFDC) segment.'),this.parse(a,{N:x.g});throw x;}break;case 65500:k+=4;break;case 65535:255!==a[k]&&k--;break;default:if(255===a[k-3]&&192<=a[k-2]&&254>=a[k-2])k-=3;else if((c=N(a,k-2))&&c.f)(0,_util.warn)("JpegImage.parse - unexpected data, current marker is: "+ +c.f),k=c.offset;else throw new D("unknown marker "+h.toString(16));}h=d()}this.width=m.v;this.height=m.g;this.A=l;this.b=[];for(h=0;h>8)+e[f+1];return r},w:function(){return this.A?!!this.A.W:3===this.i?0===this.B?!1:!0:1===this.B?!0:!1},I:function(a){for(var d,f,e,b=0,g=a.length;b probably not an image + img.isLE = id=="II"; + img.width = img["t256"][0]; //delete img["t256"]; + img.height = img["t257"][0]; //delete img["t257"]; + + var cmpr = img["t259"] ? img["t259"][0] : 1; //delete img["t259"]; + var fo = img["t266"] ? img["t266"][0] : 1; //delete img["t266"]; + if(img["t284"] && img["t284"][0]==2) log("PlanarConfiguration 2 should not be used!"); + + var bipp; // bits per pixel + if(img["t258"]) bipp = Math.min(32,img["t258"][0])*img["t258"].length; + else bipp = (img["t277"]?img["t277"][0]:1); + // Some .NEF files have t258==14, even though they use 16 bits per pixel + if(cmpr==1 && img["t279"]!=null && img["t278"] && img["t262"][0]==32803) { + bipp = Math.round((img["t279"][0]*8)/(img.width*img["t278"][0])); + } + var bipl = Math.ceil(img.width*bipp/8)*8; + var soff = img["t273"]; if(soff==null) soff = img["t324"]; + var bcnt = img["t279"]; if(cmpr==1 && soff.length==1) bcnt = [img.height*(bipl>>>3)]; if(bcnt==null) bcnt = img["t325"]; + var bytes = new Uint8Array(img.height*(bipl>>>3)), bilen = 0; + + if(img["t322"]!=null) // tiled + { + var tw = img["t322"][0], th = img["t323"][0]; + var tx = Math.floor((img.width + tw - 1) / tw); + var ty = Math.floor((img.height + th - 1) / th); + var tbuff = new Uint8Array(Math.ceil(tw*th*bipp/8)|0); + for(var y=0; y>>3, h = (img["t278"] ? img["t278"][0] : img.height), bpl = Math.ceil(bps*noc*img.width/8); + + // convert to Little Endian /* + if(bps==16 && !img.isLE && img["t33422"]==null) // not DNG + for(var y=0; y>>8)&255; + } + else if(noc==3) for(var j= 3; j>> (tab[i] >>> 8); + for(var c=0; c>>4); tgt[toff+i+1]=(b0<<4)|(b2>>>4); tgt[toff+i+2]=(b2<<4)|(b1>>>4); } + return; + } + + var pix = new Uint16Array(16); + var row, col, val, max, min, imax, imin, sh, bit, i, dp; + + var data = new Uint8Array(raw_width+1); + for (row=0; row < height; row++) { + //fread (data, 1, raw_width, ifp); + for(var j=0; j>> 11); + imax = 0x0f & (val >>> 22); + imin = 0x0f & (val >>> 26); + for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); + for (bit=30, i=0; i < 16; i++) + if (i == imax) pix[i] = max; + else if (i == imin) pix[i] = min; + else { + pix[i] = ((bin.readUshort(data, dp+(bit >> 3)) >>> (bit & 7) & 0x7f) << sh) + min; + if (pix[i] > 0x7ff) pix[i] = 0x7ff; + bit += 7; + } + for (i=0; i < 16; i++, col+=2) { + //RAW(row,col) = curve[pix[i] << 1] >> 2; + var clr = pix[i]<<1; //clr = 0xffff; + UTIF.decode._putsF(tgt, (row*raw_width+col)*tiff_bps, clr<<(16-tiff_bps)); + } + col -= col & 1 ? 1:31; + } + } +} + +UTIF.decode._decodeNikon = function(img,imgs, data, off, src_length, tgt, toff) +{ + var nikon_tree = [ + [ 0, 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ + 5,4,3,6,2,7,1,0,8,9,11,10,12 ], + [ 0, 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */ + 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 ], + [ 0, 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */ + 5,4,6,3,7,2,8,1,9,0,10,11,12 ], + [ 0, 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */ + 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 ], + [ 0, 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */ + 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 ], + [ 0, 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ + 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 ] ]; + + var raw_width = img["t256"][0], height=img["t257"][0], tiff_bps=img["t258"][0]; + + var tree = 0, split = 0; + var make_decoder = UTIF.decode._make_decoder; + var getbithuff = UTIF.decode._getbithuff; + + var mn = imgs[0].exifIFD.makerNote, md = mn["t150"]?mn["t150"]:mn["t140"], mdo=0; //console.log(mn,md); + //console.log(md[0].toString(16), md[1].toString(16), tiff_bps); + var ver0 = md[mdo++], ver1 = md[mdo++]; + if (ver0 == 0x49 || ver1 == 0x58) mdo+=2110; + if (ver0 == 0x46) tree = 2; + if (tiff_bps == 14) tree += 3; + + var vpred = [[0,0],[0,0]], bin=(img.isLE ? UTIF._binLE : UTIF._binBE); + for(var i=0; i<2; i++) for(var j=0; j<2; j++) { vpred[i][j] = bin.readShort(md,mdo); mdo+=2; } // not sure here ... [i][j] or [j][i] + //console.log(vpred); + + + var max = 1 << tiff_bps & 0x7fff, step=0; + var csize = bin.readShort(md,mdo); mdo+=2; + if (csize > 1) step = Math.floor(max / (csize-1)); + if (ver0 == 0x44 && ver1 == 0x20 && step > 0) split = bin.readShort(md,562); + + + var i; + var row, col; + var len, shl, diff; + var min_v = 0; + var hpred = [0,0]; + var huff = make_decoder(nikon_tree[tree]); + + //var g_input_offset=0, bitbuf=0, vbits=0, reset=0; + var prm = [off,0,0,0]; + //console.log(split); split = 170; + + for (min_v=row=0; row < height; row++) { + if (split && row == split) { + //free (huff); + huff = make_decoder (nikon_tree[tree+1]); + //max_v += (min_v = 16) << 1; + } + for (col=0; col < raw_width; col++) { + i = getbithuff(data,prm,huff[0],huff); + len = i & 15; + shl = i >>> 4; + diff = (((getbithuff(data,prm,len-shl,0) << 1) + 1) << shl) >>> 1; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - (shl==0?1:0); + if (col < 2) hpred[col] = vpred[row & 1][col] += diff; + else hpred[col & 1] += diff; + + var clr = Math.min(Math.max(hpred[col & 1],0),(1<>>3); dt[o]|=val>>>16; dt[o+1]|=val>>>8; dt[o+2]|=val; } + + +UTIF.decode._getbithuff = function(data,prm,nbits, huff) { + var zero_after_ff = 0; + var get_byte = UTIF.decode._get_byte; + var c; + + var off=prm[0], bitbuf=prm[1], vbits=prm[2], reset=prm[3]; + + //if (nbits > 25) return 0; + //if (nbits < 0) return bitbuf = vbits = reset = 0; + if (nbits == 0 || vbits < 0) return 0; + while (!reset && vbits < nbits && (c = data[off++]) != -1 && + !(reset = zero_after_ff && c == 0xff && data[off++])) { + //console.log("byte read into c"); + bitbuf = (bitbuf << 8) + c; + vbits += 8; + } + c = (bitbuf << (32-vbits)) >>> (32-nbits); + if (huff) { + vbits -= huff[c+1] >>> 8; //console.log(c, huff[c]>>8); + c = huff[c+1]&255; + } else + vbits -= nbits; + if (vbits < 0) throw "e"; + + prm[0]=off; prm[1]=bitbuf; prm[2]=vbits; prm[3]=reset; + + return c; +} + +UTIF.decode._make_decoder = function(source) { + var max, len, h, i, j; + var huff = []; + + for (max=16; max!=0 && !source[max]; max--); + var si=17; + + huff[0] = max; + for (h=len=1; len <= max; len++) + for (i=0; i < source[len]; i++, ++si) + for (j=0; j < 1 << (max-len); j++) + if (h <= 1 << max) + huff[h++] = (len << 8) | source[si]; + return huff; +} + +UTIF.decode._decodeNewJPEG = function(img, data, off, len, tgt, toff) +{ + var tables = img["t347"], tlen = tables ? tables.length : 0, buff = new Uint8Array(tlen + len); + + if (tables) { + var SOI = 216, EOI = 217, boff = 0; + for (var i=0; i<(tlen-1); i++) + { + // Skip EOI marker from JPEGTables + if (tables[i]==255 && tables[i+1]==EOI) break; + buff[boff++] = tables[i]; + } + + // Skip SOI marker from data + var byte1 = data[off], byte2 = data[off + 1]; + if (byte1!=255 || byte2!=SOI) + { + buff[boff++] = byte1; + buff[boff++] = byte2; + } + for (var i=2; i>>8); } + else for(var i=0; i>>8); tgt[toff+(i<<1)+1] = (out[i]&255); } + } + else if(bps==14 || bps==12) { // 4 * 14 == 56 == 7 * 8 + var rst = 16-bps; + for(var i=0; i 1); + } + + if(!isTiled) + { + if(data[off]==255 && data[off+1]==SOI) return { jpegOffset: off }; + if(jpgIchgFmt!=null) + { + if(data[off+jifoff]==255 && data[off+jifoff+1]==SOI) joff = off+jifoff; + else log("JPEGInterchangeFormat does not point to SOI"); + + if(jpgIchgFmtLen==null) log("JPEGInterchangeFormatLength field is missing"); + else if(jifoff >= soff || (jifoff+jiflen) <= soff) log("JPEGInterchangeFormatLength field value is invalid"); + + if(joff != null) return { jpegOffset: joff }; + } + } + + if(ycbcrss!=null) { ssx = ycbcrss[0]; ssy = ycbcrss[1]; } + + if(jpgIchgFmt!=null) + if(jpgIchgFmtLen!=null) + if(jiflen >= 2 && (jifoff+jiflen) <= soff) + { + if(data[off+jifoff+jiflen-2]==255 && data[off+jifoff+jiflen-1]==SOI) tables = new Uint8Array(jiflen-2); + else tables = new Uint8Array(jiflen); + + for(i=0; i offset to first strip or tile"); + + if(tables == null) + { + var ooff = 0, out = []; + out[ooff++] = 255; out[ooff++] = SOI; + + var qtables = img["t519"]; + if(qtables==null) throw new Error("JPEGQTables tag is missing"); + for(i=0; i>> 8); out[ooff++] = nc & 255; + out[ooff++] = (i | (k << 4)); + for(j=0; j<16; j++) out[ooff++] = data[off+htables[i]+j]; + for(j=0; j>> 8) & 255; out[ooff++] = img.height & 255; + out[ooff++] = (img.width >>> 8) & 255; out[ooff++] = img.width & 255; + out[ooff++] = spp; + if(spp==1) { out[ooff++] = 1; out[ooff++] = 17; out[ooff++] = 0; } + else for(i=0; i<3; i++) + { + out[ooff++] = i + 1; + out[ooff++] = (i != 0) ? 17 : (((ssx & 15) << 4) | (ssy & 15)); + out[ooff++] = i; + } + + if(jpgresint!=null && jpgresint[0]!=0) + { + out[ooff++] = 255; out[ooff++] = DRI; out[ooff++] = 0; out[ooff++] = 4; + out[ooff++] = (jpgresint[0] >>> 8) & 255; + out[ooff++] = jpgresint[0] & 255; + } + + tables = new Uint8Array(out); + } + + var sofpos = -1; + i = 0; + while(i < (tables.length - 1)) { + if(tables[i]==255 && tables[i+1]==SOF0) { sofpos = i; break; } + i++; + } + + if(sofpos == -1) + { + var tmptab = new Uint8Array(tables.length + 10 + 3*spp); + tmptab.set(tables); + var tmpoff = tables.length; + sofpos = tables.length; + tables = tmptab; + + tables[tmpoff++] = 255; tables[tmpoff++] = SOF0; + tables[tmpoff++] = 0; tables[tmpoff++] = 8 + 3*spp; tables[tmpoff++] = 8; + tables[tmpoff++] = (img.height >>> 8) & 255; tables[tmpoff++] = img.height & 255; + tables[tmpoff++] = (img.width >>> 8) & 255; tables[tmpoff++] = img.width & 255; + tables[tmpoff++] = spp; + if(spp==1) { tables[tmpoff++] = 1; tables[tmpoff++] = 17; tables[tmpoff++] = 0; } + else for(i=0; i<3; i++) + { + tables[tmpoff++] = i + 1; + tables[tmpoff++] = (i != 0) ? 17 : (((ssx & 15) << 4) | (ssy & 15)); + tables[tmpoff++] = i; + } + } + + if(data[soff]==255 && data[soff+1]==SOS) + { + var soslen = (data[soff+2]<<8) | data[soff+3]; + sosMarker = new Uint8Array(soslen+2); + sosMarker[0] = data[soff]; sosMarker[1] = data[soff+1]; sosMarker[2] = data[soff+2]; sosMarker[3] = data[soff+3]; + for(i=0; i<(soslen-2); i++) sosMarker[i+4] = data[soff+i+4]; + } + else + { + sosMarker = new Uint8Array(2 + 6 + 2*spp); + var sosoff = 0; + sosMarker[sosoff++] = 255; sosMarker[sosoff++] = SOS; + sosMarker[sosoff++] = 0; sosMarker[sosoff++] = 6 + 2*spp; sosMarker[sosoff++] = spp; + if(spp==1) { sosMarker[sosoff++] = 1; sosMarker[sosoff++] = 0; } + else for(i=0; i<3; i++) + { + sosMarker[sosoff++] = i+1; sosMarker[sosoff++] = (i << 4) | i; + } + sosMarker[sosoff++] = 0; sosMarker[sosoff++] = 63; sosMarker[sosoff++] = 0; + } + + return { jpegOffset: off, tables: tables, sosMarker: sosMarker, sofPosition: sofpos }; +} + +UTIF.decode._decodeOldJPEG = function(img, data, off, len, tgt, toff) +{ + var i, dlen, tlen, buff, buffoff; + var jpegData = UTIF.decode._decodeOldJPEGInit(img, data, off, len); + + if(jpegData.jpegOffset!=null) + { + dlen = off+len-jpegData.jpegOffset; + buff = new Uint8Array(dlen); + for(i=0; i>> 8) & 255; buff[jpegData.sofPosition+6] = img.height & 255; + buff[jpegData.sofPosition+7] = (img.width >>> 8) & 255; buff[jpegData.sofPosition+8] = img.width & 255; + + if(data[off]!=255 || data[off+1]!=SOS) + { + buff.set(jpegData.sosMarker, buffoff); + buffoff += sosMarker.length; + } + for(i=0; i=0 && n<128) for(var i=0; i< n+1; i++) { ta[toff]=sa[off]; toff++; off++; } + if(n>=-127 && n<0) { for(var i=0; i<-n+1; i++) { ta[toff]=sa[off]; toff++; } off++; } + } +} + +UTIF.decode._decodeThunder = function(data, off, len, tgt, toff) +{ + var d2 = [ 0, 1, 0, -1 ], d3 = [ 0, 1, 2, 3, 0, -3, -2, -1 ]; + var lim = off+len, qoff = toff*2, px = 0; + while(off>>6), n = (b&63); off++; + if(msk==3) { px=(n&15); tgt[qoff>>>1] |= (px<<(4*(1-qoff&1))); qoff++; } + if(msk==0) for(var i=0; i>>1] |= (px<<(4*(1-qoff&1))); qoff++; } + if(msk==2) for(var i=0; i<2; i++) { var d=(n>>>(3*(1-i)))&7; if(d!=4) { px+=d3[d]; tgt[qoff>>>1] |= (px<<(4*(1-qoff&1))); qoff++; } } + if(msk==1) for(var i=0; i<3; i++) { var d=(n>>>(2*(2-i)))&3; if(d!=2) { px+=d2[d]; tgt[qoff>>>1] |= (px<<(4*(1-qoff&1))); qoff++; } } + } +} + +UTIF.decode._dmap = { "1":0,"011":1,"000011":2,"0000011":3, "010":-1,"000010":-2,"0000010":-3 }; +UTIF.decode._lens = ( function() +{ + var addKeys = function(lens, arr, i0, inc) { for(var i=0; i>>3)>>3]>>>(7-(boff&7)))&1; + if(fo==2) bit = (data[boff>>>3]>>>( (boff&7)))&1; + boff++; wrd+=bit; + if(mode=="H") + { + if(U._lens[clr][wrd]!=null) + { + var dl=U._lens[clr][wrd]; wrd=""; len+=dl; + if(dl<64) { U._addNtimes(line,len,clr); a0+=len; clr=1-clr; len=0; toRead--; if(toRead==0) mode=""; } + } + } + else + { + if(wrd=="0001") { wrd=""; U._addNtimes(line,b2-a0,clr); a0=b2; } + if(wrd=="001" ) { wrd=""; mode="H"; toRead=2; } + if(U._dmap[wrd]!=null) { a1 = b1+U._dmap[wrd]; U._addNtimes(line, a1-a0, clr); a0=a1; wrd=""; clr=1-clr; } + } + if(line.length==w && mode=="") + { + U._writeBits(line, tgt, toff*8+y*bipl); + clr=0; y++; a0=0; + pline=U._makeDiff(line); line=[]; + } + //if(wrd.length>150) { log(wrd); break; throw "e"; } + } +} + +UTIF.decode._findDiff = function(line, x, clr) { for(var i=0; i=x && line[i+1]==clr) return line[i]; } + +UTIF.decode._makeDiff = function(line) +{ + var out = []; if(line[0]==1) out.push(0,1); + for(var i=1; i>>3)>>3]>>>(7-(boff&7)))&1; + if(fo==2) bit = (data[boff>>>3]>>>( (boff&7)))&1; + boff++; wrd+=bit; + + if(is1D) + { + if(U._lens[clr][wrd]!=null) + { + var dl=U._lens[clr][wrd]; wrd=""; len+=dl; + if(dl<64) { U._addNtimes(line,len,clr); clr=1-clr; len=0; } + } + } + else + { + if(mode=="H") + { + if(U._lens[clr][wrd]!=null) + { + var dl=U._lens[clr][wrd]; wrd=""; len+=dl; + if(dl<64) { U._addNtimes(line,len,clr); a0+=len; clr=1-clr; len=0; toRead--; if(toRead==0) mode=""; } + } + } + else + { + if(wrd=="0001") { wrd=""; U._addNtimes(line,b2-a0,clr); a0=b2; } + if(wrd=="001" ) { wrd=""; mode="H"; toRead=2; } + if(U._dmap[wrd]!=null) { a1 = b1+U._dmap[wrd]; U._addNtimes(line, a1-a0, clr); a0=a1; wrd=""; clr=1-clr; } + } + } + if(wrd.endsWith("000000000001")) // needed for some files + { + if(y>=0) U._writeBits(line, tgt, toff*8+y*bipl); + if(twoDim) { + if(fo==1) is1D = ((data[boff>>>3]>>>(7-(boff&7)))&1)==1; + if(fo==2) is1D = ((data[boff>>>3]>>>( (boff&7)))&1)==1; + boff++; + } + //log("EOL",y, "next 1D:", is1D); + wrd=""; clr=0; y++; a0=0; + pline=U._makeDiff(line); line=[]; + } + } + if(line.length==w) U._writeBits(line, tgt, toff*8+y*bipl); +} + +UTIF.decode._addNtimes = function(arr, n, val) { for(var i=0; i>>3] |= (bits[i]<<(7-((boff+i)&7))); +} + +UTIF.decode._decodeLZW = function(){var x={},y=function(L,F,i,W,_){for(var a=0;a<_;a+=4){i[W+a]=L[F+a]; +i[W+a+1]=L[F+a+1];i[W+a+2]=L[F+a+2];i[W+a+3]=L[F+a+3]}},c=function(L,F,i,W){if(!x.c){var _=new Uint32Array(65535),a=new Uint16Array(65535),Z=new Uint8Array(2e6); +for(var f=0;f<256;f++){Z[f<<2]=f;_[f]=f<<2;a[f]=1}x.c=[_,a,Z]}var o=x.c[0],z=x.c[1],Z=x.c[2],h=258,n=258<<2,k=9,C=F<<3,m=256,B=257,p=0,O=0,K=0; +while(!0){p=L[C>>>3]<<16|L[C+8>>>3]<<8|L[C+16>>>3];O=p>>24-(C&7)-k&(1<>>3]<<16|L[C+8>>>3]<<8|L[C+16>>>3];O=p>>24-(C&7)-k&(1<=h){o[h]=n;Z[o[h]]=J[0];z[h]=1;n=n+1+3&~3; +h++}else{o[h]=n;var t=o[K],l=z[K];y(Z,t,Z,n,l);Z[n+l]=Z[J];l++;z[h]=l;h++;n=n+l+3&~3}if(h+1==1<=h){o[h]=n; +z[h]=0;h++}else{o[h]=n;var t=o[K],l=z[K];y(Z,t,Z,n,l);Z[n+l]=Z[n];l++;z[h]=l;h++;y(Z,n,i,W,l);W+=l;n=n+l+3&~3}if(h+1==1<>>----------------"); + for(var i=0n; i>>----------------"); + for(var i=0; i4) { bin.writeUint(data, offset, eoff); toff=eoff; } + + if (type== 1 || type==7) { for(var i=0; i4) { dlen += (dlen&1); eoff += dlen; } + offset += 4; + } + return [offset, eoff]; +} + +UTIF.toRGBA8 = function(out) +{ + var w = out.width, h = out.height, area = w*h, qarea = area*4, data = out.data; + var img = new Uint8Array(area*4); + //console.log(out); + // 0: WhiteIsZero, 1: BlackIsZero, 2: RGB, 3: Palette color, 4: Transparency mask, 5: CMYK + var intp = (out["t262"] ? out["t262"][0]: 2), bps = (out["t258"]?Math.min(32,out["t258"][0]):1); + //log("interpretation: ", intp, "bps", bps, out); + if(false) {} + else if(intp==0) + { + var bpl = Math.ceil(bps*w/8); + for(var y=0; y>3)])>>(7- (i&7)))& 1; img[qi]=img[qi+1]=img[qi+2]=( 1-px)*255; img[qi+3]=255; } + if(bps== 4) for(var i=0; i>1)])>>(4-4*(i&1)))&15; img[qi]=img[qi+1]=img[qi+2]=(15-px)* 17; img[qi+3]=255; } + if(bps== 8) for(var i=0; i>3)])>>(7- (i&7)))&1; img[qi]=img[qi+1]=img[qi+2]=(px)*255; img[qi+3]=255; } + if(bps== 2) for(var i=0; i>2)])>>(6-2*(i&3)))&3; img[qi]=img[qi+1]=img[qi+2]=(px)* 85; img[qi+3]=255; } + if(bps== 8) for(var i=0; i>8); img[qi+1]=(map[256+mi]>>8); img[qi+2]=(map[512+mi]>>8); img[qi+3]=255; } + } + else if(intp==5) + { + var smpls = out["t258"]?out["t258"].length : 4; + var gotAlpha = smpls>4 ? 1 : 0; + for(var i=0; i>>1); + var Y = data[si+(j&1)], Cb=data[si+2]-128, Cr=data[si+3]-128; + + var r = Y + ( (Cr >> 2) + (Cr >> 3) + (Cr >> 5) ) ; + var g = Y - ( (Cb >> 2) + (Cb >> 4) + (Cb >> 5)) - ( (Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5)) ; + var b = Y + ( Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6)) ; + + img[qi ]=Math.max(0,Math.min(255,r)); + img[qi+1]=Math.max(0,Math.min(255,g)); + img[qi+2]=Math.max(0,Math.min(255,b)); + img[qi+3]=255; + } + } + } + else log("Unknown Photometric interpretation: "+intp); + return img; +} + +UTIF.replaceIMG = function(imgs) +{ + if(imgs==null) imgs = document.getElementsByTagName("img"); + var sufs = ["tif","tiff","dng","cr2","nef"] + for (var i=0; ima) { ma=ar; page=img; } + } + UTIF.decodeImage(buff, page, ifds); + var rgba = UTIF.toRGBA8(page), w=page.width, h=page.height; + var ind = UTIF._xhrs.indexOf(e.target), img = UTIF._imgs[ind]; + UTIF._xhrs.splice(ind,1); UTIF._imgs.splice(ind,1); + var cnv = document.createElement("canvas"); cnv.width=w; cnv.height=h; + var ctx = cnv.getContext("2d"), imgd = ctx.createImageData(w,h); + for(var i=0; i> 8)&255; buff[p+1] = n&255; }, + writeInt : function(buff, p, n) { var a=UTIF._binBE.ui8; UTIF._binBE.i32[0]=n; buff[p+3n]=a[0]; buff[p+2n]=a[1]; buff[p+1n]=a[2]; buff[p+0n]=a[3]; }, + writeUint : function(buff, p, n) { buff[p] = (n>>24)&255; buff[p+1n] = (n>>16)&255; buff[p+2n] = (n>>8)&255; buff[p+3n] = (n>>0)&255; }, + writeASCII : function(buff, p, s) { for(var i = 0n; i < s.length; i++) buff[p+i] = s.charCodeAt(i); }, + writeDouble: function(buff, p, n) + { + UTIF._binBE.fl64[0] = n; + for (var i = 0n; i < 8n; i++) buff[p + i] = UTIF._binBE.ui8[7n - i]; + } +} +UTIF._binBE.ui8 = new Uint8Array (8); +UTIF._binBE.i16 = new Int16Array (UTIF._binBE.ui8.buffer); +UTIF._binBE.i32 = new Int32Array (UTIF._binBE.ui8.buffer); +UTIF._binBE.ui32 = new Uint32Array (UTIF._binBE.ui8.buffer); +UTIF._binBE.ui64 = new BigUint64Array (UTIF._binBE.ui8.buffer); +UTIF._binBE.fl32 = new Float32Array(UTIF._binBE.ui8.buffer); +UTIF._binBE.fl64 = new Float64Array(UTIF._binBE.ui8.buffer); + +UTIF._binLE = +{ + nextZero : UTIF._binBE.nextZero, + readUshort : function(buff, p) { return (buff[p+1n]<< 8) | buff[p]; }, + readShort : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+0n]; a[1]=buff[p+1n]; return UTIF._binBE. i16[0]; }, + readInt : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+0n]; a[1]=buff[p+1n]; a[2]=buff[p+2n]; a[3]=buff[p+3n]; return UTIF._binBE. i32[0]; }, + readUint : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+0n]; a[1]=buff[p+1n]; a[2]=buff[p+2n]; a[3]=buff[p+3n]; return UTIF._binBE.ui32[0]; }, + readUlong : function(buff, p) { + var a=UTIF._binBE.ui8; + a[0]=buff[p+0n]; + a[1]=buff[p+1n]; + a[2]=buff[p+2n]; + a[3]=buff[p+3n]; + a[4]=buff[p+4n]; + a[5]=buff[p+5n]; + a[6]=buff[p+6n]; + a[7]=buff[p+7n]; + // console.log(a); + return UTIF._binBE.ui64[0]; }, + readUchar : UTIF._binBE.readUchar, + readASCII : UTIF._binBE.readASCII, + readFloat : function(buff, p) { var a=UTIF._binBE.ui8; for(var i=0n;i<4n;i++) a[i]=buff[p+ i]; return UTIF._binBE.fl32[0]; }, + readDouble : function(buff, p) { var a=UTIF._binBE.ui8; for(var i=0n;i<8n;i++) a[i]=buff[p+ i]; return UTIF._binBE.fl64[0]; }, + + writeUshort: function(buff, p, n) { buff[p] = (n)&255; buff[p+1n] = (n>>8)&255; }, + writeInt : function(buff, p, n) { var a=UTIF._binBE.ui8; UTIF._binBE.i32[0]=n; buff[p+0n]=a[0]; buff[p+1n]=a[1]; buff[p+2n]=a[2]; buff[p+3]=a[3]; }, + writeUint : function(buff, p, n) { buff[p] = (n>>>0)&255; buff[p+1n] = (n>>>8)&255; buff[p+2n] = (n>>>16)&255; buff[p+3n] = (n>>>24)&255; }, + writeASCII : UTIF._binBE.writeASCII +} +UTIF._copyTile = function(tb, tw, th, b, w, h, xoff, yoff) +{ + //log("copyTile", tw, th, w, h, xoff, yoff); + var xlim = Math.min(tw, w-xoff); + var ylim = Math.min(th, h-yoff); + for(var y=0; y>>8); +this._=8}return this.G>>>--this._&1},Z:function(Z){var X=this._,s=this.G,E=Math.min(X,Z);Z-=E;X-=E;var Y=s>>>X&(1<0){s=this.w[this.N];this.N+=1+(s+1>>>8);E=Math.min(8,Z);Z-=E;X=8-E;Y<<=E;Y|=s>>>X&(1<>>8);B=8}Y=$>>>--B&1;s=Z[s+Y];E=Z[s+2];if(E!=-1){X._=B;X.G=$;X.N=e;return E}}return-1};function l(Z){this.z=new t(Z); +this.D(this.z)}l.prototype={$:function(Z,X){this.Q=Z.i();this.F=Z.l();this.o=Z.l();var s=this.O=Z.i(); +this.L=[];for(var E=0;E0)Z-=this.e()},p:function(Z,X){var s=Z.i(); +if(!this.U){this.U=[]}for(var E=0;E>>4]}this.g=Z.i(); +Z.t(Z.N+X-(2+s*2))},D:function(Z){var X=!1,s=Z.l();if(s!==l.q)return;do{var s=Z.l(),E=Z.l()-2;switch(s){case l.m:this.$(Z,E); +break;case l.K:this.W(E);break;case l.V:this.p(Z,E);X=!0;break;default:Z.t(Z.N+E);break}}while(!X)},I:function(Z,X){var s=i.B(X,Z); +if(s==16)return-32768;var E=Z.Z(s);if((E&1<>>1);Z[K]=q+B(s,W[p])}}I+=X}}};l.m=65475; +l.K=65476;l.q=65496;l.V=65498;function J(Z){var X=new l(Z),s=X.Q>8?Uint16Array:Uint8Array,E=new s(X.o*X.F*X.O),Y=X.o*X.O; +X.B(E,Y);return E}return J}()) + + + + +})(UTIF, pako); +})(); \ No newline at end of file diff --git a/examples/source_file_cog.html b/examples/source_file_cog.html index 4e253fd15d..61fa6beac2 100644 --- a/examples/source_file_cog.html +++ b/examples/source_file_cog.html @@ -11,10 +11,11 @@
- + + + + +
+ + + + + + + + + + + From a8ec5216eded83ae65c22a0044ce3cdc6b49a351 Mon Sep 17 00:00:00 2001 From: gmaillet Date: Sun, 2 Feb 2020 23:37:35 +0100 Subject: [PATCH 5/7] WIP BigTIFF --- examples/js/plugins/COGSource.js | 42 ++++++++++++++++++++++---------- examples/js/plugins/UTIF.js | 22 ++++++++++++----- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/examples/js/plugins/COGSource.js b/examples/js/plugins/COGSource.js index f34ebccc6f..90385a3312 100644 --- a/examples/js/plugins/COGSource.js +++ b/examples/js/plugins/COGSource.js @@ -139,24 +139,40 @@ class COGSource extends itowns.Source { urlFromExtent(extent) { console.log(extent); - // Copy Ifd and add if to extent (for the parser) + // find the COG tile for this extent const ifdNum = this.zoomMax - extent.zoom; - extent.ifd = JSON.parse(JSON.stringify(this.ifds[ifdNum])); // get the offset/byteCount for the tile - const numTile = extent.col + extent.row * extent.ifd.nbTileX; - const offset = extent.ifd.t324[numTile]; - const byteCounts = extent.ifd.t325[numTile]; + const ifd = this.ifds[ifdNum]; + const numTile = extent.col + extent.row * ifd.nbTileX; + const offset = ifd.t324[numTile]; + const byteCounts = ifd.t325[numTile]; + const tileWidth = ifd.t322[0]; + const tileHeight = ifd.t323[0]; + // create a custom ifd copy for the TIFFParser + extent.ifd = {}; + for (const property in ifd) { + // width + if (property == 't256') { + extent.ifd[property] = tileWidth; + } + // height + else if (property == 't257') { + extent.ifd[property] = tileHeight; + } + // tile offsets + else if (property == 't324') { + extent.ifd[property] = [0n]; + } + // tile byteCounts + else if (property == 't325') { + extent.ifd[property] = [byteCounts]; + } + } + console.log(extent.ifd); // custom the networkOptions as a range request for this specific tile this.networkOptions.headers = { - 'range': `bytes=${offset}-${offset + byteCounts - 1}`, + 'range': `bytes=${offset}-${offset + BigInt(byteCounts) - 1n}`, }; - // update the ifd copy for the TIFFParser - // width/heigth from the tile size - extent.ifd.t256[0] = extent.ifd.t322[0]; - extent.ifd.t257[0] = extent.ifd.t323[0]; - // offset and byteCounts - extent.ifd.t324 = [0]; - extent.ifd.t325 = [byteCounts]; return this.url; } diff --git a/examples/js/plugins/UTIF.js b/examples/js/plugins/UTIF.js index b45f0849fb..d54f924403 100644 --- a/examples/js/plugins/UTIF.js +++ b/examples/js/plugins/UTIF.js @@ -121,7 +121,7 @@ UTIF.decode = function(buff, prm) UTIF.decodeImage = function(buff, img, ifds) { var data = new Uint8Array(buff); - var id = UTIF._binBE.readASCII(data, 0, 2); + var id = UTIF._binBE.readASCII(data, 0n, 2n); if(img["t256"]==null) return; // No width => probably not an image img.isLE = id=="II"; @@ -967,23 +967,33 @@ UTIF._readIFD = function(bin, data, offset, ifds, depth, prm) var arr = []; //ifd["t"+tag+"-"+UTIF.tags[tag]] = arr; if(type== 1 || type==7) { arr = new Uint8Array(data.buffer, (num<5 ? offset-4 : voff), num); } - if(type== 2) { var o0 = (num<5 ? offset-4 : voff), c=data[o0], len=Math.max(0, Math.min(num-1,data.length-o0)); - if(c<128 || len==0) arr.push( bin.readASCII(data, o0, len) ); - else arr = new Uint8Array(data.buffer, o0, len); } + if(type== 2) { + var o0 = (num<5n ? offset-4n : voff); + var c=data[o0]; + var len=Math.max(0, Math.min(num-1,data.length-o0)); + if(c<128 || len==0) + arr.push( bin.readASCII(data, o0, len) ); + else + arr = new Uint8Array(data.buffer, o0, len); + } if(type== 3) { for(var j=0n; j Date: Mon, 3 Feb 2020 11:22:34 +0100 Subject: [PATCH 6/7] WIP BigTIFF --- examples/js/plugins/COGSource.js | 32 +++++++++++++++--- examples/js/plugins/UTIF.js | 56 +++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 16 deletions(-) diff --git a/examples/js/plugins/COGSource.js b/examples/js/plugins/COGSource.js index 90385a3312..c33a77b37a 100644 --- a/examples/js/plugins/COGSource.js +++ b/examples/js/plugins/COGSource.js @@ -67,6 +67,7 @@ class COGSource extends itowns.Source { if (source.projection) { this.projection = itowns.CRS.formatToTms(source.projection); + this.crs = source.projection; } this.tileMatrixSetLimits = source.tileMatrixSetLimits; @@ -90,10 +91,13 @@ class COGSource extends itowns.Source { this.height = this.ifds[0].t257[0]; // Compute extent from GeoTiff Tag + console.log(this.modelTiepointTag, this.modelPixelScaleTag); this.extent = new itowns.Extent( source.projection, - this.modelTiepointTag[3], this.modelTiepointTag[3] + this.width * this.modelPixelScaleTag[0], - this.modelTiepointTag[4] - this.height * this.modelPixelScaleTag[1], this.modelTiepointTag[4]); + Math.floor(this.modelTiepointTag[3]*1000)*0.001, + Math.round((this.modelTiepointTag[3] + this.width * this.modelPixelScaleTag[0])*1000)*0.001, + Math.round((this.modelTiepointTag[4] - this.height * this.modelPixelScaleTag[1])*1000)*0.001, + Math.round(this.modelTiepointTag[4]*1000)*0.001); this.tileSize = this.ifds[0].t322[0]; this.zoomMax = Math.ceil(Math.log2(Math.max(this.width, this.height) / this.tileSize)); @@ -139,25 +143,40 @@ class COGSource extends itowns.Source { urlFromExtent(extent) { console.log(extent); + var extentOrig = extent.as(this.crs); + var xmin = extentOrig.west; + var xmax = extentOrig.east; + var ymin = extentOrig.south; + var ymax = extentOrig.north; + // recherche de cette emprise dans le cog + console.log('extent COG : ', this.extent); + var sizeX = xmax-xmin; + var sizeY = ymax-ymin; + var x0 = xmin - extent.col * sizeX; + var y0 = ymax + extent.row * sizeY; + + console.log(x0, y0); + // find the COG tile for this extent const ifdNum = this.zoomMax - extent.zoom; // get the offset/byteCount for the tile const ifd = this.ifds[ifdNum]; const numTile = extent.col + extent.row * ifd.nbTileX; - const offset = ifd.t324[numTile]; + const offset = BigInt(ifd.t324[numTile]); const byteCounts = ifd.t325[numTile]; const tileWidth = ifd.t322[0]; const tileHeight = ifd.t323[0]; // create a custom ifd copy for the TIFFParser extent.ifd = {}; + console.log(ifd); for (const property in ifd) { // width if (property == 't256') { - extent.ifd[property] = tileWidth; + extent.ifd[property] = [tileWidth]; } // height else if (property == 't257') { - extent.ifd[property] = tileHeight; + extent.ifd[property] = [tileHeight]; } // tile offsets else if (property == 't324') { @@ -167,6 +186,9 @@ class COGSource extends itowns.Source { else if (property == 't325') { extent.ifd[property] = [byteCounts]; } + else { + extent.ifd[property] = ifd[property]; + } } console.log(extent.ifd); // custom the networkOptions as a range request for this specific tile diff --git a/examples/js/plugins/UTIF.js b/examples/js/plugins/UTIF.js index d54f924403..4559d7b44a 100644 --- a/examples/js/plugins/UTIF.js +++ b/examples/js/plugins/UTIF.js @@ -112,7 +112,8 @@ UTIF.decode = function(buff, prm) var ifds = []; while(true) { var noff = UTIF._readIFD(bin, data, ifdo, ifds, 0, prm); - ifdo = bin.readUint(data, noff); + ifdo = BigInt(bin.readUint(data, noff)); + console.log(ifdo); if(ifdo==0 || noff==0) break; } return ifds; @@ -839,8 +840,29 @@ UTIF.decode._writeBits = function(bits, tgt, boff) } UTIF.decode._decodeLZW = function(){var x={},y=function(L,F,i,W,_){for(var a=0;a<_;a+=4){i[W+a]=L[F+a]; -i[W+a+1]=L[F+a+1];i[W+a+2]=L[F+a+2];i[W+a+3]=L[F+a+3]}},c=function(L,F,i,W){if(!x.c){var _=new Uint32Array(65535),a=new Uint16Array(65535),Z=new Uint8Array(2e6); -for(var f=0;f<256;f++){Z[f<<2]=f;_[f]=f<<2;a[f]=1}x.c=[_,a,Z]}var o=x.c[0],z=x.c[1],Z=x.c[2],h=258,n=258<<2,k=9,C=F<<3,m=256,B=257,p=0,O=0,K=0; +i[W+a+1]=L[F+a+1];i[W+a+2]=L[F+a+2];i[W+a+3]=L[F+a+3]}},c=function(L,F,i,W){if(!x.c){ + var _=new Uint32Array(65535),a=new Uint16Array(65535),Z=new Uint8Array(2e6); +for(var f=0;f<256;f++){ + Z[f<<2]=f; + _[f]=f<<2; + a[f]=1 +} +x.c=[_,a,Z] +} +var o=x.c[0]; +var z=x.c[1]; +var Z=x.c[2]; +var h=258; +var n=258<<2; +var k=9; +// ?????? +console.log(F); +var C=Number(F)<<3; +var m=256; +var B=257; +var p=0; +var O=0; +var K=0; while(!0){p=L[C>>>3]<<16|L[C+8>>>3]<<8|L[C+16>>>3];O=p>>24-(C&7)-k&(1<>>3]<<16|L[C+8>>>3]<<8|L[C+16>>>3];O=p>>24-(C&7)-k&(1<=h){o[h]=n;Z[o[h]]=J[0];z[h]=1;n=n+1+3&~3; @@ -953,6 +975,7 @@ UTIF._readIFD_BigTIFF = function(bin, data, offset, ifds, depth, prm) UTIF._readIFD = function(bin, data, offset, ifds, depth, prm) { + console.log('readIFD : ', bin, data, offset); var cnt = bin.readUshort(data, offset); offset+=2n; var ifd = {}; @@ -963,18 +986,29 @@ UTIF._readIFD = function(bin, data, offset, ifds, depth, prm) var type = bin.readUshort(data, offset); offset+=2n; var num = BigInt(bin.readUint (data, offset)); offset+=4n; var voff = BigInt(bin.readUint (data, offset)); offset+=4n; - console.log(tag, type, num, voff); + // console.log(tag, type, num, voff); var arr = []; //ifd["t"+tag+"-"+UTIF.tags[tag]] = arr; if(type== 1 || type==7) { arr = new Uint8Array(data.buffer, (num<5 ? offset-4 : voff), num); } if(type== 2) { - var o0 = (num<5n ? offset-4n : voff); - var c=data[o0]; - var len=Math.max(0, Math.min(num-1,data.length-o0)); - if(c<128 || len==0) - arr.push( bin.readASCII(data, o0, len) ); - else - arr = new Uint8Array(data.buffer, o0, len); + var o0 = (num<9n ? offset-8n : voff); + console.log('o0 : ', o0); + var len = num-1n; + // var c=data[o0]; + // console.log('c : ', c); + // var len=Math.max(0n, Math.min(num-1n,BigInt(data.length)-o0)); + // console.log(o0, c, len); + // if(c<128n || len==0n) + arr.push( bin.readASCII(data, o0, len) ); + // else + // arr = new Uint8Array(data.buffer, o0, len); + // var o0 = (num<5n ? offset-4n : voff); + // var c=data[o0]; + // var len=Math.max(0, Math.min(num-1,data.length-o0)); + // if(c<128 || len==0) + // arr.push( bin.readASCII(data, o0, len) ); + // else + // arr = new Uint8Array(data.buffer, o0, len); } if(type== 3) { for(var j=0n; j Date: Tue, 4 Feb 2020 04:38:12 +0100 Subject: [PATCH 7/7] single and multiple examples works! --- examples/js/plugins/COGSource.js | 98 ++++++++++------------------- examples/js/plugins/UTIF.js | 1 - examples/source_file_cog.html | 1 + examples/source_file_cog_multi.html | 70 ++++++++++++--------- 4 files changed, 74 insertions(+), 96 deletions(-) diff --git a/examples/js/plugins/COGSource.js b/examples/js/plugins/COGSource.js index c33a77b37a..54edc85a6d 100644 --- a/examples/js/plugins/COGSource.js +++ b/examples/js/plugins/COGSource.js @@ -16,14 +16,6 @@ * or other system. See [this link]{@link * https://alastaira.wordpress.com/2011/07/06/converting-tms-tile-coordinates-to-googlebingosm-tile-coordinates/} * for more information. - * @property {string} tileMatrixSet - Tile matrix set of the layer, used in the - * generation of the coordinates to build the url. Default value is 'WGS84'. - * @property {Object} zoom - Object containing the minimum and maximum values of - * the level, to zoom in the source. - * @property {number} zoom.min - The minimum level of the source. Default value - * is computed from the COG file. - * @property {number} zoom.max - The maximum level of the source. Default value - * is computed from the COG file. * * @example * // Create the source @@ -89,29 +81,22 @@ class COGSource extends itowns.Source { this.geoAsciiParamsTag = this.ifds[0].t34737; this.width = this.ifds[0].t256[0]; this.height = this.ifds[0].t257[0]; + this.resolution = Math.round(this.modelPixelScaleTag[0] * 1000) * 0.001; + this.tileSize = this.ifds[0].t322[0]; // Compute extent from GeoTiff Tag - console.log(this.modelTiepointTag, this.modelPixelScaleTag); this.extent = new itowns.Extent( source.projection, - Math.floor(this.modelTiepointTag[3]*1000)*0.001, - Math.round((this.modelTiepointTag[3] + this.width * this.modelPixelScaleTag[0])*1000)*0.001, - Math.round((this.modelTiepointTag[4] - this.height * this.modelPixelScaleTag[1])*1000)*0.001, - Math.round(this.modelTiepointTag[4]*1000)*0.001); + Math.floor(this.modelTiepointTag[3] * 1000) * 0.001, + Math.round((this.modelTiepointTag[3] + Math.ceil(this.width / this.tileSize) * this.tileSize * this.modelPixelScaleTag[0]) * 1000) * 0.001, + Math.round((this.modelTiepointTag[4] - Math.ceil(this.height /this.tileSize) * this.tileSize * this.modelPixelScaleTag[1]) * 1000) * 0.001, + Math.round(this.modelTiepointTag[4] * 1000) * 0.001); - this.tileSize = this.ifds[0].t322[0]; - this.zoomMax = Math.ceil(Math.log2(Math.max(this.width, this.height) / this.tileSize)); - console.log('zoomMax : ', this.zoomMax); - if (!this.zoom) { - this.zoom = { - min: this.zoomMax - this.ifds.length + 1, - max: this.zoomMax, - }; - console.log(this.zoom); - } - var tileMaxtrixSetLimits = {}; - var level = this.zoom.max; + this.resolutions = []; + var res = this.resolution; this.ifds.forEach((ifd) => { + this.resolutions.push(res); + res *= 2; // Format Image // var bitsPerSample = ifd.t258; // var sampleFormat = ifd.t339; @@ -124,51 +109,36 @@ class COGSource extends itowns.Source { const tileHeight = ifd.t323[0]; ifd.nbTileX = Math.ceil(width / tileWidth); ifd.nbTileY = Math.ceil(height / tileHeight); - tileMaxtrixSetLimits[level] = { - "minTileRow": 0, - "maxTileRow": ifd.nbTileY, - "minTileCol": 0, - "maxTileCol": ifd.nbTileX, - } if ((this.tileSize != tileHeight) || (this.tileSize != tileWidth)) { console.warn('all tiles must have same dimensions'); } - level -= 1; }); - if (!this.tileMaxtrixSetLimits) { - this.tileMaxtrixSetLimits = tileMaxtrixSetLimits; - } + console.log(this.resolutions); + console.log(this.ifds); + console.log('READY'); }); } - urlFromExtent(extent) { - console.log(extent); - var extentOrig = extent.as(this.crs); - var xmin = extentOrig.west; - var xmax = extentOrig.east; - var ymin = extentOrig.south; - var ymax = extentOrig.north; - // recherche de cette emprise dans le cog - console.log('extent COG : ', this.extent); - var sizeX = xmax-xmin; - var sizeY = ymax-ymin; - var x0 = xmin - extent.col * sizeX; - var y0 = ymax + extent.row * sizeY; - - console.log(x0, y0); + getTile(extent){ + const extentOrig = extent.as(this.crs); + const requestedResolution = Math.round((extentOrig.east - extentOrig.west) / this.tileSize * 1000) * 0.001; + return { + ifdNum: this.resolutions.indexOf(requestedResolution), + col: Math.round((extentOrig.west - this.extent.west) / (requestedResolution * this.tileSize) * 1000) * 0.001, + row: Math.round((this.extent.north - extentOrig.north) / (requestedResolution * this.tileSize) * 1000) * 0.001, + }; + } - // find the COG tile for this extent - const ifdNum = this.zoomMax - extent.zoom; - // get the offset/byteCount for the tile - const ifd = this.ifds[ifdNum]; - const numTile = extent.col + extent.row * ifd.nbTileX; + urlFromExtent(extent) { + var T = this.getTile(extent); + const ifd = this.ifds[T.ifdNum]; + const numTile = T.col + T.row * ifd.nbTileX; const offset = BigInt(ifd.t324[numTile]); const byteCounts = ifd.t325[numTile]; const tileWidth = ifd.t322[0]; const tileHeight = ifd.t323[0]; // create a custom ifd copy for the TIFFParser extent.ifd = {}; - console.log(ifd); for (const property in ifd) { // width if (property == 't256') { @@ -190,7 +160,6 @@ class COGSource extends itowns.Source { extent.ifd[property] = ifd[property]; } } - console.log(extent.ifd); // custom the networkOptions as a range request for this specific tile this.networkOptions.headers = { 'range': `bytes=${offset}-${offset + BigInt(byteCounts) - 1n}`, @@ -203,15 +172,12 @@ class COGSource extends itowns.Source { } extentInsideLimit(extent) { - // This layer provides data starting at level = layer.source.zoom.min - // (the zoom.max property is used when building the url to make - // sure we don't use invalid levels) - return extent.zoom >= this.zoom.min && extent.zoom <= this.zoom.max && - (this.tileMatrixSetLimits == undefined || - (extent.row >= this.tileMatrixSetLimits[extent.zoom].minTileRow && - extent.row <= this.tileMatrixSetLimits[extent.zoom].maxTileRow && - extent.col >= this.tileMatrixSetLimits[extent.zoom].minTileCol && - extent.col <= this.tileMatrixSetLimits[extent.zoom].maxTileCol)); + var T = this.getTile(extent); + return (T.ifdNum>=0)&& + (T.ifdNum=0)&&(T.row>=0)&& + (T.col { console.log(cogSource.extent); diff --git a/examples/source_file_cog_multi.html b/examples/source_file_cog_multi.html index 825465267b..625e44f8c6 100644 --- a/examples/source_file_cog_multi.html +++ b/examples/source_file_cog_multi.html @@ -21,44 +21,56 @@