読者です 読者をやめる 読者になる 読者になる

アイデアの甕

アイデアを放り込んでおくと甕は腐臭を発しない

ローカルにダウンロードした日本語PDFをRubyとpopplerで読み込む際に出たエラーの解消法

Ruby

たのしいRuby 第5版

 

 

Rubyで日本語PDFを読み込みましょう。

 

qiita.com

 

d.hatena.ne.jp

 

先達の知恵を拝借。そういえば「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さんしかいない…はず(いつだって諸悪の根源の自分自身を除く)。

 

productforums.google.com

 

上記フォーラムで、似たような、関連ありそうな話題を発見。「やはりか」と思いFirefoxやIEで当のPDFをダウンロードするものの、状況は変わらず。

 

StringIO?、Tempfile?

挙動の違いはオブジェクトの違い!というわけで、openしたオブジェクトのクラスを調べてみる。

 

開いたファイルオブジェクトは StringIO もしくは Tempfile ですが OpenURI::Meta モジュールで拡張されていて、メタ情報を獲得する メソッドが使えます

library open-uri (Ruby 2.3.0)

 

 

あ、使ったことない奴や…。

 

と、いうわけで色々挙動を調べてみたりもしたのですが、解決に至らず。最終的には冒頭に示した方法で「バイナリファイルとして読み込む」ことでエラーは解消されました。

 

あまり大きな声では言えませんが…

 

open-uriライブラリの暗黙のエンコーディングやStringIOやTempfileなんかも、全部『たのしいRuby 第5版』に掲載されてますよ!

 

今一度、基礎固めしてみてはいかが?