TTF and OTF versions of Source Sans Pro are differently displayed in Swing (Nimbus L&F)
Asked Answered
T

1

3

ttf: ttf

otf: otf

both are the same font but different fontfile types

I am running Java 7 in Windows 7

According to Miguel Sousa by Adobe the bug is not in the fonts https://github.com/adobe/source-sans-pro/issues/32#issuecomment-23319673

I am just setting the default font to the new font. The TTF version works without any issues

Font font_o = Font.createFont(Font.TRUETYPE_FONT, fonts.class.getResourceAsStream("fonts/TTF/SourceSansPro-Regular.ttf"));
//Font font_o = Font.createFont(Font.TRUETYPE_FONT, fonts.class.getResourceAsStream("fonts/OTF/SourceSansPro-Regular.otf"));
Font font_n=font_o.deriveFont(Font.PLAIN, UIManager.getLookAndFeelDefaults().getFont("defaultFont").getSize());
UIManager.getLookAndFeelDefaults().put("defaultFont",font_n);

Why is there a difference in the lineheight?

Thiel answered 27/8, 2013 at 9:7 Comment(9)
no, you misunderstood something. be sure that not, I'm delete my answer here to avoiding any further discusion aboutHereupon
and what did I misunderstand exactly? I tried the ttf version here: looks great, then tried the otf version (commenting out the ttf version) lokks not the same, see the 2 images above and see the space above the "O"Thiel
I see that, but I'm trying to avoid any debugging of methods on my side, nothing else :-)Hereupon
In FontForge both versions (otf, ttf) are really the same and look the same, seems to be a Java Swing (Nimbus L&F) bugThiel
if it is also reproduced by other Java users it will be a bug, so let's see what the community says and maybe we have to file a bug report for this. I will keep this stackoverflow question updated so other users will know in the future forums.oracle.com/thread/2573652Thiel
I'm debugged that, everything is accesible from TextAttribute, this is bug, (too lazy create an screenshots before)Hereupon
I don't think Java uses the same font renderer for TTF as OTF fonts. I can't find any "hard" evidence for this, but check out e.g. the second answer to this question. Googling does appear to support the idea that not all features in OTF fonts are supported by Java. In other words, OTF font rendering simply may not be as good.Okay
@Okay read The values for WEIGHT, WIDTH, and POSTURE are interpolated by the system, which can select the 'nearest available' font or use other techniques to approximate the user's request., but this isn't somehow, an important issue hereHereupon
@Okay mindprod.com/jgloss/opentype.html for Linux and other operating systems you have to use otf, it is currently the best option to support most platformsThiel
H
3

conclusion (forums.oracle.com/thread/2573652 similair as many his post there, nothing special)


  • not true that Java, nor Nimbus bug, this bug in Font, you can to see that in Metal, Win, WinClassic and Nimbus Laf, OTF_Font missing 2pixels above glyph

enter image description here . Windows . enter image description here

enter image description here . Metal . enter image description here

enter image description here . Nimbus . enter image description here

enter image description here . Classic . enter image description here


WinXp on Java6

enter image description here . versus . enter image description here


  • this code will help you to find difference(ies) between two fonts (and to report all diff's to author)

  • returns all available atributes from (java.awt.font.)TextAttribute for concrete Font

  • you can to get detailed properties from (almost) all TextAttributes

enter image description here

with output

java.awt.font.TextAttribute(family)
java.awt.font.TextAttribute(weight)
java.awt.font.TextAttribute(width)
java.awt.font.TextAttribute(posture)
java.awt.font.TextAttribute(size)
java.awt.font.TextAttribute(transform)
java.awt.font.TextAttribute(superscript)
java.awt.font.TextAttribute(char_replacement)
java.awt.font.TextAttribute(foreground)
java.awt.font.TextAttribute(background)
java.awt.font.TextAttribute(underline)
java.awt.font.TextAttribute(strikethrough)
java.awt.font.TextAttribute(run_direction)
java.awt.font.TextAttribute(bidi_embedding)
java.awt.font.TextAttribute(justification)
java.awt.font.TextAttribute(input method highlight)
java.awt.font.TextAttribute(input method underline)
java.awt.font.TextAttribute(swap_colors)
java.awt.font.TextAttribute(numeric_shaping)
java.awt.font.TextAttribute(kerning)
java.awt.font.TextAttribute(ligatures)
java.awt.font.TextAttribute(tracking)

from code Nimbus L&F

import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

public class SystemFontDisplayer {

    private static final long serialVersionUID = 1L;
    private JFrame frame = new JFrame("Nimbus UIDeafaults and Font");
    private JComboBox fontsBox;
    private javax.swing.Timer timer = null;
    private JButton testButton = new JButton("testButton");
    private JTextField testTextField = new JTextField("testTextField", JLabel.CENTER);
    private JLabel testLabel = new JLabel("testLabel");
    private Font font1, font2;
    private JMenuBar menuBar1 = new JMenuBar();
    private JMenu menu1= new JMenu("Menu 1");
    private JMenu menu2= new JMenu("Menu 2");
    private JMenuItem menuItem1= new JMenuItem("MenuItem 1");
    private JMenuItem menuItem2= new JMenuItem("MenuItem 2");

    public SystemFontDisplayer() {
        try {
            font1 = Font.createFont(Font.TRUETYPE_FONT, SystemFontDisplayer.class.getResourceAsStream("/Images/SourceSansPro-Regular.ttf"));
            font2 = Font.createFont(Font.TRUETYPE_FONT, SystemFontDisplayer.class.getResourceAsStream("/Images/SourceSansPro-Regular.otf"));
        } catch (FontFormatException ex) {
            Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
        }
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        //ge.registerFont(font1);
        ge.registerFont(font2);
        String[] fontFamilyNames = ge.getAvailableFontFamilyNames(Locale.getDefault());
        fontsBox = new JComboBox(fontFamilyNames);
        fontsBox.setSelectedItem(0);
        fontsBox.setRenderer(new ComboRenderer());
        fontsBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final String fontName = fontsBox.getSelectedItem().toString();
                    fontsBox.setFont(new Font(fontName, Font.PLAIN, 16));
                    start();
                }
            }
        });
        fontsBox.setSelectedItem(0);
        fontsBox.getEditor().selectAll();

        menu1.add(menuItem1);
        menuBar1.add(menu1);
        menu2.add(menuItem2);
        menuBar1.add(menu2);
        frame.setJMenuBar(menuBar1);
        frame.setLayout(new GridLayout(4, 0, 5, 5));
        frame.add(fontsBox);
        frame.add(testButton);
        frame.add(testTextField);
        frame.add(testLabel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(200, 105);
        frame.pack();
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                fontsBox.setPopupVisible(true);
                fontsBox.setPopupVisible(false);
            }
        });
        frame.setVisible(true);
    }

    private void start() {
        timer = new javax.swing.Timer(250, updateCol());
        timer.setRepeats(false);
        timer.start();
    }

    public Action updateCol() {
        return new AbstractAction("text load action") {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                final Font fnt = new Font(fontsBox.getSelectedItem().toString(), Font.PLAIN, 16);
                try {
                    LookAndFeel lnf = UIManager.getLookAndFeel().getClass().newInstance();
                    final FontUIResource res = new FontUIResource(fnt);
                    UIDefaults uiDefaults = lnf.getDefaults();
                    uiDefaults.put("defaultFont", res);
                    UIManager.getLookAndFeel().uninitialize();
                    UIManager.setLookAndFeel(lnf);
                } catch (InstantiationException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                } catch (UnsupportedLookAndFeelException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                }
                UIDefaults defaults = UIManager.getDefaults();
                final FontUIResource res = new FontUIResource(fnt);
                Object[] obj = res.getAvailableAttributes();
                for (Object objs : obj) {
                    System.out.println(objs); //returns java.awt.font.TextAttribute
                }
                defaults.put("defaultFont", res);
                SwingUtilities.updateComponentTreeUI(frame);
                frame.pack();
            }
        };
    }

    public static void main(String arg[]) {
        try {
            for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                SystemFontDisplayer systemFontDisplayer = new SystemFontDisplayer();
            }
        });
    }

    private class ComboRenderer extends BasicComboBoxRenderer {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            final Object fntObj = value;
            final String fontFamilyName = (String) fntObj;
            setFont(new Font(fontFamilyName, Font.PLAIN, 16));
            return this;
        }
    }
}

from code Oldies L&Fs

import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

public class SystemFontDisplayer extends JFrame {

    private static final long serialVersionUID = 1L;
    private JFrame frame = new JFrame("Nimbus UIDeafaults and Font");
    private JComboBox fontsBox;
    private javax.swing.Timer timer = null;
    private JButton testButton = new JButton("testButton");
    private JTextField testTextField = new JTextField("testTextField");
    private JLabel testLabel = new JLabel("testLabel");
    private Font font1, font2;
    private JMenuBar menuBar1 = new JMenuBar();
    private JMenu menu1 = new JMenu("Menu 1");
    private JMenu menu2 = new JMenu("Menu 2");
    private JMenuItem menuItem1 = new JMenuItem("MenuItem 1");
    private JMenuItem menuItem2 = new JMenuItem("MenuItem 2");

    public SystemFontDisplayer() {
        try {
            font1 = Font.createFont(Font.TRUETYPE_FONT, SystemFontDisplayer.class.getResourceAsStream("/Images/SourceSansPro-Regular.ttf"));
            font2 = Font.createFont(Font.TRUETYPE_FONT, SystemFontDisplayer.class.getResourceAsStream("/Images/SourceSansPro-Regular.otf"));
        } catch (FontFormatException ex) {
            Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
        }
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        //ge.registerFont(font1);
        ge.registerFont(font2);
        String[] fontFamilyNames = ge.getAvailableFontFamilyNames(Locale.getDefault());
        fontsBox = new JComboBox(fontFamilyNames);
        fontsBox.setSelectedItem(0);
        fontsBox.setRenderer(new ComboRenderer());
        fontsBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final String fontName = fontsBox.getSelectedItem().toString();
                    fontsBox.setFont(new Font(fontName, Font.PLAIN, 16));
                    start();
                }
            }
        });
        fontsBox.setSelectedItem(0);
        fontsBox.getEditor().selectAll();
        menu1.add(menuItem1);
        menuBar1.add(menu1);
        menu2.add(menuItem2);
        menuBar1.add(menu2);
        frame.setJMenuBar(menuBar1);
        frame.setLayout(new GridLayout(4, 0, 20, 20));
        frame.add(fontsBox);
        frame.add(testButton);
        frame.add(testTextField);
        frame.add(testLabel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(200, 105);
        frame.pack();
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                fontsBox.setPopupVisible(true);
                fontsBox.setPopupVisible(false);
            }
        });
        frame.setVisible(true);
    }

    private void start() {
        timer = new javax.swing.Timer(750, updateCol());
        timer.setRepeats(false);
        timer.start();
    }

    public Action updateCol() {
        return new AbstractAction("text load action") {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                final Font fnt = new Font(fontsBox.getSelectedItem().toString(), Font.PLAIN, 12);
                final FontUIResource res = new FontUIResource(fnt);
                UIManager.getLookAndFeelDefaults().put("Button.font", res);
                UIManager.getLookAndFeelDefaults().put("TextField.font", res);
                UIManager.getLookAndFeelDefaults().put("Label.font", res);
                SwingUtilities.updateComponentTreeUI(frame);
                frame.pack();
            }
        };
    }

    public static void main(String arg[]) {
        /*try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                SystemFontDisplayer systemFontDisplayer = new SystemFontDisplayer();
            }
        });
    }

    private class ComboRenderer extends BasicComboBoxRenderer {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            final Object fntObj = value;
            final String fontFamilyName = (String) fntObj;
            setFont(new Font(fontFamilyName, Font.PLAIN, 16));
            return this;
        }
    }
}

Hereupon answered 27/8, 2013 at 10:16 Comment(25)
how does this help me to compare the otf and ttf version of Adobe Source Sans Pro? Also it does not print the values of the attributes to the console but just which attributes exist, did you take a look at the Github issue?Thiel
1) how does this help me to compare the otf and ttf version of Adobe Source Sans Pro? ---> each of Font has many attributes, one of them is insets, empty borders, available space for displaying higher of Unicodes glyph 2) Also it does not print the values of the attributes to the console but just which attributes exist ---> again you can to get detailed properties from all Attributes 3) reason for Visual Font Designer by @ Darryl Burke and don't reinvent the wheel in my answer here 4) did you take a look at the Github issue? ---> standard answer for OpenSource ...Hereupon
no, you misunderstood something. I am using the font Source Sans Pro by Adobe. And I am using the otf or ttf version of this font. Only the otf font has some issues (line height?) but Miguel by Adobe says they both are the same. You can just select one version of the font from the list (ttf or otf?) but you can not compare them or select between otf and ttf version to compare them directly.Thiel
what did you find? In FontForge the 2 font files and metrics are the same so there are not 2px missinbg. Did you think about a Swing bug? Which textattribute differs when you compare both versions of the same font?Thiel
don't know, never caused before, if is feature or bug, but better will be to test with another Otf Font, I'm bet that with the same output in WinXP on Java6 too, have to wait a few momentsHereupon
WinXp/Java with the same issue, hehehe are someone talking about bug in Java7_025,Hereupon
maybe is there issue with Otf Fonts only, have to test with another Otf Font, but out of my endless lazyness and interest aboutHereupon
you can to use three, test with separate methods from SwingUtilitieshttp://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html, every returns -2 pixels for FONT_SIZE.16Hereupon
let us continue this discussion in chatThiel
@Daniel Ruf see answer (code lined in body) by Andrew ThompsonHereupon
no idea, only helicopter view, seems like as coordinates are repaired in the View, maybe programatically added one/two pixel, still/but I'd add 1-2 moreover (on top)Hereupon
code lined in body? do you mean the hyperlink? seems this fixed the issue, but why? the ttf font gets a bit blurry, but the otf font is fixed and looks ok. what do you mean by helicopter view? it looks ok/right here, no need to add more pixels at the topThiel
you have to notify author of code about, maybe he's able to fix issue with this Font in his code, his test will be faster as our comments about hereHereupon
can you take a look at this and answer the comments from Miguel Sousa? github.com/adobe/source-sans-pro/issues/…Thiel
1. this will be accepted as offical bug in the case that only one of JComponents caused by different layout, bug could be in the case that JTextField (then JComboBox too)for example there is but in Java7 (still not Offical) with (java.swing.)View for JTextComponents, there is difference between APIs docs and binnary source,Hereupon
2. a) font can be registred in Native OS, b) font can be registred in JVM only, have to test if is there some difference,Hereupon
3. there isn't any difference between Java6 and Java7 as is demonstrated in my answer here and for various Standard LookAndFeels on varianous WinOS version, there is important fact that renderings core is very different for WinXP and for Win7/8, then my answers is that isn't Java bugHereupon
4. most of Java bug are accesible only from SystemLookAndFeels (WindowsLook...) or WindowsClassicLook..., the result is same as for Nimbus (only one different rendering algorithm in Swing APIs)Hereupon
5. my question (don not take as flamewar) is for why reasons one part of font is rendered correctly (after font is converted, fixed), second isn't, there is possible to calculate required Rectange from SwingUtilities.(layoutCompoundLabel, e.i.) but by default there isn't some direct way to get this height (everything is about how to computeStringWidth), this value came from Font and isn't directly accesible from deriveFont for Graphics too,Hereupon
6. if is there any different conclusion I can to abuse my rep power, to ask question here about how to get, set, manage required height for Fonts from Graphics, because for JComponents is in BasicXxxUI everything about paint/paintText, but I'm think that layout for this font in Graphics will be the same as for JComponentsHereupon
please answer on Github, this is better for all ;-)Thiel
github.com/adobe/source-sans-pro/issues/… any news/updates?Thiel
not I tested another Fonts, part of them with the similair and wrong offset, BugParade (everything after merging is with Oracle names but bugs are still Sun) is official Java Bug Database,Hereupon
you know already that I have filed an issue which does not exist - which is very weird - it should exists as I have a bug id ... =( this is very disappointing with Oracle and Java and that there is no answer for this issue/answer which solves all the problems.Thiel
all this brings us to nothing, Adobe says it is not a font bug, Oracle says nothing, so for me it is a Java bugThiel

© 2022 - 2024 — McMap. All rights reserved.