Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9543

[C#/WinRT] 外部ライブラリを使用せずにPDFファイルを画像化してWinForms(またはWPF)で表示する

$
0
0

PDFium等の外部ライブラリを使用しなくても、Windows 8以降にはPDFファイルを画像としてレンダリングできるAPIがWinRTとしてOSに在ります。
UWP(Windowsストア)アプリでは特に苦もなく使用できるはずです。

WinForms(またはWPF)からは比較的最近利用できるようになりました。
この記事ではWinFormsのPictureBox(またはWPFのImage)に表示するサンプルコードを示します。

NuGetまたは手動で参照を追加する

docs.microsoft.comを参考にして、NuGetまたは手動でアセンブリへの参照を加えます。

NuGetの場合

要点を引用します。

  1. [NuGet パッケージ マネージャー] ウィンドウで、 [参照] タブを選択して、Microsoft.Windows.SDK.Contracts を検索します。

  2. 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を見れば大体わかるかと思います。
ざっくりと下記のようになります。

  1. Windows.Data.Pdf.PdfDocument.LoadFrom{Stream,File}AsyncPdfDocumentオブジェクトを取得。
  2. PdfDocument.GetPagePdfPageオブジェクトを取得。
  3. PdfPage.RenderToStreamAsyncで、引数に渡したストリームに画像(デフォルトはpng)のバイトデータが書き込まれる。
  4. バイトデータをImage(WPFであればBitmapDecoder)でイメージにする。

ただし、ストリームはSystem.IO.Streamではありません。
Windows.Storage.Streams.IRandomAccessStreamを使用する必要があります。
直接ファイルから構築するならFileRandomAccessStreamを使用すればいいですが、実際のWinFormsアプリに組み込むならIStreamではないと使い勝手が悪いです。
WindowsRuntimeStreamExtensions.AsRandomAccessStream拡張メソッドでIRandomAccessStreamを取得できます。

必要に応じてPdfPageRenderOptionsで多少カスタマイズできます。
画像をpngではなくbmpなどにする場合は、BitmapEncoderIdWICのEncoder Idを指定すれば良さそうです。

サンプルコード

フォームを表示した後、1秒毎にページを表示してきます。

WinForms

適当なフォームに、pictureBox1が張り付いている前提です。

Form1.cs
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のタイミングを調整してください。


Viewing all articles
Browse latest Browse all 9543

Trending Articles