Recalc after WebP shrink-on-load to avoid rounding errors #508

This commit is contained in:
Lovell Fuller 2016-07-21 15:18:14 +01:00
parent a2ec3642bf
commit a5bd68ef8c
3 changed files with 56 additions and 8 deletions

View File

@ -4,6 +4,20 @@
Requires libvips v8.3.1 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 - 12<sup>th</sup> July 2016 #### v0.15.1 - 12<sup>th</sup> July 2016
* Concat Stream-based input in single operation for ~+3% perf and less GC. * Concat Stream-based input in single operation for ~+3% perf and less GC.

View File

@ -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 // but not when applying gamma correction or pre-resize extract
int shrink_on_load = 1; int shrink_on_load = 1;
if ( if (
@ -361,13 +361,6 @@ class PipelineWorker : public AsyncWorker {
} }
} }
if (shrink_on_load > 1) { 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<int>(floor(xfactor)));
yshrink = std::max(1, static_cast<int>(floor(yfactor)));
xresidual = static_cast<double>(xshrink) / xfactor;
yresidual = static_cast<double>(yshrink) / yfactor;
// Reload input using shrink-on-load // Reload input using shrink-on-load
VOption *option = VImage::option()->set("shrink", shrink_on_load); VOption *option = VImage::option()->set("shrink", shrink_on_load);
if (baton->bufferInLength > 1) { if (baton->bufferInLength > 1) {
@ -389,6 +382,26 @@ class PipelineWorker : public AsyncWorker {
image = VImage::webpload(const_cast<char*>((baton->fileIn).data()), option); image = VImage::webpload(const_cast<char*>((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<double>(shrunkOnLoadWidth) / static_cast<double>(targetResizeWidth);
yfactor = static_cast<double>(shrunkOnLoadHeight) / static_cast<double>(targetResizeHeight);
xshrink = std::max(1, static_cast<int>(floor(xfactor)));
yshrink = std::max(1, static_cast<int>(floor(yfactor)));
xresidual = static_cast<double>(xshrink) / xfactor;
yresidual = static_cast<double>(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 // Ensure we're using a device-independent colour space

View File

@ -128,6 +128,27 @@ describe('Resize dimensions', function() {
done(); 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) { if (sharp.format.tiff.input.file) {
it('TIFF embed known to cause rounding errors', function(done) { it('TIFF embed known to cause rounding errors', function(done) {
sharp(fixtures.inputTiff) sharp(fixtures.inputTiff)