【问题标题】:Differences between Swing and iText font renderingSwing 和 iText 字体渲染的区别
【发布时间】:2012-08-28 18:40:47
【问题描述】:

我正在构建一个应用程序,它允许用户使用图层将文本插入 PDF。

可以使用应用程序设置 PDF 页面中文本的位置,该应用程序使用 JPanel 内的ICEPdf 呈现 PDF。选择图层的位置和大小后,应用使用iText (v. 5.3.2) 将其呈现为 PDF。

我面临的问题是 Swing 的字体渲染与 PDF 中的最终结果明显不同。

以下是一些屏幕截图,均在同一个边框内使用 Helvetica 纯字体:

使用 Swing 渲染文本:

protected void paintComponent(Graphics g){
      //for each line...
      g.drawString(text, b0, b1);
      //b0 and b1 are computed from the selected bounding box for the text
}

我有这个:

使用 iText 渲染文本:

PdfTemplate t; //PdfTemplate is created elsewhere
ColumnText ct = new ColumnText(t);
ct.setRunDirection(PdfWriter.RUN_DIRECTION_NO_BIDI);
ct.setSpaceCharRatio(1);
ct.setSimpleColumn(new Phrase(text, font), b0, b1, b3, b4, font.getSize(), Element.ALIGN_BOTTOM); 
//b0, b1, b2 and b3 are the bounding box of the text
ct.go();

我有这个:

所以问题是:怎样才能使 Swing 和 iText 以完全相同的方式呈现字体?我可以调整 Swing 或 iText,所以无论修改什么代码,我都需要为用户提供真正的 WYSIWYG 体验。

我尝试了其他字体和类型,但它们之间仍然存在一些差异。我想我缺少一些配置。

谢谢。

【问题讨论】:

  • 您使用哪种字体?您可以尝试在 PDF 中嵌入字体。您还可以检查字符对的字距调整并在任一侧对其进行自定义。
  • 我在两边都使用 Helvetica plain。 Helvetica 是核心字体之一,所以我认为我不必导入它。字距调整可能是问题之一。你知道如何在 Swing 中改变它吗?
  • 你在使用 itext 的字体映射器吗?你嵌入字体了吗?

标签: java swing pdf itext


【解决方案1】:

编辑:

Java 中的字体以像素为单位,而 iText 以点为单位,我们知道每英寸有 72 个点,而对于标准 Windows 机器,每英寸/dpi 为 96 个像素。

首先我们需要找到一个点和一个像素之间的区别:

difference = 72 / dpi
      0.75 = 72 / 96

接下来我们可以将Java字体大小与差值相乘得到iText字体大小,如果java字体大小为16,那么在使用96dpi时iText字体大小应该为12。

iTextFontSize = difference x javaFontSize
           12 = 0.75 x 16

在 Windows 机器上 96dpi 通常是标准,但请记住,并非总是如此,您应该针对每台不同的机器进行计算。


原帖

我相信差异是由渲染提示引起的。

解决方案 1:

最好的方法是在缓冲图像上绘制所有内容。然后将缓冲图像绘制到 swing 组件,并将完全相同的缓冲图像绘制到 PDF,这样它们之间应该没有区别。

另一种想法:

另一个可能效果不佳但在现有代码中效果更好的想法是将 swing 组件的内容直接绘制到缓冲图像,然后将缓冲图像绘制到 PDF。

以下是一个快速示例,它将使用一些不同的渲染提示将 JPanel 的内容绘制到缓冲图像。 (更改提示以适合您的挥杆组件)

public BufferedImage createImage(JPanel panel)
{
    BufferedImage swingComponent = new BufferedImage(
            panel.getHeight(), panel.getWidth(), 
            BufferedImage.TYPE_INT_RGB);

    Graphics2D g = swingComponent.createGraphics();

    g.setRenderingHint(RenderingHints.KEY_RENDERING,
                       RenderingHints.VALUE_RENDER_QUALITY);

    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                       RenderingHints.VALUE_ANTIALIAS_ON);

    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                       RenderingHints.VALUE_INTERPOLATION_BILINEAR);

    g.dispose();
    return swingComponent; //print this to your PDF
}

【讨论】:

  • 虽然这个解决方案可以工作,但最终的结果可能很差。渲染文本(不是图像),文本在渲染时与 PDF 的其余部分很好地缩放。如果我改用图像,当用户缩放文档时,图像可以变成pixelated(主要是文本)。为了缓解这个问题,我必须使用更大的图像(更多 dpi),这会增加 PDF 的大小。
  • 嘿,万一你错过了:我已经用一个更好的解决方案编辑了我的帖子。
  • 我不知道这是否是问题所在...将 iTextFontSize 减少任何值只会使差异比以前更大。
  • 您确定您正在正确调整 itext 字体大小而不是 Swing 大小吗?从您的图像中,它显示 itext 字体更大,因此通过减小 itext 字体大小,正如我建议的那样,文本应该与 swing 大小相同,如果不是这种情况,那么您的程序中肯定有其他问题。
  • 是的,我正在调整字体大小。我面临的问题是字符间距和粗体。我不知道可以做些什么来解决这个问题,所以目前我正在使用“不完美但足够好”的方法。
【解决方案2】:

所以问题是:怎样才能让 Swing 和 iText 以完全相同的方式渲染字体?

一模一样?很少。假设您为两者提供相同的字体特征,渲染中可能仍然存在差异。

PDF 文件(或者实际上是文本短语)包含字体信息(系列、大小、样式等),但将文本呈现到您的设备的是您的 PDF 阅读器。根据您使用的程序,它可以使用平台的渲染器,也可以选择自己的一个。

AFAIK,Java Swing 使用自己的字体渲染引擎,与底层平台的渲染器不同。这使得它在各个平台上看起来更加一致,但也使得文本不太可能以与任何其他程序相同的方式呈现。

知道,您的选择是有限的:

  • 使用也使用 Swing 字体呈现的 PDF 阅读器。这是一个相当有限的解决方案。

  • 使用您平台的渲染引擎绘制到 Swing。这听起来像是一个不确定的工作,也像是 SWT 可以解决的问题。也许你可以嵌入一个 SWT 组件?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    • 2016-11-22
    • 2011-06-30
    • 1970-01-01
    • 2018-02-15
    相关资源
    最近更新 更多