2015年9月30日水曜日

PDF の中身をオンデマンド修正する

ちょっと PDF ファイルをオンザフライで修正する案件が起こりました。理由は:

  • Subset だとフォント名が細工されるので、無理矢理訂正したい。
  • 四角形と円形の線が細くて、しかも半分隠れていた。RD を設定、Rect と Border を増加したい。 

その時のノウハウです。

基本的な流れとしては、
  • PdfReader で PDF を読み込みます。
  • 次に PdfReader がメモリー上に保持しているデータ構造を巡回して、必要個所を書き換えます。
  • その結果を PdfCopy で書き込んでもらう、という方針を取ります。。。

iText で大量の PDF をマージする
http://d.hatena.ne.jp/ocs/20110520/1305866658

PdfReader で読み込んだ後、copy.GetImportedPage(reader, i); と、copy.AddPage(page); で、コピーすれば良いようです。

参照が発生する場合は、AddToBody で追加した参照を、PdfReader から読んできたページの辞書にセット。

AP.Put(PdfName.N, copy.AddToBody(objN).IndirectReference);

PdfCopy を継承して細工します。CopyDictionary をオーバーライドすれば、事足りると思います。

  class AltPdfCopy : PdfCopy {
    public AltPdfCopy(Document document, Stream os)
      : base(document, os) {

    }

    protected override PdfDictionary CopyDictionary(PdfDictionary __inp, bool keepStruct, bool directRootKids) {
      var newd = base.CopyDictionary(__inp, keepStruct, directRootKids);
      ...
      return newd;
    }
  }

全部を晒すことはできませんが、フォント名の加工は次のようにしました。

  protected override PdfDictionary CopyDictionary(PdfDictionary __inp, bool keepStruct, bool directRootKids) {
    var newd = base.CopyDictionary(__inp, keepStruct, directRootKids);
    if (newd.GetAsName(PdfName.TYPE) == PdfName.FONTDESCRIPTOR) {
      PdfName FontName = newd.GetAsName(PdfName.FONTNAME);
      String a = enc.GetString(FontName.GetBytes());
      if (Regex.IsMatch(a, "/[A-Z]{6}\\+")) {
        newd.Put(PdfName.FONTNAME, new PdfName(enc.GetBytes("/" + a.Substring(1 + 6 + 1))));
        IsMod |= true;
      }
    }
    ...
  }

0 件のコメント:

コメントを投稿