linebender / parley

Rich text layout library
Apache License 2.0
158 stars 18 forks source link

Implement simple example using swash to render to png #54

Closed nicoburns closed 1 month ago

nicoburns commented 1 month ago

This is basically working. But it could definitely do with some actual review and cleanup before merging.

Output

output

Notes

dfrg commented 1 month ago

Emoji rendering is not working

We lost this in the switch to fontique. I can submit a small patch to fix it.

Subpixel rendering is not enabled (does this make sense when rendering to image?)

Probably not unless we’re just doing it for effect. Might be nice to add an option at some point.

The rendered text doesn't look fantastic.

Black on white without gamma correction is going to look “dirty”. Something simple like alpha.pow(1.0/2.2) would improve this a bit.

I'm not using the NormalizedCoords as they always seemed to be empty in my example (what are they for?)

These are the parameters for controlling interpolation in variable fonts. You should be able to feed the slice directly into ScalerBuilder::normalized_coords.

nicoburns commented 1 month ago

We lost this in the switch to fontique. I can submit a small patch to fix it.

Ah. Yes, it seems important!

Black on white without gamma correction is going to look “dirty”. Something simple like alpha.pow(1.0/2.2) would improve this a bit.

Perhaps using these functions? https://observablehq.com/@toja/color-blending-with-gamma-correction.

If I'm understanding correctly the correct process is:

These are the parameters for controlling interpolation in variable fonts. You should be able to feed the slice directly into ScalerBuilder::normalized_coords.

I see. Does this also need to be plugged in with skrifa?

dfrg commented 1 month ago

See #56 for a patch that might get emoji working with this example

dfrg commented 1 month ago

Perhaps using these functions? https://observablehq.com/@toja/color-blending-with-gamma-correction.

If I'm understanding correctly the correct process is:

  • Convert to float
  • Convert to linear rgb
  • Perform computation
  • Convert srgb
  • Convert to u8

We can do full sRGB if you'd like but I think just applying the power function to the alpha component will give us reasonably good results for the example.

These are the parameters for controlling interpolation in variable fonts. You should be able to feed the slice directly into ScalerBuilder::normalized_coords.

I see. Does this also need to be plugged in with skrifa?

It does. We use the LocationRef type there which is really just a wrapper for &[NormalizedCoord]. This unfortunately requires a type conversion and allocation as is done in xilem/masonry. We should probably change parley to use this type in the future.

nicoburns commented 1 month ago

We can do full sRGB if you'd like but I think just applying the power function to the alpha component will give us reasonably good results for the example.

The trouble I was having with apply pow to the alpha channel is that it's a u8 and I'm unable to apply a fractional power to a u8.

I have implemented an attempt at sRGB <-> Linear RGB conversion. Not sure if I've done it correctly (it's interesting that you suggest applying the curve to the alpha channel as the solution I've ended up with applies it to everything but the alpha channel!) as the result isn't obviously better (but it's good enough that it looks plausibly correct to me). I've left both functions in the code for the time being if you want to inspect them.

Naive:

output_naive

Gamma corrected:

output_gamma

It does. We use the LocationRef type there which is really just a wrapper for &[NormalizedCoord]. This unfortunately requires a type conversion and allocation as is done in xilem/masonry. We should probably change parley to use this type in the future.

Ah, gotcha. I'll have a look at plugging this in tomorrow.

dfrg commented 1 month ago

Assuming this is using system-ui on macOS, setting the normalized coordinates should also get you the requested bold on the first four characters since San Francisco is a variable font.

nicoburns commented 1 month ago

Assuming this is using system-ui on macOS, setting the normalized coordinates should also get you the requested bold on the first four characters since San Francisco is a variable font.

Ah, that would be good. Bold was working with Helvetica, but it generally looked pretty bad with Helvetica so I switched it out. And I'd like to leave it on system-ui as that will presumably pick something sensible cross-platform. I guess maybe I could also use sans-serif?

nicoburns commented 1 month ago

Pretty sure my gamma correction function is wrong as the serif font looks much better with the naive blending.

dfrg commented 1 month ago

Pretty sure my gamma correction function is wrong as the serif font looks much better with the naive blending.

Yeah, this is exceptionally tricky to get right. I’ll play with it later this evening.

nicoburns commented 1 month ago

I'm assuming that once the other (tiny-skia) lands, this will move to a crate as well?

Yes. Hoping to land the tiny-skia one (#55) first. Will update this one once we've settled on a design there.

nicoburns commented 1 month ago

Pretty sure my gamma correction function is wrong as the serif font looks much better with the naive blending.

Yeah, this is exceptionally tricky to get right. I’ll play with it later this evening.

Hmm... the image crate (that we're already using here) has a blend function (https://docs.rs/image/latest/image/struct.Rgba.html#method.blend). Perhaps we could just use that. Looks the same as my "naive" version to me, but it certainly makes the example shorter.

EDIT: I've update this PR to use image's built in blend function. Old code is still available in an older commit if you want to play with it.

nicoburns commented 1 month ago

These are the parameters for controlling interpolation in variable fonts. You should be able to feed the slice directly into ScalerBuilder::normalized_coords.

@dfrg Hmm.. I've added this, but I still don't seem to get bold text.

dfrg commented 1 month ago

These are the parameters for controlling interpolation in variable fonts. You should be able to feed the slice directly into ScalerBuilder::normalized_coords.

@dfrg Hmm.. I've added this, but I still don't seem to get bold text.

Was just working on this :) Found a bug in swash's avar table. Update to swash 0.1.16 should fix it.

dfrg commented 1 month ago

Overall, this is looking pretty good to me now. I'm happy to punt on the gamma issue, get the tiny-skia version landed and then merge this one after making the crate extraction changes.

nicoburns commented 1 month ago

I've rebased this on top of latest main and made it fit the new directory structure. It is ready for another round of review.