iTextSharp というオープンソースライブラリを使うことで PDF ファイルを操作する事ができます。
PDFファイルに埋め込まれている画像を取り出してみようと思います。
iTextSharpのインストール
先ずは iTextSharp をインストールします。
インストール方法は「C#でPDFファイルを操作する 準備編 (iTextSharp)」を参照してください。
サンプルコード
using System;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using iTextSharp.text.pdf;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
PDFtoImage(@"C:\test.pdf", @"C:\images\");
}
static void PDFtoImage(string pdfName, string imgFolder)
{
var imgName = Path.GetFileNameWithoutExtension(pdfName);
var pdf = new PdfReader(pdfName);
var images = new List<PdfObject>();
int n = pdf.NumberOfPages;
for (int i = 1; i <= n; i++)
{
PdfDictionary pg = pdf.GetPageN(i);
CollectImage(pg, images);
}
for (int i = 0; i < images.Count; ++i)
{
var obj = (PRIndirectReference)images[i];
var pfdStream = (PRStream)pdf.GetPdfObject(obj.Number);
byte[] bytes = PdfReader.GetStreamBytesRaw(pfdStream);
var name = string.Format("{0}{1}_{2}.jpg", imgFolder, imgName, i);
File.WriteAllBytes(name, bytes);
}
}
static void CollectImage(PdfDictionary dic, List<PdfObject> images)
{
var res = (PdfDictionary)PdfReader.GetPdfObject(dic.Get(PdfName.RESOURCES));
var xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
if (null != xobj)
{
foreach (PdfName name in xobj.Keys)
{
PdfObject obj = xobj.Get(name);
if (obj.IsIndirect())
{
var tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
var type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));
if (PdfName.IMAGE.Equals(type))
{
images.Add(obj);
}
else if (PdfName.FORM.Equals(type))
{
CollectImage(tg, images);
}
else if (PdfName.GROUP.Equals(type))
{
CollectImage(tg, images);
}
}
}
}
}
}
}
PDFを開く (22行目)
PdfReaderクラスのインスタンスを作成してPDFファイルを開きます。
PDF内の画像オブジェクトを収集する (23~29行目、42~70行目)
PDF内の様々な要素は PdfObject オブジェクトとして管理されています。
画像タイプの PdfObject オブジェクトを収集する為に「CollectImageメソッド」を作成しました。
PDF内の要素は階層構造となっている場合があるので、CollectImageメソッドは再帰的に呼び出されるようになっています。
データをbyte配列で取得して保存する (33~38行目)
GetStreamBytesRawメソッドで画像タイプの PdfObject からデータを byte配列で取得します。
取得したByte配列をそのままファイルへ書き出しています。
※残念ながらこれだけでは、一部の画像しか正しく取得する事は出来ません
※もう少し工夫が必要なようです

コメント
コメントを投稿