Merge pull request #18 from pierreinglebert/master

Add 'max' canvas option to specify the maximum width and/or height.
Approximately equivalent to GraphicsMagick's geometry option.
This commit is contained in:
Lovell Fuller 2014-05-19 21:03:04 +01:00
commit ad7735a0a6
4 changed files with 48 additions and 3 deletions

View File

@ -143,6 +143,10 @@ Scale to `width` x `height`. By default, the resized image is cropped to the exa
Crop the resized image to the exact size specified, the default behaviour. Crop the resized image to the exact size specified, the default behaviour.
### max()
Preserving aspect ratio, resize the image to the maximum width or height specified.
### embedWhite() ### embedWhite()
Embed the resized image on a white background of the exact size specified. Embed the resized image on a white background of the exact size specified.

View File

@ -44,6 +44,12 @@ Sharp.prototype.embedBlack = function() {
return this; return this;
}; };
Sharp.prototype.max = function() {
this.options.canvas = 'm';
return this;
};
Sharp.prototype.sharpen = function(sharpen) { Sharp.prototype.sharpen = function(sharpen) {
this.options.sharpen = (typeof sharpen === 'boolean') ? sharpen : true; this.options.sharpen = (typeof sharpen === 'boolean') ? sharpen : true;
return this; return this;

View File

@ -20,6 +20,7 @@ struct resize_baton {
int width; int width;
int height; int height;
bool crop; bool crop;
bool max;
VipsExtend extend; VipsExtend extend;
bool sharpen; bool sharpen;
bool progressive; bool progressive;
@ -28,7 +29,7 @@ struct resize_baton {
int compressionLevel; int compressionLevel;
std::string err; std::string err;
resize_baton(): buffer_in_len(0), buffer_out_len(0) {} resize_baton(): buffer_in_len(0), buffer_out_len(0), crop(false), max(false), sharpen(false), progressive(false) {}
}; };
typedef enum { typedef enum {
@ -138,6 +139,14 @@ class ResizeWorker : public NanAsyncWorker {
double xfactor = static_cast<double>(in->Xsize) / static_cast<double>(baton->width); double xfactor = static_cast<double>(in->Xsize) / static_cast<double>(baton->width);
double yfactor = static_cast<double>(in->Ysize) / static_cast<double>(baton->height); double yfactor = static_cast<double>(in->Ysize) / static_cast<double>(baton->height);
factor = baton->crop ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor); factor = baton->crop ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor);
// if max is set, we need to compute the real size of the thumb image
if(baton->max) {
if(xfactor > yfactor) {
baton->height = round(in->Ysize/factor);
} else {
baton->width = round(in->Xsize/factor);
}
}
} else if (baton->width > 0) { } else if (baton->width > 0) {
// Fixed width, auto height // Fixed width, auto height
factor = static_cast<double>(in->Xsize) / static_cast<double>(baton->width); factor = static_cast<double>(in->Xsize) / static_cast<double>(baton->width);
@ -226,7 +235,7 @@ class ResizeWorker : public NanAsyncWorker {
// Crop/embed // Crop/embed
VipsImage *canvased = vips_image_new(); VipsImage *canvased = vips_image_new();
if (affined->Xsize != baton->width || affined->Ysize != baton->height) { if (affined->Xsize != baton->width || affined->Ysize != baton->height) {
if (baton->crop) { if (baton->crop || baton->max) {
// Crop // Crop
int width = std::min(affined->Xsize, baton->width); int width = std::min(affined->Xsize, baton->width);
int height = std::min(affined->Ysize, baton->height); int height = std::min(affined->Ysize, baton->height);
@ -351,6 +360,9 @@ NAN_METHOD(resize) {
} else if (canvas->Equals(NanSymbol("b"))) { } else if (canvas->Equals(NanSymbol("b"))) {
baton->crop = false; baton->crop = false;
baton->extend = VIPS_EXTEND_BLACK; baton->extend = VIPS_EXTEND_BLACK;
} else if (canvas->Equals(NanSymbol("m"))) {
baton->crop = false;
baton->max = true;
} }
baton->sharpen = args[6]->BooleanValue(); baton->sharpen = args[6]->BooleanValue();
baton->progressive = args[7]->BooleanValue(); baton->progressive = args[7]->BooleanValue();

View File

@ -109,6 +109,29 @@ async.series([
done(); done();
}); });
}); });
},
// Resize to max width or height considering ratio (landscape)
function(done) {
sharp(inputJpg).resize(320,320).max().write(outputJpg, function(err) {
if (err) throw err;
imagemagick.identify(outputJpg, function(err, features) {
if (err) throw err;
assert.strictEqual(320, features.width);
assert.strictEqual(261, features.height);
done();
});
});
},
// Resize to max width or height considering ratio (portrait)
function(done) {
sharp(inputTiff).resize(320,320).max().write(outputJpg, function(err) {
if (err) throw err;
imagemagick.identify(outputJpg, function(err, features) {
if (err) throw err;
assert.strictEqual(243, features.width);
assert.strictEqual(320, features.height);
done();
});
});
} }
]); ]);