diff --git a/docs/src/content/docs/api-constructor.md b/docs/src/content/docs/api-constructor.md index b5b7a9c8..7c7e8e9c 100644 --- a/docs/src/content/docs/api-constructor.md +++ b/docs/src/content/docs/api-constructor.md @@ -44,10 +44,6 @@ where the overall height is the `pageHeight` multiplied by the number of `pages` | [options.ignoreIcc] | number | false | should the embedded ICC profile, if any, be ignored. | | [options.pages] | number | 1 | Number of pages to extract for multi-page input (GIF, WebP, TIFF), use -1 for all pages. | | [options.page] | number | 0 | Page number to start extracting from for multi-page input (GIF, WebP, TIFF), zero based. | -| [options.subifd] | number | -1 | subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. | -| [options.level] | number | 0 | level to extract from a multi-level input (OpenSlide), zero based. | -| [options.pdfBackground] | string \| Object | | Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. | -| [options.jp2Oneshot] | boolean | false | Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. | | [options.animated] | boolean | false | Set to `true` to read all frames/pages of an animated image (GIF, WebP, TIFF), equivalent of setting `pages` to `-1`. | | [options.raw] | Object | | describes raw pixel input image data. See `raw()` for pixel ordering. | | [options.raw.width] | number | | integral number of pixels wide. | @@ -82,6 +78,14 @@ where the overall height is the `pageHeight` multiplied by the number of `pages` | [options.join.background] | string \| Object | | parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. | | [options.join.halign] | string | "'left'" | horizontal alignment style for images joined horizontally (`'left'`, `'centre'`, `'center'`, `'right'`). | | [options.join.valign] | string | "'top'" | vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`). | +| [options.tiff] | Object | | Describes TIFF specific options. | +| [options.tiff.subifd] | number | -1 | Sub Image File Directory to extract for OME-TIFF, defaults to main image. | +| [options.pdf] | Object | | Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. | +| [options.pdf.background] | string \| Object | | Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. | +| [options.openSlide] | Object | | Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide. | +| [options.openSlide.level] | number | 0 | Level to extract from a multi-level input, zero based. | +| [options.jp2] | Object | | Describes JPEG 2000 specific options. Requires the use of a globally-installed libvips compiled with support for OpenJPEG. | +| [options.jp2.oneshot] | boolean | false | Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. | **Example** ```js diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index b3c068b7..125f774f 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -12,6 +12,8 @@ Requires libvips v8.17.0 * Add "Magic Kernel Sharp" (no relation) to resizing kernels. +* Deprecate top-level, format-specific constructor parameters, e.g. `subifd` becomes `tiff.subifd`. + * Expose `keepDuplicateFrames` GIF output parameter. * Expose JPEG 2000 `oneshot` decoder option. diff --git a/lib/constructor.js b/lib/constructor.js index 2cf4c3b3..5d86c422 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -153,10 +153,6 @@ const debuglog = util.debuglog('sharp'); * @param {number} [options.ignoreIcc=false] - should the embedded ICC profile, if any, be ignored. * @param {number} [options.pages=1] - Number of pages to extract for multi-page input (GIF, WebP, TIFF), use -1 for all pages. * @param {number} [options.page=0] - Page number to start extracting from for multi-page input (GIF, WebP, TIFF), zero based. - * @param {number} [options.subifd=-1] - subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. - * @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based. - * @param {string|Object} [options.pdfBackground] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. - * @param {boolean} [options.jp2Oneshot=false] - Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. * @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (GIF, WebP, TIFF), equivalent of setting `pages` to `-1`. * @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering. * @param {number} [options.raw.width] - integral number of pixels wide. @@ -192,7 +188,14 @@ const debuglog = util.debuglog('sharp'); * @param {string|Object} [options.join.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. * @param {string} [options.join.halign='left'] - horizontal alignment style for images joined horizontally (`'left'`, `'centre'`, `'center'`, `'right'`). * @param {string} [options.join.valign='top'] - vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`). - * + * @param {Object} [options.tiff] - Describes TIFF specific options. + * @param {number} [options.tiff.subifd=-1] - Sub Image File Directory to extract for OME-TIFF, defaults to main image. + * @param {Object} [options.pdf] - Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. + * @param {string|Object} [options.pdf.background] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. + * @param {Object} [options.openSlide] - Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide. + * @param {number} [options.openSlide.level=0] - Level to extract from a multi-level input, zero based. + * @param {Object} [options.jp2] - Describes JPEG 2000 specific options. Requires the use of a globally-installed libvips compiled with support for OpenJPEG. + * @param {boolean} [options.jp2.oneshot=false] - Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. * @returns {Sharp} * @throws {Error} Invalid parameters */ diff --git a/lib/index.d.ts b/lib/index.d.ts index 2a355426..1ac6fc24 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1003,14 +1003,20 @@ declare namespace sharp { pages?: number | undefined; /** Page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default 0) */ page?: number | undefined; - /** subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. (optional, default -1) */ + /** TIFF specific input options */ + tiff?: TiffInputOptions | undefined; + /** PDF specific input options */ + pdf?: PdfInputOptions | undefined; + /** OpenSlide specific input options */ + openSlide?: OpenSlideInputOptions | undefined; + /** JPEG 2000 specific input options */ + jp2?: Jp2InputOptions | undefined; + /** Deprecated: use tiff.subifd instead */ subifd?: number | undefined; - /** Level to extract from a multi-level input (OpenSlide), zero based. (optional, default 0) */ - level?: number | undefined; - /** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */ + /** Deprecated: use pdf.background instead */ pdfBackground?: Colour | Color | undefined; - /** Set to `true` to load JPEG 2000 images using [oneshot mode](https://github.com/libvips/libvips/issues/4205) */ - jp2Oneshot?: boolean | undefined; + /** Deprecated: use openSlide.level instead */ + level?: number | undefined; /** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default false) */ animated?: boolean | undefined; /** Describes raw pixel input image data. See raw() for pixel ordering. */ @@ -1116,6 +1122,26 @@ declare namespace sharp { valign?: VerticalAlignment | undefined; } + interface TiffInputOptions { + /** Sub Image File Directory to extract, defaults to main image. Use -1 for all subifds. */ + subifd?: number | undefined; + } + + interface PdfInputOptions { + /** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */ + background?: Colour | Color | undefined; + } + + interface OpenSlideInputOptions { + /** Level to extract from a multi-level input, zero based. (optional, default 0) */ + level?: number | undefined; + } + + interface Jp2InputOptions { + /** Set to `true` to load JPEG 2000 images using [oneshot mode](https://github.com/libvips/libvips/issues/4205) */ + oneshot?: boolean | undefined; + } + interface ExifDir { [k: string]: string; } diff --git a/lib/input.js b/lib/input.js index 59de9a6c..d1571555 100644 --- a/lib/input.js +++ b/lib/input.js @@ -230,32 +230,49 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { throw is.invalidParameterError('page', 'integer between 0 and 100000', inputOptions.page); } } - // Multi-level input (OpenSlide) - if (is.defined(inputOptions.level)) { + // OpenSlide specific options + if (is.object(inputOptions.openSlide) && is.defined(inputOptions.openSlide.level)) { + if (is.integer(inputOptions.openSlide.level) && is.inRange(inputOptions.openSlide.level, 0, 256)) { + inputDescriptor.level = inputOptions.openSlide.level; + } else { + throw is.invalidParameterError('openSlide.level', 'integer between 0 and 256', inputOptions.openSlide.level); + } + } else if (is.defined(inputOptions.level)) { + // Deprecated if (is.integer(inputOptions.level) && is.inRange(inputOptions.level, 0, 256)) { inputDescriptor.level = inputOptions.level; } else { throw is.invalidParameterError('level', 'integer between 0 and 256', inputOptions.level); } } - // Sub Image File Directory (TIFF) - if (is.defined(inputOptions.subifd)) { + // TIFF specific options + if (is.object(inputOptions.tiff) && is.defined(inputOptions.tiff.subifd)) { + if (is.integer(inputOptions.tiff.subifd) && is.inRange(inputOptions.tiff.subifd, -1, 100000)) { + inputDescriptor.subifd = inputOptions.tiff.subifd; + } else { + throw is.invalidParameterError('tiff.subifd', 'integer between -1 and 100000', inputOptions.tiff.subifd); + } + } else if (is.defined(inputOptions.subifd)) { + // Deprecated if (is.integer(inputOptions.subifd) && is.inRange(inputOptions.subifd, -1, 100000)) { inputDescriptor.subifd = inputOptions.subifd; } else { throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd); } } - // PDF background colour - if (is.defined(inputOptions.pdfBackground)) { + // PDF specific options + if (is.object(inputOptions.pdf) && is.defined(inputOptions.pdf.background)) { + inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdf.background); + } else if (is.defined(inputOptions.pdfBackground)) { + // Deprecated inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdfBackground); } - // JP2 oneshot - if (is.defined(inputOptions.jp2Oneshot)) { - if (is.bool(inputOptions.jp2Oneshot)) { - inputDescriptor.jp2Oneshot = inputOptions.jp2Oneshot; + // JPEG 2000 specific options + if (is.object(inputOptions.jp2) && is.defined(inputOptions.jp2.oneshot)) { + if (is.bool(inputOptions.jp2.oneshot)) { + inputDescriptor.jp2Oneshot = inputOptions.jp2.oneshot; } else { - throw is.invalidParameterError('jp2Oneshot', 'boolean', inputOptions.jp2Oneshot); + throw is.invalidParameterError('jp2.oneshot', 'boolean', inputOptions.jp2.oneshot); } } // Create new image diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index eb1b3bb7..8575f1e6 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -435,9 +435,6 @@ sharp('input.jpg').clahe({ width: 10, height: 10, maxSlope: 5 }).toFile('outfile // Support `unlimited` input option sharp('input.png', { unlimited: true }).resize(320, 240).toFile('outfile.png'); -// Support `subifd` input option for tiffs -sharp('input.tiff', { subifd: 3 }).resize(320, 240).toFile('outfile.png'); - // Support creating with noise sharp({ create: { @@ -720,13 +717,19 @@ sharp(input).composite([ } ]) +// Support format-specific input options const colour: sharp.Colour = '#fff'; const color: sharp.Color = '#fff'; -sharp({ pdfBackground: colour }); -sharp({ pdfBackground: color }); - -sharp({ jp2Oneshot: true }); -sharp({ jp2Oneshot: false }); +sharp({ pdf: { background: colour } }); +sharp({ pdf: { background: color } }); +sharp({ pdfBackground: colour }); // Deprecated +sharp({ pdfBackground: color }); // Deprecated +sharp({ tiff: { subifd: 3 } }); +sharp({ subifd: 3 }); // Deprecated +sharp({ openSlide: { level: 0 } }); +sharp({ level: 0 }); // Deprecated +sharp({ jp2: { oneshot: true } }); +sharp({ jp2: { oneshot: false } }); sharp({ autoOrient: true }); sharp({ autoOrient: false }); diff --git a/test/unit/io.js b/test/unit/io.js index 038bfe1f..a2ee4eb5 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -867,52 +867,91 @@ describe('Input/output', function () { sharp({ pages: '1' }); }, /Expected integer between -1 and 100000 for pages but received 1 of type string/); }); - it('Valid level property', function () { + it('Valid openSlide.level property', function () { + sharp({ openSlide: { level: 1 } }); sharp({ level: 1 }); }); - it('Invalid level property (string) throws', function () { - assert.throws(function () { - sharp({ level: '1' }); - }, /Expected integer between 0 and 256 for level but received 1 of type string/); + it('Invalid openSlide.level property (string) throws', function () { + assert.throws( + () => sharp({ openSlide: { level: '1' } }), + /Expected integer between 0 and 256 for openSlide.level but received 1 of type string/ + ); + assert.throws( + () => sharp({ level: '1' }), + /Expected integer between 0 and 256 for level but received 1 of type string/ + ); }); - it('Invalid level property (negative) throws', function () { - assert.throws(function () { - sharp({ level: -1 }); - }, /Expected integer between 0 and 256 for level but received -1 of type number/); + it('Invalid openSlide.level property (negative) throws', function () { + assert.throws( + () => sharp({ openSlide: { level: -1 } }), + /Expected integer between 0 and 256 for openSlide\.level but received -1 of type number/ + ); + assert.throws( + () => sharp({ level: -1 }), + /Expected integer between 0 and 256 for level but received -1 of type number/ + ); }); - it('Valid subifd property', function () { + it('Valid tiff.subifd property', function () { + sharp({ tiff: { subifd: 1 } }); sharp({ subifd: 1 }); }); - it('Invalid subifd property (string) throws', function () { - assert.throws(function () { - sharp({ subifd: '1' }); - }, /Expected integer between -1 and 100000 for subifd but received 1 of type string/); + it('Invalid tiff.subifd property (string) throws', function () { + assert.throws( + () => sharp({ tiff: { subifd: '1' } }), + /Expected integer between -1 and 100000 for tiff\.subifd but received 1 of type string/ + ); + assert.throws( + () => sharp({ subifd: '1' }), + /Expected integer between -1 and 100000 for subifd but received 1 of type string/ + ); }); - it('Invalid subifd property (float) throws', function () { - assert.throws(function () { - sharp({ subifd: 1.2 }); - }, /Expected integer between -1 and 100000 for subifd but received 1.2 of type number/); + it('Invalid tiff.subifd property (float) throws', function () { + assert.throws( + () => sharp({ tiff: { subifd: 1.2 } }), + /Expected integer between -1 and 100000 for tiff\.subifd but received 1.2 of type number/ + ); + assert.throws( + () => sharp({ subifd: 1.2 }), + /Expected integer between -1 and 100000 for subifd but received 1.2 of type number/ + ); }); - it('Valid pdfBackground property (string)', function () { + it('Valid pdf.background property (string)', function () { + sharp({ pdf: { background: '#00ff00' } }); sharp({ pdfBackground: '#00ff00' }); }); - it('Valid pdfBackground property (object)', function () { + it('Valid pdf.background property (object)', function () { + sharp({ pdf: { background: { r: 0, g: 255, b: 0 } } }); sharp({ pdfBackground: { r: 0, g: 255, b: 0 } }); }); - it('Invalid pdfBackground property (string) throws', function () { - assert.throws(function () { - sharp({ pdfBackground: '00ff00' }); - }, /Unable to parse color from string/); + it('Invalid pdf.background property (string) throws', function () { + assert.throws( + () => sharp({ pdf: { background: '00ff00' } }), + /Unable to parse color from string/ + ); + assert.throws( + () => sharp({ pdfBackground: '00ff00' }), + /Unable to parse color from string/ + ); }); - it('Invalid pdfBackground property (number) throws', function () { - assert.throws(function () { - sharp({ pdfBackground: 255 }); - }, /Expected object or string for background/); + it('Invalid pdf.background property (number) throws', function () { + assert.throws( + () => sharp({ pdf: { background: 255 } }), + /Expected object or string for background/ + ); + assert.throws( + () => sharp({ pdf: { background: 255 } }), + /Expected object or string for background/ + ); }); - it('Invalid pdfBackground property (object)', function () { - assert.throws(function () { - sharp({ pdfBackground: { red: 0, green: 255, blue: 0 } }); - }, /Unable to parse color from object/); + it('Invalid pdf.background property (object)', function () { + assert.throws( + () => sharp({ pdf: { background: { red: 0, green: 255, blue: 0 } } }), + /Unable to parse color from object/ + ); + assert.throws( + () => sharp({ pdfBackground: { red: 0, green: 255, blue: 0 } }), + /Unable to parse color from object/ + ); }); }); diff --git a/test/unit/jp2.js b/test/unit/jp2.js index ff04fe72..3fd2f4a6 100644 --- a/test/unit/jp2.js +++ b/test/unit/jp2.js @@ -117,14 +117,14 @@ describe('JP2 output', () => { it('valid JP2 oneshot value does not throw error', () => { assert.doesNotThrow( - () => sharp(fixtures.inputJp2TileParts, { jp2Oneshot: true }) + () => sharp({ jp2: { oneshot: true } }) ); }); it('invalid JP2 oneshot value throws error', () => { assert.throws( - () => sharp(fixtures.inputJp2TileParts, { jp2Oneshot: 'fail' }), - /Expected boolean for jp2Oneshot but received fail of type string/ + () => sharp({ jp2: { oneshot: 'fail' } }), + /Expected boolean for jp2.oneshot but received fail of type string/ ); }); });