Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Coverage Maps at Different Gamma Values #118

Open
overdrivenpotato opened this issue Jun 17, 2022 · 2 comments
Open

Support Coverage Maps at Different Gamma Values #118

overdrivenpotato opened this issue Jun 17, 2022 · 2 comments
Labels
enhancement New feature or request

Comments

@overdrivenpotato
Copy link

PR #115 fixes issue #114 by converting the output u8 values to sRGB after fontdue creates a coverage vector. However, when working with linear u8 values, a nonlinear function like sRGB maps u8 -> u8 values with some precision loss. When rendering text, it is also sometimes preferable to use an empirically determined gamma value like 1.45, which has the same precision issue.

This can probably be fixed by exposing a rasterization method that outputs Vec<f32>, or alternatively via a more clever API with the use of a Gamma trait in order to avoid the memory overhead of f32 values.

@mooman219
Copy link
Owner

When hand writing the vectorization, I did some AB testing with built in gamma correction which went largely unnoticeable. People that did notice it, preferred it without.

However, when working with linear u8 values, a nonlinear function like sRGB maps u8 -> u8 values with some precision loss.

Gamma correction processes work on images already, which typically have 8 bit channels, so I'm not convinced the 0.3% max precision loss is perceptible.


If you can provide convincing material (Like a PR) showing the legibility of output is noticeably improved by the small precision improvement without a significant cost to the performance, then we can use that to substantiate this issue.

@mooman219 mooman219 added the enhancement New feature or request label Jun 17, 2022
@overdrivenpotato
Copy link
Author

overdrivenpotato commented Jun 18, 2022

If you're rendering fontdue with some kind of linear blending (e.g. on a GPU), it looks fine. But if you're doing blending in a non-linear space it tends to look pretty bad in some cases:

gammatest

The top text in the above picture has a gamma adjustment, while the bottom does not (you might have to click through the image to view it in full quality). The blending is occurring in sRGB space. It's up to you whether you think the bottom text looks bad; to me it looks broken.

So naturally you can use a u8 -> u8 mapping, but this is worse than 0.3% error. For example, a value 2/255 gets mapped to 22/255 from sRGB to linear, while 3/255 becomes 28/255. So you lose the values 23, 24, 25, 26, 27, resulting in visible artifacts. And a performance problem now is that you now have to incur an entire other loop over the generated data to do that mapping, requiring more memory loads and stores.

What about adding a method like Font::rasterize_gamma<G: Gamma>(...), with a Gamma trait like:

trait Gamma {
    fn to_u8(linear: f32) -> u8;
}

(SIMD arguments left out for sake of example). This could be entirely inlined, avoiding both precision errors and the extra cost of a round trip through memory for every pixel. It would be trivial to implement simple truncation or rounding to keep the current behaviour.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants