转换PDF中的外部链接以链接到iTextSharp中的嵌入式附件

时间:2018-10-16 18:58:41

标签: c# itext pdf-generation

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

该解决方案生成PDF格式的报告。这些PDF主要包含文本,但也包含图像。这些图像是链接,激活这些链接后,它们会打开浏览器并指向该图像的完整版本。

由于我们将要关闭基础系统,因此到全尺寸图像的外部链接也将停止工作。

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

到目前为止,我制定的计划是从系统生成所有必要的报告,并通过iTextSharp处理它们。我要实现的“全部”是处理每个PDF和:

  1. 搜索外部链接
  2. 下载链接指向的原图,并将其作为嵌入式文件附加到PDF
  3. 删除原始外部链接,并将其替换为指向相关嵌入式资源的链接

我不熟悉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中的图像不再具有活动链接,并且所有附件均按预期嵌入。但是,到嵌入式资源的链接不起作用,并且在任何地方都没有指示。

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

1 个答案:

答案 0 :(得分:1)

如评论中所述,您只能链接到嵌入式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文件。

action是您的新操作,它指向嵌入式PDF文件(并且仅 一个PDF文件)。我们只用A替换了旧注释的action条目。然后,确保将action的位置设置为旧注释的位置。