【发布时间】:2013-12-10 12:51:25
【问题描述】:
我正在使用 Flying Saucer 进行 HTML 到 PDF 的转换。我需要以 Letter 大小生成 600dpi 的输出 PDF。我怎样才能做到这一点?
【问题讨论】:
标签: pdf-generation dpi flying-saucer
我正在使用 Flying Saucer 进行 HTML 到 PDF 的转换。我需要以 Letter 大小生成 600dpi 的输出 PDF。我怎样才能做到这一点?
【问题讨论】:
标签: pdf-generation dpi flying-saucer
有四个不同的因素在起作用,它们都是相互关联的:
您希望页面度量正确,这样当您要求 Flying Saucer 生成“字母”大小的页面时,生成的 PDF 将在 Acrobat 中显示为 8.5" x 11"。您可以通过在 CSS 中指定 page-size 属性直接在 FS 中配置页面大小,正如另一个答案中所指出的那样:@page { size: letter; }
您希望最终输出适合在某些打印机上以特定 XXX dpi 打印。这一切都很好,但请记住,PDF(主要)是一种矢量格式。我没有检查规范,但据我所知,PDF 文件/页面没有“具有”分辨率,因为它们是基于矢量的。话虽如此,放置在页面内的东西都有一个有效的分辨率,所以我们需要你想要的 XXX dpi 数字来计算下面的数字。
在 FlyingSaucer(和 Java)世界中,一个点始终是 1/72 英寸的常数。时期。因此,我们可以通过采用所需的分辨率并除以点的大小来计算每点的点数。例如,如果您想要 300 dpi 输出:
这不是一个幻数,该值与每点的点数以及您尝试输入 FlyingSaucer 的图形图像的预期分辨率直接相关。更具体地说,给定一个尺寸为 X x Y 像素的图形图像,您需要确定要在 PDF 中呈现多大的图像。如果您使用的是为屏幕(网络)使用而准备的图像,您可能从标准的 96 像素/英寸开始(因此 96 x 96 像素的图像将在 PDF 输出中呈现为一英寸正方形)。
所以我们可以很容易地计算每像素点数如下,再次假设我们想要 300 dpi 输出:
如果您采用这种方法,您的图像尺寸会正确,但它们不会是您正在寻找的 300 dpi 打印质量。那是因为您的图像的分辨率不够高。稍后会详细介绍。
如果您只是按照其他答案之一的建议直接致电SharedContext#setDPI,您可能会得到错误的结果。这是因为在不改变分辨率(每英寸点数)的情况下改变每点点数是不合逻辑的。 ITextRenderer 构造函数对setDPI(72*dotsPerPoint) 进行固定调用,当它创建新页面时,它还使用构造函数设置的dotsPerPoint 值来计算正确的页面宽度(以磅为单位)。如果您通过调用setDPI 更改了它的分辨率,您最终会得到错误的页面大小。
正确的方法是使用我们上面计算的值创建一个新的 ITextRenderer 对象。如果我们想要 300 dpi 的输出并且我们有 96 ppi 的图像来提供它,我们会调用:
ITextRenderer renderer = new ITextRenderer(4.1666f, 3);
请注意,dots-per-pixel 参数只接受整数,因此我们将 3.125 舍入为上面最接近的整数。然而......这确实是两个数字之间的比率似乎很重要,所以为了使最后一个参数成为整数,我们可以将两个数字乘以 8(产生整数的最小整数乘数),得到 33.3333 并且正好25. 这也是我对飞碟资料中神奇数字“20”的由来的猜测。
此时,您的输出 PDF 应该看起来与您开始时几乎相同(假设您之前使用的是飞碟的默认 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 中图像的分辨率,同时让文本保持相同的大小和位置。
答案是将样式表中的所有内容都转换为使用点。 (或英寸。至少不是像素!)如果您开始使用默认的飞碟设置(意味着像素为 96 ppi),您只需将所有“px”测量值转换为点。由于 72 点 = 1 英寸,您可以将“px”更改为“pt”并将该值乘以 72/96。
例如,上面的font-size: 10px; 将变为font-size: 7.5pt;。如果您希望与以前的内容真正保持一致,则 CSS 中提及“px”(以及任何内联样式)的所有内容也必须通过相同的转换更改为“pt”。
一旦你做了这个改变,你的文本和其他布局将保持一致,如果你决定以后需要 600 dpi 输出,你可以调整你的图像并更改构造函数参数,但布局的其余部分会仍然保持不变。完成!
【讨论】:
margin-top: 0.5pt; height: 0.5pt; 这样的 CSS 规则。
您可以在 HTML 文档中使用 CSS page size 属性设置字母大小:
@page {
size: letter;
}
您可以使用以下 ITextRenderer 构造函数更改文档的 dpi:
public ITextRenderer(float dotsPerPoint, int dotsPerPixel)
我不明白这些值真正代表什么,但默认值是dotsPerPoint = 20f * 4f / 3f 和dotsPerPixel = 20,它会输出一个96dpi 的文档。
要获得 600dpi,您可以使用 dotsPerPoint = 500f / 3f 和 dotsPerPixel = 20。
查看ITextRenderer的代码,最终dpi由公式给出:dpi = dotsPerPoint * 72 / dotsPerPixel。
【讨论】:
使用飞碟时设置 DPI 的更简单答案:
renderer.getSharedContext().setDPI(600);
与 obourgain 的回答一样,与 @page { size:letter; } CSS 结合使用。
【讨论】:
@page { width:5in; height:4in }