diff --git a/CHANGELOG.md b/CHANGELOG.md index 26fb99743..63623f23d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ project adheres to [Semantic Versioning](http://semver.org/). ### Added ### Fixed * Load images from Node.js object URLs (#2525) +* Fix off-by-one RGB values from `getImageData` on semi-transparent pixels (#1933) 3.2.3 ================== diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 6183837c0..a203455df 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -1079,10 +1079,9 @@ Context2d::GetImageData(const Napi::CallbackInfo& info) { dst[bx + 2] = b; } else { // Undo alpha pre-multiplication - float alphaR = (float)255 / a; - dst[bx + 0] = (int)((float)r * alphaR); - dst[bx + 1] = (int)((float)g * alphaR); - dst[bx + 2] = (int)((float)b * alphaR); + dst[bx + 0] = (r * 255 + a / 2) / a; + dst[bx + 1] = (g * 255 + a / 2) / a; + dst[bx + 2] = (b * 255 + a / 2) / a; } } diff --git a/test/canvas.test.js b/test/canvas.test.js index b8c50b979..60e44e205 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -2224,6 +2224,15 @@ describe('Canvas', function () { assert.equal(result.data[255], 255) // not black or junk data assert.equal(result.data[255 * 256], 255) // not black or junk data }) + + it('round-trips semi-transparent pixels through getImageData (#1933)', function () { + const canvas = createCanvas(1, 1) + const ctx = canvas.getContext('2d') + ctx.putImageData(createImageData(new Uint8ClampedArray([252, 252, 252, 252]), 1), 0, 0) + assert.deepEqual(Array.from(ctx.getImageData(0, 0, 1, 1).data), [252, 252, 252, 252]) + ctx.putImageData(createImageData(new Uint8ClampedArray([255, 128, 1, 2]), 1), 0, 0) + assert.deepEqual(Array.from(ctx.getImageData(0, 0, 1, 1).data), [255, 128, 0, 2]) + }) }) it('Canvas#createPNGStream()', function (done) {