Fonts rendering


#1

Hi Jules,

I am having some issue with the font rendering in Juce as the small fonts size are less readable than if rendered with freetype in another graphic toolkit.

Juce tends to add to much blur.

So far I’ve come up with two little mods that get things a bit better (still not perfect though)

in juce_GlyphArrangement.cpp

in FontGlyphAlphaMap::generate, I generate the second bitmap for fonts size bigger than 24 instead of the contrary in the current code.

in FontGlyphAlphaMap::createAlphaMapFromPath, I use a 4 time oversampling instead of a 16 one for fonts size smaller than 24.

Any ideas how to get things even better ?

Thanks,


#2

Oh no, not this old question again! Why do people keep complaining about this in juce, when nobody complains about the same thing on the Mac??

You second bitmap hack will just turn off sub-pixel kerning for normal fonts, which will make them look awful, and will waste memory doing it for large fonts where it’s not needed, so that’s really not a great idea. Changing the oversampling will give mixed results depending on the font and its size.

What you’re really asking for has been discussed many times before, e.g.:
http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=704&highlight=anti+font


#3

Not exactly.
I’m not looking for a font specific for small size as I already have things like that like kroeger one.

Fonts on mac are not blurred in a bad way.
If you take a close look, you’ll see that they even use strange color(not only shade version of the original color) so that the text is more readable. cleartype stuff.

I just underline the fact that fonts drawn using freetype in other toolkit just look better than the same one rendered in Juce.

So I think there is room for improvements.

my 2 cents,


#4

There’s a good discussion here:
http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=1921


#5

what about having 2 Typeface-specific options?

  • one about the desired antialiasing level
  • one about the need to round the starting (x,y) coordinate to integer boundaries so that fonts like mini7, Silkscreen, kroeger… can render as expected when centred and not in-between 2 pixels.

It could be expanded later-on with different anti-aliasing styles like the one in photoshop (sharp, strong, light…) but I don’t know how to do that.

BTW the minimal FreetypeLoader I posted some times ago is still there waiting to be used:
http://mdsp.smartelectronix.com/juce/FreetypeLoader.h
http://mdsp.smartelectronix.com/juce/FreetypeLoader.cpp


#6

I made some tests with Photoshop, and the rendering the same font, same size and same colour on same background colour looks far better in Photoshop (especially using the “sharp” setting) than in JUCE. It’s really true what MDSP says, small fonts look bad in JUCE. Sorry to say that. :?
I even tried with Silkscreen, and it always looks blurry.


#7

Photoshop will be doing exactly the same type of rendering as juce, but probably applying a gamma curve and filter to it, as well as using more accurate sub-pixel positioning. If juce didn’t have to draw the text fast, it could do all those things too!


#8

If I understand the whole concept in JUCE, the font glyphs are rendered as Images and cached, so it only takes much processing one time, to render the glyphs and then it is fast (just copying the cached bitmap to screen)? Would applying a gamma curve and postfilter (as you propose) really be a performance trade-off, as it has to be done only once?


#9

try to test it under different heights. in one of my projects i was using proggy and i experienced it was displaying perfectly without antialias at 13.1 height, not at fixed integer sizes.

probably silkscreen is the same and since it is made to look they way it is only at fixed size, experiment with the value, you should find the best way to display it.


#10

Incidentally, GlyphArrangement.cpp, line 148 makes it quite easy to tweak the number of grey levels used for the font rendering. I might try it for a while with 256 and see if it improves the overall appearance.


#11

Thanks for the tip, I wouldn’t have tried non integer-size by myself. It’s 7.4 for Silkscreen here. It’s easy to find it out in the Jucer with a Label while resizing the font in its properties.


#12

Ok peopz, I modified juce_GlyphArrangement.cpp a little bit. Now there’s gamma correction at virtually no CPU expense, and the fonts do look know much (!) better indeed than without correction.

Edit: This is true if the fonts are not dark. If they are dark, it makes the problem worse, so it would be nice if one could for a Font also set let’ say 3 levels of gamma-correction: none, mild, strong. But I leave that up to Jules :wink:

Check it out here:


(at left: with my gamma correction code, at right: original JUCE code)

To use my modification, replace the AlphaBitmapRenderer code by this code:

[code]class AlphaBitmapRenderer
{
uint8* const data;
const int stride;
uint8* lineStart;

    AlphaBitmapRenderer (const AlphaBitmapRenderer&);
    const AlphaBitmapRenderer& operator= (const AlphaBitmapRenderer&);

public:
    AlphaBitmapRenderer (uint8* const data_,
                         const int stride_) throw()
        : data (data_),
          stride (stride_)
    {
		if (haveToCreateGammaCorrectTable)
		{
			haveToCreateGammaCorrectTable=false;
			for (int i=0; i<256; i++)
			{
				float val=float(i)/255.0f;
				val=powf(val,0.5f);
				val*=255.0f;
				gammaCorrectTable[i]=(uint8)val;
			}
		}
    }

    forcedinline void setEdgeTableYPos (const int y) throw()
    {
        lineStart = data + (stride * y);
    }

    forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) const throw()
    {
		lineStart [x] = (uint8) gammaCorrectTable[alphaLevel];
    }

    forcedinline void handleEdgeTableLine (const int x, int width, const int alphaLevel) const throw()
    {
        uint8* d = lineStart + x;
		
        while (--width >= 0) *d++ = (uint8) gammaCorrectTable[alphaLevel];
    }
};[/code]

And put those 2 lines somewhere on the top of the same file:

uint8 gammaCorrectTable[256]; bool haveToCreateGammaCorrectTable=true;


#13

I’ve also experienced really strange issues with font sizes

I have several examples of 8px fonts in photoshop that when used with juce requires different sizes: 10.0 or 12.0 or even 10.01.

to illustrate that:

here’s a 8px font in photoshop with no anti-aliasing, I’ve added sizes 9 and 10 as comparison

and here’s the same in the jucer

as you can see in this example you need to use a size of 10 to have the same result.

to give a reference here is an AGG rendering using freetype_test.exe

and here is the font if you want to test it
http://mdsp.smartelectronix.com/juce/STAN0765.TTF

(I won’t leave it there for long though since I don’t remember if there are copyright issues with this one)


#14

BTW when you’ve found the correct size in juce you still need to use Justification::topLeft, using centred will result in blurry results.


#15

finally here a last example that I wish I could do in juce but actually doesn’t work (yet).

this is still a 8 px font rendered in photoshop, rescaled at sizes 8, 9, 10, 11, 12, 14, 18 with no anti-aliasing. and it’s still really usable.


#16

Gosh - a bit of gamma correction does make a big difference!

Very good - the only slight problem I can think of is that because it’s only applied to the pre-cached bitmaps, then it won’t match any fonts that are rendered using paths. But thanks, I might have a play around and see what I can do…


#17

Ooh my, this does make all the difference! We had already given up on proper font rendering but this looks fantastic!


#18

Sheesh! There’s nothing “improper” about it at the moment! :wink:

The trouble with this, though, is that a 0.5 gamma looks great for light-on-dark text, but makes a mess with dark text on a light background, for which you really need to push the gamma slightly in the other direction. But putting the gamma at this place in the rendering pipeline doesn’t let you do that. Adding gamma to all the graphics rendering is something it’d be great to add, and that’d let you set up to work really well for all text.


#19

I think, if you use just like 16 lookup tables or so, you have enough gamma steps (8 positive, 8 negative) and you can adapt to the situation, i.e. the font colour very well.


#20

Yes, it’s not a problem to create the tables, it’s just that you can’t do it to the glyph cache - you’d need to apply it when the glyph is getting drawn, because that’s when you know the colour, so it’d need to be done by the drawImage methods.