以前、 「PDFからテキストを抽出するプログラム」 で、様々なライブラリを組み合わせて 辛うじて動くレベルのものを何とか作りましたが、 PDF.js (HTML5 と Javascript の機能だけを用いて、PDFを読み込み、ブラウザの画面に表示できる Javascriptライブラリ) と、 V8 (Google Chrome用Javascriptエンジン)を繋ぎ合わせるだけで、同じようなものをもっと簡単に作れるのではないかと考え、 ちょっと試してみました。
結果、下記の処置で実現できましたので、成果物を公開します。
PDF.js でテキストをコピー&ペーストできる PDF であれば、テキストを抽出できるはずです。
私が作成した部分は BSD ライセンスとしました。他の部分はオリジナルのライセンスに従って下さい。
コマンドプロンプトで PDF ファイルを引数にしてソフトを実行すると、テキスト化された内容を標準出力に書き出します。
下記6ファイルで構成されています。
PDF.js は こちらの配布元 のPre-built版(v1.0.21)をダウンロードしました。 配布物の中にある pdf.js、pdf.worker.js の 2 点を使います。
PDFを読み込んでテキスト等を表示する処理を作る場合、特に制約がなければ PDFファイル読み込み→解析→結果表示 とストレートな処理の流れになるはずですが、 ブラウザでこの流れの通りに処理すると、特に PDF のページ数が多い場合やページ当たりのデータ量が多い場合などで、 しばらくブラウザが固まったような状態になってしまいます。 これを避けるため、PDF.js では、
といった感じで非同期処理をしています。 (なお、この処理をスマートに記述するために、Promiseパターンと呼ばれる方法を採っているようです。)
PDF.js を大修正することなく素の V8 で動かすためには、setTimeout による非同期処理を再現する必要があります。 postMessage.js と messageLoop.js の2つがこの役割を担っています。
postMessage.js の中には、 配列 timeout_queue の初期化と setTimeout 関数が入っていて、 setTimeout には、引数で与えられた関数を timeout_queue に追加する処理を記述してあります。
messageLoop.js の中には、 配列 timeout_queue の各要素を順番に実行する処理を記述してあります。
これを、postMessage.js、 pdf.js、 pdf.worker.js、 pdf2text.js (PDFのテキスト出力処理)、 messageLoop.js という順番で実行することで、上記の非同期処理と同じような流れで処理させることができるようになりました。
pdf.js には、 DOM(document.createElement(...) ) で pdf.worker.js を script要素として追加する処理が入っています。 また、pdf.worker.js も navigator オブジェクトから userAgent を取得して何らかの処理をしています。 素の V8 には DOM オブジェクトもnavigatorオブジェクトもありませんので、そのまま実行してもエラーとなってしまいます。 素の V8 で動作させる方法として、これらを再現するためのダミー関数、ダミーオブジェクト等を用意するという手もありますが、 今回は該当する処理をコメントアウトする方法で対処しました。 pdf.js や pdf.worker.js の他の場所にも同様の処理が含まれていますが、下記2箇所のコメントアウトをするだけでPDFからテキストに 変換する処理が動作しましたので、他の箇所はそのまま放置してあります。
関数の中身をコメントアウトし、callback() だけ無条件に実行するように変更
ブラウザ固有の処理のようなので不要と判断し、 checkSeacSupport() 関数、及びその呼び出し処理を全てコメントアウト
PDF.js のAPI を呼び出して PDF データを テキストに変換する処理を pdf2text.js (Javascript側) に、 PDFファイルを読み込んで ArrayBuffer オブジェクトに変換する処理、postMessage.js、 pdf.js、 pdf.worker.js、 pdf2text.js、 messageLoop.js の順に.js ファイルを読み込んで V8 に投げる処理、変換したテキストを printf で出力する処理を pdf2text_pdfjs_v8.cc (C++側) に、それぞれ記述してあります。
[PageInfo]
LastUpdate: 2015-08-15 17:54:24, ModifiedBy: mocchi_2012
[Permissions]
view:all, edit:admins, delete/config:admins