From 087798d2653bea13f7ae3d93b82504de4e65d996 Mon Sep 17 00:00:00 2001 From: Don Denton Date: Sun, 8 Dec 2024 21:00:19 -0500 Subject: [PATCH] Add `appliedOrientation` obj to metadata --- docs/api-input.md | 10 ++++------ lib/index.d.ts | 7 +++++++ lib/input.js | 10 ++++------ src/metadata.cc | 9 +++++++++ test/unit/metadata.js | 26 +++++++++++++++++++++++--- 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/docs/api-input.md b/docs/api-input.md index eaf00e23..59fe13a8 100644 --- a/docs/api-input.md +++ b/docs/api-input.md @@ -74,13 +74,11 @@ image ```js // Based on EXIF rotation metadata, get the right-side-up width and height: -const size = getNormalSize(await sharp(input).metadata()); +const metadata = await sharp(input).metadata() -function getNormalSize({ width, height, orientation }) { - return (orientation || 0) >= 5 - ? { width: height, height: width } - : { width, height }; -} +// These will match metadata.width and metadata.height, but with EXIF +// orientation applied if necessary. +const {width, height} = metadata.appliedOrientation ``` diff --git a/lib/index.d.ts b/lib/index.d.ts index 27631e2b..4443aecb 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1119,6 +1119,13 @@ declare namespace sharp { width?: number | undefined; /** Number of pixels high (EXIF orientation is not taken into consideration) */ height?: number | undefined; + /** Any changed metadata after the image orientation is applied. */ + appliedOrientation: { + /** Number of pixels wide (EXIF orientation is taken into consideration) */ + width: number; + /** Number of pixels high (EXIF orientation is taken into consideration) */ + height: number; + }; /** Name of colour space interpretation */ space?: keyof ColourspaceEnum | undefined; /** Number of bands e.g. 3 for sRGB, 4 for CMYK */ diff --git a/lib/input.js b/lib/input.js index 9aa8dd8b..6764b305 100644 --- a/lib/input.js +++ b/lib/input.js @@ -486,13 +486,11 @@ function _isStreamInput () { * @example * // Based on EXIF rotation metadata, get the right-side-up width and height: * - * const size = getNormalSize(await sharp(input).metadata()); + * const metadata = await sharp(input).metadata() * - * function getNormalSize({ width, height, orientation }) { - * return (orientation || 0) >= 5 - * ? { width: height, height: width } - * : { width, height }; - * } + * // These will match metadata.width and metadata.height, but with EXIF + * // orientation applied if necessary. + * const {width, height} = metadata.appliedOrientation * * @param {Function} [callback] - called with the arguments `(err, metadata)` * @returns {Promise|Sharp} diff --git a/src/metadata.cc b/src/metadata.cc index 2c1dfc79..4fd9d7b7 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -242,6 +242,15 @@ class MetadataWorker : public Napi::AsyncWorker { if (baton->orientation > 0) { info.Set("orientation", baton->orientation); } + Napi::Object appliedOrientation = Napi::Object::New(env); + info.Set("appliedOrientation", appliedOrientation); + if (baton->orientation >= 5) { + appliedOrientation.Set("width", baton->height); + appliedOrientation.Set("height", baton->width); + } else { + appliedOrientation.Set("width", baton->width); + appliedOrientation.Set("height", baton->height); + } if (baton->exifLength > 0) { info.Set("exif", Napi::Buffer::NewOrCopy(env, baton->exif, baton->exifLength, sharp::FreeCallback)); } diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 7aa5c256..d694a2aa 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -102,6 +102,8 @@ describe('Image metadata', function () { assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(1, metadata.orientation); + assert.strictEqual(2464, metadata.appliedOrientation.width); + assert.strictEqual(3248, metadata.appliedOrientation.height); assert.strictEqual('undefined', typeof metadata.exif); assert.strictEqual('undefined', typeof metadata.icc); assert.strictEqual('inch', metadata.resolutionUnit); @@ -148,6 +150,8 @@ describe('Image metadata', function () { assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual(2809, metadata.appliedOrientation.width); + assert.strictEqual(2074, metadata.appliedOrientation.height); assert.strictEqual('undefined', typeof metadata.exif); assert.strictEqual('undefined', typeof metadata.icc); done(); @@ -218,7 +222,11 @@ describe('Image metadata', function () { isPalette: false, isProgressive: false, space: 'b-w', - width: 32 + width: 32, + appliedOrientation: { + width: 32, + height: 32 + } }); }); @@ -239,7 +247,11 @@ describe('Image metadata', function () { isPalette: false, isProgressive: false, space: 'grey16', - width: 32 + width: 32, + appliedOrientation: { + width: 32, + height: 32 + } }); }); @@ -601,6 +613,10 @@ describe('Image metadata', function () { if (err) throw err; assert.strictEqual(true, metadata.hasProfile); assert.strictEqual(8, metadata.orientation); + assert.strictEqual(320, metadata.width); + assert.strictEqual(240, metadata.height); + assert.strictEqual(240, metadata.appliedOrientation.width); + assert.strictEqual(320, metadata.appliedOrientation.height); assert.strictEqual('object', typeof metadata.exif); assert.strictEqual(true, metadata.exif instanceof Buffer); // EXIF @@ -926,7 +942,11 @@ describe('Image metadata', function () { pagePrimary: 0, compression: 'av1', hasProfile: false, - hasAlpha: false + hasAlpha: false, + appliedOrientation: { + width: 2048, + height: 858 + } }); });