takkaO / OpenFontRender

TTF font render support library for microcomputer.
Other
105 stars 16 forks source link

Text alignment seems shifted down about 50% of glyph height #38

Open scottchiefbaker opened 7 months ago

scottchiefbaker commented 7 months ago

I'm using setAlignment() to align text to the corners of my TFT and I'm getting odd results. No matter what I do, text always seems to be shifted down about half a glyph worth. I have tried having OFR render to the TFT and to a sprite and both exhibit the same problem. I suspect there is a minor math bug in the alignment code? Am I crazy?

Here is my super simplified use case:

#include "OpenFontRender.h"
OpenFontRender ofr;

#include "NotoSans_Bold.h"
#define TTF_FONT NotoSans_Bold
#include <SPI.h>
#include <TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();

void setup(void) {
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(TFT_GREEN);

  ofr.setDrawer(tft);
  ofr.loadFont(TTF_FONT, sizeof(TTF_FONT));
  ofr.setBackgroundFillMethod(BgFillMethod::Block);

  ofr.setFontSize(80);
  ofr.setFontColor(TFT_WHITE, TFT_BLACK);

  int width  = tft.width();
  int height = tft.height();

  ofr.setCursor(width, 0)     ; ofr.setAlignment(Align::TopRight)   ; ofr.printf("TR");
  ofr.setCursor(width, height); ofr.setAlignment(Align::BottomRight); ofr.printf("BR");
  ofr.setCursor(0, height)    ; ofr.setAlignment(Align::BottomLeft) ; ofr.printf("BL");
  ofr.setCursor(0, 0)         ; ofr.setAlignment(Align::TopLeft)    ; ofr.printf("TL");
}

void loop() { }

cyd

scottchiefbaker commented 7 months ago

I just landed #40 that also shows off the discrepancy.

chconnor commented 7 months ago

I was curious about this because I haven't seen the same behavior so I started digging in to it; I think the problem might be with the embedded NotoSans_Bold.h ?

Check this out: these are images from the "A" glyph in fontforge; on the right is NotoSans-Bold.ttf from my linux installation; on the left is the contents of NotoSans_Bold.h written to a file:

NotoSans_Bold_comparison

...as you can see, the bounding box height of the included NotoSans_Bold.h is strangely tall, which as far as I know would explain what you are seeing. The character also sits all the way at the bottom of the box, unlike the distribution version.

Maybe try generating your own .h file from a TTF and see if that fixes things? (I've done this with fontforge, if you need assistance with it.)

scottchiefbaker commented 6 months ago

I didn't even think about testing a different font. Good call!

This is the font used in ALL of the examples so I just copied it over. I will test with a different font and report back tomorrow.

chconnor commented 6 months ago

Here is a version of NotoSans_Bold.h that might work better. This is exported via fontforge from the one installed with linux.

ns.zip

EDIT: I notice that my .h is about 3 times larger than the included NotoSans_Bold.h... not sure why. It uses the same reduced set of characters. I bet there is some unnecessary metadata in my exported TTF that isn't needed, but I'm not enough of a font expert to immediately know what to remove.

scottchiefbaker commented 6 months ago

Have you tested this version of NotoSans with the above script does it align properly? I'll have to test when I have access to my board tonight.

chconnor commented 6 months ago

I have not.

scottchiefbaker commented 6 months ago

I tested with the updated version of the font you provided and I'm still seeing the same weird vertical offset:

noto-sans

Interesting enough, your version of the font has glyphs that are almost doubled in size? Also the lower left has as weird left margin as well (in both versions of the font).

scottchiefbaker commented 6 months ago

Just to be 100% thorough I tested with some other fonts as well: chrusty.h.gz, shortbaby.h.gz, freedom.h.gz

chrusty shortbaby freedom

A couple of them seemed to work pretty well, but certainly not all of them. Chrusty is closest, but even it has a 1px margin at the top of the top-left. Shortbaby has 1px margin on the top left, and a 1px border on the left of the bottom left.

Freedom is just as much of a mess at NotoSans_Bold

chconnor commented 6 months ago

Hmmm... I have no further ideas. :-) I compared chrusty to my version of noto sans and I don't see any significant difference in the metrics or glyphs that would explain this to me... they seem roughly the same in terms of that stuff, so I don't know why one would work and one would not.

Comparing Chrusty with Freedom is especially strange -- they are almost identical in terms of metadata (Chrusty has a kerning lookup table, but that should only affect X positioning?) but they behave differently in your test.

I checked with the ttf2afm utility and it didn't reveal anything obvious to me, but I'm out of my depth.

I wouldn't worry about the single left pixel margins or the overall size of the glyphs; AFAIK that's normal and expected (the background black box around the glyph is just intended to clear enough pixels to cover the drawing of the glyph, not the conceptual space the glyph takes up, as far as I know, so there will be some variation from letter to letter.)

But the overall centering does seem wrong, and I have no idea why. Looking through the code, my best guess is that OFR uses FT_Glyph_Get_CBox to get the bounding box (which is used for calculating alignment stuff) which AFAICT will call TT_Load_Glyph_Header in ttgload.c which loads the glyph bounding box from the data... but this is all guesswork, and anyway, the data (judging from ttf2afm) seems fine, so I don't know.

I'll stop guessing now. It's probably more annoying than helpful at this point. :-) Hopefully the dev will swoop in with some wisdom. :-) Maybe it's related to my reported issue with right alignment.

scottchiefbaker commented 6 months ago

I appreciate you helping me drill down. I think we've made a simple enough test case that the dev should be able to tackle things from here.

For now my application is working, I'm just manually adjusting the Y position up a couple of pixels. Not ideal, but it will get me by.

alba-ado commented 2 months ago

I have similar issues with fonts I have found on the web. But the bounding box is calculated correctly. I think maybe the text should be aligned based on the bounding box.

alba-ado commented 2 months ago

Screenshot from 2024-05-07 18-02-27

For anyone having the same issue, this workaround of calculating the bounding box and then subtracting its yMin value seems to do the trick.

But it is ugly.