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
が張り付いている前提です。
using System;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using Windows.Data.Pdf;
namespace WinFormsProject1
{
public partial class Form1 : Form
{
public Form1() => InitializeComponent();
private async void Form1_Load(object sender, EventArgs e)
{
using (var pdfStream = File.OpenRead("sample.pdf"))
using (var winrtStream = pdfStream.AsRandomAccessStream())
{
var doc = await PdfDocument.LoadFromStreamAsync(winrtStream);
for (var i = 0u; i < doc.PageCount; i++)
{
using (var page = doc.GetPage(i))
using (var memStream = new MemoryStream())
using (var outStream = memStream.AsRandomAccessStream())
{
await page.RenderToStreamAsync(outStream);
pictureBox1.Image?.Dispose();
pictureBox1.Image = Image.FromStream(memStream);
await Task.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
のタイミングを調整してください。