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)