From 26afdb2318ab257b49694ca0cf769d903d29bed6 Mon Sep 17 00:00:00 2001 From: mertalev <101130780+mertalev@users.noreply.github.com> Date: Wed, 20 Mar 2024 00:37:33 -0400 Subject: [PATCH] added bitdepth setting add validation unit tests add ushort unit test add test for valid bitdepth, make test formatting consistent consistent test wording add setting to constructor remove ushort test fix unit tests bitdepth is not a boolean --- lib/constructor.js | 1 + lib/index.d.ts | 4 ++++ lib/output.js | 9 +++++++++ src/pipeline.cc | 5 +++-- src/pipeline.h | 2 ++ test/unit/avif.js | 6 ++++++ test/unit/heif.js | 10 ++++++++++ 7 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/constructor.js b/lib/constructor.js index 05b4c2db3..f6741509b 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -325,6 +325,7 @@ const Sharp = function (input, options) { heifCompression: 'av1', heifEffort: 4, heifChromaSubsampling: '4:4:4', + heifBitdepth: 8, jxlDistance: 1, jxlDecodingTier: 0, jxlEffort: 7, diff --git a/lib/index.d.ts b/lib/index.d.ts index f73a7594b..c31ccdfc1 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1244,6 +1244,8 @@ declare namespace sharp { effort?: number | undefined; /** set to '4:2:0' to use chroma subsampling, requires libvips v8.11.0 (optional, default '4:4:4') */ chromaSubsampling?: string | undefined; + /** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */ + bitdepth?: 8 | 10 | 12 | undefined; } interface HeifOptions extends OutputOptions { @@ -1257,6 +1259,8 @@ declare namespace sharp { effort?: number | undefined; /** set to '4:2:0' to use chroma subsampling (optional, default '4:4:4') */ chromaSubsampling?: string | undefined; + /** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */ + bitdepth?: 8 | 10 | 12 | undefined; } interface GifOptions extends OutputOptions, AnimationOptions { diff --git a/lib/output.js b/lib/output.js index d192b7aff..c03d6506a 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1029,6 +1029,7 @@ function tiff (options) { * @param {boolean} [options.lossless=false] - use lossless compression * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest) * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling + * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit * @returns {Sharp} * @throws {Error} Invalid options */ @@ -1055,6 +1056,7 @@ function avif (options) { * @param {boolean} [options.lossless=false] - use lossless compression * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest) * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling + * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit * @returns {Sharp} * @throws {Error} Invalid options */ @@ -1093,6 +1095,13 @@ function heif (options) { throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling); } } + if (is.defined(options.bitdepth)) { + if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [8, 10, 12])) { + this.options.heifBitdepth = options.bitdepth; + } else { + throw is.invalidParameterError('bitdepth', '8, 10 or 12', options.bitdepth); + } + } } else { throw is.invalidParameterError('options', 'Object', options); } diff --git a/src/pipeline.cc b/src/pipeline.cc index ce5ce7ba9..a9c68f123 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -989,7 +989,7 @@ class PipelineWorker : public Napi::AsyncWorker { ->set("Q", baton->heifQuality) ->set("compression", baton->heifCompression) ->set("effort", baton->heifEffort) - ->set("bitdepth", 8) + ->set("bitdepth", baton->heifBitdepth) ->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4" ? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON) ->set("lossless", baton->heifLossless))); @@ -1182,7 +1182,7 @@ class PipelineWorker : public Napi::AsyncWorker { ->set("Q", baton->heifQuality) ->set("compression", baton->heifCompression) ->set("effort", baton->heifEffort) - ->set("bitdepth", 8) + ->set("bitdepth", baton->heifBitdepth) ->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4" ? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON) ->set("lossless", baton->heifLossless)); @@ -1696,6 +1696,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) { options, "heifCompression", VIPS_TYPE_FOREIGN_HEIF_COMPRESSION); baton->heifEffort = sharp::AttrAsUint32(options, "heifEffort"); baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling"); + baton->heifBitdepth = sharp::AttrAsUint32(options, "heifBitdepth"); baton->jxlDistance = sharp::AttrAsDouble(options, "jxlDistance"); baton->jxlDecodingTier = sharp::AttrAsUint32(options, "jxlDecodingTier"); baton->jxlEffort = sharp::AttrAsUint32(options, "jxlEffort"); diff --git a/src/pipeline.h b/src/pipeline.h index 3d92dbacf..6ebf0e63f 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -181,6 +181,7 @@ struct PipelineBaton { int heifEffort; std::string heifChromaSubsampling; bool heifLossless; + int heifBitdepth; double jxlDistance; int jxlDecodingTier; int jxlEffort; @@ -349,6 +350,7 @@ struct PipelineBaton { heifEffort(4), heifChromaSubsampling("4:4:4"), heifLossless(false), + heifBitdepth(8), jxlDistance(1.0), jxlDecodingTier(0), jxlEffort(7), diff --git a/test/unit/avif.js b/test/unit/avif.js index ca9a2bc23..3075d365d 100644 --- a/test/unit/avif.js +++ b/test/unit/avif.js @@ -144,4 +144,10 @@ describe('AVIF', () => { /Processed image is too large for the HEIF format/ ) ); + + it('Invalid bitdepth value throws error', async () => { + assert.rejects( + () => sharp().avif({ bitdepth: 11 }), + /Error: Expected 8, 10 or 12 for bitdepth but received 11 of type number/); + }); }); diff --git a/test/unit/heif.js b/test/unit/heif.js index 338bda693..ccd6a3992 100644 --- a/test/unit/heif.js +++ b/test/unit/heif.js @@ -78,4 +78,14 @@ describe('HEIF', () => { sharp().heif({ compression: 'av1', chromaSubsampling: '4:4:4' }); }); }); + it('valid bitdepth value does not throw an error', () => { + assert.doesNotThrow(() => { + sharp().heif({ compression: 'av1', bitdepth: 12 }); + }); + }); + it('invalid bitdepth value should throw an error', () => { + assert.throws(() => { + sharp().heif({ compression: 'av1', bitdepth: 11 }); + }, /Error: Expected 8, 10 or 12 for bitdepth but received 11 of type number/); + }); });