Original post :
I just found myself needing to draw a single line of text containing multiple fonts.
Problem is that PB's 2D drawing lib does not allow us to draw along a common baseline because we cannot calculate the necessary font metrics without dipping into Win API and GetTextMetrics_(). Using DrawText() repeatedly to create a single line of text containing multiple fonts produces a lump of text sharing the same top line which is useless and very very ugly.
Since I need this to be cross-platform, I hacked up the following which makes simple use of the vector lib to calculate the necessary metrics which we can then use in the regular 2D drawing lib. Only tested on Windows and Ubuntu, but I see no reason why it should not work on the other platforms.
Note that the vector lib returns slightly different values for text ascents than the Win API GetTextMetrics_(), but these differences are small and possibly due to rounding errors because the vector lib uses floating point values etc. Doesn't seem to impact my tests thus far.
Thought this might be useful.
Code: Select all
;///////////////////////////////////////////////////////////////////////////////// ;Font ascent / Descent. ;====================== ;srod + Rashad : Jan 2019. ; ;With PB's vector library it is possible to draw text in multiple fonts on a single line sharing a common baseline. ;This is not currently possible with PB's 2D Drawing lib (not in a cross-platform way) since we do not have access to the necessary text metrics (ascent, descent, internal leading etc.) ;This little prog shows how to use the cross-platform vector lib to 'estimate' the ascents/descents of a given font for subsequent use ;with PB's basic 2D Drawing lib. ;With this info it is then possible to use the 2D drawing lib to draw text in multiple fonts on a single line sharing a common baseline as we demonstrate. ; ;Platforms : ALL. Tested on Windows/Ubuntu (GTK3 and QT) only. ; ;NOTES. ; ; i) During testing we found an incompatibility between PB's vector library and PB's 2D Drawing lib with certain 'wayward' fonts. ; This necessitated a Rashad inspired workaround which results in 'estimates' for the required font ascents etc. ; These estimates are looking very good though. Certainly good enough for the purposes of this utility. ;///////////////////////////////////////////////////////////////////////////////// ;The following global records the max ascent of the various fonts we are using. ;This will allow us to draw a single line of text along a common baseline with multiple fonts etc. Global gMaxAscent.d ;The following structure will hold ascent/descent info on each of our fonts. Structure fontData font.i ascent.d EndStructure ;We place all our fonts in an array for convenience. Dim fonts.fontData(3) fonts(1)\font = LoadFont(#PB_Any, "Monotype Corsiva", 45) fonts(2)\font = LoadFont(#PB_Any, "Times New Roman", 30, #PB_Font_Italic) fonts(3)\font = LoadFont(#PB_Any, "Arial", 11) Declare GetFontData(Array fonts.fontData(1)) ;Calculate font ascents/descents for all of our fonts. Global text$ = "ABCDefghIJK" GetFontData(fonts()) ;A quick test to check all is well. ;We simply use DrawText() 3 times (once for each font) to display a single line of repeated text adjusting the vertical position to ensure ;all the text shares the same baseline. Define.d tempAscent If OpenWindow(0, 0, 0, 800, 400, "Font Data", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) CanvasGadget(0, 10, 10, 780, 380) If StartDrawing(CanvasOutput(0)) ;Draw a single line of text in the various fonts sharing the same baseline. DrawingMode(#PB_2DDrawing_Transparent) For i = 1 To ArraySize(fonts()) DrawingFont(FontID(fonts(i)\font)) x=DrawText(x, 20 + gMaxAscent - fonts(i)\ascent, text$, 0) Next ;Draw the baseline. Line(0, 20 + gMaxAscent, x, 1, $0000FF) StopDrawing() EndIf Repeat Event = WaitWindowEvent() Until Event = #PB_Event_CloseWindow EndIf End ;The following procedure calculates all font ascents/descents. ;It uses the vector lib for cross platform purposes. Procedure GetFontData(Array fonts.fontData(1)) Protected image, i, TextHeight, visHeight.d, ascentScale.d ;Create a dummy image. image = CreateImage(#PB_Any, 1, 1) If image If StartVectorDrawing(ImageVectorOutput(image)) If StartDrawing(ImageOutput(image)) For i = 1 To ArraySize(fonts()) VectorFont(FontID(fonts(i)\font)) visHeight = VectorTextHeight(text$, #PB_VectorText_Visible) + VectorTextHeight(text$, #PB_VectorText_Visible|#PB_VectorText_Offset) If visHeight ascentScale = VectorTextHeight(" ", #PB_VectorText_Baseline) / visHeight Else ascentScale = 1 EndIf DrawingFont(FontID(fonts(i)\font)) fonts(i)\ascent = ascentScale * TextHeight(" ") If fonts(i)\ascent > gMaxAscent gMaxAscent = fonts(i)\ascent EndIf Next StopDrawing() EndIf StopVectorDrawing() EndIf FreeImage(image) EndIf EndProcedure