Macht DrawText() einen guten Job?

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
es_91
Beiträge: 410
Registriert: 25.01.2011 04:48

Macht DrawText() einen guten Job?

Beitrag von es_91 »

Im Test machen die Schriftzüge, die DrawText() auf's Image ausgibt einen echt schlechten optischen Eindruck. Das kann man im Vergleich daran erkennen, dass bei Übergröße und den gängigen Mitteln der Skalierung weit mehr Brillianz und Schärfe vorzufinden wären (wenn es das System performancemäßig erlaubt).

Stellt einfach in dem Quellcode mal den canvas::#scalingFactor auf 2, 4 oder 8 und die Schrift sieht bedeutend besser aus.


PB 5.73

Code: Alles auswählen

; Test ob ein verkleinertes Image besser lesbare Schrift beinhalten kann
; 25.05.2025 // 05:00 CMT+2



declareModule  app
;{
	
	
	;{
		
		
		#cv_text$  =  "Skalierung (Schrift auf Image, Image auf Canvas)"
		
		
	;}
	
	
	;{
		
		
		declare  execute  (  )
		
		
	;}
	
	
;}
endDeclareModule



declareModule  canvas
;{
	
	
	;{
		
		
		#scalingFactor  =  1.0
		
		
	;}
	
	
	;{
		
		
		declare  get  (  )
		
		declare  init  (  *window  )
		
		declare  paint  (  )
		
		
	;}
	
	
;}
endDeclareModule



declareModule  window
;{
	
	
	declare  finish  (  )
	
	declare  init  (  )
	
	declare  inputCB  (  )
	
	
;}
endDeclareModule



module  app
;{
	
	
	procedure  execute  (  )
	;{
		
		
		if  (  window::init  (  )  )
		;{
			
			
			repeat
			until  (  window::inputCB  (  )  )
			
			
			window::finish  (  )
			
			
			procedureReturn
			
			
		;}
		endIf
		
		
		procedureReturn  (  #true  )
		
		
	;}
	endProcedure
	
	
;}
endModule



module  canvas
;{
	
	
	;{
		
		
		define  *canvas
		
		
	;}
	
	
	;{
		
		
		procedure  get  (  )
		;{
			
			
			;{
				
				
				shared  *canvas
				
				
			;}
			
			
			;{
				
				
				procedureReturn  (  *canvas  )
				
				
			;}
			
			
		;}
		endProcedure
		
		
		procedure  init  (  *window  )
		;{
			
			
			;{
				
				
				shared  *canvas
				
				
			;}
			
			
			;{
				
				
				if  (  (  *window  )  and  (  isWindow  (  *window  )  )  )
				;{
					
					
					if  (  useGadgetList  (  windowId  (  *window  )  )  )
					;{
						
						
						*canvas  =  canvasGadget  (  #pb_any,  
						                             0,  
						                             0,  
						                             0,  
						                             0  )
						
						
						procedureReturn  (  *canvas  )
						
						
					;}
					endIf
					
					
				;}
				endIf
				
				
			;}
			
			
			procedureReturn
			
			
		;}
		endProcedure
		
		
		procedure  paint  (  )
		;{
			
			
			;{
				
				
				protected  *image
				
				static  *font
				
				
			;}
			
			
			;{
				
				
				shared  *canvas
				
				
			;}
			
			
			;{
				
				
				if  (  (  not  (  *font  )  or  (  not  (  isFont  (  *font  )  )  )  )  )
				;{
					
					
					*font  =  loadFont  (  #pb_any,  
					                       "Arial",  
					                       #scalingFactor  *  12.0  )
					
					
				;}
				endIf
				
				
				*image  =  createImage  (  #pb_any,  
				                           #scalingFactor  *  gadgetWidth  (  *canvas  ),  
				                           #scalingFactor  *  gadgetHeight  (  *canvas  )  )
				
				
				if  (  (  (  *image  )  and  
				(  isImage  (  *image  )  )  and  
				(  startDrawing  (  imageOutput  (  *image  )  )  )  )  )
				;{
					
					
					if  (  (  (  *font  )  and  (  isFont  (  *font  )  )  )  )
					;{
						
						
						drawingFont  (  fontId  (  *font  )  )
						
						
						box  (  0,  
						        0,  
						        imageWidth  (  *image  ),  
						        imageHeight  (  *image  ),  
						        #white  )
						
						
						drawText  (  25,  
						             25,  
						             app::#cv_text$,  
						             #black,  
						             #white  )
						
						
					;}
					endIf
					
					
					stopDrawing  (  )
					
					
				;}
				endIf
				
				
				resizeImage  (  *image,  
				                gadgetWidth  (  *canvas  ),  
				                gadgetHeight  (  *canvas  )  )
				
				
				if  (  startDrawing  (  canvasOutput  (  *canvas  )  )  )
				;{
					
					
					drawImage  (  imageId  (  *image  ),  
					              0,  
					              0  )
					
					
					stopDrawing  (  )
					
					
					freeImage  (  *image  )
					
					
					procedureReturn  (  #true  )
					
					
				;}
				endIf
				
				
			;}
			
			
			procedureReturn
			
			
		;}
		endProcedure
		
		
	;}
	
	
;}
endModule



module  window
;{
	
	
	;{
		
		
		define  *window
		
		
	;}
	
	
	;{
		
		
		declare  sizing  (  )
		
		
	;}
	
	
	;{
		
		
		procedure  finish  (  )
		;{
			
			
			;{
				
				
				shared  *window
				
				
			;}
			
			
			;{
				
				
				unbindEvent  (  #pb_event_sizeWindow,  
				                @  sizing  (  )  )
				
				closeWindow  (  *window  )
				
				
				procedureReturn  (  #true  )
				
				
			;}
			
			
			procedureReturn
			
			
		;}
		endProcedure
		
		
		procedure  init  (  )
		;{
			
			
			;{
				
				
				shared  *window
				
				
			;}
			
			
			;{
				
				
				*window  =  openWindow  (  #pb_any,  
				                           #pb_ignore,  
				                           #pb_ignore,  
				                           640,  
				                           400,  
				                           #empty$,  
				                           #pb_window_invisible  |  
				                           #pb_window_systemMenu  |  
				                           #pb_window_sizeGadget  )
				
				
				bindEvent  (  #pb_event_sizeWindow,  
				              @  sizing  (  )  )
				
				
				if  (  canvas::init  (  *window  )  )
				;{
					
					
					sizing  (  )
					
					
					hideWindow  (  *window,  
					               #false  )
					
					
					procedureReturn  (  #true  )
					
					
				;}
				endIf
				
				
				procedureReturn
				
				
			;}
			
			
		;}
		endProcedure
		
		
		procedure  inputCB  (  )
		;{
			
			
			procedureReturn  (  bool  (  waitWindowEvent  (  )  =  #pb_event_closeWindow  )  )
			
			
		;}
		endProcedure
		
		
		procedure  sizing  (  )
		;{
			
			
			;{
				
				
				shared  *window
				
				
			;}
			
			
			;{
				
				
				resizeGadget  (  canvas::get  (  ),  
				                 0,  
				                 0,  
				                 windowWidth  (  *window  ),  
				                 windowHeight  (  *window  )  )
				
				
				canvas::paint  (  )
				
				
			;}
			
			
		;}
		endProcedure
		
		
	;}
	
	
;}
endModule



app::execute  (  )



; es_91
; Please excuse my style

(Kurz was das Programm macht: Schreibe auf ein Image, passe dieses in einen Canvas ein und update das ganze bei jeder Fenstergrößenänderung.)


Kann man denn vielleicht behaupten, dass DrawText() für individuelle GUI-Designs kaum geeignet ist? :|
Benutzeravatar
mk-soft
Beiträge: 3844
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Macht DrawText() einen guten Job?

Beitrag von mk-soft »

Es wird die Standard API von Windows verwendet.
Hier ist die Verwendung von VectorDrawing die Ausgabe etwas besser.
Mit Skalierung ist bei meinen Monitor (und Brille) keine große Verbesserung sichtbar

Hinweis:
Dein Code ist kaum lesbar. Viel zu viele Leerzeichen und Zeilen.
Solltest dir unbedingt wieder abgewöhnen.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
es_91
Beiträge: 410
Registriert: 25.01.2011 04:48

Re: Macht DrawText() einen guten Job?

Beitrag von es_91 »

Ja, bei VectorDrawing scheint ClearText etwas besser zu funktionieren.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Macht DrawText() einen guten Job?

Beitrag von NicTheQuick »

Der Code ist so viel zu unübersichtlich. Wie soll man da einen Überblick bekommen, was du überhaupt tust, wenn pro Bildschirm nur gefühlt 5 Zeilen stehen, obwohl über 60 drauf passen würden?
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Macht DrawText() einen guten Job?

Beitrag von NicTheQuick »

Hier, so muss man nur noch ein Mal scrollen um alles zu überblicken:

Code: Alles auswählen

; Test ob ein verkleinertes Image besser lesbare Schrift beinhalten kann
DeclareModule app
	#cv_text$ = "Skalierung (Schrift auf Image, Image auf Canvas)"
	Declare execute()
EndDeclareModule

DeclareModule canvas
	#scalingFactor = 1.0
	Declare get()
	Declare init(*window)
	Declare paint()
EndDeclareModule

DeclareModule window
	Declare finish()
	Declare init()
	Declare inputCB()
EndDeclareModule

Module app
	Procedure execute()
		If window::init()
			Repeat
			Until window::inputCB()
			window::finish()
			ProcedureReturn
		EndIf
		ProcedureReturn(#True)
	EndProcedure
EndModule

Module canvas
	Define *canvas
	
	Procedure get()
		Shared *canvas
		ProcedureReturn *canvas
	EndProcedure
	
	Procedure init(*window)
		Shared *canvas
		If *window And IsWindow(*window)
			If UseGadgetList(WindowID(*window))
				*canvas = CanvasGadget(#PB_Any, 0, 0, 0, 0)
				ProcedureReturn *canvas
			EndIf
		EndIf
		
		ProcedureReturn
	EndProcedure
	
	Procedure paint()
		Protected *image
		Static *font
		Shared *canvas
		If (Not *font) Or (Not IsFont(*font))
			*font = LoadFont(#PB_Any, "Arial", #scalingFactor * 12.0)
		EndIf
		
		*image = CreateImage(#PB_Any, #scalingFactor * GadgetWidth(*canvas), #scalingFactor * GadgetHeight(*canvas))
		
		If *image And IsImage(*image) And StartDrawing(ImageOutput(*image))
			If *font And IsFont(*font)
				DrawingFont(FontID(*font))
				
				Box(0, 0, ImageWidth(*image), ImageHeight(*image), #White)
				
				DrawText(25, 25, app::#cv_text$, #Black, #White)
			EndIf
			StopDrawing()
		EndIf
		
		ResizeImage(*image, GadgetWidth(*canvas), GadgetHeight(*canvas))
		
		If StartDrawing(CanvasOutput(*canvas))
			DrawImage(ImageID(*image), 0, 0)
			
			StopDrawing()
			FreeImage(*image)
			ProcedureReturn #True
		EndIf
		
		ProcedureReturn #False
	EndProcedure
EndModule

Module window
	Define *window
	Declare sizing()
	
	Procedure finish()
		Shared *window
		UnbindEvent(#PB_Event_SizeWindow, @sizing())
		
		CloseWindow(*window)
		
		ProcedureReturn #True
		
		ProcedureReturn
	EndProcedure
	
	Procedure init()
		Shared *window
		*window = OpenWindow(#PB_Any, #PB_Ignore, #PB_Ignore, 640, 400, #Empty$, #PB_Window_Invisible | #PB_Window_SystemMenu | #PB_Window_SizeGadget)
		
		BindEvent(#PB_Event_SizeWindow, @sizing())
		
		If canvas::init(*window)
			sizing()
			
			HideWindow(*window, #False)
			
			ProcedureReturn #True
		EndIf
		
		ProcedureReturn #False
	EndProcedure
	
	Procedure inputCB()
		ProcedureReturn Bool(WaitWindowEvent()  =  #PB_Event_CloseWindow)
	EndProcedure
	
	Procedure sizing()
		Shared *window
		
		ResizeGadget(canvas::get(), 0, 0, WindowWidth(*window), WindowHeight(*window))
		
		canvas::paint()
	EndProcedure
EndModule

app::execute()
Im Übrigen finde ich, dass der Skalierungsfaktor 1.0 am besten aussieht. Aber so viel Unterschied gab es auch nicht zu sehen. Ist vielleicht unter Linux nochmal anders als unter Windows.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Macht DrawText() einen guten Job?

Beitrag von STARGÅTE »

es_91 hat geschrieben: 25.05.2025 05:44 Stellt einfach in dem Quellcode mal den canvas::#scalingFactor auf 2, 4 oder 8 und die Schrift sieht bedeutend besser aus.
Also ich empfinde bei meinem System (Windows 10, aktives ClearType) und Bildschirmen (DELL P2421, IPS) die Darstellung der skalierten Texte schlechter, da diese fetter und unsauberer wirken, da die Außenkanten nicht mehr per ClearType gerendert werden (also auf die Sub-Pixel des Displays zugeschnitten werden), sondern mit normalem anti-aliasing.
Hast du denn ClearType bei dir aktiviert und kalibriert?

Bild
Bild
es_91 hat geschrieben: 25.05.2025 11:46 Ja, bei VectorDrawing scheint ClearText etwas besser zu funktionieren.
VectorDrawing hat kein ClearType, dort gibt es nur das normale Anti-Aliasing.
Wobei DrawVectorParagraph() komischerweise ClearType nutzt, hier ein Beitrag von mir dazu:
Qualität von DrawVectorText unter Win 10 schlimmer in Win 7
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
es_91
Beiträge: 410
Registriert: 25.01.2011 04:48

Re: Macht DrawText() einen guten Job?

Beitrag von es_91 »

Hallo

Ich nutze einen nicht-entspiegelten 16:10 Bildschirm von 2017, aber ich glaube wir könnten es anders auf den Punkt bringen:

die 8x-Skalierung scheint den Text 3D-mäßiger hinzubekommen. Oder?

So sieht das ganze bei mir aus:
Da es Unterschiede in der (raschen) Wahrnehmung geben könnte mag ich hinzufügen, dass mir der 1x Zoom zu fett, der 2x Zoom zu pixelig und erst der 8x Zoom angenehm rund und ausgeglichen vorkommen. Ich kann mir nicht erklären warum unterschiedliche Monitore ein anderes Ergebniss bedeuten würden, aber vielleicht liegt es tatsächlich am ClearType-Algo. Bei mir ist ClearType an, jedoch etwas umkalibriert. Ich nutze auch nicht die maximale Auflösung meines Monitors.

Bild

Kleiner Nachtrag: Im Test bei voller Auflösung (1920x1200) wirken 4x ausreichend und angenehm UND TATSÄCHLICH 2x BESSER ALS 8x !!

Das ist ein bisschen blöd, solche Berechnungen sind Zeitintensiv und bringen Anwendungen auf langsamen Systemen zum stocken. Naja. Ist wohl eben so. :|

Zweiter Nachtrag: Auch bei exakt halber Desktopauflösung wirkt 2x besser als alles andere. Seltsam.

Hatte zu Beginn 2/3 Auflösung.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Macht DrawText() einen guten Job?

Beitrag von NicTheQuick »

Du meinst du nutzt deinen Flachbildschirm nicht in nativer Auflösung? Das erklärt so einiges. Dann sehen Schriften doch immer schwammig und falsch aus und da kann dann auch Cleartype mit Subpixelrendering nicht mehr viel tun.

Besser wäre es, wenn du deinen Monitor in der nativen Auflösung nutzen würdest. Und wenn dir damit alles zu klein sein sollte, kannst du die DPI in Windows erhöhen. Dafür ist sie da. Wenn du dann noch ClearType richtig einstellst, solltest du gar keine Schrift mehr in mehrfacher Auflösung rendern müssen.

Glaub mir, da haben andere Leute, die wesentlich mehr davon verstehen, schon alles erledigt. Du musst es nur nutzen. Es wäre doch sehr komisch, wenn seit Jahrzehnten Schriften schlecht gerendert werden würden. Da hätten sich ja schon Millionen beschwert.
es_91
Beiträge: 410
Registriert: 25.01.2011 04:48

Re: Macht DrawText() einen guten Job?

Beitrag von es_91 »

Nun, mein Gedanke war dass ich von einem Endanwender auch nicht erwarten kann, in jeder Beziehung "modern" zu sein. Wenn er Spiele zockt und eine langsame Grafikkarte hat wird er upscaling gewohnt sein... dann kann man eben tatsächlich mit umständlicherem Rendering punkten, falls man soviel Rechenleistung übrig hat.

Oder irre ich da? Ob das Sinn macht, es im Hintergrund so programmieren, mag ich nicht einschätzen, ich war nur interessiert an einer besseren Optik innerhalb der PB-Möglichkeiten.

Danke für all Eure Mühen. :)
es_91
Beiträge: 410
Registriert: 25.01.2011 04:48

Re: Macht DrawText() einen guten Job?

Beitrag von es_91 »

Ich habe hier nochmal ein klareres Testprogram geschrieben (diesmal ohne die Formatierungsart von oben).

Es zeigt alle Zustände mit und ohne VectorDrawing. Schön zum Spielen. Allerdings habe ich, anders als auf dem Bild unten, den scaling Faktor nochmal um 3 erhöht weil dadurch die Schriftarten erst (fast) exakt gleich aussehen. Siehe code.

Code: Alles auswählen

; 2DDrawing vs. VectorDrawing
; es_91, 2025

#globalFontSize = 16

Global *window
Global *canvas

Declare paint ()
Declare sizing ()


Procedure scaledImage (scaling. f, useVectorDrawing. b = #false)
	
	Protected imgLabel$  =  "scaling: " + Str (scaling)
	
	; HIER ANGEPASST UM KLARERE KONTUREN ZU HABEN
	
	scaling * 3
	
	; /
	
	*img = CreateImage (#PB_Any, 160 * scaling, 40 * scaling)
	
	*font = loadFont (#pb_any, 
		              "Arial", 
		              scaling * #globalFontSize)
	
	If *font And IsFont (*font) And *img And IsImage (*img)
		
		If StartDrawing (ImageOutput (*img))
			
			Box (0, 
			     0, 
			     ImageWidth (*img), 
			     ImageHeight (*img), 
			     #white)
			
			StopDrawing ()
			
		EndIf
		
		If useVectorDrawing
		
			If StartVectorDrawing (ImageVectorOutput (*img))
				
				VectorFont (FontID (*font), 
					        scaling * #globalFontSize * 1.41) ; die VectorFont muss um Sqr(2) erhöht werden
				
				DrawVectorText (imgLabel$)
				
				StopVectorDrawing ()
				
				
			EndIf
			
		Else
			
			If StartDrawing (ImageOutput (*img))
				
				DrawingFont (FontID (*font))
				
				DrawText (0, 0, imgLabel$, #Black, #White)
				
				StopDrawing ()
				
			EndIf
			
		EndIf
		
		ResizeImage (*img, 160, 40)
		
		ProcedureReturn *img
		
	EndIf
	
EndProcedure


Procedure paint ()
	
	; Übernimmt das Zeichnen aller Images sowie des Canvas
	
	Protected *img1, *img2, *img4, *img8
	Protected *imgV1, *imgV2, *imgV4, *imgV8
	
	*img1 = scaledImage (1.0)
	*img2 = scaledImage (2.0)
	*img4 = scaledImage (4.0)
	*img8 = scaledImage (8.0)
	*img16 = scaledImage (16.0)
	*imgV1 = scaledImage (1.0, #true)
	*imgV2 = scaledImage (2.0, #true)
	*imgV4 = scaledImage (4.0, #true)
	*imgV8 = scaledImage (8.0, #true)
	*imgV16 = scaledImage (16.0, #true)
	
	If StartVectorDrawing (CanvasVectorOutput (*canvas))
		
		MovePathCursor (0, 0)
		DrawVectorImage (ImageID (*img1))
		
		MovePathCursor (0, 40)
		DrawVectorImage (ImageID (*img2))
		
		MovePathCursor (0, 80)
		DrawVectorImage (ImageID (*img4))
		
		MovePathCursor (0, 120)
		DrawVectorImage (ImageID (*img8))
		
		MovePathCursor (0, 160)
		DrawVectorImage (ImageID (*img16))
		
		MovePathCursor (240, 0)
		DrawVectorImage (ImageID (*imgV1))
		
		MovePathCursor (240, 40)
		DrawVectorImage (ImageID (*imgV2))
		
		MovePathCursor (240, 80)
		DrawVectorImage (ImageID (*imgV4))
		
		MovePathCursor (240, 120)
		DrawVectorImage (ImageID (*imgV8))
		
		MovePathCursor (240, 160)
		DrawVectorImage (ImageID (*imgV16))
		
		StopVectorDrawing ()
		
	EndIf
	
EndProcedure


; Das Hauptprogram


*window = openWindow (#pb_any, 
                      #pb_ignore, 
                      #pb_ignore, 
                      512, 
                      256, 
                      "Links: 2DDrawing, Rechts: VectorDrawing. (1x, 2x, 4x, 8x, 16x)", 
                      #pb_window_systemMenu|
                      #pb_window_minimizeGadget)

*canvas = canvasGadget (#pb_any, 
                        0, 
                        0, 
                        WindowWidth (*window),  
                        WindowHeight (*window))

paint ()

repeat : until waitWindowEvent () = #pb_event_closeWindow
Bild
Antworten