SixLabors / Fonts

:black_nib: Font loading and layout library.
https://sixlabors.com/products/fonts
Other
306 stars 71 forks source link

Small font rendering really unclear (blurry, missing pixels etc) #293

Closed myblindy closed 2 years ago

myblindy commented 2 years ago

Prerequisites

Description

Rendering small fonts is unreadable with alpha blending enabled, due to the really imprecise, blurry way they're being rendered:

ImageSharp (default antialiasing settings): image

GDI+ (clear type): image

This is with Segoe UI at 10 pixels. The vertical lines especially aren't clear, and with alpha blending enabled they just disappear.

I also tried disabling antialiasing in the ImageSharp render, but that makes it even more obvious how imprecise it is: image

I also tried hinting, which is supposed to help with this, but it doesn't seem to work at all: image

For Open Sans it's even less readable, and hinting just produces long vertical lines: image

Is there some set of options I can enable to make small font rendering clear?

Steps to Reproduce

I have a sample repo that I used to generate those images at https://github.com/myblindy/font_test

System Configuration

JimBobSquarePants commented 2 years ago

There's actually two issues here.

  1. The rasterizer. We need LCD rasterization to compete with System.Drawing. We just use alpha blending and it's simply no match. I know PixelFarm have an implementation but I don't know when I'd ever get round to adding it to ImageSharp.Drawing (that's where the rasterizer lives). @tocsoft have you ever dabbled in this?
image
  1. The hinting. That appears to be a problem with the X hinting and will require careful stepping through to figure out what is happening. That one is a little heartbreaking as I thought we'd cracked it. 😔

Y-only hinting seems to be fine. a

JimBobSquarePants commented 2 years ago

Noting that both XY and Y hinting work for the ttf version of OpenSans

a

myblindy commented 2 years ago

I had stopped using the ttf version because it crashed with NRE in the previous release, I'll give it a try again.

So far I have this:

Segoe UI with Y hinting, still very blurry, and the vertical lines are not straight, look at o in particular: image

Open Sans (ttf) with XY hinting, looks okay shape-wise, but everything is blurred (ie, high transparency which breaks alpha blending against a non-black background): image

Edit: after staring at it for a while longer, the XY hinted Open Sans is actually damn near perfect for me, I just need it to have a solid white foundation and the antialiasing parts to be around it as necessary for alpha blending to work. If you're familiar with SDF font rendering, the ImageSharp renderer behaves as if the edge of the font starts at 0 and it immediately starts losing alpha strength as it gets farther away (which of course is not what an edge is).

myblindy commented 2 years ago

Noting that both XY and Y hinting work for the ttf version of OpenSans

a

Also note that white text on a transparent background doesn't render on github, it's why I'm taking screen shots :)

JimBobSquarePants commented 2 years ago

Also note that white text on a transparent background doesn't render on github, it's why I'm taking screen shots :)

Haha! I completely forgot since I'm so used to dark mode! I'll update my images.

tocsoft commented 2 years ago

... @tocsoft have you ever dabbled in this? ...

nope not something i've experimented with, however I would say the issue with 'LCD' rendering is they only work for LCD displays (not paper etc) and also you need to know the subpixel layout of the screen and the exact position on the screen where it will render, you can't rasterize the pixels once and move them, for example, as moving the it half a pixel in any direction will cause the relative subpixels layout to be different in relation to the target.

JimBobSquarePants commented 2 years ago

@tocsoft Ah no, sorry. What I mean is colorized antialiasing as described here and used by Cleartype. https://www.grc.com/cttech.htm https://www.grc.com/cttech.htm

image

I know Antigrain have an implementation and PixelFarm wrote theirs based upon that but I'm not sure how we would integrate such an approach since we use the PixelBlender to do the rendering especially since we'd need to do it in a way that works with all our brushes like System.Drawing can as demonstrated with this linear brush example.

image
tocsoft commented 2 years ago

I knew what you meant, but that technique can only be useful when rendering to screen where you can take advantage of the color shifting of the pixels rendered, it will produce fringing and be pretty useless in any other medium, and you also can't composite the rendered text on to another picture (post generation as there is not transparency retained). So unless your planning on rendering the vectors and displaying them directly to screen then it'll be very likely to produce suboptimal results. This is all remembering that real time screen graphics rendering is not a scenario we are actually targeting with this library.

FYI, Antigrain and Cleartype (which System.Drawing uses cause its a relatively thin wrapper around the GDI screen rendering subsystem system) are both screen rendering technologies they where built to draw pixels on a screen which is why it makes sense for them.

JimBobSquarePants commented 2 years ago

@tocsoft Ah right... I wonder whether it is something we should consider in the future though as it seems more people are beginning to use the library in gaming. I guess they can simply bring their own rasterizer.

@myblindy Looks like I may be having some success with the interpreter. Here's Segoe UI at 10 pixels.

Hinting XY Assigning food to tree

No Hinting Assigning food to tree

Here's with (left) and without (right) hinting zoomed and compared.

image

I have a LOT of visual testing to do now.

myblindy commented 2 years ago

Definitely an improvement, great work!

I'll keep an eye on how this shapes up (no pun intended), but for now I switched to the tried and true System.Drawing to get a working baseline version of the code. In the medium-to-long-term when cross-platform starts to matter I'll revisit ImageSharp and SkiaSharp and see where we stand!