gpt4 book ai didi

java - 为什么 java.awt.Font.getStringBounds 在不同的机器上给出不同的结果?

转载 作者:行者123 更新时间:2023-12-03 21:11:03 25 4
gpt4 key购买 nike

我有一个生成 PDF 报告的应用程序(使用 JasperReports),但是如果我在我的开发笔记本电脑上运行我的应用程序,文本字段的大小与我在服务器上生成完全相同的报告时的大小略有不同。我最终将问题简化为以下代码:

final Font font = Font.createFont(
Font.TRUETYPE_FONT,
MyTest.class.getResourceAsStream("/fonts/europa/Europa-Bold.otf")
).deriveFont(10f);
System.out.println(font);
System.out.println(font.getStringBounds(
"Text",
0,
4,
new FontRenderContext(null, true, true)
));
在我的笔记本电脑上打印:
java.awt.Font[family=Europa-Bold,name=Europa-Bold,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-9.90999,w=20.080002,h=12.669988]
在服务器上打印:
java.awt.Font[family=Europa-Bold,name=Europa-Bold,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-7.6757812,w=20.06897,h=10.094452]
如您所见,我实际上是随应用程序一起提供了字体文件,所以我相信两台机器实际上不可能使用不同的字体。
我会猜到在这些条件下 getStringBounds 的输出是独立于系统的。显然不是。什么可能导致差异?

最佳答案

免责声明! : 我不是字体开发专家,只是分享我的经验。
是的,它有点原生。例如,即使是新的 JavaFX Web View 也取决于 webkit .
如果您深入调试 getStringBounds ,你会意识到它达到了一个点,字体管理器应该决定加载一个具体的字体管理器,其中类名应该是系统属性 sun.font.fontmanager .sun.font.FontManagerFactory的源代码

...
private static final String DEFAULT_CLASS;
static {
if (FontUtilities.isWindows) {
DEFAULT_CLASS = "sun.awt.Win32FontManager";
} else if (FontUtilities.isMacOSX) {
DEFAULT_CLASS = "sun.font.CFontManager";
} else {
DEFAULT_CLASS = "sun.awt.X11FontManager";
}
}
...
public static synchronized FontManager getInstance() {
...
String fmClassName = System.getProperty("sun.font.fontmanager", DEFAULT_CLASS);
}
那些 DEFAULT_CLASS值可以验证你的显然不是。什么可能导致差异?标记。 sun.font.fontmanager 的值可能是 sun.awt.X11FontManager对于某些 nix 系统,但可能是 null以 windows 为例,因此管理器将是 sun.awt.Win32FontManager .
现在每个管理器都可能依赖于不同的底层整形/渲染引擎/impl( this may help)。
主要原因可能是字体的性质。因为它们主要是 vector 的东西。因此,基于平台/环境,渲染的文本可能更大或更小。例如,Windows 可能会在请求的文本渲染上应用桌面清除类型和屏幕文本大小 (DPI)。
看来,即使你正好有两个 sun.awt.X11FontManager经理,结果会有所不同。 this may help too
如果您只是在在线编译器上试用示例代码,您肯定会遇到不同的结果。
ideaone ( https://ideone.com/AuQvMV) 的结果,无法发生, stderr有一些有趣的信息
java.lang.UnsatisfiedLinkError: /opt/jdk/lib/libfontmanager.so: libfreetype.so.6: cannot open shared object file: No such file or directory
at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2430)
at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2487)
at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2638)
at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:827)
at java.base/java.lang.System.loadLibrary(System.java:1902)
at java.desktop/sun.font.FontManagerNativeLibrary$1.run(FontManagerNativeLibrary.java:57)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:310)
at java.desktop/sun.font.FontManagerNativeLibrary.<clinit>(FontManagerNativeLibrary.java:32)
at java.desktop/sun.font.SunFontManager$1.run(SunFontManager.java:270)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:310)
at java.desktop/sun.font.SunFontManager.<clinit>(SunFontManager.java:266)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:415)
at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:82)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:310)
at java.desktop/sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)
at java.desktop/java.awt.Font.getFont2D(Font.java:497)
at java.desktop/java.awt.Font.getFamily(Font.java:1410)
at java.desktop/java.awt.Font.getFamily_NoClientCode(Font.java:1384)
at java.desktop/java.awt.Font.getFamily(Font.java:1376)
at java.desktop/java.awt.Font.toString(Font.java:1869)
at java.base/java.lang.String.valueOf(String.java:3042)
at java.base/java.io.PrintStream.println(PrintStream.java:897)
at Ideone.main(Main.java:19)
注意 libfreetype 的失败/丢失加载这是本地人/ C字体渲染应用
编码接地结果( https://www.tutorialspoint.com/compile_java_online.php)
fnt manager: sun.awt.X11FontManager
java.awt.Font[family=Dialog,name=tahoma,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-9.282227,w=22.09961,h=11.640625]
jdoodle 的结果 ( https://www.jdoodle.com/online-java-compiler/)
fnt manager: sun.awt.X11FontManager
java.awt.Font[family=Dialog,name=tahoma,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-9.839991,w=24.0,h=12.569988]
我的机器
fnt manager: null
java.awt.Font[family=Tahoma,name=tahoma,style=plain,size=10]
java.awt.geom.Rectangle2D$Float[x=0.0,y=-10.004883,w=19.399414,h=12.0703125]
我的故事 (可能有帮助,你可以试试)
几年前我遇到过类似的问题,在 macOs/jdk8 上使用完全相同的嵌入字体进行文本渲染失败, 用于复杂的文本渲染(很多连字)。不仅是尺寸,还有破损的连字、字距调整等......
我可以使用另一个工作区来解决我的问题(不记得是否修复了大小,但肯定没有损坏的连字),如下所示
InputStream is = Main.class.getResourceAsStream(fontFile);
Font newFont = Font.createFont(Font.TRUETYPE_FONT, is);
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(newFont);
//later load the font by constructing a Font ins
Font f = new Font(name/*name of the embedded font*/, style, size);
使用 GraphicsEnvironment 注册字体,然后使用 Font 对其进行实例化解决了我们的问题。所以你也可以试一试。
解决方案
最后,我只是把jdk的东西降级了(脖子真的很疼),并想出了 harfbuzz (整形)+ freetype (渲染)native impl,这确实是一种和平。
所以...
• 您可以考虑将您的生产服务器(简单方式)作为渲染字体推进和渲染的引用,并根据它验证结果(而不是开发机器)
• 或者,使用交叉和独立(也可能是原生的)整形/渲染字体引擎/impl 来确保开发和生产结果相同。

关于java - 为什么 java.awt.Font.getStringBounds 在不同的机器上给出不同的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63849522/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com