From 969e882bea99f1d9754b2419482de7a6fe665653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Sk=C3=B3rzewski?= Date: Wed, 29 Apr 2015 17:41:10 +0200 Subject: [PATCH] Allow arbitrary gravity shifts when cropping --- index.js | 15 ++++++++++++--- src/resize.cc | 38 ++++++++++++-------------------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/index.js b/index.js index a10833347..cba585550 100755 --- a/index.js +++ b/index.js @@ -43,7 +43,7 @@ var Sharp = function(input) { width: -1, height: -1, canvas: 'crop', - gravity: 0, + gravity: { left: 0.5, top: 0.5 }, angle: 0, rotateBeforePreExtract: false, flip: false, @@ -132,11 +132,20 @@ Sharp.prototype._write = function(chunk, encoding, callback) { }; // Crop this part of the resized image (Center/Centre, North, East, South, West) -module.exports.gravity = {'center': 0, 'centre': 0, 'north': 1, 'east': 2, 'south': 3, 'west': 4}; +module.exports.gravity = { + 'center': { left: 0.5, top: 0.5 }, + 'centre': { left: 0.5, top: 0.5 }, + 'north': { left: 0.5, top: 0.0 }, + 'east': { left: 1.0, top: 0.5 }, + 'south': { left: 0.5, top: 1.0 }, + 'west': { left: 0.0, top: 0.5 } +}; Sharp.prototype.crop = function(gravity) { this.options.canvas = 'crop'; - if (typeof gravity === 'number' && !Number.isNaN(gravity) && gravity >= 0 && gravity <= 4) { + if (typeof gravity === 'object' && + typeof gravity.left === 'number' && !Number.isNaN(gravity.left) && gravity.left >= 0 && gravity.left <= 1 && + typeof gravity.top === 'number' && !Number.isNaN(gravity.top) && gravity.top >= 0 && gravity.top <= 1) { this.options.gravity = gravity; } else { throw new Error('Unsupported crop gravity ' + gravity); diff --git a/src/resize.cc b/src/resize.cc index 93ade321c..063deb059 100755 --- a/src/resize.cc +++ b/src/resize.cc @@ -73,7 +73,8 @@ struct ResizeBaton { int width; int height; Canvas canvas; - int gravity; + double gravityLeft; + double gravityTop; std::string interpolator; double background[4]; bool flatten; @@ -111,7 +112,8 @@ struct ResizeBaton { topOffsetPre(-1), topOffsetPost(-1), canvas(Canvas::CROP), - gravity(0), + gravityLeft(0.5), + gravityTop(0.5), flatten(false), blurSigma(0.0), sharpenRadius(0), @@ -619,7 +621,7 @@ class ResizeWorker : public NanAsyncWorker { // Crop/max/min int left; int top; - std::tie(left, top) = CalculateCrop(image->Xsize, image->Ysize, baton->width, baton->height, baton->gravity); + std::tie(left, top) = CalculateCrop(image->Xsize, image->Ysize, baton->width, baton->height, baton->gravityLeft, baton->gravityTop); int width = std::min(image->Xsize, baton->width); int height = std::min(image->Ysize, baton->height); VipsImage *extracted; @@ -1054,28 +1056,10 @@ class ResizeWorker : public NanAsyncWorker { within the input image, applying the given gravity. */ std::tuple - CalculateCrop(int const inWidth, int const inHeight, int const outWidth, int const outHeight, int const gravity) { - int left = 0; - int top = 0; - switch (gravity) { - case 1: // North - left = (inWidth - outWidth + 1) / 2; - break; - case 2: // East - left = inWidth - outWidth; - top = (inHeight - outHeight + 1) / 2; - break; - case 3: // South - left = (inWidth - outWidth + 1) / 2; - top = inHeight - outHeight; - break; - case 4: // West - top = (inHeight - outHeight + 1) / 2; - break; - default: // Centre - left = (inWidth - outWidth + 1) / 2; - top = (inHeight - outHeight + 1) / 2; - } + CalculateCrop(int const inWidth, int const inHeight, int const outWidth, int const outHeight, + double const gravityLeft, double const gravityTop) { + int left = (inWidth - outWidth) * gravityLeft; + int top = (inHeight - outHeight) * gravityTop; return std::make_tuple(left, top); } @@ -1177,7 +1161,9 @@ NAN_METHOD(resize) { } // Resize options baton->withoutEnlargement = options->Get(NanNew("withoutEnlargement"))->BooleanValue(); - baton->gravity = options->Get(NanNew("gravity"))->Int32Value(); + Local gravity = options->Get(NanNew("gravity"))->ToObject(); + baton->gravityLeft = gravity->Get(NanNew("left"))->NumberValue(); + baton->gravityTop = gravity->Get(NanNew("top"))->NumberValue(); baton->interpolator = *String::Utf8Value(options->Get(NanNew("interpolator"))->ToString()); // Operators baton->flatten = options->Get(NanNew("flatten"))->BooleanValue();