電書部EPUB
今回は電書部版EPUB作成の要件と入出力、そしてEPUB生成について説明します。EPUBそのものについて詳しくは説明しませんが、流れの中で必要なことにはふれていきます。
要件
ターゲット
EPUBリーダは世の中にいろいろあります。第1回 で説明したように、電書部ではまずはiPhoneアプリのStanzaをターゲットにしました。
図1 iPhone Stanzaで表示した電書
変換処理
決められた原稿フォーマットからEPUBに変換するには、おおまかに次の処理が必要になります。
本文をXHTMLに変換する
適切なcssを用意する
EPUBの必須ファイルを用意する。特にopf/ncxを生成する
ファイルを適切に配置する
EPUBの規格にしたがったzipファイルをつくりだす
変換後のEPUB
変換後のEPUBは、電書部の配信サーバで処理できる構造になっている必要があります。特に、EPUBのどこかに購入者のe-mailアドレスを入れる必要があります。
入力される原稿
入力される原稿の形式については、前回 説明しました。ここでは全体像のみ再掲します。
電書原稿の例
densho_sample/
00_maegaki.txt
01_genkou.txt
02_genkou.txt
03_atogaki.txt
04_writers.txt
cover.txt
cover.jpg
capture.jpg
okuduke.txt
toc.txt
出力されるEPUB
EPUBファイルはzip圧縮されたファイルです。電書部原稿から生成したEPUBの中は次のようになります。
変換後EPUB内文書の例
mimetype
META-INF/container.xml
OEBPS/content.opf
OEBPS/toc.ncx
OEBPS/css/miraitext.css
OEBPS/img/cover.jpg
OEBPS/img/capture.jpg
OEBPS/text/cover.html
OEBPS/text/00_maegaki.html
OEBPS/text/01_genkou.html
OEBPS/text/02_genkou.html
OEBPS/text/03_atogaki.html
OEBPS/text/04_writers.html
OEBPS/text/04_writers.html
OEBPS/text/okuduke.html
okuduke.htmlを除くhtmlファイルは、原稿のテキストファイル(YDML)から生成されています。cssファイルは、YDMLに対応する固定のものを使います。EPUB仕様に関わるファイル(mimetype,container.xml, content.opf, toc.ncx)について、以下で説明します。
mimetype
mimetypeをEPUBのzipアーカイブ先頭に非圧縮で格納します。内容は固定です。
mimetype
application/epub+zip
container.xml
container.xmlは、EPUBの構成情報に関するメタデータをおさめたOPFファイルを指し示すファイルです。電書部EPUBではOPFファイルの場所を固定していますので、内容は電書によらず同じになります。
電書部EPUBのcontainer.xml
<?xml version="1.0" encoding="UTF-8"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
<rootfiles>
<rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
</rootfiles>
</container>
content.opf
content.opfは、EPUBの構成情報をおさめます。
content.opfの例
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="BookID">
<metadata xmlns:opf="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:language>ja</dc:language>
<dc:publisher>電子書籍部(米光一成)</dc:publisher>
<dc:creator>電子書籍部</dc:creator>
<dc:date>2010-11-30</dc:date>
<dc:title>サンプル電書</dc:title>
<dc:identifier id="BookID" opf:scheme="URL">http://lv99.com/densho/ebooksdensho_sample2010/11/30</dc:identifier>
<dc:contributor>構成・テキスト:XXX
グラフィックス:XXX
写真:XXX</dc:contributor>
<meta name="cover" content="imgcover"/>
</metadata>
<manifest>
<item id="imgcover" href="img/cover.jpg" media-type="image/jpeg"/>
<item id="imgcapture" href="img/capture.jpg" media-type="image/jpeg"/>
<item id="cover" href="text/cover.html" media-type="application/xhtml+xml"/>
<item id="chap00_maegaki" href="text/00_maegaki.html" media-type="application/xhtml+xml"/>
<item id="chap01_genkou" href="text/01_genkou.html" media-type="application/xhtml+xml"/>
<item id="chap02_genkou" href="text/02_genkou.html" media-type="application/xhtml+xml"/>
<item id="chap03_atogaki" href="text/03_atogaki.html" media-type="application/xhtml+xml"/>
<item id="chap04_writers" href="text/04_writers.html" media-type="application/xhtml+xml"/>
<item id="css" href="css/miraitext.css" media-type="text/css"/>
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
<item id="okuduke" href="text/okuduke.html" media-type="application/xhtml+xml"/>
</manifest>
<spine toc="ncx">
<itemref idref="cover"/>
<itemref idref="chap00_maegaki"/>
<itemref idref="chap01_genkou"/>
<itemref idref="chap02_genkou"/>
<itemref idref="chap03_atogaki"/>
<itemref idref="chap04_writers"/>
<itemref idref="okuduke"/>
</spine>
</package>
metadata要素に、okuduke.txtにほぼ対応する情報が入ります。<meta name="cover">が指定されていると、多くのEPUBリーダでは対応するイメージを表紙画像として扱います。
manifest要素に、EPUBを構成するファイルが記述されます。そしてspine要素に、表示順序が規定されます。
toc.ncx
toc.ncxには、目次へ反映される情報を含むナビゲーション情報が記述されます。次の例では、原稿のtoc.txtに対応した内容になっています。
toc.ncxの例
<?xml version="1.0" encoding="UTF-8"?>
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
<head>
<meta name="dtb:uid" content="http://lv99.com/densho/ebooksdensho_sample2010/11/30"/>
<meta name="dtb:depth" content="1"/>
<meta name="dtb:totalPageCount" content="0"/>
<meta name="dtb:maxPageNumber" content="0"/>
</head>
<docTitle>
<text>サンプル電書</text>
</docTitle>
<navMap>
<navPoint id="chap00_maegaki" playOrder="1">
<navLabel>
<text> 前書き</text>
</navLabel>
<content src="text/00_maegaki.html"/>
</navPoint>
<navPoint id="chap01_genkou" playOrder="2">
<navLabel>
<text> この本に書かれていること</text>
</navLabel>
<content src="text/01_genkou.html"/>
</navPoint>
<navPoint id="chap04_writers" playOrder="3">
<navLabel>
<text> 執筆者プロフィール</text>
</navLabel>
<content src="text/04_writers.html"/>
</navPoint>
</navMap>
</ncx>
okuduke.html
okuduke.htmlは、原稿のokuduke.txtから自動的に生成します。
okuduke.htmlの例
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
<head>
<title>サンプル電書</title>
<link rel="stylesheet" type="text/css" href="../css/miraitext.css"></link>
</head>
<body>
<p class="backcover">
サンプル電書 <br />
電子書籍部 <br />
構成・テキスト:XXX<br />グラフィックス:XXX<br />写真:XXX<br />
2010/11/30 <br />
電子書籍部(米光一成) <br />
(this book is for !!!-mail-!!!)</p>
</body>
</html>
内容は、ほぼokuduke.txtに対応しているのが分かると思います。!!!-mail-!!!の部分は、配信サーバでの購入者のメールアドレスに置き換えられます。
そのほかのXTHMLファイルはYDMLからの変換によって生成されます。
入出力の対応
電書部のEPUBを構成するファイルは、原稿との対応から次のように分類できます。
原稿のメタデータおよび、原稿ファイルの情報からつくられるメタデータ
原稿テキストから変換して作られるテキスト
メタデータなどから生成されるテキスト
原稿の中からそのままコピーされるデータ
電書によらず内容が固定のデータ
入出力の概要は、次の通りです。
図2 入出力の対応
コンバータの構成
コンバータは次の要素から構成されています。
YDMLメタデータハンドラ
コンバータは、次のことを行います。
okuduke.txtを読みとる
toc.txtを読みとる
okuduke.htmlを生成する
EPUBライブラリに必要なメタデータを渡す
基本的には、必要な情報を構造化して持ち、必要な出力をするだけの単純な役割です。
YDML to HTML変換
cover.txtおよび本文のテキストをHTML変換を行います。前回説明したNoratextを利用しています。また、このモジュールでcssを生成します。cssの内容はYDMLからの変換に対応した固定のものです。
EPUB生成ライブラリ
最終的なEPUBを生成します。このライブラリがmimetype/content.opf/toc.ncxを生成し、与えられたxhtml/cssなどをパッケージしてzipファイルをつくります。開発開始時点ではrubyで書かれた適切なEPUB生成ライブラリがみあたらなかったため、新たに作りました。
そして、上記3つを適切に組み合わせて、呼び出すコマンドがあります。
具体的なライブラリとしてはEPUB生成ライブラリのgepub およびYDML関連ユーティリティのydml_utils(執筆時点で未公開、http://github.com/skoji/ 以下で公開予定)からなります。ydml_utilsには、上記のメタデータハンドラ・YDML to HTML変換・そして変換コマンドが含まれます。
発生した問題
ここまでで説明したように、原稿からEPUBを生成するのはそれほど難しいことではありません。しかし、それでもいくつかの問題がありました。いくつか、例をあげます。
リーダのふるまい
EPUB仕様は標準化されているものの実際にどのような見た目になるのかはリーダ次第です。また、リーダがEPUB仕様を正しく実装しているとは限りません。
たとえばiPhone Stanzaでは、本文のマージンや右よせ・左よせ・センタリングなど、見た目の一部をユーザが設定することができます。ユーザが設定できない要素でも、たとえば<h1>などはデフォルトでセンタリングされます。Stanza側のアピアランス仕様・設定とEPUB内cssの関係がどのようになっているのかがわからないため試行錯誤せざるをえず、苦労しました。現状はすべてのスタイルに!important;をつけるという乱暴な方法をとっています。
また、PCでよく使われるEPUBリーダAdobe Digital Editionsでは、各XHTMLファイルにlang属性を指定しないと日本語のEPUBがうまく表示できません。しかしEPUBの仕様では、言語指定はcontent.opfで行い、各XHTMLでは指定してはいけないことになっています。現状の電書部EPUBでは、XHTMLファイルにlang属性を付加しています。
ルビ
原稿にルビがあった場合には、EPUB2.0で拡張モジュールとして定義されている<ruby>タグをXHTML内に埋め込んでいました。対応していないリーダではタグが無視され、ルビ文字が括弧にはいるようにしました。Stanzaは<ruby>タグに対応しておらず、ルビは括弧に入って表示されていました。
ところがiPhoneがiOS4になってから、Stanzaで<ruby>タグ部分の表示がくずれるようになりました。ルビ文字が小さなフォントで表示され、前後の改行がおかしくなるのです。<ruby>タグに対応したものの、表示にバグがあるという厄介な状態です。iOS4 Safariでも<ruby>タグを含むHTMLが同じように表示されるため、WebKitに起因するバグでしょう。
EPUBのメインターゲットをiPhoneとしている電書部では仕方なく、iOS4以降に変換した電書では<ruby>タグを出力しないようにしています。
今後の予定
現在は、前回説明したパーサをEPUB変換へ組み込む変更をしています。その後コードを公開して、rubyを動作させる環境さえあれば誰でも電書部フォーマットからEPUBへの変換が使えるようにします。電書部のEPUB変換はそこで一段落つくと考えています。
EPUBライブラリgepubは、汎用EPUBライブラリというには機能が不十分なので(特に、langがja固定というのは言語道断です) 、修正していきます。また、現在はEPUB生成しかできませんが、EPUBを読み取る機能も追加する予定です。