RazrFalcon / tiny-skia

A tiny Skia subset ported to Rust
BSD 3-Clause "New" or "Revised" License
1.12k stars 69 forks source link

Linear blending? #5

Closed virtualritz closed 4 years ago

virtualritz commented 4 years ago

One of the things Skia gets right is that it uses linear color for all blending operations (as an aside it's also the only OSS vector graphics library I'm aware of that has proper color space support). The linear stuff is pretty important for anything that involves transparency. E.g. antialiasing. Aka: all colors get converted to linear before blended in any way and then converted back to whatever space they were in before, for display.

I just ran the stroke example and peeking at the edges of the lines I see the darkening in the semi-transparent pixels that is typical for blending wrongly in a gamma-corrected color space. It's easy to spot on the blue set of lines.

Of course I may be wrong and this artifact is coming from elsewhere.

RazrFalcon commented 4 years ago

Right now, tiny-skia supports only sRGB. I do plan to add LinearRGB eventually, but not in the first release.

virtualritz commented 4 years ago

Hmm, can you say what 'supports' means? Specifying colors in sRGB but they still get blended linearly, internally? That would be enough. I.e. I am not asking for specifying colors in linear quantities. I'm just asking if tiny-skia is correctly blending them internally.

RazrFalcon commented 4 years ago

Currently, tiny-skia works exactly the same as the Skia itself. So unless there is a bug that I've missed, this is the expected result.

Skia supports linear color space as an option, which is not enabled by default. And this is how tiny-skia works.

RazrFalcon commented 4 years ago

I've just recreated the stroke example in Skia and it produces exactly the same result. Pixel-perfect. So it's not a bug.

virtualritz commented 4 years ago

Maybe it's something else. I just realized the stroke example has no background. So what I'm seeing is the Preview utility of macOS doing alpha compositing. Maybe what is missing/wrong is the color encoding in the PNG that the stroke example writes.

Heaps sorry about the noise. I will investigate and re-open, if necessary.

RazrFalcon commented 4 years ago

No problem. The library is still in an alpha stage, so anything can happen.

virtualritz commented 4 years ago

The library is still in an alpha stage, so anything can happen.

Hehe, I'm using for drawing UI elements for a real product. I'll post screenshots soon.

virtualritz commented 4 years ago

Btw, I was referring to this. Apparently you can use Skia w/o correct color so that may or may not explain why your result matches Skia's.

RazrFalcon commented 4 years ago

Yes, color spaces are not supported and it's a very complex task. I do plan implementing LinearRGB, but I'm not sure about ICC. It's just too much work.

virtualritz commented 4 years ago

You only need to have a way to annotate any bitmap with a color space and single colors, e.g. for strokes, fills or ramps, you can store linear right away. Maybe use palette to do the heavy lifting for all that?

The important bit is that premultiplication/unpremutiplication/filtering/blending should only ever happen in linear. And for that you need at least 16bit precision per component (u16/f16(half)) but probably fastest on most architectures is just f32. That is pretty much what you wrote: linear RGB. That's all you ever need to do.

I'm happy to help out if there are questions.

RazrFalcon commented 4 years ago

Yes, I know how to implement this. But it would not be available in v0.2, i.e. anytime soon.

virtualritz commented 3 years ago

Hehe, I'm using for drawing UI elements for a real product. I'll post screenshots soon.

Screen shot from an AfterEffects plug-in I'm working on. The Envelope widget is drawn withtiny-skia. All other widgets are host app native btw.:

Screen Shot 2020-10-26 at 01 48 05

RazrFalcon commented 3 years ago

Nice!