mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Allow rotate before pre-resize extraction #145
This commit is contained in:
parent
a190ae6b08
commit
5dab3c8482
@ -315,6 +315,8 @@ Rotate the output image by either an explicit angle or auto-orient based on the
|
|||||||
|
|
||||||
Use this method without `angle` to determine the angle from EXIF data. Mirroring is supported and may infer the use of a `flip` operation.
|
Use this method without `angle` to determine the angle from EXIF data. Mirroring is supported and may infer the use of a `flip` operation.
|
||||||
|
|
||||||
|
Method order is important when both rotating and extracting regions, for example `rotate(x).extract(y)` will produce a different result to `extract(y).rotate(x)`.
|
||||||
|
|
||||||
#### 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 after rotation, if any.
|
||||||
|
5
index.js
5
index.js
@ -37,6 +37,7 @@ var Sharp = function(input) {
|
|||||||
canvas: 'c',
|
canvas: 'c',
|
||||||
gravity: 0,
|
gravity: 0,
|
||||||
angle: 0,
|
angle: 0,
|
||||||
|
rotateBeforePreExtract: false,
|
||||||
flip: false,
|
flip: false,
|
||||||
flop: false,
|
flop: false,
|
||||||
withoutEnlargement: false,
|
withoutEnlargement: false,
|
||||||
@ -136,6 +137,10 @@ Sharp.prototype.extract = function(topOffset, leftOffset, width, height) {
|
|||||||
['topOffset', 'leftOffset', 'width', 'height'].forEach(function(name, index) {
|
['topOffset', 'leftOffset', 'width', 'height'].forEach(function(name, index) {
|
||||||
this.options[name + suffix] = values[index];
|
this.options[name + suffix] = values[index];
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
// Ensure existing rotation occurs before pre-resize extraction
|
||||||
|
if (suffix === 'Pre' && this.options.angle !== 0) {
|
||||||
|
this.options.rotateBeforePreExtract = true;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sharp",
|
"name": "sharp",
|
||||||
"version": "0.8.4",
|
"version": "0.9.0",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Pierre Inglebert <pierre.inglebert@gmail.com>",
|
"Pierre Inglebert <pierre.inglebert@gmail.com>",
|
||||||
@ -37,10 +37,10 @@
|
|||||||
"bluebird": "^2.6.4",
|
"bluebird": "^2.6.4",
|
||||||
"color": "^0.7.3",
|
"color": "^0.7.3",
|
||||||
"nan": "^1.5.1",
|
"nan": "^1.5.1",
|
||||||
"semver": "^4.1.0"
|
"semver": "^4.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "^2.0.1",
|
"mocha": "^2.1.0",
|
||||||
"mocha-jshint": "^0.0.9",
|
"mocha-jshint": "^0.0.9",
|
||||||
"istanbul": "^0.3.5",
|
"istanbul": "^0.3.5",
|
||||||
"coveralls": "^2.11.2"
|
"coveralls": "^2.11.2"
|
||||||
|
@ -58,6 +58,7 @@ struct ResizeBaton {
|
|||||||
double gamma;
|
double gamma;
|
||||||
bool greyscale;
|
bool greyscale;
|
||||||
int angle;
|
int angle;
|
||||||
|
bool rotateBeforePreExtract;
|
||||||
bool flip;
|
bool flip;
|
||||||
bool flop;
|
bool flop;
|
||||||
bool progressive;
|
bool progressive;
|
||||||
@ -146,6 +147,25 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
vips_object_local(hook, image);
|
vips_object_local(hook, image);
|
||||||
|
|
||||||
|
// Calculate angle of rotation
|
||||||
|
Angle rotation;
|
||||||
|
bool flip;
|
||||||
|
std::tie(rotation, flip) = CalculateRotationAndFlip(baton->angle, image);
|
||||||
|
if (flip && !baton->flip) {
|
||||||
|
// Add flip operation due to EXIF mirroring
|
||||||
|
baton->flip = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate pre-extract
|
||||||
|
if (baton->rotateBeforePreExtract && rotation != Angle::D0) {
|
||||||
|
VipsImage *rotated;
|
||||||
|
if (vips_rot(image, &rotated, static_cast<VipsAngle>(rotation), NULL)) {
|
||||||
|
return Error(baton, hook);
|
||||||
|
}
|
||||||
|
vips_object_local(hook, rotated);
|
||||||
|
image = rotated;
|
||||||
|
}
|
||||||
|
|
||||||
// Pre extraction
|
// Pre extraction
|
||||||
if (baton->topOffsetPre != -1) {
|
if (baton->topOffsetPre != -1) {
|
||||||
VipsImage *extractedPre;
|
VipsImage *extractedPre;
|
||||||
@ -156,24 +176,15 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
image = extractedPre;
|
image = extractedPre;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get input image width and height
|
// Get pre-resize image width and height
|
||||||
int inputWidth = image->Xsize;
|
int inputWidth = image->Xsize;
|
||||||
int inputHeight = image->Ysize;
|
int inputHeight = image->Ysize;
|
||||||
|
|
||||||
// Calculate angle of rotation, to be carried out later
|
|
||||||
Angle rotation;
|
|
||||||
bool flip;
|
|
||||||
std::tie(rotation, flip) = CalculateRotationAndFlip(baton->angle, image);
|
|
||||||
if (rotation == Angle::D90 || rotation == Angle::D270) {
|
if (rotation == Angle::D90 || rotation == Angle::D270) {
|
||||||
// Swap input output width and height when rotating by 90 or 270 degrees
|
// Swap input output width and height when rotating by 90 or 270 degrees
|
||||||
int swap = inputWidth;
|
int swap = inputWidth;
|
||||||
inputWidth = inputHeight;
|
inputWidth = inputHeight;
|
||||||
inputHeight = swap;
|
inputHeight = swap;
|
||||||
}
|
}
|
||||||
if (flip && !baton->flip) {
|
|
||||||
// Add flip operation due to EXIF mirroring
|
|
||||||
baton->flip = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get window size of interpolator, used for determining shrink vs affine
|
// Get window size of interpolator, used for determining shrink vs affine
|
||||||
int interpolatorWindowSize = InterpolatorWindowSize(baton->interpolator.c_str());
|
int interpolatorWindowSize = InterpolatorWindowSize(baton->interpolator.c_str());
|
||||||
@ -392,7 +403,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rotate
|
// Rotate
|
||||||
if (rotation != Angle::D0) {
|
if (!baton->rotateBeforePreExtract && rotation != Angle::D0) {
|
||||||
VipsImage *rotated;
|
VipsImage *rotated;
|
||||||
if (vips_rot(image, &rotated, static_cast<VipsAngle>(rotation), NULL)) {
|
if (vips_rot(image, &rotated, static_cast<VipsAngle>(rotation), NULL)) {
|
||||||
return Error(baton, hook);
|
return Error(baton, hook);
|
||||||
@ -918,6 +929,7 @@ NAN_METHOD(resize) {
|
|||||||
baton->gamma = options->Get(NanNew<String>("gamma"))->NumberValue();
|
baton->gamma = options->Get(NanNew<String>("gamma"))->NumberValue();
|
||||||
baton->greyscale = options->Get(NanNew<String>("greyscale"))->BooleanValue();
|
baton->greyscale = options->Get(NanNew<String>("greyscale"))->BooleanValue();
|
||||||
baton->angle = options->Get(NanNew<String>("angle"))->Int32Value();
|
baton->angle = options->Get(NanNew<String>("angle"))->Int32Value();
|
||||||
|
baton->rotateBeforePreExtract = options->Get(NanNew<String>("rotateBeforePreExtract"))->BooleanValue();
|
||||||
baton->flip = options->Get(NanNew<String>("flip"))->BooleanValue();
|
baton->flip = options->Get(NanNew<String>("flip"))->BooleanValue();
|
||||||
baton->flop = options->Get(NanNew<String>("flop"))->BooleanValue();
|
baton->flop = options->Get(NanNew<String>("flop"))->BooleanValue();
|
||||||
// Output options
|
// Output options
|
||||||
|
@ -92,4 +92,28 @@ describe('Partial image extraction', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Extract then rotate', function(done) {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.extract(10, 10, 100, 100)
|
||||||
|
.rotate(90)
|
||||||
|
.toFile(fixtures.path('output.extract.extract-then-rotate.jpg'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(100, info.width);
|
||||||
|
assert.strictEqual(100, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Rotate then extract', function(done) {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.rotate(90)
|
||||||
|
.extract(10, 10, 100, 100)
|
||||||
|
.toFile(fixtures.path('output.extract.rotate-then-extract.jpg'), function(err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(100, info.width);
|
||||||
|
assert.strictEqual(100, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user