阿拉伯语中的某些单词在 Swing 中显示为书法

Some words in Arabic appear calligraphic in Swing

似乎 Swing 自动修饰了一些阿拉伯语单词,使它们看起来像某种书法。其中一个词是穆罕默德,在阿拉伯语中拼写为 محمد。

import java.awt.Font;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class TestProject extends JFrame {
    
    public static void main(String[] args) {
        TestProject frame = new TestProject();
        frame.setVisible(true);
    }
    
    public TestProject() {
        this.setSize(200, 100);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JLabel label = new JLabel("محمد");
        label.setFont(new Font("Arial", Font.BOLD, 28));
        this.add(label);
    }

}

该问题至少适用于所有广泛使用的字体。

我正在使用 Windows 10 & Java 8。我在另一台 PC 上尝试过相同的程序(也是 Windows 10)同样的问题。

我们怎样才能禁用它?

(注意:我不懂阿拉伯语。)

似乎与字体有关

默认情况下,我没有看到您的屏幕截图中显示的更长的表示(3 个字?)。

  • 当我用文本 "محمد" 编写一个最小的 Swing 应用程序时,我得到了你想要的那个短字符串(4 个字符?)。
  • 当使用特定字体时,我确实得到了我未经训练的眼睛看起来是你试图避免的书法渲染。

请注意,我的字符串不是您的字符串。我从 Google T运行slate, t运行slating Muhammad 复制了你的问题。

https://translate.google.com/?sl=en&tl=ar&text=Muhammad%0A&op=translate

我只用 JLabel 编写了这个最小的 Swing 应用程序,仅通过增加字体大小来增强。

package work.basil.example;

import javax.swing.*;
import java.awt.*;

/**
 * Hello world!
 */
public class App {
    public static void main ( String[] args ) {
        System.out.println( Runtime.version() );
        javax.swing.SwingUtilities.invokeLater( () -> createAndShowGUI() );
    }

    private static void createAndShowGUI () {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated( true );

        //Create and set up the window.
        JFrame frame = new JFrame( "Test Arabic rendering" );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

        //Add the ubiquitous "Hello World" label.
        JLabel label = new JLabel( "محمد" );
        label.setFont( new Font( label.getFont().getName() , label.getFont().getStyle() , 40 ) );  // Override default font size.
        System.out.println( "Font name: " + label.getFont().getName() + "  |  " + "Font style: " + label.getFont().getStyle() );
        frame.getContentPane().add( label );

        //Display the window.
        frame.pack();
        frame.setVisible( true );
    }
} 

当 运行 在我的 MacBook Pro(13 英寸,M1,2020 年)、Apple Silicon(不是英特尔)、16 GB 内存上时。 OS 是 macOS Big Sur,11.5.1。使用来自 this page.

的 Java 17 (17+35-2724) 的早期访问版本

(顺便说一句,这是您应该随问题一起发布的 MCVE 类型。)

我的字体查询结果是:

Font name: Lucida Grande | Font style: 0

… 但我怀疑这是 JLabel 小部件的默认字体,而不是用于呈现这些阿拉伯字符的实际字体。我依稀记得,最新版本的 macOS 包含丰富的各种专用于阿拉伯语的字体。请参阅:Fonts included with macOS Big Sur for three lists: fonts included, fonts available for download, and older fonts available for document support. Using the Font Book app bundled with macOS, and defining a "smart collection" where languages include Arabic, I get a list of 32 such fonts installed by default in macOS Big Sur. (The four items for Pragmata Pro 不适用 — 这是我购买的商业字体,我强烈推荐给开发人员。)

我运行这个修改版本的代码来自在同一台macOS上面描述的Big Sur。

package work.basil.text;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;

public class TestProject extends JFrame {

    public static void main ( String[] args ) {
        TestProject frame = new TestProject();
        frame.setVisible( true );
    }

    public TestProject () {
        this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
        this.setLayout( new FlowLayout() );

        String input = "محمد";
        String[] fontFamilies = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
        for ( String fontFamily : fontFamilies ) {
            Font font = new Font( fontFamily , Font.PLAIN , 40 );
            if ( font.canDisplayUpTo( input ) < 0 ) {
                JLabel label = new JLabel( input );
                label.setFont( font );
                label.setBorder( new TitledBorder( fontFamily ) );
                this.add( label );
            }
        }

        this.pack();
    }
}

这是结果的屏幕截图。

尝试 运行 下面的代码。它在我安装的字体范围内生成了这张图片。

另请注意,Arial(一种无衬线或未装饰字体)的阿拉伯字形似乎默认为 Times New Roman(一种衬线或装饰字体)。这是字体(或系统,不确定)经常做的事情,当用衬线字体替换无衬线字体时,它会产生相当奇怪的渲染。

另请注意,此系统安装了 255 种字体,但其中只有 23 种支持阿拉伯字符。

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

public class TestProject extends JFrame {

    public static void main(String[] args) {
        TestProject frame = new TestProject();
        frame.setVisible(true);
    }

    public TestProject() {
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel p = new JPanel(new GridLayout(0, 5));
        String arabic = "محمد";
        String[] fontFamilies = GraphicsEnvironment.
                getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
        for (String fontFamily : fontFamilies) {
            Font font = new Font(fontFamily, Font.PLAIN, 25);
            if (font.canDisplayUpTo(arabic) < 0) {
                JLabel label = new JLabel(arabic);
                label.setFont(font);
                label.setBorder(new TitledBorder(fontFamily));
                p.add(label);
            }
        }
        this.add(new JScrollPane(p));
        this.pack();
    }
}

这似乎是旧的(即最多 Java 8)字体渲染引擎中的错误。

这是 Java 8 在我的机器上的样子:

这是 Java9 的结果:

我不知道是否针对此特定问题报告了明确的错误报告。但是由于 JEP 258: HarfBuzz Font-Layout Engine.

,字体引擎已被完全替换

Replace the existing ICU OpenType font-layout engine with HarfBuzz.

因此旧字体渲染的错误消失也就不足为奇了。