Flying Saucer:为输出PDF设置自定义DPI



我正在使用Flying Saucer进行HTML到PDF的转换。我需要生成一个600dpi的Letter大小的输出PDF。我怎样才能做到这一点?

有四个不同的因素在起作用,它们都是相互关联的:

目标页面度量

您希望页面度量是正确的,这样当您要求Flying Saucer生成一个"字母"大小的页面时,生成的PDF将在Acrobat中显示为8.5"x 11"。通过在CSS中指定页面大小属性,您可以直接在FS中配置页面大小,正如oburgain在另一个答案中所指出的:@page { size: letter; }

分辨率

您希望最终输出适合在某些打印机上以特定的XXX dpi打印。这一切都很好,但请记住,PDF(主要)是一种矢量格式。我没有检查规格,但据我所知,PDF文件/页面没有"分辨率",因为它们是基于矢量的。话虽如此,放置在页面内的内容具有有效的分辨率,因此我们需要您想要的XXX dpi数字来计算下面的数字。

每点点数

在FlyingSaucer(和Java)世界中,一个点总是一个1/72英寸的常数。时期因此,我们可以通过取所需的分辨率并除以一个点的大小来计算每个点的点数。例如,如果想要300 dpi输出

  • 每点点数=300 dpi/72 ppi=300点/英寸/72点/英寸=300/72点/点=4.1666点/点

每像素点数

这不是一个神奇的数字,这个值与每个点数的点数以及您试图输入FlyingSaucer的图形图像的预期分辨率直接相关。更具体地说,给定一个尺寸为X X Y像素的图形图像,您需要决定在PDF中渲染的大小。如果你使用的是为屏幕(网络)使用准备的图像,你可能是从标准的96像素/英寸开始的(所以96 x 96像素的图像在PDF输出上会呈现为一英寸的正方形)。

因此,我们可以很容易地计算每个像素的点数,如下所示,再次假设我们想要300 dpi的输出:

  • 每像素点数=每英寸点数(点)/每英寸像素(像素)
  • 每像素点数=300点/英寸/96像素/英寸=3.125点/像素

如果采用这种方法,您的图像大小将正确,但它们不会达到您想要的300 dpi打印质量。那是因为你的图像一开始分辨率不够高。稍后会有更多内容。

设置好一切

如果按照其他答案中的建议直接调用SharedContext#setDPI,则可能会得到错误的结果。这是因为在不改变分辨率(每英寸点数)的情况下改变每点点数是没有逻辑意义的。ITextRenderer构造函数对setDPI(72*dotsPerPoint)进行固定调用,当它去创建新页面时,它还使用构造函数设置的dotsPerPoint值来计算以点为单位的正确页面宽度。如果您通过调用setDPI更改了它的分辨率,那么您最终会得到错误的页面大小。

正确的方法是使用上面计算的值创建一个新的ITextRenderer对象。如果我们想要300 dpi的输出,并且我们有96 ppi的图像来提供,我们会称之为:

ITextRenderer renderer = new ITextRenderer(4.1666f, 3);

请注意,每像素点数参数只接受整数,因此我们将3.125四舍五入到上面最接近的整数。然而实际上,这两个数字之间的比率似乎很重要,所以为了使最后一个参数成为整数,我们可以将两个数字乘以8(产生整数的最低整数乘法器),得到33.3333,正好是25。这也是我对飞梭中神奇的"20"数字来源的猜测。

检查您的输出

到目前为止,您的输出PDF应该与刚开始时几乎相同(假设您以前使用的是Flying Saucer的默认96 ppi配置)。但现在我们知道了需要调整的参数,以使一切正常工作。

要获得高质量的输出,您需要高质量的输入

因此,我们已经验证了上述参数适用于我们的目的,但我们的图像仍然是低96 ppi。如果我们想以高分辨率打印这些东西,你所需要做的就是将图像换成300 ppi版本,更改构造函数参数,然后就完成了,对吧?

也许吧。让我们研究一下数字:

您期望的输出分辨率(300 dpi)不会改变,因此每点的点数仍然是4.1666。但是您的输入图像现在是300 ppi,所以您的每像素点数=300点/英寸/300像素/英寸=1点/像素。因此,您现在将这样调用构造函数:

ITextRenderer renderer = new ITextRenderer(4.1666f, 1);

一旦你这样做,你的新的300像素x 300像素的图像将在PDF上变成1"正方形,这正是你想要的打印质量。

但是等一下!我所有的文字都变小了

Flying Saucer使用每像素点数的测量来转换许多东西,而不仅仅是图像。特别是,如果您在样式表中指定了任何使用像素的内容,则每像素点数的测量也会对其大小产生影响。

如果您有像font-size: 10px;这样的样式表规则,那么增加提供给构造函数的每像素点数会使文本变小,这可能也不是您想要的。毕竟,你应该能够提高PDF中图像的分辨率,同时保持文本的大小和位置不变。

答案是将样式表中的所有内容转换为使用点。(或者英寸。至少是像素以外的东西!)如果你一开始使用默认的Flying Saucer设置(意味着像素是96 ppi),你只需要将所有的"像素"测量值转换为点。由于72点=1英寸,您可以将"px"更改为"pt",并将该值乘以72/96。

例如,上面的font-size: 10px;将变为font-size: 7.5pt;。若你们想和以前的样式保持一致,那个么CSS中所有提到"px"(以及任何内联样式)的内容都必须用相同的转换转换为"pt"。

一旦您进行了此更改,您的文本和其他布局将保持一致,如果您决定以后需要600 dpi的输出,您可以调整图像并更改构造函数参数,但布局的其余部分仍将保持不变。完成!

您可以在HTML文档中使用CSS页面大小属性设置字母大小:

@page {
size: letter;
}

您可以使用以下ITextRenderer构造函数更改文档的dpi:

public ITextRenderer(float dotsPerPoint, int dotsPerPixel)

我不知道这些值到底代表什么,但默认值是dotsPerPoint = 20f * 4f / 3fdotsPerPixel = 20,它将输出96dpi的文档。

要获得600dpi,可以使用dotsPerPoint = 500f / 3fdotsPerPixel = 20

查看ITextRenderer的代码,最终dpi由公式dpi = dotsPerPoint * 72 / dotsPerPixel给出。

使用飞碟时设置DPI的更简单答案:

renderer.getSharedContext().setDPI(600);

与oburgain的答案一样,将与@page { size:letter; }CSS结合使用。

最新更新