ローカルにダウンロードした日本語PDFをRubyとpopplerで読み込む際に出たエラーの解消法
Rubyで日本語PDFを読み込みましょう。
先達の知恵を拝借。そういえば「poppler-data」に関しての試行錯誤もあったので、機会があればまた書きます。→ 書きました。「Windows上のRubyで日本語PDFを読むためにpoppler-dataをインストールする方法」
で、上記「ねこのここねこ」さんが示すサンプルを打ち込み、無事コンソールに日本語PDFの内容が日本語で示されましたとさ。
めでたしめでたし…じゃないんですね、これが。
PDFをダウンロードしたら、読めなくなった。
サンプルで使用したPDFファイルをブラウザ(Chrome)でダウンロードして、ローカル環境(実行rbファイルと同一ディレクトリ)に置いて読み込んでみた。
require 'poppler' slide = Poppler::Document.new(open("i2document2.pdf").read) puts slide.first.get_text;
そしたら、出るわ出るわ。エラーのオン・パレード。
PDF document is damaged (GLib::Error)
Poppler-INFO **:Syntax error at position -1: Couldn't read xref table
Poppler-INFO **:Syntax error at position -1: Couldn't find trailer dictionary
今やってみると、このようなエラーが吐き出されます。
※どっかでInvalid XRef entry
というエラーも見たのだけれど、今は再現できない…。
追記:
あー、テスト用のコードだとPoppler::Documentをeachメソッドであーだこーだするために.firstを使ってなかったわ!たぶんInvalid XRef entry
はこっちのエラーでした。
解決策
で、何が起こっていたかというとKernel.#openがちゃんとopenできてなかったようで。
というか、上記リンク先のサンプルでは(httpなんで当然ですが)標準ライブラリの'open-uri'が利用されていて、問題を暗黙に解決していたようです。
そう、暗黙に。
こちらの話は『たのしいRuby 第5版』の397ページに記載されています。
また、open-uriライブラリなどを使い、ネットワーク越しにファイルを取得する場合、その文字コードが分からない場合があります。その場合にも、エンコーディングはASCII-8BITになります。
# encoding: utf-8 require 'open-uri' str = open("http://www.example.jp/").read p str.encoding #=> #<Encoding:ASCII-8BIT>
で、さきほどのローカルでopenしてreadしたPDFファイルは、エンコードとしてUTF-8が指定されていたわけでして。
こちらはopen-uriライブラリを用いないネイティブopenになるので、明示的にエンコードを指定しなければならないようです。
ただ、今回の場合はASCII-8BITにはBINARYという別名があると『たのしいRuby』には記載がありまして、openのオプションに"rb"を指定してやると(デフォルトでは"r")。読み込み時に「バイナリの"b"!」をしてやるとエンコードがASCII-8BITになるようです。
slide = Poppler::Document.new(open("i2document2.pdf", "rb").read)
こうしてやると、ちゃんと読み込んで中身も日本語で表示することが出来ました。
そう、いつだって日本語読み書きの問題はエンコーディングに隠蔽されている…のかもしれない。
以下、試行錯誤の記録
PDFの構造なんてよく分かってないので、.pdfファイルをテキストエディタで開くことができるなんて、初めて知りました。
まぁそんな感じなので、行き当たりばったりというか、試行錯誤も暗中模索も日常茶飯で今思えばふふふ、となるようなところの壁に頭をぶっつけたのやなぁ(しみじみ)。
Google Chromeのせい?
まず疑ったのは、ダウンロードしている輩(Chromeさん)が悪さ(ファイル改変)しているんじゃないかと。だって、同じファイルのはずなのに読み込めないとしたら、関わったのはChromeさんしかいない…はず(いつだって諸悪の根源の自分自身を除く)。
上記フォーラムで、似たような、関連ありそうな話題を発見。「やはりか」と思いFirefoxやIEで当のPDFをダウンロードするものの、状況は変わらず。
StringIO?、Tempfile?
挙動の違いはオブジェクトの違い!というわけで、openしたオブジェクトのクラスを調べてみる。
開いたファイルオブジェクトは StringIO もしくは Tempfile ですが OpenURI::Meta モジュールで拡張されていて、メタ情報を獲得する メソッドが使えます
あ、使ったことない奴や…。
と、いうわけで色々挙動を調べてみたりもしたのですが、解決に至らず。最終的には冒頭に示した方法で「バイナリファイルとして読み込む」ことでエラーは解消されました。
あまり大きな声では言えませんが…
open-uriライブラリの暗黙のエンコーディングやStringIOやTempfileなんかも、全部『たのしいRuby 第5版』に掲載されてますよ!
今一度、基礎固めしてみてはいかが?