mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
feature: min
This commit is contained in:
parent
749dc61f85
commit
bcd82f4893
@ -332,6 +332,12 @@ Preserving aspect ratio, resize the image to the maximum `width` or `height` spe
|
|||||||
|
|
||||||
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
||||||
|
|
||||||
|
#### min()
|
||||||
|
|
||||||
|
Preserving aspect ratio, resize the image to the minimum `width` or `height` specified.
|
||||||
|
|
||||||
|
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
||||||
|
|
||||||
#### background(rgba)
|
#### background(rgba)
|
||||||
|
|
||||||
Set the background for the `embed` and `flatten` operations.
|
Set the background for the `embed` and `flatten` operations.
|
||||||
|
13
index.js
13
index.js
@ -41,7 +41,7 @@ var Sharp = function(input) {
|
|||||||
heightPost: -1,
|
heightPost: -1,
|
||||||
width: -1,
|
width: -1,
|
||||||
height: -1,
|
height: -1,
|
||||||
canvas: 'c',
|
canvas: 'crop',
|
||||||
gravity: 0,
|
gravity: 0,
|
||||||
angle: 0,
|
angle: 0,
|
||||||
rotateBeforePreExtract: false,
|
rotateBeforePreExtract: false,
|
||||||
@ -136,7 +136,7 @@ Sharp.prototype._write = function(chunk, encoding, callback) {
|
|||||||
module.exports.gravity = {'center': 0, 'centre': 0, 'north': 1, 'east': 2, 'south': 3, 'west': 4};
|
module.exports.gravity = {'center': 0, 'centre': 0, 'north': 1, 'east': 2, 'south': 3, 'west': 4};
|
||||||
|
|
||||||
Sharp.prototype.crop = function(gravity) {
|
Sharp.prototype.crop = function(gravity) {
|
||||||
this.options.canvas = 'c';
|
this.options.canvas = 'crop';
|
||||||
if (typeof gravity === 'number' && !Number.isNaN(gravity) && gravity >= 0 && gravity <= 4) {
|
if (typeof gravity === 'number' && !Number.isNaN(gravity) && gravity >= 0 && gravity <= 4) {
|
||||||
this.options.gravity = gravity;
|
this.options.gravity = gravity;
|
||||||
} else {
|
} else {
|
||||||
@ -176,12 +176,17 @@ Sharp.prototype.background = function(rgba) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Sharp.prototype.embed = function() {
|
Sharp.prototype.embed = function() {
|
||||||
this.options.canvas = 'e';
|
this.options.canvas = 'embed';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
Sharp.prototype.max = function() {
|
Sharp.prototype.max = function() {
|
||||||
this.options.canvas = 'm';
|
this.options.canvas = 'max';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sharp.prototype.min = function() {
|
||||||
|
this.options.canvas = 'min';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
"Amit Pitaru <pitaru.amit@gmail.com>",
|
"Amit Pitaru <pitaru.amit@gmail.com>",
|
||||||
"Brandon Aaron <hello.brandon@aaron.sh>",
|
"Brandon Aaron <hello.brandon@aaron.sh>",
|
||||||
"Andreas Lind <andreas@one.com>",
|
"Andreas Lind <andreas@one.com>",
|
||||||
"Maurus Cuelenaere <mcuelenaere@gmail.com>"
|
"Maurus Cuelenaere <mcuelenaere@gmail.com>",
|
||||||
|
"Linus Unnebäck <linus@folkdatorn.se>"
|
||||||
],
|
],
|
||||||
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -37,8 +37,9 @@ using sharp::counterQueue;
|
|||||||
|
|
||||||
enum class Canvas {
|
enum class Canvas {
|
||||||
CROP,
|
CROP,
|
||||||
|
EMBED,
|
||||||
MAX,
|
MAX,
|
||||||
EMBED
|
MIN
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Angle {
|
enum class Angle {
|
||||||
@ -252,14 +253,29 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
// Fixed width and height
|
// Fixed width and height
|
||||||
double xfactor = static_cast<double>(inputWidth) / static_cast<double>(baton->width);
|
double xfactor = static_cast<double>(inputWidth) / static_cast<double>(baton->width);
|
||||||
double yfactor = static_cast<double>(inputHeight) / static_cast<double>(baton->height);
|
double yfactor = static_cast<double>(inputHeight) / static_cast<double>(baton->height);
|
||||||
factor = (baton->canvas == Canvas::CROP) ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor);
|
switch (baton->canvas) {
|
||||||
// if max is set, we need to compute the real size of the thumb image
|
case Canvas::CROP:
|
||||||
if (baton->canvas == Canvas::MAX) {
|
factor = std::min(xfactor, yfactor);
|
||||||
if (xfactor > yfactor) {
|
break;
|
||||||
baton->height = round(static_cast<double>(inputHeight) / xfactor);
|
case Canvas::EMBED:
|
||||||
} else {
|
factor = std::max(xfactor, yfactor);
|
||||||
baton->width = round(static_cast<double>(inputWidth) / yfactor);
|
break;
|
||||||
}
|
case Canvas::MAX:
|
||||||
|
factor = std::max(xfactor, yfactor);
|
||||||
|
if (xfactor > yfactor) {
|
||||||
|
baton->height = round(static_cast<double>(inputHeight) / xfactor);
|
||||||
|
} else {
|
||||||
|
baton->width = round(static_cast<double>(inputWidth) / yfactor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Canvas::MIN:
|
||||||
|
factor = std::min(xfactor, yfactor);
|
||||||
|
if (xfactor < yfactor) {
|
||||||
|
baton->height = round(static_cast<double>(inputHeight) / xfactor);
|
||||||
|
} else {
|
||||||
|
baton->width = round(static_cast<double>(inputWidth) / yfactor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (baton->width > 0) {
|
} else if (baton->width > 0) {
|
||||||
// Fixed width, auto height
|
// Fixed width, auto height
|
||||||
@ -549,7 +565,7 @@ class ResizeWorker : public NanAsyncWorker {
|
|||||||
vips_object_local(hook, embedded);
|
vips_object_local(hook, embedded);
|
||||||
image = embedded;
|
image = embedded;
|
||||||
} else {
|
} else {
|
||||||
// Crop/max
|
// Crop/max/min
|
||||||
int left;
|
int left;
|
||||||
int top;
|
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->gravity);
|
||||||
@ -963,12 +979,14 @@ NAN_METHOD(resize) {
|
|||||||
baton->height = options->Get(NanNew<String>("height"))->Int32Value();
|
baton->height = options->Get(NanNew<String>("height"))->Int32Value();
|
||||||
// Canvas option
|
// Canvas option
|
||||||
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
||||||
if (canvas->Equals(NanNew<String>("c"))) {
|
if (canvas->Equals(NanNew<String>("crop"))) {
|
||||||
baton->canvas = Canvas::CROP;
|
baton->canvas = Canvas::CROP;
|
||||||
} else if (canvas->Equals(NanNew<String>("m"))) {
|
} else if (canvas->Equals(NanNew<String>("embed"))) {
|
||||||
baton->canvas = Canvas::MAX;
|
|
||||||
} else if (canvas->Equals(NanNew<String>("e"))) {
|
|
||||||
baton->canvas = Canvas::EMBED;
|
baton->canvas = Canvas::EMBED;
|
||||||
|
} else if (canvas->Equals(NanNew<String>("max"))) {
|
||||||
|
baton->canvas = Canvas::MAX;
|
||||||
|
} else if (canvas->Equals(NanNew<String>("min"))) {
|
||||||
|
baton->canvas = Canvas::MIN;
|
||||||
}
|
}
|
||||||
// Background colour
|
// Background colour
|
||||||
Local<Array> background = Local<Array>::Cast(options->Get(NanNew<String>("background")));
|
Local<Array> background = Local<Array>::Cast(options->Get(NanNew<String>("background")));
|
||||||
|
@ -185,6 +185,39 @@ describe('Resize dimensions', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Min width or height considering ratio (landscape)', function(done) {
|
||||||
|
sharp(fixtures.inputJpg).resize(320, 320).min().toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(392, info.width);
|
||||||
|
assert.strictEqual(320, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Min width or height considering ratio (portrait)', function(done) {
|
||||||
|
sharp(fixtures.inputTiff).resize(320, 320).min().jpeg().toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(422, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Provide only one dimension with min, should default to crop', function(done) {
|
||||||
|
sharp(fixtures.inputJpg).resize(320).min().toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(261, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Do not enlarge when input width is already less than output width', function(done) {
|
it('Do not enlarge when input width is already less than output width', function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(2800)
|
.resize(2800)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user