Proje Defteri

Adafruit GFX Font Dönüştürücü

TTF, OTF, WOFF ya da WOFF2 fontunu Adafruit GFX başlık dosyasına çevirin. Karakterleri piksel piksel önizleyin, flash boyutunu görün, Türkçe karakterleri de yanınıza alın. Her şey tarayıcıda çalışır.

Font dosyası seçin .ttf / .otf / .woff / .woff2 dosyasını buraya bırakın ya da tıklayın

128

Bu önizleme üretilen bitmap'lerin kendisini çizer, tahmini bir yerleşim değildir. Ekranda göreceğiniz piksellerin aynısıdır.

Adafruit GFX Font Formatı Nasıl Çalışır?

Bir GFX fontu üç parçadan oluşur: sıkıştırılmamış bit dizisi, karakter tablosu ve bu ikisini bağlayan font yapısı.

typedef struct {
  uint16_t bitmapOffset;  // bitmap dizisinde bu karakterin baslangici (bayt)
  uint8_t  width, height; // bitmap boyutlari (piksel)
  uint8_t  xAdvance;      // imlecin x'te ilerleyecegi miktar
  int8_t   xOffset, yOffset; // imlecten bitmap'in sol ust kosesine uzaklik
} GFXglyph;

typedef struct {
  uint8_t  *bitmap;
  GFXglyph *glyph;
  uint16_t  first, last;  // kapsanan kod araligi
  uint8_t   yAdvance;     // satir yuksekligi
} GFXfont;

Bitler satır satır, en anlamlı bitten başlayarak paketlenir. Karakterin içinde satır başına hizalama yoktur, ama her karakter yeni bir baytta başlar: Adafruit_GFX::drawChar fonksiyonu bitmapOffset değerini bayt indeksi olarak okur ve her karakterde bit sayacını sıfırlar. Kendi dönüştürücünüzü yazıyorsanız en sık yapılan hata budur, karakterler arasında bit sızdırırsanız yazının tamamı kayar.

yOffset neredeyse her zaman negatiftir, çünkü taban çizgisinden yukarıya doğru ölçülür. g ve p gibi kuyruklu harflerde bitmap taban çizgisinin altına taştığı için height değeri yOffset'in mutlak değerinden büyüktür.

Punto, piksel ve 141 DPI

Adafruit'in resmi fontconvert aracı varsayılan olarak 141 DPI kullanır. Bu yüzden FreeSans9pt7b aslında 9 piksel değil, yaklaşık 18 piksel yüksekliğindedir. Formül basit:

piksel = punto × 141 / 72

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

Bu sayfadaki punto ve piksel kutuları aynı formülle birbirine bağlıdır, hangisini yazarsanız diğeri güncellenir. Dosya adındaki 7b soneki 7 bitlik aralığı (ASCII 32-126), 8b ise 255'e uzanan aralığı gösterir.

Eşik değeri ne işe yarar?

Tarayıcı fontu kenar yumuşatmalı çizer, yani kenarlardaki pikseller yarı saydamdır. GFX fontu ise siyah beyazdır. Eşik, bir pikselin hangi saydamlık değerinden itibaren dolu sayılacağını belirler.

EşikSonuçNe zaman
60-100Kalın, dolgunKüçük puntolarda harfler kopuk çıkıyorsa
128DengeliVarsayılan, çoğu font için doğru
170-220İnce, keskinBüyük puntolarda harfler şişkin görünüyorsa

8-12 piksel civarında çalışıyorsanız eşiği tek tek deneyip karakter ızgarasına bakmakta fayda var; bu boyutlarda bir pikselin dolu olup olmaması harfin okunurluğunu değiştirir.

Türkçe karakterler

Sorun şudur: GFX tek bir sürekli kod aralığı destekler, first ile last arasındaki her kod için bir karakter tutar. Türkçe'nin altı harfi bu aralığın dışında kalır:

KarakterUnicodeLatin-1 (32-255) içinde mi?
ö Ö ü Ü ç Ç0xF6, 0xD6, 0xFC, 0xDC, 0xE7, 0xC7Evet
ğ Ğ0x11F, 0x11EHayır, Latin Extended-A
ı İ0x131, 0x130Hayır, Latin Extended-A
ş Ş0x15F, 0x15EHayır, Latin Extended-A

32'den 0x15F'e kadar tek aralık üretmek 320'den fazla karakter, yani çoğu Arduino kartında kabul edilemez bir flash maliyeti demektir. Türkçe ön ayarı bunun yerine 12 Türkçe karakteri ASCII'nin hemen üstüne, 127-138 kodlarına taşır. Toplam 107 karakter eder ve tek sürekli aralıkta kalır.

Kaydırma yaptığı için üretilen çıktıya gfxTr adında bir yardımcı fonksiyon da eklenir. UTF-8 metni bu kodlara çevirir:

#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ı"));

Fontu projede kullanmak

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "MyFont9pt7b.h"   // indirdiginiz dosya, .ino ile ayni klasorde

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 taban cizgisidir, ust kenar degil
  display.print("Merhaba");
  display.display();
}

void loop() {}

İki nokta sık sık gözden kaçar. Birincisi, setCursor'a verdiğiniz y değeri taban çizgisidir; 0 verirseniz yazı ekranın üstünde kalır. İkincisi, setFont(NULL) çağırarak kütüphanenin gömülü 5x7 fontuna geri dönebilirsiniz, özel font yalnızca ayarlandığı sürece geçerlidir.

Flash maliyeti

Aralığı daraltmak en etkili tasarruftur. Ekranda yalnızca sayı gösteriyorsanız 96 karakterlik ASCII aralığına ihtiyacınız yoktur; yalnızca rakam ve işaret ön ayarı 16 karakter üretir ve bitmap'i onda birine indirir. Sayfa üretilen her font için toplam baytı gösterir, Arduino Uno'nun 32 KB flash'ı düşünüldüğünde bu sayı doğrudan karar verdirir.

Tek bir logo ya da ikon çizdirecekseniz font hiç gerekmez; bir bitmap çok daha az yer tutar. Bunun için image2cpp aracını kullanın. U8g2 kütüphanesindeki hazır fontları arıyorsanız U8g2 font listesi sayfası işinizi görür.

Sıkça Sorulan Sorular

Çıktı fontconvert.c ile birebir aynı mı?

Yapısal olarak aynı formattır ve Adafruit_GFX ile sorunsuz çalışır, ama bayt bayt aynı değildir. fontconvert FreeType'ın hinting motorunu kullanır, bu araç tarayıcının kendi rasterizasyonunu kullanır. Fark tek tek piksellerde görülür ve eşik kaydırıcısıyla istediğiniz yöne çekilebilir.

Hangi font formatlarını kabul ediyor?

TTF, OTF, WOFF ve WOFF2. Tarayıcının FontFace API'si hangi formatı açabiliyorsa bu araç da açabilir, ayrı bir çözümleyici yüklenmez.

Karakterler kopuk ya da eksik çıkıyor

Neredeyse her zaman punto çok küçüktür. 8 pikselin altında ince serif fontlar okunmaz hale gelir; ya puntoyu büyütün ya da eşiği 80-100 aralığına indirerek yarı saydam pikselleri de dolu sayın. Ekran fontu olarak tasarlanmış eş aralıklı bir font seçmek de küçük boyutlarda ciddi fark yaratır.

Yazı ekranda görünmüyor

En sık sebep setCursor'a 0 verilmesidir. GFX'te y değeri taban çizgisidir, üst kenar değil; ilk satır için en az font yüksekliği kadar bir değer vermelisiniz. İkinci sebep display.display() çağrısının atlanmasıdır, tampon ekrana basılmadan çizim görünmez.

uint16 taşma uyarısı ne demek?

bitmapOffset alanı uint16_t'dir, yani bitmap dizisi 65535 baytı aşarsa son karakterlerin başlangıcı yanlış hesaplanır. Puntoyu küçültmeniz ya da karakter aralığını daraltmanız gerekir. Bu boyuttaki bir font zaten çoğu mikrodenetleyicinin flash'ına sığmaz.

Font dosyam bir yere gönderiliyor mu?

Hayır. Dosya yalnızca tarayıcının belleğine okunur, rasterizasyon canvas üzerinde yapılır ve hiçbir ağ isteği gönderilmez.