Hi all,
Someone was asking how to add a bookmark/outline/toc to a PDF file, so I thought I'd give our what I did.
For my app, most of my reports are 2 or more individual reports (up to 8) that are returned to the user as a single PDF file. This way I can show them multiple views of the same data (financial totals with different groupings and sortings) in a single report. The problem I was having is that I needed a way to show the user how many reports were in their PDF file, and a simple way to navigate between the reports in the PDF. This is what I came up with.
First off, I wrote this a long time ago, and I believe (if I remember correctly) that I got most (if not all) of the code to do this from the iText documentation.
For me, it's a four step process.
1 - Use JFR to create the PDF file.
2 - Call my static method to add a bookmark/title/toc to the pdf report
3 - Repeate 1 & 2 till done
4 - Concatenate all the PDF files into a single PDF.
What's here is step #2 - a static method that is called after each individual report is generated and adds the bookmark. It takes the PDF file that JFR created, and a string name that you want to use as the bookmark. It then creates a new PDF file with the contents of the old PDF file but it has a bookmark/TOC/outline entry (using the passed name) pointing to the first page of the PDF.
There will be one spot where you need to make a code adjustment - the first line under the "try" statement where it creates a new File object. I've got a couple of my own static method calls that give the new PDF file a random name in a temporary (in the context of my app) directory. Once you fix that that, it should work fine.
This method also returns a pointer to the new (bookmarked) PDF, but it does nothing to the old (unbookmarked) PDF. I've got a thread process that deletes any old files in my app's temp directory, so I don't need to worry about deleting the original PDF file. Just so you know.
The final step that I do is I take the 2+ PDF's that are returned (now with bookmarks!) and concatenate them into one big PDF. The concatenation process maintains the bookmark order, and correctly points each bookmark to the right page. I then return the uber-PDF back the user and it's all good.
If you need/want the contcatenation code, let me know.
Good luck -
Jeff
Code:// probably too many imports for just the bookmark part of the code import com.lowagie.text.Document; import com.lowagie.text.pdf.PdfCopy; import com.lowagie.text.pdf.PdfImportedPage; import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.SimpleBookmark; import com.lowagie.text.pdf.PdfDestination; import com.lowagie.text.pdf.PdfOutline; import com.lowagie.text.pdf.PdfAction; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** add a outline to the pdf, and mark the first page w/a bookmark link */ static public File createTitleBookmark(File p_pdf, String p_title) { try { // create output file File m_newfile = new File(Finder.getTempPath(), Crypto.hash(Crypto.getRandomString(20))); String m_resultfile = m_newfile.getCanonicalPath(); Document document = null; PdfCopy writer = null; int pageOffset = 0; // we create a reader for a certain document PdfReader reader = new PdfReader(p_pdf.getCanonicalPath()); reader.consolidateNamedDestinations(); int n = reader.getNumberOfPages(); // step 1: creation of a document-object document = new Document(reader.getPageSizeWithRotation(1)); // step 2: we create a writer that listens to the document writer = new PdfCopy(document, new FileOutputStream(m_resultfile)); writer.setViewerPreferences(writer.PageModeUseOutlines); // step 3: we open the document document.open(); // step 4: we add content. loop for each page PdfImportedPage page; for (int i = 0; i < n; ) { ++i; page = writer.getImportedPage(reader, i); writer.addPage(page); System.out.println("Processed page " + i); } // add the bookmark action PdfDestination d5 = new PdfDestination(PdfDestination.FIT); PdfAction m_action = PdfAction.gotoLocalPage(1, d5, writer); PdfOutline out1 = new PdfOutline(writer.getDirectContent().getRootOutline(), m_action, p_title); // step 5: we close the document document.close(); return new File(m_resultfile); } catch (Exception e) { System.out.println(e.getMessage()); } return null; }


Reply With Quote