Page 1 of 1

Strange "Included" Fonts Behavior

Posted: Tue Oct 28, 2014 11:04 pm
by hudsonjo
I got my program debugged and compiled successfully as a 64-bit, Win7 executable. Then I wanted to make it available to Windows 32-bit environments. Once I figured out I had to install & run under the PB 'x86' compiler to compile a 32-bit (x86) build of my program - I obtained the new executable. I wanted to verify it on a 32-bit "XP" system and luckily I have an older Dell laptop that fit this requirement.

When I launched it, it came up and appeared to run okay, but with one major exception - I was confronted with a totally unexpected anomaly involving the size of the included fonts. They display out of scale with the rest of the screen graphics objects! They are way too big. BTW - This causes problems with my graphics routines that use 'FillArea(X,Y)' commands since the text will break the bounding color and allow the filled background to leak out.

Note: - I am using the PB 'Windowed Screen mode' with the resizable screen flag enabled. When I drag the window edge around everything resizes just as you would expect - including the relative text font size. But the font is always scaled way larger than its underlying graphics, even though it does resize in coodination with any window resizing. As far as I can tell, this font problem is the only issue I have when running the 'exe' on my chosen testbed - 'XP' 32-bit Dell laptop. I wonder if a difference in screen resolution could be part of the problem(?).

These fonts (3 of them) are embedded using the 'IncludeBinary()' data method. This is desirable in order to make the executable file portable. The font size is set using the "LoadFont" command.

By way of comparison, this did NOT appear to be an issue when I ran this 32-bit (x86) program on my two Win7 64-bit computers - all was fine. I was about to conclude that the issue is unique to 'XP', but just recently I ran a 64-bit version on a family member's Win7 machine (a Gateway) and it also had this font problem as well. So now I'm really :? - confused!

Can anyone help to shed some light on this? Many thanks!

Re: Strange "Included" Fonts Behavior

Posted: Wed Oct 29, 2014 1:20 am
by heartbone
This is likely a (Windows® only) problem that shows up when you have previously changed the DPI scaling on your computer(s) away from the default 100%.

To compensate for this situation, first reset the development computer's DPI scaling to 100% (96 DPI),
and then choose your program's font sizes based on what looks best with that setting.
Your selected font size will also look fine when running your program in XP, or on a newer Windows® OS using the default scaling.

To properly scale the fonts in your programs running on Vista and later computers where the DPI is not set to 100%
[96 DPI (Default) | 120 DPI (125%) | 144 DPI (150%) | 192 DPI (200%)],
examine the following code snippet which adjusts four different font sizes.

Code: Select all

; SET DEFAULT FONT SIZES
FS1= 12 : FS2= 24 : FS3= 36 : FS4= 48
; GET DESKTOP DPI AND ADJUST FONT SIZES
ExamineDesktops()
DPI= GetDeviceCaps_(GetDC_(0),#LOGPIXELSX)
; ADJUST THE FONT SIZE FOR SCALING IF NEEDED 
If DPI <> 96 And DPI > 15 And DPI < 193
   FS1= (FS1*100)/DPI
   FS2= (FS2*100)/DPI
   FS3= (FS3*100)/DPI
   FS4= (FS4*100)/DPI
EndIf
LoadFont(1,"UnDinaru",FS1,#PB_Font_Bold|#PB_Font_HighQuality)
LoadFont(2,"UnDinaru",FS2,#PB_Font_Bold|#PB_Font_HighQuality)
LoadFont(3,"UnDinaru",FS3,#PB_Font_Bold|#PB_Font_HighQuality)
LoadFont(4,"UnDinaru",FS4,#PB_Font_Bold|#PB_Font_HighQuality)
Regardless of the Windows® computer DPI setting,
that algorithm should produce a font size consistent with what is displayed when running on XP.
Simply multiply the XP fontsize by 100 and divide by the current DPI value to calculate the proper equivalent font size.

I developed this from trial and error,
and you may find a better value to use for the calculation,
or a better method to rescale the font size,
or a better range in which to apply the rescaling.

Re: Strange "Included" Fonts Behavior

Posted: Wed Oct 29, 2014 9:36 am
by infratec
Hi,

a crossplatform way is:
Write a loop wich increases the fontsize and use TextHeight() until you get the size you need.

Code: Select all

Procedure GetFontHeight(Fontname$, Size.i, Style.i=0)
  
  Protected.i Result, Font, Image
  
  
  Font = LoadFont(#PB_Any, Fontname$, Size, Style)
  If Font
    Image = CreateImage(#PB_Any, Size * 2, Size * 2)
    If Image
      If StartDrawing(ImageOutput(Image))
        DrawingFont(FontID(Font))
        Result = TextHeight(" ")
        StopDrawing()
      EndIf
      FreeImage(Image)
    EndIf
    FreeFont(Font)
  EndIf
  
  ProcedureReturn Result
  
EndProcedure
Bernd

Re: Strange "Included" Fonts Behavior

Posted: Wed Oct 29, 2014 10:42 pm
by hudsonjo
Two very interesting and illuminating approaches. The response by Heartbone is certainly a new concept for me. So it provokes a few additional questions:

I didn't know about the ExamineDesktops() functions, so this was a surprise revelation. But I have no info on the "what, where and how" of the related "GetDeviceCaps" and "GetDC" functions, along with the constant, #LOGPIXELSX. Where can I find details? In the PB Manual? Clearly, these functions return the DPI for the current (or specified) desktop. But I need to be further educated about these capabilities? I've run across other "Get-something" type functions that seem to burrow into the OS - but haven't found any documentation. Are these part of the API, or other library resources that PB uses?

Even after reading Heartbone's link to the Windows article, I was still somewhat puzzled by his discussion of the default screen DPI (of 96) being (intentially?) changed. As far as I know all the Windows computers which I have had access to are running at their recommended (default) settings. But what I did seem to get out of this, is that different computers having different size monitors & resolution settings, may exhibit different DPIs. Thus, this condition may need to be compensated for. E.g., my main computer (aka "development") is 1920 x 1080 with a 20" screen width yielding 96 DPI - quoted as 100%. But if I was to set it to 1600 instead, it would become 80 DPI, would it not? Anyway this is where I end up with that subject.

As far the use of the routine goes, I was wondering about the choice of 100 as a multiplication factor. I don't want to split hairs, but I was wondering if 96 was used instead, wouldn't this make it unnecessary to block the 'default' resolution out of the calculation in the 'If' statement? If the DPI was returned as '96' it would calc out as font size, FSx * 96/96, or no change. Just wondering...? I understand this is an experimental situ.

I also notice that as the DPI gets smaller, the computed font size (FSx) gets bigger. This feels counterintuitive, but once implemented & tested I suppose it can be verified. I know this routine works because I have already put it into a test routine and successfully gotten test text displays.

I think the bottom line here is to obtain the target system's DPI from ExamineDesktops() functions and use it to rescale the initial font size(s) determined when the program was developed, preferably on a computer which was running at 100% DPI (which is apparently 96 by default consensus).
---------------
As for Infratec's response, I still need to play around with it to see how I might use it in my application. In either case, a routine would need to detect what the environment is and dynamically rescale the font size by choosing the appropriate scaling factor.

I'm not sure what is especially "crossplatform" about this code, I think he just means it is basically self-contained PB code which therefore can run on whatever platform the compiler may be targeting - then I get it.

My cursory study of this procedure, doesn't explicitly tell how I may use it to detect and execute a dynamic change of font size, but I expect that once I have tested it, that will become clear. It looks like one would write a routine to check the returned "Result" (Text Height) to see if font size compensation is required.

My sincere thanks to both for two very educational and distinct solutions!

Re: Strange "Included" Fonts Behavior

Posted: Thu Oct 30, 2014 1:14 am
by heartbone
I am glad to be of assistance.
I didn't know about the ExamineDesktops() functions, so this was a surprise revelation. But I have no info on the "what, where and how" of the related "GetDeviceCaps" and "GetDC" functions, along with the constant, #LOGPIXELSX. Where can I find details? In the PB Manual? Clearly, these functions return the DPI for the current (or specified) desktop. But I need to be further educated about these capabilities? I've run across other "Get-something" type functions that seem to burrow into the OS - but haven't found any documentation. Are these part of the API, or other library resources that PB uses?
This is the earliest mention of the function that I've found on the forum. It works and I moved on without any further investigation.
As far the use of the routine goes, I was wondering about the choice of 100 as a multiplication factor. I don't want to split hairs, but I was wondering if 96 was used instead, wouldn't this make it unnecessary to block the 'default' resolution out of the calculation in the 'If' statement? If the DPI was returned as '96' it would calc out as font size, FSx * 96/96, or no change. Just wondering...? I understand this is an experimental situ.
I agree with you that using 96 makes more sense intuitively than 100.
But when I tested it on my systems, 100 gave the best scaling results over the entire DPI range.
Your results might be different, and if you find that 96 or another value works better for you kindly post your findings.
I just found this discusion where floating point is mentioned in the scaling and that should probably work better, but I was satisfied with the results from the integer scaling.
I'm confident that eventually we will find the best algorithm to make our Windows® applications DPI aware.
I'm thinking that quite a few applications that use fonts will have display issues when running on a system not set at the default 96 DPI.

My question for you hudsonjo is, was the font problem caused by your development system not being set to 96 DPI, or the other computers not being set to 96 DPI?

Re: Strange "Included" Fonts Behavior

Posted: Thu Oct 30, 2014 3:40 pm
by IdeasVacuum
ExamineDesktops() is redundant in that code snippet. GetDeviceCaps/GetDC are pointed at the default Monitor '0'. Both of the 'Gets' are Windows API only, so if coding for other platforms too, infratec's snippet looks like a good solution.

Re: Strange "Included" Fonts Behavior

Posted: Thu Oct 30, 2014 5:56 pm
by heartbone
IdeasVacuum wrote:ExamineDesktops() is redundant in that code snippet. GetDeviceCaps/GetDC are pointed at the default Monitor '0'. Both of the 'Gets' are Windows API only, so if coding for other platforms too, infratec's snippet looks like a good solution.
Good catch IdeasVacuum.
ExamineDesktops() was in the section of code that I cut the snippet from, (it is used to get the desktop dimensions) and I should have removed it before posting the snippet here.

During a program's development I can comprehend infratec's code being used to obtain a font size to use in the code,
but I do not understand how at run time the algorithm could be used to automatically obtain the font scale factor needed to make a font appear as desired.
As far as the cross-platform ability, I did not think it was necessary.
Is font scaling even a programming problem in Linux?

Re: Strange "Included" Fonts Behavior

Posted: Thu Oct 30, 2014 8:29 pm
by infratec
Hi,

1. Arial 20 for example has not evrywhere the same size in pixel.
And this is not only OS dependent.

2. I needed it to scale my window complete and not only the window size.

For that I used the following:

Code: Select all

FontSize = 15
Repeat
  FontSize + 1
Until GetFontHeight("Arial", FontSize, #PB_Font_Bold) >= 24 * WinSizeFactor
Debug FontSize

LoadFont(0, "Arial", FontSize, #PB_Font_Bold)
The smallest size of the window has a WinSizeFactor of 1.0
When I maximize the window the factor is a result of the desktop dimension.
24 is the pixelsize which is needed in the smallest window.

As result I get always the correct fontsize.

Since I use 2 different font sizes, I do it in the same way for the second font where the target size is 14 pixel:

Code: Select all

FontSize = 5
Repeat
  FontSize + 1
Until GetFontHeight("Arial", FontSize) >= 14 * WinSizeFactor

LoadFont(1, "Arial", FontSize)

SetGadgetFont(#PB_Default, FontID(1))
Oh, the calculation of the WinSizeFactor is done this way:

Code: Select all

ExamineDesktops()

WinSizeFactor = 1.0

If MaxWindowFlag
  DeskWidth = DesktopWidth(0)
  DeskHeight = DesktopHeight(0)
  
  ;Debug Str(DeskWidth) + " x " + Str(DeskHeight)
  
  If DeskWidth >= 1024 And DeskHeight >= 768
    WinSizeWidthFactor = (DeskWidth - 20) / #MainWindowWidth
    WinSizeHeightFactor = (DeskHeight - 100) / #MainWindowHeight
    If WinSizeWidthFactor > WinSizeHeightFactor
      WinSizeFactor = WinSizeHeightFactor
    Else
      WinSizeFactor = WinSizeWidthFactor
    EndIf
  EndIf
EndIf
Maybe not the best way, it it works on all OSs and under all circumstances.
(up to now :mrgreen: )

Bernd

Re: Strange "Included" Fonts Behavior

Posted: Thu Oct 30, 2014 9:59 pm
by hudsonjo
Very interesting and informative! There are a lot more details to know about all this than I thought. I can report that I have incorporated Heartbone's proposed code into my larger program and it tested successfully - but so far on only one other computer, may old XP Dell laptop. The DPI on that machine reads back as '120' vs. my desktop dev machine at '96'. There was a slight sizing tweak needed on one of the 3 fonts I use, but that's because it was used as part of a graphic image which gets stored in an array (re: CreateImage(); DrawImage(); etc.). So the the pixel dimensions for this one are very critical. If the font point size is just a few points too small, the image drawing black background begins to show at runtime. As a workaround I was able to adjust the divisor in the Font Size (FS1) expression for just this font.

I expect (hope) that some code refinements can be found that will make the scaling even smoother and transparent to most system environments. So far, the results are very promising! To answer Heartbone's question, my development system has always been 96DPI - I haven't had a need to change it. It is set at the maximum (and recommended) setting my graphics & display hardware prefers. This provides 1920 x 1080 pixels on a 20" x 11.5" display. What I don't quite get is how the monitor size by itself, can affect the internal DPI. If I were to change to a 27" monitor, then it seems this would change the screen DPI(?)... 1920pixels / 27" = 71.111DPI. I suppose if the monitor is properly installed & recognized by the OS, then this new DPI would be internalized - and this is highly probable. (Of course in actuality 27" is diagonal, but the argument holds).

Like Heartbone I was also concerned about the scaling factor calcs WRT floating-point results. I too was wondering what the effect of rounding (or truncation) errors would be on the final font size. Pehaps this could be acceptable on one system (DPI), but bad on another.

Great discussion and very appreciated! So in the meantime I guess I will give these various, insightful ideas more study to see what more can be gleaned.

Re: Strange "Included" Fonts Behavior

Posted: Fri Oct 31, 2014 5:37 pm
by heartbone
Thank you much Bernd for the detailed reply.
I will save your suggestion in my coding tips folder as infratec's font scaling method just in case I ever have a need to go there.
hudsonjo wrote:Very interesting and informative! There are a lot more details to know about all this than I thought. I can report that I have incorporated Heartbone's proposed code into my larger program and it tested successfully - but so far on only one other computer, may old XP Dell laptop. The DPI on that machine reads back as '120' vs. my desktop dev machine at '96'. There was a slight sizing tweak needed on one of the 3 fonts I use, but that's because it was used as part of a graphic image which gets stored in an array (re: CreateImage(); DrawImage(); etc.). So the the pixel dimensions for this one are very critical. If the font point size is just a few points too small, the image drawing black background begins to show at runtime. As a workaround I was able to adjust the divisor in the Font Size (FS1) expression for just this font.

I expect (hope) that some code refinements can be found that will make the scaling even smoother and transparent to most system environments. So far, the results are very promising! To answer Heartbone's question, my development system has always been 96DPI - I haven't had a need to change it. It is set at the maximum (and recommended) setting my graphics & display hardware prefers. This provides 1920 x 1080 pixels on a 20" x 11.5" display. What I don't quite get is how the monitor size by itself, can affect the internal DPI. If I were to change to a 27" monitor, then it seems this would change the screen DPI(?)... 1920pixels / 27" = 71.111DPI. I suppose if the monitor is properly installed & recognized by the OS, then this new DPI would be internalized - and this is highly probable. (Of course in actuality 27" is diagonal, but the argument holds).

Like Heartbone I was also concerned about the scaling factor calcs WRT floating-point results. I too was wondering what the effect of rounding (or truncation) errors would be on the final font size. Pehaps this could be acceptable on one system (DPI), but bad on another.

Great discussion and very appreciated! So in the meantime I guess I will give these various, insightful ideas more study to see what more can be gleaned.
I also appreciate this discussion.
I was unaware that users could change the display DPI in XP, the first that I heard of it was with Vista.
I am reluctant to investigate any algebraic algorithm to make font scaling any smoother because font sizing does not seem to be a linear function inter-font and perhaps even intra-font.
I just realized that my 96 best fit results might be an artifact of the particular font that I was working with.
Bernd's approach seems to be the way to go if font sizing is critical, like for an application that allows the user to change the font sizes or font.