diff --git a/docs/changelog.md b/docs/changelog.md index 4d04ba63..47fca4f1 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -9,6 +9,9 @@ Requires libvips v8.13.2 * Ensure manual flip, rotate, resize operation ordering (regression in 0.31.1) [#3391](https://github.com/lovell/sharp/issues/3391) +* Ensure auto-rotation works without resize (regression in 0.31.1) + [#3422](https://github.com/lovell/sharp/issues/3422) + ### v0.31.1 - 29th September 2022 * Upgrade to libvips v8.13.2 for upstream bug fixes. diff --git a/src/pipeline.cc b/src/pipeline.cc index d69a88b0..0171110e 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -162,7 +162,9 @@ class PipelineWorker : public Napi::AsyncWorker { int targetResizeHeight = baton->height; // Swap input output width and height when rotating by 90 or 270 degrees - bool swap = !baton->rotateBeforePreExtract && (rotation == VIPS_ANGLE_D90 || rotation == VIPS_ANGLE_D270); + bool swap = !baton->rotateBeforePreExtract && + (rotation == VIPS_ANGLE_D90 || rotation == VIPS_ANGLE_D270 || + autoRotation == VIPS_ANGLE_D90 || autoRotation == VIPS_ANGLE_D270); // Shrink to pageHeight, so we work for multi-page images std::tie(hshrink, vshrink) = sharp::ResolveShrink( @@ -379,6 +381,10 @@ class PipelineWorker : public Napi::AsyncWorker { ->set("kernel", baton->kernel)); } + // Auto-rotate post-extract + if (autoRotation != VIPS_ANGLE_D0) { + image = image.rot(autoRotation); + } // Flip (mirror about Y axis) if (baton->flip || autoFlip) { image = image.flip(VIPS_DIRECTION_VERTICAL); @@ -388,7 +394,7 @@ class PipelineWorker : public Napi::AsyncWorker { image = image.flip(VIPS_DIRECTION_HORIZONTAL); } // Rotate post-extract 90-angle - if (!baton->rotateBeforePreExtract && rotation != VIPS_ANGLE_D0) { + if (rotation != VIPS_ANGLE_D0) { image = image.rot(rotation); } diff --git a/test/unit/rotate.js b/test/unit/rotate.js index e3a4637a..a08bc51a 100644 --- a/test/unit/rotate.js +++ b/test/unit/rotate.js @@ -8,16 +8,43 @@ const fixtures = require('../fixtures'); describe('Rotation', function () { ['Landscape', 'Portrait'].forEach(function (orientation) { [1, 2, 3, 4, 5, 6, 7, 8].forEach(function (exifTag) { - it('Input image has Orientation EXIF tag value of (' + exifTag + '), auto-rotate', function (done) { - sharp(fixtures['inputJpgWith' + orientation + 'Exif' + exifTag]) + const input = fixtures[`inputJpgWith${orientation}Exif${exifTag}`]; + const expectedOutput = fixtures.expected(`${orientation}_${exifTag}-out.jpg`); + it(`Auto-rotate ${orientation} image with EXIF Orientation ${exifTag}`, function (done) { + const [expectedWidth, expectedHeight] = orientation === 'Landscape' ? [600, 450] : [450, 600]; + sharp(input) .rotate() - .resize(320) .toBuffer(function (err, data, info) { if (err) throw err; - assert.strictEqual('jpeg', info.format); - assert.strictEqual(320, info.width); - assert.strictEqual(orientation === 'Landscape' ? 240 : 427, info.height); - fixtures.assertSimilar(fixtures.expected(orientation + '_' + exifTag + '-out.jpg'), data, done); + assert.strictEqual(info.width, expectedWidth); + assert.strictEqual(info.height, expectedHeight); + fixtures.assertSimilar(expectedOutput, data, done); + }); + }); + it(`Auto-rotate then resize ${orientation} image with EXIF Orientation ${exifTag}`, function (done) { + const [expectedWidth, expectedHeight] = orientation === 'Landscape' ? [320, 240] : [320, 427]; + sharp(input) + .rotate() + .resize({ width: 320 }) + .toBuffer(function (err, data, info) { + if (err) throw err; + assert.strictEqual(info.width, expectedWidth); + assert.strictEqual(info.height, expectedHeight); + fixtures.assertSimilar(expectedOutput, data, done); + }); + }); + it(`Resize then auto-rotate ${orientation} image with EXIF Orientation ${exifTag}`, function (done) { + const [expectedWidth, expectedHeight] = orientation === 'Landscape' + ? (exifTag < 5) ? [320, 240] : [320, 240] + : [320, 427]; + sharp(input) + .resize({ width: 320 }) + .rotate() + .toBuffer(function (err, data, info) { + if (err) throw err; + assert.strictEqual(info.width, expectedWidth); + assert.strictEqual(info.height, expectedHeight); + fixtures.assertSimilar(expectedOutput, data, done); }); }); });