TrueType font zerlegen: glyf table

Hi,

ich habe die Aufgabe bekommen, auf einem Mikrocontroller chinesische Schrift zum laufen zu kriegen. Das Format der Wahl ist TrueType, die einzige Sprache, die ich verwenden darf, ist C (kein objective und kein ++). Diverse Sourcecodes in anderen Sprachen beziehen sich auf externe Methoden, die ich nicht habe (auch mit includes muss ich sparsam umgehen, Speicher ist teuer)

Meine Frage ist auf die glyf-Tabelle(ich weiß dass es im englischen eigentlich glyph heißt) bezogen.
Ich habe bereits 3 Dokumentationen über das Format gelesen aber ich blicke nicht durch. Von meinen Kollegen kann mir auch keiner weiterhelfen. Meine Frage ist jetzt, ob sich das flag bei den Composite-glyf-description auch auf mehrere Buchstaben beziehen kann, ich kriege nur Mist beim auslesen und keine realistischen Werte.

Wenn jemand Ahnung von dem Thema hat oder mir sonstwie weiterhelfen kann schonmal danke im Voraus.

MfG Sebastian

Hallo Sebastian,

mir scheint Dein Problem ein sprachunabhängiges zu sein und in der Aufgabenstellung die Hälfte zu fehlen.

ich habe die Aufgabe bekommen, auf einem Mikrocontroller

Das scheint schon mal klar: irgendeine schwachbrüstige CPU mit spartanischen Ressourcen. Aber alles ist relativ …

chinesische Schrift zum laufen zu kriegen.

Das wiederum nicht: Wo sollen denn die Schrift erscheinen und wie sieht die Anbindung aus? Im Zweifelsfalle ist es dem Microcontroller egal, ob seine Bytes in irgendeinem Ausgabegerät später als ASCII oder UTF16 interpretiert werden.

Das Format der Wahl
ist TrueType,

Klingt alles so, als müsstest Du das Raster Image Processing machen? Wo liegen die Restriktionen der Plattform. Bei ganz knappen Ressourcen erscheint mir ein Bitmap-Ansatz sinnvoller. Oder geht es Dir darum in der Entwicklungsphase Bitmaps zu generieren?

die einzige Sprache, die ich verwenden darf, ist
C (kein objective und kein ++).

Hängt halt davon ab, welche Entwicklungswerkzeuge Du für die Zielplattform zur Verfügung hast.

Diverse Sourcecodes in anderen
Sprachen beziehen sich auf externe Methoden, die ich nicht
habe (auch mit includes muss ich sparsam umgehen, Speicher ist
teuer)

Was haben includes mit Speicher zu tun? Die Frage wäre eher, welche Bibliotheken Du für die Zielplattform zur Verfügung hast und welche Du davon nutzen und verlinken musst.

Ciao, Allesquatsch

Danke erstmal für die Antwort.
Das ist mein erstes Projekt in C, das über HelloWorld usw. hinaus geht. Ausserdem ist es auch mein erstes Programm, das auf einem Mikrocontroller laufen soll. Deswegem kanns auch sein, dass ich manche Dinge noch nicht weiß.

Das Problem bei der Schrift ist, dass der chinesische Schriftsatz in jeder Ausführung mehrere tausend Zeichen hat. Der Mikrocontroller hat atm nur 512KB nicht-flüchtigen Speicher. Der muss aufgestockt werden, aber je weniger, desto billiger (Massenprodukt). Ausserdem sind Bitmaps bei verschiedenen Schriftgrößen entweder mehrfach benötigt oder werden schrecklich skaliert… Jedenfalls war der Ansatz, die Daten direkt ans Display zu schicken (zum testen muss die Konsole herhalten).

Entwickelt wird vorerst mit Visual C++ 2010 Express. Die Übertragung auf den Mikrocontroller übernimmt dann jemand anderes, aber erstmal muss es laufen…
Die Bibliotheken brauche ich ja, um die includes machen zu können, und Speicher für die hab ich nur wenig. Das hab ich damit gemeint.

Hallo Fragewurm,

Entwickelt wird vorerst mit Visual C++ 2010 Express. Die
Übertragung auf den Mikrocontroller übernimmt dann jemand
anderes, aber erstmal muss es laufen…
Die Bibliotheken brauche ich ja, um die includes machen zu
können, und Speicher für die hab ich nur wenig. Das hab ich
damit gemeint.

Tja, da kannst du die Speichergrösse überhaupt nicht abschätzen.
Bibliotheken für den PC (Windows) sind überhaupt nicht auf Speichergrösse optimiert. Auch wird da oft eine weitere Bibliothek mitbenutzt, wenn du Pech hast nur für eine Hardware-Option welche 1x beim initialisieren aufgerufen wird. Durch den virtuellen Speicher beim PC macht das auch keine Probleme, da disese Teil dann nur kurz von der Festplatte in den Speicher geladen werden muss…

Dein Hauptproblem dürften Floting-Point-Operationen sein. Seit dem 80386 ist die FPU in die CPU integriert, bei Controllern gibt es meist gar keine FPU. Dann müssen FP-Operationen per Software emuliert werden, was zusätzlichen Speicherplatz benötigt und rund um den Faktor 100 langsamer ist.

Die PC-Bibliotheken müssen dafür ausgelegt sein alle möglichen Skalierungen berechnen zu können, da es ja die Unterschiedlichsten Auflösungen beim Ausgabemedium gibt. Bei deiner Anwendung dürfte die Auflösung fix sein und zudem wohl auch nur einige unterschiedliche Schriftgrössen vorhanden sein. Damit kann man die Algorithmen vereinfachen; Rechenfehler welche unter der Auflösung des Display bleiben sind unsichtbar.

Bei Postscript und TrueType wird die Umsetzung in einen Raster erst im Ausgabegerät selbst gemacht, damit man immer das bestmögliche Ergebnis erhält, egal welche Auflösung das Gerät hat.

Für manche Projekte hatte ich ein Tool geschrieben, welches mit .BMP im ein internes Format umgesetzt hat. Das hatte einfach den Vorteil, dass man irgendwelche PC-Tools für das Erstellen der Zeichen und Symbole verwenden konnte.
Mein Hauptproblem war, dass .BMP für Geräte optimiert sind, welche die Pixel Zeilenweise schreiben, ein einfaches LCD will die Pixel aber Spaltenweise. Also macht es Sinn, diese Umrechnerei in den Compiliervorganz zu verlegen, anstatt die ganze Rechenzeit bei jedem einzelnen Zeichen aufwenden zu müssen.
Achja, bei Postscript (PDF) ist es auch¨üblich, nur die tatsächlich verwendeten Zeichen in einem Dokument einzubetten.

Das wäre für dich auch evtl. eine Option. Von den etwa 30’000 Zeichen dürften niemals alle in euren Texten vorkommenWenn man geschickt ist, kann man da vieles dem Linker übertragen, andernfalls schreib man ein kleines Tool, welches im Make-File eingebunden wird.

Programmieren auf Controllern ist eine ganz andere Welt !!!

MfG Peter(TOO)

1 Like

Nachtrag
Ein paar grundlegende Punkte wurden hier angesprochen:
/t/speicherbedarf-von-applikationen/6694072

Danke für die Hinweise, werd sie mir zu Herzen nehmen.
Mikrocontroller sind ne komplett neue Herausforderung für mich, aber ich krieg das schon hin ^^
Vom Speicher siehts bisher gut aus. Von den Methoden, die ich brauche, werd ich sicher nicht die ganzen Bibliotheken mitnehmen. Ich such mir die Bausteine oder verwende was anderes. Der Controller hat schon sowas wie ne Eigenbau-Bibliothek mit den benötigten Funktionen.

Vom Speicher her siehts gut aus, hab jetz nen modifizierten Font mit notdürftigen 9000 Zeichen und 1,5MB. Die Frage mit der glyf-table wusste aber immer noch niemand zu beantworten.

Sehr geehrter Salzstangl,

Hier ein Beispiel mit Pseudocode :
http://www.microsoft.com/typography/otspec/glyf.htm
Welcher Teil ist Ihnen unklar ?

Mit freundlichem Gruß

TechPech 1984

Diesen Pseudocode hab ich mir schon gefühlte 500 mal durchgelesen ^^

Ich lese gemütlich mit fread(in der Testversion) meine bytes in meine Strukturen ein. Beim ersten Durchlauf geht noch alles gut, aber dann kommt nur noch Chaos (10000+ Konturen in einem Buchstaben usw.). Jetzt wollte ich wissen, ob und wenn ja wann ich diese flags für den nächsten Buchstaben übernehmen muss. Bei der Single-glyph-description ist es ja einfach, dank dem repeat-flag.
Tut mir echt Leid falls es ganz einfach is und ich es nicht finde…

Tja, da kannst du die Speichergrösse überhaupt nicht
abschätzen.
Bibliotheken für den PC (Windows) sind überhaupt nicht auf
Speichergrösse optimiert.

Das ist genauso richtig wie unerheblich. Denn diese Bibliotheken sind für x86/x64 CPUs und Windows. Das ist weder auf Microcontrollern lauffähig noch sind die notwendigen Systemroutinen da, die dann angesprochen werden.

Programmieren auf Controllern ist eine ganz andere Welt !!!

Jepp. Und man sollte es beherrschen, wenn etwas Anspruchsvolles herauskommen soll.

Ciao, Allesquatsch

Himmelfahrtskommando
Hi,

Das ist mein erstes Projekt in C, das über HelloWorld usw.
hinaus geht.

Keine wirklichen Voraussetzungen …

Ausserdem ist es auch mein erstes Programm, das
auf einem Mikrocontroller laufen soll.

uff!

Deswegem kanns auch sein, dass ich manche Dinge noch nicht weiß.

Sehr optimistische Sichtweise

Entwickelt wird vorerst mit Visual C++ 2010 Express. Die
Übertragung auf den Mikrocontroller übernimmt dann jemand
anderes, aber erstmal muss es laufen…

Klingt alles nicht danach, als ob in Deinem Umfeld überhaupt jemand Ahnung hat, wie man Cross-Entwicklung betreibt.

Die Bibliotheken brauche ich ja, um die includes machen zu
können, und Speicher für die hab ich nur wenig. Das hab ich
damit gemeint.

Ich befürchte, dass ich verstanden habe, wie Du es meintest und dass es darauf hindeutet, dass das ganze Grundlagenwissen wie Compiler, Linker und Betriebssysteme funktionieren.

In der Regel gibt es für Microcontroller jeweils genau zu diesem Typ passende Entwicklungswerkzeuge.
Irgendwas vorweg mit VC++ zu entwickeln, hilft vielleicht Dein Grundlagenwissen marginal zu verbessern, aber ist für das Endziel unerheblich.

Die Aufgabe in VC++ für Windows zu lösen ist wie mit dem Dreirad im Kreis fahren zu üben, wenn das Endziel ein Looping mit einem Hubschrauber sein soll.

Die gestellte Arbeitsaufgabe wäre selbst für jemand, der über reichlich Programmiererfahrung und das Grundlagenwissen über Microcontroller verfügt, noch eine stolze Herausforderung.
Für einen blutigen Anfänger bestünde selbst mit genügend Hertz und RAM keine realistische Chance.

Ciao, Allesquatsch

Klingt gut, krieg ich hin ^^

Der Sinn, das in VC++ zu erledigen ist auch, den Mikrocontroller-Entwicklern die Routinen vorzulegen, die das ganze dann übertragen (von C haben sie schon Ahnung, aber von Fonts nicht). Bis jetzt hab ich 70% damit verbraucht, rauszufinden wie ich das mit dem truetype mache, 15% nachschlagen wie das in C geht und 15% wirkliche Programmierung. Aber es geht voran, abgesehen von diesem glyf-Detail, das ich erstmal hinten angestellt hab.

Irgendwie hast du Recht, die hätten mir auch die Aufgabe geben können, ein Menü in Assembler zu entwerfen, wesentlich einfacher…

Vorgehensweise funktioniert nicht

Der Sinn, das in VC++ zu erledigen ist auch, den
Mikrocontroller-Entwicklern die Routinen vorzulegen, die das
ganze dann übertragen (von C haben sie schon Ahnung, aber von
Fonts nicht).

Mir scheint, dass Du erst gar nicht verstehst, wo das Problem liegt.

Würdest Du „reines“ C verwenden ohne irgendwelche includes verwenden, ließe sich ein solches Programm portieren, wenn es für den Microcontroller eine Entwicklungsumgebung für C gibt. Schleifen, Variablen, Aufrufe selbstgeschriebener Funktionen, Arithmetik, Vergleich - alles das, aber nur das ist C.

Ich nehme aber an, dass Du sehr wohl irgendwelche includes verwendest (, mit der Du in der Entwicklungsumgebung die Existenz und Spezifikation von Bibliotheksfunktionen bekannt machst). Wahrscheinlich sogar spezifische Bibliotheken mit Font-Funktionen.
Beim Linken werden diese Bibliotheken dann eingebunden bzw. heute meist DLLs angesprochen.

Im Endeffekt besteht ein Programm, welches Du mit VC++ erzeugst, zu 0,01% aus Deinem Code und zu 99,99% aus Code von Microsoft und dem Hersteller der Entwicklungsumgebung und Bibliotheken.

Doch diese DLLs und Bibliotheken sind Windows und x86-CPU. In vergleichbarer Form wird Du für Deinen Microcontroller aber mit größter Wahrscheinlichkeit nichts finden. Ohne diesen riesigen Fundus an sehr mächtigen Routinen, wie es ihn für die gängigen Computer-Betriebssysteme und Benutzeroberflächen gibt, nutzen Dir dann Deine 0,01% Code auch nichts.

Ciao, Allesquatsch

Hallo ,

gut, aber dann kommt nur noch Chaos (10000+ Konturen in einem
Buchstaben usw.).

Ohne Beispiel würd ich sagen , der wert ist Falsch berechnet.

Sehr geehrter Allesquatsch

Sie brauchen nicht ständig wiederholen was Sie schon gesagt haben . Und beim lesen der Antworten wäre Ihnen aufgefallen das es nur zu Demonstrationszwecken benutzt wird. Z.b. baut man ein Handout für eine App auch mal gerne via HTML und JavaScript auch wenn später die Umsetzung bestimmt nicht in HTML sein wird . Er hat die Aufgabe bekommen , somit bringt es wohl weniger hier den Boss zu spielen. Solange er für die Arbeit bezahlt wird, liegt es an seinem Boss sich Beraten zu lassen und das Projekt zu planen.

P.S. Es langweilt solche Bossy Argumentation zu lesen . Trägt nichts zur Lösung bei und stellt sich dar als seien Sie die Projektleitung und erklären dem Azubi was er nicht machen darf. Obwohl der Azubi die ganze Zeit auf den Chef verweist.

P.P.S. Manchmal sollte man einfach nicht Antworten wenn es nur ums „SO NICHT“ geht. Zumal Ihnen der gesamt Überblick fehlt.

P.P.P.S Ich stimme Ihnen ja zu , aber wer meinen Sie sind Sie , das Sie hier den Projektleiter spielen.

Mit freundlichem Gruß

TechPech 1984

Und beim lesen der Antworten wäre Ihnen aufgefallen
das es nur zu Demonstrationszwecken benutzt wird.

Dann habe ich die Aussagen völlig anders interpretiert, denn ich habe nur verstanden, dass man sich vorstellt, die Mikrocontroller-Entwicklern könnten dann das Ganze übertragen.

Z.b. baut
man ein Handout für eine App auch mal gerne via HTML und
JavaScript auch wenn später die Umsetzung bestimmt nicht in
HTML sein wird . Er hat die Aufgabe bekommen , somit bringt es
wohl weniger hier den Boss zu spielen. Solange er für die
Arbeit bezahlt wird, liegt es an seinem Boss sich Beraten zu
lassen und das Projekt zu planen.

Von Cross-Entwicklungen her kenne ich Simulationsumgebungen, mit denen man voll unter Windows und *nix Plattformen schon Showcases herstellen konnte, die primär für Entwickler- und Usability-Test gedacht sind. Nach solchen Entwicklungswerkzeugen hatte ich ja explizit gefragt, hörte aber nur was von VC++.

Ciao, Allesquatsch

Hallo Allesquatsch,

Würdest Du „reines“ C verwenden ohne irgendwelche includes
verwenden, ließe sich ein solches Programm portieren, wenn es
für den Microcontroller eine Entwicklungsumgebung für C gibt.
Schleifen, Variablen, Aufrufe selbstgeschriebener Funktionen,
Arithmetik, Vergleich - alles das, aber nur das ist C.

Ich nehme aber an, dass Du sehr wohl irgendwelche includes
verwendest (, mit der Du in der Entwicklungsumgebung die
Existenz und Spezifikation von Bibliotheksfunktionen bekannt
machst). Wahrscheinlich sogar spezifische Bibliotheken mit
Font-Funktionen.

Wenn man weiss was man macht sind includes kein Problem.

Ich habe in meinem Leben jede Menge Module, meistens Datenübertragungsprotokolle, geschrieben bei denen der selbe Sourcecode unter VC auf dem PC und unter einem anderen C-Compiler auf einem Controller läuft. Auch die ganzen Datenstrukturen sind da nur einmal vorhanden, auch wenn sich die CPUs in Little und Big Endian unterscheiden.

Aber man muss wissen was man, und der Compiler daraus, macht.

MfG Peter(TOO)

Teile Deine Einschätzung
Gerade C ist eine exzellente Plattform für Cross-Entwicklung.

Wenn man versteht, wie das alles funktioniert, gibt es kaum etwas Mächtigeres. Dank Posix war es meist auch gar kein Problem, Bibliotheksfunktionen zu benutzen. Als dann STL kam, war meine Phase beruflicher Entwicklertätigkeit schon vorbei.

Aus Spaß habe ich mir für einen kleinen PIM mal die Entwicklerunterlagen besorgt. Das lief tatsächlich sogar mit MS VC++.

Die gelieferten Windowsbibliotheken waren aufrufkompatibel zu den PIM-Originalroutinen, erzeugten aber ein Windows-Executable mit der kompletten Simulation des PIM.
Allerdings war es mir dann zu kompliziert, meine Beispielanwendung auf den PIM selbst zu bekommen. Der PIM hatte noch eine 8-bit CPU (Z80), die ja nur 64k adressieren kann. Entsprechend fricklig war die Speicherverwaltung von 1 MB durch Paging.

Ciao, Allesquatsch

Hallo Fragewurm,

Ich lese gemütlich mit fread(in der Testversion) meine bytes
in meine Strukturen ein. Beim ersten Durchlauf geht noch alles
gut, aber dann kommt nur noch Chaos (10000+ Konturen in einem
Buchstaben usw.).

Also, du weisst ja gar nicht wie gross die Struktur ist.
Das weisst du erst, wenn du die Struktur auswertest.

Das nächste Problem ist, dass man Strukturen NIE mit fread() einlesen sollte, wenn man den Compiler nicht ganz genau kennt!

Ein Compiler fügt, je nach dem, noch zusätzliche Füll-Bytes in Strukturen ein.
z.B. können manche CPUs nur auf 16-Bit-Daten zugreifen, wenn diese an einer geraden Adresse abgelegt werden. Wenn also auf ein 8-Bit Wert ein 16-Bit folgt, würde der 16-Bit-Wert auf eine ungerade Adresse fallen. Also fügt der Compiler ein zusatzliches Füllbyte ein.
Die x86 CPU hat diese Limitte zwar nicht, aber der Compiler kann trotzdem FüllBytes einfügen umd die Geschwindigkeit zu optimieren.

Dann ist zusätzlich auch nich definiert, wie viele Bits, z.B. int hat. Dies ist dem Compilerhersteller überlassen, muss aber im Handbuch stehen.
Ich selber kenne Compiler bei welchen int 16, 32 oder 64 Bit lang sind. Bei manchen Compilern lässt sich dies sogar noch einstellen.
Im alten K&R stand:
_Man kann sich nur darauf verlassen, dass char
Als C entwickelt wurde, gab es auch noch CPUs mit Wortbreiten von 9, 12, 18, 36 und 48 Bit. Microprozessoren sind heute fast nur noch mit Wortbreiten von 4, 8, 16, 32 und 64 Bit zu finden. Bei DCP (Signalprozessoren) sind aber heute noch Wortbreiten zu finden, welche keinen ganzen 2er Potenzen entsprechen.

Dann gibt es noch das Problem von Big- und Little-Endian und die ganzen Mischformen bei 32-Bit-Werten.
Hinzu kommt noch, dass ein Dateiformat nicht identisch mit der Endianness der CPU sein muss!
Bei Datei- und Prtokoll-Formaten wird oft Big-Endian bevorzugt, weil sich dieses Format als Hexdump besser lesen lässt.
http://de.wikipedia.org/wiki/Byte-Reihenfolge

Wenn man portierbar programmieren will, bleibt nichts anderes übrig, als zeichenweise einzulesen:
(Dies wäre für ein Datenformat in Big-Endian)

int i; // 32-Bit

i = getc();
1 

MfG Peter(TOO)_     

Ich weiß, wie groß die Strukturen sind, weil ich die Daten aus der Spezifikation habe, alle unbekannt großen Arrays sind Pointer auf Arrays und werden erst alloziiert wenn ich es weiß.
Ich hab mir eigene Datentypen gebaut, die eine feste Bitbreite haben und da ich die Daten vorerst im Windows habe und später in ein Header-file übertrage sollte das Problem mit den Füllbytes nicht auftreten, oder?
Ich weiß, dass die Endians im TTF im „Motorola-Stil“ gespeichert sind, auf dem Entwicklungsrechner und auf unserem Controller allerdins nicht. Deswegen hab ich auch swapmethoden, mit denen ich alle Werte direkt nach dem Einlesen umdrehe. Ja ich habe auf 32Bit-Werte geachtet, 64 brauche ich nicht, weil die wenn ich das richtig verstanden habe nur beim Datum vorkommen, was ich nicht verwende.

Zuerstmal
@TechPech: Danke für die Absicht, hier zum Thema zurückzuführen. Allerdings bin ich wirklich dankbar für alle Antworten und Vermutungen, was ich falsch gemacht haben könnte. Tatsächlich hab ich dadurch schon ein Paar Performance-Schwachstellen und Passagen in meiner eigenen Dokumentation verbessert. Der Bug wurde aber leider noch nicht gefixt :frowning:

Ich bin leider hier nur Praktikant, bin aber wahrscheinlich erfahrener als die meisten Azubis, was sich aber leider nur auf Objektorientierte Sprachen, Webentwicklung und minimales Grundwissen in Assembler bezieht. Ich verdiene aber nur einen Bruchteil vom Azubigehalt, quasi als Trinkgeld.
Mein Chef (quasi jeder in der Firma ist mein Chef) hatte vorher keine Ahnung, wieviel das ist. Er ist wie ich von maximal 3-4 Wochen ausgegangen (Er hat aber 15 Jahre C-Erfahrung oO )