更改 PDF 文件中轮廓(书签)的缩放级别

Change zoom level in outlines (bookmarks) in PDF files

我想使用 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 已保存,但缩放级别没有变化。

更新 我想出了一个不同的解决方案(灵感来自 ):

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);
    }
}

是这样的吗?

    PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(DEST));                                                   
    pdfDoc.getCatalog().setOpenAction(PdfExplicitDestination.createXYZ(pdfDoc.getPage(1), 0,                                                       pdfDoc.getPage(1).getPageSize().getHeight(), 0.75f)); 
    pdfDoc.close();

https://itextpdf.com/en/resources/faq/technical-support/itext-7/how-can-i-set-zoom-level-pdf-using-itext-7

您的原始代码

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坐标(你为什么也改变它?)被改变了!

但其他大纲未更改,原因有二:

  • 您的原始代码仅迭代顶层大纲(直接目录大纲children),因此根本只能更改顶层大纲条目。

  • 您的原始代码假设大纲有一个 GoTo Action (A) 包装一个明确的 XYZ 目标D 映射到 5 元素数组)。

    如果您的文档仅适用于扉页,所有其他大纲立即包含一个 non-explicit,名为 DestinationDest 映射到名称)。

您的替代代码

您的替代代码确实解决了问题,特别是

  • 它还递归地访问顶层大纲的所有祖先,因此所有大纲条目都可以更改;和
  • 它使用 iText 类 来识别和评估各种目的地,无论它们是否包含在动作中,无论它们是明确的还是命名的,...

在 Adob​​e Reader 中,结果似乎符合预期,但仔细研究后发现存在问题:

  • 扉页大纲(这是您唯一一个带有 Action 条目的大纲)现在有 both 旧的 Action 条目和一个新的 Destination 条目。严格来说这是规范所禁止的;因此,您应该删除现有的 Action 条目。
  • 创建的 destination 数组包含作为整数页码的目标页面(第一个数组条目)。这仅适用于 Remote GoTo Actions 中的目的地。由于您的新目的地显然是 non-Remote 和 non-Actions,这只是因为 Adob​​e Reader 非常宽松。您应该使用页码 object 而不是页码,并且您不应该使用 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作为目标视图左上角的坐标。这假定坐标系的原点是页面的左下角您应该使用 box.getLeft(), box.getTop() 而不是 box 作为相关页面的裁剪框。

不过,对于您的示例文档,媒体框和裁剪框重合,原点确实是左下角。因此,对于该文档,您不需要该改进。