免责声明:我不是字体开发专家,只是分享我的经验。
没错,这有点本地化。例如,即使是新的JavaFX web视图,也依赖于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
的值可以验证你的“显然不是。什么可能导致这种差异?”。
对于某些nix系统,sun.font.fontmanager
的值可能为sun.awt.X11FontManager
,但对于Windows来说可能为null
,因此管理器将会是sun.awt.Win32FontManager
。
现在每个管理器都可能依赖于各种底层塑形/渲染引擎/实现(这可能有所帮助)。
主要原因可能是字体的性质。它们大多是矢量图形。因此,根据平台/环境,呈现的文本可能更大或更小。例如,Windows可能应用桌面Cleartype和屏幕文本大小(DPI)于请求的文本呈现。
似乎即使您确切地拥有两个sun.awt.X11FontManager
管理器,结果也会有所不同。这也可能有所帮助
如果您只是在在线编译器上尝试示例代码,肯定会遇到不同的结果。
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, style, size);
使用GraphicsEnvironment
注册字体,然后使用Font
创建实例解决了我们的问题。因此,您也可以尝试一下。
解决方案
最终,我舍弃了JDK的东西(真的很麻烦),改用harfbuzz
(字形处理)+ freetype
(渲染)本地实现,这确实让人放心。
所以...
• 您可以将生产服务器(简单的方法)作为呈现字体和渲染的参考,并基于它验证结果(而不是开发机器)。
• 或者,使用跨平台和独立的(可能是本地的)字形处理/渲染字体引擎/实现,以确保开发和生产结果将相同。
GlyphVector
得到了一致的结果吗? `public static Shape getShapeOfText(Font font, String msg) { BufferedImage bi = new BufferedImage( 1, 1, BufferedImage.TYPE_INT_RGB);Graphics2D g = bi.createGraphics();FontRenderContext frc = g.getFontRenderContext(); GlyphVector gv = font.createGlyphVector(frc, msg);return gv.getOutline(); }` - Andrew Thompson