‘2013/05’ カテゴリーのアーカイブ

iBooksの注ポップアップを試してみた

2013/05/23

 海外系のストアで最後に残った格好だったAppleのiBookstoreがようやく日本語コンテンツの配信を開始してから、約2ヶ月半が経ちました。iBookstoreは先行していたAmazon Kindleや紀伊國屋書店BookWebなどに比べて電子ペーパー端末やPC上でのコンテンツ閲覧環境が用意されていないなど見劣りするポイントもありますが、その反面でjavascriptを使ったEPUB3が動作する使える数少ないストアであることなどデバイスが限定されているからこそリッチコンテンツに強い面もあり、iPhoneやiPadなどのiOS端末の普及率の高さを考えると潜在的には相当大きな力を持ったストアと言えるように思います。

 iBooks向けのリッチなコンテンツ作りは、私が所属している会社のコンテンツ作りの方向性とは少し距離があることもあり、そこまで熱心に研究はしていなかったのですが、<aside>〜</aside>のタグで注テキスト(footnotes)を囲む形でマークアップしておくことで、該当する単語のリンクをタップした時に注のウィンドウがポップアップするという機能は、私が所属している会社で多く手がける専門書でもかなりのニーズがありそうに思えましたので、今回このあたりの情報を参考にちょっと試してみました(有名なエリザベス・カストロさんのサイトですね)。

 なお、今回のエントリに用いたサンプルは柳田国男の「遠野物語」を青空文庫よりダウンロードして使わせていただきました。また、ルビ等のタグはテキストの可読性を考え、削除しています。

マークアップ自体は簡単

 マークアップ自体はとても簡単です。

<p>一 <a epub:type=”noteref” href=”#cyu001″>遠野郷</a>は今の陸中上閉伊郡の西の半分、〜(中略)〜奥州の地名には多くあり。</p>
<div class=”start-1em”>

<aside epub:type=”footnote” id=”cyu001″>

<p>○遠野郷のトーはもとアイヌ語の湖という語より出でたるなるべし、ナイもアイヌ語なり。</p>

</aside>

</div>

注のポップアップ

注のポップアップ

 といったようなかたちでマークアップしておくことで、リンク部分をタップした際に注の対象文字からふきだしが出るような形で注がポップアップされます。ちょっと感動しました。素晴らしい!

注リンク部分にタグが含まれていると不具合が出る

メニューを表示させてリンクを開く

メニューを表示させてリンクを開く

 ただ、上記のようにシンプルなテキストへの注であれば問題はないのですが、例えばテキストに「<span class=”bold”>テキスト</span>」のような形で太字のタグが当たっているパターンや、「H<span class=”sub”>2</span>O」などのように一部のテキストに下付き文字のタグがついているなどといったように、リンク内に何らかのタグが含まれている場合には問題が出ます。
 具体的には何度リンク部分をタップしても注がポップアップされません。ちなみにダブルタップしてメニューを開き「リンクを開く」を選べば注のポップアップ表示自体は可能ですが、この状態ではユーザビリティが高いとはとても言えません。

ルビが含まれていると表示が破綻する

ルビは表示が破綻する

ルビは表示が破綻する

 特に問題が多いのが、注の部分にルビが振られていた場合です。iBooksの注ポップアップウィンドウ内ではあらゆるマークアップタグの効果は無視され、テキスト部分のみが表示されますので、たとえば「七七十里」に「しちしちじゅうり」とモノルビでルビが付加されていた場合、ポップアップウインドウ内には「七しち七しち十じゅう里り」と表示されてしまいます。日本語でルビが振られるような単語はすなわち難解で注が必要になる可能性の高い単語ですので、これはいささか困ります。

合印にリンクを貼れば破綻はしないが・・・

合印にリンクを貼るパターン

合印にリンクを貼るパターン

 これを避けるために対象の単語自体にはリンクを貼らず、単語のすぐ後ろに「※2」などいったような合印を付けてやり、合印に対してリンクを設定してやることで一応破綻なく注をポップアップ表示させることができます。
 ただ、iBooksのポップアップ注表示では、リンクを貼った部分のテキストが見出1として大きく表示されるため、「※2」が見出しとして表示されるといういささか間の抜けた状態になってしまうことは防げません。もう少し工夫をすればどうにかなるのかも知れませんが、ちょっとやり方を思いつきませんでした。

 いかがでしょうか。今回取り上げさせていただいたasideタグを用いた注のポップアップ表示は、比較的手軽にインタラクティブな要素を実現できそうなファクターとして期待していたのですが、結局まだ日本語EPUBコンテンツで利用するには難があるようです。
 今回取り上げた「遠野物語」のみならず、専門性が高くて注が多数配置されているようなコンテンツは、とても電子書籍の利便性を感じやすい分野です。読書の流れを切らずに注を参照できることは読みやすさを大幅に高めます。
 コンテンツの流用性としてもポップアップに対応しないビューアに持って行ってもリンク自体は機能するためソースの流用が可能で、ルビなどをきちんとポップアップウィンドウ内で表示できるようになれば相当使い勝手がよさそうなだけに、早い段階でのビューアのアップデートに期待したいところです。

(2013.5.23)

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追記)

プロフィール
Jun Tajima

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

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