【MAGICK.NET】PDFを画像に変換する
昔の話だけど、ImageMagickというオープンソースを使ってPDFの変換を試みたことがある。
しかし、リファレンスが全く無かったのと、メモリリークが起こってしまい断念した。
今はImageMagickではなく、Magick.NETっていうオープンソース用のライブラリが公開されている。
以下からダウンロードできる。
Release Magick.NET 7.9.0.0 · dlemstra/Magick.NET · GitHub
ただ、これを動かすにはghostscriptをインストールする必要がある。
ポータブル版ではダメだった。
サービス終了のお知らせ
そんなわけで、それを使ってPDF変換をやってみることにした。
動作環境は.NET Framework4.0で、言語はVisual Basic.NET。
GhostScriptのバージョンは9.25。
Magick.NETのバージョンは、「Magick.NET-7.9.0.0-Q16-x64」を使用した。
x64のライブラリじゃないとメモリがパンクするような気がするし。
ちなみに
「Magick.NET-Q16-x64.dll」は参照として追加。
「Magick.NET-Q16-x64.Native.dll」はexeと同じ場所に配置した。
もちろん、ターゲットCPUはx64。
ソリューション構成はこんな感じ。
「Magick.NET-Q16-x64.Native.dll」は参照しないで置いとくだけ。
ちなみにビルドと一緒にコピーしてしまえば楽なので、「常にコピー」にした方がいい。
Visual Studio2017でやってるけど、基本的にIDEは下位バージョンでも変わらない。
とりあえず、FORMアプリケーション作って、LOADイベントで動かしてみる
Imports ImageMagick Public Class Form1 ''' <summary> ''' PDFをPNGイメージに変換する ''' </summary> ''' <param name="pdf_name">PDFファイルパス</param> ''' <param name="Export_name">返還後のファイル名(拡張子はいらない)</param> Public Function PDFTOPNG(pdf_name As String, Export_name As String, ByRef Optional ERRMSG As String = "") As Boolean '読み込み設定クラスのインスタンス化 Dim settings As New MagickReadSettings() '解像度の設定 settings.Density = New Density(300, 300) '全部読み込むとメモリが足りなくなるので1ページずつ読み込むために最初のインデックスを設定 settings.FrameIndex = 0 'カラータイプの設定 settings.ColorSpace = ColorSpace.sRGB settings.ColorType = ColorType.TrueColorAlpha 'アンチエイリアスは無効にしておく settings.StrokeAntiAlias = False settings.TextAntiAlias = False 'クラスのインスタンス化 Dim images As New MagickImageCollection() Try While True '再インスタンス化 images = New MagickImageCollection() 'PDFの読み込み images.Read(pdf_name, settings) 'EXIF情報を削除 images.Item(0).Strip() '解像度を大きくしているので半分にリサイズする images.Item(0).Scale(percentage:=50) 'ページ変数のカウントアップ settings.FrameIndex += 1 'PNG形式で保存設定 images.Item(0).Format = MagickFormat.Png 'PNGファイル書き出し images.Item(0).Write(Export_name & CStr(settings.FrameIndex) & ".png") 'ページの明示的開放 images.Item(0).Dispose() 'コレクションの明示的開放 images.Dispose() 'メモリがいっぱいになる可能性があるので明示的に開放したリソースを 'ガーベジコレションを強制的に起こすことによって解放 GC.Collect() End While Catch ex As Exception 'エラーとして検知されるとき、読み込んだPDFのページ数以上で読み込みを行った場合は終了とする If InStr(ex.Message, "Requested FirstPage is greater than the number of pages in the file") <> 0 Then ERRMSG = "" Return True Else ERRMSG = ex.Message Return False End If Finally '念のため、最後に解放しておく images.Dispose() GC.Collect() End Try End Function 'ロードイベント Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load Dim errmsg As String = "" If Not PDFTOPNG("C:\temp\test.pdf", "PDFIMG", errmsg) Then MsgBox(errmsg) End If End Sub End Class
一応、ネットで公開されているソースは基本的にC#で書かれていることが多いので、
参考にしたC#ソースをVBに書き換えて記述している。
世の中はやっぱり、C#なんだなと思った。
このソースは1ページずつ読み込んでPNG形式に保存している。
一気に読み込みこともできるんだけど、使用メモリが尋常じゃないほど増える。
62ページのPDFファイルがちょうどあったので、一気に変換しようとしたら
3GB以上もメモリを使用されてちょっと焦った。
PDF変換メソッドをクラスライブラリとかにすれば、ASP.NETでも組み込むことができるだろうな。
画像の劣化との戦いもあるけど、解像度をどう調整して、リサイズしていくかで奇麗になりそうだ。
また、PNG形式以外でも保存できるし、イメージをPDFに変換することもできるので、
結構、出来ることは広い。
でも・・・
これ、内部でghostscriptのコマンドが呼ばれてるだけなんだよね。
それが分かっていれば、ghostscript単体のみでなんでも行けてしまいそうな気がするな。