diff --git a/docs/api-input.md b/docs/api-input.md index 44a4e839..7e7dbfb9 100644 --- a/docs/api-input.md +++ b/docs/api-input.md @@ -22,9 +22,10 @@ A `Promise` is returned when `callback` is not provided. - `density`: Number of pixels per inch (DPI), if present - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan +- `isPalette`: Boolean indicating whether the image is palette-based (GIF, PNG). +- `bitsPerSample`: Number of bits per sample for each channel (GIF, PNG, HEIF). - `pages`: Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP - `pageHeight`: Number of pixels high each page in a multi-page image will be. -- `paletteBitDepth`: Bit depth of palette-based image (GIF, PNG). - `loop`: Number of times to loop an animated image, zero refers to a continuous loop. - `delay`: Delay in ms between each page in an animated image, provided as an array of integers. - `pagePrimary`: Number of the primary page in a HEIF image diff --git a/docs/changelog.md b/docs/changelog.md index 4f86aaf1..cc81c2a2 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -6,6 +6,8 @@ Requires libvips v8.16.0-rc2 ### v0.33.6 - TBD +* Add `isPalette` and `bitsPerSample` to metadata, deprecate `paletteBitDepth`. + * TypeScript: Ensure channel counts use the correct range. [#4197](https://github.com/lovell/sharp/pull/4197) [@DavidVaness](https://github.com/DavidVaness) diff --git a/lib/index.d.ts b/lib/index.d.ts index 77415e23..12816b2d 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1076,6 +1076,10 @@ declare namespace sharp { chromaSubsampling?: string | undefined; /** Boolean indicating whether the image is interlaced using a progressive scan */ isProgressive?: boolean | undefined; + /** Boolean indicating whether the image is palette-based (GIF, PNG). */ + isPalette?: boolean | undefined; + /** Number of bits per sample for each channel (GIF, PNG). */ + bitsPerSample?: number | undefined; /** Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP */ pages?: number | undefined; /** Number of pixels high each page in a multi-page image will be. */ diff --git a/lib/input.js b/lib/input.js index abb10e53..9760de52 100644 --- a/lib/input.js +++ b/lib/input.js @@ -434,9 +434,10 @@ function _isStreamInput () { * - `density`: Number of pixels per inch (DPI), if present * - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK * - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan + * - `isPalette`: Boolean indicating whether the image is palette-based (GIF, PNG). + * - `bitsPerSample`: Number of bits per sample for each channel (GIF, PNG, HEIF). * - `pages`: Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP * - `pageHeight`: Number of pixels high each page in a multi-page image will be. - * - `paletteBitDepth`: Bit depth of palette-based image (GIF, PNG). * - `loop`: Number of times to loop an animated image, zero refers to a continuous loop. * - `delay`: Delay in ms between each page in an animated image, provided as an array of integers. * - `pagePrimary`: Number of the primary page in a HEIF image diff --git a/src/metadata.cc b/src/metadata.cc index 9d0ac6f3..8be08294 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -47,8 +47,11 @@ class MetadataWorker : public Napi::AsyncWorker { if (image.get_typeof("interlaced") == G_TYPE_INT) { baton->isProgressive = image.get_int("interlaced") == 1; } - if (image.get_typeof("palette-bit-depth") == G_TYPE_INT) { - baton->paletteBitDepth = image.get_int("palette-bit-depth"); + if (image.get_typeof(VIPS_META_PALETTE) == G_TYPE_INT) { + baton->isPalette = image.get_int(VIPS_META_PALETTE); + } + if (image.get_typeof(VIPS_META_BITS_PER_SAMPLE) == G_TYPE_INT) { + baton->bitsPerSample = image.get_int(VIPS_META_BITS_PER_SAMPLE); } if (image.get_typeof(VIPS_META_N_PAGES) == G_TYPE_INT) { baton->pages = image.get_int(VIPS_META_N_PAGES); @@ -171,8 +174,13 @@ class MetadataWorker : public Napi::AsyncWorker { info.Set("chromaSubsampling", baton->chromaSubsampling); } info.Set("isProgressive", baton->isProgressive); - if (baton->paletteBitDepth > 0) { - info.Set("paletteBitDepth", baton->paletteBitDepth); + info.Set("isPalette", baton->isPalette); + if (baton->bitsPerSample > 0) { + info.Set("bitsPerSample", baton->bitsPerSample); + if (baton->isPalette) { + // Deprecated, remove with libvips 8.17.0 + info.Set("paletteBitDepth", baton->bitsPerSample); + } } if (baton->pages > 0) { info.Set("pages", baton->pages); diff --git a/src/metadata.h b/src/metadata.h index b31af869..f93dd516 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -24,7 +24,8 @@ struct MetadataBaton { int density; std::string chromaSubsampling; bool isProgressive; - int paletteBitDepth; + bool isPalette; + int bitsPerSample; int pages; int pageHeight; int loop; @@ -59,7 +60,8 @@ struct MetadataBaton { channels(0), density(0), isProgressive(false), - paletteBitDepth(0), + isPalette(false), + bitsPerSample(0), pages(0), pageHeight(0), loop(-1), diff --git a/test/unit/avif.js b/test/unit/avif.js index 3075d365..9f1e6626 100644 --- a/test/unit/avif.js +++ b/test/unit/avif.js @@ -34,6 +34,7 @@ describe('AVIF', () => { // Math.round(13.40625) = 13 height: 13, isProgressive: false, + isPalette: false, space: 'srgb', width: 32 }); @@ -55,6 +56,8 @@ describe('AVIF', () => { hasProfile: false, height: 26, isProgressive: false, + isPalette: false, + bitsPerSample: 8, pagePrimary: 0, pages: 1, space: 'srgb', @@ -77,6 +80,8 @@ describe('AVIF', () => { hasProfile: false, height: 13, isProgressive: false, + isPalette: false, + bitsPerSample: 8, pagePrimary: 0, pages: 1, space: 'srgb', @@ -100,6 +105,8 @@ describe('AVIF', () => { hasProfile: false, height: 300, isProgressive: false, + isPalette: false, + bitsPerSample: 8, pagePrimary: 0, pages: 1, space: 'srgb', @@ -124,6 +131,8 @@ describe('AVIF', () => { hasProfile: false, height: 26, isProgressive: false, + isPalette: false, + bitsPerSample: 8, pagePrimary: 0, pages: 1, space: 'srgb', diff --git a/test/unit/metadata.js b/test/unit/metadata.js index ca8bc413..eb3459d3 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -878,6 +878,8 @@ describe('Image metadata', function () { channels: 3, depth: 'uchar', isProgressive: false, + isPalette: false, + bitsPerSample: 8, pages: 1, pagePrimary: 0, compression: 'av1', diff --git a/test/unit/png.js b/test/unit/png.js index a9ee09d8..8460ad40 100644 --- a/test/unit/png.js +++ b/test/unit/png.js @@ -146,6 +146,8 @@ describe('PNG', function () { density: 72, depth: 'uchar', isProgressive: false, + isPalette: true, + bitsPerSample: 8, paletteBitDepth: 8, hasProfile: false, hasAlpha: false @@ -218,8 +220,10 @@ describe('PNG', function () { .png({ colours: 2, palette: false }) .toBuffer(); - const { channels, paletteBitDepth, size, space } = await sharp(data).metadata(); + const { channels, isPalette, bitsPerSample, paletteBitDepth, size, space } = await sharp(data).metadata(); assert.strictEqual(channels, 1); + assert.strictEqual(isPalette, false); + assert.strictEqual(bitsPerSample, 1); assert.strictEqual(paletteBitDepth, undefined); assert.strictEqual(size, 89); assert.strictEqual(space, 'b-w');