NPlot にPDF出力機能を追加しました

イメージ 1

先日紹介したグラフ描画ライブラリNPlotに、PDF出力機能を追加してみました。
オリジナルのNPlotは出力先として、ベクタ系の画像をサポートしていないようだったので、
PDFを作成できるライブラリiTextSharpを使って、PDF出力機能を追加しました。
LaTeX用のグラフを出力できるプログラムを作りたいというのが開発動機です。

使い方は↓のような感じです。

FileStream fs = new FileStream("nplot_demo.pdf", FileMode.Create);
iTextSharp.text.Document document = new iTextSharp.text.Document(new iTextSharp.text.Rectangle(600.0f, 500.0f), 0,0,0,0);
iTextSharp.text.pdf.PdfWriter writer = iTextSharp.text.pdf.PdfWriter.GetInstance(document, fs);

document.Open();

iTextSharp.text.pdf.BaseFont bf = iTextSharp.text.pdf.BaseFont.CreateFont(
@"sazanami-gothic.ttf", iTextSharp.text.pdf.BaseFont.IDENTITY_H,
iTextSharp.text.pdf.BaseFont.EMBEDDED);
NPlot.PDF.PlotSurface2D s2d = new NPlot.PDF.PlotSurface2D(writer.DirectContent, bf);
s2d.Legend = new NPlot.Legend();
s2d.Legend.AttachTo(NPlot.PlotSurface2D.XAxisPosition.Top, NPlot.PlotSurface2D.YAxisPosition.Right);
s2d.Legend.VerticalEdgePlacement = NPlot.Legend.Placement.Inside;
s2d.Legend.HorizontalEdgePlacement = NPlot.Legend.Placement.Inside;
s2d.Legend.XOffset = -5;
s2d.Legend.YOffset = 0;
s2d.Legend.Font = new Font(FontFamily.GenericMonospace, 30.0f);

s2d.Add(barPlot1);
s2d.Add(line1);
s2d.Add(pointPlot1);
s2d.Refresh();
document.Close();

NPlotでは、グラフを作成するクラスに直接Graphicsオブジェクトを渡して描画を行うような構造になっています。GDI+のGraphicsオブジェクトはPDFをサポートしてませんし、継承などを利用してGraphicsのインタフェースを残して中身を変えられるようにもできていないので、NPlot本体の変更なしではPDFに対応できません。
そこで、NPlotが使っているGraphicsの機能をIGraphicsインタフェースに書き出して、グラフを作成するクラスにGraphicsを渡す代わりに、必要な描画機能をメンバとして持っているIGraphicsインタフェースを渡します。IGraphicsの実装として、Graphicsをほぼそのままラップしたものと、PdfContentByteをラップしたものの2つを用意し、PDF用ではPdfContentByteをラップしたものを使って、それ以外(Windowやビットマップ用、つまり従来からあるもの)ではGraphicsをラップしたものを使うようにしてあります。

NPlot.PDF.PlotSurface2D オブジェクトに数箇所、System.Drawing.Pen や System.Drawing.Brushを指定できるプロパティがあります。それらのオブジェクトを直接利用する代わりに、それらの属性を見て同じように描画するようにしています。なのでBitmapなどに書き出したときと完璧には一致しませんが、基本的な属性はそこそこ同じになるようにしてあります。
Penの属性として、Color、Width、Dash(あと確認してませんがEndCapとLineJoinも一応対応させてみました)が使えます。
BrushはSolidBrushのみ使えます。それ以外のBrushをいれても多分認識しません。

フォントは、System.Drawing.Fontのフォントサイズを参照して、NPlot.PDF.PlotSurface2Dに渡したBaseFontで描画します。なので、1つのグラフ内で複数のフォントサイズを使うことはできますが、複数の種類のフォントは使えません。

さらに新たな出力先(svg、ps、OpenGL、emf…他にもありそうですね)を追加したいときは、IGraphicsインタフェースを実装すればいいと思いますので、場合によってはNPlotの修正なしに追加できる可能性があります。

- http://www.geocities.jp/mocchi_2003/soft/NPlot_with_self_patch_051.zip
PDF機能追加済み NPlotバイナリ+ソース (2006 8/8現在の最新版へリンクしています)
- http://www.geocities.jp/mocchi_2003/soft_readme/nplot_with_pdf/nplot_demo.pdf
- http://www.nplot.com/
NPlot
- http://itextsharp.sourceforge.net/
iTextSharp

当記事に関する感想、疑問などありましたら、どしどし書き込んで下さい。


関連
- NPlot で値の表示範囲を設定する方法
- NPlot でマーカー付き折れ線グラフを使いたい!
- NPlot にPDF出力機能を追加しました
- グラフ作成ライブラリNPlot


もっちーの小部屋 自作のソフトを公開してます。
http://www.geocities.jp/mocchi_2003/index.html