2018年9月19日水曜日

マルチフォーマット対応の iTextSharp.text.Image

 PDF に画像をぺったんこ貼り付けする目的で…

iTextSharp.text.Image.GetInstance(Uri url) は次のイメージフォーマットに対応している模様です。
  • GifImage
  • Jpeg
  • Jpeg2000
  • PngImage
  • ImgWF
  • TiffImage (最初のページのみ)
  • JBIG2Image
  • BmpImage


TiffImage.GetTiffImage(RandomAccessFileOrArray s, int page) をダイレクトに使用することで、TIFF ファイルを読み込みできます。

しかし中には受付しないものもありました。
  • System.IO.IOException: Compression JPEG is only supported with a single strip. This image has 30 strips.
  • System.ArgumentException: Extra samples are not supported.

2018年5月8日火曜日

透明テキストを持つ PDF を作成するには

サンプルコードです。重要なのは SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_INVISIBLE) を指定することで、普通に ShowTextAligned で良いようです。

 using (var fs = File.Create(@"C:\A\A.pdf"))
 {
  Rectangle A4 = new Rectangle(0, 0, 595.44f, 841.68f);
  Rectangle A4R = new Rectangle(0, 0, 841.68f, 595.44f);
  var document = new Document(A4R);
  var writer = PdfWriter.GetInstance(document, fs);
  document.Open();
  var appender = writer.DirectContent;

  // http://www.plusism.biz/blog/2013/12/14/2
  FontFactory.Register(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "msgothic.ttc"));

  var font = iTextSharp.text.FontFactory.GetFont("MS-UIGothic", BaseFont.IDENTITY_H, 40f);

  appender.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_INVISIBLE);
  appender.SetFontAndSize(font.GetCalculatedBaseFont(false), 40f);
  appender.BeginText();
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "1", 40, 40, 0);
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "2", 60, 40, 0);
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "3", 80, 40, 0);
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "A", 100, 40, 0);
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "B", 120, 40, 0);
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "C", 140, 40, 0);
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "あ", 160, 40, 0);
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "い", 200, 40, 0);
  appender.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "う", 240, 40, 0);
  appender.EndText();
  document.Close();
  writer.Close();
 }

2017年7月21日金曜日

PDF のファイル構造を分析/解析するツール

PDFXplorer 1.0.0


辞書の内容を、リスト表示できます(下図参照)


特徴:
  • 各オブジェクト(Bool, Number, String, Name, Array, Dictionary, Stream, Indirect Reference)を認識します。
    • 右側のリストに列挙。表示例:
      • /Filter Name /FlateDecode
      • /MediaBox Array [0 0 256 156 ]
      • /Pages Indirect Reference 3 0 R
    • 左側ツリーにも列挙。表示例:
      • /Filter /FlateDecode
      • /MediaBox 4 elements
      • /Pages 3 0 R
    • アイコン・デザインに気合が入っています。素晴らしい!
  • PDF のデザインを尊重するような表示になっています:
    • Name の /FlateDecode は /FlateDecode と、そのまま表示します。
    • Document Structure を表示しています。つまり /Type と /Pages を表示しています。
  • stream について
    • /Filter /FlateDecode を解除して表示可能
    • Display mode:
      • Binary
      • Text
      • Image (DCT streams only)
    • Save stream to disk でファイルに保存可能
  • 編集はできません。
総評
  • 使いやすい!
  • PDF ファイルの構造を忠実に表現しようとしているように感じました。

pdfbox PDFDebugger


下図参照

起動例:

java -jar pdfbox-app-3.0.0-RC1.jar debug pdfFile

特徴:

  •  各オブジェクトを認識します。
    • 左側のツリーには、オブジェクトの一覧を列挙します。表示例:
      • Interpolate: true
      • Width:  712
      • Ordering:  Japan1
      • Encoding:  Identity-H 
      • MediaBox:  (4)
      • Resources:  (3) [6 0 R]
      • Contents:  (2) [4 0 R]
      • 0:  (5) [2 0 R]  /T:Page
    • 右側のリストには、オブジェクトの内容を表示します。
  • stream について
    • ページ (/T:Page とついているもの) は、ページをレンダリングします。
    • 画像 (/T:XObject /S:Image つき) は、画像をレンダリングします。
    • フォント (/T:Font /S:Type0 つき) は、フォントの字体一覧をレンダリングします。一覧の列:
      • Code
      • CID
      • GID
      • Unicode Character
      • Glyph
 総評:
  • 使いやすい。
  • 一部、オブジェクトの表示機能がついているのが特徴的です。
  • MediaBox など、配列はツリーを展開しないと要素が見えません。

PDF Document Inspector

http://www.cheapimpostor.com/PDFInspector/
macOS アプリ。未評価。

PDFedit

http://pdfedit.cz/en/pdfedit_windows.html

Windows 版はこちらの PDFedit ではなく、TIAEditor という別物になっているようです…

iText RUPS

https://github.com/itext/rups

RUPS → Reads, Updates PDF Syntax?

下図参照:
特徴:
  • PDFXplorer と大体同じです。
  • iText RUPS では編集(辞書オブジェクトの中身の修正程度)ができます。
    • 編集しても保存確認はしません。File → Save as... で自分で保存しましょう。
  • 画面右側にナビゲーションが実装されています。
    • Pages にて、特定 Page へジャンプできます。
    • XRef にて、参照元の間接オブジェクトへジャンプできます。
  • Stream のテキスト表示に、Graphics operators 用のシンタックスハイライトが装備されています。Text objects, Text positioning, XObjects, Path 系, Special graphics state, その他, Graphics operators 以外は黒, のような色分けかなと思いました。


peepdf

https://pypi.org/project/peepdf/0.3.2/
https://github.com/jesparza/peepdf

PDF のファイル内容を、コマンドライン上で、対話式に解析できるツールです。

Windows で peepdf を使うなら、
ネイティブの CPython を使用するよりも、
Cygwin 上の Python 3.8 を使った方が良いでしょう。

peepdf のインストール中にネイティブライブラリのビルドを必要とするようで、
これがどうも解決するのが大変なためです。


2017年3月24日金曜日

PDF GetPageRotation /Rotate 0 90 180 270 正規化する

/Rotate 90 は時計回りに 90 度回転します。


/Rotate を付けてもらうには…
  • Adobe Acrobat 8.0 を使用
  • 複合機でスキャンした PDF を回転

サンプル PDF はこちら

/Rotate の付与状況は PDFXplorer で確認できます。



こうしてできてしまった PDF を正規化するサンプルコード。iTextSharp 4.1.6 を使用しています。

  public void MakePdf2(string fppdfIn, string fppdfOut) {
    // https://www.codeproject.com/Articles/277065/Creating-PDF-documents-with-iTextSharp

    using (var si = File.OpenRead(fppdfIn)) {
      PdfReader reader = new PdfReader(si);
      reader.ConsolidateNamedDestinations();

      using (var fs = File.Create(fppdfOut)) {
        Document document = null;
        PdfWriter writer = null;
        int numPages = reader.NumberOfPages;
        for (int pageNum = 1; pageNum <= numPages; pageNum++) {
          var pageSizeAfterRotation = reader.GetPageSizeWithRotation(pageNum);
          if (document == null) {
            document = new Document(pageSizeAfterRotation);
            writer = PdfWriter.GetInstance(document, fs);
            document.Open();
          }
          else {
            document.SetPageSize(pageSizeAfterRotation);
            document.NewPage();
          }

          PdfTemplate background = writer.GetImportedPage(reader, pageNum);

          float[] transferMatrix = new float[6];
          switch (reader.GetPageRotation(pageNum)) {
            case 0:
            default:
              transferMatrix[0] = 1;
              transferMatrix[3] = 1;
              break;
            case 270:
              transferMatrix[0] = (float)Math.Cos((float)(270 / 180.0f * Math.PI));
              transferMatrix[1] = (float)-Math.Sin((float)(270 / 180.0f * Math.PI));
              transferMatrix[2] = -transferMatrix[1];
              transferMatrix[3] = transferMatrix[0];
              transferMatrix[4] = pageSizeAfterRotation.Width;
              //transferMatrix[5] = pageSizeAfterRotation.Height;
              break;
            case 180:
              transferMatrix[0] = (float)Math.Cos((float)(180 / 180.0f * Math.PI));
              transferMatrix[1] = (float)-Math.Sin((float)(180 / 180.0f * Math.PI));
              transferMatrix[2] = -transferMatrix[1];
              transferMatrix[3] = transferMatrix[0];
              transferMatrix[4] = pageSizeAfterRotation.Width;
              transferMatrix[5] = pageSizeAfterRotation.Height;
              break;
            case 90:
              transferMatrix[0] = (float)Math.Cos((float)(90 / 180.0f * Math.PI));
              transferMatrix[1] = (float)-Math.Sin((float)(90 / 180.0f * Math.PI));
              transferMatrix[2] = -transferMatrix[1];
              transferMatrix[3] = transferMatrix[0];
              //transferMatrix[4] = pageSizeAfterRotation.Width;
              transferMatrix[5] = pageSizeAfterRotation.Height;
              break;
          }

          var ww = writer.DirectContentUnder;
          ww.AddTemplate(background, transferMatrix[0], transferMatrix[1], transferMatrix[2],
            transferMatrix[3], transferMatrix[4], transferMatrix[5]);
        }

        document.Close();
        writer.Close();
      }
    }
  }

2016年2月12日金曜日

PDF 注釈の Rect と BBox と Matrix の関係

PDF の注釈を固定化しようとしています。この 3 つの関係がイマイチ良く分かりません。仕様書を読んだらよいのですが、そんな時間は有りません。。。

ーーー
注釈 1
/Subtype /FreeText

0  Rect(451, 724, 529, 736) BBox(451, 724, 529, 736) Matrix

Rect = BBox
Matrix なし
AP/N は、BBox に収まるような描画内容

ーーー
注釈 2
/Subtype /FreeText

65 /FreeTextCallout Rect(711, 445, 1127, 542) BBox(711, 445, 1127, 542) Matrix|1.0 0.0 0.0 1.0 -711.186 -444.702|

Rect = BBox
Matrix あり。
AP/N は、BBox に収まるような描画内容


ーーー
注釈 3
/Subtype /FreeText

67  Rect(843, 413, 1145, 427) BBox(848, 375, 1151, 389) Matrix

Rect != BBox
Matrix なし。
AP/N は、BBox に収まるような描画内容

ーーー
注釈 4
/Subtype /Stamp

49  Rect(88, 484, 243, 630) BBox(0, 0, 645, 606) Matrix|1 0 0 1 0 0|

Rect != BBox
Matrix は Identity
AP/N は、BBox に収まるような描画内容

ーーー
注釈 5
/Subtype /FreeText

76 /FreeTextTypewriter Rect(842, 391, 1022, 409) BBox(860, 374, 1040, 392) Matrix|1.0 0.0 0.0 1.0 -860.438 -374.371|

Rect != BBox
Matrix あり。
AP/N は、BBox に収まるような描画内容

2015年11月24日火曜日

PDF の外観辞書のレンダリング

PDF注釈→固定化する事案が発生しました。

Rect やら BBox やら Matrix やら出てきて、どれをどうするのか、良く分かりません。

得られた知見:

  • 外観辞書のXObjectの原点は、左下(0,0)原点で描いた方が後で管理しやすい。
  • 掛ける物。
    1. Matrix の行列
    2. Rectに合うように、BBoxの幅高さを拡大縮小する行列
    3. Rect のオフセットと、BBox のオフセットを足す行列
  • 外観辞書のXObjectは、同じスタンプを押す等で、使いまわしされます。

2015年11月16日月曜日

PDF の行列

[ a b c d e f ]
↑に対して、↓のようになります。
| a b |
| c d |
| e f |

座標を求めるときは、次のように:
            | a b |
| x y 1 | * | c d |
            | e f |