2009/05/22

AndroidでPDFが読みたいのだけど…

AndroidでPDFファイル読む時って、皆さんどうしているのでしょう?

Android Dev Phone 1(以下ADP1と記述)でAndroid Marketを探したりネットで検索してみるとPDFを読むためのアプリ(Viewer, Reader)がいくつか見つかるのですが、私の環境では読みたいPDFファイルを読むことができません。

仕方ないので、GIMPでPDFファイルをインポートしてContinus SaveというScript-fuを使用して複数のPNGファイルに変換し、Picturesという画像ビューアで読んでいました。

ところが、やはり画像ビューアでは文章を読むのに適しているとは言えません。
読む前に必ず画像の拡大をしなければならなかったり、画像を拡大しようとしたのにタッチした場所が悪くて次のファイルに移ってしまったり…。


そこでAndroid Marketに登録されているDroid Comic Viewer(以下ACVと記述)というアプリケーションを使ってみることにしました。
Droid Comic Viewer | Robot Comics [www.robotcomics.net]

ACVは複数の画像ファイルを集めた書庫ファイルを開いて読むことができます。
書庫形式はCBZ, ZIP及びACV、画像形式はJPEG, PNG, BMP 及び GIFに対応しているようです。

私はPDFをPNGに変換し、ZIPでまとめることにしました。


GIMPでContinus Saveを使用して複数のPNGファイルにエクスポートしたものをZIPにまとめればとりあえずは読めるのですが、面倒です。

PDF -> 複数の画像ファイル -> ZIP
と変換することができるUNIX用のアプリケーションを検索してみたのですが見つかりません。

無いものは作ろうということで、Ubuntu 9.04 で動作するシェルスクリプトを勉強がてら作ってみました。
内容は全く保証できませんが、とりあえず目的は果せたようです。

自分の作ったシェルスクリプトでは次を内部で実行しています。
  • pdftoppm (XPDFに含まれるらしい)
    PDFファイルをPPMファイルに変換する

  • convert (ImageMagickに含まれる)
    PPMファイルをPNGファイルに変換する

  • zip
    ZIPファイルにまとめる


シェルスクリプト内で気になっている点は次のとおりです。
「こんなことする必要はない」とか「ここはこうすればもっと良くなる」とか色々あるんでしょうが、よく分かりません。
  • 第一引数はPDFファイル、オプションとして第二引数で作成されるPNGファイルの横幅を指定する
    変換前のPDFファイルがあまりに大きいサイズだとACVで読む時に字がつぶれてしまいます
    800くらいが良いみたい

  • mktempコマンドで一時ディレクトリを作成して作業する

  • 第一引数がPDFファイルかどうかは次の構文で拡張子から判定している
    case $ARG1 in
    *.[Pp][Dd][Ff])

    ;;
    *)

    ;;
    esac

    合っているかな?

  • 第二引数が数字かどうかは次の構文で判定している
    if echo "$2" | grep -E '^[0-9]+$' >/dev/null 2>&1; then


解決できていない問題は次のとおりです。
  • pdftoppm実行時に次のようなエラーが出るPDFファイルがある
    Error: Illegal entry in bfchar block in ToUnicode CMap
    スクウェア・エニックスのアニュアルレポートで発生しましたが、特に問題なくACVで読むことはできるみたいです

  • pdftoppm、convertやzipの実行結果が失敗していることは考慮していない

  • 英語はテキトー


以下はコードです。
段々と直していきます。
#!/bin/sh
MKTEMP=$(which mktemp)
PDFTOPPM=$(which pdftoppm)
CONVERT=$(which convert)
ZIP=$(which zip)

EXECDIR=$PWD
WIDTH_VALUE=''

# check argument
echo '*** checking argument... ***'
if [ $1 ] ; then
ARG1=$1
if [ -f $ARG1 ] ; then
# $ARG1 is a file
case $ARG1 in
*.[Pp][Dd][Ff])
# $ARG1 is a PDF file
echo 'SUCCESS: '$ARG1' is a PDF file'
ZIPFILE=$EXECDIR'/'${ARG1%.[Pp][Dd][Ff]}.zip
BASENAME=${ARG1%%.*}
if [ -f $ZIPFILE ] ; then
echo 'ERROR: '$ZIPFILE' is already exist'
exit
else
if [ $2 ] ; then
if echo "$2" | grep -E '^[0-9]+$' >/dev/null 2>&1; then
WIDTH_VALUE=' -resize '$2' '
else
echo 'ERROR: '$2' is not a number'
exit
fi
fi
fi
;;
*)
echo 'ERROR: '$ARG1' is not a PDF file'
exit
;;
esac
else
# $1 is not a file
echo 'ERROR: '$ARG1' is not a file'
exit
fi
else
# $1 is not
echo 'usage: '$0' PDF-file [Image-width]'
exit
fi

echo
echo '*** checking program... ***'

if [ -x $PDFTOPPM ] ; then
echo 'SUCCESS: find '$PDFTOPPM
else
# cannot find pdftoppm
echo 'ERROR: cannot find pdftoppm'
exit
fi

if [ -x ${CONVERT} ] ; then
echo 'SUCCESS: find '$CONVERT
else
# cannot find convert
echo 'ERROR: cannot find convert'
exit
fi

if [ -x ${ZIP} ] ; then
echo 'SUCCESS: find '$ZIP
else
echo 'cannot find zip'
exit
fi

if [ -x ${MKTEMP} ] ; then
echo 'SUCCESS: find '$MKTEMP
else
echo 'ERROR: cannot find mktemp'
exit
fi

# create temporary directory
echo
echo '*** create temporary directory... ***'
TMPDIR1=$(mktemp -d)
if [ -d $TMPDIR1 ] ; then
echo 'SUCCESS: mktemp -> '$TMPDIR1

TMPDIR2=$(mktemp -d)
if [ -d $TMPDIR2 ] ; then
echo 'SUCCESS: mktemp -> '$TMPDIR2
else
echo 'ERROR: mktemp distination directory error'
fi
else
echo 'ERROR: mktemp error'
fi

echo
echo '*** converting pdf to ppm... ***'
$PDFTOPPM $ARG1 $TMPDIR1'/'$BASENAME

# cd temporary directory
cd $TMPDIR1

echo
echo '*** converting ppm to png... ***'
for i in *.ppm ; do
echo $i' to '$TMPDIR2'/'${i%.ppm}'.png'
$CONVERT $WIDTH_VALUE $i $TMPDIR2'/'${i%.ppm}.png
done

# archive
echo
echo '*** archiving... ***'
cd $TMPDIR2
$ZIP $ZIPFILE *

echo
echo '*** cleaning '$TMPDIR1'... *** '
rm -rf $TMPDIR1
echo '*** cleaning '$TMPDIR2'... *** '
rm -rf $TMPDIR2

exit


ADP1でPDFファイルを読みたいだけなんだけどなぁ…。
何でこんなことやってるのだろう?

0 件のコメント: