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

标签 java itext itext7

我想使用 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 类来识别和评估各种目的地,无论它们是否包含在操作中,无论它们是显式的还是命名的,...

在 Adob​​e Reader 中,结果似乎可以按预期工作,但仔细研究就会发现存在问题:

  • 标题页大纲(这是唯一一个带有操作条目的大纲)现在两者都有旧的操作条目,并且新的目的地条目。严格来说这是规范所禁止的;因此,您应该删除现有的操作条目。
  • 创建的目标数组包含目标页面(第一个数组条目)作为整数页码。这仅适用于远程转到操作中的目的地。由于您的新目的地显然是非远程且非操作的,因此这只有效,因为 Adob​​e 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/

相关文章:

java - 在 GRAL 中绘制多个图形

java - 如何使用 iText 保存 .pdf 文件?

cryptography - iText 加密数字签名的 PDF

java - iText 或 iTextSharp : when i use the ‘PdfStamper’ , target file use adobe.reader Verify signature failure

java - 使用 iText pdfHTML 的 PDF 页面大小和格式

java - iText 7 : Set image to button that appears multiple times

Java (Windows) - 通过进程id,获取内存使用、磁盘使用、网络使用

java - Veracode XML 外部实体引用 (XXE) 解码 org.w3c.dom.Element

java - 记录数量过多时 PDF 生成失败

java - 为 Java 代理使用 Byte Buddy