PDFium等の外部ライブラリを使用しなくても、Windows 8以降にはPDFファイルを画像としてレンダリングできるAPIがWinRTとしてOSに在ります。
UWP(Windowsストア)アプリでは特に苦もなく使用できるはずです。
WinForms(またはWPF)からは比較的最近利用できるようになりました。
この記事ではWinFormsのPictureBox(またはWPFのImage)に表示するサンプルコードを示します。
NuGetまたは手動で参照を追加する
docs.microsoft.comを参考にして、NuGetまたは手動でアセンブリへの参照を加えます。
NuGetの場合
要点を引用します。
[NuGet パッケージ マネージャー] ウィンドウで、 [参照] タブを選択して、Microsoft.Windows.SDK.Contracts を検索します。
Microsoft.Windows.SDK.Contracts パッケージが見つかったら、 [NuGet パッケージ マネージャー] ウィンドウの右側のペインで、ターゲットにする Windows 10 のバージョンに基づいて、インストールするパッケージのバージョンを選択します。
- 10.0.18362.xxxx:Windows 10 バージョン 1903 の場合は、これを選択します。
- 10.0.17763.xxxx:Windows 10 バージョン 1809 の場合は、これを選択します。
- 10.0.17134.xxxx:Windows 10 バージョン 1803 の場合は、これを選択します。
PDFファイルをレンダリングするAPI
docs.microsoft.comを見れば大体わかるかと思います。
ざっくりと下記のようになります。
Windows.Data.Pdf.PdfDocument.LoadFrom{Stream,File}Async
でPdfDocument
オブジェクトを取得。PdfDocument.GetPage
でPdfPage
オブジェクトを取得。PdfPage.RenderToStreamAsync
で、引数に渡したストリームに画像(デフォルトはpng)のバイトデータが書き込まれる。- バイトデータをImage(WPFであればBitmapDecoder)でイメージにする。
ただし、ストリームはSystem.IO.Stream
ではありません。Windows.Storage.Streams.IRandomAccessStream
を使用する必要があります。
直接ファイルから構築するならFileRandomAccessStream
を使用すればいいですが、実際のWinFormsアプリに組み込むならIStream
ではないと使い勝手が悪いです。WindowsRuntimeStreamExtensions.AsRandomAccessStream
拡張メソッドでIRandomAccessStream
を取得できます。
必要に応じてPdfPageRenderOptions
で多少カスタマイズできます。
画像をpngではなくbmpなどにする場合は、BitmapEncoderId
にWICのEncoder Idを指定すれば良さそうです。
サンプルコード
フォームを表示した後、1秒毎にページを表示してきます。
WinForms
適当なフォームに、pictureBox1
が張り付いている前提です。
usingSystem;usingSystem.Drawing;usingSystem.Threading.Tasks;usingSystem.Windows.Forms;usingSystem.IO;usingWindows.Data.Pdf;namespaceWinFormsProject1{publicpartialclassForm1:Form{publicForm1()=>InitializeComponent();privateasyncvoidForm1_Load(objectsender,EventArgse){using(varpdfStream=File.OpenRead("sample.pdf"))using(varwinrtStream=pdfStream.AsRandomAccessStream()){vardoc=awaitPdfDocument.LoadFromStreamAsync(winrtStream);for(vari=0u;i<doc.PageCount;i++){using(varpage=doc.GetPage(i))using(varmemStream=newMemoryStream())using(varoutStream=memStream.AsRandomAccessStream()){awaitpage.RenderToStreamAsync(outStream);pictureBox1.Image?.Dispose();pictureBox1.Image=Image.FromStream(memStream);awaitTask.Delay(1000).ConfigureAwait(false);}}}}}}
C# 8.0であればusing
文を簡略化できるかと思います。
WPF
WinFormsの例の
pictureBox1.Image?.Dispose();pictureBox1.Image=Image.FromStream(memStream);
の代わりに、
image1.Source=BitmapDecoder.Create(memStream,BitmapCreateOptions.None,BitmapCacheOption.OnLoad).Frames[0];
としてください。
他の部分はWPFに合わせて適宜変えてください。
OnLoadが嫌なら、using
のタイミングを調整してください。