将 PDF 中的外部 link 转换为 link 以嵌入 iTextSharp 中的附件

Convert external links in PDF to link to embedded attachment in iTextSharp

我有一个奇怪的任务。我们即将关闭一个相当大的内部解决方案,并希望对其保存的数据进行一次性导出。

该解决方案生成 PDF 格式的报告。这些 PDF 主要包含文本,但也包含图像。图片是 links,激活后会打开浏览器并指向图片的全尺寸版本。

由于我们即将关闭底层系统,因此全尺寸图像的外部 link 也将停止工作。

出于各种奇怪的原因,我们对报告生成本身的控制有限,因此我们主要限于对报告进行 post 处理。

到目前为止我制定的计划是从系统生成所有必要的报告并通过 iTextSharp 处理它们。 "All" 我正在努力实现的是处理每一个 PDF 并且:

  1. 搜索外部 links
  2. 下载 links 指向的全尺寸图像并将其作为嵌入文件附加到 PDF
  3. 删除原来的外部link并用link替换为相关的嵌入资源

我不熟悉 PDF 的底层结构,因此在尝试使用 iTextSharp 时遇到了很多困难。但是,到目前为止,我已经设法解决了 (1) 和 (2)。但我正在努力解决 (3):

我主要使用 this 作为我的支持文件,但我还没有完全达到我的目标。

这是我处理每个注释的代码。请注意,我正在使用 iTextSharp 5.5.13 版:

if (AnnotationDictionary.Get(PdfName.A) != null)
{
    var annotActionObject = AnnotationDictionary.Get(PdfName.A);
    var AnnotationAction = (PdfDictionary)(annotActionObject.IsIndirect() ? PdfReader.GetPdfObject(annotActionObject) : annotActionObject);

    var type = AnnotationAction.Get(PdfName.S);
    //Test if it is a URI action
    if (type.Equals(PdfName.URI))
    {
        //Attach the downloaded file
        PdfFileSpecification pfs = PdfFileSpecification.FileEmbedded(writer, embFile.Path, embFile.Description, null);
        pfs.AddDescription(embFile.Description, false);
        writer.AddFileAttachment(pfs);

        //Removing old annotation
        AnnotationAction.Remove(PdfName.A);
        AnnotationDictionary.Remove(PdfName.A);

        PdfDestination destination = new PdfDestination(PdfDestination.FIT);
        destination.AddFirst(new PdfNumber(1));

        var target = new PdfTargetDictionary(true);
        target.EmbeddedFileName = embFile.Name;

        PdfAction action = PdfAction.GotoEmbedded(null, target, destination, true);

        AnnotationDictionary.Put(PdfName.D, action.Get(PdfName.D));
        AnnotationAction.Put(PdfName.D, action.Get(PdfName.D));
    }
}

这对某些人来说很明显,为什么它不起作用:)

现在,一切正常,并且在另一端输出了一个 PDF。如前所述,PDF 中的图像不再具有活动的 link,并且所有附件都按预期嵌入。但是,嵌入资源的 link 不起作用,并且在任何地方都没有指示。

非常感谢所有反馈。谢谢。

如评论中所述,您只能 link 嵌入 PDF 文件。

您只是在更改 D 条目。您需要覆盖整个 A 条目,但请确保保留目标的位置。

这是我创建的快速 POC:

PdfReader reader = new PdfReader(INPUT_FILE);
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(OUTPUT_FILE));

    PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(stamper.getWriter(), null, "EmbeddedFile.pdf", FileUtils.readFileToByteArray(new File(INPUT_FOLDER + "embeddedfile.pdf")));
    fs.addDescription("specificname", false);
    stamper.getWriter().addFileAttachment(fs);
    PdfTargetDictionary targetDictionary = new PdfTargetDictionary(true);
    targetDictionary.setEmbeddedFileName("specificname");


    PdfDestination dest = new PdfDestination(PdfDestination.FIT);
    dest.addFirst(new PdfNumber(1));
    PdfAction action = PdfAction.gotoEmbedded(null, targetDictionary, dest, true);

    PdfDictionary page = reader.getPageN(1);
    PdfArray annotations = page.getAsArray(PdfName.ANNOTS);


    for(int x=0;x<annotations.size();x++) {
        PdfDictionary annotation = annotations.getAsDict(x);
        PdfArray location = annotation.getAsArray(PdfName.RECT);
        action.put(PdfName.RECT,location);
        annotation.put(PdfName.A, action);
    }


    stamper.close();

INPUT_FILE 指向原始文件,OUTPUT_FILE 指向您想要保存它的位置,INPUT_FOLDER + "embeddedFile.pdf" 指向您想要注释的 PDF 文件 link到.

所以 action 是指向嵌入的 PDF 文件的新操作( PDF 文件)。我们只是将旧注释的 A 条目替换为 action。然后我们确保将 action 的位置设置为旧注释的位置。