こんにちは、木村です。(非常に遅ればせながら)本年もよろしくお願いいたします。
さて、入社してから2年が経とうとしています。よりスキルアップしていきたいなと思うこの頃ですが、勉強の一つとして技術書を幅広く読みたいなーと思う一方、なかなか時間がとれなかったり集中できなかったり… そんななか、私は技術書にかかわらず本を読むのによく Kindle を使用します。本を嵩張らず持ち運べるっていうのはいいですよね。最近購入した本は PDF 形式だったため、直接 Kindle に入れて読むことができたのですが、ふと「Kindle で読む通常の本ってなんで文字の大きさが変更できるの?」と思いました。
PDF は直感で文字の大きさの変更やページ範囲の調整ができない、という前提で読んでいたんですが、じゃあできる本の形式は PDF じゃないのかと気になりました。
そこで今回は、大まかな文書形式についてと、その中でも一番気になった EPUB について調べてまとめました。よろしくお願いします!
文書形式
- PDF(Portable Document Format)
PDF とは「Portable Document Format(ポータブル・ドキュメント・フォーマット)」の略で、アドビが開発したファイル形式です。PDF ファイルは文書を紙に印刷したときと同じレイアウトで保存でき、PC やスマホなど、どんな環境で開いても基本的に同じように表示できるのが特長です。文書をパスワードで保護でき、印刷代や紙代の削減にもつながるので、契約書類やマニュアルなど、様々な文書に採用されています。 https://www.adobe.com/jp/acrobat/roc/blog/about-pdf.html 特徴については大まかに以下のようなものになります。 - Adobe によって開発されたファイル形式(国際標準規格) - レイアウトを固定して保存することができる - パスワードの設定等ができる
- EPUB(Electronic PUBlication)
- 電子書籍のファイルフォーマット規格の一つ
- 固定型とリフロー(再レイアウト)型の2種類がある。
- 固定型は PDF をそのまま EPUB のフォーマット化するようなイメージ
- リフロー型は、設定するリーダーの設定に合わせて文字の大きさや行間を変更ができる形式。 特に、EPUB 3.0 以降では日本語の縦書きやルビ、禁則処理のも対応しているため、電子書籍のデフォルトとして採用されることが多いようです
「じゃあ Kindle で行間とか設定できる本は EPUB なんか〜」と思ったんですが、調べるとちょっと違ったみたいです。
Kindle アプリで保存されているデータの拡張子を見に行ったところ、書籍のデータの中身をのぞいてみると「azw(azw8, azw9)」の拡張子のデータがありました。EPUB とはまた別の形式みたいです。
azw 形式についての詳しい情報を見つけることが出来なかった(おそらく非公式になっている)ので EPUB とは違った形式、ということしかわかりませんでしたが、どうやら DRM(著作権保護)が組み込まれた Kindle 独自の形式、ということらしいです。
ただ、kindle の対応フォーマットは以下の通りなので、EPUB 形式のファイルでも読むことが出来そうです。
PDF、DOC、DOCX、TXT、RTF、HTM、HTML、PNG、GIF、JPG、JPEG、BMP、EPUB (https://www.amazon.co.jp/sendtokindle/)
また、apple ユーザーにとっては 「ブック」 というアプリが初期インストールされていて見覚えがあるかとは思うのですが、こちらのアプリでも EPUB 形式のファイルを読み込んで扱うことが出来ます。
EPUB とは
EPUB という形式に初めて触れたので、深掘りして調べてみます。
EPUB を構成する技術
EPUB の中身を理解するために、まずベースとなっている技術を見てみます。
- XHTML — 本文のコンテンツはXHTMLで書かれています。
- CSS — 文字サイズや行間、縦書きなどの見た目の指定
- XML — 書籍のメタ情報(タイトル、著者など)や目次の構造を記述
言葉でつらつらと書いてもあんまりパッとしないので、実際の構造を見ながら作っていきます。
EPUB の構造
実際に作っていくための下準備として、今回は青空文庫から「変身」(フランツ・カフカ)をダウンロードしています。(https://www.aozora.gr.jp/) これを3章構成で作成していこうと思います。
mimetype
This appendix registers the media type application/epub+zip for the EPUB Open Container Format (OCF). An OCF ZIP container, or EPUB container, file is a container technology based on the zip archive format (see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT). It is used to encapsulate the EPUB publication. OCF and its related standards are maintained and defined by the World Wide Web Consortium (W3C).
この付録は、EPUB オープンコンテナフォーマット(OCF)のメディアタイプとして application/epub+zip を登録する。 OCF ZIP コンテナ(または EPUB コンテナ)ファイルは、zip アーカイブ形式に基づくコンテナ技術である(https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT 参照)。これは EPUB 出版物をカプセル化するために使用される。OCF および関連規格は、World Wide Web Consortium(W3C)によって維持・定義されている。 (https://www.w3.org/TR/epub-33/#app-media-type%EF%BC%89)
EPUB creators MUST include the mimetype file as the first file in the OCF ZIP container. In addition: (https://www.w3.org/TR/epub-33/#sec-zip-container-mime%EF%BC%89)
意訳ですが、一つの EPUB として構成するファイルに、「application/epub+zip」と書かれたファイルが必要で、ZIP ファイルを作成するときに最初に無圧縮で格納する必要がある、ということです。
META-INF/container.xml
The REQUIRED container.xml file in the META-INF directory identifies the package documents available in the OCF abstract container. All [xml] elements defined in this section are in the urn:oasis:names:tc:opendocument:xmlns:container namespace [xml-names] unless specified otherwise.
META-INF ディレクトリ内の必須ファイル container.xml は、OCF 抽象コンテナ内で利用可能なパッケージ文書を識別します。 本節で定義される全ての[xml]要素は、特に指定がない限り urn:oasis:names:tc:opendocument:xmlns:container 名前空間[xml-names]に属します(https://www.w3.org/TR/epub-33/#sec-container-metainf-container.xml)
書籍の設定ファイルがある箇所を記述するファイルをつくれということみたいですね。 私は普段 フロントをよく触っているのでフロントで例えるなら、index.html で
<script src="main.js">
と記述して、エントリーポイントとして記述するのに近いでしょうか。
<!-- META_INF/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>
OEBPS/content.opf
A package document carries meta information about the EPUB publication, provides a manifest of resources, and defines a default reading order.
パッケージドキュメントは、EPUB 出版物のメタ情報を保持し、リソースのマニフェスト(一覧)を提供し、デフォルトの読み順を定義します。(https://www.w3.org/TR/epub-33/#sec-package-doc%EF%BC%89:~:text=abstract%20container.-,package,-document)
先ほどの container.xml で指定したファイルですね。大きく 3 つの役割があります。
- metadata — タイトル、著者、言語などの書籍情報。リーダーの本棚に表示される情報もここから取得されます
- manifest — この本に含まれる全ファイル(XHTML、CSS、画像など)の一覧
- spine — チャプターを読む順番の定義
<!-- /OEBPS/content.opf --> <?xml version="1.0" encoding="UTF-8"?> <package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="book-id" xml:lang="ja"> <!-- metadata: 本の情報 --> <metadata xmlns:dc="http://purl.org/dc/elements/1.1/"> <dc:identifier id="book-id">henshin-001</dc:identifier> <!--一意のIDを設定--> <dc:title>変身1</dc:title> <!--タイトル--> <dc:creator>フランツ・カフカ</dc:creator> <!--著者名--> <dc:language>ja</dc:language> <!--言語--> <meta property="dcterms:modified">2024-01-01T00:00:00Z</meta> </metadata> <!-- manifest: この本に含まれる全ファイルの一覧 --> <manifest> <item id="nav" href="toc.xhtml" media-type="application/xhtml+xml" properties="nav"/> <item id="css" href="style.css" media-type="text/css"/> <item id="chapter1" href="chapter1.xhtml" media-type="application/xhtml+xml"/> <item id="chapter2" href="chapter2.xhtml" media-type="application/xhtml+xml"/> <item id="chapter3" href="chapter3.xhtml" media-type="application/xhtml+xml"/> </manifest> <!-- spine: 読む順番 --> <spine> <itemref idref="chapter1"/> <itemref idref="chapter2"/> <itemref idref="chapter3"/> </spine> </package>
OEBPS/toc.xhtml
The EPUB navigation document is a specialization of the XHTML content document that contains human- and machine-readable global navigation information, providing critical navigation capabilities, such as the table of contents, that allow users to navigate the content quickly and easily.
EPUB ナビゲーションドキュメントは、人間と機械の両方が読めるグローバルなナビゲーション情報を含む XHTML コンテンツドキュメントの特殊形式で、目次などの重要なナビゲーション機能を提供し、ユーザーがコンテンツをすばやく簡単にナビゲートできるようにします。(https://www.w3.org/TR/epub-33/#sec-package-doc%EF%BC%89:~:text=%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82-,EPUB,-%E5%87%BA%E7%89%88%E7%89%A9%E3%81%AB%E3%81%AF)
要するに目次ファイルです。機械(EPUB リーダー)とユーザーの両方が使えるように XHTMLで構成してるよってことらしいです。
<!-- OEBPS/toc.xhtml --> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="ja"> <head> <title>目次</title> </head> <body> <nav epub:type="toc"> <h1>目次</h1> <ol> <li><a href="chapter1.xhtml">一</a></li> <li><a href="chapter2.xhtml">二</a></li> <li><a href="chapter3.xhtml">三</a></li> </ol> </nav> </body> </html>
OEBPS/style.css
EPUB 3 supports CSS as defined by the CSS Working Group Snapshot.
EPUB 3 は、CSS Working Group Snapshot で定義された CSS をサポートしています。(https://www.w3.org/TR/epub-33/#sec-css)
つまり、Web ページと同じ CSS がそのまま使えるということです。文字のフォント、行間、余白などを指定できます。
一旦シンプルに以下のように記述します。
body { font-family: serif; line-height: 1.8; margin: 1em; } h1 { text-align: center; font-size: 1.5em; margin-bottom: 2em; } p { text-indent: 1em; margin: 0.5em 0; } ruby rt { font-size: 0.6em; }
圧縮
cd "[一連のファイルをまとめているフォルダパス]" && zip -0 -X "[作成したいepubファイル名(パスで指定)].epub" mimetype && zip -r -X "[先に作成したepubファイルのパス]" META-INF OEBPS
最初の mimetype を無圧縮で追加し、次にそれ以外を追加するコマンドです。 これによって epub が作成されます。
開いてみましたが、この時点では横書きになります。 EPUB はデフォルトで横書きです。(開発が行われたのは日本ではありませんからね...)
ただ、EPUB 3からはちゃんと縦書き・右開きにも対応してくれているので、設定を追加していきましょう。
縦書き対応
The page-progression-direction attribute sets the global direction in which the content flows. Allowed values are ltr (left-to-right), rtl (right-to-left) and default. When EPUB creators specify the default value, they are expressing no preference and the reading system can choose the rendering direction.
page-progression-direction属性は、コンテンツの流れのグローバルな方向を設定します。許可される値はltr(左から右)、rtl(右から左)、およびdefaultです。EPUB作成者がdefault値を指定する場合、特定の好みを示さず、閲覧システムがレンダリング方向を選択できます。
Although the page-progression-direction attribute sets the global flow direction, individual EPUB content documents and parts of EPUB content documents MAY override this setting (e.g., via the writing-mode CSS property). Reading systems may also provide mechanisms to override the default direction (e.g., buttons or settings that allow the application of alternate style sheets).
page-progression-direction属性はグローバルな流れの方向を設定しますが、個々のEPUBコンテンツ文書およびEPUBコンテンツ文書の一部は、この設定を上書きすることがあります(例:writing-mode CSSプロパティによる)。また、閲覧システムはデフォルトの方向を上書きする仕組み(例:代替スタイルシートの適用を可能にするボタンや設定)を提供する場合があります。 (https://www.w3.org/TR/epub-33/#attrdef-spine-page-progression-direction)
要するに縦書きにするには、以下2 つのファイルを変更します。
1. content.opf の <spine> に page-progression-direction="rtl" を追加
<spine page-progression-direction="rtl">
2. style.css に writing-mode: vertical-rl を追加
body { writing-mode: vertical-rl; -webkit-writing-mode: vertical-rl; }
vertical-rl は「縦書き、右から左へ行が進む」という意味です。これは CSS の標準プロパティなので、EPUB に限らず Web ページでも使えます。
-webkit-writing-mode は Books アプリ(WebKit 系)向けのベンダープレフィックスです。
この 2 つの変更を加えて再度 EPUB をビルドすると、日本語の一般的な書籍と同じ形式の縦書き・右開きとして表示されるようになりました。
しかし Kindle ユーザーの私にとっては大問題、この設定だけでは Books アプリでは縦書き表示されますが、Send to Kindle で送った場合は縦書きになりませんでした。(2時間格闘しました笑)
Kindle での縦書き対応
色々と設定方法について探したのですが(なぜか公式ドキュメントが全然出てこない)、やっと見つけました。
メタデータガイドライン meta name="book-type"電子書籍はデフォルトでリフロー可能です。リフロー可能な電子書籍では、OPFファイルで 指定する必要はありませんが、< dc:language>と< dc:title>は必須です。ページ展開方向が左から右でない場合は、メタデータまたは背表紙でページ展開方向を指定する必要があります。(例:) (https://kdp.amazon.com/en_US/help/topic/GPNJPYK298J8TRRV)
Kindle は EPUB をそのまま表示しているわけではなく、内部で独自フォーマットに変換しています。そのため、EPUB 標準の page-progression-direction だけでは縦書きが認識されないことがあるみたいですね。
公式ドキュメントに従って、content.opf の <metadata> に以下の 1 行を追加します。
<meta name="primary-writing-mode" content="horizontal-rl"/>
この 1 行を追加して再ビルドしたところ、Send to Kindle でも縦書き・左開きで表示されるようになりました。
EPUB の中身
改めて EPUB の中身を見に行ってみましょう。
EPUB の中身を確認するには、拡張子を .zip に変更して展開するだけです。EPUB の実体は zip アーカイブなので、中身はそのまま取り出せます。
mv henshin.epub henshin.zip unzip henshin.zip -d henshin
展開すると以下のようなファイル構成になっています。
henshin/
├── mimetype # EPUB であることを示すファイル
├── META-INF/
│ └── container.xml # 本の設定ファイルの場所を示す
└── OEBPS/
├── content.opf # 本の情報(タイトル、著者、ファイル一覧、読む順番)
├── toc.xhtml # 目次
├── toc.ncx # 目次(EPUB 2 互換)
├── style.css # スタイルシート
├── 0_.xhtml # 第一章
├── 1_.xhtml # 第二章
└── 2_.xhtml # 第三章
先ほどまでの流れから分かるように、HTML + CSS + XML という、Web の技術がそのまま使われています。 なんかもっと小難しいことをしているのかと思ったのですが、意外と身近なものでした。
EPUB 変換ツール
さて、ここまで色々とやってきましたが、正直これを一から作成するのはかなり面倒くさいですね。特に EPUB 変換の部分で圧縮化の際に mimetype を無圧縮でやって...みたいな操作、コマンドに不慣れな私はきっとすぐに忘れてしまうことでしょう。(精進します) ここまで普及している電子書籍のフォーマットならきっと自動で EPUB を作成してくれるツールがあるはず...というわけで調べてみると流石にありました。 複数ありましたが、今回は「epub-gen-memory」を使ってみます。
https://www.npmjs.com/package/epub-gen-memory
HTML から EPUB ファイルを生成してくれる Node.js ライブラリです。手動でやった mimetype / container.xml / content.opf / toc.xhtml の作成や zip 圧縮を全部やってくれます。
セットアップ
npmでインストールできます。
npm install epub-gen-memory
package.json に "type": "module" を追加して、ESM の import 構文を使えるようにしておきます。
変換スクリプト
先ほど手動で作った XHTML ファイルの本文を読み込んで、EPUB を生成するスクリプトをJSで書きます。 ライブラリでEPubをインポートして使用することができます。割と直感で使える形になっていたので、ライブラリについての詳しい説明は割愛します。
import { EPub } from "epub-gen-memory"; import fs from "fs"; // 手動で作ったXHTMLからbodyの中身を抽出する関数 const extractBody = (xhtmlPath) => { const content = fs.readFileSync(xhtmlPath, "utf-8"); const match = content.match(/<body[^>]*>([\s\S]*)<\/body>/); return match ? match[1] : ""; }; // 各章の本文を読み込み const chapters = [ { title: "一", content: extractBody("epub1/OEBPS/chapter1.xhtml") }, { title: "二", content: extractBody("epub1/OEBPS/chapter2.xhtml") }, { title: "三", content: extractBody("epub1/OEBPS/chapter3.xhtml") }, ]; // CSSは手動で作ったものと同じ const css = ` body { font-family: serif; line-height: 1.8; margin: 1em; writing-mode: vertical-rl; -webkit-writing-mode: vertical-rl; } h1 { text-align: center; font-size: 1.5em; margin-bottom: 2em; } p { text-indent: 1em; margin: 0.5em 0; } ruby rt { font-size: 0.6em; } `; // EPUBを生成 const epubInstance = new EPub( { title: "変身", author: ["フランツ・カフカ"], lang: "ja", css, tocTitle: "目次", prependChapterTitles: false, }, chapters, ); const buffer = await epubInstance.genEpub(); fs.writeFileSync("henshin4.epub", buffer); console.log("henshin4.epub を生成しました!");
簡単でいいですね!書籍ごとにコピペして EPUB ファイルをビルドして、、、という手動よりコマンドをほぼ意識せずに作成できるので非常に便利でした。
最後に
今回は EPUB に初めて触れてみました。ひょんな疑問を記事にしてみたんですが、結構面白くて満足です。EPUB のドキュメントがかなり長く(その上英語だし翻訳も微妙に読みにくい感じになってしまうので)、結構奥が深そうだなと感じました。 ドキュメント化してリーダーに保存すればオフラインでも読めること、リーダーによってはメモ等が保存できるので個人的には便利なツールになってくれそうです。
下記リンクよりご応募お待ちしております!
iimon採用サイト / Wantedly / Green
参考・引用
https://techracho.bpsinc.jp/genki/2018_10_25/63573
https://www.jepa.or.jp/ebookpedia/201507_2529/
https://qiita.com/ryota_haga/items/d9b2efb45337544bb9ff
https://www.w3.org/TR/epub-33/
https://kdp.amazon.com/en_US/help/topic/GPNJPYK298J8TRRV
https://www.adobe.com/jp/acrobat/roc/blog/about-pdf.html