mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Ensure op ordering is respected where possible #3319
Emit warnings when previous ops might be ignored Flip and flop now occur before rotate, if any
This commit is contained in:
parent
e547eaa180
commit
212a6e7519
@ -16,8 +16,11 @@ Mirroring is supported and may infer the use of a flip operation.
|
|||||||
|
|
||||||
The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
|
The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
|
||||||
|
|
||||||
Method order is important when both rotating and extracting regions,
|
Only one rotation can occur per pipeline.
|
||||||
for example `rotate(x).extract(y)` will produce a different result to `extract(y).rotate(x)`.
|
Previous calls to `rotate` in the same pipeline will be ignored.
|
||||||
|
|
||||||
|
Method order is important when rotating, resizing and/or extracting regions,
|
||||||
|
for example `.rotate(x).extract(y)` will produce a different result to `.extract(y).rotate(x)`.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
@ -40,13 +43,24 @@ const pipeline = sharp()
|
|||||||
readableStream.pipe(pipeline);
|
readableStream.pipe(pipeline);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const rotateThenResize = await sharp(input)
|
||||||
|
.rotate(90)
|
||||||
|
.resize({ width: 16, height: 8, fit: 'fill' })
|
||||||
|
.toBuffer();
|
||||||
|
const resizeThenRotate = await sharp(input)
|
||||||
|
.resize({ width: 16, height: 8, fit: 'fill' })
|
||||||
|
.rotate(90)
|
||||||
|
.toBuffer();
|
||||||
|
```
|
||||||
|
|
||||||
* Throws **[Error][5]** Invalid parameters
|
* Throws **[Error][5]** Invalid parameters
|
||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
## flip
|
## flip
|
||||||
|
|
||||||
Flip the image about the vertical Y axis. This always occurs after rotation, if any.
|
Flip the image about the vertical Y axis. This always occurs before rotation, if any.
|
||||||
The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
|
The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
@ -63,7 +77,7 @@ Returns **Sharp**
|
|||||||
|
|
||||||
## flop
|
## flop
|
||||||
|
|
||||||
Flop the image about the horizontal X axis. This always occurs after rotation, if any.
|
Flop the image about the horizontal X axis. This always occurs before rotation, if any.
|
||||||
The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
|
The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
@ -36,6 +36,9 @@ Possible interpolation kernels are:
|
|||||||
* `lanczos2`: Use a [Lanczos kernel][7] with `a=2`.
|
* `lanczos2`: Use a [Lanczos kernel][7] with `a=2`.
|
||||||
* `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
* `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
||||||
|
|
||||||
|
Only one resize can occur per pipeline.
|
||||||
|
Previous calls to `resize` in the same pipeline will be ignored.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
* `width` **[number][8]?** pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
|
* `width` **[number][8]?** pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
|
||||||
|
@ -14,6 +14,8 @@ Requires libvips v8.13.0
|
|||||||
|
|
||||||
* Remove previously-deprecated WebP `reductionEffort` and HEIF `speed` options. Use `effort` to control these.
|
* Remove previously-deprecated WebP `reductionEffort` and HEIF `speed` options. Use `effort` to control these.
|
||||||
|
|
||||||
|
* The `flip` and `flop` operations will now occur before the `rotate` operation.
|
||||||
|
|
||||||
* Use combined bounding box of alpha and non-alpha channels for `trim` operation.
|
* Use combined bounding box of alpha and non-alpha channels for `trim` operation.
|
||||||
[#2166](https://github.com/lovell/sharp/issues/2166)
|
[#2166](https://github.com/lovell/sharp/issues/2166)
|
||||||
|
|
||||||
@ -42,6 +44,10 @@ Requires libvips v8.13.0
|
|||||||
* Ensure only properties owned by the `withMetadata` EXIF Object are parsed.
|
* Ensure only properties owned by the `withMetadata` EXIF Object are parsed.
|
||||||
[#3292](https://github.com/lovell/sharp/issues/3292)
|
[#3292](https://github.com/lovell/sharp/issues/3292)
|
||||||
|
|
||||||
|
* Ensure the order of `rotate`, `resize` and `extend` operations is respected where possible.
|
||||||
|
Emit warnings when previous calls in the same pipeline will be ignored.
|
||||||
|
[#3319](https://github.com/lovell/sharp/issues/3319)
|
||||||
|
|
||||||
## v0.30 - *dresser*
|
## v0.30 - *dresser*
|
||||||
|
|
||||||
Requires libvips v8.12.2
|
Requires libvips v8.12.2
|
||||||
|
File diff suppressed because one or more lines are too long
@ -18,8 +18,11 @@ const is = require('./is');
|
|||||||
*
|
*
|
||||||
* The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
|
* The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
|
||||||
*
|
*
|
||||||
* Method order is important when both rotating and extracting regions,
|
* Only one rotation can occur per pipeline.
|
||||||
* for example `rotate(x).extract(y)` will produce a different result to `extract(y).rotate(x)`.
|
* Previous calls to `rotate` in the same pipeline will be ignored.
|
||||||
|
*
|
||||||
|
* Method order is important when rotating, resizing and/or extracting regions,
|
||||||
|
* for example `.rotate(x).extract(y)` will produce a different result to `.extract(y).rotate(x)`.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const pipeline = sharp()
|
* const pipeline = sharp()
|
||||||
@ -32,6 +35,16 @@ const is = require('./is');
|
|||||||
* });
|
* });
|
||||||
* readableStream.pipe(pipeline);
|
* readableStream.pipe(pipeline);
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
|
* const rotateThenResize = await sharp(input)
|
||||||
|
* .rotate(90)
|
||||||
|
* .resize({ width: 16, height: 8, fit: 'fill' })
|
||||||
|
* .toBuffer();
|
||||||
|
* const resizeThenRotate = await sharp(input)
|
||||||
|
* .resize({ width: 16, height: 8, fit: 'fill' })
|
||||||
|
* .rotate(90)
|
||||||
|
* .toBuffer();
|
||||||
|
*
|
||||||
* @param {number} [angle=auto] angle of rotation.
|
* @param {number} [angle=auto] angle of rotation.
|
||||||
* @param {Object} [options] - if present, is an Object with optional attributes.
|
* @param {Object} [options] - if present, is an Object with optional attributes.
|
||||||
* @param {string|Object} [options.background="#000000"] parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
* @param {string|Object} [options.background="#000000"] parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
||||||
@ -39,6 +52,9 @@ const is = require('./is');
|
|||||||
* @throws {Error} Invalid parameters
|
* @throws {Error} Invalid parameters
|
||||||
*/
|
*/
|
||||||
function rotate (angle, options) {
|
function rotate (angle, options) {
|
||||||
|
if (this.options.useExifOrientation || this.options.angle || this.options.rotationAngle) {
|
||||||
|
this.options.debuglog('ignoring previous rotate options');
|
||||||
|
}
|
||||||
if (!is.defined(angle)) {
|
if (!is.defined(angle)) {
|
||||||
this.options.useExifOrientation = true;
|
this.options.useExifOrientation = true;
|
||||||
} else if (is.integer(angle) && !(angle % 90)) {
|
} else if (is.integer(angle) && !(angle % 90)) {
|
||||||
@ -61,7 +77,7 @@ function rotate (angle, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flip the image about the vertical Y axis. This always occurs after rotation, if any.
|
* Flip the image about the vertical Y axis. This always occurs before rotation, if any.
|
||||||
* The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
|
* The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@ -76,7 +92,7 @@ function flip (flip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flop the image about the horizontal X axis. This always occurs after rotation, if any.
|
* Flop the image about the horizontal X axis. This always occurs before rotation, if any.
|
||||||
* The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
|
* The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
@ -92,6 +92,13 @@ function isRotationExpected (options) {
|
|||||||
return (options.angle % 360) !== 0 || options.useExifOrientation === true || options.rotationAngle !== 0;
|
return (options.angle % 360) !== 0 || options.useExifOrientation === true || options.rotationAngle !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function isResizeExpected (options) {
|
||||||
|
return options.width !== -1 || options.height !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resize image to `width`, `height` or `width x height`.
|
* Resize image to `width`, `height` or `width x height`.
|
||||||
*
|
*
|
||||||
@ -123,6 +130,9 @@ function isRotationExpected (options) {
|
|||||||
* - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
|
* - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
|
||||||
* - `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
* - `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
||||||
*
|
*
|
||||||
|
* Only one resize can occur per pipeline.
|
||||||
|
* Previous calls to `resize` in the same pipeline will be ignored.
|
||||||
|
*
|
||||||
* @example
|
* @example
|
||||||
* sharp(input)
|
* sharp(input)
|
||||||
* .resize({ width: 100 })
|
* .resize({ width: 100 })
|
||||||
@ -220,6 +230,9 @@ function isRotationExpected (options) {
|
|||||||
* @throws {Error} Invalid parameters
|
* @throws {Error} Invalid parameters
|
||||||
*/
|
*/
|
||||||
function resize (width, height, options) {
|
function resize (width, height, options) {
|
||||||
|
if (isResizeExpected(this.options)) {
|
||||||
|
this.options.debuglog('ignoring previous resize options');
|
||||||
|
}
|
||||||
if (is.defined(width)) {
|
if (is.defined(width)) {
|
||||||
if (is.object(width) && !is.defined(options)) {
|
if (is.object(width) && !is.defined(options)) {
|
||||||
options = width;
|
options = width;
|
||||||
@ -300,6 +313,9 @@ function resize (width, height, options) {
|
|||||||
this._setBooleanOption('fastShrinkOnLoad', options.fastShrinkOnLoad);
|
this._setBooleanOption('fastShrinkOnLoad', options.fastShrinkOnLoad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isRotationExpected(this.options) && isResizeExpected(this.options)) {
|
||||||
|
this.options.rotateBeforePreExtract = true;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,7 +428,10 @@ function extend (extend) {
|
|||||||
* @throws {Error} Invalid parameters
|
* @throws {Error} Invalid parameters
|
||||||
*/
|
*/
|
||||||
function extract (options) {
|
function extract (options) {
|
||||||
const suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post';
|
const suffix = isResizeExpected(this.options) || isRotationExpected(this.options) ? 'Post' : 'Pre';
|
||||||
|
if (this.options[`width${suffix}`] !== -1) {
|
||||||
|
this.options.debuglog('ignoring previous extract options');
|
||||||
|
}
|
||||||
['left', 'top', 'width', 'height'].forEach(function (name) {
|
['left', 'top', 'width', 'height'].forEach(function (name) {
|
||||||
const value = options[name];
|
const value = options[name];
|
||||||
if (is.integer(value) && value >= 0) {
|
if (is.integer(value) && value >= 0) {
|
||||||
@ -422,8 +441,10 @@ function extract (options) {
|
|||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
// Ensure existing rotation occurs before pre-resize extraction
|
// Ensure existing rotation occurs before pre-resize extraction
|
||||||
if (suffix === 'Pre' && isRotationExpected(this.options)) {
|
if (isRotationExpected(this.options) && !isResizeExpected(this.options)) {
|
||||||
this.options.rotateBeforePreExtract = true;
|
if (this.options.widthPre === -1 || this.options.widthPost === -1) {
|
||||||
|
this.options.rotateBeforePreExtract = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -951,7 +951,7 @@ namespace sharp {
|
|||||||
|
|
||||||
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
||||||
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction) {
|
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction) {
|
||||||
if (swap) {
|
if (swap && canvas != Canvas::IGNORE_ASPECT) {
|
||||||
// Swap input width and height when requested.
|
// Swap input width and height when requested.
|
||||||
std::swap(width, height);
|
std::swap(width, height);
|
||||||
}
|
}
|
||||||
@ -982,9 +982,6 @@ namespace sharp {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Canvas::IGNORE_ASPECT:
|
case Canvas::IGNORE_ASPECT:
|
||||||
if (swap) {
|
|
||||||
std::swap(hshrink, vshrink);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (targetWidth > 0) {
|
} else if (targetWidth > 0) {
|
||||||
|
@ -387,6 +387,18 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("kernel", kernel));
|
->set("kernel", kernel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flip (mirror about Y axis)
|
||||||
|
if (baton->flip || flip) {
|
||||||
|
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
||||||
|
image = sharp::RemoveExifOrientation(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flop (mirror about X axis)
|
||||||
|
if (baton->flop || flop) {
|
||||||
|
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||||
|
image = sharp::RemoveExifOrientation(image);
|
||||||
|
}
|
||||||
|
|
||||||
// Rotate post-extract 90-angle
|
// Rotate post-extract 90-angle
|
||||||
if (!baton->rotateBeforePreExtract && rotation != VIPS_ANGLE_D0) {
|
if (!baton->rotateBeforePreExtract && rotation != VIPS_ANGLE_D0) {
|
||||||
image = image.rot(rotation);
|
image = image.rot(rotation);
|
||||||
@ -401,18 +413,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
image = sharp::RemoveExifOrientation(image);
|
image = sharp::RemoveExifOrientation(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flip (mirror about Y axis)
|
|
||||||
if (baton->flip || flip) {
|
|
||||||
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
||||||
image = sharp::RemoveExifOrientation(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flop (mirror about X axis)
|
|
||||||
if (baton->flop || flop) {
|
|
||||||
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
||||||
image = sharp::RemoveExifOrientation(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join additional color channels to the image
|
// Join additional color channels to the image
|
||||||
if (baton->joinChannelIn.size() > 0) {
|
if (baton->joinChannelIn.size() > 0) {
|
||||||
VImage joinImage;
|
VImage joinImage;
|
||||||
|
BIN
test/fixtures/expected/extract-rotate-extract.jpg
vendored
Normal file
BIN
test/fixtures/expected/extract-rotate-extract.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
test/fixtures/expected/rotate-extract-45.jpg
vendored
BIN
test/fixtures/expected/rotate-extract-45.jpg
vendored
Binary file not shown.
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
@ -138,7 +138,20 @@ describe('Partial image extraction', function () {
|
|||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(280, info.width);
|
assert.strictEqual(280, info.width);
|
||||||
assert.strictEqual(380, info.height);
|
assert.strictEqual(380, info.height);
|
||||||
fixtures.assertSimilar(fixtures.expected('rotate-extract.jpg'), data, { threshold: 7 }, done);
|
fixtures.assertSimilar(fixtures.expected('rotate-extract.jpg'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Extract then rotate then extract', function (done) {
|
||||||
|
sharp(fixtures.inputPngWithGreyAlpha)
|
||||||
|
.extract({ left: 20, top: 10, width: 180, height: 280 })
|
||||||
|
.rotate(90)
|
||||||
|
.extract({ left: 20, top: 10, width: 200, height: 100 })
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(200, info.width);
|
||||||
|
assert.strictEqual(100, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('extract-rotate-extract.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -164,7 +177,7 @@ describe('Partial image extraction', function () {
|
|||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(380, info.width);
|
assert.strictEqual(380, info.width);
|
||||||
assert.strictEqual(280, info.height);
|
assert.strictEqual(280, info.height);
|
||||||
fixtures.assertSimilar(fixtures.expected('rotate-extract-45.jpg'), data, { threshold: 7 }, done);
|
fixtures.assertSimilar(fixtures.expected('rotate-extract-45.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -281,5 +294,27 @@ describe('Partial image extraction', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Multiple extract emits warning', () => {
|
||||||
|
let warningMessage = '';
|
||||||
|
const s = sharp();
|
||||||
|
s.on('warning', function (msg) { warningMessage = msg; });
|
||||||
|
const options = { top: 0, left: 0, width: 1, height: 1 };
|
||||||
|
s.extract(options);
|
||||||
|
assert.strictEqual(warningMessage, '');
|
||||||
|
s.extract(options);
|
||||||
|
assert.strictEqual(warningMessage, 'ignoring previous extract options');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Multiple rotate+extract emits warning', () => {
|
||||||
|
let warningMessage = '';
|
||||||
|
const s = sharp().rotate();
|
||||||
|
s.on('warning', function (msg) { warningMessage = msg; });
|
||||||
|
const options = { top: 0, left: 0, width: 1, height: 1 };
|
||||||
|
s.extract(options);
|
||||||
|
assert.strictEqual(warningMessage, '');
|
||||||
|
s.extract(options);
|
||||||
|
assert.strictEqual(warningMessage, 'ignoring previous extract options');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -791,4 +791,14 @@ describe('Resize dimensions', function () {
|
|||||||
sharp().resize(null, null, { position: 'unknown' });
|
sharp().resize(null, null, { position: 'unknown' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Multiple resize emits warning', () => {
|
||||||
|
let warningMessage = '';
|
||||||
|
const s = sharp();
|
||||||
|
s.on('warning', function (msg) { warningMessage = msg; });
|
||||||
|
s.resize(1);
|
||||||
|
assert.strictEqual(warningMessage, '');
|
||||||
|
s.resize(2);
|
||||||
|
assert.strictEqual(warningMessage, 'ignoring previous resize options');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -25,8 +25,8 @@ describe('Rotation', function () {
|
|||||||
|
|
||||||
it('Rotate by 30 degrees with semi-transparent background', function (done) {
|
it('Rotate by 30 degrees with semi-transparent background', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.rotate(30, { background: { r: 255, g: 0, b: 0, alpha: 0.5 } })
|
|
||||||
.resize(320)
|
.resize(320)
|
||||||
|
.rotate(30, { background: { r: 255, g: 0, b: 0, alpha: 0.5 } })
|
||||||
.png()
|
.png()
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@ -39,8 +39,8 @@ describe('Rotation', function () {
|
|||||||
|
|
||||||
it('Rotate by 30 degrees with solid background', function (done) {
|
it('Rotate by 30 degrees with solid background', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.rotate(30, { background: { r: 255, g: 0, b: 0, alpha: 0.5 } })
|
|
||||||
.resize(320)
|
.resize(320)
|
||||||
|
.rotate(30, { background: { r: 255, g: 0, b: 0, alpha: 0.5 } })
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
@ -51,25 +51,31 @@ describe('Rotation', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Rotate by 90 degrees, respecting output input size', function (done) {
|
it('Rotate by 90 degrees, respecting output input size', function (done) {
|
||||||
sharp(fixtures.inputJpg).rotate(90).resize(320, 240).toBuffer(function (err, data, info) {
|
sharp(fixtures.inputJpg)
|
||||||
if (err) throw err;
|
.rotate(90)
|
||||||
assert.strictEqual(true, data.length > 0);
|
.resize(320, 240)
|
||||||
assert.strictEqual('jpeg', info.format);
|
.toBuffer(function (err, data, info) {
|
||||||
assert.strictEqual(320, info.width);
|
if (err) throw err;
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(true, data.length > 0);
|
||||||
done();
|
assert.strictEqual('jpeg', info.format);
|
||||||
});
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Rotate by 30 degrees, respecting output input size', function (done) {
|
it('Resize then rotate by 30 degrees, respecting output input size', function (done) {
|
||||||
sharp(fixtures.inputJpg).rotate(30).resize(320, 240).toBuffer(function (err, data, info) {
|
sharp(fixtures.inputJpg)
|
||||||
if (err) throw err;
|
.resize(320, 240)
|
||||||
assert.strictEqual(true, data.length > 0);
|
.rotate(30)
|
||||||
assert.strictEqual('jpeg', info.format);
|
.toBuffer(function (err, data, info) {
|
||||||
assert.strictEqual(397, info.width);
|
if (err) throw err;
|
||||||
assert.strictEqual(368, info.height);
|
assert.strictEqual(true, data.length > 0);
|
||||||
done();
|
assert.strictEqual('jpeg', info.format);
|
||||||
});
|
assert.strictEqual(397, info.width);
|
||||||
|
assert.strictEqual(368, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
[-3690, -450, -90, 90, 450, 3690].forEach(function (angle) {
|
[-3690, -450, -90, 90, 450, 3690].forEach(function (angle) {
|
||||||
@ -141,8 +147,8 @@ describe('Rotation', function () {
|
|||||||
|
|
||||||
it('Rotate by 270 degrees, rectangular output ignoring aspect ratio', function (done) {
|
it('Rotate by 270 degrees, rectangular output ignoring aspect ratio', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240, { fit: sharp.fit.fill })
|
|
||||||
.rotate(270)
|
.rotate(270)
|
||||||
|
.resize(320, 240, { fit: sharp.fit.fill })
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
@ -300,6 +306,16 @@ describe('Rotation', function () {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it('Multiple rotate emits warning', () => {
|
||||||
|
let warningMessage = '';
|
||||||
|
const s = sharp();
|
||||||
|
s.on('warning', function (msg) { warningMessage = msg; });
|
||||||
|
s.rotate();
|
||||||
|
assert.strictEqual(warningMessage, '');
|
||||||
|
s.rotate();
|
||||||
|
assert.strictEqual(warningMessage, 'ignoring previous rotate options');
|
||||||
|
});
|
||||||
|
|
||||||
it('Flip - vertical', function (done) {
|
it('Flip - vertical', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320)
|
.resize(320)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user