VSCodeで書く  C# × PDFium（PDFiumViewer）

# 前置き
PDFiumはGoogleが作ってオープンソース化したフリーに使えるライブラリです。
C++で作られているのでC#で扱うにはラッパーであるPDFiumViewrを使うといいそうです。
VSCodeではNuGetからパッケージを追加すると使えます。

# メイン
## ・環境


OS： Windows 10 Home
Visual Studio Code バージョン： 1.73.1
言語バージョン： C#10.0
.NETバージョン： .NET 6.0.11

## ・準備

### ◆プロジェクトの作成

ソリューションとプロジェクトを作成して開きます。
```powershell:ターミナル
dotnet new sln -o ./PdfHoge
cd ./PdfHoge
dotnet new console -o ./PdfHoge
dotnet sln add ./PdfHoge/PdfHoge.csproj
```

### ◆NuGetパッケージの追加

NuGetから**PdfiumViewer**と本体である**PdfiumVewer.Native.x86_64.v8-xfa**（64bitの場合）を追加します。
バージョンはとりあえず最新。
#### ◇PdfiumViewerの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/b517e00b-354d-b137-9fdb-52e8b388f631.png)
#### ◇Nativeの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/1bc5a9a5-dbed-d86f-c1d7-f7d396b0d1fb.png)

### ◆ビルド警告の抑制
これまででプログラミングの準備はできていますが、ビルドするとターゲットフレームワーク云々～の警告がでるので、.csprojのPdfiumViewerに<b>「NoWarn="NU1701"」</b>を入れておいて警告を非表示にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/cc393b34-5d5c-c78f-4476-79c4e08ed75a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/2578ceee-84bd-da81-0617-04643b08a670.png)

## ・PDFを読む

サンプルPDFをWordで作りました。↓ これを読んでいきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/cd574414-0475-02fb-4724-d25db5775e78.png)

### ◆テキストを読む
#### ◇コード
サンプルPDFは.csprojと同じディレクトリに置きました。テキストの読み取りは**PdfDocumentクラス**の**GetPdfTextメソッド**を使います。引数にはページ番号－１を渡します。結果をみるとフッターが本文より前に来ていたり、タブがなくなってたりしますがおそらくPDFのバイナリはその順序になっているのでしょう。
```csharp:Program.cs
using PdfiumViewer;
string path = "sample.pdf";
using (PdfDocument doc = PdfDocument.Load(path))
{
    for (var pageNum = 0; pageNum < doc.PageCount; pageNum++)
    {
        string text = doc.GetPdfText(pageNum);
        Console.WriteLine(text);
    }
}
Console.ReadKey();
```
#### ◇実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/177eefeb-736b-cba3-2900-55ea387ff797.png)


### ◆画像として保存する
#### ◇Nugetパッケージの追加
JPEGで保存するために、Imageクラスを使います。
Imageクラスを利用するために**System.Drawing.Common**をNugetから追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/aa11435a-064a-f574-05d0-ac762de55c96.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/c27516b1-a0aa-b0b7-6f58-90d5716941c5.png)
#### ◇コード
画像は**Renderメソッド**で取得します。
```csharp:Program.cs
using System.Drawing;
using PdfiumViewer;

string path = "sample.pdf";
const int dpi = 96;
const int ppi = 72;
using (PdfDocument doc = PdfDocument.Load(path))
{
    for (var pageNum = 0; pageNum < doc.PageCount; pageNum++)
    {
        SizeF pageSize = doc.PageSizes[pageNum];
        int width = (int) (pageSize.Width * dpi / ppi);
        int height = (int) (pageSize.Height * dpi / ppi);
        Image image = doc.Render(pageNum, width, height, dpi, dpi, false);
        image.Save($"image{pageNum + 1}.jpg");
    }
}
```
#### ◇実行結果
↓作成されたJPEG画像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/942bf581-5c2b-7c79-7e01-2c72e73f72a7.png)


### ◆WPFのImageで表示する
#### ◇プロジェクトの作成
まずはWPFプロジェクトを追加し、tasks.jsonおよびlaunch.jsonを修正して複数プロジェクトに対応させます。
```powershell:ターミナル
dotnet new wpf -o PdfHogeWpf
dotnet sln add ./PdfHogeWpf/PdfHogeWpf.csproj
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/41d3899b-2d13-5e17-5258-5f5b93d65d38.png)
#### ◇NuGetパッケージの追加
コンソールと同じようにPdfiumViewerとSystem.Drawing.Commonを追加しておき、いったんビルドします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/42e07072-8b21-adb7-1bf4-d06c5867280f.png)
#### ◇xamlの編集
MainWindow.xamlにImageコントロールを記述します。ここにPDFの画像を表示させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/06b18523-5b64-aace-945f-b1b3531dc586.png)
#### ◇コードビハインドの編集
コードビハインドで画像を流しこみます。
```csharp:MainWindow.xaml.cs
using System.Drawing;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using PdfiumViewer;

namespace PdfHogeWpf;

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        string path = "sample.pdf";
        const int dpi = 96;
        const int ppi = 72;
        int pageNum = 0;
        BitmapSource bitmapSource;
        using (PdfDocument doc = PdfDocument.Load(path))
        {
            SizeF pageSize = doc.PageSizes[pageNum];
            int width = (int) (pageSize.Width * dpi / ppi);
            int height = (int) (pageSize.Height * dpi / ppi);
            Bitmap bitmap = (Bitmap) doc.Render(pageNum, width, height, dpi, dpi, false);
            nint hBitmap = bitmap.GetHbitmap();
            bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
                hBitmap, 
                nint.Zero, 
                Int32Rect.Empty, 
                BitmapSizeOptions.FromEmptyOptions());
        }
        image.Source = bitmapSource;
        this.Height = bitmapSource.Height;
        this.Width = bitmapSource.Width;
    }
}
```
#### ◇実行結果
デバッグするとこう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/fbf4980e-ae13-adce-8d83-e5aff63960b3.png)
ざらざらして荒く見えるのは解像度を上げればよくなります。


# 参考URL

https://mag.osdn.jp/14/05/27/163000

http://www.technocity.jp/Tips/CSharp/pdf_001.html

https://note.com/takase_hiroyuki/n/ne7117c13edea