Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Optimize single-tile reads #348

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions src/geotiffimage.js
Original file line number Diff line number Diff line change
@@ -346,10 +346,50 @@ class GeoTIFFImage {
return this.fileDirectory.BitsPerSample[sampleIndex];
}

getArrayForSample(sampleIndex, size) {
getArrayForSample(sampleIndex, sizeOrBuffer) {
const format = this.getSampleFormat(sampleIndex);
const bitsPerSample = this.getBitsPerSample(sampleIndex);
return arrayForType(format, bitsPerSample, size);
return arrayForType(format, bitsPerSample, sizeOrBuffer);
}

/**
* Check for possible bulk-read optimization
* @private
* @param {Array} imageWindow The image window in pixel coordinates
* @param {TypedArray|TypedArray[]} valueArrays The array(s) to write into
* @param {Boolean} interleave Whether or not to write in an interleaved manner
* @param {number} width the width of window to be read into
* @param {number} height the height of window to be read into
* @returns {Promise<boolean>}
*/
_bulkReadable(imageWindow, valueArrays, interleave, width, height) {
const imageWidth = this.getWidth();
const imageHeight = this.getHeight();
const tileWidth = this.getTileWidth();
const tileHeight = this.getTileHeight();
// The requested tile aligns with stored IFD
const aligned = 0 === Math.max.apply(null, [
imageWindow[0] % tileWidth,
imageWindow[1] % tileHeight,
Math.min(imageWindow[2], imageWidth) % tileWidth,
Math.min(imageWindow[3], imageHeight) % tileHeight
]);
const osLittleEndian = () => {
const buffer = new ArrayBuffer(2);
const uint8 = new Uint8Array(buffer);
const uint16 = new Uint16Array(buffer);
uint8[0] = 0x00;
uint8[1] = 0xFF;
return (uint16[0] === 0xFF00);
}
const oneValue = valueArrays.length === 1;
const serialPixel = this.planarConfiguration === 1;
const sameEndian = this.littleEndian === osLittleEndian();
// The requested tile exactly matches the stored IFD
if (aligned && oneValue && serialPixel && sameEndian) {
return width === tileWidth && height === tileHeight;
}
return false;
}

/**
@@ -607,6 +647,17 @@ class GeoTIFFImage {
}

const poolOrDecoder = pool || await getDecoder(this.fileDirectory);
if (this._bulkReadable(imageWindow, valueArrays, interleave, width, height)) {
const tileWidth = this.getTileWidth();
const tileHeight = this.getTileHeight();
const xTile = Math.max(Math.floor(imageWindow[0] / tileWidth), 0);
const yTile = Math.max(Math.floor(imageWindow[1] / tileHeight), 0);
const tile = await this.getTileOrStrip(xTile, yTile, samples[0], poolOrDecoder, signal);
valueArrays[0] = this.getArrayForSample(samples[0], tile.data);
valueArrays.height = tileHeight;
valueArrays.width = tileWidth;
return valueArrays;
}

const result = await this._readRaster(
imageWindow, samples, valueArrays, interleave, poolOrDecoder, width, height, resampleMethod, signal,