diff --git a/src/sharp.cc b/src/sharp.cc index b6262ee2..41704956 100755 --- a/src/sharp.cc +++ b/src/sharp.cc @@ -135,17 +135,17 @@ class ResizeWorker : public NanAsyncWorker { double factor; if (baton->width > 0 && baton->height > 0) { // Fixed width and height - double xfactor = (double)(in->Xsize) / (double)(baton->width); - double yfactor = (double)(in->Ysize) / (double)(baton->height); + double xfactor = static_cast(in->Xsize) / static_cast(baton->width); + double yfactor = static_cast(in->Ysize) / static_cast(baton->height); factor = baton->crop ? std::min(xfactor, yfactor) : std::max(xfactor, yfactor); } else if (baton->width > 0) { // Fixed width, auto height - factor = (double)(in->Xsize) / (double)(baton->width); - baton->height = floor((double)(in->Ysize) / factor); + factor = static_cast(in->Xsize) / static_cast(baton->width); + baton->height = floor(static_cast(in->Ysize) / factor); } else if (baton->height > 0) { // Fixed height, auto width - factor = (double)(in->Ysize) / (double)(baton->height); - baton->width = floor((double)(in->Xsize) / factor); + factor = static_cast(in->Ysize) / static_cast(baton->height); + baton->width = floor(static_cast(in->Xsize) / factor); } else { // Identity transform factor = 1; @@ -156,7 +156,7 @@ class ResizeWorker : public NanAsyncWorker { if (shrink < 1) { shrink = 1; } - double residual = shrink / (double)factor; + double residual = static_cast(shrink) / factor; // Try to use libjpeg shrink-on-load int shrink_on_load = 1; @@ -199,6 +199,14 @@ class ResizeWorker : public NanAsyncWorker { if (vips_shrink(shrunk_on_load, &shrunk, shrink, shrink, NULL)) { return resize_error(baton, shrunk_on_load); } + // Recalculate residual float based on dimensions of required vs shrunk images + double residualx = static_cast(baton->width) / static_cast(shrunk->Xsize); + double residualy = static_cast(baton->height) / static_cast(shrunk->Ysize); + if (baton->crop) { + residual = std::max(residualx, residualy); + } else { + residual = std::min(residualx, residualy); + } } else { vips_copy(shrunk_on_load, &shrunk, NULL); } diff --git a/tests/unit.js b/tests/unit.js index d4d27919..4d8c7774 100755 --- a/tests/unit.js +++ b/tests/unit.js @@ -9,6 +9,9 @@ var fixturesPath = path.join(__dirname, "fixtures"); var inputJpg = path.join(fixturesPath, "2569067123_aca715a2ee_o.jpg"); // http://www.flickr.com/photos/grizdave/2569067123/ var outputJpg = path.join(fixturesPath, "output.jpg"); +var inputTiff = path.join(fixturesPath, "G31D.TIF"); // http://www.fileformat.info/format/tiff/sample/e6c9a6e5253348f4aef6d17b534360ab/index.htm +var outputTiff = path.join(fixturesPath, "output.tiff"); + async.series([ // Resize with exact crop function(done) { @@ -83,6 +86,29 @@ async.series([ }); }); }); + }, + // TIFF with dimensions known to cause rounding errors + function(done) { + sharp(inputTiff).resize(240, 320).embedBlack().write(outputJpg, function(err) { + if (err) throw err; + imagemagick.identify(outputJpg, function(err, features) { + if (err) throw err; + assert.strictEqual(240, features.width); + assert.strictEqual(320, features.height); + done(); + }); + }); + }, + function(done) { + sharp(inputTiff).resize(240, 320).write(outputJpg, function(err) { + if (err) throw err; + imagemagick.identify(outputJpg, function(err, features) { + if (err) throw err; + assert.strictEqual(240, features.width); + assert.strictEqual(320, features.height); + done(); + }); + }); } ]);