MeasureString und DrawString - GDI auf die harte Tour
-
Nein, leider kann ich diese Differenz bei weitem nicht akzeptieren. Im Beispiel handelt es sich ja nur um einen einzelnen Buchstaben, und solch eine Differenz würde sich über eine Zeile auch noch vergrößern.
Was mich auch noch stört, ist, dass die Funktion GetCharABCWidthsFloat immer nur ganzzahlige Werte zurückliefert, egal, welche Schriftgröße ich einsetze.
Mir ist bekannt, dass Fonts in einem ganzzahligen Raster (i.d.R. 1024x1024 oder 20148x2048) designed werden. daraus errechnen sich dann in Abhängigkeit von der tatsächlich gewählten Schriftgröße die aktuellen Werte der Punkte, u.a. auch für die Breite des Glyph, und dann natürlich immer in float-Werten.
Wenn ich an die Werte für die Design-Schriftgröße und an die Weiten-Werte dieser Design-Schriftgröße herankäme, wäre die Umrechnung wohl deutlich einfacher. Aber diese Funktionen habe ich noch nicht gefunden. Irgendwie sind diese Werte in den Font-Daten enthalten, und ich mag einfach nicht glauben, dass ich dafür die Daten aus der Font-Datei selbst noch einmal interpretieren muss.
-
Noch schnell ein Nachtrag:
Messraster usw sind sicher Lösungen für einzelne Zeichen, aber ich möchte schon eine mehr generelle Messmethode finden. (Jeder Editor kann das, und ganz bestimmt auch ohne sehr aufwändige Umwege - sonst würde er sich totrechnen).
-
WishfulThinking schrieb:
Noch schnell ein Nachtrag:
Du kannst deinen Beitrag auch bearbeiten.
-
Ist schon klar, aber irgendwie sieht das dann nicht authentisch aus.
-
Das Thema interessiert mich auch. Gibt es eigentlich auch eine Möglichkeit, einen GDI-Font (HFONT) direkt aus dem GDI+-Font abzuleiten und nicht, wie im Beispiel geschehen, den Font in GDI neu zu erstellen?
-
WishfulThinking schrieb:
Nein, leider kann ich diese Differenz bei weitem nicht akzeptieren. Im Beispiel handelt es sich ja nur um einen einzelnen Buchstaben, und solch eine Differenz würde sich über eine Zeile auch noch vergrößern.
Das ist schon klar, ich wollte nur sichergehen, dass wir von denselben Werten reden.
Das Messraster wäre eine Hilfsmethode um festzustellen, wie die Funktionen genau ticken. Das muss man erstmal genau verstanden haben, und die verschiedenen Werte könnte man am Messraster dann evtl. besser nachvollziehen.GetCharABCWidthsFloat gibt im MM_TEXT Modus tatsächlich nur Integer zurück. Der Sinn von den Floats hier ist nur, dass du bei anderen Koordinatensystemen genauere Umrechnungen hast.
PaulB48a schrieb:
Gibt es eigentlich auch eine Möglichkeit, einen GDI-Font (HFONT) direkt aus dem GDI+-Font abzuleiten und nicht, wie im Beispiel geschehen, den Font in GDI neu zu erstellen?
Hab ich doch schon geschrieben.
-
Du könntest vielleicht mal versuchen, dir das Buch "Windows Graphics Programming" zu besorgen. Da steht auch einiges zu dem Thema drin. Hab jetzt z.B. noch die Funktion GetCharacterPlacement gefunden, die hatte ich gar nicht mehr in Erinnerung. Bin mir nicht sicher, ob sie dir jezt weiterhilft, könnte aber sein.
-
Mit dem modifizierten Test #3 hatte ich tatsächlich nur die LOGFONT-Daten aus dem Gdi+-Font gewonnen (Funktion
GetLogFontW
) und mit diesen Daten dann perCreateFontIndirectW
einen neuen Gdi-Font erzeugt, in der Hoffnung, dass dieser wirklich dem Gdi+-Font ähnlich genug ist. Ich habe keinen Zweifel daran, dass beide Fonts ihre Daten aus derselben Quelle bezogen haben, aber ob die beiden Fonts auch in allen Parametern gleich sind, weiß ich leider nicht.Immerhin gibt es bei der Test-Messung der Breite von "M" ja Unterschiede.....
MM_TEXT
hatte ich gewählt, weil dieses Maßsystem in GDI und GDI+ gleich zu sein scheint; für die anderen Koordinatensysteme sah ich zwischen GDI und GDI+ eben keine Übereinstimmungen. Welches alternative Koordinatensystem würdest du vorschlagen?Dass GetABCCharWidthsFloat im Maßsystem MM_TEXT nur ganzzahlige Werte zurückgibt, habe ich in meiner Quelle (http://msdn.microsoft.com/en-us/library/dd144858%28v=vs.85%29.aspx) nicht nachvollziehen können. Hast du dazu eine andere Quelle? Die würde mich sehr interessieren. Bei der Beschreibung von GetABCCharWidths habe ich übrigens noch einen Hinweis gefunden, wie ich an Messwerte in Font Design Units kommen kann. Die sind, soweit ich weiß, tatsächlich nur ganzzahlig. Der Sache werde ich in dieser Woche mal nachgehen.
-
Ich scheine mir wirklich ein komplexes Thema ausgesucht zu haben. Bei meiner Suche im Netz bin ich allerdings gerade auf einen hochinteressanten Artikel gestoßen, in dem die wesentlichen Unterschiede beim Zeichnen (und vermutlich auch beim Berechnen der Textlänge) zwischen GDI und GDI+ aufgezeigt werden: http://support.microsoft.com/kb/307208/en-us. Die deutsche Übersetzung ist allerdings nicht besonders gut.
Das werde ich mal verinnerlichen und meine Tests entsprechend anpassen. Mal sehen, wie weit ich damit komme.
(Kann man hier eigentlich auch Bilder anhängen? Dann könnte ich auch zeigen, wie die Resultate von DrawString vs TextOut aussehen)
-
WishfulThinking schrieb:
MM_TEXT
hatte ich gewählt, weil dieses Maßsystem in GDI und GDI+ gleich zu sein scheint; für die anderen Koordinatensysteme sah ich zwischen GDI und GDI+ eben keine Übereinstimmungen. Welches alternative Koordinatensystem würdest du vorschlagen?Dass GetABCCharWidthsFloat im Maßsystem MM_TEXT nur ganzzahlige Werte zurückgibt, habe ich in meiner Quelle (http://msdn.microsoft.com/en-us/library/dd144858%28v=vs.85%29.aspx) nicht nachvollziehen können. Hast du dazu eine andere Quelle?
Das steht in dem Buch, das ich erwähnt habe, Windows Graphics Programming. Das geht sehr detailliert auf viele Themen bezüglich GDI ein.
Du kriegst die Infos mit GetABCCharWidthsFloat nicht genauer raus (steht auch in dem Buch). Das sind nur Floats, damit du in anderen Koordinatensystemen auch sinnvolle Werte bekommst. Also, wenn du sagst, du willst die Breite in Metern, dann bringt dir ein Integer nichts. Du kriegst einen Float, der auf Pixel gerundet ist. Aber eben nicht genauer als Pixel.
Edit: hier kannst du keine Bilder anhängen, aber du kannst irgendeinen Imagehoster verwenden und hier einen Link reinposten.
-
Der in meinem vorangegangenen Posting erwähnte Artikel hat mir ein sehr gutes Stück weiter geholfen. Hier meine bisherigen Erkenntnisse:
- GDI+ kann nicht als Ersatz für GDI angesehen werden -- GDI+ ist eine alternative Methode zur Ausgabe von Grafik.
- GDI funktioniert pixelorientiert und damit unbedingt abhängig von dem Ausgabe-Device bzw. der gewählten Auflösung. Zeichen werden immer in ein ganzzahliges Geviert von Pixeln aufgelöst, deshalb sind Höhe und Breite immer nur Integer-Werte. So kommen bei höherer Auflösung natürlich sehr viel genauere Konturen zu Stande, weil dann eine größere Annäherung an das Design-Raster erzielt wird. Damit ändert sich die Breite eines ausgegebenen Textes nicht einfach linear mit der Auflösung oder der Schriftgröße.
- GDI+ löst seine Ausgaben auch in Bruchteilen von Pixeln auf; die Ausgaberesultate werden damit (weitgehend) unabhängig von der Auflösung oder Schriftgröße und damit auch unabhängig von der Ausgabe-Device.
Na schön, damit wäre erklärt, dass ich GDI-Ausgaben nicht mit GDI+-Ausgaben vergleichen kann.
In GDI kann ich tatsächlich nur pixelgenau messen und positionieren, etwas anderes macht in diesem System auch keinen Sinn. Die gemessene Breite eines Zeichens (z.B. "M"), mal zehn genommen, entspricht auch genau der gemessenen Breite eines String mit zehn "M".
Als nächstes werde ich mal versuchen, ähnliche Resultate in GDI+ zu erzielen, nur eben auf Bruchteile von Pixeln genau.Editiert: fett gedruckte Stellen
-
Klasse Zusammenfassung, das habe ich endlich mal verstanden.
In Zukunft benutze ich nur noch GDI
-
Vorsicht -- das kann nach hinten losgehen!
Die Beschränkung auf auflösungsabhängige Ausgaben (oder auch: Device-abhängig) bedeutet, dass man kein Wysiwyg hat. Auf dem Bildschirm mit z.B. 96 dpi bekommt man dann vollkommen andere Textumbrüche als auf dem Drucker, der mit 300, 600 oder sogar mit 1200 dpi arbeitet.
Aus diesem Grund würde ich - wenn nur irgendwie nachvollziehbar möglich - lieber GDI+ verwenden. Dann würden meine Texte auf dem Bildschirm UND auf dem Drucker praktisch vollkommen übereinstimmen.
-
Ich bin nicht sicher, wie du das meinst, aber ich denke, das ist im Endeffekt egal. Wenn du die Daten irgendwie "speicherst", dann solltest du eigene Einheiten verwenden, die möglichst genau und geräteunabhängig auflösen, z.B. in Bruchteilen von mm.
Aber wenns dann ums "Zeichnen" geht, versteh ich nicht, wo du hier WYSIWYG siehst oder nicht siehst. Wenn du die Ausgabe für den Drucker berechnest, hast du ein anderes Device Context, als wenn du die für den Bildschirm berechnest. Oder wolltest du die für den Bildschirm voberechnen und dann für den den Drucker einfach hochskalieren? Das wäre in der Tat nicht sinnvoll.
-
@Mechanics
Zwischen Speichern (bzw. Laden) und Zeichnen muss man erstmal noch das Layout erstellen.Wenn dieser Teil über GDI implementiert ist, dann ist er deviceabhängig, und dadurch kann es passieren dass für den Schirm z.B. Zeilenumbrüche anders gesetzt werden als für den Drucker. Das ist dann doof.
Deswegen muss die Layout-/Flow-Engine deviceunabhängig arbeiten.
Und wenn die Layout-/Flow-Engine deviceunabhängig arbeitet, dann muss auch der Renderer/Rasterizer deviceunabhängig arbeiten. Weil er sonst u.U. den Text gar nicht in den von der Layout-/Flow-Engine berechneten Platz reinbringt. Oder viel zu wenig braucht. Was dann beides doof aussieht.
@WishfulThinking
Ich denke du hast dich da verschrieben:GDI funktioniert pixelorientiert und damit unbedingt von der Ausgabe-Device.
Ich würde hier "abhängig" schreiben. "unbedingt" macht hier für mich keinen Sinn. Wenn dann würde ich "unbedingt" als "unabhängig" interpretieren, und das ist es ja gerade nicht.
Und "Device" wird im Deutschen üblicherweise als Neutrum verwendet. Also "das Device", nicht "die Device"
-
hustbaer schrieb:
@Mechanics
Zwischen Speichern (bzw. Laden) und Zeichnen muss man erstmal noch das Layout erstellen.Ich seh das Layouten erstmal als Teil des Zeichnens. Je nachdem, um welche Datenmengen es geht, würde ich es dann direkt beim Zeichnen machen, device abhängig. Wenn man aber tatsächlich sowas wie eine Textverarbeitung schreibt, die das Layout mitspeichert und unabhängig von der Ausgabe wissen muss, wieviele Seiten es gibt usw., dann muss man das Layout natürlich geräteunabhängig bestimmen.
-
Mechanics schrieb:
Je nachdem, um welche Datenmengen es geht, würde ich es dann direkt beim Zeichnen machen, device abhängig.
Dann kann es sein dass das Dokument im Editor anders aussieht als auf dem Ausdruck.
Und das bedeutet: du hast kein WYSIWYG mehr. Genau das was WishfulThinking geschrieben hat.Ich verstehe nicht wo hier kein Bezug zu WYSIWYG zu sehen sein soll
-
@WishfulThinking
Guck dir mal GetCharacterPlacement an.Ansonsten gäbe es noch die Uniscribe API und natürlich DirectWrite
-
hustbaer schrieb:
@WishfulThinking
Ich denke du hast dich da verschrieben:GDI funktioniert pixelorientiert und damit unbedingt von der Ausgabe-Device.
Ich würde hier "abhängig" schreiben. "unbedingt" macht hier für mich keinen Sinn. Wenn dann würde ich "unbedingt" als "unabhängig" interpretieren, und das ist es ja gerade nicht.
Und "Device" wird im Deutschen üblicherweise als Neutrum verwendet. Also "das Device", nicht "die Device"Danke, ich habe mich tatsächlich verschrieben. Es hätte heißen sollen "unbedingt deviceabhängig". Das werde ich der Klarkeit halber im alten Posting editieren.
Und noch danke für den zweiten Rechtschreibtipp. Ein Device ist eine Sache, sogar in der deutschen Sprache. Das war fehlerhafte Anwendung von Neu-Hochdeutsch.Die Funktion
GetCharacterPlacement
habe ich mir bereits angesehen. Das bringt die Angelegenheit leider nicht weiter wegen der Begrenzung der GDI-Auflösung auf ganze Pixel.Die beiden anderen Funktionen werde ich mir noch genauer ansehen.
Trotzdem bleibt die Frage erst einmal offen: Wie hat z.B. WORD das Problem gelöst? Da haben wir ganz offensichtlich ein deviceunabhängiges Layout. UniScribe und DirectWrite sind deutlich neuer als WORD.
(Ich habe nicht den Ehrgeiz, einen neuen Texteditor zu schreiben, ich möchte einfach nur dasselbe Layout für verschiedene Devices (z.B. Bildschirm und Drucker) verwenden können.)
-
WishfulThinking schrieb:
(Ich habe nicht den Ehrgeiz, einen neuen Texteditor zu schreiben, ich möchte einfach nur dasselbe Layout für verschiedene Devices (z.B. Bildschirm und Drucker) verwenden können.)
Dann guck dir mal DirectWrite an. Ich kenn mich damit nicht gut genug aus um sagen zu können ob man damit an die "detailierten" Layout-Infos drankommt die man draucht um z.B. einzelne Buchstaben innerhalb eines Wortes anders einfärben zu können, aber ich würde schätzen dass es geht.
WishfulThinking schrieb:
Wie hat z.B. WORD das Problem gelöst? Da haben wir ganz offensichtlich ein deviceunabhängiges Layout. UniScribe und DirectWrite sind deutlich neuer als WORD.
Word hat mit an Sicherheit grenzender Wahrscheinlichkeit ne eigene Layout-Engine die die nötigen Infos direkt aus den Fonts rauszieht und halt alles "zu fuss" macht.
Internet Explorer hat damals zu Windows 98 Zeiten soweit ich weiss Uniscribe verwendet.
Auf jeden Fall ist Uniscribe mit dem IE mit installiert worden, wodurch der IE dann auch auf z.B. Windows 95 oder 98 Unicode Text korrekt darstellen konnte (inklusive Arabisch und andere "Complex-Scripts" -- wohingegen die GDI Funktionen von Windows 95/98 mit arabsich genau nix anfangen können, denen fehlt der Layout Code für die komplexen Ligaturen/Substitutions die Arabisch benötigt).
Wobei ich heute nix mehr mit Uniscribe anfangen würde. Die Library ist schon sehr alt, und falls es mit DirectWrite geht gehe ich davon aus dass es damit angenehmer und vermutlich auf performanter geht.
(Wobei IE natürlich nicht Device-independent layouten muss. Ist nur das einzige Programm wo ich eine solide Grundlage habe Vermutungen darüber anzustellen welche API zum Layouten verwendet wurde.)Oder du schreibst eben deinen eigenen Layout-Code. So lange du kein RTL und keine Complex-Scripts unterstützen musst ist das auch nicht SO schwer. Im Prinzip brauchst du dazu nur die ABC Widths und die Kerning-Pairs. Grid-Fitting und Hinting brauchst du ja nicht zu berücksichtigen wenn du Device-independent layouten willst.
Und Rendern kannst du dann mit GDI+, FreeType, DirectWrite - ziemlich egal so lange es nur eine Lib ist wo man Grid-Fitting abdrehen kann (und idealerweise Subpixel Koordinaten übergeben).