MeasureString und DrawString - GDI auf die harte Tour



  • 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

    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).



  • WishfulThinking schrieb:

    Ein Device ist eine Sache, sogar in der deutschen Sprache. Das war fehlerhafte Anwendung von Neu-Hochdeutsch.

    Ja, in dem Fall stimmt das üblicherweise verwendete Geschlecht für "Device" mit dem der deutschen Übersetzung "das Gerät" überein. Wobei es bei der Übersetzung "der Apparat" schon nicht mehr passt.

    Das Geschlecht der Übersetzung ist nicht immer anwendbar, "stimmen" tut letztlich das was von der Mehrzahl als "nicht falsch" angesehen wird 🙂



  • Naja, ich glaube, dies ist wohl eher ein WinAPI-Forum 😉

    Inzwischen habe ich mir schon einmal oberflächlich die DirectWrite -Umgebung angesehen. Ich gestehe, dieses Kapitel habe ich bisher aus Bequemlichkeit (die Schnittstelle ist ja um einiges umfangreicher als die von GDI) für mich ausgeblendet. Jetzt sehe ich aber schon, dass ich da wohl alle gewünschten Fontfamilien, Fontgrößen, Farben u.s.w. einstellen kann.

    Eine Layout-Engine, die auch Formatierungskommandos versteht, zu schreiben ist tatsächlich kein Hexenwerk, das habe ich in mehreren Varianten bereits mit GDI gemacht. Diese Engine hat allerdings den Nachteil der Auflösungsabhängigkeit/Geräteabhängigkeit, das möchte ich jetzt mit einer neuen Engine, wahrscheinlich sogar auf der Basis von DirectWrite, lösen. Das wird erst einmal einige kleine Versuche und anschließend einige größere Code-Umstellungen erfordern, aber es scheint die Mühe wert.

    GDI+ schein übrigens keine geeignete Basis für meine Layout-Engine zu sein. Nach der ersten Durchsicht der DirectWrite-Umgebung sehe ich jetzt auch ein, dass eine Zeile immer in einem Zuge geschrieben werden muss, weil es sonst in den Pixel-Spalten an der Grenze zwischen zwei Schreibvorgängen zu Konflikten kommt.



  • WishfulThinking schrieb:

    Nach der ersten Durchsicht der DirectWrite-Umgebung sehe ich jetzt auch ein, dass eine Zeile immer in einem Zuge geschrieben werden muss, weil es sonst in den Pixel-Spalten an der Grenze zwischen zwei Schreibvorgängen zu Konflikten kommt.

    Verstehe ich jetzt nicht ganz. Wo siehst du da ein Problem?

    Die Berechnung der Positionen für die einzelnen Glyphen muss in einem Rutsch gemacht werden, ja. Aber rausschreiben kann man die dann hübsch einzeln.
    Natürlich ist das Ergebnis theoretisch genauer wenn man erstmal die Vektordarstellung der ganzen Zeile erstellt, und dann alles auf einmal rasterized. Das macht aber keiner*, weil es viel zu langsam ist. Macht auch DirectWrite nicht.
    Und der Unterschied wird, wenn überhaupt mit freiem Auge sichtbar, vermutlich wirklich minimalst sein.

    *: Vermutlich gibt es Programme die doch genau das machen. Bzw. dann vermutlich gleich die ganze Seite auf einmal. Vielleicht Programme wie Corel-Draw und vergleichbare. Ich meine: keine normale Text-Rendering Engine wie sie für Text-Editoren, Browser etc. verwendet wird. Eben weil viel zu langsam.



  • vieleicht hilfts:

    /*
    ===============================================================================
    MeassureText_NitasTrickMethod
    
    ===============================================================================
    */
    void MeassureText_NitasTrickMethod(long *width, long *height, char *text, HDC hDCMem){
    
    	SIZE			sizeText, sizeLastCharacter;
    	RECT			rect;
    	HBITMAP		hBitmap, hOldBitmap;
    	int			i, iXmax, iYmed;
    	boolean			bFound;
    
    	GetTextExtentPoint32(hDCMem, text, lstrlen(text), &sizeText);
    	*height = sizeText.cy;
    	*width = sizeText.cx;
    	if((text == NULL) || (text[0] == '\0')){
    		TEXTMETRIC	tm;
    		GetTextMetrics(hDCMem,&tm);
    		*height = tm.tmHeight;
    		return;
    	}
    	GetTextExtentPoint32(hDCMem, &text[-1+lstrlen(text)], 1, &sizeLastCharacter);
    	rect.left = 0; 
    	rect.top = 0; 
    	rect.right = *width + sizeLastCharacter.cx; 
    	rect.bottom = *height;
    	hBitmap= CreateCompatibleBitmap(hDCMem, rect.right-rect.left, rect.bottom-rect.top);
    	hOldBitmap = (HBITMAP)SelectObject(hDCMem, hBitmap);
    	FillRect(hDCMem, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
    	SetBkColor(hDCMem,RGB(0,0,0)); 
    	DrawText(hDCMem, text, -1, &rect, (DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX));
    	iXmax = 0;
    	bFound = FALSE;
    	iYmed = (rect.bottom + rect.top)/2;
    	for(i = rect.right-1; i >= 0 && !bFound; i--){
    		COLORREF	rgbColor = GetPixel(hDCMem, i, iYmed);
    		if(rgbColor != RGB(255,255,255)){
    			iXmax = i;
    			bFound = TRUE;
    		}
    	}
    	*width = iXmax + 1;
    	SelectObject(hDCMem, hOldBitmap);
    	DeleteObject(hBitmap);
    }
    
    /*
    ===============================================================================
    MeassureText_SmartMethod
    
    ===============================================================================
    */
    void MeassureText_SmartMethod(long *width, long *height, char *text, HDC hDCMem){
    
    	SIZE			sizeText, sizeLastCharacter;
    	RECT			rect;
    	boolean			bFound;
    	int			x, y, iXmax;
    	HBITMAP		hBitmap, hOldBitmap;
    
    	GetTextExtentPoint32(hDCMem, text, lstrlen(text), &sizeText);
    	*height = sizeText.cy;																		//height==0 if the text is empty, so try GetTextMetrics below!
    	*width = sizeText.cx;
    	if((text == NULL) || (text[0] == '\0')){
    		TEXTMETRIC	tm;
    		GetTextMetrics(hDCMem,&tm);
    		*height = tm.tmHeight;
    		return;
    	}
    	GetTextExtentPoint32(hDCMem, &text[lstrlen(text) - 1], 1, &sizeLastCharacter);
    	rect.left = 0; 
    	rect.top = 0; 
    	rect.right = *width + sizeLastCharacter.cx; 
    	rect.bottom = *height;
    	hBitmap = CreateCompatibleBitmap(hDCMem, rect.right-rect.left, rect.bottom-rect.top);
    	hOldBitmap = (HBITMAP)SelectObject(hDCMem, hBitmap);
    	FillRect(hDCMem, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
    	DrawText(hDCMem, text, -1, &rect, (DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX));
    	iXmax = 0;
    	bFound = FALSE;
    	for(x = rect.right-1; x >= 0 && !bFound; x--){
    		for(y = 0; y <= rect.bottom-1 && !bFound; y++){
    			COLORREF	rgbColor = GetPixel(hDCMem,x,y);
    			if(rgbColor != RGB(255,255,255)){
    				iXmax = x;
    				bFound = TRUE;
    			}
    		}
    	}	
    	*width = iXmax + 1;
    	SelectObject(hDCMem, hOldBitmap);
    	DeleteObject(hBitmap);
    }
    
    /*
    ===============================================================================
    MeassureText_ClassicMethod
    
    ===============================================================================
    */
    void MeassureText_ClassicMethod(long *width, long *height, char *text, HDC hDC, double *dOverhangTrailing, boolean bAdjustOverhang){
    
    	SIZE			sizeText;
    	TEXTMETRIC		tm;
    
    	GetTextExtentPoint32(hDC, text, lstrlen(text), &sizeText);
    	*height = sizeText.cy;
    	*width = sizeText.cx;
    	GetTextMetrics(hDC,&tm);
    	*height = tm.tmHeight;
    	if(lstrlen(text) == 0){
    		return;
    	}
    	if(bAdjustOverhang){
    		ABCFLOAT	WidthsABC[256];
    		boolean		bResult;
    
    		*dOverhangTrailing = 0;
    		bResult = GetCharABCWidthsFloat(hDC,0,255, WidthsABC);
    		if(bResult){
    			*dOverhangTrailing = WidthsABC[text[lstrlen(text)-1]].abcfC;
    			if(*dOverhangTrailing < 0){
    				*width -= (LONG)*dOverhangTrailing;
    			}
    		}
    	}
    }
    
    /*
    ===============================================================================
    MeassureText_FontHandle
    
    misst die Textlänge und Breite, es wird ein Handle auf einen Font benötigt 
    ===============================================================================
    */
    boolean MeassureText_FontHandle(long *width, long *height, char *text, HFONT hFont, u_int method){
    
    	HDC			hDC, hDCMem;
    	HFONT			hFontOld;
    
    	hDC = GetDC(NULL);
    	switch(method){
    		case MESSURETEXT_NITASTRICK:
    			hDCMem = CreateCompatibleDC(hDC);
    			hFontOld = (HFONT)SelectObject(hDCMem, hFont);
    			MeassureText_NitasTrickMethod(width, height, text, hDCMem);
    			SelectObject(hDCMem, hFontOld);
    			DeleteDC(hDCMem);
    			break;
    		case MESSURETEXT_SMART:
    			hDCMem = CreateCompatibleDC(hDC);
    			hFontOld  = (HFONT)SelectObject(hDCMem, hFont);
    			MeassureText_SmartMethod(width, height, text, hDCMem);
    			SelectObject(hDCMem, hFontOld);
    			DeleteDC(hDCMem);
    			break;
    		case MESSURETEXT_CLASSIC:{
    			hFontOld = (HFONT)SelectObject(hDC, hFont);
    			MeassureText_ClassicMethod(width, height, text, hDC, 0, 0);
    			SelectObject(hDC, hFontOld);
    			break;
    		}
    	}
    	ReleaseDC(NULL, hDC);	
    	return TRUE;
    }
    
    /*
    ===============================================================================
    MeassureText_LogFont
    
    ===============================================================================
    */
    boolean MeassureText_LogFont(long *width, long *height, char *text, LOGFONT *lf, u_int method){
    
    	HFONT			hFont;
    	boolean			back;
    
    	hFont = CreateFontIndirect(lf);
    	if(!hFont){
    		return FALSE;
    	}
    	back = MeassureText_FontHandle(width, height, text, hFont, method);
    	DeleteObject(hFont);
    	return back;
    }
    


  • hustbaer schrieb:

    Ich verstehe nicht wo hier kein Bezug zu WYSIWYG zu sehen sein soll 😉

    Naja, das Dokument schaut auf dem Bildschirm so gut aus, wie es auf dem Bildschirm ausschauen kann, weil pixelgenau gerechnet wird. Auf dem Drucker schaut es so gut aus, wie es auf dem Drucker ausschauen kann, weil die Pixel kleiner sind. Aber das Problem hat man ja grundsätzlich. Das ist immer noch WYSIWYG. Aber ich besteh nicht drauf 😉 Entweder steh ich komplett auf dem Schlauch oder das ist Interpretationssache.

    Bei DirectWrite sind einige interessante Funktionen erst mit Windows 8 reingekommen, das würde den Nutzerkreis evtl. einschränken.



  • WYSIWYG heisst in dem Zusammenhang dass du das bekommst (=der Ausdruck) was du im Editor (=am Bildschirm) siehst.
    Wenn das Layouting deviceabhängig ist, und dadurch auf dem Ausdruck die Zeilenumbrücke/Seitenumbrüche etc. anders sind ... dann ist das ja wohl ganz klar und krass überhaupt nicht mehr das selbe.
    Und kann daher auch kein WYSIWYG sein.

    Und nur damit wir uns nicht falsch verstehen...
    Es kann durch deviceabhängigs Layouting sein dass es am Bildschirm so aussieht:

    The quick brown|
    fox jumped over|
    the lazy dog.  |
    

    Und beim Drucker kommt das dann so raus:

    The quick      |
    brown fox      |
    jumped over    |
    the lazy dog.  |
    

    Dadurch kann sich *alles* ändern was die Layout-/Flow-Engine so "flowt".

    Und da check grad echt nicht wie man das noch als WYSIWYG bezeichnen wollen würde 🙂



  • Ok, dass dabei mehr oder weniger Zeilen rauskommen können, habe ich nicht berücksichtigt, da hast du Recht. Ich dachte bisher immer an etwas unsauberes Kerning, aber nicht daran, dass der Unterschied natürlich so groß sein kann, dass die Zeile umbrochen wird.



  • @.-)

    .-) schrieb:

    vieleicht hilfts:

    Ja, schon möglich, dass ich gute Messergebnisse für die Textbreite bekomme. Aber das alles hilft nichts, wenn ich nicht - nachvollziehbar - dasselbe Ausgabeergebnis bekomme.

    @hustbaer

    hustbaer schrieb:

    Verstehe ich jetzt nicht ganz. Wo siehst du da ein Problem?
    Die Berechnung der Positionen für die einzelnen Glyphen muss in einem Rutsch gemacht werden, ja. Aber rausschreiben kann man die dann hübsch einzeln.

    Nein, das würde leider nicht zufriedenstellend funktionieren.
    Wenn ein Glyph innerhalb einer Pixelspalte endet und der nächste Glyph unmittelbar daran anschließend geschrieben werden soll, weiß der Renderer nicht, was beim vorangegangenen Glyph geschrieben wurde und beschreibt die Pixelspalte so, als ob der vorangegangene Rendering-Vorgang nicht stattgefunden hätte.



  • WishfulThinking schrieb:

    Wenn ein Glyph innerhalb einer Pixelspalte endet und der nächste Glyph unmittelbar daran anschließend geschrieben werden soll, weiß der Renderer nicht, was beim vorangegangenen Glyph geschrieben wurde und beschreibt die Pixelspalte so, als ob der vorangegangene Rendering-Vorgang nicht stattgefunden hätte.

    Meinst du den Fall wo...
    * Der nachfolgende Glyph "nahtlos" an den vorhergehenden anschliessen soll
    * Die Trennlinie mitten in einem Pixel liegt (statt genau zwischen zwei Pixeln)
    * Man ohne Grid-Fitting rendert
    ...und dadurch dann kein Nahtloser Zusammenschluss erfolgt? Sondern man statt dessen eine nicht vollständig schwarze Trennlinie bekommt.

    Der Fall ist in der Tat doof.

    Beheben liesse sich das indem man ala 3D Karten mit FSAA rendert. Also z.B. die 4-fache Auflösung horizontal und vertikal verwendet, dafür ohne klassischem Antialiasing, und dann zum schluss das gesamte Bild runterskaliert. Dabei könnte man die gerasterten Glyphen auch cachen. Die subpixel Genauigkeit bei der Positionierung wäre dann natürlich durch den Oversampling-Faktor begrenzt, aber ich denke das sollte kein Problem sein. Und vermutlich ist es performanter mit 16-facher (4x4) Auflösung Glyphen aus nem Cache zu kopieren als alles jedes mal neu zu rastern.

    Bzw. eine "nicht perfekt aber vermutlich gut genug" Lösung wäre wenn man die Pixel einfach additiv blendet (bzw. subtraktiv - additiv wenn man den Hintergrund mit 0.0 abbildet und die Glyphen mit 1.0, subtraktiv wenn man es ala "schwarz auf weiss" umgekehrt macht). Wobei der Renderer dazu natürlich halbwegs gute und vor allem lineare (=nicht Gamma-korrigierte) Coverage-Werte ausspucken muss.

    Aber ist schon irgendwie interessant wie nicht-trivial sowas triviales wie Anzeige von Text sein kann, wenn man es "ordentlich" machen will 🙂



  • Ja, WYSIWYG kann ich nur bekommen, wenn ich auf GridFitting verzichte. Ziel ist es, DASSELBE Layout auf dem Bildschirm (z.B. 96dpi) und auf dem Drucker (z.B. 1200dpi) zu bekommen. Der Zusammenhang ist nicht ganz einfach, ich muss ein wenig ausholen und hoffe, dass ich das so vollständig und korrekt darstelle:

    Eine Schrift wird in einem Designraster (i.d.R. 1024x1024 oder 2048x2048 Punkte) definiert. Wenn nun die Glyphs für eine konkrete Font-Instanz berechnet werden, muss bei GridFitting natürlich gerundet werden, und jetzt macht die Auflösung tatsächlich einen bedeutenden Unterschied. Nehmen wir mal an, die Breite eines bestimmten Glyph, der in 2048x2048 entworfen wurde, beträgt 800 Design-Einheiten; mit diesem Zeichen soll in der Schriftgröße 24 Punkt (auf dem Bildschirm bei 96dpi) und auf dem Drucker (1200dpi) eine Zeile der Breite von 10,0 Inch gefüllt werden.

    Unabhängig davon, welches Maßsystem ich bei GDI, GDI+,... verwende -- es läuft immer darauf hinaus, dass ich letztendlich Ausgabe-Pixel habe. Der Einfachheit halber will ich mich jetzt auch nur um die Zeichen-Breiten kümmern. Für die Umrechnung von Points in Pixel soll die allgemeine akzeptierte Formel {points = pixels * 72 / dpi} bzw. {pixels = points * dpi / 72} gelten.

    Ausgabe auf dem Bildschirm mit 96dpi:
    Die Schriftgröße 24Pt entspricht {24*96/72=32,0}Pixeln; 32 Pixel entsprechen also den 2048 Designraster-Punkten. Die 800 Designeinheiten des Beispiel-Zeichens rechnen sich um in {32/2048*800} 12,5 Pixel. Ich nehme mal an, dass dieser Wert fürs Gridfitting auf 13 Pixel aufgerundet wird -- der Glyph wird entsprechend skaliert.
    Die Ausgabezeile hat eine Breite von 10,0 Inch; das sind bei 96dpi 960 Pixel. Das Zeichen mit der Breite von 13 Pixel geht also 960/13=73,85 mal in die Zeile.

    Jetzt möchte ich die Ausgabe auf dem Drucker (bei 1200 dpi) wiederholen:
    Die Schriftgröße 24Pt entspricht {24*1200/72=400}Pixel; 400 Pixel entsprechen also den 2048 Designraster-Punkten. Die 800 Designeinheiten des Beispiel-Zeichens rechnen sich um in {400/2048*800} 156,25 Pixel. Ich nehme mal an, dass dieser Wert fürs Gridfitting auf 156 Pixel abgerundet wird -- der Glyph wird entsprechend skaliert.
    Die Ausgabezeile hat eine Breite von 10,0 Inch; das sind bei 1200dpi 12000 Pixel. Das Zeichen mit der Breite von 156 Pixel geht also 12000/156=76,92 mal in die Zeile.

    GridFit?
    Das ist ein willkürlich herausgegriffenes Beispiel mit einem einzigen Zeichen. Je nachdem, wie der Mix der Zeichen in einer Zeile ist, kann das Layout durch Auf- und Abrunden sich mehr oder weniger stark verändern.
    Ich glaube, damit konnte ich zeigen, dass GridFit nicht die taugliche Mess- und Ausgabemethode ist, wenn man dasselbe Layout auf dem Bildschirm und auf dem Drucker (also: WYSIWYG) erzielen möchte. Das kann ich nur dann zufriedenstellend hinbekommen, wenn ich auf das Auf- und Abrunden der GridFit-Methode verzichte. Damit läge die Trennlinie zwischen zwei Zeichen wohl immer innerhalb einer Pixel-Spalte. Oder sieht da noch jemand einen Fehler in meiner Darstellung?
    (Vielleicht sollte ich in der Darstellung nicht den Begriff "Glyph" sondern lieber den Begriff "Zeichen" verwenden; das "Zeichen" enthält zusätzlich noch den designbedigten Lerrraum vor und nach dem Glyph)



  • WishfulThinking schrieb:

    Damit läge die Trennlinie zwischen zwei Zeichen wohl immer innerhalb einer Pixel-Spalte. Oder sieht da noch jemand einen Fehler in meiner Darstellung?

    Nö das wird schon hinkommen.
    Ist aber Wurst, wenn ohne Antialiasing gerendert wird.
    Mit klassischem Antialiasing wie schon erwähnt ein Problem.



  • Naja, jetzt haben wir nachgewiesen, warum der Schuh drückt -- es tut aber immer noch weh. Den "Schmerz" versuche ich jetzt auf der Suche nach einer Mess- und Renderlogik, die dieselben Ergebnisse liefern sollen, zu lindern. Ich mache also weiter mit meiner Exploration von [c]DirectWrite[/c].



  • Die DirectWrite-Methode IDWriteFactory::CreateTextLayout erlaubt, soweit ich sehe, nur die Anwendung eines einzigen Font innerhalb des Layout (=Zeile?). In einem solchen Layout kann ich alle möglichen Parameter der Schrift verändern (Fett, kursiv, unterstrichen, Größe), aber ich habe noch keine Methode gefunden, mit der ich den Font selbst für einen Teil des Layout ändern kann. Habe ich da etwas übersehen? 😃



  • Hat sich schon erledigt ..... IDWriteTextLayout::SetFontFamilyName 😃

    Es steht ja alles in der Dokumentation ..... man muss es eben nur finden (Nachdem man es genügend intensiv gesucht hat).



  • So, jetzt bin ich ein gutes Stück weiter. Ich habe in den vergangenen Tagen intensiv mit DirectWrite experimentiert (Dank an hustbaer für den Tipp) und weiß jetzt schon, dass alle meine Anforderungen mit dieser Engine erfüllt werden.

    Für alle, die auch an der Anwendung von DirectWrite interessiert sind, hier habe ich einige Links, die mir bei meinen Experimenten erheblich weitergeholfen haben:

    Aber alle diese Quellen drücken sich um das Thema TABulation. Lediglich in der MSDN-Dokumentation wird die Existenz der Funktionen SetIncrementalTab und GetIncrementalTab sehr sparsam zugegeben. Man erfährt leider nicht, wie diese TABs in der Praxis angewendet werden können: So würde ich z.B. sehr gerne (und dringend) wissen, wie man das Text-Alignment für die verschiedenen TAB-Spalten einstellt.
    Weiß jemand, wie das funktioniert; oder kennt jemand eine Quelle, in der dieses offenbar sehr spezielle DirectWrite-Thema näher beleuchtet wird?


Anmelden zum Antworten