在Windows和Linux中加载ttf字体时JLabel的差异

11
我正在使用以下代码在Java中上传aller字体:

我正在使用以下代码在Java中上传aller字体:

private Font loadFont(final String path) {
    Font font = null;

    InputStream fontFile = null;
    fontFile = FontLoaderClass.class.getResourceAsStream(path);

    if (fontFile != null) {
        try {
            font = Font.createFont(Font.PLAIN, fontFile);
        } catch (FontFormatException e) {
            LOGGER.error("Error with font format {}", e);
        } catch (IOException e) {
            LOGGER.error("Error accessing font {}", e);
        }
    }
    return font;
}

字体已经正确加载:

http://www.fontsquirrel.com/fonts/Aller

字体设置为所有".font",更改了Java应用程序的默认设置,但在Linux中显示正确,而在Windows中则不正确。

private Font buildFont(final String key, final int size) {
    Font f = loadFont(ALLER_LT_FONT_PATH);
    GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(f);
    if (f == null) {
        f = (Font) UIManager.get(key);
    }
    f = f.deriveFont(Font.TRUETYPE_FONT, size);
    return f;
}

Linux显示: linux image pick

Windows显示: enter image description here

正如您在图片中看到的那样,Windows存在一些被截断的问题,这导致图像显示不正确。

是否有人之前遇到过这个问题?


1
我看不出有什么问题...它们看起来一样,除了 Windows 上的标签似乎稍微大一些。 - Branislav Lazic
在Windows中,显然不像在Linux中那样流畅。 - RamonBoza
1
  1. 在这种情况下,请使用PNG图像而不是JPEG。
  2. 你确定问题不是由于系统清晰度设置引起的吗?
- Crozin
它们是字体,不是图像。 - RamonBoza
3个回答

4

请查看附带的两个小演示,它们分别为Swing组件和绘制操作启用了抗锯齿功能。

适用于Swing组件。

// to enable antialiasing (AA) for Swing components
//
// either:
//    start the JVM with the option -Dawt.useSystemAAFontSettings=on
//    see also: http://docs.oracle.com/javase/6/docs/technotes/guides/2d/flags.html#aaFonts
// or:
//    System.setProperty("awt.useSystemAAFontSettings", "on");
//    - you must call it before the first Swing component is rendered
//    - if AA it's on by default you must set it "off", otherwise you can't
//      toggle it inside the application

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import static java.awt.RenderingHints.KEY_ANTIALIASING;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_OFF;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;

public class SwingAntiAliasingDemo {

    public static void main(String[] args) {
        System.setProperty("awt.useSystemAAFontSettings", "off");
        initGui();
    }

    public static void initGui() {
        JFrame frame = new JFrame();

        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent we) {
                System.exit(0);
            }
        });

        Font font = new Font("Serif", Font.TRUETYPE_FONT, 96);
        JPanel jpanel = new JPanel(new BorderLayout());

        JLabel labelAA = new JLabel("Antialiasing ON") {
            @Override
            public void paintComponent(Graphics g) {
                Graphics2D graphics2d = (Graphics2D) g;
                graphics2d.setRenderingHint(KEY_ANTIALIASING,
                        VALUE_ANTIALIAS_ON);
                super.paintComponent(g);
            }
        };
        labelAA.setFont(font);
        labelAA.setForeground(Color.WHITE);

        JLabel labelNoAA = new JLabel("Antialiasing OFF") {
            @Override
            public void paintComponent(Graphics g) {
                Graphics2D graphics2d = (Graphics2D) g;
                graphics2d.setRenderingHint(KEY_ANTIALIASING,
                        VALUE_ANTIALIAS_OFF);
                super.paintComponent(g);
            }
        };
        labelNoAA.setFont(font);
        labelNoAA.setForeground(Color.WHITE);

        jpanel.setBackground(new Color(0, 22, 95));
        jpanel.add(labelAA, BorderLayout.NORTH);
        jpanel.add(labelNoAA, BorderLayout.SOUTH);

        frame.setTitle("stackoverflow question 16304254");
        frame.getContentPane().add(jpanel);
        frame.setLocation(200, 200);
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
    }
}

用于绘图操作

// to enable antialiasing (AA) for draw operations

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;

import static java.awt.RenderingHints.KEY_ANTIALIASING;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_OFF;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;

public class DrawAntiAliasingDemo extends JFrame {

    private Font font;
    private Color backGroundColor;

    public static void main(String[] args) {
        new DrawAntiAliasingDemo();
    }

    public DrawAntiAliasingDemo() {
        font = new Font("Serif", Font.TRUETYPE_FONT, 96);
        backGroundColor = new Color(0, 22, 95);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent we) {
                System.exit(0);
            }
        });

        setTitle("stackoverflow question 16304254");
        setSize(850, 260);
        setResizable(false);
        setVisible(true);
    }

    @Override
    public void paint(Graphics g) {
        Graphics2D d = (Graphics2D) g;
        d.setColor(backGroundColor);
        d.fillRect(0, 0, getWidth(), getHeight());
        d.setFont(font);
        d.setPaint(Color.white);

        d.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
        d.drawString("Antialiasing ON", 10, 115);

        d.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_OFF);
        d.drawString("Antialiasing OFF", 10, 230);
    }
}

致敬
弗兰克


根据JAVA文档(您的链接),"awt.useSystemAAFontSettings"默认为开启状态,我刚刚测试了一下,我的桌面设置显然表明应该使用AA。这是您的第一个示例,没有使用System.setProperty,对我来说标签是相同的。所以我想那个行为是可以接受的。如果RamonBoza想确保他的应用程序无论桌面设置如何都使用AA,则应使用JVM参数解决方案,这似乎是最简单的方法。 - Trilarion
JVM会自动检查操作系统是否启用了AA支持。可以通过以下方式进行交叉检查:System.out.println(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"));JVM选项“-Dawt.useSystemAAFontSettings=on”强制启用AA支持(使用操作系统的默认设置)。如果您想使用其他设置,可以使用javado链接下描述的可能值之一。 - SubOptimal

1

我之前遇到过类似的问题,直到我在SourceForge找到了这个叫做Smooth Metal的库,你可以从这里下载它。

库主页Smooth Metal

Smooth Metal外观是对包括Java在内的一些外观的补充,通过抗锯齿文本增强它们。

你会注意到,在Windows中选择ClearType选项不会影响结果...

在将库的jar文件添加到类路径后,我编写了这个小的Java应用程序,用两个JButtons渲染JLabel并撤消渲染,结果非常清晰:

以下是你可以测试的代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.plaf.basic.BasicLabelUI;
import smoothmetal.SmoothLabelUI; // UI Class to set for the JLabel


public class LabelRender extends JFrame{

    JPanel panel = new JPanel();
    JPanel panel2 = new JPanel();
    JButton button = new JButton("RENDER");
    JButton button2 = new JButton("UNDO");
    JLabel label = new JLabel("HELLO WORLD");

    public LabelRender(){
        setSize(600, 250);
        setLocationRelativeTo(null);
        setTitle("JLabel Renderer");


        setLayout(new BorderLayout());

        label.setFont(new Font("Aller", Font.PLAIN, 70));
        label.setForeground(Color.WHITE);

        panel.add(label);
        panel2.add(button);
        panel2.add(button2);

        panel.setBackground(Color.BLACK);

        this.add(panel2, BorderLayout.NORTH );
        this.add(panel,BorderLayout.CENTER);

        setVisible(true);
        validate();


       // System.out.println(label.getUI());

        button.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                label.setUI(new SmoothLabelUI());
            }
        });

        button2.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                label.setUI(new BasicLabelUI());
            }
        });

    }

    public static void main(String args[]){
        new LabelRender();
    }
}

嗨, 当您运行以下示例时`java -cp .;smoothmetal.jar -Dawt.useSystemAAFontSettings=on LabelRender`它证实了我在第一个示例中提到的内容:“如果默认情况下启用了AA,则必须将其设置为“关闭”,否则您无法在应用程序内切换它” 干杯,弗兰克 - SubOptimal

1
我觉得Windows操作系统没有使用ClearType。 ClearType是一种选项,启用后可以平滑字体。 有时出于调整或性能原因会禁用它。请参见http://support.microsoft.com/kb/306527。尝试启用它。
要在屏幕字体中使用ClearType:
1. 单击“开始”,单击“控制面板”,单击“外观和主题”,然后单击“显示”。 2. 在“外观”选项卡上,单击“效果”。 3. 单击以选中“使用以下方法平滑屏幕字体边缘”复选框,然后在列表中单击ClearType。

1
实际上,该应用程序在默认启用ClearType的Windows 8中执行,禁用它可以使应用程序正常工作,但Windows看起来不太好。 - RamonBoza
我的建议是启用它,而不是禁用它。此外,渲染可能会导致轻微的差异。请参见http://www.oracle.com/technetwork/java/javase/tech/faq-jsp-138165.html - 文本渲染部分。 - cinhtau
即使已启用ClearType,是否仍需要进行调整,如http://windows.microsoft.com/zh-cn/windows7/make-text-easier-to-read-using-cleartype中所建议的? - Ajai Gopal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接