mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Add quality and compressionLevel options for output image. #24
This commit is contained in:
parent
8322b442e0
commit
f8338e7c4f
16
README.md
16
README.md
@ -94,11 +94,11 @@ sharp('input.jpg').resize(null, 200).progressive().toBuffer(function(err, buffer
|
||||
```
|
||||
|
||||
```javascript
|
||||
sharp('input.png').resize(300).sharpen().webp(function(err, buffer) {
|
||||
sharp('input.png').resize(300).sharpen().quality(90).webp(function(err, buffer) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
// buffer contains sharpened WebP image data (converted from PNG), 300 pixels wide
|
||||
// buffer contains 300 pixels wide, sharpened, 90% quality WebP image data
|
||||
});
|
||||
```
|
||||
|
||||
@ -159,6 +159,18 @@ Perform a mild sharpen of the resultant image. This typically reduces performanc
|
||||
|
||||
Use progressive (interlace) scan for JPEG and PNG output. This typically reduces compression performance by 30% but results in an image that can be rendered sooner when decompressed.
|
||||
|
||||
### quality(quality)
|
||||
|
||||
The output quality to use for lossy JPEG, WebP and TIFF output formats. The default quality is `80`.
|
||||
|
||||
`quality` is a Number between 1 and 100.
|
||||
|
||||
### compressionLevel(compressionLevel)
|
||||
|
||||
An advanced setting for the _zlib_ compression level of the lossless PNG output format. The default level is `6`.
|
||||
|
||||
`compressionLevel` is a Number between -1 and 9.
|
||||
|
||||
### sequentialRead()
|
||||
|
||||
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`. This will reduce memory usage and can improve performance on some systems.
|
||||
|
22
index.js
22
index.js
@ -14,6 +14,8 @@ var Sharp = function(input) {
|
||||
sharpen: false,
|
||||
progressive: false,
|
||||
sequentialRead: false,
|
||||
quality: 80,
|
||||
compressionLevel: 6,
|
||||
output: '__jpeg'
|
||||
};
|
||||
if (typeof input === 'string') {
|
||||
@ -57,6 +59,24 @@ Sharp.prototype.sequentialRead = function(sequentialRead) {
|
||||
return this;
|
||||
};
|
||||
|
||||
Sharp.prototype.quality = function(quality) {
|
||||
if (!Number.isNaN(quality) && quality >= 1 && quality <= 100) {
|
||||
this.options.quality = quality;
|
||||
} else {
|
||||
throw 'Invalid quality (1 to 100) ' + quality;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Sharp.prototype.compressionLevel = function(compressionLevel) {
|
||||
if (!Number.isNaN(compressionLevel) && compressionLevel >= -1 && compressionLevel <= 9) {
|
||||
this.options.compressionLevel = compressionLevel;
|
||||
} else {
|
||||
throw 'Invalid compressionLevel (-1 to 9) ' + compressionLevel;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Sharp.prototype.resize = function(width, height) {
|
||||
if (!width) {
|
||||
this.options.width = -1;
|
||||
@ -115,6 +135,8 @@ Sharp.prototype._sharp = function(output, callback) {
|
||||
this.options.sharpen,
|
||||
this.options.progressive,
|
||||
this.options.sequentialRead,
|
||||
this.options.quality,
|
||||
this.options.compressionLevel,
|
||||
callback
|
||||
);
|
||||
return this;
|
||||
|
20
src/sharp.cc
20
src/sharp.cc
@ -24,6 +24,8 @@ struct resize_baton {
|
||||
bool sharpen;
|
||||
bool progessive;
|
||||
VipsAccess access_method;
|
||||
int quality;
|
||||
int compressionLevel;
|
||||
std::string err;
|
||||
|
||||
resize_baton(): buffer_in_len(0), buffer_out_len(0) {}
|
||||
@ -259,37 +261,37 @@ class ResizeWorker : public NanAsyncWorker {
|
||||
// Output
|
||||
if (baton->file_out == "__jpeg" || (baton->file_out == "__input" && inputImageType == JPEG)) {
|
||||
// Write JPEG to buffer
|
||||
if (vips_jpegsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", 80, "optimize_coding", TRUE, "interlace", baton->progessive, NULL)) {
|
||||
if (vips_jpegsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progessive, NULL)) {
|
||||
return resize_error(baton, sharpened);
|
||||
}
|
||||
} else if (baton->file_out == "__png" || (baton->file_out == "__input" && inputImageType == PNG)) {
|
||||
// Write PNG to buffer
|
||||
if (vips_pngsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "compression", 6, "interlace", baton->progessive, NULL)) {
|
||||
if (vips_pngsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progessive, NULL)) {
|
||||
return resize_error(baton, sharpened);
|
||||
}
|
||||
} else if (baton->file_out == "__webp" || (baton->file_out == "__input" && inputImageType == WEBP)) {
|
||||
// Write WEBP to buffer
|
||||
if (vips_webpsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", 80, NULL)) {
|
||||
if (vips_webpsave_buffer(sharpened, &baton->buffer_out, &baton->buffer_out_len, "strip", TRUE, "Q", baton->quality, NULL)) {
|
||||
return resize_error(baton, sharpened);
|
||||
}
|
||||
} else if (is_jpeg(baton->file_out)) {
|
||||
// Write JPEG to file
|
||||
if (vips_jpegsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "Q", 80, "optimize_coding", TRUE, "interlace", baton->progessive, NULL)) {
|
||||
if (vips_jpegsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, "optimize_coding", TRUE, "interlace", baton->progessive, NULL)) {
|
||||
return resize_error(baton, sharpened);
|
||||
}
|
||||
} else if (is_png(baton->file_out)) {
|
||||
// Write PNG to file
|
||||
if (vips_pngsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "compression", 6, "interlace", baton->progessive, NULL)) {
|
||||
if (vips_pngsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "compression", baton->compressionLevel, "interlace", baton->progessive, NULL)) {
|
||||
return resize_error(baton, sharpened);
|
||||
}
|
||||
} else if (is_webp(baton->file_out)) {
|
||||
// Write WEBP to file
|
||||
if (vips_webpsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "Q", 80, NULL)) {
|
||||
if (vips_webpsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "Q", baton->quality, NULL)) {
|
||||
return resize_error(baton, sharpened);
|
||||
}
|
||||
} else if (is_tiff(baton->file_out)) {
|
||||
// Write TIFF to file
|
||||
if (vips_tiffsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", 80, NULL)) {
|
||||
if (vips_tiffsave(sharpened, baton->file_out.c_str(), "strip", TRUE, "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, "Q", baton->quality, NULL)) {
|
||||
return resize_error(baton, sharpened);
|
||||
}
|
||||
} else {
|
||||
@ -345,8 +347,10 @@ NAN_METHOD(resize) {
|
||||
baton->sharpen = args[6]->BooleanValue();
|
||||
baton->progessive = 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();
|
||||
|
||||
NanCallback *callback = new NanCallback(args[9].As<v8::Function>());
|
||||
NanCallback *callback = new NanCallback(args[11].As<v8::Function>());
|
||||
|
||||
NanAsyncQueueWorker(new ResizeWorker(callback, baton));
|
||||
NanReturnUndefined();
|
||||
|
@ -69,5 +69,20 @@ async.series([
|
||||
done();
|
||||
});
|
||||
});
|
||||
},
|
||||
// Quality
|
||||
function(done) {
|
||||
sharp(inputJpg).resize(320, 240).quality(70).jpeg(function(err, buffer70) {
|
||||
if (err) throw err;
|
||||
sharp(inputJpg).resize(320, 240).jpeg(function(err, buffer80) {
|
||||
if (err) throw err;
|
||||
sharp(inputJpg).resize(320, 240).quality(90).jpeg(function(err, buffer90) {
|
||||
assert(buffer70.length < buffer80.length);
|
||||
assert(buffer80.length < buffer90.length);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user