4

我正在开发一个我认为相当简单/直接的应用程序。它所做的只是将字符串呈现为BufferedImage特定字体的 a (来自文件,未安装在系统上)。我正在取得一些进展,但经过几天的努力,Java 似乎对字体指标非常善变。有时它喜欢提供良好的字体度量,有时它喜欢返回全零和全 240 的某种组合(无论字体大小),但没有明显的原因。

在少数情况下,我发现仅调用f = f.deriveFont(myFloat)会导致字体度量完全失败,从有效数字变为全零,而调用f = f.deriveFont(Font.PLAIN, (int) myInt)会保留度量,因此新字体实例可以正常工作。(是的,我知道这应该是一个浮点数,但由于某种原因,用浮点数调用它在某些情况下会再次破坏字体指标。)

通过TextAttributes在字体和对象RenderingHints中的组合Graphics2D,我设法让大多数字体工作......但我仍然有少数OpenType字体(.otf)在 Java 中破坏了指标(JSE/JDK 7 ) 虽然它们在Windows 7字体查看器中显示良好。

因此,我选择了其中一种字体,并删除了应用程序中的所有内容,只在 Main 方法中获得了最原始的字体视图。这段代码中的echo()方法只是System.out.println(). (另外,我很抱歉这段代码的草率——我只是把我能找到的任何可能在这一点上产生新信息的东西都扔进去。)

BufferedImage img = new BufferedImage(730, 70, TYPE_INT_ARGB); 
Graphics2D g = img.createGraphics(); 
FontRenderContext frc = g.getFontRenderContext(); 
String text = "Hello World"; 

File media = new File("z:\\path\\to\\fonts\\LondonDoodles.otf"); 
Font f7 = Font.createFont(Font.TRUETYPE_FONT, media);
f7 = f7.deriveFont(Font.PLAIN, (int) 20);
TextLayout lay = new TextLayout(text, f7, frc);
Rectangle2D r = lay.getPixelBounds(frc, 0, 0);

echo("NumGlyphs=" + f7.getNumGlyphs());
echo("bounds=" + r); // these bounds are all zeros 

// use an array of GlyphCodes instead of a String 
// to try and get at the glyphs directly without going through the CMAP 
GlyphVector gv = f7.createGlyphVector(frc, new int[] { 1, 2, 3, 4, 5 });

echo("Glyph0Logical=" + gv.getGlyphLogicalBounds(0).getBounds2D()); // all 240s, go figure 
echo("Glyph0Pixel=" + gv.getGlyphPixelBounds(0, frc, 0, 0)); // all zeros 
echo("GlyphVectorLogical=" + gv.getLogicalBounds()); // random assortment of zeros & 240s
echo("GlyphVectorPixel=" + gv.getPixelBounds(frc, 0, 0)); // all zeros 

echo(g.getFontMetrics(f7)); // 240s 

LineMetrics lm = f7.getLineMetrics(text, frc);
echo("LineMetrics=" + lm.getAscent() + "/" + lm.getDescent() + "/" + lm.getHeight() + "/" + lm.getLeading()); // 240s 

此代码的输出如下所示:

NumGlyphs=33
bounds=java.awt.Rectangle[x=0,y=0,width=0,height=0]

Glyph0Logical=java.awt.geom.Rectangle2D$Float[x=240.0,y=240.0,w=240.0,h=240.0]
Glyph0Pixel=java.awt.Rectangle[x=0,y=0,width=0,height=0]
GlyphVectorLogical=java.awt.geom.Rectangle2D$Float[x=0.0,y=240.0,w=0.0,h=240.0]
GlyphVectorPixel=java.awt.Rectangle[x=0,y=0,width=0,height=0]

sun.font.FontDesignMetrics[font=java.awt.Font[family=London Doodles,name=LondonDoodles,style=plain,size=20]ascent=-239, descent=240, height=241]
LineMetrics=-240.0/240.0/240.0/240.0

显然有可能从这个字体进来的 .otf 文件中获得正确的字体指标,因为 Windows 7 字体查看器和另一个用 C 编写的应用程序能够将它呈现到 PNG 上,就像我在这里尝试做的那样,我只是可以'不知道为什么 Java 不喜欢它。

  • 它不是抛出 anIOException或 a FontFormatException,所以我知道它正在读取文件并创建一个表面上有效的Font 对象。
  • 在上面的代码中,我GlyphVector使用一个 int 数组创建了一个 int 数组,它是GlyphCodes从 1 到字体中字形数(在本例中为 33)的索引,因此它不必搜索 从Unicode CodePoints转换为的CMAP字形并可能找不到这些字符。
  • 您还可以在FontMetricsFont 报告的大小为 20pts 的回声中看到,所以它不像被设置为 size=0 或任何东西。无论我在字体上设置什么大小,输出中的 240 都不会改变。

经过几天尝试为 Google 提供搜索词后,我仍然找不到有关此特定问题的信息。看起来真的很奇怪。你会认为字体指标看似随机地左右打破(尽管我确信它实际上不是随机的)会是人们会问他们是否有这个问题,特别是考虑到我测试过的所有字体似乎始终报告零和 240 的组合。后半部分,他们都一致报告 240 秒,对于一个不容易通过谷歌搜索的问题,这似乎有点奇怪。

无论如何,我想知道是否有人有可能导致 Java 中字体指标错误的项目列表(文本属性、图形设置、JRE 标志、操作系统环境变量、字体创建程序、字体文件中的标志等)?或者可能是损坏字体指标的解决方法列表?还是Java中的字体很糟糕,我应该研究一下LaTeX?(老实说,我目前对此一无所知。)

谢谢!

编辑:嗯......这有点令人沮丧......我想也许如果我挖掘 OpenJDK 的“开源”,也许我可以产生一个Font可以解决这些指标问题的派生实现......但显然这是通过将所有必要的内部结构设为私有、静态和最终的来故意防止。请参阅:字体,如何扩展它们......我无法在运行时替换核心类 - 请参阅:替换 java 类?...因此,如果我想尝试以这种方式修复指标,唯一的选择是使用 , 等的完整副本重新创建整个 Java 字体体系结构,java.awt.Font然后手动将sun.font.Font2D字形绘制到对象上,因为没有它就无法工作或衍生物Graphics2DGraphics.drawGlyphVector()Graphics.drawString()FontFont因为他们使用Font类作为参数,Graphics.setFont()而不是为 Font 声明一个接口来实现。...除非我误读了第二个堆栈溢出参考的答案?我误读了吗?我可以创建一个自定义类加载器,Font用修改后的版本替换该类吗?

编辑:也许我应该在发布最后一次编辑之前做更多的研究,但是对于任何正在阅读这个问题并想知道的人,是的,您可以用 JVM 参数替换核心 Java 类的修改版本。请参阅: http: //media.techtarget.com/tss/static/articles/content/CovertJava/Sams-CovertJava-15.pdf所以我现在正在做的是挖掘大量核心类来尝试找到这个地方其中度量是从字体文件中读取的。如果我能找到,那么我可以用修改后的版本替换该类,以纠正损坏的指标。

4

0 回答 0