We have a ton of pdf documents that each have links that open other pdf documents. When clicking on the links it will open up the other pdf document in the same file system. The problem is that we need to change the name of some of the directories which will require the changing of all the links that point to pdf documents in that directory. We would do this manually but there are literally thousands of links that need to be alter.
We have tried to use iTextSharp and PdfSharp to alter the links but are having a difficult time getting to the right object. Below shows the contents of a sample pdf file with two links. You can see that object 12 is a link that references object 21 and object 21 opens a new window using the reference in object 20. Object 20, of type Filespec contains the path to the linked pdf, Folder-Name/A.pdf. The second link follows the same pattern but uses objects 16, 23, and 22.
12 0 obj<</Type/Annot/P 5 0 R/F 4/C[1 0 0]/Subtype/Link/A 21 0 R/M(D:20130710103035-07'00')/Border[0 0 0]/Rect[144 612 216 630]/NM(QVDTKWKAZGVAAGHJ)/BS 13 0 R>>
endobj
13 0 obj<</W 0/S/S/Type/Border>>
endobj
16 0 obj<</Type/Annot/P 5 0 R/F 4/C[1 0 0]/Subtype/Link/A 23 0 R/M(D:20130710103040-07'00')/Border[0 0 0]/Rect[126 594 216 612]/NM(WFAYQFGTTIESQOKW)/BS 17 0 R>>
endobj
17 0 obj<</W 0/S/S/Type/Border>>
endobj
20 0 obj<</Type/Filespec/F(Folder-Name/A.pdf)/UF(Folder-Name/A.pdf)/Desc()>>
endobj
21 0 obj<</S/GoToR/D[0/Fit]/NewWindow true/F 20 0 R>>
endobj
22 0 obj<</Type/Filespec/F(Folder-Name-2/B.pdf)/UF(Folder-Name-2/B.pdf)/Desc()>>
endobj
23 0 obj<</S/GoToR/D[0/Fit]/NewWindow true/F 22 0 R>>
endobj
How can we use iTextSharp or PdfSharp to change "Folder-Name" and "Folder-Name-2" to some other arbitrary folder path?
In case anyone cares, I was able to use the code linked by Chris Haas in the first comment above but modified it as follows:
foreach (FileInfo file in files)
{
PdfReader reader = default(PdfReader);
bool linkReplaced = false;
//Setup some variables to be used later
reader = new PdfReader(file.FullName);
int pageCount = reader.NumberOfPages;
PdfDictionary pageDictionary = default(PdfDictionary);
PdfArray annots = default(PdfArray);
//Loop through each page
for (int i = 1; i <= pageCount; i++)
{
//Get the current page
pageDictionary = reader.GetPageN(i);
//Get all of the annotations for the current page
annots = pageDictionary.GetAsArray(PdfName.ANNOTS);
//Make sure we have something
if ((annots == null) || (annots.Length == 0))
continue;
foreach (PdfObject A in annots.ArrayList)
{
//Convert the itext-specific object as a generic PDF object
PdfDictionary AnnotationDictionary = (PdfDictionary)PdfReader.GetPdfObject(A);
//Make sure this annotation has a link
if (!AnnotationDictionary.Get(PdfName.SUBTYPE).Equals(PdfName.LINK))
continue;
//Make sure this annotation has an ACTION
if (AnnotationDictionary.Get(PdfName.A) == null)
continue;
string fValue = string.Empty;
string ufValue = string.Empty;
string uriValue = string.Empty;
PdfObject a = AnnotationDictionary.Get(PdfName.A);
if (a.IsDictionary())
{
//Get the ACTION for the current annotation
PdfDictionary AnnotationAction = (PdfDictionary)a;
//Test if it is a URI action
if (AnnotationAction.Get(PdfName.S).Equals(PdfName.URI))
{
uriValue = AnnotationAction.Get(PdfName.URI).ToString();
if ((uriValue.IndexOf(findValue, StringComparison.OrdinalIgnoreCase) > -1))
{
string uriValueReplace = Replace(uriValue, findValue, replaceValue, StringComparison.OrdinalIgnoreCase);
//Change the URI to something else
AnnotationAction.Put(PdfName.URI, new PdfString(uriValueReplace));
linkReplaced = true;
}
}
}
else if (a.IsIndirect())
{
// Get the indirect reference
PdfIndirectReference indirectRef = (PdfIndirectReference)a;
// Get the GoToR type object which is at the document level
PdfDictionary goToR = (PdfDictionary)reader.GetPdfObject(indirectRef.Number);
// Get the FileSpec object whic his at the document lelvel
PdfObject f = goToR.Get(PdfName.F);
if (f == null || !f.IsIndirect())
continue;
PdfObject fileSpecObject = reader.GetPdfObject(((PdfIndirectReference)goToR.Get(PdfName.F)).Number);
if (!fileSpecObject.IsDictionary())
continue;
PdfDictionary fileSpec = (PdfDictionary)fileSpecObject;
fValue = fileSpec.Get(PdfName.F).ToString();
ufValue = fileSpec.Get(PdfName.UF).ToString();
if ((fValue.IndexOf(findValue, StringComparison.OrdinalIgnoreCase) > -1) || (ufValue.IndexOf(findValue, StringComparison.OrdinalIgnoreCase) > -1))
{
string fValueReplace = Replace(fValue, findValue, replaceValue, StringComparison.OrdinalIgnoreCase);// fValue.Replace(findValue, replaceValue);
string ufValueReplace = Replace(fValue, findValue, replaceValue, StringComparison.OrdinalIgnoreCase);// ufValue.Replace(findValue, replaceValue);
// Update the references to the file
fileSpec.Put(PdfName.F, new PdfString(fValueReplace));
fileSpec.Put(PdfName.UF, new PdfString(ufValueReplace));
linkReplaced = true;
}
}
}
}
}