指定されたPDFをページごとに分解、指定解像度の画像ファイル(PNGファイル)に変換したのち、指定ディレクトリに保存するWindows用プログラムを作成したので公開します。
ひとつのPDFから下図のように複数のPNG形式の画像ファイルに変換することができます。
※2022/02/03 14:00 GUI対応版を公開しました。
では、本当にそのまま画像化されているのか変換元のPDFをAcrobat Readerで確認してみます。
Acrobat Readerで変換元のPDFを表示したときは下図のように表示されます。
改ページがずれて次ページに少しだけはみ出てしまったパターンもそのまま画像化されていることが確認できます。
プログラムの流れとしては、以前記事にした『Microsoft OCRを用いてPDFからテキストを抽出する』とほぼ同じで、OCRエンジンに流していた画像を解像度指定でPNG形式に変換できるようにしました。
Visual Studio Professional 2019 Version 16.11.9
Windows 10 Ver. 21H1(ビルド 19043)
NYSL ( http://www.kmonos.net/nysl/ )
ソース: http://www.ria-lab.com/omiyage/PDF2PNG_1.0.0_SRC.zip
バイナリ(実行プログラム): http://www.ria-lab.com/omiyage/PDF2PNG_1.0.0_BIN.zip
このプログラムはOCRを実現するためWinRT APIを使用しています。
NuGetなどでMicrosoft.Windows.SDK.Contractsをインストールしてください。
Microsoft.Windows.SDK.Contractsをインストールするためにプロジェクトの形式をPackageReferenceに移行する必要があるかも知れません。
移行の手順は『packages.config から PackageReference への移行』に詳しく記載されています。
移行が行えない環境の場合は、UwpDesktopなどWinRT呼び出しのために必要なパッケージをプロジェクトに追加することで解決できる可能性があります。
// // PDFをページごとに画像変換(PNG形式)に変換するツール // // This software is distributed under the license of NYSL. // http://www.kmonos.net/nysl/ // // using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Interop; using System.Windows.Media.Imaging; using Windows.Data.Pdf; using Windows.Graphics.Imaging; using Windows.Storage.Streams; using BitmapFrame = System.Windows.Media.Imaging.BitmapFrame; namespace PDF2PNG { public class Program { [System.Runtime.InteropServices.DllImport("gdi32.dll")] private static extern bool DeleteObject(IntPtr hObject); /// <summary> /// /// </summary> /// <param name="args"> /// 0: PDF /// 1: 生成した画像ファイルの保存先(省略可。省略時PDFファイル名+タイムスタンプでフォルダ作成) /// 2: DPI(省略可。省略時300) /// </param> /// <returns></returns> public static int Main(string[] args) { if (args.Length < 1) { Console.Out.WriteLine("[使い方]"); Console.Out.WriteLine("PDF2PNG 変換元PDFファイルのパス [PNGファイルの保存先フォルダ] [DPI]\n"); Console.Out.WriteLine("・PNGファイルの保存先フォルダ省略時、変換元PDFファイルの存在するフォルダにPNG保存用フォルダを作成して使用"); Console.Out.WriteLine(" 生成されるフォルダ名: 《変換元PDFファイル名から拡張子を取り除いたもの》_《タイムスタンプYYYYMMDDHHMMSS形式》"); Console.Out.WriteLine("・DPI省略時、デフォルト値として300を使用"); return 1; } return _mainasync(args).Result; } /// <summary> /// /// </summary> /// <param name="args"></param> /// <returns></returns> private static async Task<int> _mainasync(string[] args) { // PDFファイルの場所 string pdfpath = args[0]; if (!System.IO.File.Exists(pdfpath)) { Console.Error.WriteLine($"指定されたPDFファイルが存在しません(PDF={pdfpath})"); return 1; } // PNGファイルの保存先 string savepath = (args.Length >= 2) ? args[1] : System.IO.Path.Combine(System.IO.Path.GetDirectoryName(pdfpath), $"{System.IO.Path.GetFileNameWithoutExtension(pdfpath)}_{DateTime.Now:yyyyMMddHHmmss}"); if (!System.IO.Directory.Exists(savepath)) { if (!System.IO.Directory.CreateDirectory(savepath).Exists) { Console.Error.WriteLine($"保存先ディレクトリの作成に失敗しました(PATH={savepath})"); return 1; } } // DPI int dpi; if (!int.TryParse((args.Length >= 3) ? args[2] : "300", out dpi)) { Console.Error.WriteLine("DPIは数値を設定してください"); return 1; } return await new Program().Perform(pdfpath, savepath, dpi); } /// <summary> /// /// </summary> /// <param name="pdfpath"></param> /// <param name="saveFolderPath"></param> /// <param name="dpi"></param> /// <returns></returns> public async Task<int> Perform(string pdfpath, string saveFolderPath, int dpi = 300) { // PNGファイルの基本ファイル名を決定 var basename = System.IO.Path.GetFileNameWithoutExtension(pdfpath); // PDFを読み込み、ページごとに画像に変換 using (var instream = new MemoryStream(System.IO.File.ReadAllBytes(pdfpath))) using (var inrastream = instream.AsRandomAccessStream()) { // 変数pdfdocは処理のあいだ開いていないとビットマップへのレンダリングに失敗する var pdfdoc = await PdfDocument.LoadFromStreamAsync(inrastream); for (uint pageIndex = 0; pageIndex < pdfdoc.PageCount; pageIndex++) { // ファイル名を決定 var imageFilePath = System.IO.Path.Combine(saveFolderPath, $"{basename}_{pageIndex + 1:0000}.png"); using (var pdfpage = pdfdoc.GetPage(pageIndex)) using (var outstream = new MemoryStream()) using (var outratream = outstream.AsRandomAccessStream()) { // ページの内容をBitmapにレンダリング var renderOptions = new Windows.Data.Pdf.PdfPageRenderOptions(); // 解像度などを指定のものに変換 renderOptions.DestinationWidth = (uint)((pdfpage.Size.Width / (96d / 72d)) * (dpi / 72d)); renderOptions.DestinationHeight = (uint)((pdfpage.Size.Height / (96d / 72d)) * (dpi / 72d)); await pdfpage.RenderToStreamAsync(outratream, renderOptions); // Bitmapの内容をPNGに変換 using (var image = System.Drawing.Image.FromStream(outstream)) { SavePng(ConvertToBitmapSource(image as Bitmap), imageFilePath); } } } } return 0; } /// <summary> /// BitmapをBitmapSourceに変換する /// </summary> /// <param name="bmp"></param> /// <returns></returns> private static System.Windows.Media.Imaging.BitmapSource ConvertToBitmapSource(Bitmap bmp) { using (var dest = new Bitmap(bmp.Width, bmp.Height)) using (var g = Graphics.FromImage(dest)) { g.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height); var hbitmap = dest.GetHbitmap(); BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(bmp.Width, bmp.Height)); DeleteObject(hbitmap); return bitmapSource; } } /// <summary> /// /// </summary> /// <param name="bitmapSource"></param> /// <param name="pngFilePath"></param> /// <returns></returns> private static bool SavePng(BitmapSource bitmapSource, string pngFilePath) { using (var outstream = new System.IO.FileStream(pngFilePath, System.IO.FileMode.Create)) { var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); encoder.Save(outstream); outstream.Flush(); } return true; } } }
※ソースコードから実行プログラムを作成するしたい場合、以下の手順で行うことができます。
※Visual Studioをお持ちでない場合、こちらからCommunity版が無償で入手可能です。
PDF2PNGは三種類の方法で実行することができます。
PDF2PNG.exe <変換元PDFのパス> [PNGファイルの保存先フォルダ] [DPI]
《変換元のPDFファイル名から拡張子を除いたもの》_《ページ番号(前ゼロ4桁)》.png
プログラムの実行時に第2パラメータの保存先フォルダを省略した場合、PDFファイルの存在するフォルダにPDFファイル名+タイムスタンプでフォルダを作成し、作成したフォルダに画像を保存します。
第3パラメータのDPIを省略した場合、デフォルト値として300を使用します。
エクスプローラ上で変換したいPDFをPDF2PNG.exeにドラッグアンドドロップします。
この場合DPIは300固定、PDFの存在するフォルダに画像保存用のフォルダが新たに作成されPNGファイルが格納されます。
※「送る」への追加方法は、NEC LAVIE公式サイトの『Windows 10で「送る」メニューに項目を追加する方法』に詳しく紹介されています。(NEC以外のパソコンでも使えるテクニックです)
[…] 『PDFをページごとに画像変換(PNG形式)するツール』にGUIをつけてみました。基本的な操作はコマンド版と同じで、変換元PDF、変換後の画像ファイル保存先、DPI(解像度)を指定し実行ボタンを押すと処理が始まります。画像ファイルに変換後、指定フォルダの内容をGUIアプリケーションの画面下部に一覧表示します。 […]