为什么这个字体在Java中如此之大?

时间:2021-07-23 05:29:23

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?

我正在尝试使用OpenDyslexic作为Swing应用程序中的字体选项。但令人惊讶的是,OpenDyslexic看起来比同一点大小的任何其他字体大得多,即使它在其他应用程序中看起来通常很大。我尝试了一些其他OpenType字体,它们看起来并不特别大或小。为什么OpenDyslexic在Java中如此之大,如何让Java正常大小以便我不需要特殊情况下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:

在所有操作系统上的Oracle JRE(我试过1.7.0_11,1.7.0_15和最新的1.7.0_21)上,当Java使用Font.createFont加载字体文件时,字体太大了。但是,当我将字体安装到操作系统中时,所有3个平台上的行为都不同:

  • In Linux, installing the font to ~/.fonts does no good. The screenshot looks the same before installing the font and after installing it.
  • 在Linux中,将字体安装到〜/ .fonts并不好。在安装字体之前和安装后,屏幕截图看起来相同。
  • In Windows, installing the font fixes the font glyphs, but the font spacing is still too big! See screenshot below.
  • 在Windows中,安装字体会修复字体字形,但字体间距仍然太大!见下面的截图。
  • In OS X, installing the font fixes it! It looks like a normal-sized font on OS X.
  • 在OS X中,安装字体可以修复它!它看起来像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.

更新:有趣的是,OpenJDK(Linux中的7u21 Ubuntu软件包和OS X上的obuildfactory构建版本)都没有出现这个bug。 OpenFDK上的15pt OpenDyslexic'm'应该是15px宽,无论是从文件创建字体还是操作系统处理字体时都是如此。该错误发布在最新的Oracle JRE中,但不在最新的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.

这是我的示例程序。请注意,要尝试它,您需要将OpenDyslexic文件放入资源/。或者,将OpenDyslexic安装到您的系统中并取出registerFonts()调用。

为什么这个字体在Java中如此之大?为什么这个字体在Java中如此之大?为什么这个字体在Java中如此之大?为什么这个字体在Java中如此之大?

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);
            }
        });
    }
}

1 个解决方案

#1


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.

并非每个Java版本都支持OpenType(参见本概述)。如果您可以在没有OpenType功能的情况下使用,最简单的解决方案是将字体文件转换为TTF。似乎有几个免费的在线选项可以帮助您解决这个问题,如果这可以解决您的问题,您仍然可以投资专业软件,以获得更好的结果。

#1


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.

并非每个Java版本都支持OpenType(参见本概述)。如果您可以在没有OpenType功能的情况下使用,最简单的解决方案是将字体文件转换为TTF。似乎有几个免费的在线选项可以帮助您解决这个问题,如果这可以解决您的问题,您仍然可以投资专业软件,以获得更好的结果。