Method of conversion from PDF to Text.
説明
PDFをテキストに変換しファイル出力を行います。
2種類の形式でテキスト出力するサンプルです。
サンプル:ExcelのVBA
- F8キーでステップ実行しながら動作確認出来ます。
- 事前に参照設定もして下さい。
001 Option Explicit
002
003 Sub CommandButton21_Click()
004
005 Dim objAcroApp As New Acrobat.AcroApp
006 Dim objAcroAVDoc As New Acrobat.AcroAVDoc
007 Dim objAcroPDDoc As Acrobat.AcroPDDoc
008 Dim lRet As Long
009 Dim jso As Object
010
011 'Acrobatアプリケーションを起動する。
012 lRet = objAcroApp.Show
013 'PDFファイルを開いて表示する。
014 lRet = objAcroAVDoc.Open("E:¥save_as_xml.pdf", "")
015 'PDDocオブジェクトを取得する
016 Set objAcroPDDoc = objAcroAVDoc.GetPDDoc()
017 'JavaScriptオブジェクトを作成する。
018 Set jso = objAcroPDDoc.GetJSObject
019
020 'PDFをアクセステキスト(accesstext)に変換する。
021 jso.SaveAs "E:¥test-01A.txt", "com.adobe.acrobat.accesstext"
022 'PDFをプレーンテキスト(plain-text)に変換する。
023 jso.SaveAs "E:¥test-01P.txt", "com.adobe.acrobat.plain-text"
024
025 'PDFファイルを閉じます。
026 lRet = objAcroAVDoc.Close(1)
027 'Acrobatアプリケーションを終了する。
028 lRet = objAcroApp.Hide
029 lRet = objAcroApp.Exit
030 'OLEを行うとAcrobatが不安定になるので
031 '一応オブジェクトを強制開放する。
032 Set objAcroPDDoc = Nothing
033 Set objAcroAVDoc = Nothing
034 Set objAcroApp = Nothing
035
036 End Sub
Highlight:プログラミング言語のソースコードを構文で色分け (GUI編)
補足
- Acrobat Readerでは出来ません。
Acrobat本体がデフォルトでインストールされているパソコン環境だけです。 - accesstext(アクセステキスト):
PDFに透明テキスト文字列があればテキスト変換されます。
改行があれば、その位置で改行してテキスト出力されます。 - plain-text(プレーンテキスト):
PDFの透明テキスト文字列があればテキスト変換されます。
改行コードは無視されます。
よって、2行が1行につながってテキスト出力され、文章としては読みずらいです。
ページによってはテキストに変換されない場合もあります。
この仕様は不明です。
Acrobat SDK 8.1にある「Extending the Acrobat SaveAsXML Plug-in」save_as_xml.pdf の場合は2ページ目の内容がテキストの最後に変換されてテキスト出力されます。
この形式に変換する目的も機能も当サイト管理者には理解出来ません。 - 上記サンプルでは objAcroApp.Show でAcrobatアプリ本体を起動表示しています。
これはjso.SaveAs メソッドを連続で行うときに発生する不可解なエラー回避策です。
高速化したいのならば objAcroApp.CloseAllDocs に置き換えて下さい。 - 当サンプルよりも以下の関数を利用してのテキスト変換をおすすめします。
「関数:PDFを特定のフォーマットに変換する」
当ページのサンプルよりも安全にテキスト変換が可能になります。
注意
- Acrobat SDK 8.1 に書かれているSaveAsメソッドの第2引数の説明が一部間違っています。
以下が正解です。
SDK:com.adobe.Acrobat.accesstext ※間違い
SDK:com.adobe.Acrobat.plain-text ※間違い
正解:com.adobe.acrobat.accesstext ※「a」1文字違う
正解:com.adobe.acrobat.plain-text ※「a」1文字違う
この情報は、"C:¥Program Files¥Adobe¥Acrobat 8.0¥Acrobat¥ExportTask.xml"ファイルに入っている内容から当サイト管理者が勝手に判断したものです。
この「ExportTask.xml」ファイルに関する説明はAcrobat SDKにはありません。 - 当サイト作成「Acrobat SDK:正誤表」も参考にして下さい。
- OSがインストールされているC:ドライブへの保存は出来ません。
詳細は、「Acrobat JavaScript における「Safe Path」についての注意事項」を参照。
動作確認環境
- WindowsXP Pro + SP3 +
Acrobat 8.1.6 Pro + Office 2003 + フルMicrosoftUpdate
< サンプル一覧 >
初めてメールします。アクロバットプロ11で大量のTIFファイルをPDF化しOCRをかけようとしています。アクションウィザードを使えば、一つのフォルダーの中にある全てのファイルに対し、上記の処理はできます。ところが、なぜか、OCRができないファイルがあるために、そこで、ファイルが開いたまま止まってしまいます。原因はよくわかりません。そこで、VBAでOCRをかけ、もしも、30分以上、かかってもOCRが終了しない場合は、とっとと、次のファイルのOCRをするようなプログラムを組めないかと思っています。あるいは、もっと、良い手軽かもしれませんが、教えてください。よろしくお願いいたします。
倉崎 さん。
はじめまして。
VBA等の言語に関係無く、AcrobatのOCR機能部分をプログラミング操作できる命令等の部分は見つかりません。
アクションウイザードの処理部分もプログラミング操作等が出来ないかと再調査しましたが、出来ないと、言うより出来る方法が見つかりませんでした。
OCR処理でフリーズ?した場合にスキップ処理をさせたいという部分は理解できますが。
TIFからPDFへ変換して、そのPDF上の文字画像をテキスト化をするにはAcrobat以外に選択肢は無いでしょう。
唯一知っているPDFのテキスト化ソフトに「読んde!!ココ」が有りますが、2012年9月30日を持って当ソフトは販売終了となりました。
※今でも大事に使ってますが(汗
「読取革命」と言うOCRソフトも有るらしいですが使った事を無いので仕様等は不明です。
何か倉崎さんの助けになる様な情報を思案しましたが、見つかりません。
残念です。
いろいろと、アドバイスを、ありがとうございました。
倉崎 さんへ。
前のコメントで「見つからない」と返答しましたが・・・。
以前から検討していた事が有り、現在はその手段が見つかっています。
と言っても「出来る」かはテストして見ないと分かりません。
1ヶ月前からのテストで、Acrobat 10 以下のバージョンのアクション処理(バッチ処理)のプログラミング操作が可能な状態になっています。
現在はその手法のドキュメント化(HTML)作業を行っています。
それと同じ手法を使えばOCRの起動と稼働の監視が可能かもしれません。
但し、Acrobat 11 に関してはアクション処理自体の仕様が下位バージョンと基本的に変わっているので、手法は同じですがプログラミング操作に関しては再検討(再作成)する必要が有る状態です。
この内容が伝わる事を祈っています。
倉橋さんへ、横から失礼します。
tiffを直接OCRにかけてはいけないのでしょうか。モノクロ2階調の印刷した文字なら、私見ではわりと優秀ですし、MSOfficeにもれなくついてきます。
http://office.microsoft.com/ja-jp/help/HP003083269.aspx
いろいろとアドバイスありがとうございます。
取り急ぎ、お礼を申し上げます。
いろいろと試してみます。
また、よろしくお願いいたします。
いつも参考にさせていただいており、大変助かっております。
質問なのですが、PDFの先頭ページのみをテキスト化する方法はございますでしょうか。
もしご存知でしたらご教示いただけますと幸いです。
どうぞよろしくお願いいたします。
きゃべつ さん
初めまして。
テキスト化時にページ指定は無いので、一時的に先頭ページ以外を削除します。
このページのサンプルの以下のコードの下に、
Set objAcroPDDoc = objAcroAVDoc.GetPDDoc()
以下を追加します。
'2ページ目から最後までを削除する
lRet = objAcroPDDoc.DeletePages(1, objAcroPDDoc.GetNumPages() - 1)
詳細はAcroExch.PDDoc: DeletePages メソッドを御覧ください。
なお、ページの削除をするので当ページのサンプルのように保存しないで閉じて下さい。
テキスト化まで動作確認してないですが、多分大丈夫でしょう。
参考になれば幸いです。
管理人様
ありがとうございます、期待していた動作となりました、助かりました。
もう1点質問なのですが、保護のかかったPDFファイル(開いたときにウィンドウ枠に 「~(ファイル名)~.pdf(保護) 」と出るタイプ)をテキスト化しようとすると、
「この操作は、この文書では許可されていません。」
とエラーポップアップが出て止まってしまいます。
保護ファイルはテキスト化できなくて問題ないので、
①SaveAs メソッドの前に保護されているかどうか確認するif文を設定する
②エラーが出た後にポップアップを消すプログラムを入れる
のいずれかで対応したいのですが、プログラムをお教えいただけませんでしょうか。
また、先ほどは記載しておらず申し訳ございませんでしたが、私の環境は以下となります。
OS:Windows 10 64bit
Acrobat:Adobe Acrobat 8 professional
Excel:2016
お忙しいところお手数ですが、何卒よろしくお願いいたします。
きゃべつ さんへ。
以下をお試し下さい。
Option Explicit
Sub CommandButton21_Click()
Dim objAcroPDDoc As New Acrobat.AcroPDDoc
Dim lRet As Long
Dim lPageCnt As Long
Dim jso As Object
Const CON_FILE = "I:¥AcroPDDoc¥Open\PasswordCopy.pdf"
Const CON_TEXT1 = "I:¥AcroPDDoc¥text1.txt"
Const CON_TEXT2 = "I:¥AcroPDDoc¥text2.txt"
lRet = objAcroPDDoc.Open(CON_FILE)
If lRet = 0 Then
'このPDFは文書を開くときにパスワードが必要です。
Debug.Print "PDFファイルはパスワードで保護されている。"
GoTo Skip_02:
End If
lPageCnt = objAcroPDDoc.GetNumPages()
lRet = objAcroPDDoc.DeletePages(1, lPageCnt - 1)
If lRet = 0 Then
'PDF文書はセキュリティ(パスワード)で保護されているので
' ページの削除は出来ない。
Debug.Print "PDFの編集は出来ない。"
GoTo Skip_01:
End If
Set jso = objAcroPDDoc.GetJSObject
'PDFをアクセステキスト(accesstext)に変換する。
jso.SaveAs CON_TEXT1, "com.adobe.acrobat.accesstext"
'PDFをプレーンテキスト(plain-text)に変換する。
jso.SaveAs CON_TEXT2, "com.adobe.acrobat.plain-text"
Set jso = Nothing
Skip_01:
lRet = objAcroPDDoc.Close
Skip_02:
Set objAcroPDDoc = Nothing
End Sub
・PDFファイルを開くときのパスワード付き
・PDF文書のコピー&編集に付いたパスワード付き
の2種類対応版です。
正確にPDFの文書プロパティの保護情報を調べたいときは上記のOLEを使用したサンプルでは無理です。
別途、コマンドラインの別ソフトが必要になる場合が有ります。
※例:qpdf.exe xxx.pdf --show-encryption > text.txt
※上記例のtext.txtの内容を読み込んで判断する。
各メソッドは該当ページを御覧ください。
希望通りの処理が出来るかの確認をお願いします。
お忙しい中ご回答いただきありがとうございます。大変助かります。
2ページ以上のPDFファイルについては今回お教えいただいたコードで希望の動作となることを確認いたしました。
ただし、1ページのPDFファイルのときは保護されていなくてもエラーとなってしまうので、似たようなロジックで回避してみました。
(貴サイトにあるものを色々試しましたが、今のところ使えそうなのがSaveメソッドしか見つかりませんでした。。)
ファイルが上書きされてしまうのが難点ですが、一旦別のフォルダにコピーしてから実行すればいいので最悪これでもいいかなと思っております。
もし、1ページのファイルに対しても使えるロジックをなにかご存知でしたら、再三で恐縮ですがお教えいただけると非常に助かります。
どうぞよろしくお願いいたします。
~
プログラムコードを記載したところエラーになってしまいましたが、
「lRet = objAcroPDDoc.DeletePages(1, lPageCnt - 1)」の下に
'別名でPDFファイルを保存する
lRet = objAcroPDDoc.Save(&H20, "C:\Users\temporary.pdf") 'なぜか~~.pdfで上書きされてしまう
を追加しました。
きゃべつ さんへ。
>・・1ページのファイルに対しても使えるロジック・・
If lPageCnt > 1 Then
lRet = objAcroPDDoc.DeletePages(1, lPageCnt - 1)
End If
とすればイイのでは?
objAcroPDDoc.GetNumPages()の結果が入ったlPageCnt にページ数が入っているので、1ページ以上の時のみ実行する。
lPageCnt の内容を見て処理をすればイイと思います。
ご回答いただき、ありがとうございました。
そちらのロジックですと、
1ページしかない&保護されているPDF
でポップアップを回避できなくなってしまうので断念いたしました。。
きゃべつ さんへ。
どうやら、私がうまく質問内容を理解できてないみたいです。
最初から読み返してみました。
>・・PDFの先頭ページのみをテキスト化する方法・・
これが最初の質問で一番の目的と見ました。
>・・保護のかかったPDFファイル・・・・エラーポップアップが出て止まってしまいます。
これもサンプルで 2箇所でlRetの結果を見て処理する、でOKと見ました。
>・・1ページのPDFファイルのときは保護されていなくてもエラーとなってしまう・・
これもlPageCntの判断で回避できる。ただし・・、
>・・がSaveメソッドしか見つかりません・・
この意味が不明です。なぜ保存する必要が有るのか?
テキスト化(のみ)が目的と思っていたのですが・・。
>ファイルが上書きされてしまうのが難点・・
サンプルは上書きしないで閉じています。
lRet = objAcroPDDoc.Close
どこで上書きするのでしょうか?
こちらの提示したサンプルは全ての要件を満たしておりません。
2ページ目以降を削除しているのは、テキスト化するときにページ指定が出来ないので、その対処方法としてです。削除したPDFを保存する必要は無いです。サンプルは保存せずに閉じています。
と書きましたが、「何か私が見落としている」のでしょう。
すこし時間を置いて、もう一度最初からコメントを見直すつもりです。
管理人様
お世話になっております。
読み返してみましたが、私の説明が明らかに不足しておりました。
大変失礼いたしました。
今回私が行いたいのは、
「PDFの1ページ目をテキスト化し、保存すること」
「ただし、保護がかかっているPDFについてはスキップすること」
です。
7/29にいただいたご回答(2ページ目以降を削除できるかどうかで、保護状況を確認する)で、
①保護なし複数ページPDF⇒テキスト化
②保護あり複数ページPDF⇒スキップ
③保護なし単ページPDF⇒【テキスト化】
④保護あり単ページPDF⇒スキップ
となり③のパターンでテキスト化できませんでした。
7/31にいただいたロジックを含めると
①②③はOKですが、④のパターンでエラーメッセージが出てしまいます。
("If lPageCnt > 1 Then" にひっかからず、テキスト変換まで進んでしまう)
7/31のコメントの意味としては、
「2ページ目以降を削除できるかどうかで、保護状況を確認する」を
「&H20で保存できるかどうかで、保護状況を確認する」と変更したら③もクリアできそうです、
(ただし、この確認を行う過程でPDFが上書きされてしまう)
という内容でした。
(3,4ファイル試しただけで、この方法ですべてのファイルの保護状況を確認できるかは疑問です)
最後の段落の内容があまりに突飛なため混乱させてしまったかと思います。
申し訳ございませんでした。
現在の質問としては、「保護状況を確認するためにもう少しいい方法はないか」でございます。
実行速度の観点からQpdfはなるべく避けたいと考えています。
長文・駄文で申し訳ございませんが、どうぞよろしくお願いいたします。
きゃべつ さんへ。
イチから見直しました。
Sub Call_PrintSave()
Dim objAcroPDDocNew As New Acrobat.AcroPDDoc
Dim objAcroPDDoc As New Acrobat.AcroPDDoc
Dim lRet As Long
Dim jso As Object
Const CON_FILE = "I:\AcroPDDoc\Open\NoPassword-1.pdf"
Const SAVE_FILE = "I:\AcroPDDoc\Open\temporary.pdf"
Const CON_TEXT1 = "I:\AcroPDDoc\Open\text1.txt"
Const CON_TEXT2 = "I:\AcroPDDoc\Open\text2.txt"
'① 空(0ページ)のPDFファイルを作成する
lRet = objAcroPDDocNew.Create()
'② 処理対象のPDFを開く
lRet = objAcroPDDoc.Open(CON_FILE)
If lRet = 0 Then
'※このPDFは文書を開くときにパスワードが必要です。
Debug.Print "PDFファイルはパスワードで保護されている。"
GoTo Skip_02:
End If
'③ 1ページ目を取り出し、空のPDFへ入れる(コピーする)
lRet = objAcroPDDocNew.InsertPages(-1, objAcroPDDoc, 0, 1, False)
If lRet = 0 Then
'※PDF文書はセキュリティ(パスワード)で保護されているので
' ページの抽出(コピー)は出来ない。
Debug.Print "PDFは保護されていて抽出は出来ない。"
GoTo Skip_01:
End If
'④ 1ページ目からテキストを取り出す
Set jso = objAcroPDDocNew.GetJSObject
'PDFをアクセステキスト(accesstext)に変換する。
jso.SaveAs CON_TEXT1, "com.adobe.acrobat.accesstext"
'PDFをプレーンテキスト(plain-text)に変換する。
jso.SaveAs CON_TEXT2, "com.adobe.acrobat.plain-text"
lRet = objAcroPDDocNew.Close()
Set jso = Nothing
'⑤ PDFを保存する。
lRet = objAcroPDDoc.Save(&H1 + &H20, SAVE_FILE)
'⑥ 保護(ページの編集)のチェックを行う。
' ※この処理は保険です。
If objAcroPDDoc.GetNumPages() > 1 Then
'2ページ目のみ削除する。※時間の短縮
lRet = objAcroPDDoc.DeletePages(1, 1)
If lRet = 0 Then
'※PDF文書はセキュリティ(パスワード)で保護されているので
' ページの削除は出来ない。
Debug.Print "PDFは保護されていて編集(ページ削除)は出来ない。"
'以前に保存したファイルを削除する
Kill CON_TEXT1
Kill CON_TEXT2
Kill SAVE_FILE
End If
End If
Skip_01:
lRet = objAcroPDDoc.Close
Skip_02:
Set objAcroPDDocNew = Nothing
Set objAcroPDDoc = Nothing
End Sub
説明:
① ゼロページの空のPDFを仮に作ります。
OLEではゼロページのPDFを基本的に許しませんが、ココだけはOKです。
② 処理したいPDFを開きます。※「AのPDF」とこの後は呼びます。
③ AのPDFの1ページ目を空のPDFへコピーします。
ここで「抽出」の保護が有れば、エラー扱いにします。
④ 1ページがコピーされた空のPDFを使って、テキスト化を行います。
⑤ AのPDFを別名で保存します。
別名で保存する時は引数に「&H1」が必要です。無いと別名は無視されて上書きされます。
⑥ は保険です。
「編集」の保護がかかっている場合は保存したテキストとPDFを削除します。
「抽出(コピー)」出来て、「編集(削除)」が出来ないPDFには出会ったことは無いですが、100%無いと言う保証はないので入れました。不要ならば削除して下さい。
Qpdfを使って厳密に保護情報をチェックしない場合は、少しカッコ悪い形ですが、処理速度を考えると、こうなるのかな?、と思いました。
ご検証ください。
管理人様
お世話になっております。
おかげさまでようやく意図していた動作を確認することができました。
”objAcroPDDoc.Open(CON_FILE)” の部分で若干動作がもたつく傾向がありますが、
こればかりは仕方ないですね。
根気強くご説明いただき、大変感謝しております。
本当にありがとうございました。
またなにかございましたら相談させてください。
きゃべつ さんへ。
お役に立てて、嬉しいです。
初めまして。
別サイトでまことに恐縮なのですが、こちらのサイト
https://www.sejuku.net/blog/99122
を参考にしながらpdfの表データを、vbaを使ってexcelに取り込もうとしておりました。
pdfを取り込む部分が本記事にある処理と同様であったので、よろしければご教示いただきたいと存じます。
処理を実行しておりますが、テキストデータが生成されません。
当方Acrbat ProとOffice365使用です。参照設定ができていることは確認いたしました。ほかに何か足りない設定などございますでしょうか?
K さん はじめまして。
実際にVBAを動かして見ました。
A1.フォルダ指定の部分が間違っています。
【間違い】
Const folderPath = "C:UsersSamuraiDesktop部分一致テスト"
【正解】
Const folderPath = "C:¥UsersSamuraiDesktop部分一致テスト¥"
VBAソースをサイト記事内にペーストした時に「 ¥ 」部分をHTMLエンティティ文字として判断され、画面上から削除されたと考えられます。「HTMLあるある」です。
A2.その他で考えられるケースとしてPDF上では表に見えても、実は画像だったと言う事も有ります。人から見たら表内のテキスト文字ですが、PDFファイル内はただの画像の点の集まりなので文字としての抽出は出来ません。画像内の文字をスキャンすれはイイのでは?と思いますが、Acrobatにはその様な超高機能は有りません。
※他のツールを併用すればある程度は可能ですが、ピッタリの情報はネット上には存在しません。
A3.VBA内の「"com.adobe.acrobat.plain-text"」部分はAcrobatのバージョン7.0以下では使えないはずです。多分、大丈夫だとは思うのですが。
A4.エラー処理を入れれば、A1の問題は起きません。
AcrobatId = objAcrobatAVDoc.Open(pdfFilePath, "")
を
AcrobatId = objAcrobatAVDoc.Open(pdfFilePath, "")
If AcrobatId <> -1 Then MsgBox "PDF Fileが無い。"
とした方がいいです。
A5.PDFの「文書のプロパティ」->「セキュリティ」で「ページの抽出」が「許可しない」になっている。つまり、PDFファイルのセキュリティ設定で取り出せないになっている。
ご確認ください。
それと、以下の行は不要です。AcrobatId = objAcrobatApp.Show
デバック用なので削除して構いません。処理速度が大幅にアップします。
以下の行を
AcrobatId = objAcrobatApp.Show
以下に変更してください。
AcrobatId = objAcrobatApp.CloseAllDocs
理由は処理速度UPと、エラー対策です。VBA処理中に実行エラー等で中断するとAcrobatプロセスがメモリに残り、次回Acrobat起動時に「PDFファイルが既に開かれています」等の不可解なエラーが多数出ます。PDFファイルが既に開かれて無い状態でCloseAllDocsを実行してもエラーにはなりません。更に、これを最初に実行する事により様々なトラブルも回避できます。特に複数のPDFを連続で処理する場合は処理前にこの命令は必須になってきます。(経験談+これ以上の詳細は省略)