diff --git a/docs/changelog.md b/docs/changelog.md index 811e0bace..3db12151c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -13,6 +13,9 @@ Requires libvips v8.13.1 * Ensure auto-rotation works with shrink-on-load and extract (regression in 0.31.0). [#3352](https://github.com/lovell/sharp/issues/3352) +* Ensure AVIF output is always 8-bit. + [#3358](https://github.com/lovell/sharp/issues/3358) + ### v0.31.0 - 5th September 2022 * Drop support for Node.js 12, now requires Node.js >= 14.15.0. diff --git a/src/pipeline.cc b/src/pipeline.cc index 5209d46b8..aa453b433 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -902,12 +902,13 @@ class PipelineWorker : public Napi::AsyncWorker { } else if (baton->formatOut == "heif" || (baton->formatOut == "input" && inputImageType == sharp::ImageType::HEIF)) { // Write HEIF to buffer - image = sharp::RemoveAnimationProperties(image); + image = sharp::RemoveAnimationProperties(image).cast(VIPS_FORMAT_UCHAR); VipsArea *area = reinterpret_cast(image.heifsave_buffer(VImage::option() ->set("strip", !baton->withMetadata) ->set("Q", baton->heifQuality) ->set("compression", baton->heifCompression) ->set("effort", baton->heifEffort) + ->set("bitdepth", 8) ->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4" ? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON) ->set("lossless", baton->heifLossless))); @@ -1073,12 +1074,13 @@ class PipelineWorker : public Napi::AsyncWorker { } else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) || (willMatchInput && inputImageType == sharp::ImageType::HEIF)) { // Write HEIF to file - image = sharp::RemoveAnimationProperties(image); + image = sharp::RemoveAnimationProperties(image).cast(VIPS_FORMAT_UCHAR); image.heifsave(const_cast(baton->fileOut.data()), VImage::option() ->set("strip", !baton->withMetadata) ->set("Q", baton->heifQuality) ->set("compression", baton->heifCompression) ->set("effort", baton->heifEffort) + ->set("bitdepth", 8) ->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4" ? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON) ->set("lossless", baton->heifLossless)); diff --git a/test/unit/avif.js b/test/unit/avif.js index 9a17f7231..12ff888e0 100644 --- a/test/unit/avif.js +++ b/test/unit/avif.js @@ -103,4 +103,28 @@ describe('AVIF', () => { width: 10 }); }); + + it('should cast to uchar', async () => { + const data = await sharp(inputJpg) + .resize(32) + .sharpen() + .avif({ effort: 0 }) + .toBuffer(); + const { size, ...metadata } = await sharp(data) + .metadata(); + assert.deepStrictEqual(metadata, { + channels: 3, + compression: 'av1', + depth: 'uchar', + format: 'heif', + hasAlpha: false, + hasProfile: false, + height: 26, + isProgressive: false, + pagePrimary: 0, + pages: 1, + space: 'srgb', + width: 32 + }); + }); });