1995年2月に最初のバージョンが登場し、
当時のアプリケーション開発に変革をもたらした「Delphi」が、2025年2月に30周年を迎えます。
当時はまだInternet ExplorerもYahoo!もGoogleも存在せず、Windows 95も発売前。
そこから30年の長きにわたってDelphiが愛されてきた要因の一つには、
機能拡張やサードパーティ製品が数多く登場し、その発展を支えてきたことが挙げられるでしょう。
今回はそんな拡張機能の中から、
PDFから画像や文字を抽出できるツール「PDFium」を紹介します。
PDFiumの概要
『PDFium』はChromeで利用されているPDFレンダリングエンジンです。
(pdfium – Git at Google)
読み方は諸説ありますが、海外の動画だと
「ピーディーエフィアム」や「ピーディーエファイウム」と発音されていました。
Apacheライセンスなので商用利用も可能です。
このライブラリを使用して、
DelphiのFireMonkeyアプリケーションでPDFの読み込みや出力が可能になります。
PDFium Component Suiteのダウンロード
今回使用するPDFium Component Suite for FireMonkeyは、
スロバキアのWinSoft社が開発した、PDFiumをDelphiで使用するためのコンポーネント スイートです。
Windows向けはFireMonkeyが利用可能な各バージョンに対応していますが、
iOS・Android向けのライブラリはDelphi/400 10.4 Sydney以上での対応となっています。
【エンバカデロ社の紹介記事】
PDFium – Delphi/C++Builder FireMonkeyアプリケーション向けPDFエンジン
(インストール動画:WinSoft PDFium for FireMonkey – Install Guide)
概要は上記の紹介記事にもありますが、
ここからは導入手順を紹介していきます。
WinSoft社のHPにあるこちらのページにアクセスし、
『Download PDFium for FireMonkey 6.9 trial version』をクリックしてダウンロードします。
デモプログラムをダウンロードしたい場合は、それぞれのリンクをクリックします。
上記のtrial versionのリンクをクリックすると
『fpdfium.exe』がダウンロードされます。
こちらをダブルクリックで起動してインストールを行います。
なお、「trial version」とある通り評価版のため、
EXE起動後最初の処理時には以下のような評価版であることを示す
ダイアログが表示されますが、処理結果には影響はありません。
(購入時の価格等詳細は公式サイトをご確認ください。)
PDFium Component Suiteを使って画像抽出
DelphiのFireMonkeyアプリケーションを新規作成したら、
画面に『TFPdf』および各コンポーネントを配置します。
以下のようにイベントを定義し、ロジックを記述します。
TFPdfコンポーネントを使って、PDFをページ単位で画像に出力できます。
出力直前のロジック(①②部分)で出力画像の幅と高さを変更できます。
また、保存時のファイル名によって画像の形式(JPG/PNG)を変更できます。(③部分)
uses FMX.BehaviorManager; // uses節追加
{*****************************************************************************
画面生成時処理(初期設定)
*****************************************************************************}
procedure TFormMain.FormCreate(Sender: TObject);
var DeviceBehavior: IDeviceBehavior;
begin
PixelsPerInch := 96;
if TBehaviorServices.Current.SupportsBehaviorService(IDeviceBehavior, DeviceBehavior, Self) then
PixelsPerInch := DeviceBehavior.GetDisplayMetrics(Self).PixelsPerInch;
end;
{*****************************************************************************
Convert JPG ボタン押下時処理(PDFと同階層にページ毎に出力)
*****************************************************************************}
procedure TFormMain.ButtonConvertClick(Sender: TObject);
var
I: Integer;
FileName: string;
Bitmap: TBitmap;
begin
ProgressBar.Value := 0;
EditPdfFile.Enabled := False;
ButtonText.Enabled := False;
ButtonConvert.Enabled := False;
FormMain.Cursor := crHourGlass;
try
FPdf.FileName := EditPdfFile.Text;
FPdf.PageNumber := 0;
FPdf.Active := True;
ProgressBar.Max := FPdf.PageCount;
FileName := ExtractFileName(FPdf.FileName);
FileName := Copy(FileName, 1, Length(FileName) - Length(ExtractFileExt(FPdf.FileName)));
FileName := ExtractFilePath(FPdf.FileName) + FileName;
for I := 1 to FPdf.PageCount do
begin
FPdf.PageNumber := I;
Bitmap := FPdf.RenderPage(0, 0,
Round(PointsToPixels(FPdf.PageWidth, PixelsPerInch)), // ①出力画像の横幅
Round(PointsToPixels(FPdf.PageHeight, PixelsPerInch))); // ②出力画像の高さ
try
Bitmap.SaveToFile(FileName + '_Page' + IntToStr(I) + '.jpg'); // ③拡張子はpngも対応
finally
Bitmap.Free;
end;
ProgressBar.Value := I;
Application.ProcessMessages;
end;
finally
FormMain.Cursor := crDefault;
FPdf.Active := False;
EditPdfFile.Enabled := True;
ButtonText.Enabled := True;
ButtonConvert.Enabled := True;
end;
end;
例えば弊社テクニカルレポートのPDFをこのロジックで
画像にして出力した場合、このようなイメージになります。
PDFium Component Suiteを使ってテキスト抽出
次はTFPdfコンポーネントを使って、PDF内の文字を抽出します。
抽出可能なのはPDF内に文字データとして埋め込まれている文字列のみです。
PDF内の画像に書かれている文字を認識させる機能はありません。
{*****************************************************************************
Convert TEXT ボタン押下時処理(画面下部のTMemoに出力)
*****************************************************************************}
procedure TFormMain.ButtonTextClick(Sender: TObject);
var
I: Integer;
Text: RawByteString;
FileName: string;
begin
FPdf.FileName := EditPdfFile.Text;
FPdf.PageNumber := 0;
FPdf.Active := True;
ProgressBar.Max := FPdf.PageCount;
FileName := ExtractFileName(FPdf.FileName);
FileName := Copy(FileName, 1, Length(FileName) - Length(ExtractFileExt(FPdf.FileName)));
FileName := ExtractFilePath(FPdf.FileName) + FileName;
try
for I := 1 to FPdf.PageCount do
begin
FPdf.PageNumber := I;
Text := UTF8Encode(FPdf.Text);
if Text <> '' then
begin
Memo1.Lines.Add(Text);
end;
ProgressBar.Value := I;
Application.ProcessMessages;
end;
finally
FPdf.Active := False;
end;
end;
例えば弊社テクニカルレポートのPDFから文字抽出した場合、
このようなイメージでMemoに出力されます。