Compare commits

..

2 Commits

Author SHA1 Message Date
Lovell Fuller
ccd6012152 Version bump 2014-01-21 22:49:40 +00:00
Lovell Fuller
377662fffc Ensure gm perf tests actually resize. Prevent coredump when embeding pre-shrunk image within same dimensions. 2014-01-21 22:48:33 +00:00
4 changed files with 67 additions and 54 deletions

View File

@@ -9,9 +9,9 @@ _adj_
The typical use case for this high speed Node.js module is to convert large JPEG and PNG images to smaller JPEG and PNG images of varying dimensions.
Under the hood you'll find the blazingly fast [libvips](https://github.com/jcupitt/libvips) image processing library, originally created in 1989 at Birkbeck College and currently maintained by John Cupitt.
The performance of JPEG resizing is typically 15x-25x faster than ImageMagick and GraphicsMagick, based mainly on the number of CPU cores available.
Performance is up to 18x faster than ImageMagick and up to 8x faster than GraphicsMagick, based mainly on the number of CPU cores available.
Under the hood you'll find the blazingly fast [libvips](https://github.com/jcupitt/libvips) image processing library, originally created in 1989 at Birkbeck College and currently maintained by John Cupitt.
## Prerequisites
@@ -119,35 +119,35 @@ Test environment:
### JPEG
* imagemagick x 5.50 ops/sec ±0.48% (31 runs sampled)
* gm-file-file x 11.19 ops/sec ±0.51% (57 runs sampled)
* gm-file-buffer x 11.11 ops/sec ±0.42% (57 runs sampled)
* epeg-file-file x 28.59 ops/sec ±0.09% (71 runs sampled)
* epeg-file-buffer x 28.67 ops/sec ±0.14% (71 runs sampled)
* imagemagick x 5.53 ops/sec ±0.62% (31 runs sampled)
* gm-file-file x 4.10 ops/sec ±0.41% (25 runs sampled)
* gm-file-buffer x 4.10 ops/sec ±0.36% (25 runs sampled)
* epeg-file-file x 23.82 ops/sec ±0.18% (60 runs sampled)
* epeg-file-buffer x 23.98 ops/sec ±0.16% (61 runs sampled)
* sharp-buffer-file x 24.72 ops/sec ±0.42% (62 runs sampled)
* sharp-buffer-buffer x 24.24 ops/sec ±0.36% (61 runs sampled)
* sharp-file-file x 97.15 ops/sec ±0.44% (80 runs sampled)
* sharp-file-buffer x __98.51 ops/sec__ ±0.42% (80 runs sampled)
* sharp-buffer-file x 20.76 ops/sec ±0.55% (54 runs sampled)
* sharp-buffer-buffer x 20.90 ops/sec ±0.26% (54 runs sampled)
* sharp-file-file x 91.78 ops/sec ±0.38% (88 runs sampled)
* sharp-file-buffer x __93.05 ops/sec__ ±0.61% (76 runs sampled)
* sharp-file-buffer-sharpen x 56.99 ops/sec ±5.43% (57 runs sampled)
* sharp-file-buffer-progressive x 64.89 ops/sec ±0.42% (79 runs sampled)
* sharp-file-buffer-sequentialRead x 64.13 ops/sec ±0.40% (78 runs sampled)
* sharp-file-buffer-sharpen x 63.09 ops/sec ±5.58% (63 runs sampled)
* sharp-file-buffer-progressive x 61.68 ops/sec ±0.53% (76 runs sampled)
* sharp-file-buffer-sequentialRead x 60.66 ops/sec ±0.38% (75 runs sampled)
### PNG
* imagemagick x 4.31 ops/sec ±0.27% (26 runs sampled)
* gm-file-file x 17.89 ops/sec ±0.21% (86 runs sampled)
* gm-file-buffer x 14.74 ops/sec ±0.15% (73 runs sampled)
* imagemagick x 4.27 ops/sec ±0.21% (25 runs sampled)
* gm-file-file x 8.33 ops/sec ±0.19% (44 runs sampled)
* gm-file-buffer x 7.45 ops/sec ±0.16% (40 runs sampled)
* sharp-buffer-file x 4.97 ops/sec ±120.47% (26 runs sampled)
* sharp-buffer-buffer x 13.00 ops/sec ±0.53% (65 runs sampled)
* sharp-file-file x 53.00 ops/sec ±7.15% (88 runs sampled)
* sharp-file-buffer x __55.43 ops/sec__ ±0.65% (89 runs sampled)
* sharp-file-buffer-sharpen x 45.37 ops/sec ±0.38% (74 runs sampled)
* sharp-file-buffer-progressive x 55.49 ops/sec ±0.45% (89 runs sampled)
* sharp-file-buffer-sequentialRead x 32.27 ops/sec ±0.29% (79 runs sampled)
* sharp-buffer-file x 4.94 ops/sec ±118.46% (26 runs sampled)
* sharp-buffer-buffer x 12.59 ops/sec ±0.55% (64 runs sampled)
* sharp-file-file x 44.06 ops/sec ±6.86% (75 runs sampled)
* sharp-file-buffer x __46.29 ops/sec__ ±0.38% (76 runs sampled)
* sharp-file-buffer-sharpen x 38.86 ops/sec ±0.22% (65 runs sampled)
* sharp-file-buffer-progressive x 46.35 ops/sec ±0.20% (76 runs sampled)
* sharp-file-buffer-sequentialRead x 29.02 ops/sec ±0.62% (72 runs sampled)
## Licence

View File

@@ -1,6 +1,6 @@
{
"name": "sharp",
"version": "0.1.0",
"version": "0.1.1",
"author": "Lovell Fuller",
"description": "High performance module to resize JPEG and PNG images using the libvips image processing library",
"scripts": {

View File

@@ -18,7 +18,7 @@ struct resize_baton {
int width;
int height;
bool crop;
int embed;
VipsExtend extend;
bool sharpen;
bool progessive;
VipsAccess access_method;
@@ -98,17 +98,20 @@ void resize_async(uv_work_t *work) {
int shrink_on_load = 1;
if (inputImageType == JPEG) {
if (shrink >= 8) {
residual = residual * shrink / 8;
factor = residual * shrink / 8;
shrink_on_load = 8;
shrink = 1;
shrink = floor(factor);
residual = shrink / factor;
} else if (shrink >= 4) {
residual = residual * shrink / 4;
factor = residual * shrink / 4;
shrink_on_load = 4;
shrink = 1;
shrink = floor(factor);
residual = shrink / factor;
} else if (shrink >= 2) {
residual = residual * shrink / 2;
factor = residual * shrink / 2;
shrink_on_load = 2;
shrink = 1;
shrink = floor(factor);
residual = shrink / factor;
}
if (shrink_on_load > 1) {
g_object_unref(in);
@@ -138,26 +141,36 @@ void resize_async(uv_work_t *work) {
// Use vips_affine with the remaining float part using bilinear interpolation
VipsImage *affined = vips_image_new();
if (vips_affine(shrunk, &affined, residual, 0, 0, residual, "interpolate", vips_interpolate_bilinear_static(), NULL)) {
return resize_error(baton, shrunk);
if (residual > 0) {
if (vips_affine(shrunk, &affined, residual, 0, 0, residual, "interpolate", vips_interpolate_bilinear_static(), NULL)) {
return resize_error(baton, shrunk);
}
} else {
vips_copy(shrunk, &affined, NULL);
}
g_object_unref(shrunk);
VipsImage *canvased = vips_image_new();
if (baton->crop) {
int width = std::min(affined->Xsize, baton->width);
int height = std::min(affined->Ysize, baton->height);
int left = (affined->Xsize - width + 1) / 2;
int top = (affined->Ysize - height + 1) / 2;
if (vips_extract_area(affined, &canvased, left, top, width, height, NULL)) {
return resize_error(baton, affined);
if (affined->Xsize != baton->width && affined->Ysize != baton->height) {
if (baton->crop && affined->Xsize != baton->width && affined->Ysize != baton->height) {
// Crop
int width = std::min(affined->Xsize, baton->width);
int height = std::min(affined->Ysize, baton->height);
int left = (affined->Xsize - width + 1) / 2;
int top = (affined->Ysize - height + 1) / 2;
if (vips_extract_area(affined, &canvased, left, top, width, height, NULL)) {
return resize_error(baton, affined);
}
} else {
// Embed
int left = (baton->width - affined->Xsize) / 2;
int top = (baton->height - affined->Ysize) / 2;
if (vips_embed(affined, &canvased, left, top, baton->width, baton->height, "extend", baton->extend, NULL)) {
return resize_error(baton, affined);
}
}
} else {
int left = (baton->width - affined->Xsize) / 2;
int top = (baton->height - affined->Ysize) / 2;
if (vips_embed(affined, &canvased, baton->embed, left, top, baton->width, baton->height, NULL)) {
return resize_error(baton, affined);
}
vips_copy(affined, &canvased, NULL);
}
g_object_unref(affined);
@@ -248,10 +261,10 @@ Handle<Value> resize(const Arguments& args) {
baton->crop = true;
} else if (canvas->Equals(String::NewSymbol("w"))) {
baton->crop = false;
baton->embed = 4;
baton->extend = VIPS_EXTEND_WHITE;
} else if (canvas->Equals(String::NewSymbol("b"))) {
baton->crop = false;
baton->embed = 0;
baton->extend = VIPS_EXTEND_BLACK;
}
baton->sharpen = args[6]->BooleanValue();
baton->progessive = args[7]->BooleanValue();

View File

@@ -13,7 +13,7 @@ var outputJpg = __dirname + "/output.jpg";
var inputPng = __dirname + "/50020484-00001.png"; // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
var outputPng = __dirname + "/output.png";
var width = 640;
var width = 720;
var height = 480;
async.series({
@@ -39,7 +39,7 @@ async.series({
}).add("gm-file-file", {
defer: true,
fn: function(deferred) {
gm(inputJpg).crop(width, height).quality(80).write(outputJpg, function (err) {
gm(inputJpg).resize(width, height).quality(80).write(outputJpg, function (err) {
if (err) {
throw err;
} else {
@@ -50,7 +50,7 @@ async.series({
}).add("gm-file-buffer", {
defer: true,
fn: function(deferred) {
gm(inputJpg).crop(width, height).quality(80).toBuffer(function (err, buffer) {
gm(inputJpg).resize(width, height).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
@@ -183,7 +183,7 @@ async.series({
}).add("gm-file-file", {
defer: true,
fn: function(deferred) {
gm(inputPng).crop(width, height).write(outputPng, function (err) {
gm(inputPng).resize(width, height).write(outputPng, function (err) {
if (err) {
throw err;
} else {
@@ -194,7 +194,7 @@ async.series({
}).add("gm-file-buffer", {
defer: true,
fn: function(deferred) {
gm(inputPng).crop(width, height).quality(80).toBuffer(function (err, buffer) {
gm(inputPng).resize(width, height).quality(80).toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {