(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o CLEAR_CODE) { throw 'corrupted code at scanline ' + code; } if (code === EOI_CODE) { break; } else { var val = this.dictionary[code]; this.appendArray(this.result, val); oldCode = code; } } else { if (this.dictionary[code] !== undefined) { var _val = this.dictionary[code]; this.appendArray(this.result, _val); var newVal = this.dictionary[oldCode].concat(this.dictionary[code][0]); this.addToDictionary(newVal); oldCode = code; } else { var oldVal = this.dictionary[oldCode]; if (!oldVal) { throw "Bogus entry. Not in dictionary, " + oldCode + " / " + this.dictionary.length + ", position: " + this.position; } var _newVal = oldVal.concat(this.dictionary[oldCode][0]); this.appendArray(this.result, _newVal); this.addToDictionary(_newVal); oldCode = code; } } // This is strange. It seems like the if (this.dictionary.length >= Math.pow(2, this.byteLength) - 1) { this.byteLength++; } code = this.getNext(mydataview); } return new Uint8Array(this.result); }, appendArray: function appendArray(dest, source) { for (var i = 0; i < source.length; i++) { dest.push(source[i]); } return dest; }, haveBytesChanged: function haveBytesChanged() { if (this.dictionary.length >= Math.pow(2, this.byteLength)) { this.byteLength++; return true; } return false; }, addToDictionary: function addToDictionary(arr) { this.dictionary.push(arr); if (this._makeEntryLookup) { this.entryLookup[arr] = this.dictionary.length - 1; } this.haveBytesChanged(); return this.dictionary.length - 1; }, getNext: function getNext(dataview) { var byte = this.getByte(dataview, this.position, this.byteLength); this.position += this.byteLength; return byte; }, // This binary representation might actually be as fast as the completely illegible bit shift approach // getByte: function getByte(dataview, position, length) { var d = position % 8; var a = Math.floor(position / 8); var de = 8 - d; var ef = position + length - (a + 1) * 8; var fg = 8 * (a + 2) - (position + length); var dg = (a + 2) * 8 - position; fg = Math.max(0, fg); if (a >= dataview.byteLength) { console.warn('ran off the end of the buffer before finding EOI_CODE (end on input code)'); return EOI_CODE; } var chunk1 = dataview.getUint8(a, this.littleEndian) & Math.pow(2, 8 - d) - 1; chunk1 = chunk1 << length - de; var chunks = chunk1; if (a + 1 < dataview.byteLength) { var chunk2 = dataview.getUint8(a + 1, this.littleEndian) >>> fg; chunk2 = chunk2 << Math.max(0, length - dg); chunks += chunk2; } if (ef > 8 && a + 2 < dataview.byteLength) { var hi = (a + 3) * 8 - (position + length); var chunk3 = dataview.getUint8(a + 2, this.littleEndian) >>> hi; chunks += chunk3; } return chunks; }, // compress has not been optimized and uses a uint8 array to hold binary values. compress: function compress(input) { this._makeEntryLookup = true; this.initDictionary(); this.position = 0; var resultBits = []; var omega = []; resultBits = this.appendArray(resultBits, this.binaryFromByte(CLEAR_CODE, this.byteLength)); // resultBits.concat(Array.from(this.binaryFromByte(this.CLEAR_CODE, this.byteLength))) for (var i = 0; i < input.length; i++) { var k = [input[i]]; var omk = omega.concat(k); if (this.entryLookup[omk] !== undefined) { omega = omk; } else { var _code = this.entryLookup[omega]; var _bin = this.binaryFromByte(_code, this.byteLength); resultBits = this.appendArray(resultBits, _bin); this.addToDictionary(omk); omega = k; if (this.dictionary.length >= Math.pow(2, MAX_BITS)) { resultBits = this.appendArray(resultBits, this.binaryFromByte(CLEAR_CODE, this.byteLength)); this.initDictionary(); } } } var code = this.entryLookup[omega]; var bin = this.binaryFromByte(code, this.byteLength); resultBits = this.appendArray(resultBits, bin); resultBits = resultBits = this.appendArray(resultBits, this.binaryFromByte(EOI_CODE, this.byteLength)); this.binary = resultBits; this.result = this.binaryToUint8(resultBits); return this.result; }, byteFromCode: function byteFromCode(code) { var res = this.dictionary[code]; return res; }, binaryFromByte: function binaryFromByte(byte) { var byteLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 8; var res = new Uint8Array(byteLength); for (var i = 0; i < res.length; i++) { var mask = Math.pow(2, i); var isOne = (byte & mask) > 0; res[res.length - 1 - i] = isOne; } return res; }, binaryToNumber: function binaryToNumber(bin) { var res = 0; for (var i = 0; i < bin.length; i++) { res += Math.pow(2, bin.length - i - 1) * bin[i]; } return res; }, inputToBinary: function inputToBinary(input) { var inputByteLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 8; var res = new Uint8Array(input.length * inputByteLength); for (var i = 0; i < input.length; i++) { var bin = this.binaryFromByte(input[i], inputByteLength); res.set(bin, i * inputByteLength); } return res; }, binaryToUint8: function binaryToUint8(bin) { var result = new Uint8Array(Math.ceil(bin.length / 8)); var index = 0; for (var i = 0; i < bin.length; i += 8) { var val = 0; for (var j = 0; j < 8 && i + j < bin.length; j++) { val = val + bin[i + j] * Math.pow(2, 8 - j - 1); } result[index] = val; index++; } return result; } }; // the actual decoder interface function LZWDecoder() { this.decompressor = new LZW(); } LZWDecoder.prototype = Object.create(AbstractDecoder.prototype); LZWDecoder.prototype.constructor = LZWDecoder; LZWDecoder.prototype.decodeBlock = function (buffer) { return this.decompressor.decompress(buffer).buffer; }; module.exports = LZWDecoder; },{"../abstractdecoder.js":1}],4:[function(require,module,exports){ "use strict"; var AbstractDecoder = require("../abstractdecoder.js"); function PackbitsDecoder() {} PackbitsDecoder.prototype = Object.create(AbstractDecoder.prototype); PackbitsDecoder.prototype.constructor = PackbitsDecoder; PackbitsDecoder.prototype.decodeBlock = function (buffer) { var dataView = new DataView(buffer); var out = []; var i, j; for (i = 0; i < buffer.byteLength; ++i) { var header = dataView.getInt8(i); if (header < 0) { var next = dataView.getUint8(i + 1); header = -header; for (j = 0; j <= header; ++j) { out.push(next); } i += 1; } else { for (j = 0; j <= header; ++j) { out.push(dataView.getUint8(i + j + 1)); } i += header + 1; } } return new Uint8Array(out).buffer; }; module.exports = PackbitsDecoder; },{"../abstractdecoder.js":1}],5:[function(require,module,exports){ "use strict"; var AbstractDecoder = require("../abstractdecoder.js"); function RawDecoder() {} RawDecoder.prototype = Object.create(AbstractDecoder.prototype); RawDecoder.prototype.constructor = RawDecoder; RawDecoder.prototype.decodeBlock = function (buffer) { return buffer; }; module.exports = RawDecoder; },{"../abstractdecoder.js":1}],6:[function(require,module,exports){ "use strict"; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var DataView64 = function () { function DataView64(arrayBuffer) { _classCallCheck(this, DataView64); this._dataView = new DataView(arrayBuffer); } _createClass(DataView64, [{ key: "getUint64", value: function getUint64(offset, littleEndian) { var left = this.getUint32(offset, littleEndian); var right = this.getUint32(offset + 4, littleEndian); if (littleEndian) { return left << 32 | right; } return right << 32 | left; } }, { key: "getInt64", value: function getInt64(offset, littleEndian) { var left, right; if (littleEndian) { left = this.getInt32(offset, littleEndian); right = this.getUint32(offset + 4, littleEndian); return left << 32 | right; } left = this.getUint32(offset, littleEndian); right = this.getInt32(offset + 4, littleEndian); return right << 32 | left; } }, { key: "getUint8", value: function getUint8(offset, littleEndian) { return this._dataView.getUint8(offset, littleEndian); } }, { key: "getInt8", value: function getInt8(offset, littleEndian) { return this._dataView.getInt8(offset, littleEndian); } }, { key: "getUint16", value: function getUint16(offset, littleEndian) { return this._dataView.getUint16(offset, littleEndian); } }, { key: "getInt16", value: function getInt16(offset, littleEndian) { return this._dataView.getInt16(offset, littleEndian); } }, { key: "getUint32", value: function getUint32(offset, littleEndian) { return this._dataView.getUint32(offset, littleEndian); } }, { key: "getInt32", value: function getInt32(offset, littleEndian) { return this._dataView.getInt32(offset, littleEndian); } }, { key: "getFloat32", value: function getFloat32(offset, littleEndian) { return this._dataView.getFloat32(offset, littleEndian); } }, { key: "getFloat64", value: function getFloat64(offset, littleEndian) { return this._dataView.getFloat64(offset, littleEndian); } }, { key: "buffer", get: function get() { return this._dataView.buffer; } }]); return DataView64; }(); module.exports = DataView64; },{}],7:[function(require,module,exports){ "use strict"; var globals = require("./globals.js"); var GeoTIFFImage = require("./geotiffimage.js"); var DataView64 = require("./dataview64.js"); var fieldTypes = globals.fieldTypes, fieldTagNames = globals.fieldTagNames, arrayFields = globals.arrayFields, geoKeyNames = globals.geoKeyNames; /** * The abstraction for a whole GeoTIFF file. * @constructor * @param {ArrayBuffer} rawData the raw data stream of the file as an ArrayBuffer. * @param {Object} [options] further options. * @param {Boolean} [options.cache=false] whether or not decoded tiles shall be cached. */ function GeoTIFF(rawData, options) { this.dataView = new DataView64(rawData); options = options || {}; this.cache = options.cache || false; var BOM = this.dataView.getUint16(0, 0); if (BOM === 0x4949) { this.littleEndian = true; } else if (BOM === 0x4D4D) { this.littleEndian = false; } else { throw new TypeError("Invalid byte order value."); } var magicNumber = this.dataView.getUint16(2, this.littleEndian); if (this.dataView.getUint16(2, this.littleEndian) === 42) { this.bigTiff = false; } else if (magicNumber === 43) { this.bigTiff = true; var offsetBytesize = this.dataView.getUint16(4, this.littleEndian); if (offsetBytesize !== 8) { throw new Error("Unsupported offset byte-size."); } } else { throw new TypeError("Invalid magic number."); } this.fileDirectories = this.parseFileDirectories(this.getOffset(this.bigTiff ? 8 : 4)); } GeoTIFF.prototype = { getOffset: function getOffset(offset) { if (this.bigTiff) { return this.dataView.getUint64(offset, this.littleEndian); } return this.dataView.getUint32(offset, this.littleEndian); }, getFieldTypeLength: function getFieldTypeLength(fieldType) { switch (fieldType) { case fieldTypes.BYTE:case fieldTypes.ASCII:case fieldTypes.SBYTE:case fieldTypes.UNDEFINED: return 1; case fieldTypes.SHORT:case fieldTypes.SSHORT: return 2; case fieldTypes.LONG:case fieldTypes.SLONG:case fieldTypes.FLOAT: return 4; case fieldTypes.RATIONAL:case fieldTypes.SRATIONAL:case fieldTypes.DOUBLE: case fieldTypes.LONG8:case fieldTypes.SLONG8:case fieldTypes.IFD8: return 8; default: throw new RangeError("Invalid field type: " + fieldType); } }, getValues: function getValues(fieldType, count, offset) { var values = null; var readMethod = null; var fieldTypeLength = this.getFieldTypeLength(fieldType); var i; switch (fieldType) { case fieldTypes.BYTE:case fieldTypes.ASCII:case fieldTypes.UNDEFINED: values = new Uint8Array(count);readMethod = this.dataView.getUint8; break; case fieldTypes.SBYTE: values = new Int8Array(count);readMethod = this.dataView.getInt8; break; case fieldTypes.SHORT: values = new Uint16Array(count);readMethod = this.dataView.getUint16; break; case fieldTypes.SSHORT: values = new Int16Array(count);readMethod = this.dataView.getInt16; break; case fieldTypes.LONG: values = new Uint32Array(count);readMethod = this.dataView.getUint32; break; case fieldTypes.SLONG: values = new Int32Array(count);readMethod = this.dataView.getInt32; break; case fieldTypes.LONG8:case fieldTypes.IFD8: values = new Array(count);readMethod = this.dataView.getUint64; break; case fieldTypes.SLONG8: values = new Array(count);readMethod = this.dataView.getInt64; break; case fieldTypes.RATIONAL: values = new Uint32Array(count * 2);readMethod = this.dataView.getUint32; break; case fieldTypes.SRATIONAL: values = new Int32Array(count * 2);readMethod = this.dataView.getInt32; break; case fieldTypes.FLOAT: values = new Float32Array(count);readMethod = this.dataView.getFloat32; break; case fieldTypes.DOUBLE: values = new Float64Array(count);readMethod = this.dataView.getFloat64; break; default: throw new RangeError("Invalid field type: " + fieldType); } // normal fields if (!(fieldType === fieldTypes.RATIONAL || fieldType === fieldTypes.SRATIONAL)) { for (i = 0; i < count; ++i) { values[i] = readMethod.call(this.dataView, offset + i * fieldTypeLength, this.littleEndian); } } // RATIONAL or SRATIONAL else { for (i = 0; i < count; i += 2) { values[i] = readMethod.call(this.dataView, offset + i * fieldTypeLength, this.littleEndian); values[i + 1] = readMethod.call(this.dataView, offset + (i * fieldTypeLength + 4), this.littleEndian); } } if (fieldType === fieldTypes.ASCII) { return String.fromCharCode.apply(null, values); } return values; }, getFieldValues: function getFieldValues(fieldTag, fieldType, typeCount, valueOffset) { var fieldValues; var fieldTypeLength = this.getFieldTypeLength(fieldType); if (fieldTypeLength * typeCount <= (this.bigTiff ? 8 : 4)) { fieldValues = this.getValues(fieldType, typeCount, valueOffset); } else { var actualOffset = this.getOffset(valueOffset); fieldValues = this.getValues(fieldType, typeCount, actualOffset); } if (typeCount === 1 && arrayFields.indexOf(fieldTag) === -1 && !(fieldType === fieldTypes.RATIONAL || fieldType === fieldTypes.SRATIONAL)) { return fieldValues[0]; } return fieldValues; }, parseGeoKeyDirectory: function parseGeoKeyDirectory(fileDirectory) { var rawGeoKeyDirectory = fileDirectory.GeoKeyDirectory; if (!rawGeoKeyDirectory) { return null; } var geoKeyDirectory = {}; for (var i = 4; i < rawGeoKeyDirectory[3] * 4; i += 4) { var key = geoKeyNames[rawGeoKeyDirectory[i]], location = rawGeoKeyDirectory[i + 1] ? fieldTagNames[rawGeoKeyDirectory[i + 1]] : null, count = rawGeoKeyDirectory[i + 2], offset = rawGeoKeyDirectory[i + 3]; var value = null; if (!location) { value = offset; } else { value = fileDirectory[location]; if (typeof value === "undefined" || value === null) { throw new Error("Could not get value of geoKey '" + key + "'."); } else if (typeof value === "string") { value = value.substring(offset, offset + count - 1); } else if (value.subarray) { value = value.subarray(offset, offset + count - 1); } } geoKeyDirectory[key] = value; } return geoKeyDirectory; }, parseFileDirectories: function parseFileDirectories(byteOffset) { var nextIFDByteOffset = byteOffset; var fileDirectories = []; while (nextIFDByteOffset !== 0x00000000) { var numDirEntries = this.bigTiff ? this.dataView.getUint64(nextIFDByteOffset, this.littleEndian) : this.dataView.getUint16(nextIFDByteOffset, this.littleEndian); var fileDirectory = {}; for (var i = byteOffset + (this.bigTiff ? 8 : 2), entryCount = 0; entryCount < numDirEntries; i += this.bigTiff ? 20 : 12, ++entryCount) { var fieldTag = this.dataView.getUint16(i, this.littleEndian); var fieldType = this.dataView.getUint16(i + 2, this.littleEndian); var typeCount = this.bigTiff ? this.dataView.getUint64(i + 4, this.littleEndian) : this.dataView.getUint32(i + 4, this.littleEndian); fileDirectory[fieldTagNames[fieldTag]] = this.getFieldValues(fieldTag, fieldType, typeCount, i + (this.bigTiff ? 12 : 8)); } fileDirectories.push([fileDirectory, this.parseGeoKeyDirectory(fileDirectory)]); nextIFDByteOffset = this.getOffset(i); } return fileDirectories; }, /** * Get the n-th internal subfile a an image. By default, the first is returned. * * @param {Number} [index=0] the index of the image to return. * @returns {GeoTIFFImage} the image at the given index */ getImage: function getImage(index) { index = index || 0; var fileDirectoryAndGeoKey = this.fileDirectories[index]; if (!fileDirectoryAndGeoKey) { throw new RangeError("Invalid image index"); } return new GeoTIFFImage(fileDirectoryAndGeoKey[0], fileDirectoryAndGeoKey[1], this.dataView, this.littleEndian, this.cache); }, /** * Returns the count of the internal subfiles. * * @returns {Number} the number of internal subfile images */ getImageCount: function getImageCount() { return this.fileDirectories.length; } }; module.exports = GeoTIFF; },{"./dataview64.js":6,"./geotiffimage.js":8,"./globals.js":9}],8:[function(require,module,exports){ "use strict"; var globals = require("./globals.js"); var RGB = require("./rgb.js"); var RawDecoder = require("./compression/raw.js"); var LZWDecoder = require("./compression/lzw.js"); var DeflateDecoder = require("./compression/deflate.js"); var PackbitsDecoder = require("./compression/packbits.js"); var sum = function sum(array, start, end) { var s = 0; for (var i = start; i < end; ++i) { s += array[i]; } return s; }; var arrayForType = function arrayForType(format, bitsPerSample, size) { switch (format) { case 1: // unsigned integer data switch (bitsPerSample) { case 8: return new Uint8Array(size); case 16: return new Uint16Array(size); case 32: return new Uint32Array(size); } break; case 2: // twos complement signed integer data switch (bitsPerSample) { case 8: return new Int8Array(size); case 16: return new Int16Array(size); case 32: return new Int32Array(size); } break; case 3: // floating point data switch (bitsPerSample) { case 32: return new Float32Array(size); case 64: return new Float64Array(size); } break; } throw Error("Unsupported data format/bitsPerSample"); }; /** * GeoTIFF sub-file image. * @constructor * @param {Object} fileDirectory The parsed file directory * @param {Object} geoKeys The parsed geo-keys * @param {DataView} dataView The DataView for the underlying file. * @param {Boolean} littleEndian Whether the file is encoded in little or big endian * @param {Boolean} cache Whether or not decoded tiles shall be cached */ function GeoTIFFImage(fileDirectory, geoKeys, dataView, littleEndian, cache) { this.fileDirectory = fileDirectory; this.geoKeys = geoKeys; this.dataView = dataView; this.littleEndian = littleEndian; this.tiles = cache ? {} : null; this.isTiled = fileDirectory.StripOffsets ? false : true; var planarConfiguration = fileDirectory.PlanarConfiguration; this.planarConfiguration = typeof planarConfiguration === "undefined" ? 1 : planarConfiguration; if (this.planarConfiguration !== 1 && this.planarConfiguration !== 2) { throw new Error("Invalid planar configuration."); } switch (this.fileDirectory.Compression) { case undefined: case 1: // no compression this.decoder = new RawDecoder(); break; case 5: // LZW this.decoder = new LZWDecoder(); break; case 6: // JPEG throw new Error("JPEG compression not supported."); case 8: // Deflate this.decoder = new DeflateDecoder(); break; //case 32946: // deflate ?? // throw new Error("Deflate compression not supported."); case 32773: // packbits this.decoder = new PackbitsDecoder(); break; default: throw new Error("Unknown compresseion method identifier: " + this.fileDirectory.Compression); } } GeoTIFFImage.prototype = { /** * Returns the associated parsed file directory. * @returns {Object} the parsed file directory */ getFileDirectory: function getFileDirectory() { return this.fileDirectory; }, /** * Returns the associated parsed geo keys. * @returns {Object} the parsed geo keys */ getGeoKeys: function getGeoKeys() { return this.geoKeys; }, /** * Returns the width of the image. * @returns {Number} the width of the image */ getWidth: function getWidth() { return this.fileDirectory.ImageWidth; }, /** * Returns the height of the image. * @returns {Number} the height of the image */ getHeight: function getHeight() { return this.fileDirectory.ImageLength; }, /** * Returns the number of samples per pixel. * @returns {Number} the number of samples per pixel */ getSamplesPerPixel: function getSamplesPerPixel() { return this.fileDirectory.SamplesPerPixel; }, /** * Returns the width of each tile. * @returns {Number} the width of each tile */ getTileWidth: function getTileWidth() { return this.isTiled ? this.fileDirectory.TileWidth : this.getWidth(); }, /** * Returns the height of each tile. * @returns {Number} the height of each tile */ getTileHeight: function getTileHeight() { return this.isTiled ? this.fileDirectory.TileLength : this.fileDirectory.RowsPerStrip; }, /** * Calculates the number of bytes for each pixel across all samples. Only full * bytes are supported, an exception is thrown when this is not the case. * @returns {Number} the bytes per pixel */ getBytesPerPixel: function getBytesPerPixel() { var bitsPerSample = 0; for (var i = 0; i < this.fileDirectory.BitsPerSample.length; ++i) { var bits = this.fileDirectory.BitsPerSample[i]; if (bits % 8 !== 0) { throw new Error("Sample bit-width of " + bits + " is not supported."); } else if (bits !== this.fileDirectory.BitsPerSample[0]) { throw new Error("Differing size of samples in a pixel are not supported."); } bitsPerSample += bits; } return bitsPerSample / 8; }, getSampleByteSize: function getSampleByteSize(i) { if (i >= this.fileDirectory.BitsPerSample.length) { throw new RangeError("Sample index " + i + " is out of range."); } var bits = this.fileDirectory.BitsPerSample[i]; if (bits % 8 !== 0) { throw new Error("Sample bit-width of " + bits + " is not supported."); } return bits / 8; }, getReaderForSample: function getReaderForSample(sampleIndex) { var format = this.fileDirectory.SampleFormat ? this.fileDirectory.SampleFormat[sampleIndex] : 1; var bitsPerSample = this.fileDirectory.BitsPerSample[sampleIndex]; switch (format) { case 1: // unsigned integer data switch (bitsPerSample) { case 8: return DataView.prototype.getUint8; case 16: return DataView.prototype.getUint16; case 32: return DataView.prototype.getUint32; } break; case 2: // twos complement signed integer data switch (bitsPerSample) { case 8: return DataView.prototype.getInt8; case 16: return DataView.prototype.getInt16; case 32: return DataView.prototype.getInt32; } break; case 3: switch (bitsPerSample) { case 32: return DataView.prototype.getFloat32; case 64: return DataView.prototype.getFloat64; } break; } }, getArrayForSample: function getArrayForSample(sampleIndex, size) { var format = this.fileDirectory.SampleFormat ? this.fileDirectory.SampleFormat[sampleIndex] : 1; var bitsPerSample = this.fileDirectory.BitsPerSample[sampleIndex]; return arrayForType(format, bitsPerSample, size); }, getDecoder: function getDecoder() { return this.decoder; }, /** * Returns the decoded strip or tile. * @param {Number} x the strip or tile x-offset * @param {Number} y the tile y-offset (0 for stripped images) * @param {Number} plane the planar configuration (1: "chunky", 2: "separate samples") * @returns {(Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array)} */ getTileOrStrip: function getTileOrStrip(x, y, sample, callback) { var numTilesPerRow = Math.ceil(this.getWidth() / this.getTileWidth()); var numTilesPerCol = Math.ceil(this.getHeight() / this.getTileHeight()); var index; var tiles = this.tiles; if (this.planarConfiguration === 1) { index = y * numTilesPerRow + x; } else if (this.planarConfiguration === 2) { index = sample * numTilesPerRow * numTilesPerCol + y * numTilesPerRow + x; } if (tiles !== null && index in tiles) { if (callback) { return callback(null, { x: x, y: y, sample: sample, data: tiles[index] }); } return tiles[index]; } else { var offset, byteCount; if (this.isTiled) { offset = this.fileDirectory.TileOffsets[index]; byteCount = this.fileDirectory.TileByteCounts[index]; } else { offset = this.fileDirectory.StripOffsets[index]; byteCount = this.fileDirectory.StripByteCounts[index]; } var slice = this.dataView.buffer.slice(offset, offset + byteCount); if (callback) { return this.getDecoder().decodeBlockAsync(slice, function (error, data) { if (!error && tiles !== null) { tiles[index] = data; } callback(error, { x: x, y: y, sample: sample, data: data }); }); } var block = this.getDecoder().decodeBlock(slice); if (tiles !== null) { tiles[index] = block; } return block; } }, _readRasterAsync: function _readRasterAsync(imageWindow, samples, valueArrays, interleave, callback, callbackError) { var tileWidth = this.getTileWidth(); var tileHeight = this.getTileHeight(); var minXTile = Math.floor(imageWindow[0] / tileWidth); var maxXTile = Math.ceil(imageWindow[2] / tileWidth); var minYTile = Math.floor(imageWindow[1] / tileHeight); var maxYTile = Math.ceil(imageWindow[3] / tileHeight); var numTilesPerRow = Math.ceil(this.getWidth() / tileWidth); var windowWidth = imageWindow[2] - imageWindow[0]; var windowHeight = imageWindow[3] - imageWindow[1]; var bytesPerPixel = this.getBytesPerPixel(); var imageWidth = this.getWidth(); var predictor = this.fileDirectory.Predictor || 1; var srcSampleOffsets = []; var sampleReaders = []; for (var i = 0; i < samples.length; ++i) { if (this.planarConfiguration === 1) { srcSampleOffsets.push(sum(this.fileDirectory.BitsPerSample, 0, samples[i]) / 8); } else { srcSampleOffsets.push(0); } sampleReaders.push(this.getReaderForSample(samples[i])); } var allStacked = false; var unfinishedTiles = 0; var littleEndian = this.littleEndian; var globalError = null; function checkFinished() { if (allStacked && unfinishedTiles === 0) { if (globalError) { callbackError(globalError); } else { callback(valueArrays); } } } function onTileGot(error, tile) { if (!error) { var dataView = new DataView(tile.data); var firstLine = tile.y * tileHeight; var firstCol = tile.x * tileWidth; var lastLine = (tile.y + 1) * tileHeight; var lastCol = (tile.x + 1) * tileWidth; var sampleIndex = tile.sample; for (var y = Math.max(0, imageWindow[1] - firstLine); y < Math.min(tileHeight, tileHeight - (lastLine - imageWindow[3])); ++y) { for (var x = Math.max(0, imageWindow[0] - firstCol); x < Math.min(tileWidth, tileWidth - (lastCol - imageWindow[2])); ++x) { var pixelOffset = (y * tileWidth + x) * bytesPerPixel; var value = sampleReaders[sampleIndex].call(dataView, pixelOffset + srcSampleOffsets[sampleIndex], littleEndian); var windowCoordinate; if (interleave) { if (predictor !== 1 && x > 0) { windowCoordinate = (y + firstLine - imageWindow[1]) * windowWidth * samples.length + (x + firstCol - imageWindow[0] - 1) * samples.length + sampleIndex; value += valueArrays[windowCoordinate]; } windowCoordinate = (y + firstLine - imageWindow[1]) * windowWidth * samples.length + (x + firstCol - imageWindow[0]) * samples.length + sampleIndex; valueArrays[windowCoordinate] = value; } else { if (predictor !== 1 && x > 0) { windowCoordinate = (y + firstLine - imageWindow[1]) * windowWidth + x - 1 + firstCol - imageWindow[0]; value += valueArrays[sampleIndex][windowCoordinate]; } windowCoordinate = (y + firstLine - imageWindow[1]) * windowWidth + x + firstCol - imageWindow[0]; valueArrays[sampleIndex][windowCoordinate] = value; } } } } else { globalError = error; } // check end condition and call callbacks unfinishedTiles -= 1; checkFinished(); } for (var yTile = minYTile; yTile <= maxYTile; ++yTile) { for (var xTile = minXTile; xTile <= maxXTile; ++xTile) { for (var sampleIndex = 0; sampleIndex < samples.length; ++sampleIndex) { var sample = samples[sampleIndex]; if (this.planarConfiguration === 2) { bytesPerPixel = this.getSampleByteSize(sample); } var _sampleIndex = sampleIndex; unfinishedTiles += 1; this.getTileOrStrip(xTile, yTile, sample, onTileGot); } } } allStacked = true; checkFinished(); }, _readRaster: function _readRaster(imageWindow, samples, valueArrays, interleave, callback, callbackError) { try { var tileWidth = this.getTileWidth(); var tileHeight = this.getTileHeight(); var minXTile = Math.floor(imageWindow[0] / tileWidth); var maxXTile = Math.ceil(imageWindow[2] / tileWidth); var minYTile = Math.floor(imageWindow[1] / tileHeight); var maxYTile = Math.ceil(imageWindow[3] / tileHeight); var numTilesPerRow = Math.ceil(this.getWidth() / tileWidth); var windowWidth = imageWindow[2] - imageWindow[0]; var windowHeight = imageWindow[3] - imageWindow[1]; var bytesPerPixel = this.getBytesPerPixel(); var imageWidth = this.getWidth(); var predictor = this.fileDirectory.Predictor || 1; var srcSampleOffsets = []; var sampleReaders = []; for (var i = 0; i < samples.length; ++i) { if (this.planarConfiguration === 1) { srcSampleOffsets.push(sum(this.fileDirectory.BitsPerSample, 0, samples[i]) / 8); } else { srcSampleOffsets.push(0); } sampleReaders.push(this.getReaderForSample(samples[i])); } for (var yTile = minYTile; yTile < maxYTile; ++yTile) { for (var xTile = minXTile; xTile < maxXTile; ++xTile) { var firstLine = yTile * tileHeight; var firstCol = xTile * tileWidth; var lastLine = (yTile + 1) * tileHeight; var lastCol = (xTile + 1) * tileWidth; for (var sampleIndex = 0; sampleIndex < samples.length; ++sampleIndex) { var sample = samples[sampleIndex]; if (this.planarConfiguration === 2) { bytesPerPixel = this.getSampleByteSize(sample); } var tile = new DataView(this.getTileOrStrip(xTile, yTile, sample)); var reader = sampleReaders[sampleIndex]; var ymax = Math.min(tileHeight, tileHeight - (lastLine - imageWindow[3])); var xmax = Math.min(tileWidth, tileWidth - (lastCol - imageWindow[2])); var totalbytes = (ymax * tileWidth + xmax) * bytesPerPixel; var tileLength = new Uint8Array(tile.buffer).length; if (2 * tileLength !== totalbytes && this._debugMessages) { console.warn('dimension mismatch', tileLength, totalbytes); } for (var y = Math.max(0, imageWindow[1] - firstLine); y < ymax; ++y) { for (var x = Math.max(0, imageWindow[0] - firstCol); x < xmax; ++x) { var pixelOffset = (y * tileWidth + x) * bytesPerPixel; var value = 0; if (pixelOffset < tileLength - 1) { value = reader.call(tile, pixelOffset + srcSampleOffsets[sampleIndex], this.littleEndian); } var windowCoordinate; if (interleave) { if (predictor !== 1 && x > 0) { windowCoordinate = (y + firstLine - imageWindow[1]) * windowWidth * samples.length + (x + firstCol - imageWindow[0] - 1) * samples.length + sampleIndex; value += valueArrays[windowCoordinate]; } windowCoordinate = (y + firstLine - imageWindow[1]) * windowWidth * samples.length + (x + firstCol - imageWindow[0]) * samples.length + sampleIndex; valueArrays[windowCoordinate] = value; } else { if (predictor !== 1 && x > 0) { windowCoordinate = (y + firstLine - imageWindow[1]) * windowWidth + x - 1 + firstCol - imageWindow[0]; value += valueArrays[sampleIndex][windowCoordinate]; } windowCoordinate = (y + firstLine - imageWindow[1]) * windowWidth + x + firstCol - imageWindow[0]; valueArrays[sampleIndex][windowCoordinate] = value; } } } } } } callback(valueArrays); return valueArrays; } catch (error) { return callbackError(error); } }, /** * This callback is called upon successful reading of a GeoTIFF image. The * resulting arrays are passed as a single argument. * @callback GeoTIFFImage~readCallback * @param {(TypedArray|TypedArray[])} array the requested data as a either a * single typed array or a list of * typed arrays, depending on the * 'interleave' option. */ /** * This callback is called upon encountering an error while reading of a * GeoTIFF image * @callback GeoTIFFImage~readErrorCallback * @param {Error} error the encountered error */ /** * Reads raster data from the image. This function reads all selected samples * into separate arrays of the correct type for that sample. When provided, * only a subset of the raster is read for each sample. * * @param {Object} [options] optional parameters * @param {Array} [options.window=whole image] the subset to read data from. * @param {Array} [options.samples=all samples] the selection of samples to read from. * @param {Boolean} [options.interleave=false] whether the data shall be read * in one single array or separate * arrays. * @param {GeoTIFFImage~readCallback} [callback] the success callback. this * parameter is mandatory for * asynchronous decoders (some * compression mechanisms). * @param {GeoTIFFImage~readErrorCallback} [callbackError] the error callback * @returns {(TypedArray|TypedArray[]|null)} in synchonous cases, the decoded * array(s) is/are returned. In * asynchronous cases, nothing is * returned. */ readRasters: function readRasters() /* arguments are read via the 'arguments' object */{ // parse the arguments var options, callback, callbackError; switch (arguments.length) { case 0: break; case 1: if (typeof arguments[0] === "function") { callback = arguments[0]; } else { options = arguments[0]; } break; case 2: if (typeof arguments[0] === "function") { callback = arguments[0]; callbackError = arguments[1]; } else { options = arguments[0]; callback = arguments[1]; } break; case 3: options = arguments[0]; callback = arguments[1]; callbackError = arguments[2]; break; default: throw new Error("Invalid number of arguments passed."); } // set up default arguments options = options || {}; callbackError = callbackError || function (error) { console.error(error); }; var imageWindow = options.window || [0, 0, this.getWidth(), this.getHeight()], samples = options.samples, interleave = options.interleave; // check parameters if (imageWindow[0] < 0 || imageWindow[1] < 0 || imageWindow[2] > this.getWidth() || imageWindow[3] > this.getHeight()) { throw new Error("Select window is out of image bounds."); } else if (imageWindow[0] > imageWindow[2] || imageWindow[1] > imageWindow[3]) { throw new Error("Invalid subsets"); } var imageWindowWidth = imageWindow[2] - imageWindow[0]; var imageWindowHeight = imageWindow[3] - imageWindow[1]; var numPixels = imageWindowWidth * imageWindowHeight; var i; if (!samples) { samples = []; for (i = 0; i < this.fileDirectory.SamplesPerPixel; ++i) { samples.push(i); } } else { for (i = 0; i < samples.length; ++i) { if (samples[i] >= this.fileDirectory.SamplesPerPixel) { throw new RangeError("Invalid sample index '" + samples[i] + "'."); } } } var valueArrays; if (interleave) { var format = this.fileDirectory.SampleFormat ? Math.max.apply(null, this.fileDirectory.SampleFormat) : 1, bitsPerSample = Math.max.apply(null, this.fileDirectory.BitsPerSample); valueArrays = arrayForType(format, bitsPerSample, numPixels * samples.length); } else { valueArrays = []; for (i = 0; i < samples.length; ++i) { valueArrays.push(this.getArrayForSample(samples[i], numPixels)); } } // start reading data, sync or async var decoder = this.getDecoder(); if (decoder.isAsync()) { if (!callback) { throw new Error("No callback specified for asynchronous raster reading."); } return this._readRasterAsync(imageWindow, samples, valueArrays, interleave, callback, callbackError); } else { callback = callback || function () {}; return this._readRaster(imageWindow, samples, valueArrays, interleave, callback, callbackError); } }, /** * Reads raster data from the image as RGB. The result is always an * interleaved typed array. * Colorspaces other than RGB will be transformed to RGB, color maps expanded. * When no other method is applicable, the first sample is used to produce a * greayscale image. * When provided, only a subset of the raster is read for each sample. * * @param {Object} [options] optional parameters * @param {Array} [options.window=whole image] the subset to read data from. * @param {GeoTIFFImage~readCallback} callback the success callback. this * parameter is mandatory. * @param {GeoTIFFImage~readErrorCallback} [callbackError] the error callback */ readRGB: function readRGB() { // parse the arguments var options = null, callback = null, callbackError = null; switch (arguments.length) { case 0: break; case 1: if (typeof arguments[0] === "function") { callback = arguments[0]; } else { options = arguments[0]; } break; case 2: if (typeof arguments[0] === "function") { callback = arguments[0]; callbackError = arguments[1]; } else { options = arguments[0]; callback = arguments[1]; } break; case 3: options = arguments[0]; callback = arguments[1]; callbackError = arguments[2]; break; default: throw new Error("Invalid number of arguments passed."); } // set up default arguments options = options || {}; callbackError = callbackError || function (error) { console.error(error); }; var imageWindow = options.window || [0, 0, this.getWidth(), this.getHeight()]; // check parameters if (imageWindow[0] < 0 || imageWindow[1] < 0 || imageWindow[2] > this.getWidth() || imageWindow[3] > this.getHeight()) { throw new Error("Select window is out of image bounds."); } else if (imageWindow[0] > imageWindow[2] || imageWindow[1] > imageWindow[3]) { throw new Error("Invalid subsets"); } var width = imageWindow[2] - imageWindow[0]; var height = imageWindow[3] - imageWindow[1]; var pi = this.fileDirectory.PhotometricInterpretation; var bits = this.fileDirectory.BitsPerSample[0]; var max = Math.pow(2, bits); if (pi === globals.photometricInterpretations.RGB) { return this.readRasters({ window: options.window, interleave: true }, callback, callbackError); } var samples; switch (pi) { case globals.photometricInterpretations.WhiteIsZero: case globals.photometricInterpretations.BlackIsZero: case globals.photometricInterpretations.Palette: samples = [0]; break; case globals.photometricInterpretations.CMYK: samples = [0, 1, 2, 3]; break; case globals.photometricInterpretations.YCbCr: case globals.photometricInterpretations.CIELab: samples = [0, 1, 2]; break; default: throw new Error("Invalid or unsupported photometric interpretation."); } var subOptions = { window: options.window, interleave: true, samples: samples }; var fileDirectory = this.fileDirectory; return this.readRasters(subOptions, function (raster) { switch (pi) { case globals.photometricInterpretations.WhiteIsZero: return callback(RGB.fromWhiteIsZero(raster, max, width, height)); case globals.photometricInterpretations.BlackIsZero: return callback(RGB.fromBlackIsZero(raster, max, width, height)); case globals.photometricInterpretations.Palette: return callback(RGB.fromPalette(raster, fileDirectory.ColorMap, width, height)); case globals.photometricInterpretations.CMYK: return callback(RGB.fromCMYK(raster, width, height)); case globals.photometricInterpretations.YCbCr: return callback(RGB.fromYCbCr(raster, width, height)); case globals.photometricInterpretations.CIELab: return callback(RGB.fromCIELab(raster, width, height)); } }, callbackError); }, /** * Returns an array of tiepoints. * @returns {Object[]} */ getTiePoints: function getTiePoints() { if (!this.fileDirectory.ModelTiepoint) { return []; } var tiePoints = []; for (var i = 0; i < this.fileDirectory.ModelTiepoint.length; i += 6) { tiePoints.push({ i: this.fileDirectory.ModelTiepoint[i], j: this.fileDirectory.ModelTiepoint[i + 1], k: this.fileDirectory.ModelTiepoint[i + 2], x: this.fileDirectory.ModelTiepoint[i + 3], y: this.fileDirectory.ModelTiepoint[i + 4], z: this.fileDirectory.ModelTiepoint[i + 5] }); } return tiePoints; }, /** * Returns the parsed GDAL metadata items. * @returns {Object} */ getGDALMetadata: function getGDALMetadata() { var metadata = {}; if (!this.fileDirectory.GDAL_METADATA) { return null; } var string = this.fileDirectory.GDAL_METADATA; var xmlDom = globals.parseXml(string.substring(0, string.length - 1)); var result = xmlDom.evaluate("GDALMetadata/Item", xmlDom, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < result.snapshotLength; ++i) { var node = result.snapshotItem(i); metadata[node.getAttribute("name")] = node.textContent; } return metadata; } }; module.exports = GeoTIFFImage; },{"./compression/deflate.js":2,"./compression/lzw.js":3,"./compression/packbits.js":4,"./compression/raw.js":5,"./globals.js":9,"./rgb.js":11}],9:[function(require,module,exports){ "use strict"; var fieldTagNames = { // TIFF Baseline 0x013B: 'Artist', 0x0102: 'BitsPerSample', 0x0109: 'CellLength', 0x0108: 'CellWidth', 0x0140: 'ColorMap', 0x0103: 'Compression', 0x8298: 'Copyright', 0x0132: 'DateTime', 0x0152: 'ExtraSamples', 0x010A: 'FillOrder', 0x0121: 'FreeByteCounts', 0x0120: 'FreeOffsets', 0x0123: 'GrayResponseCurve', 0x0122: 'GrayResponseUnit', 0x013C: 'HostComputer', 0x010E: 'ImageDescription', 0x0101: 'ImageLength', 0x0100: 'ImageWidth', 0x010F: 'Make', 0x0119: 'MaxSampleValue', 0x0118: 'MinSampleValue', 0x0110: 'Model', 0x00FE: 'NewSubfileType', 0x0112: 'Orientation', 0x0106: 'PhotometricInterpretation', 0x011C: 'PlanarConfiguration', 0x0128: 'ResolutionUnit', 0x0116: 'RowsPerStrip', 0x0115: 'SamplesPerPixel', 0x0131: 'Software', 0x0117: 'StripByteCounts', 0x0111: 'StripOffsets', 0x00FF: 'SubfileType', 0x0107: 'Threshholding', 0x011A: 'XResolution', 0x011B: 'YResolution', // TIFF Extended 0x0146: 'BadFaxLines', 0x0147: 'CleanFaxData', 0x0157: 'ClipPath', 0x0148: 'ConsecutiveBadFaxLines', 0x01B1: 'Decode', 0x01B2: 'DefaultImageColor', 0x010D: 'DocumentName', 0x0150: 'DotRange', 0x0141: 'HalftoneHints', 0x015A: 'Indexed', 0x015B: 'JPEGTables', 0x011D: 'PageName', 0x0129: 'PageNumber', 0x013D: 'Predictor', 0x013F: 'PrimaryChromaticities', 0x0214: 'ReferenceBlackWhite', 0x0153: 'SampleFormat', 0x0154: 'SMinSampleValue', 0x0155: 'SMaxSampleValue', 0x022F: 'StripRowCounts', 0x014A: 'SubIFDs', 0x0124: 'T4Options', 0x0125: 'T6Options', 0x0145: 'TileByteCounts', 0x0143: 'TileLength', 0x0144: 'TileOffsets', 0x0142: 'TileWidth', 0x012D: 'TransferFunction', 0x013E: 'WhitePoint', 0x0158: 'XClipPathUnits', 0x011E: 'XPosition', 0x0211: 'YCbCrCoefficients', 0x0213: 'YCbCrPositioning', 0x0212: 'YCbCrSubSampling', 0x0159: 'YClipPathUnits', 0x011F: 'YPosition', // EXIF 0x9202: 'ApertureValue', 0xA001: 'ColorSpace', 0x9004: 'DateTimeDigitized', 0x9003: 'DateTimeOriginal', 0x8769: 'Exif IFD', 0x9000: 'ExifVersion', 0x829A: 'ExposureTime', 0xA300: 'FileSource', 0x9209: 'Flash', 0xA000: 'FlashpixVersion', 0x829D: 'FNumber', 0xA420: 'ImageUniqueID', 0x9208: 'LightSource', 0x927C: 'MakerNote', 0x9201: 'ShutterSpeedValue', 0x9286: 'UserComment', // IPTC 0x83BB: 'IPTC', // ICC 0x8773: 'ICC Profile', // XMP 0x02BC: 'XMP', // GDAL 0xA480: 'GDAL_METADATA', 0xA481: 'GDAL_NODATA', // Photoshop 0x8649: 'Photoshop', // GeoTiff 0x830E: 'ModelPixelScale', 0x8482: 'ModelTiepoint', 0x85D8: 'ModelTransformation', 0x87AF: 'GeoKeyDirectory', 0x87B0: 'GeoDoubleParams', 0x87B1: 'GeoAsciiParams' }; var key; var fieldTags = {}; for (key in fieldTagNames) { fieldTags[fieldTagNames[key]] = parseInt(key); } var arrayFields = [fieldTags.BitsPerSample, fieldTags.ExtraSamples, fieldTags.SampleFormat, fieldTags.StripByteCounts, fieldTags.StripOffsets, fieldTags.StripRowCounts, fieldTags.TileByteCounts, fieldTags.TileOffsets]; var fieldTypeNames = { 0x0001: 'BYTE', 0x0002: 'ASCII', 0x0003: 'SHORT', 0x0004: 'LONG', 0x0005: 'RATIONAL', 0x0006: 'SBYTE', 0x0007: 'UNDEFINED', 0x0008: 'SSHORT', 0x0009: 'SLONG', 0x000A: 'SRATIONAL', 0x000B: 'FLOAT', 0x000C: 'DOUBLE', // introduced by BigTIFF 0x0010: 'LONG8', 0x0011: 'SLONG8', 0x0012: 'IFD8' }; var fieldTypes = {}; for (key in fieldTypeNames) { fieldTypes[fieldTypeNames[key]] = parseInt(key); } var photometricInterpretations = { WhiteIsZero: 0, BlackIsZero: 1, RGB: 2, Palette: 3, TransparencyMask: 4, CMYK: 5, YCbCr: 6, CIELab: 8, ICCLab: 9 }; var geoKeyNames = { 1024: 'GTModelTypeGeoKey', 1025: 'GTRasterTypeGeoKey', 1026: 'GTCitationGeoKey', 2048: 'GeographicTypeGeoKey', 2049: 'GeogCitationGeoKey', 2050: 'GeogGeodeticDatumGeoKey', 2051: 'GeogPrimeMeridianGeoKey', 2052: 'GeogLinearUnitsGeoKey', 2053: 'GeogLinearUnitSizeGeoKey', 2054: 'GeogAngularUnitsGeoKey', 2055: 'GeogAngularUnitSizeGeoKey', 2056: 'GeogEllipsoidGeoKey', 2057: 'GeogSemiMajorAxisGeoKey', 2058: 'GeogSemiMinorAxisGeoKey', 2059: 'GeogInvFlatteningGeoKey', 2060: 'GeogAzimuthUnitsGeoKey', 2061: 'GeogPrimeMeridianLongGeoKey', 2062: 'GeogTOWGS84GeoKey', 3072: 'ProjectedCSTypeGeoKey', 3073: 'PCSCitationGeoKey', 3074: 'ProjectionGeoKey', 3075: 'ProjCoordTransGeoKey', 3076: 'ProjLinearUnitsGeoKey', 3077: 'ProjLinearUnitSizeGeoKey', 3078: 'ProjStdParallel1GeoKey', 3079: 'ProjStdParallel2GeoKey', 3080: 'ProjNatOriginLongGeoKey', 3081: 'ProjNatOriginLatGeoKey', 3082: 'ProjFalseEastingGeoKey', 3083: 'ProjFalseNorthingGeoKey', 3084: 'ProjFalseOriginLongGeoKey', 3085: 'ProjFalseOriginLatGeoKey', 3086: 'ProjFalseOriginEastingGeoKey', 3087: 'ProjFalseOriginNorthingGeoKey', 3088: 'ProjCenterLongGeoKey', 3089: 'ProjCenterLatGeoKey', 3090: 'ProjCenterEastingGeoKey', 3091: 'ProjCenterNorthingGeoKey', 3092: 'ProjScaleAtNatOriginGeoKey', 3093: 'ProjScaleAtCenterGeoKey', 3094: 'ProjAzimuthAngleGeoKey', 3095: 'ProjStraightVertPoleLongGeoKey', 3096: 'ProjRectifiedGridAngleGeoKey', 4096: 'VerticalCSTypeGeoKey', 4097: 'VerticalCitationGeoKey', 4098: 'VerticalDatumGeoKey', 4099: 'VerticalUnitsGeoKey' }; var geoKeys = {}; for (key in geoKeyNames) { geoKeys[geoKeyNames[key]] = parseInt(key); } var parseXml; // node.js version if (typeof window === "undefined") { parseXml = function parseXml(xmlStr) { // requires xmldom module var DOMParser = require('xmldom').DOMParser; return new DOMParser().parseFromString(xmlStr, "text/xml"); }; } else if (typeof window.DOMParser !== "undefined") { parseXml = function parseXml(xmlStr) { return new window.DOMParser().parseFromString(xmlStr, "text/xml"); }; } else if (typeof window.ActiveXObject !== "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) { parseXml = function parseXml(xmlStr) { var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = "false"; xmlDoc.loadXML(xmlStr); return xmlDoc; }; } module.exports = { fieldTags: fieldTags, fieldTagNames: fieldTagNames, arrayFields: arrayFields, fieldTypes: fieldTypes, fieldTypeNames: fieldTypeNames, photometricInterpretations: photometricInterpretations, geoKeys: geoKeys, geoKeyNames: geoKeyNames, parseXml: parseXml }; },{"xmldom":"xmldom"}],10:[function(require,module,exports){ "use strict"; var GeoTIFF = require("./geotiff.js"); /** * Main parsing function for GeoTIFF files. * @param {(string|ArrayBuffer)} data Raw data to parse the GeoTIFF from. * @param {Object} [options] further options. * @param {Boolean} [options.cache=false] whether or not decoded tiles shall be cached. * @returns {GeoTIFF} the parsed geotiff file. */ var parse = function parse(data, options) { var rawData, i, strLen, view; if (typeof data === "string" || data instanceof String) { rawData = new ArrayBuffer(data.length * 2); // 2 bytes for each char view = new Uint16Array(rawData); for (i = 0, strLen = data.length; i < strLen; ++i) { view[i] = data.charCodeAt(i); } } else if (data instanceof ArrayBuffer) { rawData = data; } else { throw new Error("Invalid input data given."); } return new GeoTIFF(rawData, options); }; if (typeof module !== "undefined" && typeof module.exports !== "undefined") { module.exports.parse = parse; } if (typeof window !== "undefined") { window["GeoTIFF"] = { parse: parse }; } },{"./geotiff.js":7}],11:[function(require,module,exports){ "use strict"; function fromWhiteIsZero(raster, max, width, height) { var rgbRaster = new Uint8Array(width * height * 3); var value; for (var i = 0, j = 0; i < raster.length; ++i, j += 3) { value = 256 - raster[i] / max * 256; rgbRaster[j] = value; rgbRaster[j + 1] = value; rgbRaster[j + 2] = value; } return rgbRaster; } function fromBlackIsZero(raster, max, width, height) { var rgbRaster = new Uint8Array(width * height * 3); var value; for (var i = 0, j = 0; i < raster.length; ++i, j += 3) { value = raster[i] / max * 256; rgbRaster[j] = value; rgbRaster[j + 1] = value; rgbRaster[j + 2] = value; } return rgbRaster; } function fromPalette(raster, colorMap, width, height) { var rgbRaster = new Uint8Array(width * height * 3); var greenOffset = colorMap.length / 3; var blueOffset = colorMap.length / 3 * 2; for (var i = 0, j = 0; i < raster.length; ++i, j += 3) { var mapIndex = raster[i]; rgbRaster[j] = colorMap[mapIndex] / 65536 * 256; rgbRaster[j + 1] = colorMap[mapIndex + greenOffset] / 65536 * 256; rgbRaster[j + 2] = colorMap[mapIndex + blueOffset] / 65536 * 256; } return rgbRaster; } function fromCMYK(cmykRaster, width, height) { var rgbRaster = new Uint8Array(width * height * 3); var c, m, y, k; for (var i = 0, j = 0; i < cmykRaster.length; i += 4, j += 3) { c = cmykRaster[i]; m = cmykRaster[i + 1]; y = cmykRaster[i + 2]; k = cmykRaster[i + 3]; rgbRaster[j] = 255 * ((255 - c) / 256) * ((255 - k) / 256); rgbRaster[j + 1] = 255 * ((255 - m) / 256) * ((255 - k) / 256); rgbRaster[j + 2] = 255 * ((255 - y) / 256) * ((255 - k) / 256); } return rgbRaster; } function fromYCbCr(yCbCrRaster, width, height) { var rgbRaster = new Uint8Array(width * height * 3); var y, cb, cr; for (var i = 0, j = 0; i < yCbCrRaster.length; i += 3, j += 3) { y = yCbCrRaster[i]; cb = yCbCrRaster[i + 1]; cr = yCbCrRaster[i + 2]; rgbRaster[j] = y + 1.40200 * (cr - 0x80); rgbRaster[j + 1] = y - 0.34414 * (cb - 0x80) - 0.71414 * (cr - 0x80); rgbRaster[j + 2] = y + 1.77200 * (cb - 0x80); } return rgbRaster; } // converted from here: // http://de.mathworks.com/matlabcentral/fileexchange/24010-lab2rgb/content/Lab2RGB.m // still buggy function fromCIELab(cieLabRaster, width, height) { var T1 = 0.008856; var T2 = 0.206893; var MAT = [3.240479, -1.537150, -0.498535, -0.969256, 1.875992, 0.041556, 0.055648, -0.204043, 1.057311]; var rgbRaster = new Uint8Array(width * height * 3); var L, a, b; var fX, fY, fZ, XT, YT, ZT, X, Y, Z; for (var i = 0, j = 0; i < cieLabRaster.length; i += 3, j += 3) { L = cieLabRaster[i]; a = cieLabRaster[i + 1]; b = cieLabRaster[i + 2]; // Compute Y fY = Math.pow((L + 16) / 116, 3); YT = fY > T1; fY = (YT !== 0) * (L / 903.3) + YT * fY; Y = fY; fY = YT * Math.pow(fY, 1 / 3) + (YT !== 0) * (7.787 * fY + 16 / 116); // Compute X fX = a / 500 + fY; XT = fX > T2; X = XT * Math.pow(fX, 3) + (XT !== 0) * ((fX - 16 / 116) / 7.787); // Compute Z fZ = fY - b / 200; ZT = fZ > T2; Z = ZT * Math.pow(fZ, 3) + (ZT !== 0) * ((fZ - 16 / 116) / 7.787); // Normalize for D65 white point X = X * 0.950456; Z = Z * 1.088754; rgbRaster[j] = X * MAT[0] + Y * MAT[1] + Z * MAT[2]; rgbRaster[j + 1] = X * MAT[3] + Y * MAT[4] + Z * MAT[5]; rgbRaster[j + 2] = X * MAT[6] + Y * MAT[7] + Z * MAT[8]; } return rgbRaster; } module.exports = { fromWhiteIsZero: fromWhiteIsZero, fromBlackIsZero: fromBlackIsZero, fromPalette: fromPalette, fromCMYK: fromCMYK, fromYCbCr: fromYCbCr, fromCIELab: fromCIELab }; },{}]},{},[10]);