Seite 1 von 2
Textbreite ermitteln, Vergleich PB zu Api
Verfasst: 26.01.2008 17:22
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.
Verfasst: 26.01.2008 20:55
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
Verfasst: 26.01.2008 21:13
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
---------------------------
Verfasst: 26.01.2008 22:01
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

Verfasst: 26.01.2008 22:15
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
Verfasst: 26.01.2008 22:47
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.
Verfasst: 26.01.2008 23:04
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))
Verfasst: 27.01.2008 18:00
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.
Verfasst: 27.01.2008 19:40
von STARGÅTE
es gibt kein zwischenraum, sonder jeder Buchstabe hat schon selber ein kleinen Platzhalte in sich drin.
Verfasst: 27.01.2008 20:20
von AND51
Ahso, okay.