弁護士ドットコム株式会社 Creators’ blog

弁護士ドットコムがエンジニア・デザイナーのサービス開発事例やデザイン活動を発信する公式ブログです。

「HTML解体新書」リフロー版電子書籍を作りました

写真:「HTML解体新書」書影

4月に発売された書籍「HTML解体新書」。その電子版は今までPDF版しかありませんでしたが、このたびリフロー版が発売となり、Amazonでも購入できるようになりました。

この記事では、HTML解体新書のリフロー版電子書籍を実際に作成した際の流れについて、なぜ作成したのか、どうやって作成したのか、どのようなトラブルがあったか、といった点をご紹介します。リフロー版の電子書籍の作成、出版を検討されている方の参考になれば幸いです。

リフロー版の電子書籍を作った理由

「HTML解体新書」の発売後には色々な反響をいただきましたが、よくいただいた質問の一つに、「電子版はないの?」というものがあります。

実は、固定レイアウトのPDF版は紙版と同時に発売されており、出版社のサイト (ボーンデジタル オンラインブックストア) から購入できるようになっていました。

にもかかわらず「電子版はないの?」と聞かれるのは、Amazonで電子版が購入できなかったからです。電子書籍の購入ルートはいろいろあるのですが、多くの方が利用するのはAmazonです。Amazonにないと、電子版が存在しないと思われてしまうわけです。

では、なぜPDF版がAmazonで版購入できなかったのか。その理由のひとつに、Amazonではリフロー版を販売したかったということがあります。

リフロー型と固定レイアウト型

電子書籍のフォーマットは大きく、リフロー型と固定レイアウト型にわかれます1

リフロー (reflow) とは、テキストのフロー (流し込み) を再実行できるという意味です。書籍では、紙面上のテキストが長ければ改行されて次の行に送られ、さらに長ければ次のページに送られます。このようにテキストを随時レイアウトしていくことを、フロー (流し込み) といいます2

紙の本では、文字の大きさや1行の長さは固定です。読む人によって改行位置が変わることもありません。しかし電子書籍では、これらは変動します。端末の種類によっても変わりますし、読者が好みに合わせて設定を変更することもできます。このように、端末側で自由なフロー処理を実行することを「リフロー」と言います。

ただし、電子書籍には端末側でのリフローが行えないものもあります。漫画や画集のような書籍の場合、レイアウトが重要な意味を持つため、リフローによってレイアウトが変わると、著者の意図がうまく伝わらなくなることもあります。このような書籍は、レイアウトが変わらない形で提供されることがあり、「固定レイアウト」とよばれます。

リフロー型とアクセシビリティ

アクセシビリティの観点では、リフロー型に大きなメリットがあります。弱視 (ロービジョン) の読者は画面を拡大して読むことがありますが、固定レイアウトの場合、単純に画面を拡大すると、テキストが画面の外にはみ出します。上下左右にスクロールすれば読めますが、複数方向のスクロールを併用しながら読むのは大変です。リフローの場合、画面幅に応じてテキストが折り返すため、一方向にスクロールするだけで読めます。

また、固定レイアウトのPDFファイルは、スクリーンリーダーの読み上げで問題が起きる場合があります。テキストの一部がまったく読まれなかったり、不適切な順に読まれることがあるのです。PDFの作り方によっては問題が起きないこともありますが、紙の書籍のために作成されたデータでは、ほぼ確実に問題が起きます。実際、「HTML解体新書」の固定レイアウト版PDFもそうでした。

「HTML解体新書」はアクセシビリティの話題も大きく扱っており、視覚に障害のある方からも読みたいというリクエストをいただいています。この本の電子版をAmazonで配信するなら、アクセシビリティに優れたリフロー版にしたいと考えました。

リフロー版の電子書籍を作るには

リフロー版の電子書籍は、主に"EPUB"というフォーマットで提供されます。仕様はW3Cの勧告となっており、2022年現在の最新はEPUB 3.2となっています。

EPUBの実体はXHTMLです。書籍の内容をXML構文のHTMLとしてマークアップし、画像、CSSなどのサブリソースを用意して、それらをZIPファイルにまとめればEPUBになります3。つまり、Web制作の技術がそのまま応用できるのです。

通常、この手の制作は専門の事業者に依頼するところなのでしょうが、Web制作の技術が使えるということで、自分で作ってしまうこともできそうです。というわけで、著者が自ら手を動かして作成してみることにしました。

電書協 EPUB 3 制作ガイド

基本的には仕様を読みつつ作れば良いのですが、より実践的なガイドとして、一般社団法人デジタル出版者連盟 (旧名「日本電子書籍出版社協会」、通称「電書協」) から「電書協 EPUB 3 制作ガイド」という文書も出ています。仕様には書かれていない端末依存の問題や、おすすめのファイル名、ディレクトリ構成などの情報もあります。簡単なEPUBのサンプルもついており、サンプルをベースに作っていくこともできます。

このガイドの大きな特徴は、各種の古い端末との互換性を重視している点です。そのため、HTMLの要素の多くは使用が推奨されていない状態になっています。

たとえば、本文中に箇条書きがある場合、通常はリストとして表現するためにul要素とli要素を使いますが、このガイドでは、本文中のリスト系はリーディングシステムが対応していない場合があるため、「利用を想定しない」としています。

nav 要素とリスト系要素 本ガイドでは、ナビゲーション文書以外での nav 要素と、ol、li などのリスト系要素の利用を想定しない。 ナビゲーション文書中では、EPUB Content Documents 3.0.1 の記載にあるように、リスト要素にはリスト番号を表示しないこと。

このほかにも、sectionfigureeminsといった多くの要素が「利用を想定しない」とされています。

「HTML解体新書」にも書いたとおり、HTMLの適切な要素を利用すると、スクリーンリーダーで適切な通知がなされたり、さまざまな機能が使えるようになったり、アクセシビリティ上のメリットが多数得られます。電書協 EPUB 3 制作ガイドの「利用を想定しない」要素を使わないことにした場合、アクセシビリティを損なうことになってしまいます。

そこで今回は、「電書協 EPUB 3 制作ガイド」のディレクトリ構成などは参考にしつつ、「利用を想定しない」とされるHTML要素については、あえて気にせず使ってしまうことにしました。問題が起きたら起きたでその際に対応しようという考えです。

実際の制作の流れ

ということで、実際にEPUBの制作を進めていきます。大まかに言うと、このような流れになります。

  • テキスト原稿を用意する
  • XHTMLを作る
  • その他EPUBに必要なファイルを準備する
  • EPUBを作る
  • 検証する
  • 各種の調整

以下、それぞれの流れについて触れていきます。

テキスト原稿を用意する

電子書籍を作るにあたり、確実に必要になるのが原稿のテキストです。紙の書籍を出しているのですから、その原稿は間違いなく存在します。原稿はテキストファイルの形で存在していますから、そのまま使えば問題ありません……。

と、言いたいところなのですが、残念なことに、紙版の原稿をそのまま使うことはできませんでした。紙版の制作フローは、大雑把に言うと以下のようになっています。

  1. テキスト原稿を用意
  2. DTP作業を行い、原稿をレイアウト
  3. レイアウトが完了したDTPデータに対して校正、修正
  4. 印刷して出版!

DTP作業が済んだ後の修正は、DTPデータに対して行います。土壇場で大量の修正が発生したため、それらの修正を元のテキスト原稿に反映する余裕はありませんでした。そのため、テキストデータは最新の状態ではないのです。

それならば、最終的なDTPデータからテキストを抜き出せば良いと思われることでしょう。Adobe InDesignからPDF形式で書き出されたデータは存在し、そこからテキストを抽出することは一応可能です。しかし、抽出されたデータはさまざまな問題を抱えていることがあります。たとえば以下のようなことが起こります。

  • 不要な改行やスペースが大量に混入している
  • 文章の一部が段落単位でまるごと欠落している
  • 文章の順番がおかしかったり、注釈と本文が混ざり合ったりする箇所がある
  • 一部の文字が化けている

一見しただけでは気づきにくい問題も多く、これを原稿として利用するのはかなり厳しいです。

では、どうするべきでしょうか。答えは単純です。PDFから手作業で一段落ずつコピーして、内容をチェックしながら進めていけば良いのです。おそろしい遠回りに見えますが、結局のところ、この方法が一番早いと考えています。

原稿には、見出しやリンクなどの情報も含まれます。プレーンテキストではそれらの情報が表現できないので、のちのことも考え、Markdown形式にしておくとよいでしょう。

と、簡単に言いましたが、正直に言って、この作業量は膨大です。作業を誰かにお願いする (外注する) ことで時間を短縮できないかとも考えましたが、外注した場合、その成果物が適切かどうか、著者がチェックする必要があります。原稿の正解を最終的に判断できるのは著者だけなのです。そう考えると、最初から著者が全部やった方が早いのではないかと思えたため、もう全部自分でやることにしました。長い時間をかけて、地道に取り組むことになりました。

XHTMLを作る

原稿が出揃ったら、XHTMLを作成します。元の原稿をMarkdown形式で用意しておけば、HTMLの生成自体は簡単です。今回はPandocを利用して、MarkdownからHTMLに変換することにしました。

実は、PandocではMarkdownからEPUBに直接変換することもできます。ただしこの場合、すべての原稿の内容を連結して、ひとつのXHTMLファイルにまとめてしまうようです。

今回は、章の切り替わりの都合 (特に、脚注番号を章ごとに振っている都合) で、XHTMLファイルは章ごとに分割したほうが好都合でした。そのため、EPUBへの加工は別途行うこととして、PandocではXHTMLへの変換だけを行いうことにします。以下のようなシェルスクリプトで処理しました。

for pathname in ../epub_text/*.md
do
  echo $pathname
  MarkdownFileName="${pathname##*/}"
  HtmlFileName="${MarkdownFileName%.*}.xhtml"
  pandoc $pathname --standalone --template=template.html > "./epub/root/item/xhtml/$HtmlFileName"
done

これで、拡張子.mdのファイルに対応する.xhtmlのファイルが生成されます。

その他EPUBに必要なファイルを準備する

HTMLが用意できたら、EPUBのファイルを作っていきます。

EPUBファイルの仕様は案外複雑です。EPUB仕様にはEPUBフォーマットの構造という図があるのですが、以下のような入れ子構造になっています。

  • EPUB Container
    • EPUB Publication
      • Available Renditions
        • EPUB Package
          • Package Document
          • Navigation Document
          • Publication Resources

全体を包含するコンテナである"EPUB Container"は"EPUB Open Container Format"(OCF)という形式で提供されるもので、以下に仕様があります。

中に含まれるパッケージ"EPUB Package"は、"Open Packaging Format"という形式で提供されるもので、以下で仕様を読むことができます。

簡単に言ってしまうと、EPUBファイルはXHTMLのリソースをOPFパッケージの形式でパッケージングし、それをOCFコンテナとして固めたもの、ということになります。

OCFコンテナのメタデータを用意する

そんなわけで、まずはOCFコンテナに必要なメタデータファイルを用意していきます。

mimetype

まず、ルートディレクトリにmimetypeという名前のファイルを置きます。詳しくは、OCF仕様の4.3 OCF ZIP Container Media Type Identificationをご覧ください。

このファイル名はmimetype固定で、変更できません。ファイルの内容は以下の文字列です。

application/epub+zip

仕様はかなり厳しく定められており、前後に空白や改行を含めることも、先頭にバイトオーダーマーク (U+FEFF) をつけることも許されていません。また、ZIPアーカイブには無圧縮 (圧縮率0) の状態で含める必要があります。

container.xml

次に、OCF Abstract Containerと呼ばれるメタデータファイルを用意します。container.xmlというファイルが必須で、/META-INF/というディレクトリにcontainer.xmlを置きます。

ファイルの内容はXMLで、たとえば以下のようになります。詳しくはOCF仕様の3.5.2.1 Container File (container.xml)をご覧ください。

<?xml version="1.0"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
    <rootfiles>
        <rootfile full-path="item/standard.opf" media-type="application/oebps-package+xml" />
    </rootfiles>
</container>

rootfile要素のfull-path属性で、OPFパッケージドキュメント(OPFのルートファイル) のパス名を指定します。ここではitem/standard.opfを指定していますが、ファイル名やディレクトリ名は自由です。慣習的に、OEBPSというディレクトリ名が使われることも多いようです。今回は電書協ガイドのサンプルで使われているファイル名をそのまま採用しました。

rootfile要素のmedia-type属性で、コンテンツのメディアタイプを指定します。EPUBパッケージのメディアタイプはapplication/oebps-package+xmlです。oebpsの名は、EPUB仕様の旧名であるOEBPS("Open Ebook Forum Publication Structure")に由来します。

OPFパッケージのデータを用意する

OPFパッケージには、OPFパッケージドキュメントと呼ばれるメタデータファイルが必要です。先にitem/standard.opfというパス名を指定していたので、そのパスにファイルを作成します。

内容はpackage要素をルート要素とするXMLです。以下はXMLの一部を抜粋したものです。実際にはもっとたくさんの要素があります。

<?xml version="1.0" encoding="UTF-8"?>
<package
 xmlns="http://www.idpf.org/2007/opf"
 version="3.0"
 xml:lang="ja"
 unique-identifier="unique-id"
 prefix="ebpaj: http://www.ebpaj.jp/"
>

  <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
    <dc:title id="title">HTML解体新書</dc:title>
    <meta refines="#title" property="file-as">HTMLカイタイシンショ</meta>
    <dc:identifier id="unique-id">urn:uuid:C97618FB-06D8-452D-A25E-BEA797E1BD5C</dc:identifier>
  </metadata>

  <manifest>
    <!-- navigation -->
    <item media-type="application/xhtml+xml" id="toc" href="navigation-documents.xhtml" properties="nav"/>

    <!-- style -->
    <item media-type="text/css" id="book-style"     href="style/default.css"/>
 
    <!-- image -->
    <item media-type="image/png" id="cover-image" href="image/cover.png" properties="cover-image"/>
    <item media-type="image/png" id="fig1-1-01" href="image/C1_01_01.png"/>

    <!-- xhtml -->
    <item media-type="application/xhtml+xml" id="cover"       href="xhtml/cover.xhtml"/>
    <item media-type="application/xhtml+xml" id="intro"       href="xhtml/intro.xhtml"/>
    <item media-type="application/xhtml+xml" id="caution"     href="xhtml/caution.xhtml"/>
    <item media-type="application/xhtml+xml" id="contents"    href="xhtml/toc.xhtml"/>
    <item media-type="application/xhtml+xml" id="chapter1-0"  href="xhtml/1-0.xhtml"/>
    <item media-type="application/xhtml+xml" id="profile"     href="xhtml/profile.xhtml"/>
    <item media-type="application/xhtml+xml" id="colophon"    href="xhtml/colophon.xhtml"/>
  </manifest>

  <spine page-progression-direction="ltr">
    <itemref linear="yes" idref="cover"/>
    <itemref linear="yes" idref="intro"/>
    <itemref linear="yes" idref="caution"/>
    <itemref linear="yes" idref="contents"/>
    <itemref linear="yes" idref="chapter1-0"/>
    <itemref linear="yes" idref="profile"/>
    <itemref linear="yes" idref="colophon"/>
  </spine>

</package>

metadata要素の中には、書名、著者名、出版社名といった各種のメタデータが入ります。

また、このパッケージのIDも含まれており、<dc:identifier id="unique-id">で指定しています。これは必須で、EPUBのリーディングシステムは、このIDによってEPUBファイルの同一性を識別します。uuidgenコマンドで適当に生成したUUIDを指定しておきます。

manifest要素の中には、パッケージに含まれるすべてのリソースを列挙します。ここではXHTML、CSS、画像を指定しています。何かリソースを追加した場合、この記述も追加しなければなりません。漏れがあると、HTMLの中で参照されていても適切に表示されない場合があります。

後述のEPUBCheckを利用すると、利用しているファイルがmanifestに含まれていない場合に警告してくれます。

spine要素では、XHTMLファイルの並び順、閲覧時の表示順を指定します (spineは背表紙の意味です)。XHTMLファイルを追加した場合、この記述も追加しなければなりません。

目次を用意する

書籍にはたいてい、目次が含まれています。紙の書籍では、目次は先頭付近の特定のページに入っていますが、EPUBの場合、メニューからいつでも目次を表示できるのが普通です。

実は、この目次はリーディングシステムが自動生成しているのではなく、制作者が用意したものです。リーディングシステムは単に、目次として用意されたXHTMLを表示しているだけなのです。

正確には"EPUB Navigation Document"と呼ばれるもので、内容はXHTMLのサブセットになっています。nav要素が必須であり、その内容には見出しとリストしか入れられないなど、書ける内容はかなり限定されています。

このEPUB Navigation Documentを作成し、OPFドキュメントのmanifestからproperties="nav"として参照しておくと、目次として利用できるようになります。

なお、書籍の中に含まれる目次も、それはそれとして用意したほうが良いでしょう。これは単にXHTMLでページを作成しておけば問題ありません4。つまり、メニューから表示される目次と、書籍本体に含まれる目次の2種類を用意することになります。

表紙ページを用意する

忘れがちですが、電子書籍にも表紙が必要です。表紙として扱われるものは2種類あります。

1つは表紙画像です。主に、書籍を一覧表示した際にサムネイルとして表示されます。OPFドキュメントのmanifestからproperties="cover-image"として画像を参照すると、その画像が表紙画像として扱われます。帯のない状態の表紙画像を用意して、それを指定します。

「HTML解体新書」帯なし表紙画像

もう1つは先頭ページです。通常、EPUBの書籍を開くと、まず表紙が表示されます。これは特別なものではなく、単なる1ページです。表紙にしたいXHTMLをspineの先頭に指定することで、表紙ページとして機能します。

これらは別々に用意する必要がありますが、画像は使い回しでも問題ありません。表紙画像だけを表示するXHTMLページを用意し、それを先頭ページとします。body内は以下のような内容としました。

<body>
<section class="cover">
<img src="../image/cover.png" alt="HTML解体新書 仕様から紐解く本格入門 / 著:太田良典 中村直樹 / 制作協力:株式会社ミツエーリンクス" />
</section>
</body>

EPUBを作る

これで一通りの材料が揃ったので、EPUBファイルを生成します。基本的には、ファイルを適切なディレクトリに配置し、それをZIPファイルにするだけです。ただし、先にも述べたように、mimetypeファイルだけは無圧縮で格納しなければなりません。

コマンドラインでzipコマンドを使う場合、-0オプションを指定すると無圧縮になります。たとえば以下のようにします。

zip -0 -X FILENAME.epub mimetype

こうしてできたZIPファイルに、他のファイルを追加します。-rオプションを指定して、カレントディレクトリ以下のファイルを再起的に処理します。また、mimetypeファイルが二重に格納されないように、-xオプションで除外します。

zip -r FILENAME.epub * -x mimetype

Macの場合は"*.DS_Store"も除外しておくと良いでしょう。

zip -r FILENAME.epub * -x mimetype -x "*.DS_Store"

これで、意外とあっさりEPUBのファイルが完成します。

検証する

ひとまずEPUBのファイルは作成できました。不備さえなければ、実際にリーディングシステムで読むことができるはずです。とはいえ、なにごとにもミスはつきものですから、実際にうまくできているかどうか確認する必要があります。

EPUBCheckによる検証

まず、EPUBとして適切なフォーマットになっているかどうかを確認します。W3CがEPUBCheckというツールを配布しているので、これを利用します。

EPUBCheckはJavaで書かれているため、実行にはJavaのランタイム (Java Runtime Environment, JRE) が必要です。事前にJREを導入して、javaコマンドを使えるようにしておく必要があります。

EPUBCheckをダウンロードするとさまざまなファイルが出てきますが、本体はepubcheck.jarです。以下のようにして呼び出します。

java -jar ../../epubcheck-4.2.6/epubcheck.jar FILENAME.epub

チェックが終わり、問題がなければ以下のようなメッセージが出力されます。

EPUB version 3.2 のルールを使って検証します.
エラーも警告も検出されませんでした.
メッセージ: 0 件の致命的エラー / 0 件のエラー / 0 件の警告 / 0 件の情報

問題がある場合はエラーメッセージが出力されます。

EPUB version 3.2 のルールを使って検証します.
ERROR(RSC-008): html_kaitai.epub/item/xhtml/1-1.xhtml(28,43): 参照されているリソース "item/image/C1_01_01.png" がOPF manifest内で宣言されていません.
WARNING(OPF-003): html_kaitai.epub(-1,-1): アイテム "item/image/C1_01_01.png" がEPUB内に存在しますが、OPFマニフェストで宣言されていません.

何が問題かは、メッセージを読めばだいたいわかるはずです。上記の例の場合は、XHTMLから参照している画像がOPFドキュメントの中で宣言されていないことが原因です。OPFのmanifest要素に以下のように追加すればエラーが出なくなります。

<item media-type="image/png" id="fig1-1-01" href="image/C1_01_01.png"/>

このほか、HTMLの文法違反などが報告されることもあります。エラーが出た場合は、適宜修正していきましょう。

各種端末での表示確認

EPUBとして適切な形式になっていても、実際に各種の端末で問題なく表示できるとは限りません。各種の端末で表示の確認を行います。私の手元では以下のアプリケーションで表示確認を行いました。

その他、各種スマートフォンアプリや、楽天Koboの端末などで確認を行います。多数の端末での検証を一人で行うことは現実的でないため、関係者各位に協力をお願いしました。

各種の調整

各種端末での表示確認の結果、いくつかの不都合があることがわかり、調整をする必要がありました。

脚注の調整

不都合のひとつは、脚注です。脚注のリンクにepub:type="noteref"という属性があると、リーディングシステムはこれを脚注と認識し、単なるリンクとは異なる扱いをすることがあります。たとえば、脚注をポップアップで表示し、本文と同時に読めるようにすることがあります。

単純にPandocでHTMLを生成した場合、脚注のリンクにはepub:type属性がつきません。この属性がないと、単なるリンクとして扱われ、単にリンク先の脚注のところに飛ぶだけになってしまいます。

Pandocが生成した脚注のリンクには、role="doc-noteref"という属性がついていました。これをキーに、sedで置換処理を行ってepub:type属性を追加するようにします。

sed 's/role="doc-noteref"/role="doc-noteref" epub:type="noteref"/g' 

また、Pandocが生成した脚注には本文へ戻るリンクもありますが、リンクテキストとして「↩︎」(U+21A9、LEFTWARDS ARROW WITH HOOK) が使われています。各種端末で検証してみると、どうも楽天Koboの端末ではこの文字が表示できないようでした。

そのため、これを日本語の「本文へ」というテキストに置き換えることにしました。ついでに、戻るリンクの前で改行すべくbr要素も追加しています。

sed 's/>↩︎</><br\/>(本文へ)</g' 

表示できない文字の調整

先に挙げた戻るリンクのほかにも、本書には、あまり一般的でない文字が使われている箇所があります。ひとつはアラビア語の文字です。これは書字方向の説明のところで使用しています。

もうひとつは寿司の絵文字(U+1F363)です。maxlengthおよびminlength属性を説明する部分の注釈において、1文字で長さが2とカウントされる例として使用しています。

これらの文字は端末やフォントによって表示できないことがあるようなので、画像に置き換えることにしました。単純にimg要素で画像を参照し、代替テキストとしてalt属性に元の文字を指定します。

スタイルの調整

端末によっては、CSSの表現力にも限界があるようで、スタイルがうまく適用されないことがあるようでした。

  • SVGが使用されているとエラーになる (単にその箇所が表示されないのではなく、エラーになって書籍そのものが表示されない)
  • borderのスタイルがうまく再現されない
  • 文字装飾が再現されない

当初はいろいろ試行錯誤しつつ紙版のスタイルに近づけようとしていましたが、どう工夫してもうまくいかない端末がありました。ここはもう割り切ってシンプルな方向にしています。結果、見出しの表現などは紙版と比べるとかなりシンプルになっています。

発売後の問題

ということで、色々調整した結果、なんとかEPUBが完成して発売に漕ぎ着けることができました。

しかし、なんと発売後に問題が発覚。Amazonでのプレビューが文字化けしている、一部のKindle端末で文字化けが起きるという報告がありました。

事前にKindle Previewerで表示確認を行っていたのですが、その際には特に文字化けはありませんでした。しかし、実際にAmazonのサイトで配布されているプレビュー版をダウンロードして閲覧してみると、確かに文字化けが起こっていました。一部ではなく全てが化けており、読みにくいというレベルではなく、全く読めない状態です。これは放置できませんので、調査と対応を行いました。

文字化けの内容とその原因

文字化けしているというAmazonのプレビューを、macOSの「ブック」アプリで表示してみます。画像は書籍の「はじめに」を表示させたところです。

スクリーンショット: 電子書籍プレビューが文字化けしている様子。冒頭の表示は「ã�¯ã�~ã,�ã�«」のような形

確かに化けています。見出しの「はじめに」からして文字化けしており、ã(aチルダ、小文字aの上に~がついた字系)が多数表示されています。

これを見た瞬間、何が起きているのか想像がついた方もいることでしょう。これは、UTF-8をISO-8859-1として解釈した場合に典型的な化け方です。

UTF-8では、日本語の文字の多くは0xE3で始まる3バイトで表現されます。たとえば、「はじめに」は、以下のようなバイト列となります。

0xE3 0x81 0xAF
0xE3 0x81 0x98
0xE3 0x82 0x81
0xE3 0x81 0xAB

ISO-8859-1では、0xE3ãに相当します。また、0x810x9Fには文字が定義されていないため、多くの環境では、文字が表示できないことを示す記号 (Replacement Character、豆腐、バツ印、疑問符のようなもので表現されることが多い) が表示されます。これにより、ãと奇妙な記号が繰り返し表示されることになるのです。

このことから、一部のKindle端末ではEPUBの文字コードをUTF-8ではなく、ISO-8859-1と誤認識した可能性が考えられます。

EPUBに含めたXHTMLファイルを確認すると、meta charsetによる文字コードの指定が含まれていました。これはPandocが自動生成しているものです。

<meta charset="UTF-8">

しかし、これは比較的新しい書き方です。おそらく、古いKindle端末はこの指定を認識できず、認識できなかった場合にはデフォルトでISO-8859-1として扱うのでしょう。プレビューのファイルについては、Amazon側で切り出しと変換の処理をしているのですが、その変換の際の処理でも同様のことが起きているものと推察しました。

仕様的に言えばXMLのデフォルトがUTF-8なのですから、本来であれば、デフォルトでISO-8859-1として解釈するのはおかしいはずです。おそらくKindleの歴史的な経緯があって、古い端末はデフォルトISO-8859-1、比較的新しい端末はデフォルトUTF-8として解釈するのでしょう。そう考えると、端末によって化なかったり、Kindle Previewerでは問題がなかったことにも説明がつきます。

ともあれ、Pandocが出力したmeta charsetを古い書き方に変換する処理を書きました。

sed 's/<meta charset="utf-8" \/>/<meta http-equiv="content-type" content="text\/html; charset=utf-8" \/>/g'

また、XML宣言のencodingは認識されるらしいという情報もありました。Pandocが出力したHTMLにはXML宣言がなく、先頭がDOCTYPEで始まっている形になっています。XML宣言も追加することとし、DOCTYPEの前にXML宣言を追加する処理を書きました。

sed 's/<!DOCTYPE html>/<\?xml version="1.0" encoding="UTF-8"\?>\n<!DOCTYPE html>/g'

この処理を行ったものを納品したので、文字化けが解消されたはずです (反映されたという連絡がいただけていないのですが、多分反映されています)。

まとめ

「HTML解体新書」EPUB版の作成、検証、修正について、実際におこなってきたこと一通りご紹介しました。

EPUBのコンテンツそのものはXHTML+CSSであり、Web制作の知識があれば、作ること自体は簡単です。

ただし、そもそものテキスト原稿を用意することに大きな課題がありました。実は私が過去に出した書籍でも同様の問題が起きており、初めての経験ではありません。紙書籍の制作プロセスを改善すればどうにができるのではないかと思いつつ、毎回どうにもなっていない問題です。常に締め切りギリギリで作業をしているのが悪い、といえばそうなのでしょうが……。

また、各種端末での表示の問題Amazonプレビューでのトラブルなどがあり、その対応には苦労しました。これは、各種ブラウザの挙動にかなりの差異があった頃のWeb制作の状況と似ているかもしれません。EPUBのリーディングシステムが新しくなっていくにつれて、このような問題も減っていくのではないでしょうか。もっとも、それはまだ先の話かもしれません。

と、いろいろありましたが、ともあれEPUBの制作と出版をすることができました。ただなにぶん、素人が作成したものですので、いろいろ不具合もあるかもしれません。何かお気づきの点がありましたら、お知らせいただければと思います。

この記事が、これからEPUBを制作してみようという方に少しでも参考になれば幸いです。


  1. 固定レイアウトは「フィックス型」などと呼ぶこともあります。「電書協 EPUB 3 制作ガイド」や「Amazon Kindle パブリッシング・ガイドライン」では「リフロー」と「固定レイアウト」という用語が使われているので、本記事はそれらにならいました。
  2. Webの世界ではCSSにもflowという用語があり、同じ意味で使われています。https://www.w3.org/TR/CSS22/visuren.html#normal-flow
  3. 正確には、"EPUB Open Container Format"(OCF)形式のデータを作成する必要があります。XHTML以外にも、メタデータなど、いくつかの追加データも必要です。詳しくは後述します。
  4. 先にすこし触れたように、「電書協 EPUB 3 制作ガイド」ではNavigation Document以外でのリスト系要素は「利用を想定していない」とされています。これを重視する場合、Navigation Documentではol要素を使いつつ、本文中の目次ページではol要素やul要素は使わないことになります。ただし、本書ではこのガイドは気にせず、本文中の目次でもulを使用しています。