diff --git a/docs/api-input.md b/docs/api-input.md index 7e7dbfb9b..eaf00e235 100644 --- a/docs/api-input.md +++ b/docs/api-input.md @@ -31,7 +31,7 @@ A `Promise` is returned when `callback` is not provided. - `pagePrimary`: Number of the primary page in a HEIF image - `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide - `subifds`: Number of Sub Image File Directories in an OME-TIFF image -- `background`: Default background colour, if present, for PNG (bKGD) and GIF images, either an RGB Object or a single greyscale value +- `background`: Default background colour, if present, for PNG (bKGD) and GIF images - `compression`: The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC) - `resolutionUnit`: The unit of resolution (density), either `inch` or `cm`, if present - `hasProfile`: Boolean indicating the presence of an embedded ICC profile diff --git a/docs/changelog.md b/docs/changelog.md index 01446f9c7..261b3ec5c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -10,6 +10,9 @@ Requires libvips v8.16.0-rc2 * Expose WebP `smartDeblock` output option. +* Ensure `background` metadata can be parsed by `color` package. + [#4090](https://github.com/lovell/sharp/issues/4090) + * 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 12816b2de..695fd5442 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1106,8 +1106,8 @@ declare namespace sharp { tifftagPhotoshop?: Buffer | undefined; /** The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC) */ compression?: 'av1' | 'hevc'; - /** Default background colour, if present, for PNG (bKGD) and GIF images, either an RGB Object or a single greyscale value */ - background?: { r: number; g: number; b: number } | number; + /** Default background colour, if present, for PNG (bKGD) and GIF images */ + background?: { r: number; g: number; b: number } | { gray: number }; /** Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide */ levels?: LevelMetadata[] | undefined; /** Number of Sub Image File Directories in an OME-TIFF image */ diff --git a/lib/input.js b/lib/input.js index 9760de525..3a1562d46 100644 --- a/lib/input.js +++ b/lib/input.js @@ -443,7 +443,7 @@ function _isStreamInput () { * - `pagePrimary`: Number of the primary page in a HEIF image * - `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide * - `subifds`: Number of Sub Image File Directories in an OME-TIFF image - * - `background`: Default background colour, if present, for PNG (bKGD) and GIF images, either an RGB Object or a single greyscale value + * - `background`: Default background colour, if present, for PNG (bKGD) and GIF images * - `compression`: The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC) * - `resolutionUnit`: The unit of resolution (density), either `inch` or `cm`, if present * - `hasProfile`: Boolean indicating the presence of an embedded ICC profile diff --git a/src/metadata.cc b/src/metadata.cc index 8be08294b..2c1dfc797 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -226,15 +227,15 @@ class MetadataWorker : public Napi::AsyncWorker { info.Set("subifds", baton->subifds); } if (!baton->background.empty()) { + Napi::Object background = Napi::Object::New(env); if (baton->background.size() == 3) { - Napi::Object background = Napi::Object::New(env); background.Set("r", baton->background[0]); background.Set("g", baton->background[1]); background.Set("b", baton->background[2]); - info.Set("background", background); } else { - info.Set("background", baton->background[0]); + background.Set("gray", round(baton->background[0] * 100 / 255)); } + info.Set("background", background); } info.Set("hasProfile", baton->hasProfile); info.Set("hasAlpha", baton->hasAlpha); diff --git a/test/fixtures/bgbn4a08.png b/test/fixtures/bgbn4a08.png new file mode 100644 index 000000000..7cbefc3bf Binary files /dev/null and b/test/fixtures/bgbn4a08.png differ diff --git a/test/fixtures/bggn4a16.png b/test/fixtures/bggn4a16.png new file mode 100644 index 000000000..13fd85ba1 Binary files /dev/null and b/test/fixtures/bggn4a16.png differ diff --git a/test/fixtures/index.js b/test/fixtures/index.js index e4b8e266e..ba79504df 100644 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -80,6 +80,8 @@ module.exports = { inputPngWithGreyAlpha: getPath('grey-8bit-alpha.png'), inputPngWithOneColor: getPath('2x2_fdcce6.png'), inputPngWithTransparency16bit: getPath('tbgn2c16.png'), // http://www.schaik.com/pngsuite/tbgn2c16.png + inputPng8BitGreyBackground: getPath('bgbn4a08.png'), // http://www.schaik.com/pngsuite/bgbn4a08.png + inputPng16BitGreyBackground: getPath('bggn4a16.png'), // http://www.schaik.com/pngsuite/bggn4a16.png inputPng16BitGreyAlpha: getPath('16-bit-grey-alpha.png'), // CC-BY-NC-SA florc http://www.colourlovers.com/pattern/50713/pat inputPngOverlayLayer0: getPath('alpha-layer-0-background.png'), inputPngOverlayLayer1: getPath('alpha-layer-1-fill.png'), diff --git a/test/unit/metadata.js b/test/unit/metadata.js index eb3459d33..7aa5c2561 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -201,6 +201,48 @@ describe('Image metadata', function () { }); }); + it('PNG with greyscale bKGD chunk - 8 bit', async () => { + const data = await sharp(fixtures.inputPng8BitGreyBackground).metadata(); + assert.deepStrictEqual(data, { + background: { + gray: 0 + }, + bitsPerSample: 8, + channels: 2, + density: 72, + depth: 'uchar', + format: 'png', + hasAlpha: true, + hasProfile: false, + height: 32, + isPalette: false, + isProgressive: false, + space: 'b-w', + width: 32 + }); + }); + + it('PNG with greyscale bKGD chunk - 16 bit', async () => { + const data = await sharp(fixtures.inputPng16BitGreyBackground).metadata(); + assert.deepStrictEqual(data, { + background: { + gray: 67 + }, + bitsPerSample: 16, + channels: 2, + density: 72, + depth: 'ushort', + format: 'png', + hasAlpha: true, + hasProfile: false, + height: 32, + isPalette: false, + isProgressive: false, + space: 'grey16', + width: 32 + }); + }); + it('WebP', function (done) { sharp(fixtures.inputWebP).metadata(function (err, metadata) { if (err) throw err;