tchapi / Adafruit-GFX-Font-Customiser

A little utility to customise pixel fonts for the Adafruit GFX library
https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
MIT License
90 stars 47 forks source link

Oblique glyphs not completely shown: clipped at xAdvance #9

Closed BillyDonahue closed 4 years ago

BillyDonahue commented 4 years ago

For oblique glyphs, the xAdvance can be to the left of the right side of the glyph's bitmap bounding box. I'm including a test example which is just the SOLIDUS glyph from the FreeMonoBoldOblique24pt7b font. Clicking on the "+xAdv" input element of the Customizer page will reveal more of the glyph bitmap. But then the xAdv is being incorrectly set.

(I have my own diagnostic scripts for annotating the GFXfonts which I'm using to draw the bitmaps inline in the headers, as shown).

const uint8_t FreeMonoBoldOblique24pt7bBitmaps[] PROGMEM = {
0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x00,
0x00,0x01,0xF0,0x00,0x00,0x3E,0x00,0x00,
0x03,0xE0,0x00,0x00,0x7C,0x00,0x00,0x0F,
0x80,0x00,0x00,0xF8,0x00,0x00,0x1F,0x00,
0x00,0x03,0xE0,0x00,0x00,0x3E,0x00,0x00,
0x07,0xC0,0x00,0x00,0xF8,0x00,0x00,0x1F,
0x80,0x00,0x01,0xF0,0x00,0x00,0x3E,0x00,
0x00,0x07,0xE0,0x00,0x00,0x7C,0x00,0x00,
0x0F,0x80,0x00,0x01,0xF8,0x00,0x00,0x1F,
0x00,0x00,0x03,0xE0,0x00,0x00,0x7C,0x00,
0x00,0x07,0xC0,0x00,0x00,0xF8,0x00,0x00,
0x1F,0x00,0x00,0x01,0xF0,0x00,0x00,0x3E,
0x00,0x00,0x07,0xC0,0x00,0x00,0xFC,0x00,
0x00,0x0F,0x80,0x00,0x01,0xF0,0x00,0x00,
0x3F,0x00,0x00,0x03,0xE0,0x00,0x00,0x7C,
0x00,0x00,0x07,0xC0,0x00,0x00,0xF8,0x00,
0x00,0x07,0x00,0x00,0x00,  // 0x2F '/' (28 x 38) @(3,-32) +28
// [   .........................**.]
// [   ........................****]
// [   .......................*****]
// [   ......................*****.]
// [   ......................*****.]
// [   .....................*****..]
// [   ....................*****...]
// [   ....................*****...]
// [   ...................*****....]
// [   ..................*****.....]
// [   ..................*****.....]
// [   .................*****......]
// [   ................*****.......]
// [   ...............******.......]
// [   ...............*****........]
// [   ..............*****.........]
// [   .............******.........]
// [   .............*****..........]
// [   ............*****...........]
// [   ...........******...........]
// [   ...........*****............]
// [   ..........*****.............]
// [   .........*****..............]
// [   .........*****..............]
// [   ........*****...............]
// [   .......*****................]
// [   .......*****................]
// [   ......*****.................]
// [   .....*****..................]
// [   ....******..................]
// [   ....*****...................]
// [   ...*****....................]
// [0  ..******.................>..]
// [   ..*****.....................]
// [   .*****......................]
// [   .*****......................]
// [   *****.......................]
// [   .***........................]
};

const GFXglyph FreeMonoBoldOblique24pt7bGlyphs[] PROGMEM = {
  {0, 28, 38, 28, 3, -32} // 0x2F '/':SOLIDUS
};

const GFXfont FreeMonoBoldOblique24pt7b PROGMEM = {
    (uint8_t *)FreeMonoBoldOblique24pt7bBitmaps,
    (GFXglyph *)FreeMonoBoldOblique24pt7bGlyphs,
    0x2F, 0x2F, 47
};
tchapi commented 4 years ago

It seems that the GFXGlyph definition is not right then, it should be :

const GFXglyph FreeMonoBoldOblique24pt7bGlyphs[] PROGMEM = {
  {0, 28, 38, 31, 3, -32} // 0x2F '/':SOLIDUS
};

No ?

Or should we add the xOff automatically to the adv param (so as to make 31 ?). Is it what your diagnostic tool does ? I'm curious ... :)

BillyDonahue commented 4 years ago

No, the glyph definition is correct.

The fields are {bo,w,h,xa,xo,yo}.

{0, 28, 38, 28, 3, -32}

not

{0, 28, 38, 31, 3, -32}

It's an oblique font, so all the glyphs are slanted to the right, and adjacent glyphs can have overlapping bounding boxes. Because this glyph's xAdvance doesn't escape its bounding box, the following glyph will be tucked a little under this one. Some glyphs even have negative xOffset, so they can draw to the left of the origin and reach into their predecessor's box. It's all supposed to be anticipated by the font designer. They shouldn't overwrite each other's pixels as long as all the clustered chars are from the same consistent font.

My diagnostic tool calculates a rectangle that encloses the bitmap's edges, the origin, and the (xAdvance,0) point.

I can just show it to you. This thing will read a font header and spit it back out as another valid font header, but with comments containing all the glyph drawings and metadata comments, and with the glyph bitmap bytes separated out.

https://github.com/BillyDonahue/Adafruit-GFX-Library/blob/11acd7d925d29ff528ab50c24ce7448932ff11fd/fontconvert/gfxfont_annotate.py

The annotated fonts look like this: https://github.com/BillyDonahue/Adafruit-GFX-Library/tree/34adb94739acc1a4f74c885be9a899562bfbca05/fontconvert/Fonts.annotated.orig

tchapi commented 4 years ago

Ok, if I understand correctly, I should replace xadvance in this line :

https://github.com/tchapi/Adafruit-GFX-Font-Customiser/blob/master/index.html#L128

with xadvance + xoffset — wdyt ?

BillyDonahue commented 4 years ago

I don't think that's right. (My JS sux, sorry) you need the union of 2 boxes, so it's more like:

  var box_l = Math.min(0, xo);
  var box_t = Math.min(0, yo);
  var box_r = Math.max(xa, xo+w);
  var box_b = Math.max(ya, yo+h);
  for (var px_y = box_t; px_y <= box_b; ++px_y) {
    var grid_y = i - box_t;
    for (var px_x = box_l; px_x <= box_r ; ++px_x) {
      var grid_x = px_x - box_l;

      // paint grid cell (grid_x, grid_y) as logical pixel (px_x, px_y)
    }
  }
tchapi commented 4 years ago

Hmm. Except for the min/max calculations that I had missed, I think your loop is somehow equivalent to mine. I've created a branch with new modifications including yours: https://github.com/tchapi/Adafruit-GFX-Font-Customiser/tree/feature/xoffset

The forward / backward overlapping pixels are red-ish so it's easy to spot them. I'm always displaying xadvance + xoffset pixels for the characters.

As for the other issue, if you can have a look, that'd be great !

Thanks again !

BillyDonahue commented 4 years ago

The bounds are still not right, I think. Here try this:

https://billydonahue.github.io/Adafruit-GFX-Font-Customiser/

And feed it this test file:

https://billydonahue.github.io/Adafruit-GFX-Font-Customiser/test/BangOblique24pt7b.h

src is on branch: https://github.com/BillyDonahue/Adafruit-GFX-Font-Customiser/tree/mark_points_fix_bounds

The red paint is cool. One problem I had with it though, is that you can't see the xadvance point unless you cross it. So I also added a little marker on the origin and the xadvance point (which will be the next character's origin.

tchapi commented 4 years ago

Ok, good, I get it. It was close. Thanks so much !

Very good idea to add the two limits, I'll just change it to lines instead of cell borders, so as to keep the table cell widths consistent.

Is it ok for you if I put your name and Github profile link in the readme file, under "Contributors" ?

BillyDonahue commented 4 years ago

great. that was fun. thanks

On Wed, Jun 3, 2020 at 5:18 AM tchap notifications@github.com wrote:

Ok, good, I get it. It was close. Thanks so much !

Very good idea to add the two limits, I'll just change it to lines instead of cell borders, so as to keep the table cell widths consistent.

Is it ok for you if I put your name and Github profile link in the readme file, under "Contributors" ?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/tchapi/Adafruit-GFX-Font-Customiser/issues/9#issuecomment-638073354, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACBWORDX5OHEMXAO4FLHGG3RUYINJANCNFSM4NQDI6IA .

-- ǝnɥɐuop ʎllıq