【问题标题】:Which system component is responsible for binding Unicode ligatures in a Java application?哪个系统组件负责在 Java 应用程序中绑定 Unicode 连字?
【发布时间】:2011-08-27 07:20:53
【问题描述】:

这是我在尝试为我的另一个问题 (Rendering Devanagari ligatures (Unicode) in Java Swing JComponent on Mac OS X) 寻找更好的规范时遇到的“元问题”。

到目前为止,我还不太了解给定系统的哪个“组件”(因为需要更好的词)负责在 Java 中显示 Unicode 文本,更具体地说是 连字 .

据我了解,以下组件对流程有影响:

  1. 系统字符编码(例如 Mac OS X 10.6 上的 UTF-8,Windows 7 上的 UTF-16(根据 akira 对此superuser.com post 的评论)。
  2. Java Charset(在 Mac OS X 10.6 上默认为 MacRoman,在 Windows 7 上默认为 cp1252)。
  3. 用于呈现文本的字体,以及该字体的编码信息(正如 Donal Fellows 在my other question 上所建议的那样:

    “字体包含有关它们使用的编码的信息”。

  4. 显然要呈现的字符是否存在于各自的 Unicode 代码点。

因此,如果一串 Unicode 字符没有正确显示(如我在另一个问题中所见,s.a.),那么问题最可能出在哪里?即,什么“组件”(更好的词是什么?)负责“绑定”连字及其组成?

非常感谢您,如果您需要更多信息,请告诉我。

【问题讨论】:

  • 我会冒险猜测虚拟机,但我没有这方面的证据或专业知识。
  • @Mr47:好的,谢谢,那就是数字 (2)。我猜这就是 stackoverflow.com/questions/361975/…> 可能派上用场的地方。我会记住这一点。我已经对帖子进行了一些修改,以便为其他人指定我的问题的“入口点”。

标签: java unicode character-encoding rendering system


【解决方案1】:

该系统组件称为字体渲染器或字体光栅器。它负责根据字体中定义的字形将一系列字符代码转换为像素。正如其他答案所述,您可以从 Java 获取和设置的各种字符编码值是无关紧要的。当 JVM 给字体渲染器一个字符代码序列时,它会告诉它应用什么编码(可能是 UTF16,但这对 Java 程序员是透明的。)字体渲染器使用字体文件中指定的字体编码来匹配相应的字形。

当前版本的 Windows 和 Mac OS X 带有出色的字体渲染器。

混淆的第一点是 JRE 带有自己的字体渲染器,作为 Java2D 平台的一部分,而这正是 Swing 使用的。应该有一个选项来控制 Java 是使用自己的渲染器还是系统渲染器。

编辑:正如McDowell 在评论中指出的那样,在 OS X 上,您可以通过设置 Java 属性 apple.awt.graphics.UseQuartz=true 来启用系统渲染器。

混淆的第二点是连字在英语中是可选的。当桌面发布应用程序看到“shuffle”之类的词时,它将替换为“ffl”连字(字体中的单个字形),但大多数其他应用程序不会打扰。根据你所说的梵文(以及我刚刚在维基百科上读到的内容),我认为连字在该语言中不是可选的。

默认情况下,Java2D 字体渲染器不执行连字。但是,java.awt.font.TextAttribute.LIGATURES 的 JavaDoc 说,对于需要它们的编写系统,始终启用连字。如果这不是您的经验,您可能在 Java2D 字体渲染器中发现了一个错误。同时,尝试使用带有字体属性映射的 Font 构造函数,包括 TextAttribute.LIGATURES。

【讨论】:

  • 非常感谢这个有趣的见解。你说得对,在梵文中连字根本不是可选的。然而,我已经测试了LIGATURES_ONTextAttribute(正如Oracle 所建议的,见下文),不幸的是它并没有改变任何事情。这使得 fontconfig 文件成为问题的最可取的来源。 Map<TextAttribute, Object> m = new Hashtable<TextAttribute, Object>(); m.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON); font = font.deriveFont( map ); g2.setFont( font );
  • @baphomet13 - 看来您可以在 OS X 上使用 Java system property 在 Java2D 和 Quartz 渲染之间切换:apple.awt.graphics.UseQuartz
  • @McDowell:您的最后一条评论很到位,解决了我的问题。我可以建议您将其编辑到您的答案中,以便我可以接受它作为最佳答案吗?另外,我已经对我的相关问题 [stackoverflow.com/questions/5994815/… 设置了赏金,我建议你也在那里添加你的答案,以便我可以将赏金奖励给你!再次非常感谢,你帮了我很多!
  • @McDowell - 尽管有 bahomet13 的建议,但我只是编辑了我的答案以包含对您评论的引用。
【解决方案2】:

我不是专家,但希望这些提示可以为您指明正确的方向...

源数据的编码对字体的呈现方式几乎没有影响。 Java 中的所有字符数据都是 UTF-16,因此只要您将信息从源正确转码为字符/字符串,就应该保持数据的完整性。

但是,请注意:

  • AWT 系统可以使用默认的系统编码来做字体映射
  • 这不太可能适用于梵文(我不知道支持它的旧编码)

AWT 映射字体是通过fontconfig file。在我的 Windows 系统上,这映射到 Mangal 字体:

allfonts.devanagari=Mangal

毫无疑问,Mac OS 上使用了不同的字体。

在 Java 6 生命周期的某个时候引入了原生文本渲染 - 我不知道这是否对字体支持有任何影响,或者只是影响渲染速度/抗锯齿等。

【讨论】:

  • 感谢您的提示!这听起来很像我一直在寻找的东西,尽管我的问题是描述问题。我需要一点时间来测试它,但一定会在这里跟进。
  • 我刚刚查询了几个 Mac 用户,他们都有 fontconfig.properties 映射到 Mangal 的 allfonts.devanagari。老实说,我现在完全不知道为什么 Mac 和 Windows 显示器之间应该存在差异,因此我将不胜感激任何进一步的提示。
  • @baphomet13 - 假设 Mangal 字体在两个平台上是相同的(而不是同名的不同实现),那么我怀疑 gatkin 更接近标记 - 问题可能出在 如何字体被渲染。
【解决方案3】:

如果您严格参考视觉渲染,则“编码”和相关主题不再相关:渲染从String 转到视觉显示。 String 具有已定义(且不可更改)的编码,即 UTF-16。因此,必须首先解决诸如“我是否以正确的编码读取此二进制流”之类的所有问题。

文本的实际渲染必须由图形子系统完成。那将是“普通”Java 或 SWT 或任何其他替代系统的 AWT/Swing。

第一步(严格来说不是“渲染”的一部分)是将一些二进制数据转换为String。这可以涉及平台默认编码iff代码没有明确指定一些编码。这是编码通常发挥作用的步骤。在那之后,我们就进入了happy-happy-pure-Unicode-land。

【讨论】:

  • 非常感谢您对条款的详细说明。恐怕我的解释不是很具体。然而,我是否正确,假设连字的正确显示(例如,लक्ष्मी,使用七个 Unicode 代码点或德语 ff)与 字符编码有关(SystemProperty"file-encoding")?
  • 另外,我已更改标题和文字以反映您的更正。
  • @baphomet:不,正确的 显示 没有。问题是:你的 unicode 数据是包含 U+FB00 LATIN SMALL LIGATURE FF 还是包含 2 U+0066 LATIN SMALL LETTER F?
  • 我的String 包含七个代码点 (\u0932\u0915\u094D\u0937\u094D\u092E\u0940),应该显示梵文连字 लक्ष्मी (/laksmi/)。我希望像这样编写的 Unicode 数据会显示为连字,这在 Windows 7 和 Ubuntu 机器上确实如此,但在 Mac OS X 上却没有。因为天城文中的连字通常是单词,它们没有像这样的单个代码点拉丁文小连字 FF。
  • 应该注意的是,U+FB00 有点奇怪:Unicode 通常不为连字提供单独的代码点(认为这些是渲染决策而不是文本信息)。那个(和类似的)只存在于往返正确性,一些常用的遗留编码可以对这些连字进行编码。
【解决方案4】:

与 Joachim 所说的类似,数据的来源是什么?如果您从文件或流中读取,我肯定会不信任系统默认编码。您应该在读取数据时明确设置编码,例如

BufferedReader br = new BufferedReader( new InputStreamReader( file, "UTF-8" ) );

或者您的流使用的任何编码。

见:

http://download.oracle.com/javase/1.4.2/docs/api/java/io/InputStreamReader.html#InputStreamReader(java.io.InputStream,%20java.lang.String)

【讨论】:

  • 好的,我现在知道为什么我会触发 Joachim 的响应了。事实上,我确实不从文件中读取,而是使用 Unicode 字符定义了一个 String 变量(例如,String str = "\u0932\u0915\u094D\u0937\u094D\u092E\u0940")。这些 not 在 Mac 系统上正确显示,但 are 在 Windows 系统上正确显示,这引发了我的问题。我将删除数字 (3),这样它就不会触发有关读取流的进一步答案。抱歉,为了完整起见,我想我会把它放进去。
猜你喜欢
  • 1970-01-01
  • 2016-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多