Skip to content

Commit

Permalink
feat: add pages option (#47)
Browse files Browse the repository at this point in the history
* refactor: remove I for interface and export TiffIfd

Closes: #37

BREAKING CHANGE: removed `firstImage` option, use `pages` option instead.

Closes: #46
  • Loading branch information
opatiny committed Dec 22, 2023
1 parent 1e543c8 commit f0f0bac
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 18 deletions.
25 changes: 23 additions & 2 deletions src/__tests__/decode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ test('should decode RGB 8bit data with pre-multiplied alpha and lost precision',
});

test('should decode with onlyFirst', () => {
const result = decode(readImage('grey8.tif'), { onlyFirst: true });
const result = decode(readImage('grey8.tif'), { pages: [0] });
expect(result[0]).toHaveProperty('data');
});

Expand All @@ -236,7 +236,7 @@ test('should omit data', () => {

test('should read exif data', () => {
const result = decode(readImage('grey8.tif'), {
onlyFirst: true,
pages: [0],
ignoreImageData: true,
});
// @ts-ignore
Expand All @@ -256,6 +256,27 @@ test('should decode stacks', () => {
}
});

test('specify pages to decode', () => {
const decoded = decode(stack, { pages: [0, 2, 4, 6, 8] });
expect(decoded).toHaveLength(5);
for (const image of decoded) {
expect(image.width).toBe(128);
expect(image.height).toBe(128);
}
});

test('should throw if pages invalid', () => {
expect(() => decode(stack, { pages: [-1] })).toThrow(
'Index -1 is invalid. Must be a positive integer.',
);
expect(() => decode(stack, { pages: [0.5] })).toThrow(
'Index 0.5 is invalid. Must be a positive integer.',
);
expect(() => decode(stack, { pages: [20] })).toThrow(
'Index 20 is out of bounds. The stack only contains 10 images.',
);
});

test('should decode palette', () => {
const decoded = decode(readImage('palette.tif'));
expect(decoded).toHaveLength(1);
Expand Down
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import TIFFDecoder from './tiffDecoder';
import TiffIfd from './tiffIfd';
import { BufferType, IDecodeOptions } from './types';
import { BufferType, DecodeOptions } from './types';

function decodeTIFF(data: BufferType, options?: IDecodeOptions): TiffIfd[] {
function decodeTIFF(data: BufferType, options?: DecodeOptions): TiffIfd[] {
const decoder = new TIFFDecoder(data);
return decoder.decode(options);
}
Expand All @@ -17,4 +17,4 @@ function pageCount(data: BufferType): number {
return decoder.pageCount;
}

export { decodeTIFF as decode, isMultiPage, pageCount, IDecodeOptions };
export { decodeTIFF as decode, isMultiPage, pageCount, DecodeOptions, TiffIfd };
52 changes: 41 additions & 11 deletions src/tiffDecoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ import IFD from './ifd';
import { getByteLength, readData } from './ifdValue';
import { decompressLzw } from './lzw';
import TiffIfd from './tiffIfd';
import { BufferType, IDecodeOptions, IFDKind, DataArray } from './types';
import { BufferType, DecodeOptions, IFDKind, DataArray } from './types';
import { decompressZlib } from './zlib';

const defaultOptions: IDecodeOptions = {
const defaultOptions: DecodeOptions = {
ignoreImageData: false,
onlyFirst: false,
};

interface IInternalOptions extends IDecodeOptions {
interface InternalOptions extends DecodeOptions {
kind?: IFDKind;
}

Expand Down Expand Up @@ -58,15 +57,35 @@ export default class TIFFDecoder extends IOBuffer {
throw unsupported('ifdCount', c);
}

public decode(options: IDecodeOptions = {}): TiffIfd[] {
public decode(options: DecodeOptions = {}): TiffIfd[] {
const { pages } = options;
checkPages(pages);

const maxIndex = pages ? Math.max(...pages) : Infinity;

options = Object.assign({}, defaultOptions, options);
const result = [];
this.decodeHeader();
let index = 0;
while (this._nextIFD) {
result.push(this.decodeIFD(options, true));
if (options.onlyFirst) {
return [result[0]];
if (pages) {
if (pages.includes(index)) {
result.push(this.decodeIFD(options, true));
} else {
this.decodeIFD({ ignoreImageData: true }, true);
}
if (index === maxIndex) {
break;
}
} else {
result.push(this.decodeIFD(options, true));
}
index++;
}
if (index < maxIndex && maxIndex !== Infinity) {
throw new RangeError(
`Index ${maxIndex} is out of bounds. The stack only contains ${index} images.`,
);
}
return result;
}
Expand All @@ -91,9 +110,9 @@ export default class TIFFDecoder extends IOBuffer {
this._nextIFD = this.readUint32();
}

private decodeIFD(options: IInternalOptions, tiff: true): TiffIfd;
private decodeIFD(options: IInternalOptions, tiff: false): IFD;
private decodeIFD(options: IInternalOptions, tiff: boolean): TiffIfd | IFD {
private decodeIFD(options: InternalOptions, tiff: true): TiffIfd;
private decodeIFD(options: InternalOptions, tiff: false): IFD;
private decodeIFD(options: InternalOptions, tiff: boolean): TiffIfd | IFD {
this.seek(this._nextIFD);

let ifd: TiffIfd | IFD;
Expand Down Expand Up @@ -380,3 +399,14 @@ function fillFloat32(
function unsupported(type: string, value: any): Error {

Check warning on line 399 in src/tiffDecoder.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
return new Error(`Unsupported ${type}: ${value}`);
}
function checkPages(pages: number[] | undefined) {
if (pages) {
for (let page of pages) {
if (page < 0 || Number.isInteger(page) === false) {
throw new RangeError(
`Index ${page} is invalid. Must be a positive integer.`,
);
}
}
}
}
7 changes: 5 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { IOBuffer } from 'iobuffer';

export type BufferType = ArrayBufferLike | ArrayBufferView | IOBuffer | Buffer;

export interface IDecodeOptions {
export interface DecodeOptions {
ignoreImageData?: boolean;
onlyFirst?: boolean;
/**
* Specify the indices of the pages to decode in case of a multi-page TIFF.
*/
pages?: number[];
}

export type IFDKind = 'standard' | 'exif' | 'gps';
Expand Down

0 comments on commit f0f0bac

Please sign in to comment.