diff --git a/img/female.tiff b/img/female.tiff new file mode 100644 index 0000000..fff7c6b Binary files /dev/null and b/img/female.tiff differ diff --git a/img/jellybeans.tiff b/img/jellybeans.tiff new file mode 100644 index 0000000..08def93 Binary files /dev/null and b/img/jellybeans.tiff differ diff --git a/src/__tests__/decode.test.ts b/src/__tests__/decode.test.ts index e8f87e1..849d73a 100644 --- a/src/__tests__/decode.test.ts +++ b/src/__tests__/decode.test.ts @@ -207,6 +207,22 @@ const files: TiffFile[] = [ components: 1, alpha: false, }, + { + name: 'jellybeans.tiff', + width: 256, + height: 256, + bitsPerSample: 8, + components: 3, + alpha: false, + }, + { + name: 'female.tiff', + width: 256, + height: 256, + bitsPerSample: 8, + components: 3, + alpha: false, + }, // Checks only the first frame of the image. { name: 'dog.tiff', @@ -385,7 +401,7 @@ test('should decode image compressed with deflate algorithm', () => { }); }); -test('should decode basic 2x2 1-bit image ', () => { +test('should decode basic 2x2 1-bit image', () => { const decoded = decode(readImage('bw1bit.tif')); expect(decoded).toHaveLength(1); @@ -500,3 +516,19 @@ test('should decode multiframe image', () => { expect(decoded[1].samplesPerPixel).toBe(2); expect(decoded[1].data.slice(352, 384)).toStrictEqual(secondFrameTwelvethRow); }); + +test('should decode image with undefined rowsPerStrip', () => { + const decodedFemale = decode(readImage('female.tiff')); + + expect(decodedFemale[0].rowsPerStrip).toStrictEqual(2 ** 32 - 1); + expect(decodedFemale[0].data.slice(0, 10)).toStrictEqual( + new Uint8Array([94, 0, 115, 27, 61, 103, 26, 60, 104, 27]), + ); + + const decodedJellybeans = decode(readImage('jellybeans.tiff')); + + expect(decodedJellybeans[0].rowsPerStrip).toStrictEqual(2 ** 32 - 1); + expect(decodedJellybeans[0].data.slice(0, 10)).toStrictEqual( + new Uint8Array([139, 132, 90, 141, 136, 92, 142, 131, 89, 143]), + ); +}); diff --git a/src/tiff_decoder.ts b/src/tiff_decoder.ts index 970b46c..4d546f4 100644 --- a/src/tiff_decoder.ts +++ b/src/tiff_decoder.ts @@ -293,6 +293,7 @@ export default class TIFFDecoder extends IOBuffer { ifd.bitsPerSample !== 1 ? width * ifd.samplesPerPixel * height : Math.ceil((width * ifd.samplesPerPixel) / 8) * height; + // Compressed Strip Layout const stripOffsets = ifd.stripOffsets; const stripByteCounts = ifd.stripByteCounts || guessStripByteCounts(ifd); @@ -302,6 +303,7 @@ export default class TIFFDecoder extends IOBuffer { ifd.bitsPerSample !== 1 ? width * ifd.samplesPerPixel * ifd.rowsPerStrip : Math.ceil((width * ifd.samplesPerPixel) / 8) * ifd.rowsPerStrip; + const readSamples = this.createSampleReader( ifd.sampleFormat, ifd.bitsPerSample, diff --git a/src/tiff_ifd.ts b/src/tiff_ifd.ts index 4785f36..561957e 100644 --- a/src/tiff_ifd.ts +++ b/src/tiff_ifd.ts @@ -91,7 +91,7 @@ export default class TiffIfd extends Ifd { return this.get('SamplesPerPixel') || 1; } public get rowsPerStrip(): number { - return this.get('RowsPerStrip'); + return this.get('RowsPerStrip') || 2 ** 32 - 1; } public get stripByteCounts(): number[] { return alwaysArray(this.get('StripByteCounts'));