mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Add withoutEnlargement option #36
This commit is contained in:
parent
906311d403
commit
9a05684302
@ -175,6 +175,12 @@ 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.
|
||||
|
||||
### withoutEnlargement()
|
||||
|
||||
Do not enlarge the output image if the input image width *or* height are already less than the required dimensions.
|
||||
|
||||
This is equivalent to GraphicsMagick's `>` geometry option: "change the dimensions of the image only if its width or height exceeds the geometry specification".
|
||||
|
||||
### sharpen()
|
||||
|
||||
Perform a mild sharpen of the resultant image. This typically reduces performance by 30%.
|
||||
|
29
index.js
29
index.js
@ -12,6 +12,7 @@ var Sharp = function(input) {
|
||||
height: -1,
|
||||
canvas: 'c',
|
||||
angle: 0,
|
||||
withoutEnlargement: false,
|
||||
sharpen: false,
|
||||
progressive: false,
|
||||
sequentialRead: false,
|
||||
@ -20,9 +21,9 @@ var Sharp = function(input) {
|
||||
output: '__jpeg'
|
||||
};
|
||||
if (typeof input === 'string') {
|
||||
this.options.inFile = input;
|
||||
this.options.fileIn = input;
|
||||
} else if (typeof input ==='object' && input instanceof Buffer) {
|
||||
this.options.inBuffer = input;
|
||||
this.options.bufferIn = input;
|
||||
} else {
|
||||
throw 'Unsupported input ' + typeof input;
|
||||
}
|
||||
@ -65,6 +66,16 @@ Sharp.prototype.rotate = function(angle) {
|
||||
return this;
|
||||
};
|
||||
|
||||
/*
|
||||
Do not enlarge the output if the input width *or* height are already less than the required dimensions
|
||||
This is equivalent to GraphicsMagick's ">" geometry option:
|
||||
"change the dimensions of the image only if its width or height exceeds the geometry specification"
|
||||
*/
|
||||
Sharp.prototype.withoutEnlargement = function(withoutEnlargement) {
|
||||
this.options.withoutEnlargement = (typeof withoutEnlargement === 'boolean') ? withoutEnlargement : true;
|
||||
return this;
|
||||
};
|
||||
|
||||
Sharp.prototype.sharpen = function(sharpen) {
|
||||
this.options.sharpen = (typeof sharpen === 'boolean') ? sharpen : true;
|
||||
return this;
|
||||
@ -127,7 +138,7 @@ Sharp.prototype.toFile = function(output, callback) {
|
||||
if (!output || output.length === 0) {
|
||||
callback('Invalid output');
|
||||
} else {
|
||||
if (this.options.inFile === output) {
|
||||
if (this.options.fileIn === output) {
|
||||
callback('Cannot use same file for input and output');
|
||||
} else {
|
||||
this._sharp(output, callback);
|
||||
@ -157,18 +168,8 @@ Sharp.prototype.webp = function(callback) {
|
||||
|
||||
Sharp.prototype._sharp = function(output, callback) {
|
||||
sharp.resize(
|
||||
this.options.inFile,
|
||||
this.options.inBuffer,
|
||||
this.options,
|
||||
output,
|
||||
this.options.width,
|
||||
this.options.height,
|
||||
this.options.canvas,
|
||||
this.options.sharpen,
|
||||
this.options.progressive,
|
||||
this.options.sequentialRead,
|
||||
this.options.quality,
|
||||
this.options.compressionLevel,
|
||||
this.options.angle,
|
||||
callback
|
||||
);
|
||||
return this;
|
||||
|
64
src/sharp.cc
64
src/sharp.cc
@ -24,13 +24,21 @@ struct resize_baton {
|
||||
VipsExtend extend;
|
||||
bool sharpen;
|
||||
bool progressive;
|
||||
bool without_enlargement;
|
||||
VipsAccess access_method;
|
||||
int quality;
|
||||
int compressionLevel;
|
||||
int angle;
|
||||
std::string err;
|
||||
|
||||
resize_baton(): buffer_in_len(0), buffer_out_len(0), crop(false), max(false), sharpen(false), progressive(false) {}
|
||||
resize_baton():
|
||||
buffer_in_len(0),
|
||||
buffer_out_len(0),
|
||||
crop(false),
|
||||
max(false),
|
||||
sharpen(false),
|
||||
progressive(false),
|
||||
without_enlargement(false) {}
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@ -213,6 +221,17 @@ class ResizeWorker : public NanAsyncWorker {
|
||||
}
|
||||
double residual = static_cast<double>(shrink) / factor;
|
||||
|
||||
// Do not enlarge the output if the input width *or* height are already less than the required dimensions
|
||||
if (baton->without_enlargement) {
|
||||
if (inputWidth < baton->width || inputHeight < baton->height) {
|
||||
factor = 1;
|
||||
shrink = 1;
|
||||
residual = 0;
|
||||
baton->width = inputWidth;
|
||||
baton->height = inputHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to use libjpeg shrink-on-load
|
||||
int shrink_on_load = 1;
|
||||
if (inputImageType == JPEG) {
|
||||
@ -403,20 +422,29 @@ class ResizeWorker : public NanAsyncWorker {
|
||||
resize_baton* baton;
|
||||
};
|
||||
|
||||
/*
|
||||
resize(options, output, callback)
|
||||
*/
|
||||
NAN_METHOD(resize) {
|
||||
NanScope();
|
||||
|
||||
// V8 objects are converted to non-V8 types held in the baton struct
|
||||
resize_baton *baton = new resize_baton;
|
||||
baton->file_in = *String::Utf8Value(args[0]->ToString());
|
||||
if (args[1]->IsObject()) {
|
||||
Local<Object> buffer = args[1]->ToObject();
|
||||
Local<Object> options = args[0]->ToObject();
|
||||
|
||||
// Input filename
|
||||
baton->file_in = *String::Utf8Value(options->Get(NanNew<String>("fileIn"))->ToString());
|
||||
// Input Buffer object
|
||||
if (options->Get(NanNew<String>("bufferIn"))->IsObject()) {
|
||||
Local<Object> buffer = options->Get(NanNew<String>("bufferIn"))->ToObject();
|
||||
baton->buffer_in_len = Buffer::Length(buffer);
|
||||
baton->buffer_in = Buffer::Data(buffer);
|
||||
}
|
||||
baton->file_out = *String::Utf8Value(args[2]->ToString());
|
||||
baton->width = args[3]->Int32Value();
|
||||
baton->height = args[4]->Int32Value();
|
||||
Local<String> canvas = args[5]->ToString();
|
||||
// Output image dimensions
|
||||
baton->width = options->Get(NanNew<String>("width"))->Int32Value();
|
||||
baton->height = options->Get(NanNew<String>("height"))->Int32Value();
|
||||
// Canvas options
|
||||
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
||||
if (canvas->Equals(NanNew<String>("c"))) {
|
||||
baton->crop = true;
|
||||
} else if (canvas->Equals(NanNew<String>("w"))) {
|
||||
@ -426,15 +454,19 @@ NAN_METHOD(resize) {
|
||||
} else if (canvas->Equals(NanNew<String>("m"))) {
|
||||
baton->max = true;
|
||||
}
|
||||
baton->sharpen = args[6]->BooleanValue();
|
||||
baton->progressive = args[7]->BooleanValue();
|
||||
baton->access_method = args[8]->BooleanValue() ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||
baton->quality = args[9]->Int32Value();
|
||||
baton->compressionLevel = args[10]->Int32Value();
|
||||
baton->angle = args[11]->Int32Value();
|
||||
|
||||
NanCallback *callback = new NanCallback(args[12].As<v8::Function>());
|
||||
// Other options
|
||||
baton->sharpen = options->Get(NanNew<String>("sharpen"))->BooleanValue();
|
||||
baton->progressive = options->Get(NanNew<String>("progressive"))->BooleanValue();
|
||||
baton->without_enlargement = options->Get(NanNew<String>("withoutEnlargement"))->BooleanValue();
|
||||
baton->access_method = options->Get(NanNew<String>("sequentialRead"))->BooleanValue() ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||
baton->quality = options->Get(NanNew<String>("quality"))->Int32Value();
|
||||
baton->compressionLevel = options->Get(NanNew<String>("compressionLevel"))->Int32Value();
|
||||
baton->angle = options->Get(NanNew<String>("angle"))->Int32Value();
|
||||
// Output filename or __format for Buffer
|
||||
baton->file_out = *String::Utf8Value(args[1]->ToString());
|
||||
|
||||
// Join queue for worker thread
|
||||
NanCallback *callback = new NanCallback(args[2].As<v8::Function>());
|
||||
NanAsyncQueueWorker(new ResizeWorker(callback, baton));
|
||||
NanReturnUndefined();
|
||||
}
|
||||
|
@ -212,6 +212,30 @@ async.series([
|
||||
} catch (e) {}
|
||||
assert(!isValid);
|
||||
done();
|
||||
},
|
||||
// Do not enlarge the output if the input width is already less than the output width
|
||||
function(done) {
|
||||
sharp(inputJpg).resize(2800).withoutEnlargement().write(outputJpg, function(err) {
|
||||
if (err) throw err;
|
||||
imagemagick.identify(outputJpg, function(err, features) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(2725, features.width);
|
||||
assert.strictEqual(2225, features.height);
|
||||
done();
|
||||
});
|
||||
});
|
||||
},
|
||||
// Do not enlarge the output if the input height is already less than the output height
|
||||
function(done) {
|
||||
sharp(inputJpg).resize(null, 2300).withoutEnlargement().write(outputJpg, function(err) {
|
||||
if (err) throw err;
|
||||
imagemagick.identify(outputJpg, function(err, features) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(2725, features.width);
|
||||
assert.strictEqual(2225, features.height);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user