Reputation: 290
I have a bit of an odd task. We're about to close down a rather large internal solution and want to do a one-off export of the data it holds.
The solution generates reports in PDF format. These PDFs mostly contain text but also contains images. The images are links which, when activated, opens a browser and points to a full-size version of the image.
Since we're about to close the underlying system, the external links to the full-size images will also stop working.
For a variety of odd reasons, we have a limited control of the report generation itself and so we are mostly limited to doing post-processing of the reports.
The plan I've devised so far is to generate all the necessary reports from the system and process them through iTextSharp. "All" I'm trying to achieve is to process each and every PDF and:
I'm not familiar with the underlying structure of PDFs so I'm hitting quite a few walls when trying to work with iTextSharp. However, so far I've managed to (1) and (2) sorted out. But I'm struggling with (3):
I'm mainly using this as my supporting document, but I'm not quite reaching my goal.
This is my code where I'm processing each of the annotations. As a note, I'm making use of iTextSharp version 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));
}
}
It's most likely rather obvious to some, why its not working :)
Right now, everything runs just fine and it spits out a PDF in the other end. As mentioned, the images in the PDF no longer has an active link and all the attached files are embedded as expected. However, the link to embedded resource doesn't work and there's no indication of it anywhere.
All feedback is much appreciated. Thank you.
Upvotes: 5
Views: 1634
Reputation: 1006
As noted in the comments you can only link to an embedded PDF file.
You are only changing the the D
entry. You need to override the entire A
entry, but make sure to keep the target's location.
Here is a quick POC I created:
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
points to the original file, OUTPUT_FILE
points to where you want it to be saved, and INPUT_FOLDER + "embeddedFile.pdf"
points to the PDF file you want your annotation to link to.
So action
is your new action that points to the embedded PDF file (and only a PDF file). We just replace the old annotation's A
entry with action
. Then we make sure to set action
's location to the location of the old annotation.
Upvotes: 1