I got this working. In case anyone else needs to rename the PDF bookmarks in many PDF files (batch bookmark renaming), you can avoid paying for Autobookmark with the script below. I'll be the first to admit that it could be improved, probably drastically (not least by refactoring), but it works! I'm using Windows 7 64bit and files with UTF-8 encoded glyphs. It assumes you'll create a c:\in and c:\out with the "in" folder containing your originals and "out" containing the renamed bookmark versions. This program won't change your original PDF's. Watch the console output for any PDF's that itext can't handle. In my case, I had some zero byte PDF's, secured PDF's, and even corrupted PDF's that wouldn't process.
package annotations;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.SimpleBookmark;
public class RenameDestinations {
public static void main(String[] args) throws IOException, DocumentException {
String in = "c:/in"; // this must be a directory
String out = "c:/out"; // this must be a directory
// Parent Bookmarks
String find1 = "_\n <"; // e.g., Something_ <Title ...> child bookmark</Title>
String repl1 = "X\n <"; // e.g., SomethingX <Title ...> child bookmark</Title>
// No children
String find2 = "_</Title>"; // e.g., <Title>Something_</Title>
String repl2 = "X</Title>"; // e.g., <Title>SomethingX</Title>
// read a directory of files
// http://stackoverflow.com/questions/13918876/java-open-directory
File directory = new File(in);
File[] contents = directory.listFiles();
for (File f : contents) {
// get extension
String filename = f.getName();
String extension = filename.substring(filename.lastIndexOf(".") + 1, filename.length()).toLowerCase();
// leave if not a PDF
if (!extension.equals("pdf")) {
System.out.println(filename);
System.out.println(" NOT PDF, SKIPPED");
continue;
}
// inform user
System.out.println(filename);
String src = f.getAbsolutePath();
String dst = out + "/" + f.getName();
String srcx = in + "/bookmarks.xml"; // save this book's bookmarks
// read and create an xml file of the bookmarks
PdfReader reader = new PdfReader(src);
List<HashMap<String, Object>> list = SimpleBookmark.getBookmark(reader);
// Create a stamper
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dst));
//leave if no bookmarks
if (list == null) {
System.out.println(filename);
System.out.println(" NO BOOKMARKS, THUS NO CHANGES MADE");
stamper.setOutlines(list);
}else {
// create bookmarks xml
SimpleBookmark.exportToXML(list, new FileOutputStream(srcx), "UTF-8", true);
// find and replace bookmark titles
// http://stackoverflow.com/questions/3935791/find-and-replace-words-lines-in-a-file
Path path = Paths.get(srcx);
Charset charset = StandardCharsets.UTF_8;
// store
String content = new String(Files.readAllBytes(path), charset);
// replace
content = content.replaceAll(find1, repl1);
content = content.replaceAll(find2, repl2);
// write
Files.write(path, content.getBytes(charset));
// read
// https://code.google.com/p/pdf-pub-tools/source/browse/trunk/pdf-pub-tools/src/java/net/mitnet/tools/pdf/book/pdf/util/PdfBookmarkBuilder.java?spec=svn133&r=133
List<HashMap<String, Object>> bookmarks = SimpleBookmark.importFromXML(new FileReader(srcx));
stamper.setOutlines(bookmarks);
//inform user
System.out.println(" BOOKMARKS RENAMED!");
}
// Close the stamper and reader
stamper.close();
reader.close();
}
//inform user
System.out.println("DONE!");
}
}