PDFbox is a fairly robust library for manipulating and extracting information from PDF documents. This is a short and simple Java class that utilizes PDFbox to stamp/watermark a PDF from the command line, be it a bash script or exec call. There isn’t much in the way of existing user documentation for this type of action using PDFbox, so I’m leaving it here in case it’s useful.
/* * A Simple PDF Stamper using PDFBox * * July, 2013 * @author jack */ package simplestamper; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.apache.pdfbox.Overlay; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.exceptions.CryptographyException; import org.apache.pdfbox.exceptions.InvalidPasswordException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType1Font; /** * * @author jack */ public class SimpleStamper { private static PDDocument pdf; private static int numPages; private static Properties config = new Properties(); private static String configFile; private static String outputFN = null; private static String inputFN = null; private static String stampString = null; private static String fontFamily = null; private static Float fontSize = null; /** * The main class. It's what plants crave. * * @param args the command line arguments * args[0] -> The config file * args[1] -> The PDF document to be stamped * args[2] -> The string to stamp (optional, falls back to ss.text in the config file) * args[3] -> The desired name and path of the stamped PDF (optional, also defined in config file as ss.outputFN) */ public static void main(String[] args) throws IOException, CryptographyException, COSVisitorException { // if we don't have any parameters... if (args.length == 0) { usage(); } else { // the config file path configFile = args[0]; // load the config loadConfig(configFile, args); } // stamp stampPdf(); } /** * Loads the configuration data. * * @param configFile */ public static void loadConfig(String configFile, String[] args) { // the input stream InputStream is; try { is = new FileInputStream(configFile); try { // try to load the config file config.load(is); is.close(); } catch (IOException e) { e.printStackTrace(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // the input PDF filename/path if (args.length > 1) { inputFN = args[1]; }else{ inputFN = config.getProperty("ss.inputFN"); } // the string to be stamped if(args.length > 2){ stampString = args[2]; }else{ stampString = config.getProperty("ss.text"); } // the output PDF filename/path if(args.length > 3){ outputFN = args[3]; }else{ outputFN = config.getProperty("ss.outputFN"); } // make sure we have a font from the prop file try{ fontFamily = config.getProperty("ss.fontFamily"); } catch (NullPointerException e){ System.err.println("You must specify a font in the properties file."); } // make sure we have a font size from the prop file try{ fontSize = Float.parseFloat(config.getProperty("ss.fontSize")); } catch (NullPointerException e){ System.err.println("You must specify a font size in the properties file."); } } /** * Coordinate the stamping procedure. * */ public static void stampPdf() throws IOException, CryptographyException, COSVisitorException { // load the PDF to be stamped pdf = PDDocument.load(inputFN); if (pdf.isEncrypted()) { try { // try to open the encrypted PDF pdf.decrypt(""); } catch (InvalidPasswordException e) { // This error message dictates that the document is encrypted and we have no password System.err.println("The document is encrypted or otherwise has prohibitive security settings.."); System.exit(1); } } // create the overlay page with the text to be stamped PDDocument overlayDoc = createOverlay(stampString); // update the number of pages we have in the incoming pdf numPages = pdf.getPageCount(); // do the overlay doOverlay(pdf, overlayDoc); // close pdf.close(); overlayDoc.close(); } /** * Creates the overlay PDF. * * @param text * @return PDDocument * @throws IOException * @throws COSVisitorException */ public static PDDocument createOverlay(String text) throws IOException, COSVisitorException { // Create a document and add a page to it PDDocument document = new PDDocument(); PDPage page = new PDPage(); document.addPage(page); // the x/y coords Float xVal = Float.parseFloat(config.getProperty("ss.xVal")); Float yVal = Float.parseFloat(config.getProperty("ss.yVal")); // Create a new font object selecting one of the PDF base fonts PDFont font = PDType1Font.getStandardFont(fontFamily); // Start a new content stream which will "hold" the to be created content PDPageContentStream contentStream = new PDPageContentStream(document, page); // Create the text and position it contentStream.beginText(); contentStream.setFont(font, fontSize); contentStream.moveTextPositionByAmount(xVal, yVal); contentStream.drawString(text); contentStream.endText(); // Make sure that the content stream is closed: contentStream.close(); //return the string doc return document; } /** * Performs the overlay of the two documents. * * @param basePDF * @param overlayDoc * @throws IOException * @throws COSVisitorException */ private static void doOverlay(PDDocument basePDF, PDDocument overlayDoc) throws IOException, COSVisitorException { PDDocumentCatalog docCatalog = basePDF.getDocumentCatalog(); // get the pages of the pdf List pages = docCatalog.getAllPages(); Iterator pageIter = pages.iterator(); while (pageIter.hasNext()) { PDPage page = (PDPage) pageIter.next(); } Overlay overlay = new Overlay(); PDDocument output = overlay.overlay(overlayDoc, basePDF); //overlay.overlay(overlayDoc, basePDF); // save the new doc to the file name specified in the config output.save(outputFN); // close, close overlayDoc.close(); basePDF.close(); } /** * Attempts to provide basic usage information. */ private static void usage() { System.err.println("usage: java -jar simplestamper \"PdfToStamp.pdf\" \"The text to stamp, in parenthesis.\" \"Output.pdf\""); } }