我想使用 iText7
更改轮廓的缩放级别。请注意,与 iText 5 中完成的方式相比,这可能已经发生了变化。 .
通过反复试验,我想出了代码:
List<PdfOutline> outlines = pdfDoc.getOutlines(true).getAllChildren();
for (int i = 0; i < outlines.size(); i++) {
PdfOutline outline = outlines.get(i);
PdfDictionary content = outline.getContent();
PdfDictionary pdfDictionary = (PdfDictionary) content.get(PdfName.A);
if (pdfDictionary != null) {
PdfArray arr = (PdfArray) pdfDictionary.get(PdfName.D);
if (arr.size() == 5) { // for XYZ zoom type
PdfName xyz = (PdfName) arr.get(1);
arr.set(3, new PdfNumber(2_000));
arr.set(4, new PdfNumber(2_000));
}
}
编辑
问题是上面的代码似乎不起作用,因为生成的 pdf 已保存,但缩放级别没有变化。
更新 我想出了一个不同的解决方案(受到 different question at SO 的启发):
PdfNameTree destsTree = document.getCatalog().getNameTree(PdfName.Dests);
PdfOutline outline = document.getOutlines(false);
if (outline != null) {
walkOutlines(outline, destsTree.getNames(), document);
}
private static void walkOutlines(PdfOutline outline, Map<String, PdfObject> names,
PdfDocument document) {
if (outline.getDestination() != null) {
int pageNumber = document.getPageNumber(
(PdfDictionary) outline.getDestination().getDestinationPage(names));
float height = document.getPage(pageNumber).getPageSize().getHeight();
outline.setOpen(false);
outline.addDestination(PdfExplicitRemoteGoToDestination.createXYZ(
pageNumber, 0F, height, ZOOM_LEVEL));
}
for (PdfOutline child : outline.getAllChildren()) {
walkOutlines(child, names, document);
}
}
最佳答案
您的原始代码
The problem is that the above code doesn't seem to work as the resulting pdf is saved but there are no changes in zoom level.
尝试您的原始代码,我无法确认这一点,标题页轮廓的缩放级别和 y 坐标(为什么您也更改它?)已更改!
不过,其他轮廓没有改变,原因有两个:
您的原始代码仅迭代顶级大纲(直接目录大纲子项),因此只能更改顶级大纲条目。
您的原始代码假设轮廓有一个GoTo Action (A),包装了一个明确的XYZ Destination ( D 映射到 5 元素数组)。
如果您的文档仅适用于标题页,则所有其他大纲立即包含一个非明确的、名为Destination(Dest 映射到名称)的情况.
您的备用代码
您的替代代码确实解决了问题,特别是
- 它还会递归地访问顶级大纲的所有祖先,因此所有大纲条目都可以更改;和
- 它使用 iText 类来识别和评估各种目的地,无论它们是否包含在操作中,无论它们是显式的还是命名的,...
在 Adobe Reader 中,结果似乎可以按预期工作,但仔细研究就会发现存在问题:
- 标题页大纲(这是唯一一个带有操作条目的大纲)现在两者都有旧的操作条目,并且新的目的地条目。严格来说这是规范所禁止的;因此,您应该删除现有的操作条目。
- 创建的目标数组包含目标页面(第一个数组条目)作为整数页码。这仅适用于远程转到操作中的目的地。由于您的新目的地显然是非远程且非操作的,因此这只有效,因为 Adobe Reader 非常宽松。您应该使用页面对象而不是页码,并且不应该使用
PdfExplicitRemoteGoToDestination
开始。
改进您的备用代码
要解决上述问题,请更改
outline.addDestination(PdfExplicitRemoteGoToDestination.createXYZ(
pageNumber, 0F, height, ZOOM_LEVEL));
至
outline.getContent().remove(PdfName.A);
outline.addDestination(PdfExplicitDestination.createXYZ(
document.GetPage(pageNumber), 0F, height, ZOOM_LEVEL));
严格来说,您的代码还可以进一步改进。
- 您可以使用
PageSize
,但对于可见页面区域,您应该使用CropBox
。 - 并且您使用
0F, height
作为目标 View 左上角的坐标。这假设坐标系的原点是页面的左下角。您应该使用 box.getLeft()、box.getTop() 代替box
作为相关页面的裁剪框。
但是,在您的示例文档中,媒体框和裁剪框重合,并且原点确实是左下角。因此,对于该文档,您不需要进行改进。
关于java - 更改 PDF 文件中轮廓(书签)的缩放级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58699707/