gpt4 book ai didi

java - 为什么我的Font是从文件创建的,为什么还要调用GraphicsEnvorinment.registerFont()?

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:51:30 29 4
gpt4 key购买 nike

我正在开发一个使用JFreeChart呈现图表的Web应用程序。但是,当服务器未安装任何中文字体时,即使我设置了字体,JFreeChart也不显示中文字符。
然后,我编写了一个小的测试代码,发现在绘制图表之前添加这行代码可以解决问题。

GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);
所以我的问题是-
  • 为什么即使从File创建字体,我也必须将字体注册到JVM中? 这是否意味着JFreeChart不使用我直接设置的字体?
  • 将程序部署到服务器中时,即使添加此行代码,也不会显示中文字符。 如何使其始终使用我设置的字体,以便在所有环境中正确显示字符?

  • 我知道我可以在 fallback中创建一个 $JAVA_HOME/jre/lib目录,并将字体放入其中。但这不能解释为什么JFreeChart无法使用我设置的字体显示。
    更新
    我很确定字体可以正确加载,并且在将程序部署到Tomcat时 registerFont()也返回true。
    更新2
    根据 JAVA 2D FAQ的介绍,现在我意识到必须调用 registerFont()才能将自己的字体“安装”到JVM中,并且可以通过 Font构造函数使用我的字体。

    从Java SE 6开始,有一种方法:
    GraphicsEnvironment.registerFont()使您能够制作
    “创建的”字体可供字体构造函数使用,并通过列出
    字体枚举API。 Font.createFont()和此方法结合在一起
    提供一种将字体“安装”到正在运行的JRE中的方法
    与O / S安装字体一样可用。但是此字体不
    在JRE调用中保持不变。

    但是,由于我已经从 Font创建/派生了 createFont()实例,为什么我的程序仍不需要创建其他 Font

    以下是我使用的代码,它只是以PNG格式输出图表。如果要运行代码,则应更改输出位置和字体以适合您的需要,并为我在代码中使用的中文字体更改 here is the SourceForge link
    import java.awt.Font;
    import java.awt.GraphicsEnvironment;
    import java.io.File;

    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartUtilities;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.StandardChartTheme;
    import org.jfree.data.general.DefaultPieDataset;
    import org.jfree.data.general.PieDataset;

    public class Problem {

    public static void main(String[] args) throws Exception {
    setJFreeChartTheme();

    PieDataset dataset = createDataSet();
    JFreeChart chart = ChartFactory.createPieChart(
    "Chinese Testing", dataset, true, true, false);
    ChartUtilities.saveChartAsJPEG(new File("/tmp/output.png"),
    chart, 800, 600);

    System.out.println("Done");
    }

    private static void setJFreeChartTheme() throws Exception {
    Font font = loadFont();
    //==================================================================
    GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);
    //==================================================================
    StandardChartTheme theme = new StandardChartTheme("Chinese font", true);
    theme.setExtraLargeFont(font.deriveFont(Font.BOLD, 20));
    theme.setLargeFont(font.deriveFont(Font.BOLD, 16));
    theme.setRegularFont(font.deriveFont(Font.PLAIN, 14));
    theme.setSmallFont(font.deriveFont(Font.PLAIN, 12));
    ChartFactory.setChartTheme(theme);
    }

    private static Font loadFont() throws Exception {
    File file = new File("/tmp/wqy-zenhei.ttc");
    return Font.createFont(Font.TRUETYPE_FONT, file);
    }

    private static PieDataset createDataSet() {
    DefaultPieDataset dataset = new DefaultPieDataset();
    dataset.setValue("種類1", Integer.valueOf(1));
    dataset.setValue("種類2", Integer.valueOf(2));
    dataset.setValue("種類3", Integer.valueOf(3));
    return dataset;
    }
    }

    最佳答案

    当直接从TTF创建Font时,Java显然知道从该单个Font对象中获取字体文件本身的副本的位置。那么,为什么还需要注册该字体才能使用它? 答案是,它不一定总是必须注册,或者至少在整个控制链中直接使用原始Font对象时才注册。

    当Java尝试渲染字体时,真正发生了什么?

    区别在于JFreeChart如何要求呈现文本。文本的呈现是通过jcommon的TextUtilities#drawRotatedString方法执行的。在JDK7上,默认情况下,此方法将:

  • 根据您传入的字体
  • 的“属性”创建 AttributedString
  • 在属性字符串上调用Graphics2D#drawString,然后
  • 创建一个新的TextLayout对象。
  • TextLayout是选择要提供给 Graphics2D的实际Font对象的类。 TextLayout旨在通过使用自动字体选择为字符串的每一段查找合适的字体来支持使用各种字体(即使需要使用多种字体来呈现相同的单个源字符串)来呈现多语言文本。

    上面提到的“属性”是关于字体的简单事实(如字体系列名称,大小等),这些事实是从您提供的 Font派生而来的。如果您提供的字体无法呈现输入字符串中的所有字符,则该属性用于选择相似的字体以用于需要使用其他字体的那些文本运行。

    当JFreeChart调用TextLayout时,它始终具有以下功能:
  • 从提供的Font对象
  • 中提取属性
  • 调用静态Font#getFont以获取与提供的属性匹配的字体(请参见TextLayout#singleFont),以及
  • 使用返回的(可能是不同的)Font对象绘制文本。

  • 如果您尚未在某处静态注册字体(例如 GraphicsEnvironment#registerFont),那么静态 Font#getFont方法将必须继续执行的操作是包含字体系列名称的属性字符串。它不知道在哪里访问包含对TTF的引用的Font对象,更不用说实际渲染字体所需的任何数据了。

    好的,但是我想你说我不需要注册字体?

    如果您不想注册字体,那么诀窍在于确保仅使用提供的 Font对象呈现文本。碰巧的是, TextLayout的另一个构造函数直接接受 Font对象,而不是一组用于查找字体的属性。

    有用的是,JFreeChart甚至提供了一种方法来强制其使用此构造函数。在 TextUtilities#drawRotatedString中,可以使用特殊的配置参数来强制JFreeChart使用您提供的确切 TextLayout对象构造 Font对象本身。

    为此,您可以像这样设置jcommon.properties文件:
  • 创建一个名为jcommon.properties的资源文件(应该以您的类路径/ JAR的根目录结尾),然后创建
  • 向其添加以下行:
  • org.jfree.text.UseDrawRotatedStringWorkaround=true
    否则只需调用静态函数即可:
    TextUtilities.setUseDrawRotatedStringWorkaround(true)

    这将要求JFreeChart直接使用您的字体呈现文本,然后... 瞧!即使没有注册字体,它也可以工作。这是在上述问题的上下文中进行测试的,即使用JFreeChart将文本直接呈现为光栅图像。如果尝试渲染到显示设备(我没有尝试),则里程可能会有所不同。

    不注册字体是否明智?

    我不能肯定地说。我的一个应用程序在OSGi容器中运行,并且我对通过静态注册一个永不注销的Font来创建PermGen类加载器泄漏感到担心。直接使用Font对象可以避免该问题,这就是为什么我要走这条路线。我想如果您这样做,特定的Java平台总是有可能出现问题,但是在我的测试中,至少在使用Oracle JDK 7的Windows,Linux和OS X主机上,这可以正常工作。

    关于java - 为什么我的Font是从文件创建的,为什么还要调用GraphicsEnvorinment.registerFont()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12112353/

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