I wanted to add my own little margin notes to any PDF file (using LaTeX and the multistamp feature of PDFTk). However, because the PDF was arbitrary, I could not write on the existing margin. Instead, I had to add an extra margin at the side. But none of the standard tools supports that, and using pypdf and similar toolsets loses the metadata like bookmarks. Here is a quick hack to expand the relevant page boxes:
#!env python2.7 import os import os.path import subprocess import re # Margin in points. margin = 150 def addmargin(fn_src, fn_dst): fn_tmp = fn_dst + '.tmp' subprocess.call(['pdftk', fn_src, 'output', fn_dst, 'uncompress']) # We leave rotate pages alone, as they usually contain tables or images. rotate = 0 # We leave Bleed and Art alone. box = re.compile(r'^/(Media|Crop|Trim)Box\s+\[(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\]$') rot = re.compile(r'^/Rotate\s+(.+)$') infile = open(fn_dst, 'rb') outfile = open(fn_tmp, 'wb') # This is a hack, but what the hell. for line in infile: lr = rot.match(line) if lr: print line rotate = int(lr.group(1)) elif rotate == 0: lm = box.match(line) if lm: print line (btype, bl, bt, br, bb) = lm.groups() line = '/%sBox[%s %s %.3f %s]\n' % (btype, bl, bt, float(br) + margin, bb) outfile.write(line) outfile.close() infile.close() subprocess.call(['pdftk', fn_tmp, "output", fn_dst, "compress"]) os.remove(fn_tmp) if __name__ == '__main__': addmargin("in.pdf", "out.pdf")
Adding rotation support is left as an exercise for the reader.
I also made a custom version of pdftk to disable scaling of the stamp, because I controlled the stamp PDF in such a way that each page was a perfect fit on the original page. The positions of text elements on the original page were available due to
pdftotext -bbox-extended -xmlmeta. The xmlmeta option is not part of the regular PDFTk distribution: We enriched our version of pdftotext (poppler) to have a more complete xml output to do that.