1
votes

I'm trying to manually scale some fonts in my Java Swing application (ie. for a high res screen).

at 96 DPI (100%), Windows Look & Feel tells me the default font is Tahoma size 11. (using Label.font in the WLF) At 200% it's 21, 300% is 32, 400% is 43, and 500% is 53. (note that point size == font ascent)

My original approach is to take "my" default font: Tahoma size 11. Then calculate the scaling factor (ie. 2.0 for 200%). From there I want to calculate the font point size, however doing a straight up multiplication isn't in line with the Windows scaling,

so the question(s):

  1. How does font scaling work in Windows? and
  2. How do I scale my fonts? (There is also other scaling done for components, etc.) The two main fonts in my application are Tahoma(11) and Segoe UI (12).

    new WindowsLookAndFeel().getDefaults().getFont("Label.font") //returns 11 @ 100%
    
    Font font = StyleContext.getDefaultStyleContext().getFont("Tahoma",  Font.PLAIN, 11); //my inital Composite font (Tahoma with Dialog fallback)
    
    Font newFont = font.deriveFont(zoomFactor * 11); // this gets me 22 @ 200%
    

Thanks!

1
Why not ask Java what the underlying dpi are? If you're trying to compensate for high-dpi displays, take that Tahoma at 11px per 96 dpi and scale it to 11*[real]/96 px per [real] dpi - Mike 'Pomax' Kamermans
Hey thanks for your comment. I'm doing exactly this, I calculate the zoom factor by asking the dpi (best i can do) and dividing by 96 (ie. 100%). The problem is that @ 192 dpi, Windows Look and Feel tells me Tahoma is at size 21. When I do the zoom * 11 calculation, you get point size 22 instead (11 * 192/96) - Andrei Pivkine
That doesn't actually sound like a problem so much as a consequence of point rounding. 11px might not actually be a true pixel value but a pixel representation of a (fractional) pt value, in which case the 21px at 192dpi can easily be due to a floor(...) on the conversion result from pt to px. At that point you may need to know which text shaper you're dealing with (GDI, GDI+, DirectWrite?), or set your font size based on the dimensions of the container it needs to end up in. - Mike 'Pomax' Kamermans
@Mike'Pomax'Kamermans "Why not ask Java what the underlying dpi are?" - Because generally, Java can't tell you (or at least not accurately) - MadProgrammer
Newer java ( java11 ) can tell the dpi accurately - Jayan

1 Answers

1
votes

In my case, my solution was to iterate through each font size and check the width of a test string and stop at the Font closest (but not larger) than the scaled width size.

This is similar to sizing a font to a specific component's size. One thing to note is that I had to choose a relatively long string for the Test string.

By following this method, Tahoma 21 is chosen for the correct font at 200% (192 DPI). Something along the lines of:

while(true) {

        Font newFont = font.deriveFont((float)fontSize + 1);
        int newWidth = StyleContext.getDefaultStyleContext().getFontMetrics(newFont).stringWidth(TEST_STIRNG);
        if(newWidth <= targetWidth) {
            fontSize++;
        } else {
            System.out.println("Rejected Font:" + newFont.getName() + " size:" + newFont.getSize() + " width: " + newWidth);        
            break;
        }
    }