Proje Defteri

Adafruit GFX Font Converter

Turn a TTF, OTF, WOFF or WOFF2 font into an Adafruit GFX header file. Preview every glyph pixel by pixel, watch the flash cost as you go, and keep non-ASCII letters. Nothing leaves your browser.

Choose a font file Drop a .ttf / .otf / .woff / .woff2 file here, or click to browse

128

This preview draws the generated bitmaps themselves, not an estimated layout. What you see here is what the display will show.

How the Adafruit GFX font format works

A GFX font is three pieces: a packed bit array, a glyph table, and a struct tying them together.

typedef struct {
  uint16_t bitmapOffset;  // byte index of this glyph in the bitmap array
  uint8_t  width, height; // bitmap dimensions in pixels
  uint8_t  xAdvance;      // how far the cursor moves in x
  int8_t   xOffset, yOffset; // cursor to the top-left corner of the bitmap
} GFXglyph;

typedef struct {
  uint8_t  *bitmap;
  GFXglyph *glyph;
  uint16_t  first, last;  // code range covered
  uint8_t   yAdvance;     // line height
} GFXfont;

Bits are packed row by row, most significant bit first. There is no per-row alignment inside a glyph, but every glyph starts on a fresh byte: Adafruit_GFX::drawChar reads bitmapOffset as a byte index and resets its bit counter for each character. That is the classic mistake when writing your own converter, since letting bits run across glyph boundaries shifts the entire text.

yOffset is almost always negative because it is measured upward from the baseline. For descenders like g and p the bitmap reaches below the baseline, so height exceeds the absolute value of yOffset.

Points, pixels and 141 DPI

Adafruit's own fontconvert defaults to 141 DPI, which is why FreeSans9pt7b is around 18 pixels tall rather than nine. The conversion is simple:

pixels = points × 141 / 72

 9pt →  18px
12pt →  24px
18pt →  35px
24pt →  47px

The point and pixel boxes on this page are linked by that formula, so editing either updates the other. The 7b suffix in a font name marks the 7-bit range (ASCII 32-126); 8b marks a range that runs past 127.

What the threshold does

The browser draws the font with antialiasing, so edge pixels are partly transparent. A GFX font is pure black and white. The threshold decides how opaque a pixel has to be before it counts as set.

ThresholdResultUse when
60-100Heavier, filled inSmall sizes break letters apart
128BalancedDefault, right for most fonts
170-220Thinner, sharperLarge sizes look bloated

Anywhere near 8 to 12 pixels it pays to step through threshold values and watch the glyph grid. At that size a single pixel decides whether a letter reads at all.

Characters outside Latin-1

GFX stores one contiguous code range and keeps a glyph for every code between first and last. Turkish is the clearest example of where that breaks down:

LettersUnicodeInside Latin-1 (32-255)?
ö Ö ü Ü ç Ç0xF6, 0xD6, 0xFC, 0xDC, 0xE7, 0xC7Yes
ğ Ğ0x11F, 0x11ENo, Latin Extended-A
ı İ0x131, 0x130No, Latin Extended-A
ş Ş0x15F, 0x15ENo, Latin Extended-A

Emitting a single range from 32 to 0x15F means more than 320 glyphs, which most microcontrollers cannot afford. The Turkish preset instead remaps the twelve letters into codes 127 to 138, just above ASCII. That is 107 glyphs in one contiguous range.

Because the codes are remapped, the output also carries a gfxTr helper that converts UTF-8 text into them:

#include <Adafruit_GFX.h>
#include "MyFont9pt8b.h"

display.setFont(&MyFont9pt8b);
display.setCursor(0, 20);
display.print(gfxTr("Sicaklik: 23,4 °C  ölçüm başladı"));

The same trick works for any script that needs a handful of letters from outside Latin-1: use a custom range, or remap into the gap above ASCII and translate on the way in.

Using the font in a sketch

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "MyFont9pt7b.h"   // the file you downloaded, next to the .ino

Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setFont(&MyFont9pt7b);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 20);   // y is the baseline, not the top edge
  display.print("Hello");
  display.display();
}

void loop() {}

Two details trip people up. The y value you pass to setCursor is the baseline, so passing 0 puts the text above the top of the screen. And setFont(NULL) returns you to the library's built-in 5x7 font, which is worth knowing when you mix sizes on one screen.

Flash cost

Narrowing the range saves the most. If the display only ever shows numbers, the full 96-glyph ASCII range is wasted: the digits and signs preset emits 16 glyphs and cuts the bitmap to roughly a tenth. The page reports total bytes for every font it generates, which is the number that actually decides things on a 32 KB part.

If all you need is one logo or icon, skip fonts entirely, a bitmap is far smaller. Use the image2cpp tool for that. If you are looking for ready-made bitmap fonts instead, the U8g2 font list covers those.

Frequently Asked Questions

Is the output identical to fontconvert.c?

Same format, works with Adafruit_GFX unchanged, but not byte for byte identical. fontconvert rasterises through FreeType with hinting; this tool uses the browser's rasteriser. The difference is at the level of single pixels, and the threshold slider moves it either way.

Which font formats are accepted?

TTF, OTF, WOFF and WOFF2. Whatever the browser's FontFace API can open, this tool can open; no separate parser is loaded.

Glyphs come out broken or hollow

Nearly always the size is too small. Below 8 pixels a thin serif face stops being readable. Either raise the size, or drop the threshold to 80-100 so partly transparent pixels count as set. Choosing a face designed as a screen font makes a large difference at small sizes.

Nothing shows up on the display

The usual cause is passing 0 to setCursor. In GFX the y value is the baseline, not the top edge, so the first line needs at least the font height. The other common cause is forgetting display.display(), without which the buffer is never pushed to the panel.

What is the uint16 overflow warning?

bitmapOffset is a uint16_t, so once the bitmap array passes 65535 bytes the later glyphs point at the wrong place. Reduce the size or narrow the range. A font that large would not fit most microcontrollers anyway.

Is my font file uploaded anywhere?

No. It is read into browser memory only, rasterised on a canvas, and no network request is made at any point.