3 Replies Latest reply on Oct 22, 2010 10:36 AM by DarceyW

    Trying to add a bookmark to existing PDF using iText

    DarceyW

      I have copied code I located on cfsearching for concatenating pdfs and including any existing bookmarks ( http://cfsearching.blogspot.com/2007/12/getting-started-with-itext-part-17.html ), have purchased the iTextinAction book, but am stuck when trying to add a new bookmark. I keep getting the message '

      java.util.ArrayList cannot be cast to java.util.HashMap.

       

      I suspect I am not adding my own 'custom' bookmarks to the list of existing bookmarks correctly. I tried changing the list of existing bookmarks from an explicit vector (this was how the example was written) to an array instead, but still have this issue when I try to close my document. Following is the code I have modified. I would appreciate any help. I am not a Java programmer and am really struggling to understand how this works and how to make changes to it.

       

       

       

      <cfscript>
        savedErrorMessage = "";

        // cfSearching: All file paths are relative to the current directory
        fullPathToOutputFile = ExpandPath("./Concatenated.pdf");
        arrayOfInputFiles = arrayNew(1);
        arrayAppend(arrayOfInputFiles, ExpandPath("./Version control.pdf"));
        arrayAppend(arrayOfInputFiles, ExpandPath("./iTextinAction,SecondEdition.pdf"));
        try {

            pageOffset = 0;
            PdfReader = createObject("java", "com.lowagie.text.pdf.PdfReader");
            SimpleBookmark = createObject("java", "com.lowagie.text.pdf.SimpleBookmark");
            // cfSearching: Internally CF stores arrays as Vectors. So I chose to use an explict vector
            // cfSearching:  here, but you could use an array and CF array functions instead
            allBookmarks = createObject("java", "java.util.Vector");

             outlines = arrayNew(1);
           arrayAppend(outlines, 'Pirate Jack');

            for ( fileIndex = 1; fileIndex LTE arrayLen(arrayOfInputFiles); fileIndex = fileIndex + 1) {
                // we create a reader for a certain document
                reader = pdfReader.init( arrayOfInputFiles[fileIndex] );
                reader.consolidateNamedDestinations();
                // we retrieve the total number of pages
                totalPages = reader.getNumberOfPages();
                bookmarks = SimpleBookmark.getBookmark(reader);
                if (IsDefined("bookmarks")) {
                    if (pageOffset neq 0) {
                        SimpleBookmark.shiftPageNumbers(bookmarks, javacast("int", pageOffset), javacast("null", 0));
                    }
                    allBookmarks.addAll(bookmarks);
                }

                pageOffset = pageOffset + totalPages;

                if (fileIndex EQ 1) {
                    // step 1: creation of a document-object
                    document = createObject("java", "com.lowagie.text.Document");
                    document = document.init( reader.getPageSizeWithRotation( javacast("int", 1)) );
                    // step 2: we create a writer that listens to the document
                    outStream = createObject("java", "java.io.FileOutputStream").init( fullPathToOutputFile );
                    pdfWriter = createObject("java", "com.lowagie.text.pdf.PdfCopy").init(document, outStream);
                    // step 3: we open the document
                    document.open();
                 }
                 // step 4: we add content
                 for (pageIndex = 1; pageIndex LTE totalPages; pageIndex = pageIndex + 1) {
                      page = pdfWriter.getImportedPage(reader, javacast("int", pageIndex) );
                      pdfWriter.addPage(page);
                 }

                 formFields = reader.getAcroForm();
                 if (IsDefined("formFields")) {
                    pdfWriter.copyAcroForm(reader);
                 }
            }
            if (arraylen(outlines) gt 0) {
                allBookmarks.addAll(outlines);
            }

            if (NOT allBookmarks.isEmpty()) {
                pdfWriter.setOutlines( allBookmarks );
            }

            // step 5: we close the document
            document.close();

            WriteOutput("Finished!");
        }
        catch (java.language.Exception de) {
            savedErrorMessage = de;
        }
        // cfSearching: close document and output stream objects
        if (IsDefined("document")) {
            document.close();
        }
        if (IsDefined("outputStream")) {
            outputStream.close();
        }
      </cfscript>

        • 1. Re: Trying to add a bookmark to existing PDF using iText
          -==cfSearching==- Level 4

          That entry is _really_ old ;-)  CF8/9 introduced a bunch of new features which removed a lot of the need to dip down  into iText for basic pdf stuff.  For example

           

          http://www.coldfusionjedi.com/index.cfm/2010/2/19/Quick-Tip-Adding-a-bookmark-to-a-PDF-whe n-it-has-none

           

               outlines = arrayNew(1);
               arrayAppend(outlines, 'Pirate Jack');

           

          But .. bookmarks are more than just simple text. That is why the error occurs. Bookmarks are like a structure and can consist of properties like a title, action, url, page number, style etcetera. So it is not as simple as appending a string. To see what a bookmark object looks like to CF, dump the "bookmarks" variable right after the isDefined() statement:

           

                    ....

                    if (IsDefined("bookmarks")) {

                        // for CF9 use WriteDump() for CF8 try http://www.cflib.org/udf/Dump
                        dump(bookmarks);

                        ....

                    }

           

          -Leigh

          • 2. Re: Trying to add a bookmark to existing PDF using iText
            DarceyW Level 1

            Thanks for replying. The link for the dump syntax is very helpful!

             

            I am using CF8 (although had looked into CF9 to see if it resolved my issue). And had found everything I wanted for my process (creating some pdf's from html, then merging all of those plus extra 'external' pdfs into 1) all in CF tags. All worked great except for the ability to add a bookmark to an existing pdf (which was not created via CF) which did not have one.

             

            Dumb question here, but just to be sure, are you saying that my new bookmark to add needs to be in a structure format, and if I create it similar to how an iText bookmark looks, I can then add it using addAll()? I did briefly attempt that in one of my many attempts to get this to work, but didn't have success there either, so did not pursue that further. Perhaps I was just missing a few key things?

             

            As for the Quick Tip from coldfusionjedi, I had also found that and tried it, but without success. As you can probably guess, I've never worked with the DDX in CF either. Are you saying that I should be able to use this DDX code on an existing pdf file which does not have a bookmark (and was created from some source other than CF) and see that a bookmark gets added? I can certainly do some reading up on how to use DDX. And that this would be a better method than trying to use iText directly via CF?

             

            Once again, thank you for your initial help.

            • 3. Re: Trying to add a bookmark to existing PDF using iText
              DarceyW Level 1

              I was successful today using the DDX example from the coldfusionjedi site you mentioned ( http://www.coldfusionjedi.com/index.cfm/2010/2/19/Quick-Tip-Adding-a-bookmark-to-a-PDF-whe n-it-has-none ). Worked very nicely thank you.