diff --git a/docs/changelog.md b/docs/changelog.md index c291b567..55ac8292 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,20 @@ Requires libvips v8.3.1 +#### v0.15.2 - TBD + +* Ensure boolean, bandbool, extractChannel ops occur before sRGB conversion. + [#504](https://github.com/lovell/sharp/pull/504) + [@mhirsch](https://github.com/mhirsch) + +* Recalculate factors after WebP shrink-on-load to avoid round-to-zero errors. + [#508](https://github.com/lovell/sharp/issues/508) + [@asilvas](https://github.com/asilvas) + +* Prevent boolean errors during extract operation. + [#511](https://github.com/lovell/sharp/pull/511) + [@mhirsch](https://github.com/mhirsch) + #### v0.15.1 - 12th July 2016 * Concat Stream-based input in single operation for ~+3% perf and less GC. diff --git a/src/pipeline.cc b/src/pipeline.cc index 78223750..3e440525 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -338,7 +338,7 @@ class PipelineWorker : public AsyncWorker { } } - // If integral x and y shrink are equal, try to use libjpeg shrink-on-load, + // If integral x and y shrink are equal, try to use shrink-on-load for JPEG and WebP, // but not when applying gamma correction or pre-resize extract int shrink_on_load = 1; if ( @@ -361,13 +361,6 @@ class PipelineWorker : public AsyncWorker { } } if (shrink_on_load > 1) { - // Recalculate integral shrink and double residual - xfactor = std::max(xfactor, 1.0); - yfactor = std::max(yfactor, 1.0); - xshrink = std::max(1, static_cast(floor(xfactor))); - yshrink = std::max(1, static_cast(floor(yfactor))); - xresidual = static_cast(xshrink) / xfactor; - yresidual = static_cast(yshrink) / yfactor; // Reload input using shrink-on-load VOption *option = VImage::option()->set("shrink", shrink_on_load); if (baton->bufferInLength > 1) { @@ -389,6 +382,26 @@ class PipelineWorker : public AsyncWorker { image = VImage::webpload(const_cast((baton->fileIn).data()), option); } } + // Recalculate integral shrink and double residual + int shrunkOnLoadWidth = image.width(); + int shrunkOnLoadHeight = image.height(); + if (!baton->rotateBeforePreExtract && + (rotation == VIPS_ANGLE_D90 || rotation == VIPS_ANGLE_D270)) { + // Swap input output width and height when rotating by 90 or 270 degrees + std::swap(shrunkOnLoadWidth, shrunkOnLoadHeight); + } + xfactor = static_cast(shrunkOnLoadWidth) / static_cast(targetResizeWidth); + yfactor = static_cast(shrunkOnLoadHeight) / static_cast(targetResizeHeight); + xshrink = std::max(1, static_cast(floor(xfactor))); + yshrink = std::max(1, static_cast(floor(yfactor))); + xresidual = static_cast(xshrink) / xfactor; + yresidual = static_cast(yshrink) / yfactor; + if ( + !baton->rotateBeforePreExtract && + (rotation == VIPS_ANGLE_D90 || rotation == VIPS_ANGLE_D270) + ) { + std::swap(xresidual, yresidual); + } } // Ensure we're using a device-independent colour space diff --git a/test/unit/resize.js b/test/unit/resize.js index cf134e17..62bff466 100644 --- a/test/unit/resize.js +++ b/test/unit/resize.js @@ -128,6 +128,27 @@ describe('Resize dimensions', function() { done(); }); + it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', function(done) { + sharp(fixtures.inputJpg) + .resize(1080, 607) + .webp() + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual('webp', info.format); + assert.strictEqual(1080, info.width); + assert.strictEqual(607, info.height); + sharp(data) + .resize(233, 131) + .toBuffer(function(err, data, info) { + if (err) throw err; + assert.strictEqual('webp', info.format); + assert.strictEqual(233, info.width); + assert.strictEqual(131, info.height); + done(); + }); + }); + }); + if (sharp.format.tiff.input.file) { it('TIFF embed known to cause rounding errors', function(done) { sharp(fixtures.inputTiff)