diff --git a/lib/composite.js b/lib/composite.js
index 2dd122fb..4a133d68 100644
--- a/lib/composite.js
+++ b/lib/composite.js
@@ -110,6 +110,7 @@ const blend = {
* @param {number} [images[].input.text.dpi=72] - the resolution (size) at which to render the text. Does not take effect if `height` is specified.
* @param {boolean} [images[].input.text.rgba=false] - set this to true to enable RGBA output. This is useful for colour emoji rendering, or support for Pango markup features like `Red!`.
* @param {number} [images[].input.text.spacing=0] - text line height in points. Will use the font line height if none is specified.
+ * @param {Boolean} [images[].autoOrient=false] - set to true to use EXIF orientation data, if present, to orient the image.
* @param {String} [images[].blend='over'] - how to blend this image with the image below.
* @param {String} [images[].gravity='centre'] - gravity at which to place the overlay.
* @param {Number} [images[].top] - the pixel offset from the top edge.
@@ -136,8 +137,11 @@ function composite (images) {
throw is.invalidParameterError('image to composite', 'object', image);
}
const inputOptions = this._inputOptionsFromObject(image);
+ const descriptor = this._createInputDescriptor(image.input, inputOptions, { allowStream: false });
+ console.log('inputOptions', inputOptions);
+ console.log('descriptor', descriptor);
const composite = {
- input: this._createInputDescriptor(image.input, inputOptions, { allowStream: false }),
+ input: descriptor,
blend: 'over',
tile: false,
left: 0,
diff --git a/lib/input.js b/lib/input.js
index 41233094..9aa8dd8b 100644
--- a/lib/input.js
+++ b/lib/input.js
@@ -36,6 +36,7 @@ function _inputOptionsFromObject (obj) {
*/
function _createInputDescriptor (input, inputOptions, containerOptions) {
const inputDescriptor = {
+ autoOrient: false,
failOn: 'warning',
limitInputPixels: Math.pow(0x3FFF, 2),
ignoreIcc: false,
diff --git a/src/common.cc b/src/common.cc
index 1d6a8f63..3b0610e7 100644
--- a/src/common.cc
+++ b/src/common.cc
@@ -166,6 +166,8 @@ namespace sharp {
descriptor->access = AttrAsBool(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
// Remove safety features and allow unlimited input
descriptor->unlimited = AttrAsBool(input, "unlimited");
+ // Use the EXIF orientation to auto orient the image
+ descriptor->autoOrient = AttrAsBool(input, "autoOrient");
return descriptor;
}
diff --git a/src/common.h b/src/common.h
index 67d86411..b8a6d438 100644
--- a/src/common.h
+++ b/src/common.h
@@ -33,6 +33,7 @@ namespace sharp {
struct InputDescriptor { // NOLINT(runtime/indentation_namespace)
std::string name;
std::string file;
+ bool autoOrient;
char *buffer;
VipsFailOn failOn;
uint64_t limitInputPixels;
@@ -73,6 +74,7 @@ namespace sharp {
std::vector pdfBackground;
InputDescriptor():
+ autoOrient(false),
buffer(nullptr),
failOn(VIPS_FAIL_ON_WARNING),
limitInputPixels(0x3FFF * 0x3FFF),
diff --git a/src/pipeline.cc b/src/pipeline.cc
index ec714eea..eae463a6 100644
--- a/src/pipeline.cc
+++ b/src/pipeline.cc
@@ -627,6 +627,32 @@ class PipelineWorker : public Napi::AsyncWorker {
composite->input->access = access;
std::tie(compositeImage, compositeImageType) = sharp::OpenInput(composite->input);
compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspacePipeline);
+
+ if (composite->input->autoOrient) {
+ // Calculate angle of rotation
+ VipsAngle compositeAutoRotation = VIPS_ANGLE_D0;
+ bool compositeAutoFlip = false;
+ bool compositeAutoFlop = false;
+
+ // Rotate and flip image according to Exif orientation
+ std::tie(compositeAutoRotation, compositeAutoFlip, compositeAutoFlop) =
+ CalculateExifRotationAndFlip(sharp::ExifOrientation(compositeImage));
+
+ compositeImage = sharp::RemoveExifOrientation(compositeImage);
+
+ if (compositeAutoRotation != VIPS_ANGLE_D0) {
+ compositeImage = compositeImage.rot(compositeAutoRotation);
+ }
+ // Mirror vertically (up-down) about the x-axis
+ if (compositeAutoFlip) {
+ compositeImage = compositeImage.flip(VIPS_DIRECTION_VERTICAL);
+ }
+ // Mirror horizontally (left-right) about the y-axis
+ if (compositeAutoFlop) {
+ compositeImage = compositeImage.flip(VIPS_DIRECTION_HORIZONTAL);
+ }
+ }
+
// Verify within current dimensions
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
throw vips::VError("Image to composite must have same dimensions or smaller");