即使我的字体是从文件创建的,为什么我必须调用 GraphicsEnvorinment.registerFont() ?

2023-12-01

我正在开发一个使用 JFreeChart 来呈现图表的 Web 应用程序。但是,当服务器没有安装任何中文字体时,即使我设置了字体,JFreeChart也不会显示中文字符。

然后我写了一个小测试代码,发现在绘制图表之前添加这行代码可以解决问题。

GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);

所以我的问题是 -

  1. 即使我从文件创建字体,为什么也必须将字体注册到 JVM 中?这是否意味着 JFreeChart 不使用我直接设置的字体?

  2. 当我将程序部署到服务器时,即使我添加这行代码,它也不会显示汉字。如何让它始终使用我设置的字体,以便在所有环境下都能正确显示字符?

我知道我可以做一个fallback目录在$JAVA_HOME/jre/lib并将我的字体放入其中。但这并不能解释为什么 JFreeChart 无法以我设置的字体显示。

UPDATE

我很确定字体已正确加载,也是如此registerFont()当我将程序部署到 Tomcat 中时返回 true。

UPDATE 2

根据JAVA 2D 常见问题解答,现在我意识到我必须打电话registerFont()为了使我自己的字体“安装”到 JVM 中,并且我的字体将通过Font构造函数。

从 Java SE 6 开始,有一种方法: GraphicsEnvironment.registerFont() 使您能够 可供字体构造函数使用的“创建”字体,并通过以下方式列出 字体枚举 API。 Font.createFont() 和此方法结合起来 提供一种将字体“安装”到正在运行的 JRE 中的方法,因此它是 就像操作系统安装的字体一样可用。然而这个字体不 在 JRE 调用中保持不变。

但是,既然我已经有了Font创建/派生自的实例createFont(),为什么我的程序不需要创建其他的Font?


以下是我使用的代码,它只是输出 PNG 格式的图表。如果您想运行代码,您应该更改输出位置和字体以满足您的需要,并且这是 SourceForge 链接对于我在代码中使用的中文字体。

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;
  }
}

当您创建一个Font直接从 TTF 中,Java 显然知道从单个 Font 对象中的何处获取字体文件本身的副本。那么为什么字体也需要注册才能使用呢?答案是并不总是需要注册,或者至少只要整个控制链都使用原始的Font直接反对。

当 Java 尝试渲染字体时到底会发生什么?

细微差别在于 JFreeChart 要求如何呈现文本。文本的渲染是在TextUtilities#drawRotatedString来自 jcommon 的方法。在 JDK7 上,默认情况下此方法将:

  • 创建一个AttributedString基于您传入的字体的“属性”,
  • call Graphics2D#drawString在属性字符串上,然后
  • 创建一个新的TextLayout object.

TextLayout是选择要提供给的实际 Font 对象的类Graphics2D. TextLayout旨在支持使用各种字体呈现多语言文本(即使同一单个源字符串需要以多种字体呈现),通过使用自动字体选择来为字符串的每一段找到合适的字体。

上面提到的“属性”是关于字体的简单事实(如字体系列名称、大小等),它们源自Font您提供的。如果您提供的字体无法呈现输入字符串中的所有字符,则这些属性将用于选择类似的字体,以用于需要使用不同字体的文本运行。

当 JFreeChart 调用 TextLayout 时,它的功能总是如下所示:

  • 从中提取属性Font您提供的对象,
  • 打电话给static Font#getFont获取与提供的属性相匹配的字体(请参阅TextLayout#singleFont), and
  • 使用返回的(可能不同的)Font 对象来绘制文本。

如果你还没有静态地在某处注册了你的字体(比如GraphicsEnvironment#registerFont),那么所有的static 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 容器内运行,我担心通过静态注册永远无法取消注册的字体来创建 PermGen 类加载器泄漏。直接使用 Font 对象可以避免这个问题,这就是我想走这条路的原因。我想,如果您这样做,特定的 Java 平台总是可能会遇到问题,但在我的测试中,至少在使用 Oracle JDK 7 的 Windows、Linux 和 OS X 主机上,这工作得很好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

即使我的字体是从文件创建的,为什么我必须调用 GraphicsEnvorinment.registerFont() ? 的相关文章

  • java中的csv到pdf文件

    我正在尝试获得一个csv文件解析为pdf 到目前为止我所拥有的内容附在下面 我的问题是这段代码最终出现在 pdf 中的文件在 csv 文件的第一行被截断 我不明白为什么 附示例 本质上我想要一个没有任何操作的 csv 文件的 pdf 版本
  • 用 @DataJpaTest 注释的测试不是用 @Autowired 注释的自动装配字段

    我有一个 Spring Boot 应用程序 其中包含 Spring Data Jpa 存储库 我需要围绕这个存储库运行单元 或组件 测试 我对 Spring Data Jpa 没有太多经验 这是我的测试 这很简单 我无法让它通过 impor
  • 如何在 Eclipse 中用阿拉伯语读写

    我在 eclipse 中编写了这段代码来获取一些阿拉伯语单词 然后打印它们 public class getString public static void main String args throws Exception PrintS
  • 检查双精度值的等于和不等于条件

    我在比较两者时遇到困难double values using and 我创建了 6 个双变量并尝试进行比较If健康 状况 double a b c d e f if a b c d e f My code here in case of t
  • 通过 InjectMocks Spy 注入对象

    我需要对一个类运行一系列单元测试 该类具有 Autowired Logger 实现 实现的基本思想是 Mock Logger logger InjectMocks TestedClass tested 但我想保存日志输出功能 Mockito
  • Java 重写 hashCode() 得到 StackOverflowError

    所以我不太熟悉重写 hashCode 并且我似乎在 hashCode 方法中以某种方式进行了一些无限递归 这是我的场景 我有一个 DuplicateCache 类 它是一个缓存对象 用于检查系统中的重复对象 我有一个静态内部类 Duplic
  • Android - 除了普通 SSL 证书之外还验证自签名证书

    我有一个通过 SSL 调用 Web 服务的 Android 应用程序 在生产中 我们将拥有由受信任的 CA 签名的普通 SSL 证书 但是 我们需要能够支持自签名证书 由我们自己的 CA 签名 我已经成功实施了接受自签名证书的建议解决方案
  • 为什么我在 Mac 上看到“java.lang.reflect.InaccessibleObjectException: Unable to make private java.nio.DirectByteBuffer(long,int)accessibl

    我已经在工作中愉快地构建代码好几天了 但突然我的一个项目 不是全部 失败并出现此错误消息 看看下面的答案吧 我是如何修复它的 起初我用谷歌搜索 看到很多有这个问题的人正在使用 Java 16 但我认为 错误 我正在使用 Java 11 因为
  • 使用 java 按电子邮件发送日历邀请

    我正在尝试使用 java 发送每封电子邮件的日历邀请 收件人收到电子邮件 但不会显示接受或拒绝的邀请 而是将该事件自动添加到他的日历中 我正在使用 ical4j jar 构建活动 邀请 private Calendar getInvite
  • 参数动态时如何构建 JPQL 查询?

    我想知道是否有一个好的解决方案来构建基于过滤器的 JPQL 查询 我的查询太 富有表现力 我无法使用 Criteria 就像是 query Select from Ent if parameter null query WHERE fiel
  • 打印包含 JBIG2 图像的 PDF

    请推荐一些库 帮助我打印包含 JBIG2 编码图像的 PDF 文件 PDFRenderer PDFBox别帮我 这些库可以打印简单的 PDF 但不能打印包含 JBIG2 图像的 PDF PDFRenderer尝试修复它 根据 PDFRedn
  • Apache Commons CLI:替代已弃用的 OptionBuilder?

    IntelliJ 显示此示例代码中不推荐使用 OptionBuilderhttp commons apache org proper commons cli usage html http commons apache org proper
  • 如何使用 Mockito 和 Junit 模拟 ZonedDateTime

    我需要模拟一个ZonedDateTime ofInstant 方法 我知道SO中有很多建议 但对于我的具体问题 到目前为止我还没有找到任何简单的解决办法 这是我的代码 public ZonedDateTime myMethodToTest
  • 从java中的字符串数组中删除空值

    java中如何从字符串数组中删除空值 String firstArray test1 test2 test4 我需要像这样没有 null 空 值的 firstArray String firstArray test1 test2 test4
  • struts 教程或示例

    我正在尝试在 Struts 中制作一个登录页面 这个想法是验证用户是否存在等 然后如果有错误 则返回到登录页面 错误显示为红色 典型的登录或任何表单页面验证 我想知道是否有人知道 Struts 中的错误管理教程 我正在专门寻找有关的教程 或
  • Spock模拟inputStream导致无限循环

    我有一个代码 gridFSFile inputStream bytes 当我尝试这样测试时 given def inputStream Mock InputStream def gridFSDBFile Mock GridFSDBFile
  • Path2D 上的鼠标指针检测

    我构建了一个Path2D http docs oracle com javase 7 docs api java awt geom Path2D html表示由直线组成的未闭合形状 我希望能够检测何时单击鼠标并且鼠标指针靠近路径 在几个像素
  • Java 编码风格、局部变量与重复方法调用

    我更喜欢使用局部变量而不是多次调用同一方法 I prefer this Vehicle vehicle person getVehicle if vehicle instanceof Car Car car Car vehicle car
  • Java 推断泛型类型

    我正在寻找类似的推断捕获泛型类型的概念 类似于以下方法片段 但不是捕获泛型类型的类 public
  • 使用 eclipse IDE 配置 angularjs

    我想开始使用 AngularJs 和 Java Spring 进行开发 我使用 Eclipse 作为 IDE 我想配置我的 Eclipse 以使这些框架无缝工作 我知道我可能要求太多 但相信我 我已经做了很多研究 你们是我最后的选择 任何帮

随机推荐

  • Spring:PropertyPlaceholderConfigurer找不到属性文件

    我在使用 Spring 时遇到一个奇怪的问题PropertyPlaceholderConfigurer 我的一种豆子设计如下
  • C++ 纯虚函数的多重继承问题

    我制作了一个最小的示例来复制我在更复杂的类层次结构中遇到的问题 include
  • Django - 模型 - 递归检索叶节点的父节点

    我有一个用户模型类定义如下 class CustomUser models Model user models OneToOneField User slug models SlugField max length 35 unique Tr
  • 导入错误:没有名为 pynput.keyboard 的模块

    我有问题 找不到任何帮助 想法是我无法导入 pynput 我做了 pip install 它显示的是 gt Traceback most recent call last File sb py line 1 in
  • C++读取带空格的字符串

    我有这样的文件 59 137 New York 137 362 Syracuse 216 131 New Jersey 我想将其读入一个结构 X Y 城市名称 char city 100 int x y f open map txt f g
  • 删除 XWPFHyperlinkRun Apache POI

    我和这位小伙伴有同样的问题 如何通过 poi 删除 XWPFHyperlinkRun 由于 XWPFHyperlinkRun 元素 我无法将 doc 转换为 pdf 我可以删除一个简单运行的段落 如下所示 for XWPFParagraph
  • NumberPicker 在 setValue() 之后显示错误的值

    我试图创建一个可以满足我的需求的 NumberPicker 但我偶然发现了一些东西 但我不明白它是什么 行为很简单 我有三个数字选择器 每个数字选择器的值可以从 15 到 15 之间 当用户按下Ok按钮选择的值 如果有效 将保存在 结构 和
  • 如何计算 unix 中给定日期之前的日期?

    我有两个变量 X 和 Y X 的值将以格式给出的日期mmddyy我想计算日期前那个日期and以格式返回yyyymmdd 让我举一个例子 当X 091509 时 mmddyy格式 Y 应为 20090914 yyyymmdd format d
  • Android popupWindow,无法获取弹出窗口中的元素

    我在抓取我的东西时遇到问题Buttons 和 my 中的其他元素PopupWindow 使用debugger它只是报告为null private void initiatePopupWindow try We need to get the
  • 视图有什么用?

    我只是想大致了解 RDBMS 中视图的用途 也就是说 我知道什么是视图以及如何创建视图 我也知道我过去用它们做什么 但我想确保我彻底了解视图的用途和视图不应该用途 进一步来说 视图有什么用 是否存在某些情况下 当您不应该使用视图时却很想使用
  • 如何在 PHP 中使用准备好的语句从 mysql 更改为 pdo?

    dml insert into bookmark accountId category url hash title created value SESSION accountId POST category POST url md5 PO
  • 接口与抽象类

    我有点熟悉抽象类和接口类之间的区别 但是 你认为下面这句话的意思是什么 接口只能定义常量 而抽象类可以有字段 接口只能定义常量 而抽象类可以有字段 接口中的字段是隐式的public static final 抽象类则不然
  • 我可以将枚举添加到现有的 .NET 结构(例如日期)中吗?

    显然 微软的日期结构中没有月份枚举 我想知道是否可以创建一个枚举并将其附加到 DateTime 结构 扩展方法立即浮现在我的脑海中 但我不知道如何使用它们来实现这一点 Dim july As DateTime Months DateTime
  • 为什么循环引用被认为是有害的? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 Locked 这个问题及其答案是locked因为这个问题是题外话 但却具有历史意义 目前不接受新的答案或互动 为什么一个对象引用另一个引用第一个对象的对象是一个糟糕的设计 之间的循环依赖关
  • 分离线程与可连接 POSIX 线程

    我一直在使用pthread用于在 C 中创建和连接线程的库 我什么时候应该从一开始就创建一个分离的线程 与可连接线程相比 它是否具有任何性能优势 不这样做是否合法pthread join 在可连接 默认 线程上 或者这样的线程应该始终使用d
  • Perl 正则表达式匹配具有特殊字符的字符串

    我有一个子字符串列表 需要在 URL 字符串列表中进行匹配 子字符串具有特殊字符 如 等 如果 URL 字符串包含该子字符串 我需要执行一些操作 但现在我们只说我将在控制台中打印 TRUE 我通过首先读取子字符串列表并将其放入哈希中来做到这
  • 将数据框中的字符串转换为双精度

    我使用构建了一个数据框concat它产生一个字符串 import sqlContext implicits val df sc parallelize Seq 1 0 2 0 3 0 4 0 toDF k v df registerTemp
  • 如何在 iPhone 中修剪音频文件?

    我的文档目录文件夹中有声音文件 我想修剪该声音文件 怎么做 您可以使用扩展音频文件服务 查看 ExtAudioFileRead 和 ExtAudioFileWrite 的参考 它们有示例代码 然后您可以打开一个音频文件读取它 修剪它 然后写
  • Excel 自动化 Windows 服务

    我有一个运行的 Windows 服务Excel Interop以便自动执行各种宏 然而 当我尝试时遇到了一个特殊的问题运行使用 Windows 身份验证访问数据库的宏 如果宏运行通过Windows服务 工作簿已打开 宏已开始执行 但应用程序
  • 即使我的字体是从文件创建的,为什么我必须调用 GraphicsEnvorinment.registerFont() ?

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