VectorTextWidth returns wrong values

Post bugreports for the Windows version here
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

VectorTextWidth returns wrong values

Post by Michael Vogel »

When using larger font sizes you may get wrong values like seen below. The drawing functions seem to work correct, but the TextWidth is calcuated wrong.

Code: Select all

For i=990 To 1010
		z0=z1
		VectorFont(FontID(#FontID),i)
		z1=VectorTextWidth(Text)
		Debug Str(i)+": "+Str(z1)+", "+Str(z1-z0)
Next i
990: 6021, 6021
991: 6027, 6
992: 6033, 6
993: 6039, 6
994: 6046, 7
995: 6052, 6
996: 6058, 6
997: 6064, 6
998: 6070, 6
999: 6076, 6
1000: 6082, 6
1001: 6149, 67
1002: 6155, 6
1003: 6161, 6
1004: 6167, 6
1005: 6173, 6
1006: 6179, 6
1007: 6186, 7
1008: 6192, 6
1009: 6198, 6
1010: 6204, 6
User avatar
STARGÅTE
Addict
Addict
Posts: 2067
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: VectorTextWidth returns wrong values

Post by STARGÅTE »

No problem here (PB 5.60 x64 Windows 7)

I tried it with multiple fonts and sizes.

Code: Select all

Enumeration
	#Window
	#Gadget
	#Font1
	#Font2
	#Font3
EndEnumeration


Procedure UpdateCanvasGadget(Gadget.i)
	
	Protected i, Z0, Z1
	Protected Text.s = "Hello World"
	
	If StartVectorDrawing(CanvasVectorOutput(Gadget))
		
		Debug "---"
		For i=500 To 1500
			z0=z1
			VectorFont(FontID(#Font1), i)
			z1=VectorTextWidth(Text)
			Debug Str(i)+": "+Str(z1)+", "+Str(z1-z0)
		Next i
		
		Debug "---"
		For i=500 To 1500
			z0=z1
			VectorFont(FontID(#Font2), i)
			z1=VectorTextWidth(Text)
			Debug Str(i)+": "+Str(z1)+", "+Str(z1-z0)
		Next i
		
		Debug "---"
		For i=500 To 1500
			z0=z1
			VectorFont(FontID(#Font3), i)
			z1=VectorTextWidth(Text)
			Debug Str(i)+": "+Str(z1)+", "+Str(z1-z0)
		Next i
		
		StopVectorDrawing()
	EndIf
	
EndProcedure


Procedure Callback_SizeWindow()
	
	ResizeGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))
	UpdateCanvasGadget(#Gadget)
	
EndProcedure



OpenWindow(#Window, 0, 0, 800, 450, "Vector Canvas Gadget", #PB_Window_MaximizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window), #PB_Canvas_Keyboard)

LoadFont(#Font1, "Arial", 128)
LoadFont(#Font2, "Times New Roman", 128)
LoadFont(#Font3, "Courier New", 128)

UpdateCanvasGadget(#Gadget)
BindEvent(#PB_Event_SizeWindow, @Callback_SizeWindow(), #Window)

Repeat
	
	Select WaitWindowEvent()
		
		Case #PB_Event_CloseWindow
			Break
		
	EndSelect
	
ForEver

End
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: VectorTextWidth returns wrong values

Post by infratec »

With this working example all went Ok with PB 5.70B2 32bit Win10

Code: Select all

#FontID = 0
LoadFont(#FontID, "Arial",  100)
Text$ = "12345678901234567890"
CreateImage(0, 100, 100)
If StartVectorDrawing(ImageVectorOutput(0))
  For i=990 To 1010
    z0=z1
    VectorFont(FontID(#FontID), i)
    z1=VectorTextWidth(Text$)
    Debug Str(i)+": "+Str(z1)+", "+Str(z1-z0)
  Next i
  StopVectorDrawing()
EndIf
990: 11012, 11012
991: 11023, 11
992: 11034, 11
993: 11045, 11
994: 11056, 11
995: 11067, 11
996: 11079, 12
997: 11090, 11
998: 11101, 11
999: 11112, 11
1000: 11123, 11
1001: 11134, 11
1002: 11145, 11
1003: 11156, 11
1004: 11168, 12
1005: 11179, 11
1006: 11190, 11
1007: 11201, 11
1008: 11212, 11
1009: 11223, 11
1010: 11234, 11
Bernd
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: VectorTextWidth returns wrong values

Post by Michael Vogel »

The whole thing seems to depend from the (true type) font and the chosen text, with the following code I get multiple hits here:

Code: Select all

Global NewMap FontMap.s()
Global NewList Fonts.s()

Procedure EnumFontInfo(*elfx.ENUMLOGFONTEX,*ntmx.NEWTEXTMETRICEX,FontType.i,lParam.i)

	AddMapElement(FontMap(),PeekS(@*elfx\elfLogFont\lfFaceName[0]))
	ProcedureReturn #True

EndProcedure
Procedure EnumFontList(WinID,List FontList.s())

	Protected FontLog.LOGFONT
	Protected FontHDC

	FontHDC=GetDC_(WinID)

	FillMemory(@FontLog,SizeOf(LOGFONT))
	FontLog\lfCharSet=		#DEFAULT_CHARSET
	FontLog\lfFaceName[0]=	0

	If EnumFontFamiliesEx_(FontHDC,@FontLog,@EnumFontInfo(),0,0)

		ForEach FontMap()
			AddElement(FontList())
			FontList()=MapKey(FontMap())
		Next

		ProcedureReturn #True

	Else
		ProcedureReturn #False
	EndIf

EndProcedure

OpenWindow(0,0,0,0,0,"*")

If EnumFontList(WindowID(0),Fonts())
	ForEach Fonts()
		#FontID = 0
		LoadFont(#FontID,Fonts(),15)
		;Text$ = "12345678901234567890"
		Text$ = "CAPTT"
		CreateImage(0, 100, 100)
		StartVectorDrawing(ImageVectorOutput(0))
		#limit=20
		z1=0
		error=0
		For i=990 To 1010
			z0=z1
			VectorFont(FontID(#FontID), i)
			z1=VectorTextWidth(Text$)
			If i>991 And z1-z0>#limit
				Debug Fonts()+" / "+Str(i)+": "+Str(z1)+", "+Str(z1-z0)
				error=1
			EndIf
		Next i
		If error
			Debug z1-z0
		EndIf
		StopVectorDrawing()
	Next
EndIf
The most extreme outlier is the following:
Benguiat / 1001: 2822, 93
3
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: VectorTextWidth returns wrong values

Post by infratec »

Hi,

now you know why always a working example is needed :wink:

My results:
Source Sans Pro ExtraLight / 1001: 2634, -30
Noto Sans / 1001: 3011, 23
Miriam Libre / 1001: 2826, 25
Noto Sans Cond / 1001: 2386, 17
Noto Sans Light / 1001: 2902, 22
Source Sans Pro Light / 1001: 2659, -28
Source Sans Pro / 1001: 2732, -21
Source Sans Pro Semibold / 1001: 2792, -16
(I added ABS() to get also the negative results)

One thing is very interesting:
It happens always at 1001. Also your mentioned font throw this error with 1001.
Maybe it's a magic number :mrgreen:
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: VectorTextWidth returns wrong values

Post by infratec »

Or it has something todo with the floatingpoint arithmetic, since the size parameter is .d
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: VectorTextWidth returns wrong values

Post by Michael Vogel »

Not sure what the reason for the difference between the calculation and the drawing output, I only found and UPM parameter within the ttf files which has the value 1000.

Another interesting thing, I don't see these issues when using standard drawing commands (but the calculated widths are 33% higher compared to the vector texts):

Code: Select all

text$ = "CAPTT"
CreateImage(0, 100, 100)

For i=997 To 1005
	LoadFont(0,"Benguiat",i)
	StartDrawing(ImageOutput(0))
	z0=z1
	DrawingFont(FontID(0))
	z1=TextWidth(Text$)
	Debug Str(i)+": "+Str(z1)+", "+Str(z1-z0)
	StopDrawing()
Next i

User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: VectorTextWidth returns wrong values

Post by Michael Vogel »

infratec wrote:Or it has something todo with the floatingpoint arithmetic, since the size parameter is .d
I was hoping the floats are leading to smoother results - and this seems to be correct for normal (see below), using non vector functions would lead to a more wobbling effect...

Code: Select all

#X=960
#Y=640

;LoadFont(1,"Benguiat",15)
LoadFont(1,"Segoe UI",15)

Procedure Draw(time)

	Protected s.s
	Protected frames,now
	Protected alpha,glass,color
	Protected fx.f,fy.f,fw.f,fs.f
	Protected delta.f

	StartVectorDrawing(CanvasVectorOutput(0))
	VectorSourceColor($FF000000)
	FillVectorOutput()

	#Width=0.012

	If time>=0 And time<500
		now=time
		frames=200
		delta=now/frames
		fs=3000+delta*-400-time*4

		alpha=$FF000000
		glass=$60000000
		
				VectorFont(FontID(1),fs)
		fx=300+delta*20-VectorTextWidth("N")/2
		fy=450+delta*80-VectorTextHeight("N")/2
		fw=1+#Width*fs

		MovePathCursor(fx,fy)
		AddPathText("N")
		VectorSourceColor(alpha|$0000D0)
		StrokePath(fw)

		MovePathCursor(fx,fy)
		AddPathText("N")
		VectorSourceColor(glass|$1010FF)
		StrokePath(fw*1.4)

		MovePathCursor(fx,fy)
		AddPathText("N")
		VectorSourceColor(glass|$1010FF)
		fs/10
		DashPath(fw*0.9,fs,#PB_Path_DiagonalCorner,fs)

	EndIf

	StopVectorDrawing()

EndProcedure

OpenWindow(0,0,0,#X,#Y,"*",#PB_Window_ScreenCentered|#PB_Window_BorderLess)
StickyWindow(0,1)
CanvasGadget(0,0,0,#X,#Y)

AddWindowTimer(0,0,10)
Repeat
	Select WaitWindowEvent()
	Case #PB_Event_Timer
		time+1
		Draw(time)
	Case #PB_Event_CloseWindow,#WM_CHAR
		End
	EndSelect
ForEver

User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: VectorTextWidth returns wrong values

Post by Michael Vogel »

Here's a workaround for the wrong VectorTextWidth calculation - remember to recalculate the correction value for every different text you are using!
If you are using more than one font type you can easily adapt the procedure to manage this as well...

Code: Select all


Procedure.d TextWidthCorrection(text.s)

	#TmpImage=999
	#TmpFont=999

	Protected i
	Protected Dim value.d(2)

	LoadFont(#TmpFont,"Benguiat",666)

	If CreateImage(#TmpImage,1,1)
		If StartVectorDrawing(ImageVectorOutput(#TmpImage))
			For i=0 To 2
				VectorFont(FontID(#TmpFont),1000+i)
				value(i)=VectorTextWidth(text)
			Next i
			StopVectorDrawing()
		EndIf

		FreeImage(#TmpImage)
	EndIf
	
	ProcedureReturn value(0)-value(1)*2+value(2)
	
EndProcedure

text.s

text = "TJ"
;text = "LJ"
;text = "TT"

correction.d=TextWidthCorrection(text)

LoadFont(0,"Benguiat",666)
CreateImage(0,1,1)
StartVectorDrawing(ImageVectorOutput(0))
For n=990 To 1010
	VectorFont(FontID(0),n)
	Debug Str(n)+": "+StrD(VectorTextWidth(text)+correction*Bool(n>1000),2)
Next n
StopVectorDrawing()
Post Reply