Skip to content

Fix rounding when un-premultiplying alpha in getImageData - #2622

Open
chiliec wants to merge 1 commit into
Automattic:masterfrom
chiliec:fix/getimagedata-unpremultiply-rounding
Open

chiliec wants to merge 1 commit into
Automattic:masterfrom
chiliec:fix/getimagedata-unpremultiply-rounding

Conversation

@chiliec

@chiliec chiliec commented Sep 20, 2026

Copy link
Copy Markdown

Fixes #1933

getImageData un-premultiplies semi-transparent pixels with (int)((float)r * ((float)255 / a)), which truncates. Because cairo's premultiplied channel is already rounded down, truncating again on the way back drops the value by one for most inputs: putImageData([252,252,252,252]) reads back as [251,251,251,252].

This switches to the integer round-half-up division that canvas_unpremultiply_data in src/PNG.h already uses ((c * 255 + a / 2) / a), so getImageData and PNG export un-premultiply identically. Fully transparent/opaque pixels keep the existing fast path.

Exhaustively checking every (value, alpha) pair with alpha in 1..254 (65,024 pixels): exact putImageData → getImageData round-trips go from 1,450 to 17,369, and no pixel gets worse; the remaining differences are the information lost by premultiplication itself.

  • Have you updated CHANGELOG.md?

Validation (linux x64, zig 0.16.0, node 22.12):

zig build
npx mocha test/canvas.test.js -g 1933   # fails before the change: [251,251,251,252]
npm test                                # 306 passing, 6 pending

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inaccurate RGB values due to a rounding error caused by premultiplication

1 participant