完成済みPDFにヘッダを埋め込む
とある事情で40個くらいの完成済みPDF全ての1ページ目のみにヘッダを入れる必要がでてきました。このような編集機能を総称するとアノテーションというそうで、製品版のAdobe Acobat(無償のReaderではなく、作成や編集機能がついたもの)を持っているとGUI操作でできるようです。
しかしながら普段からPDFはTeX経由で作っていたり、M$のwordやPower Pointをあえて使う必要があっても無償のPrimoPDFでPDF作りに励んでいるため、残念ながら手元にAcobatがありません。またこの40個程度という数が微妙で、GUI操作、というかマウスを使う操作が比較的嫌いな僕としては、CUIなコマンドツールの方がうれしいです。
そこで今回は色々と調べまわってみた結果、解決にたどり着くことができましたので、それをまとめておこうと思います。
トップページから読まれている方は続きをどうぞ。
まずはGUIでも構わないので、このような機能が無償で提供されているツールがあるか調べてみました。『無料 PDF 編集』でGoogleを引いてみると、『PDF編集ツール情報』というページがPDFに対して行う操作別に整理されており参考になりました。実は以前、PDFの結合について記事を書いたことがありましたが、そのときも解決法を模索するにあたって、このページから有用なヒントを得た記憶があります。
残念ながら完全に目的に一致したツール(無償で特定ページのみヘッダが入れれる、かつCUI操作可能)を探し当てることはできませんでしたが、完成済みPDFにヘッダやページ番号を埋め込むアノテーション機能を持つツールの多くは、iTextという共通のPDF操作ライブラリを使用していることがわかりました。
iTextはJavaのライブラリです。Javaはここ久しく触っていないため、できればRubyネイティブのライブラリが良かったのですが、iTextの豊富な機能に押されてJavaでちょっとしたプログラムを組むことにしました(実はRuby Java BridgeによってRubyからiTextをコントロール可能だそうですが、少し手間がかかりそうであったので試していません)。実際iTextについて検索をしてみると、『PDFファイルをパスワード設定し、ヘッダーとフッターを追加』というかなり近い内容がヒットし、またiTextの公式APIドキュメントや、氏原さんという方が公開されている日本語チュートリアルなど参考になるものが多数あるので、Javaで目的のコードを書くこと自体、結果的には苦痛になりませんでした。
で完成した目的のコードは以下のようなものです。
import java.io.FileOutputStream;
import java.io.IOException;
import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfWriter;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.HeaderFooter;
import com.lowagie.text.PageSize;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;
public class PdfAddHeader {
public static void main(String[] args) throws Exception {
System.out.println("Add Header");
try {
try {
// TemplatePageの作成
Document document = new Document(PageSize.A4,
PageSize.A4.getWidth() / 210 * 25,
PageSize.A4.getWidth() / 210 * 25,
PageSize.A4.getWidth() / 294 * 25,
PageSize.A4.getWidth() / 294 * 25);
BaseFont bfArial =
BaseFont.createFont(
"C:\\WINDOWS\\FONTS\\ARIAL.TTF",
BaseFont.CP1252,
BaseFont.NOT_EMBEDDED);
PdfWriter.getInstance(document, new FileOutputStream("template.pdf"));
// set header
String posterNum = (args.length < 1) ? "hoge" : args[0];
HeaderFooter header = new HeaderFooter(
new Phrase(9,
"Header1\r\n" +
"Header2 NUM-" + posterNum, new Font(bfArial, 9)), false);
header.setAlignment(Element.ALIGN_RIGHT);
header.setBorder(Rectangle.NO_BORDER);
document.setHeader(header);
document.open();
document.add(new Paragraph(" "));
document.close();
} catch (DocumentException de) {
System.err.println(de.getMessage());
} catch (IOException ioe) {
System.err.println(ioe.getMessage());
}
PdfReader reader_orig = new PdfReader("orig.pdf");
PdfStamper stamp = new PdfStamper(reader_orig, new FileOutputStream("modified.pdf"));
PdfReader reader_template = new PdfReader("template.pdf");
if(reader_orig.getNumberOfPages() > 1){
PdfContentByte under = stamp.getUnderContent(1);
under.addTemplate(stamp.getImportedPage(reader_template, 1), 0, 0);
}
stamp.close();
}catch(Exception e){
e.printStackTrace();
}
System.out.println("DONE!");
}
}
これで作成済みPDFのorig.pdfに対して、1ページ目、上下左右25mmあるマージンのうち右上に、Arial 9ポイント2段の右揃いでヘッダ情報が記入されたPDFが、modified.pdfという名前で出力されるようになりました。あとは適当に改造して、外部からRubyで40個程度のPDFを処理するスクリプトを用意し、めでたく問題解決となりました。
少し補足をしておきますと日本語でヘッダを作る場合、フォントに注意する必要があるようです。その辺りの事情は@ITのiTextの解説ページ等をご覧ください。
コメント
コメントする
- 匿名でのコメントは受け付けておりません。
- お名前(ハンドル名可)とメールアドレスは必ず入力してください。
- メールアドレスを表示されたくないときはURLも必ず記入してください。
- コメント欄でHTMLタグは使用できません。
- コメント本文に日本語(全角文字)がある程度多く含まれている必要があります。
- コメント欄内のURLと思われる文字列は自動的にリンクに変換されます。
- 投稿ボタンを押してエラーがでなければ、投稿は成功しています。反映されるまでには少し時間がかかります。