Textbreite ermitteln, Vergleich PB zu Api

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Textbreite ermitteln, Vergleich PB zu Api

Beitrag von hjbremer »

Hier mal ein Vergleich der Methoden zur Ermittlung der Textbreite zwischen PB und Api Funktionen.

Bei mir sind die Geschwindigkeitswerte ca 640 zu 530 ohne Debugger.

Außerdem hätte ich gerne eure Meinung gewußt. Welche Methode haltet ihr für die Bessere. Mal abgesehen von der Geschwindigkeit. Oder gibt es noch eine Bessere ?

Code: Alles auswählen

Procedure.l TextBreitePB(fontid,txt$)

    StartDrawing(WindowOutput(0))
            
        If fontid
           DrawingFont(fontid) 
        EndIf
    
        br = TextWidth(txt$) 
            
    StopDrawing() 
    
    ProcedureReturn br

EndProcedure


Procedure TextbreiteApi(fontid,txt$,handle)
    
    dc=GetDC_(handle)
    SelectObject_(dc,fontid)     
    GetTextExtentPoint32_(dc,@txt$,Len(txt$),s.size)
    ReleaseDC_(handle,dc)
    
    ProcedureReturn s\cx
    
EndProcedure

;=======================================================

fontid = FontID(LoadFont(#PB_Any, "arial", 8))  

max=100000
txt$="TeststringTeststringTeststring"

hwnd = OpenWindow(0, 0,0, 100, 100, "Test",#PB_Window_SystemMenu | 1) 
       CreateGadgetList(WindowID(0)) 
    
       buttonnr=ButtonGadget(#PB_Any,0,0,80,40,txt$)
       buttonid=GadgetID(buttonnr)
       
       SetGadgetFont(buttonnr,fontid)
       
       a=GetTickCount_()
         For j=1 To max
          br1=TextBreitePB (fontid,txt$)
         Next
       b=GetTickCount_()-a
       
       
       a=GetTickCount_()
         For j=1 To max
          br2=TextBreiteApi(fontid,txt$,hwnd) ;oder buttonid)
         Next
       c=GetTickCount_()-a
       MessageRequester(Str(br1)+"-"+Str(br2),"PB "+Str(b)+#LF$+"Api "+Str(c))
   
;Repeat 
;Until WaitWindowEvent() = #PB_Event_CloseWindow    
PS: Die IF Abrage in der PB Methode sollte da sein, falls fontid null ist, bzw auf einen nicht geladenen Font verweist.
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Hi,

450 zu 350.

Ich nehm die Schnelle Methode ;-)

Du solltest aber der fairnisshalber das StartDrawing auslagern, da man die Funktion ohnehin nur in solchen Blöcken aufruft...

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7032
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag von STARGÅTE »

Beide zu langsam. da habe ich hier n schnellere Variante:

Code: Alles auswählen

Procedure.l TextBreitePB(fontid,txt$) 

    StartDrawing(WindowOutput(0)) 
            
        If fontid 
           DrawingFont(fontid) 
        EndIf 
    
        br = TextWidth(txt$) 
            
    StopDrawing() 
    
    ProcedureReturn br 

EndProcedure 


Global Dim ZeichenLen(255)
Procedure Einlesen(fontid)
 StartDrawing(WindowOutput(0))
  If fontid 
   DrawingFont(fontid) 
  EndIf 
  For n = 1 To 255
   ZeichenLen(n) = TextWidth(Chr(n))
  Next
 StopDrawing()
EndProcedure
Procedure TextBreiteIch(txt$) 
 len = Len(txt$)-1
 For n = 0 To len
  br + ZeichenLen(PeekB(@txt$+n))
 Next n   
 ProcedureReturn br
EndProcedure 



Procedure TextbreiteApi(fontid,txt$,handle) 
    
    dc=GetDC_(handle) 
    SelectObject_(dc,fontid)      
    GetTextExtentPoint32_(dc,@txt$,Len(txt$),s.size) 
    ReleaseDC_(handle,dc) 
    
    ProcedureReturn s\cx 
    
EndProcedure 

;======================================================= 

fontid = FontID(LoadFont(#PB_Any, "arial", 8))  
max=100000 
txt$="TeststringTeststring" 

hwnd = OpenWindow(0, 0,0, 100, 100, "Test",#PB_Window_SystemMenu | 1) 
       CreateGadgetList(WindowID(0)) 

Einlesen(fontid)
    
       buttonnr=ButtonGadget(#PB_Any,0,0,80,40,txt$) 
       buttonid=GadgetID(buttonnr) 
        
       SetGadgetFont(buttonnr,fontid) 
        
       a=GetTickCount_() 
         For j=1 To max 
          br1=TextBreitePB(fontid,txt$) 
         Next 
       b=GetTickCount_()-a 
         
       a=GetTickCount_() 
         For j=1 To max 
          br2=TextBreiteApi(fontid,txt$,hwnd) ;oder buttonid) 
         Next 
       c=GetTickCount_()-a 
       
       a=GetTickCount_() 
         For j=1 To max 
          br3=TextBreiteIch(txt$) 
         Next 
       d=GetTickCount_()-a 

       MessageRequester(Str(br1)+"-"+Str(br2)+"-"+Str(br3),"PB "+Str(b)+#LF$+"Api "+Str(c)+#LF$+"Ich "+Str(d)) 
    
;Repeat 
;Until WaitWindowEvent() = #PB_Event_CloseWindow
---------------------------
144-144-144
---------------------------
PB 1406
Api 1172
Ich 109
---------------------------
OK
---------------------------
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
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Beitrag von hjbremer »

zu Scarabol: StartDrawing Auslagern bringt sicher etwas Zeit, aber dann muß auch EndDrawing irgendwo stehen, außerdem ist es so übersichtlicher und in sich geschlossen.

zu STARGÅTE: ganz starke Idee und vor allem selbst bei verschiedenen Fonts praktikabel und wenn man wirklich mal Speed braucht, finde ich den Code echt genial :allright: :allright: :allright:
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7032
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag von STARGÅTE »

naja das prob bei mir ist ja das ich irgendwo die Länger des Buchstaben speichern muss, sodass man auch dynamisch die Font wechseln kann.

Ich müsste dann bei LoadFont in einer LL den Pointer speichern an dem sich die Zeichenlängen befinden.

Da müsste doch dann der Word-Typ reichen oder gibt es größere Zeichenbreiten als 32767?

EDIT: habe gerade mitbekommen das das prob abstürzt wenn man über ASC() 127 kommt ^^, bugfixe ich gerade
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
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Beitrag von hjbremer »

Theoretisch mag es größere Zeichenbreiten geben, aber wie soll das auf dem Bildschirm/Drucker passen. Unrealistisch.
Und welchen Typ man wählt ist bei deinem Code fast egal und nur noch für Puristen, denn er ist gegenüber Api um einiges schneller.

Interressant wäre es um der Schönheit willen bzw. um zu zeigen wie es geht, deinen Code auf Zeiger umzustellen und nochmal etwas Speed heraus zukitzeln.
Vielleicht hat ja einer Lust dazu.

EDIT: Abstürzen ? wie das ? habe eben 128 , 222 , 255 eingegeben und bei mir kein Absturz.
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7032
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag von STARGÅTE »

PeekB() liefert ja zahlen von -128 bis 127 und wenn ein Zeichen nun über Ascii 127 liegt kommt ein negativer wert raus un verursacht ein read fehler:

Hier der neue Code, aber man sieht schon das meine Variante langsammer ist wenn StartDrawing() außerhalt der schleife liegt,
Ligt es innerhalb ist meins aber schneller

Code: Alles auswählen


Structure CharSizePointer
 FontID.l
 CharSize.w[256]
EndStructure

Global NewList CharSizePointer.CharSizePointer()

Procedure CatchCharSize(FontID, Output)
 AddElement(CharSizePointer())
 CharSizePointer()\FontID = FontID
 StartDrawing(Output)
  DrawingFont(FontID) 
  For n = 1 To 127
   CharSizePointer()\CharSize[n+128] = TextWidth(Chr(n))
  Next
  For n = 128 To 255
   CharSizePointer()\CharSize[n-128] = TextWidth(Chr(n))
  Next
 StopDrawing()
EndProcedure 

Procedure MyTextWidth(FontID, Text$) 
 ForEach CharSizePointer()
  If CharSizePointer()\FontID = FontID
   Len = Len(Text$)-1
   For n = 0 To Len
    Width + CharSizePointer()\CharSize[PeekB(@Text$+n)+128]
   Next n   
   ProcedureReturn Width
   Break
  EndIf
 Next
 ProcedureReturn #False
EndProcedure 



MeineFont = FontID(LoadFont(#PB_Any, "arial", 8))  
MeinText$ = "ABCabc123!'§äöü©³ÅABCabc123!'§äöü©³Å" 

max=1000000

OpenWindow(0, 0,0, 100, 100, "Test",#PB_Window_SystemMenu | 1) 
 CatchCharSize(MeineFont, WindowOutput(0))
 
 Time = timeGetTime_()
 For m = 1 To max
  Breite1 = MyTextWidth(MeineFont, MeinText$)
 Next
 Zeit1 = timeGetTime_()-Time

  StartDrawing(WindowOutput(0))
   Time = timeGetTime_()
   For m = 1 To max
    DrawingFont(MeineFont)
    Breite2 = TextWidth(MeinText$)
   Next
  StopDrawing()
  Zeit2 = timeGetTime_()-Time
 
 MessageRequester("Ergebnis", "MyTextWidth: "+Str(Breite1)+" Zeit:"+Str(Zeit1)+Chr(10)+"TextWidth: "+Str(Breite2)+" Zeit:"+Str(Zeit2))
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
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

@ STARGÅTE:
Es ist keine Schande, den neuen Datentyp '.c' (Character) zu benutzen und endlich '.b' (Byte) zu vergessen!
Character wird von PureBasic automatisch umgeschaltet. Reicht im ASCII Modus von 0-256 und im Unicode-Modus von 0-65536.

> Interressant wäre es um der Schönheit willen bzw. um zu zeigen wie es geht, deinen Code auf Zeiger umzustellen und nochmal etwas Speed heraus zukitzeln
Ich würde es mit Pointern machen, aber die Buchstabenbreite in einem Array, das innerhalb der Prozedur gespeichert wird, speichern. Dabei darf das Array aber nicht Protected sein, sondern Static.

Frage: Wenn ich vom Text "ABC" als gesamtes die Breite mit TextWidth() ermittle, bekomme ich dann dasselbe Ergebnis, als wenn ich von jedem Buchstaben einzeln die Breite ermittle? Ich frage, weil ich nicht weiß, was mit den Zwischenräumen zwischen den Buchstaben ist.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7032
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag von STARGÅTE »

es gibt kein zwischenraum, sonder jeder Buchstabe hat schon selber ein kleinen Platzhalte in sich drin.
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
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Ahso, okay.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Antworten