Add bitdepth option to heif output (#4036)

Prebuilt binaries support only AVIF with a bitdepth of 8
This commit is contained in:
Mert 2024-03-21 10:36:17 -04:00 committed by GitHub
parent dc07fd4e9c
commit 3c26080c39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 35 additions and 2 deletions

View File

@ -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,

4
lib/index.d.ts vendored
View File

@ -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 {

View File

@ -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);
}

View File

@ -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");

View File

@ -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),

View File

@ -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/);
});
});

View File

@ -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/);
});
});