Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fontconvert: remap characters, for smaller custom fonts #395

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

nilclass
Copy link

@nilclass nilclass commented Jul 31, 2022

This change modifies fontconvert to add support for a new (optional) "remap" parameter.

If given, that parameter replaces the glyphs for certain characters with glyphs of a different character.

It's interpreted as a utf8 encoded string of pairs of characters, for example xy! 😉 would mean: for character x, put the glyph of y into the font, and for the character ! put the winking emoji into the font.

This way a font can be created which still only contains a single contiguous range of characters (thus stays small), while no longer being limited to 7 bit ASCII.

The downside of this approach is, that the characters as they appear in the code won't show up on screen the same way.

Example:

Suppose I need the following set of characters: 0123456789+-.%°.
The first 14 characters are all in the ASCII plane, so without remapping, I could get them by converting the range 37 (%) to 57 (9):

./fontconvert FreeSerifBold.ttf 24 37 57

(° is not on the ASCII plane, so I couldn't get that character this way, no matter the range).

Note that even though I needed only 15 characters, I had to specify a 20 character range to get only 14 of them. There are 6
characters (&'()*,/) for which glyphs will be included as well, but I'll never use those.

This isn't ideal, so "remap" to the rescue!

First I'm choosing an ASCII range that includes as many of the characters as I need, by having as little extra characters as
possible.
In this case that range is 43 (+) to 57 (9), which has two characters I don't need: , and /. Luckily I also have two characters which are not in that range (% and °).

By using the ° glyph for the , character and the % glyph for the / character, I get a single range of characters which contains only the symbols I need:

Charcode ASCII Glyph
43 + +
44 , °
45 - -
46 . .
47 / %
48 0 0
49 1 1
50 2 2
51 3 3
52 4 4
53 5 5
54 6 6
55 7 7
56 8 8
57 9 9

The remap parameter for this case is ,°/%:

./fontconvert FreeSerifBold.ttf 24 43 57 ,°/%

From arduino code then, I can just write:

  display.display("37.5,");

Which will render "37.5°".

Add support for a new (optional) "remap" parameter for `fontconvert`.

If given, that parameter replaces the glyphs for certain characters
with glyphs of a different character.

This way a font can be created which contains a single contiguous
range of characters, without being limited to 7 bit ASCII.

The downside of this approach is, that the characters as they appear
in the code won't show up on screen the same way.

Example:

Suppose I need the following set of characters: `0123456789+-.%°`.
The first 14 characters are all in the ASCII plane, so without
remapping, I could get them by converting the range 37 (%) to 57 (9):

    ./fontconvert FreeSerifBold.ttf 24 37 57

(`°` is not on the ASCII plane, so I cannot get that character, no
matter the range).

Note that even though I needed only 15 characters, I had to specify a
20 character range to get only 14 of them. There are 6
characters (`&'()*,/`) for which glyphs will be included as well, but
I'll never use them.

This isn't ideal, so "remap" to the rescue!

First I'm choosing an ASCII range that includes as many of the
characters as I need, by having as little extra characters as
possible.
In this case that range is 43 (`+`) to 57 (`9`), which has two
characters I don't need: `,` and `/`. Luckily I also have two
characters which are *not* in that range (`%` and `°`).

By using the `°` glyph for the `,` character and the `%` glyph for the
`/` character, I get a contigious range of characters which contains
only the symbols I need:

| Charcode | ASCII | Glyph |
|----------|-------|-------|
| 43       | `+`   | `+`   |
| 44       | `,`   | `°`   |
| 45       | `-`   | `-`   |
| 46       | `.`   | `.`   |
| 47       | `/`   | `%`   |
| 48       | `0`   | `0`   |
| 49       | `1`   | `1`   |
| 50       | `2`   | `2`   |
| 51       | `3`   | `3`   |
| 52       | `4`   | `4`   |
| 53       | `5`   | `5`   |
| 54       | `6`   | `6`   |
| 55       | `7`   | `7`   |
| 56       | `8`   | `8`   |
| 57       | `9`   | `9`   |

The remap parameter for this case is `,°/%`:

    ./fontconvert FreeSerifBold.ttf 24 43 57 ,°/%

From arduino code then, I can just write:

  display.display("37.5,");

Which will render "37.5°".
@nilclass nilclass mentioned this pull request Jul 31, 2022
@liyong4github
Copy link

@nilclass hello,
When I try to replace one character, fontconvert prompts Assertion failed:*input, line 340; and when I try to replace two characters, it outputs the font header file normally, but the replacement character is not displayed.(what I want glyph is ℃ and ℉)
Can you help me, thanks!

@nilclass
Copy link
Author

@liyong4github

Unfortunately I cannot reproduce those issues.

When I try to replace one character, fontconvert prompts Assertion failed:*input, line 340

Running

./fontconvert /usr/share/fonts/truetype/freefont/FreeSerifBold.ttf 24 43 57 ,℃

works for me, and produces

const uint8_t FreeSerifBold24pt7bCustomBitmaps[] PROGMEM = {
  0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78,
  0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00,
  0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x0F, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFC, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01,
  0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00,
  0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x0F, 0x80,
  0x00, 0x3F, 0xC0, 0x21, 0xFE, 0x00, 0x1F, 0xFF, 0x06, 0x38, 0x70, 0x07,
  0xF0, 0x7C, 0xE6, 0x03, 0x00, 0xFC, 0x01, 0xFE, 0x60, 0x38, 0x1F, 0x80,
  0x07, 0xEC, 0x01, 0x83, 0xF0, 0x00, 0x3E, 0xC0, 0x18, 0x7F, 0x00, 0x01,
  0xEC, 0x01, 0x8F, 0xE0, 0x00, 0x1E, 0xC0, 0x18, 0xFE, 0x00, 0x00, 0xE6,
  0x03, 0x9F, 0xE0, 0x00, 0x06, 0x60, 0x31, 0xFC, 0x00, 0x00, 0x63, 0x87,
  0x1F, 0xC0, 0x00, 0x02, 0x1F, 0xE3, 0xFC, 0x00, 0x00, 0x00, 0xF8, 0x3F,
  0xC0, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0,
  0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x00,
  0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00,
  0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x00,
  0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x00, 0x01,
  0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFE,
  0x00, 0x00, 0x20, 0x00, 0x07, 0xF0, 0x00, 0x07, 0x00, 0x00, 0x3F, 0x00,
  0x00, 0xE0, 0x00, 0x01, 0xF8, 0x00, 0x1C, 0x00, 0x00, 0x0F, 0xC0, 0x07,
  0x80, 0x00, 0x00, 0x7F, 0x01, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0x00,
  0x00, 0x00, 0x03, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
  0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x00, 0x1E, 0x00, 0x7C,
  0x00, 0xF0, 0x01, 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x00,
  0xF0, 0x01, 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x00, 0xF0,
  0x01, 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x00, 0xF0, 0x01,
  0xE0, 0x03, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0xF0, 0x01, 0xE0,
  0x03, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0xF0, 0x00, 0x00, 0xFC,
  0x00, 0x0F, 0x3C, 0x00, 0x78, 0x78, 0x03, 0xE1, 0xF0, 0x1F, 0x03, 0xE0,
  0x7C, 0x0F, 0x83, 0xF0, 0x3F, 0x0F, 0xC0, 0xFC, 0x7F, 0x03, 0xF9, 0xFC,
  0x0F, 0xE7, 0xF0, 0x3F, 0xBF, 0xC0, 0xFE, 0xFF, 0x03, 0xFF, 0xFC, 0x0F,
  0xFF, 0xF0, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xFF, 0xFC, 0x0F, 0xFF,
  0xF0, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0,
  0x3F, 0x9F, 0xC0, 0xFE, 0x7F, 0x03, 0xF9, 0xFC, 0x0F, 0xE3, 0xF0, 0x3F,
  0x0F, 0xC0, 0xFC, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x80, 0xF8, 0x7C, 0x01,
  0xE1, 0xE0, 0x03, 0xCF, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x0C, 0x00, 0x0F,
  0x00, 0x0F, 0xC0, 0x0F, 0xF0, 0x0F, 0xFC, 0x0D, 0xFF, 0x00, 0x3F, 0xC0,
  0x0F, 0xF0, 0x03, 0xFC, 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0x0F, 0xF0, 0x03,
  0xFC, 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0x0F, 0xF0, 0x03, 0xFC, 0x00, 0xFF,
  0x00, 0x3F, 0xC0, 0x0F, 0xF0, 0x03, 0xFC, 0x00, 0xFF, 0x00, 0x3F, 0xC0,
  0x0F, 0xF0, 0x03, 0xFC, 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0x0F, 0xF0, 0x03,
  0xFC, 0x00, 0xFF, 0x00, 0x7F, 0xC0, 0x3F, 0xF8, 0xFF, 0xFF, 0xC0, 0x00,
  0xFC, 0x00, 0x1F, 0xF8, 0x03, 0xFF, 0xE0, 0x3F, 0xFF, 0x81, 0xFF, 0xFC,
  0x1C, 0x1F, 0xF1, 0xC0, 0x7F, 0x8C, 0x01, 0xFC, 0x40, 0x0F, 0xE0, 0x00,
  0x3F, 0x00, 0x01, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x7C, 0x00, 0x03, 0xE0,
  0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x07,
  0x00, 0x00, 0x70, 0x00, 0x07, 0x80, 0x00, 0x38, 0x00, 0x03, 0x80, 0x00,
  0x38, 0x01, 0x03, 0x80, 0x18, 0x38, 0x00, 0x81, 0x80, 0x1C, 0x1F, 0xFF,
  0xE1, 0xFF, 0xFF, 0x1F, 0xFF, 0xF9, 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0xFF,
  0xFF, 0xE0, 0x00, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0xFF, 0xFE, 0x06, 0x1F,
  0xF8, 0x20, 0x1F, 0xF1, 0x80, 0x7F, 0xC4, 0x00, 0xFF, 0x00, 0x03, 0xFC,
  0x00, 0x0F, 0xF0, 0x00, 0x3F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00,
  0x1F, 0x80, 0x00, 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x3F, 0xFC, 0x00, 0x3F,
  0xF8, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x00, 0x01, 0xFC,
  0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00,
  0x01, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1C, 0x3C, 0x00, 0x71, 0xFC, 0x03,
  0x87, 0xF8, 0x0C, 0x1F, 0xF8, 0xE0, 0x3F, 0xFE, 0x00, 0x3F, 0xC0, 0x00,
  0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x80, 0x01,
  0xFC, 0x00, 0x0F, 0xE0, 0x00, 0xFF, 0x00, 0x0D, 0xF8, 0x00, 0xEF, 0xC0,
  0x06, 0x7E, 0x00, 0x63, 0xF0, 0x07, 0x1F, 0x80, 0x30, 0xFC, 0x03, 0x07,
  0xE0, 0x38, 0x3F, 0x03, 0x81, 0xF8, 0x18, 0x0F, 0xC1, 0xC0, 0x7E, 0x1C,
  0x03, 0xF0, 0xC0, 0x1F, 0x8E, 0x00, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xF0, 0x00,
  0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF8,
  0x00, 0x0F, 0xC0, 0x03, 0xFF, 0xF8, 0x1F, 0xFF, 0xC1, 0xFF, 0xFC, 0x0F,
  0xFF, 0xE0, 0x7F, 0xFF, 0x07, 0xFF, 0xF0, 0x30, 0x00, 0x01, 0x80, 0x00,
  0x0C, 0x00, 0x00, 0xC0, 0x00, 0x07, 0xF0, 0x00, 0x3F, 0xF8, 0x03, 0xFF,
  0xF0, 0x1F, 0xFF, 0xC0, 0xFF, 0xFF, 0x07, 0xFF, 0xFC, 0x3F, 0xFF, 0xE0,
  0x01, 0xFF, 0x80, 0x03, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x1F, 0x00, 0x00,
  0x78, 0x00, 0x01, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x60, 0x00, 0x03, 0x0F,
  0x00, 0x10, 0xFE, 0x01, 0x87, 0xFC, 0x38, 0x3F, 0xFF, 0x80, 0xFF, 0xF0,
  0x03, 0xFE, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00,
  0x0F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF8,
  0x00, 0x0F, 0xE0, 0x00, 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x0F, 0xF0, 0x00,
  0x7F, 0x80, 0x01, 0xFF, 0xFC, 0x07, 0xFF, 0xFC, 0x3F, 0xE3, 0xF8, 0xFF,
  0x07, 0xF3, 0xFC, 0x1F, 0xEF, 0xF0, 0x7F, 0xBF, 0xC0, 0xFF, 0xFF, 0x03,
  0xFF, 0xFC, 0x0F, 0xFF, 0xF0, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xFD,
  0xFC, 0x0F, 0xF7, 0xF0, 0x3F, 0x9F, 0xC0, 0xFE, 0x3F, 0x03, 0xF8, 0x7E,
  0x0F, 0xC1, 0xF8, 0x3E, 0x03, 0xE1, 0xF0, 0x03, 0xC7, 0x80, 0x03, 0xF8,
  0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0xFF, 0xFF, 0xE7,
  0xFF, 0xFF, 0x3F, 0xFF, 0xF9, 0x80, 0x07, 0x98, 0x00, 0x3C, 0xC0, 0x03,
  0xE4, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00,
  0x03, 0xC0, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0xF0,
  0x00, 0x07, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x01,
  0xF0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x07, 0xC0, 0x00, 0x3C, 0x00,
  0x01, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C,
  0x00, 0x01, 0xFE, 0x00, 0x3C, 0x3C, 0x03, 0xC0, 0xF0, 0x3C, 0x07, 0xC3,
  0xE0, 0x1F, 0x3F, 0x00, 0xF9, 0xF8, 0x07, 0xCF, 0xE0, 0x3E, 0x7F, 0x01,
  0xF3, 0xFC, 0x0F, 0x1F, 0xF0, 0xF8, 0x7F, 0xC7, 0x83, 0xFF, 0xF0, 0x0F,
  0xFE, 0x00, 0x3F, 0xFC, 0x00, 0xFF, 0xF0, 0x03, 0xFF, 0xC0, 0x0F, 0xFF,
  0x03, 0xDF, 0xFC, 0x3C, 0x7F, 0xE3, 0xC0, 0xFF, 0x3E, 0x03, 0xFF, 0xE0,
  0x0F, 0xFF, 0x00, 0x7F, 0xF8, 0x03, 0xFF, 0xC0, 0x0F, 0xFE, 0x00, 0x7F,
  0xF0, 0x03, 0xE7, 0xC0, 0x1F, 0x3E, 0x01, 0xF8, 0xF8, 0x0F, 0x83, 0xE0,
  0xF8, 0x0F, 0xFF, 0x00, 0x0F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x1E, 0x3C,
  0x00, 0xF8, 0x7C, 0x07, 0xC1, 0xF8, 0x3F, 0x07, 0xE1, 0xFC, 0x0F, 0xC7,
  0xF0, 0x3F, 0x9F, 0xC0, 0xFE, 0xFF, 0x03, 0xFB, 0xFC, 0x0F, 0xFF, 0xF0,
  0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0, 0x3F,
  0xDF, 0xE0, 0xFF, 0x7F, 0x83, 0xFC, 0xFE, 0x0F, 0xF1, 0xFC, 0x7F, 0x83,
  0xFF, 0xFE, 0x03, 0xF7, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0x00, 0x03,
  0xF8, 0x00, 0x0F, 0xE0, 0x00, 0x7F, 0x00, 0x03, 0xF8, 0x00, 0x0F, 0xC0,
  0x00, 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x3F,
  0x00, 0x03, 0x80, 0x00, 0x00 };

const GFXglyph FreeSerifBold24pt7bCustomGlyphs[] PROGMEM = {
  {     0,  26,  25,  32,    3,  -24 },   // 0x2B '+'
  {    82,  44,  34,  47,    1,  -32 },   // 0x2C '℃'
  {   269,  11,   5,  16,    2,  -12 },   // 0x2D '-'
  {   276,   8,   8,  12,    2,   -6 },   // 0x2E '.'
  {   284,  15,  33,  13,   -1,  -32 },   // 0x2F '/'
  {   346,  22,  34,  23,    1,  -32 },   // 0x30 '0'
  {   440,  18,  33,  24,    3,  -32 },   // 0x31 '1'
  {   515,  21,  33,  24,    1,  -32 },   // 0x32 '2'
  {   602,  22,  34,  24,    0,  -32 },   // 0x33 '3'
  {   696,  21,  33,  24,    1,  -32 },   // 0x34 '4'
  {   783,  21,  32,  23,    1,  -31 },   // 0x35 '5'
  {   867,  22,  34,  24,    1,  -32 },   // 0x36 '6'
  {   961,  21,  32,  23,    1,  -31 },   // 0x37 '7'
  {  1045,  21,  34,  23,    1,  -32 },   // 0x38 '8'
  {  1135,  22,  34,  23,    1,  -32 } }; // 0x39 '9'

const GFXfont FreeSerifBold24pt7bCustom PROGMEM = {
  (uint8_t  *)FreeSerifBold24pt7bCustomBitmaps,
  (GFXglyph *)FreeSerifBold24pt7bCustomGlyphs,
  0x2B, 0x39, 52 };

// Approx. 1341 bytes

when I try to replace two characters, it outputs the font header file normally, but the replacement character is not displayed.

Could you provide an example of:

  • the exact fontconvert call you are using
  • the code you use to display the character?

@liyong4github
Copy link

@nilclass Hi,
The posting is my process for font conversion。
font_20240722081356

@nilclass
Copy link
Author

@liyong4github is there a space between the , and ? It is hard to see on that screenshot. There should not be a space, the whole remap part is a single argument.

@liyong4github
Copy link

@nilclass No space between , and °C, when running
fontconvert SimSun-01.ttf 12 43 57 ,℃/℉ > Simsun12pt.h
it produces

const uint8_t SimSun_0112pt7bCustomBitmaps[] PROGMEM = {
0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x41, 0xFF, 0xC1, 0x00, 0x20, 0x04,
0x00, 0x80, 0x10, 0x00, 0xFE, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18,
0x61, 0x86, 0x18, 0x7F, 0xFF, 0xC0, 0xFF, 0x80, 0x00, 0x40, 0x30, 0x08,
0x06, 0x01, 0x00, 0x40, 0x20, 0x08, 0x04, 0x01, 0x00, 0xC0, 0x20, 0x08,
0x04, 0x01, 0x00, 0x80, 0x20, 0x18, 0x04, 0x03, 0x00, 0x80, 0x00, 0x1E,
0x0C, 0xC6, 0x19, 0x86, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C,
0x0F, 0x03, 0x61, 0x98, 0x63, 0x30, 0x78, 0x08, 0xF8, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x3E,
0x21, 0xA0, 0x78, 0x3C, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x02,
0x02, 0x0A, 0x07, 0x03, 0xFF, 0x3C, 0x63, 0x30, 0xD8, 0x60, 0x30, 0x18,
0x18, 0x38, 0x03, 0x00, 0x80, 0x60, 0x3C, 0x1E, 0x0F, 0x0C, 0x78, 0x03,
0x00, 0x60, 0x1C, 0x05, 0x80, 0xB0, 0x26, 0x08, 0xC1, 0x18, 0x43, 0x10,
0x63, 0xFF, 0x81, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x7E, 0x7F, 0xA0, 0x10,
0x08, 0x04, 0x02, 0x01, 0x78, 0xC6, 0x41, 0x80, 0xC0, 0x78, 0x3C, 0x1C,
0x19, 0x0C, 0x7C, 0x0F, 0x0C, 0x66, 0x19, 0x80, 0x40, 0x30, 0x0C, 0xF3,
0x46, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0x40, 0xD8, 0x23, 0x18, 0x7C, 0x7F,
0xE0, 0xE0, 0x50, 0x40, 0x20, 0x30, 0x10, 0x08, 0x08, 0x04, 0x02, 0x03,
0x01, 0x80, 0xC0, 0x60, 0x30, 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0xD8,
0x27, 0x10, 0x78, 0x27, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x36, 0x18,
0x7C, 0x1E, 0x18, 0x46, 0x1B, 0x02, 0xC0, 0xF0, 0x3C, 0x0F, 0x07, 0x62,
0xCF, 0x30, 0x0C, 0x06, 0x01, 0x98, 0x46, 0x30, 0xF0 };

const GFXglyph SimSun_0112pt7bCustomGlyphs[] PROGMEM = {
{ 0, 11, 11, 12, 1, -13 }, // 0x2B '+'
{ 16, 6, 16, 8, 1, -15 }, // 0x2C '�'
{ 28, 10, 1, 12, 1, -8 }, // 0x2D '-'
{ 30, 3, 3, 12, 2, -2 }, // 0x2E '.'
{ 32, 10, 21, 12, 1, -18 }, // 0x2F '/'
{ 59, 10, 16, 12, 1, -15 }, // 0x30 '0'
{ 79, 8, 16, 12, 2, -15 }, // 0x31 '1'
{ 95, 9, 16, 12, 1, -15 }, // 0x32 '2'
{ 113, 9, 16, 12, 1, -15 }, // 0x33 '3'
{ 131, 11, 16, 12, 1, -15 }, // 0x34 '4'
{ 153, 9, 16, 12, 1, -15 }, // 0x35 '5'
{ 171, 10, 16, 12, 1, -15 }, // 0x36 '6'
{ 191, 9, 16, 12, 2, -15 }, // 0x37 '7'
{ 209, 10, 16, 12, 1, -15 }, // 0x38 '8'
{ 229, 10, 16, 12, 1, -15 } }; // 0x39 '9'

const GFXfont SimSun_0112pt7bCustom PROGMEM = {
(uint8_t *)SimSun_0112pt7bCustomBitmaps,
(GFXglyph *)SimSun_0112pt7bCustomGlyphs,
0x2B, 0x39, 27 };

// Approx. 361 bytes

@liyong4github
Copy link

And when I running
fontconvert SimSun-01.ttf 12 43 57 /℉ > Simsun12pt.h
it report
Unexpected end of remap after: H

@nilclass
Copy link
Author

@liyong4github the command looks correct to me. This could be an encoding issue. The remap parameter is expected to be UTF8 encoded. It's possible your terminal is using a different encoding.
You could try running chcp 65001 before running fontconvert to switch the terminal to UTF8.

@liyong4github
Copy link

Switched to utf encoding by chcp 65001 , but it's still the same as before

@liyong4github
Copy link

It's really an encoding issue, as I running fontconvert SimSun-01.ttf 12 43 57 /A > simsun12pt.h ,there is a correct output for me, but I don't know how to fix this

@liyong4github
Copy link

@nilclass There's a confusing question. when I running
fontconvert SimSun-01.ttf 12 43 57 /A
It can correctly output:

const uint8_t SimSun_0112pt7bCustomBitmaps[] PROGMEM = {
  0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x41, 0xFF, 0xC1, 0x00, 0x20, 0x04,
  0x00, 0x80, 0x10, 0x00, 0xDD, 0x95, 0x00, 0xFF, 0xC0, 0xFF, 0x80, 0x06,
  0x00, 0x60, 0x0A, 0x00, 0xB0, 0x09, 0x00, 0x90, 0x11, 0x81, 0x18, 0x10,
  0x81, 0xF8, 0x20, 0xC2, 0x0C, 0x20, 0x44, 0x04, 0x40, 0x6F, 0x0F, 0x1E,
  0x0C, 0xC6, 0x19, 0x86, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C,
  0x0F, 0x03, 0x61, 0x98, 0x63, 0x30, 0x78, 0x08, 0xF8, 0x18, 0x18, 0x18,
  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x3E,
  0x21, 0xA0, 0x78, 0x3C, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x02,
  0x02, 0x0A, 0x07, 0x03, 0xFF, 0x3C, 0x63, 0x30, 0xD8, 0x60, 0x30, 0x18,
  0x18, 0x38, 0x03, 0x00, 0x80, 0x60, 0x3C, 0x1E, 0x0F, 0x0C, 0x78, 0x03,
  0x00, 0x60, 0x1C, 0x05, 0x80, 0xB0, 0x26, 0x08, 0xC1, 0x18, 0x43, 0x10,
  0x63, 0xFF, 0x81, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x7E, 0x7F, 0xA0, 0x10,
  0x08, 0x04, 0x02, 0x01, 0x78, 0xC6, 0x41, 0x80, 0xC0, 0x78, 0x3C, 0x1C,
  0x19, 0x0C, 0x7C, 0x0F, 0x0C, 0x66, 0x19, 0x80, 0x40, 0x30, 0x0C, 0xF3,
  0x46, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0x40, 0xD8, 0x23, 0x18, 0x7C, 0x7F,
  0xE0, 0xE0, 0x50, 0x40, 0x20, 0x30, 0x10, 0x08, 0x08, 0x04, 0x02, 0x03,
  0x01, 0x80, 0xC0, 0x60, 0x30, 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0xD8,
  0x27, 0x10, 0x78, 0x27, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x36, 0x18,
  0x7C, 0x1E, 0x18, 0x46, 0x1B, 0x02, 0xC0, 0xF0, 0x3C, 0x0F, 0x07, 0x62,
  0xCF, 0x30, 0x0C, 0x06, 0x01, 0x98, 0x46, 0x30, 0xF0 };

const GFXglyph SimSun_0112pt7bCustomGlyphs[] PROGMEM = {
  {     0,  11,  11,  12,    1,  -13 },   // 0x2B '+'
  {    16,   3,   6,  12,    2,   -2 },   // 0x2C ','
  {    19,  10,   1,  12,    1,   -8 },   // 0x2D '-'
  {    21,   3,   3,  12,    2,   -2 },   // 0x2E '.'
  {    23,  12,  16,  12,    0,  -15 },   // 0x2F 'A'
  {    47,  10,  16,  12,    1,  -15 },   // 0x30 '0'
  {    67,   8,  16,  12,    2,  -15 },   // 0x31 '1'
  {    83,   9,  16,  12,    1,  -15 },   // 0x32 '2'
  {   101,   9,  16,  12,    1,  -15 },   // 0x33 '3'
  {   119,  11,  16,  12,    1,  -15 },   // 0x34 '4'
  {   141,   9,  16,  12,    1,  -15 },   // 0x35 '5'
  {   159,  10,  16,  12,    1,  -15 },   // 0x36 '6'
  {   179,   9,  16,  12,    2,  -15 },   // 0x37 '7'
  {   197,  10,  16,  12,    1,  -15 },   // 0x38 '8'
  {   217,  10,  16,  12,    1,  -15 } }; // 0x39 '9'

const GFXfont SimSun_0112pt7bCustom PROGMEM = {
  (uint8_t  *)SimSun_0112pt7bCustomBitmaps,
  (GFXglyph *)SimSun_0112pt7bCustomGlyphs,
  0x2B, 0x39, 27 };

// Approx. 349 bytes

And when running fontconvert SimSun-01.ttf 12 43 57 ,A, It will report an error “Unexpected end of remap after: A”

@nilclass
Copy link
Author

nilclass commented Jul 23, 2024

@liyong4github it's possible your terminal is doing something weird with that comma. Try quoting the entire remap parameter

@liyong4github
Copy link

@nilclass It doesn't work either. I tried to print ℃ via fprintf,it works. There is garbled code when I put it in the remap parameters.

@nilclass
Copy link
Author

@liyong4github

does this work for you?

const uint8_t SimSun12pt7bCustomBitmaps[] PROGMEM = {
  0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x41, 0xFF, 0xC1, 0x00, 0x20, 0x04,
  0x00, 0x80, 0x10, 0x00, 0x00, 0x00, 0x3C, 0x3F, 0x09, 0x18, 0x36, 0x4C,
  0x03, 0x66, 0x00, 0xC1, 0x00, 0x10, 0xC0, 0x04, 0x30, 0x00, 0x0C, 0x00,
  0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x04, 0x00, 0x01, 0x80, 0x00,
  0x60, 0x08, 0x0C, 0x06, 0x01, 0x86, 0x00, 0x1F, 0x00, 0xFF, 0xC0, 0xFF,
  0x80, 0x67, 0xFF, 0xE6, 0x20, 0x38, 0x88, 0x06, 0x62, 0x01, 0x70, 0x80,
  0x00, 0x20, 0x80, 0x08, 0x20, 0x03, 0xF8, 0x00, 0x86, 0x00, 0x20, 0x80,
  0x08, 0x20, 0x02, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x08, 0x00, 0x02,
  0x00, 0x03, 0xE0, 0x00, 0x1E, 0x0C, 0xC6, 0x19, 0x86, 0xC0, 0xF0, 0x3C,
  0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0x61, 0x98, 0x63, 0x30, 0x78,
  0x08, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
  0x18, 0x18, 0x18, 0xFF, 0x3E, 0x21, 0xA0, 0x78, 0x3C, 0x18, 0x0C, 0x0C,
  0x06, 0x06, 0x04, 0x04, 0x04, 0x14, 0x0C, 0x0F, 0xFF, 0xFF, 0x3C, 0x23,
  0x30, 0xD8, 0x6C, 0x30, 0x18, 0x18, 0x38, 0x03, 0x00, 0x80, 0x78, 0x3C,
  0x1E, 0x0D, 0x0C, 0x78, 0x01, 0x00, 0xC0, 0x70, 0x1C, 0x0B, 0x04, 0xC1,
  0x30, 0x8C, 0x43, 0x10, 0xC8, 0x33, 0xFF, 0x03, 0x00, 0xC0, 0x30, 0x0C,
  0x0F, 0xC0, 0x7F, 0xBF, 0xD0, 0x08, 0x04, 0x02, 0x01, 0x78, 0xC6, 0x41,
  0x80, 0xC0, 0x78, 0x3C, 0x1C, 0x19, 0x0C, 0x7C, 0x0F, 0x0C, 0x66, 0x19,
  0x80, 0x40, 0x30, 0x0C, 0xF3, 0x46, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0x40,
  0xD8, 0x23, 0x18, 0x7C, 0x7F, 0xFF, 0xF0, 0x50, 0x48, 0x20, 0x10, 0x10,
  0x08, 0x08, 0x04, 0x02, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x3F, 0x18,
  0x6C, 0x0F, 0x03, 0xC0, 0xF8, 0x27, 0x98, 0x78, 0x67, 0x10, 0xEC, 0x1F,
  0x03, 0xC0, 0xF0, 0x36, 0x18, 0x7C, 0x1E, 0x18, 0x46, 0x1B, 0x02, 0xC0,
  0xF0, 0x3C, 0x0F, 0x07, 0x62, 0xCF, 0x30, 0x0C, 0x06, 0x01, 0x98, 0x46,
  0x30, 0xF0 };

const GFXglyph SimSun12pt7bCustomGlyphs[] PROGMEM = {
  {     0,  11,  11,  12,    1,  -13 },   // 0x2B '+'
  {    16,  18,  18,  24,    3,  -17 },   // 0x2C '℃'
  {    57,  10,   1,  12,    1,   -8 },   // 0x2D '-'
  {    59,   3,   3,  12,    2,   -2 },   // 0x2E '.'
  {    61,  18,  17,  24,    2,  -17 },   // 0x2F '℉'
  {   100,  10,  16,  12,    1,  -15 },   // 0x30 '0'
  {   120,   8,  16,  12,    2,  -15 },   // 0x31 '1'
  {   136,   9,  16,  12,    1,  -15 },   // 0x32 '2'
  {   154,   9,  16,  12,    1,  -15 },   // 0x33 '3'
  {   172,  10,  17,  12,    1,  -16 },   // 0x34 '4'
  {   194,   9,  16,  12,    1,  -15 },   // 0x35 '5'
  {   212,  10,  16,  12,    1,  -15 },   // 0x36 '6'
  {   232,   9,  16,  12,    2,  -15 },   // 0x37 '7'
  {   250,  10,  16,  12,    1,  -15 },   // 0x38 '8'
  {   270,  10,  16,  12,    1,  -15 } }; // 0x39 '9'

const GFXfont SimSun12pt7bCustom PROGMEM = {
  (uint8_t  *)SimSun12pt7bCustomBitmaps,
  (GFXglyph *)SimSun12pt7bCustomGlyphs,
  0x2B, 0x39, 27 };

// Approx. 402 bytes

@liyong4github
Copy link

@nilclass it works, thank u!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants