Repository navigation
fix(render): interpolate gradients in sRGB and honour premultiplied alpha - #31
Open
leshchenko1979 wants to merge 1 commit into
Open
leshchenko1979 wants to merge 1 commit into
leshchenko1979 wants to merge 1 commit into
Conversation
…lpha CSS gradients interpolate in gamma-encoded sRGB, but the renderer blended in linear light and the SVG output asked for `color-interpolation="linearRGB"`, which is the SVG 1.1 default rather than what CSS specifies. Every gradient came out too bright: a red-to-blue ramp hit (188,0,188) at the midpoint where browsers give (128,0,128). The PNG path had a second defect: `image.RGBA` stores premultiplied pixels, but the loops wrote the straight colour next to the raw alpha. With `alpha == 0` that produces an invalid pixel, so a gradient fading to a transparent stop read back as a fade to black instead of to white. The interpolator also blended straight alpha, swinging the hue of a partially transparent stop pair. Both loops (linear and radial) now blend in premultiplied sRGB and store premultiplied RGB; the SVG defs request sRGB. Fixes Macawls#27 Fixes Macawls#30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Gradients were rendered in the wrong colour space, and PNG gradients that fade to a transparent stop came out black instead of transparent.
Fixes #27
Fixes #30
Why
#27 — colour space. CSS Images specifies gradient interpolation in gamma-encoded sRGB. The renderer blended in linear light and emitted
color-interpolation="linearRGB"in the SVG defs — legal per SVG 1.1, but not what CSS asks for. Ared → blueramp landed on(188,0,188)at the midpoint; Chromium gives(128,0,128).#30 — premultiplied alpha.
image.RGBAstores premultiplied pixels, but both gradient loops wrote the straight colour beside the raw alpha:With
s.a == 0that is an invalid premultiplied pixel. Composited onto white, a fade torgba(0,0,255,0)darkened towards black. The interpolator had the sibling bug of blending straight alpha, so a transparent stop pair swung the hue through a desaturated middle instead of holding the visible colour.How
render/background.go:color-interpolation="sRGB"for both<linearGradient>and<radialGradient>.render/png.go: the linear and radial loops now blend in premultiplied sRGB (interpolateStops, replacinginterpolateLinear+ thelinearToSrgbFround-trip) and store RGB scaled by alpha. The dead sRGB LUT is gone.-update; the diff is 5 lines, alllinearRGB→sRGB.Verification
21-case Chromium comparison harness (
% of pixels differing by >8 per channel), before → after:Alpha ramp
rgba(255,0,0,1) → rgba(0,0,255,0)sampled on a white composite, Ogre vs Chromium:Within 1/255 across the ramp.
New tests in
render/gradient_test.go, each confirmed to fail against the previous code:TestSVGLinearGradientUsesSRGB,TestSVGRadialGradientUsesSRGB— fail with the old defs (linearRGB).TestPNGGradientMidpointIsSRGB— fails on the old PNG path withmidpoint red = 187, want ~128.TestPNGGradientAlphaIsPremultiplied— every pixel must satisfychannel <= alpha; the transparent end must stay near-white on white.TestGradientInterpolationIsPremultiplied— ared → transparent bluemidpoint must keep red and drop blue.go test ./...andgo vet ./...pass.