From 2492f84d1cc3b17a38e9f71cc47721bd5d28f7c1 Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Fri, 30 Jan 2026 16:21:38 -0500 Subject: [PATCH] feat: support exif autoOrient from base64encoded payloads Service code that makes autoOrient() unreachable via a JSON payload. Here is the breakdown of the issue: The JSON Limitation: The JSON.parse() method (and the JSON standard) cannot produce a value of undefined. If you send {"rotate": null}, then edits.rotate is null. If you send {"rotate": 0}, then edits.rotate is 0. The Condition (edits.rotate === undefined): Since you must provide the key for the loop to enter the case, edits.rotate will always have a value (like null). null === undefined is false. --- source/image-handler/image-handler.ts | 2 +- .../test/image-handler/rotate.spec.ts | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/source/image-handler/image-handler.ts b/source/image-handler/image-handler.ts index 6dc7899b7..05b9316fd 100644 --- a/source/image-handler/image-handler.ts +++ b/source/image-handler/image-handler.ts @@ -192,7 +192,7 @@ export class ImageHandler { } case "rotate": { // Handle rotate specifically to support autoOrient when undefined - if (edits.rotate === undefined) { + if (edits.rotate === undefined || edits.rotate === null || edits.rotate === 'autoOrient') { // When rotate is undefined (filters:rotate() without parameters), call autoOrient() // This aligns with Sharp's behavior where rotate() without parameters auto-orients based on EXIF originalImage.autoOrient(); diff --git a/source/image-handler/test/image-handler/rotate.spec.ts b/source/image-handler/test/image-handler/rotate.spec.ts index fff812a4a..c5abf7bad 100644 --- a/source/image-handler/test/image-handler/rotate.spec.ts +++ b/source/image-handler/test/image-handler/rotate.spec.ts @@ -103,4 +103,54 @@ describe("rotate", () => { // Clean up autoOrientSpy.mockRestore(); }); + + it("Should call autoOrient when rotate is null (filters:rotate() without parameters)", async () => { + // Arrange + const originalImage = fs.readFileSync("./test/image/1x1.jpg"); + const request: ImageRequestInfo = { + requestType: RequestTypes.DEFAULT, + bucket: "sample-bucket", + key: "test.jpg", + edits: { rotate: null }, + originalImage, + }; + + // Create a spy on Sharp's autoOrient method + const autoOrientSpy = jest.spyOn(sharp.prototype, "autoOrient"); + + // Act + const imageHandler = new ImageHandler(s3Client, rekognitionClient); + await imageHandler.process(request); + + // Assert + expect(autoOrientSpy).toHaveBeenCalled(); + + // Clean up + autoOrientSpy.mockRestore(); + }); + + it("Should call autoOrient when rotate is 'autoOrient' (filters:rotate() without parameters)", async () => { + // Arrange + const originalImage = fs.readFileSync("./test/image/1x1.jpg"); + const request: ImageRequestInfo = { + requestType: RequestTypes.DEFAULT, + bucket: "sample-bucket", + key: "test.jpg", + edits: { rotate: "autoOrient" }, + originalImage, + }; + + // Create a spy on Sharp's autoOrient method + const autoOrientSpy = jest.spyOn(sharp.prototype, "autoOrient"); + + // Act + const imageHandler = new ImageHandler(s3Client, rekognitionClient); + await imageHandler.process(request); + + // Assert + expect(autoOrientSpy).toHaveBeenCalled(); + + // Clean up + autoOrientSpy.mockRestore(); + }); });