‘epubcheck’ タグのついている投稿

EPUB用IVS/サロゲートペア文字チェッカーを作ってみた

2013/05/07

 前回のエントリで書かせていただいた通り、現状IVS/サロゲートペア文字はビューアの表示でトラブルになるケースが多いため、EPUB3データの中にIVS/サロゲートペア文字が混入していないかどうかチェックするためのチェッカーを作ってみました。また、三分スペース(THREE-PER-EM SPACE/U+2004)などのJIS X0213に符号位置割り当てのないスペース文字が一部のリーディングシステムで文字化けするとのお話がありましたので、こちらのチェックもできるようにいたしました(ある方よりご要望をいただいたため機能を追加しました)。
 引数としてEPUBファイルのパスを与えてやると内容をチェックしてログを出力するだけの簡単なものですが、制作の役に立てていただければ幸いです。

 Mac、Winともに使用することは可能ですが、環境によってはモジュールの追加インストールが必要になるかも知れません。私の環境ではWindowsのActivePerl環境にMinGWモジュールを追加インストールする必要がありました(コマンドプロンプトで「ppm install MinGW」と入力)。

use utf8;

#Encodeモジュールをインポート

use Encode qw/encode decode/;

use File::Basename qw/basename dirname/;

use Archive::Zip;

use Archive::Extract;

use File::Path;

#引数1で指定したepubファイルを取得

$epubFilePath = $ARGV[0];

$epubFilePath = decode(‘UTF-8’, $epubFilePath);

my $epubFileName = basename $epubFilePath;

###################チェック用一時epubファイルのパスを取得###################

my $epubpackage = Archive::Zip->new();

die unless $epubpackage->read($epubFilePath) == Archive::Zip::AZ_OK;

#パスリスト変数の定義

my @xhtmlfilePaths;

my @files = $epubpackage->members();

foreach my $file (@files) {

push(@xhtmlfilePaths,$file->fileName) if ($file->fileName =~ /^(.*?)\.xhtml$/);

}

###################チェック用一時ファイル解凍処理###################

my $uniqueFolderPath = ‘/tmp/’ . $epubFileName;

#同一フォルダが存在したら連番をつける処理

my $mynum = 1;

if (-d $uniqueFolderPath){

while (-d $uniqueFolderPath){

$uniqueFolderPath = (‘/tmp/’ . $epubFileName . ‘_’ . $mynum);

$mynum++;

}

}

#解凍実行

my $epubArchive = Archive::Extract->new(archive => $epubFilePath,type => ‘zip’) or die;

$epubArchive->extract(to => $uniqueFolderPath);

###################文字チェック処理###################

#ログ出力用変数定義

our $finalSarrogatePairOutputLog = “”;

our $finalIVSOutputLog = “”;

our $finalIrregularSpaceOutputLog = “”;

#各xhtmlファイルを展開

foreach $myXhtmlfilePath (@xhtmlfilePaths){

&eachFileProceed($myXhtmlfilePath);

}

###################ログにタイトル部分を合成###################

if ($finalSarrogatePairOutputLog eq “”){

$finalSarrogatePairOutputLog = ‘##SarrogatePair Character Check Result : ‘ . “\r\n” . ‘OK! Not Any SarrogatePair Characters in EPUB File!’;

} else {

$finalSarrogatePairOutputLog = ‘##SarrogatePair Character Check Result : ‘ . “\r\n” . $finalSarrogatePairOutputLog;

}

if ($finalIVSOutputLog eq “”){

$finalIVSOutputLog = ‘##Unicode IVS Character Check Result : ‘ . “\r\n” . ‘OK! Not Any Unicode IVS Characters in EPUB File!’;

} else {

$finalIVSOutputLog = ‘##Unicode IVS Character Check Result : ‘ . “\r\n” . $finalIVSOutputLog;

}

if ($finalIrregularSpaceOutputLog eq “”){

$finalIrregularSpaceOutputLog = ‘##Irregular Space Character Check Result : ‘ . “\r\n” . ‘OK! Not Any Irregular Space Characters in EPUB File!’;

} else {

$finalIrregularSpaceOutputLog = ‘##Irregular Space Character Check Result : ‘ . “\r\n” . $finalIrregularSpaceOutputLog;

}

###################チェック用一時ファイルの削除###################

rmtree($uniqueFolderPath);

###################ログ出力###################

my $logOutputPath = (dirname $epubFilePath) . ‘/EpubTotalDataCheck.log’;

$logOutputPath = encode(‘UTF-8’, $logOutputPath);

open(OUT,”>> $logOutputPath”);

#チェックしたepubファイル名を出力

my $finalFilename = ‘####Checked FileName : ‘ . “\r\n” . $epubFileName;

$finalFilename = encode(‘UTF-8’, $finalFilename);

print OUT $finalFilename . “\r\n\r\n”;

#サロゲートペア文字の有無を出力

$finalSarrogatePairOutputLog = encode(‘UTF-8’, $finalSarrogatePairOutputLog);

print OUT $finalSarrogatePairOutputLog . “\r\n\r\n”;

#Unicode IVS文字の有無を出力

$finalIVSOutputLog = encode(‘UTF-8’, $finalIVSOutputLog);

print OUT $finalIVSOutputLog . “\r\n\r\n”;

#特殊スペース文字の有無を出力

$finalIrregularSpaceOutputLog = encode(‘UTF-8’, $finalIrregularSpaceOutputLog);

print OUT $finalIrregularSpaceOutputLog . “\r\n\r\n”;

close (OUT);

exit;

###################サブルーチン###################

#各xhtmlファイルのチェック

sub eachFileProceed {

my $myXhtmlfilePath = $_[0];

#各xhtmlファイル名を取得

our $xhtmlFileName = basename $myXhtmlfilePath;

my $eachFilePath = ($uniqueFolderPath . “/” . $myXhtmlfilePath);

open(IN,”$eachFilePath”);

#改行コードの統一処理

@myCHECKFILEtxts = ;

$myCHECKFILEtxts = join(“”,@myCHECKFILEtxts);

$myCHECKFILEtxts =~ s@\x0D\x0A@\x0D@g;

$myCHECKFILEtxts =~ s@\x0A@\x0D@g;

$myCHECKFILEtxts = decode(‘UTF-8’, $myCHECKFILEtxts);

@eachLine = split(“\x0D”,$myCHECKFILEtxts);

close (IN);

our $lineNumCount = 1;

#各ファイル内各行にIVS/サロゲートペア文字が含まれているかどうかのチェック

foreach $myLine (@eachLine){

&eachLineProceed($myLine);

$lineNumCount++;

}

}

#各xhtmlファイル内各行のチェック

sub eachLineProceed {

my $myLine = $_[0];

###サロゲートペア文字参照のチェック、ログに追記###

#16進数

while($myLine =~ /&\#x2[0-9A-Z]{4};/ig) {

$matchPlace = pos($myLine);

$finalSarrogatePairOutputLog = ($finalSarrogatePairOutputLog . ‘Caution! SarrogatePairCharacterRefernce at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $matchPlace . “\n”)

}

#10進数

while($myLine =~ /&\#(1[0-9]{5});/ig) {

$matchPlace = pos($myLine);

if ($1 >= 131072 && $1 <= 196607) {

$finalSarrogatePairOutputLog = ($finalSarrogatePairOutputLog . ‘Caution! SarrogatePairCharacterRefernce at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $matchPlace . “\n”)

}

}

###IVS文字参照のチェック###

#16進数

while($myLine =~ /&\#xE[0-9A-Z]{4};/ig) {

$matchPlace = pos($myLine);

$finalIVSOutputLog = ($finalIVSOutputLog . ‘Caution! UnicodeIVSCharacterRefernce at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $matchPlace . “\n”)

}

#10進数

while($myLine =~ /&\#(9[0-9]{5});/ig) {

$matchPlace = pos($myLine);

if ($1 >= 917504 && $1 <= 983039) {

$finalIVSOutputLog = ($finalIVSOutputLog . ‘Caution! UnicodeIVSCharacterRefernce at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $matchPlace . “\n”)

}

}

###特殊スペース文字のチェック###

#16進数

while($myLine =~ /&\#x(200[456789ACD]);/ig) {

$matchPlace = pos($myLine);

$finalIrregularSpaceOutputLog = ($finalIrregularSpaceOutputLog . ‘Caution! IrregularSpaceCharactorRefernce at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $matchPlace . “\n”)

}

#10進数

while($myLine =~ /&\#(819[6789]|820[01245]);/ig) {

$matchPlace = pos($myLine);

$finalIrregularSpaceOutputLog = ($finalIrregularSpaceOutputLog . ‘Caution! IrregularSpaceCharactorRefernce at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $matchPlace . “\n”)

}

#キャラクタごとの処理へ

my @eachchara = split(//,$myLine);

our $CharaNumCount = 1;

foreach $mychara(@eachchara){

&eachCharaProceed($myChara);

$CharaNumCount++;

}

}

#各xhtmlファイル内各行内各キャラクタのチェック

sub eachCharaProceed {

my $myChara = $_[0];

###サロゲートペア文字のチェック###

#サロゲートペア文字の場所をチェック、ログに追記

if ($mychara =~ /[\x{20000}-\x{2FFFF}]/){

$finalSarrogatePairOutputLog = ($finalSarrogatePairOutputLog . ‘Caution! SarrogatePairCharacter at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $CharaNumCount . “\n”)

}

###IVS文字のチェック###

#Unicode IVS文字の場所をチェック、ログに追記

if ($mychara =~ /[\x{E0000}-\x{EFFFF}]/){

$finalIVSOutputLog = ($finalIVSOutputLog . ‘Caution! UnicodeIVSCharacter at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $CharaNumCount . “\n”)

}

###特殊スペース文字のチェック###

#4分スペースなどの特殊スペース文字が含まれているかどうかのチェック

if ($mychara =~ /[\x{2004}-\x{200A}\x{200C}-\x{200D}]/){

$finalIrregularSpaceOutputLog = ($finalIrregularSpaceOutputLog . ‘Caution! IrregularSpaceCharactor at ‘ . ‘ ‘ . ‘FileName:’ . $xhtmlFileName . ‘ ‘ . ‘Line:’ . $lineNumCount . ‘ ‘ . ‘Character:’ . $CharaNumCount . “\n”)

}

}

 なお、Mac用にはEPUBCheck 3.0を組み込み、同時にログ出力できるようにしたドロップレットを作ってみました。Mac OS X 10.6/10.7/10.8で動作を確認しています。Mac OS X 10.5でも動作自体はしたのですが、Perlの呼び出しでエラーが出ました。Perlのアップデートが必要になると思われます。

実行ログ

実行ログ

 Mac版ドロップレットはIVS/サロゲートペア文字のチェックとEPUBCheckを連続実行しますので、多数のepubファイルをまとめてチェックすると多少の時間がかかります。チェック結果は、epubファイルと同じ場所に出力される「EpubTotalDataCheck.log」で一括確認できます。既に同名のファイルが存在していた場合は末尾に追記します。

チェック完了時にアラートを表示

チェック完了時にアラートを表示

 また、全てのファイルのチェックが完了するとアラートを表示します。バックグラウンドでチェックさせておいても安心です。
 なお、こちらのスクリプトを使用したことにより生じた損害等につきましては、一切責任を負いかねますので、あくまで自己責任にてご使用ください。

 ドロップレットのダウンロードはこちらからどうぞ。

>>EPUB3トータルデータチェッカー2.1.0(Mac用アプリ) ダウンロードはこちら
>>EPUB内特殊文字チェックスクリプト&バッチファイル(Win用) ダウンロードはこちら

 なお、Windowsでは、事前にActiveperl等のperl環境のインストールが必要です。

(2013.5.07)

ご要望をいただき、ログファイルにチェックした日付・時刻を出力する機能を追加いたしました。

(2013.5.09追記)

「電書ちゃんねる」に、epubcheckに関する記事が掲載されたようです。「エラーメッセージ一覧日本語訳」はとても参考になるありがたい資料ですのでぜひ参照することをおすすめします。

(2013.5.23追記)

数値文字参照形式でドキュメント内に挿入されたIVS/サロゲートペア文字、特殊幅スペース文字のチェックに対応させる形でソースコードを修正しました。また、Mac用アプリにつきましては「EPUB3トータルデータチェッカー1.1」にてEpubCheck3.0.1にも対応させました。

(2013.5.29追記)

特殊幅スペース文字として「|」(U+007C)が検出されていた問題を修正しました。ダウンロードコンテンツも同様に修正済みです。

(2013.6.04追記)

IDPFのバリデータに叱られてみた

2012/10/16

 「バリデータ」。DTP畑の方には言葉に聞き覚えのない方がおられるかも知れませんが、これは納品データが一定の仕様に沿っているかをチェックする整合性チェックプログラムのことです。IDPFは制作したEPUB3が仕様に沿っているかをチェックするためのバリデータを提供しており、無償で誰でも使うことができます。

 紙の印刷物の場合には、最終成果物はあくまで出力された紙であり、同じ出力結果が得られるのであればデータはどのように作ろうが自由でした。しかし、電子書籍の場合は事情が異なり、最終成果物はデータそのものであり、それはきちんとした仕様に沿って作られたものでなければなりません。特にEPUB3の場合はXMDFやドットブックよりも閲覧環境が多岐にわたるため、仕様に沿ってデータを作ることは重要です。従って、納品前に最低限「ちゃんとIDPFのバリデータを通るかどうかをチェックする」ことが必須になってくるわけです。先日発表された『電書協EPUB3制作ガイド』にも「最新版の epubcheck でエラーの出ないデータを制作すること」との記述があり、これは今後ごく当然の要求としてデータの納品時に求められてくるものと思われます。

 IDPFのバリデータは、EPUB3の容量が10MB以下であればこちらでwebサービス版を利用できますし、こちらから最新版Epubcheckをダウンロードすれば大容量のEPUBをチェックすることも可能です。ただ、こちらのツールはコマンドラインから利用するCUIのツールですので、コマンドラインツールに慣れていない方には少々敷居の高い面があることは確かです。そういった方には、Mac環境で利用できるこちらのGUIアプリケーション「EPUB Checker」をおすすめしておきます。内部的にIDPFのバリデータを利用しており、簡単なドラッグ&ドロップ操作でEPUBファイルをチェックすることができます。残念ながらWindows環境向けにはまだこれといったGUIバリデートチェックツールはなさそうで、早期の登場が望まれるところです。

 さて、今回は、実際にEPUB3を制作し、バリデートチェックをする際に私が遭遇したさまざまなエラーメッセージと、それぞれのエラーへの対処方法について書いてみます(画面はwebサービス版のものです)。正しいEPUBデータ制作の一助としていただければ幸いです。

パターン1 XHTML内「<meta>」行のエラー

XHTML内「meta」行のエラー 「File」はEPUB3パッケージ内ファイルのうち、問題のあったファイルを差しています。「Line」は問題のあった行で、「Message」はエラー内容です。正規表現を用いて書かれているので若干わかりにくいですが、この場合は、「cover.xhtml」ファイル内5行目の「<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />」のうち、「http-equiv」の属性値が不正なので修正せよと言われています。これはJBasic08の公式サンプルをそのまま使用した場合に遭遇するエラーです。
 エラー内容をそのまま適用すれば、「Default-Style」もしくは「Refresh」に修正することになりますが、最近のサンプルではこの行は「<meta charset="UTF-8" />」となっているものを多く見かけますので(電書協ガイドもこの表記)、そうした表記に変更する形で良いと思われます。また、この行そのものを記述しなくてもそう問題はないようです。

パターン2 「navigation.xhtml」内「nav.css」のリンクエラー

「navigation.xhtml」内「nav.css」のリンクエラー オーサリングツールとしてFUSEeβを使用している時に良く遭遇するエラーです。目次ファイル「navigation.xhtml」内にスタイルシート「nav.css」へのリンクが記載されているのに、実際にはファイルが存在しないことによりエラーが出ています。これはFUSEeβのデフォルト設定のため、頻繁にこのエラーに遭遇します。
 一度EPUBパッケージを解凍して「navigation.xhtml」内の「nav.css」へのリンク行を削除するか、あるいは内容は空でも構わないので「nav.css」を作成してFUSEeβで再度EPUB3ファイルを書き出せばこのエラーは消えます。

パターン3 空の「images」フォルダがある

空の「images」フォルダがある 電書協EPUB3ガイドの仕様では、画像を収納するフォルダ名は「image」です。しかしFUSEeβの標準仕様では画像フォルダ名は「images」で、FUSEeβ内で画像フォルダ名を「image」に変更することはできますが、何故か書き出し時に空の「images」も書き出され、このエラーが出ます。
 一度EPUBパッケージを解凍し、空の「images」フォルダを削除することでエラーは消えます。

パターン4 目次ファイル内に「<ol>」タグが連続で記述されている

目次ファイル内に「ol」タグが連続で記述されている 目次ファイル内に「<ol>」タグが連続で記述されているとこのエラーが出ます。FUSEeβの環境設定の「カバー・目次」の項目で、「<h1>〜<h3>タグを目次に含める」(目次に含めるタグ範囲は任意選択可能)の項目をオンにしていると、目次ファイル内に<ol>タグが連続する形でデータが書き出され、このエラーが出るようです。
 一度EPUBパッケージを解凍し、目次ファイル内の<ol>タグのうち内側のものを消すかコメントアウトすればこのエラーは消えます。

パターン5 パッケージ内にOPFファイルに記述されていない画像がある

パッケージ内にOPFファイルに記述されていない画像がある 画像フォルダ内にOPFパッケージファイルに記述されていない画像ファイルがある場合のエラーメッセージです。FUSEeβなどのツールを使用しているとOPFファイルへのファイル名の自動登録を行ってくれるため、このエラーに遭遇することはありませんが、ハンドコーディングでEPUB3を作成している場合などに、OPFパッケージファイルに画像ファイル名を記述し忘れるとこのエラーに遭遇します。適正にパッケージファイルへの記述を行えばエラーは消えます。

パターン6 パッケージ内にOPFファイルに記述されている画像がない

パッケージ内にOPFファイルに記述されている画像がない パターン5の逆で、パッケージファイルには画像ファイル名の記述があるのに実際にはファイルがない場合です。画像ファイルを入れ直す、(必要なければ)OPFファイル内の画像ファイルの記述を削除するなどの操作をすることでエラーは消えます。

パターン7 パッケージ内にファイル「.DS_Store」が存在する

パッケージ内にファイル「.DS_Store」が存在する Macがアイコンの配置などを記録している不可視の設定ファイル「.DS_Store」がフォルダ内に存在する場合のエラーです。これは不可視ファイルですので通常Macでは見えません。ただし実際には存在するためバリデート時にエラーになってしまいます。「Ds Store Remover」などのツールを使うことで除去できます。

パターン8 パッケージ内にファイル「iTunesMetadata.plist」が存在する

パッケージ内にファイル「iTunesMetadata.plist」が存在する 校正などの目的でiBooksなどのiOS内アプリにデータをコピーする際に、iTunesの同期機能を使うとパッケージ内にメタデータの管理ファイルを作成されてしまい、エラーが出ます。一度EPUBパッケージを解凍し、「iTunesMetadata.plist」ファイルを削除することでエラーは消えます。EPUB3ファイルの校正にiPad等を用いる際には、クラウドサービス「DropBox」経由でファイルを転送すると、この問題は起きませんので、そちらの方法をおすすめしておきます。

バリデータ通過画面

バリデータ通過画面

 これらのエラーを全て解消し、IDPFのバリデータをクリアすると「Congratulations!〜」と画面に表示されます。バリデータではきちんとCSSが適用されているか、XHTMLの表記が適正かといった部分まではチェックしてくれませんのでそうした校正は別立てで行う必要は当然ありますが、とりあえずはこれで最低限の「エラーを引き起こさないファイル」になったと言えるでしょう。

 なお、緊デジでEPUB3を制作する際に出てくるさまざまな問題を制作者同士の情報交換である程度解決するために、情報交換wiki「緊デジWiki」を先日公開しました。ご利用いただければ幸いです。

(2012.10.16)

「電書ちゃんねる」に、epubcheckに関する記事が掲載されたようです。「エラーメッセージ一覧日本語訳」はとても参考になるありがたい資料ですのでぜひ参照することをおすすめします。

(2013.5.23追記)

プロフィール
Jun Tajima

こちらにて、電子書籍&Web制作を担当しています。
このブログは、EPUB3をはじめとした電子書籍制作担当オペレータからの、「電子書籍の制作時にたとえばこんな問題が出てきていますよ」的な「現地レポート」です。少しでも早い段階で快適な電子書籍閲覧・制作環境が整うことを願って、現場からの声を発信していこうと目論んでおります。

当ブログ内の記事・資料は、私の所属しております組織の許諾を得て掲載していますが、内容は私個人の見解に基づくものであり、所属する組織の見解を代表するものではありません。また、本ブログの情報・ツールを利用したことにより、直接的あるいは間接的に損害や債務が発生した場合でも、私および私の所属する組織は一切の責任を負いかねます。