Swing和iText字体渲染之间的差异

时间:2012-08-28 18:40:47

标签: java swing pdf itext

我正在构建一个应用程序,除其他外,它允许用户使用图层将文本插入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
}

我有这个:

Swing rendering

使用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();

我有这个:

PDF rendering

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

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

感谢。

2 个答案:

答案 0 :(得分:2)

编辑:

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
}

答案 1 :(得分:0)

  

所以问题是:如何使Swing和iText以完全相同的方式呈现字体?

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

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

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

知道这一点,您的选择有限:

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

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