Why is this font so big in Java?
Asked Answered
S

1

8

I’m trying to use OpenDyslexic as a font option in a Swing application. But surprisingly, OpenDyslexic looks much bigger than any other font at the same point size, even though it looks normally sized in other applications. I’ve tried a handful of other OpenType fonts, and they don’t look especially large or small. Why is OpenDyslexic so big in Java, and how can I get Java to size it normally so I don’t have to special-case the size of OpenDyslexic?

On Oracle JRE (I tried 1.7.0_11, 1.7.0_15, and the latest 1.7.0_21) on all OSes, the font is too big when Java loads the font file using Font.createFont. However, when I install the font into the operating system, the behavior is different on all 3 platforms:

  • In Linux, installing the font to ~/.fonts does no good. The screenshot looks the same before installing the font and after installing it.
  • In Windows, installing the font fixes the font glyphs, but the font spacing is still too big! See screenshot below.
  • In OS X, installing the font fixes it! It looks like a normal-sized font on OS X.

Update: Interestingly, OpenJDK (both the 7u21 Ubuntu package in Linux and the obuildfactory build on OS X) does not exhibit the bug. The 15pt OpenDyslexic ‘m’ is 15px wide on OpenJDK, as it should be, both when the font is created from file and when the font is handled by the operating system. The bug is in the latest Oracle JRE but not in the latest OpenJDK.

Here’s my example program. Note that to try it, you need to put the OpenDyslexic files into resources/. Alternatively, install OpenDyslexic into your system and take out the registerFonts() call.

SansSerif is normal size OpenDyslexic is huge at the same point size After installing OpenDyslexic on Windows, it looks stupid After installing font on OS X: perfect!

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;

import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

public class FontFrame {
    /**
     * Register extra fonts from resources. If you already have it installed on
     * the computer, you can skip this.
     */
    private static void registerFonts() {
        String[] resources = {
            "OpenDyslexic-Regular.otf",
            "OpenDyslexic-Italic.otf",
            "OpenDyslexic-Bold.otf",
            "OpenDyslexic-BoldItalic.otf"
        };
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        for (String filename: resources) {
            InputStream stream = FontFrame.class.getResourceAsStream("resources/" + filename);
            try {
                Font font = Font.createFont(Font.TRUETYPE_FONT, stream);
                ge.registerFont(font);
            } catch (FontFormatException | IOException e) {
                throw new IllegalStateException(e);
            }
        }
    }
    private static void createUI(boolean allFonts) {
        final JTextArea textArea = new JTextArea(
                "Font created to help dyslexic readers. " +
                "Bottom heavy and unique character shapes help " +
                "prevent letters and numbers from being confused.");
        textArea.setWrapStyleWord(true);
        textArea.setLineWrap(true);
        final DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
        if (allFonts) {
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            HashSet<Object> seenFamilies = new HashSet<>();
            Font[] fonts = ge.getAllFonts();
            for (Font font: fonts) {
                String familyName = font.getFamily(Locale.ENGLISH);
                if (seenFamilies.contains(familyName))
                    continue;
                seenFamilies.add(familyName);
                model.addElement(familyName);
            }
        } else {
            model.addElement("SansSerif");
            model.addElement("OpenDyslexic");
        }

        final int fontSize = 15;
        textArea.setFont(new Font("SansSerif", Font.PLAIN, fontSize));
        model.addListDataListener(new ListDataListener() {
            @Override public void intervalRemoved(ListDataEvent e) {}
            @Override public void intervalAdded(ListDataEvent e) {}
            @Override public void contentsChanged(ListDataEvent e) {
                if (e.getIndex0() == -1 && e.getIndex1() == -1) {
                    SwingUtilities.invokeLater(new Runnable() { @Override public void run() {
                        String selectedFamily = (String) model.getSelectedItem();
                        Font font = new Font(selectedFamily, Font.PLAIN, fontSize);
                        textArea.setFont(font);
                    }});
                }
            }
        });
        JComboBox<String> familyChooser = new JComboBox<>(model);
        familyChooser.setMaximumRowCount(50);
        familyChooser.setRenderer(new DefaultListCellRenderer() {
            private static final long serialVersionUID = 1L;
            public Component getListCellRendererComponent(JList<?> list,
                    Object value, int index, boolean isSelected,
                    boolean cellHasFocus) {
                Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                String familyName = (String) value;
                Font font = new Font(familyName, Font.PLAIN, fontSize);
                comp.setFont(font);
                return comp;
            }
        });

        JPanel jpanel = new JPanel();
        jpanel.setLayout(new BorderLayout());
        jpanel.add(familyChooser, BorderLayout.NORTH);
        jpanel.add(textArea, BorderLayout.CENTER);
        JFrame jframe = new JFrame();
        jframe.getContentPane().add(jpanel);
        jframe.setSize(300, 300);
        jframe.invalidate();
        jframe.setVisible(true);
        jframe.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }
    public static void main(String[] args) throws InvocationTargetException, InterruptedException {
        registerFonts();
        final boolean allFonts = Arrays.asList(args).contains("--all");
        SwingUtilities.invokeAndWait(new Runnable() {
            @Override public void run() {
                createUI(allFonts);
            }
        });
    }
}
Supersensitive answered 16/5, 2013 at 20:3 Comment(2)
you can to test if is true, made by Darryl BurkeAvouch
@mKorbel, the font looks the same in Visual Font Designer Demo as it does when you look at the installed font. On OS X it looks good, but on other platforms it looks bad. (Note that I’ve updated the question to describe installing the font on different platforms.)Supersensitive
C
1

Not every Java version supports OpenType (cf. this overview). If you can live without some of the OpenType features, the easiest solution would be converting the font file to TTF. There seem to be a couple of free online options to help you with that, and if this solves your problem you can still invest in professional software to possibly get better results.

Cr answered 21/5, 2013 at 17:18 Comment(3)
But the webpage you linked claims that Java on Windows supports OpenType (both the TrueType and PostScript variants), and Windows actually looked the worst.Supersensitive
Since that is not an official statement, the take away for me would be that OTF can cause problems. The specific reification of these problems might also depend on other factors like the OS version. // On the other hand, I personally only ever had problems with PS fonts, and converting them was the solution. Are there other reasons that prevent you from trying that? For example, I didn't read the OpenDyslexic license...Cr
Thanks Tilo. After converting the font from otf to ttf, it has the correct size on all platforms, both when installed and when loaded from font file.Supersensitive

© 2022 - 2024 — McMap. All rights reserved.