電子書的規範

由於公司有開發電子書的需求,遂希望有一個便於製作電子書的平台,功能不外乎有匯入文章、編輯文章、編輯目錄與書籍資訊⋯⋯等,最後『一鍵匯出電子書』。功能本身不難,但要先理解電子書的架構,確保符合電子書規範;以前未接觸過這領域,所以簡單紀錄一下學習內容。

電子書的架構

一本電子書 epub 主要由三個規範組成,分別是 OCFOPFOPS

  • OCF (Open Container Format)

    以 zip 封裝所有檔案,完成一個 epub 容器。

  • OPF (Open Packaging Format)

    以 xml 描述 epub 的檔案結構,連結各種資源。

  • OPS (Open Publication Structure)

    以 xhtml 建構電子書內容,確保內容一致性。

總結來說,一個 epub 先遵守最底層的 OPS 規範來製作內容,接著透過 OPF 規範組織內容,最後以 OCF 規範完成封裝,形成一個 epub 檔。

也由於 epub 遵循 OCF 規範以 zip 封裝,因此也可以反封裝 epub,得到下面的檔案結構:

- META-INF
    - container.xml
- OEBPS
    - content.opf
    - toc.ncx
    - xxx.xhtml
- mimetype

提醒

mimetype 與 container.xml 為 OCF 所規範,檔名與檔案位置皆不可改。

content.opf 為 OPF 所規範,檔名與檔案位置未嚴格限制,但多數電子書開發工具習慣以此命名,並與 OPS 所規範的檔案合併在 OEBPS (Open eBook Publication Structure) 目錄。

mimetype

mimetype 對應 OCF 規範,主要用來宣告電子書的檔案類型,內容僅有一行:

application/epub+zip

注意

mimetype 檔名不可更改,且內容不能包含空格與其他空白行。

container.xml

container.xml 同樣對應於 OCF 規範,是電子書閱讀軟體優先讀取的檔案,主要紀錄 opf 檔的位置,引導電子書閱讀軟體讀取 opf 檔,進而獲取 OPS 內容( opf 檔主要描述這本電子書包含哪些受 OPS 規範的內容)。檔案內容如下:

<?xml version="1.0"?>
<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>

基本上,唯一會改的可能只有 <rootfile>full-path 這個屬性,要注意的是其路徑是相對於整個電子書的專案頂層,而不是相對於 META-INF 目錄。

content.opf

content.opf 顧名思義,對應的是 OPF 規範,主要紀錄電子書內容資源的位置,指引電子書閱讀軟體找到屬於 OPS 所規範的檔案。內容大致如下:

<?xml version='1.0' encoding='utf-8'?>
<package version="2.0"
    xmlns="http://www.idpf.org/2007/opf"  
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    unique-identifier="book_id">
    <metadata>
        <dc:title>...</dc:title>
        <dc:identifier id="book_id">...</dc:identifier>
    </metadata>
    <manifest>
        <item id="ncx" href="toc.ncx"
         media-type="application/x-dtbncx+xml"/>
        <item id="ch1" href="ch1.xhtml"
         media-type="application/xhtml+xml"/>
        ...
    </manifest>
    <spine toc="ncx">
        <itemref idref="ch1"/>
        ...
    </spine>
</package>
<package> schemas & namespace

epub 是由國際數位出版論壇 (International Digital Publishing Forum, IDPF) 所提出的電子書格式,因此須引用 http://www.idpf.org/2007/opf 為命名空間;此外在描述 <metadata> 時也引用了 Dublin Core 的元素集,因此也須加入 http://purl.org/dc/elements/1.1/

<metadata>

Dublin Core 定義一組常用項目來描述多種數位內容(不單為了電子書),epub 引入了這些項目,因此可在 <metadata> 中定義:

titleidentifier 為必要項目,依照規範 identifier 必須是唯一值,出版商一般會使用含 ISBN 在內的一組字串;其他書籍創造者則使用一組隨機產生的 UUID 填寫。

提示

<dc:identifier>id 須對應 <package>unique-identifier

<manifest>

電子書的『內容』一般是編輯在 xhtml 裡面,<manifest> 負責指出所有在電子書專案中與這些內容相關的檔案。要注意的是:除了 xhtml 本身之外,該檔案所引入的 css、image⋯⋯等樣式等、媒體檔,也要列入裡面。

提示

每個檔案都必須賦予一個 id,並標記該檔案的位置 (href) 與媒體類型 (media-type),幫助閱讀軟體能夠找到並打開該檔案。

除了與內容相關的檔案之外,<manifest> 還會列出一個與 metadata 相關的檔案:toc.ncx

<spine>

條列完這本電子書有哪些內容資源後,接下來要想辦法組織、編排,便在 <spine> 處理,告訴閱讀軟體這些內容資源的讀取順序,也就是我們讀者的閱讀順序。

提示

<spine>toc 必須與 <manifest> 中指向 toc.ncx 的 <item>id 一致。

每個 <itemref> 都要有一個 idref,同樣要與 <manifest> 中所對應的 <item>id 一致。

toc.ncx

僅管前述的 content.opf 已經定義了大多數 metadata,但 epub 還同時借用了 DAISY 的 NCX (Navigation Center eXtended) DTD 來定義書籍的目錄表格,以應付複雜的書籍目錄 (例如分層章節這種巢狀目錄結構)。大致內容如下:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN" "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
    <head>
        <meta name="dtb:uid" content="..."/>
        <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="navpoint-1" playOrder="1">
            <navLabel><text>Chapter 1</text></navLabel>
            <content src="ch1.xhtml"/>
        </navPoint>
        ...
    </navMap>
</ncx>
<meta>

toc.ncx 須在 <head> 加入 4 個 <meta> 元素:

  • uid 為電子書的唯一ID,應與 content.opf 中的 dc:identifer 一致。

  • depth 為目錄層級。

  • totalPageCountmaxPageNumber 主要應用於紙本書籍,因此在電子書這邊可設為 0 就好。

<docTitle>

電子書的書籍名稱,應與 content.opf 中的 dc:title 一致。

主要描述電子書內容的順序,是 ncx 檔中最重要的一個部分。它包含了多個 <navPoint> 元素,每個 navPoint 相當於目錄節點,其 <navLabel> 底下的 <text> 內容即節點標題,而 <content> 則對應該節點所連結的檔案資源。

說明

ncx 的 <navMap> 與 opf 的 <spine> 皆描述了電子書內容的順序,然而實際上有很大的差異,較好的解讀方式是用紙本書類比:

  • opf <spine> 的描述相當於紙本書的『裝訂』,將書的各章節『實際』裝訂在一起。例如將第一章與第二章綁定,那麼在閱讀到第一章的最後一頁時,翻下一頁即會接續閱讀第二章的第一頁。

  • ncx <navMap> 的描述則是書籍的目錄,目錄所顯示的編排順序未必等同於實際的裝訂順序。今天也許你點了目錄的第一篇文章,實際上卻跳到了書籍的最後一篇;明明目錄顯示後面還有文章,卻無法透過翻下一頁跳轉,只能點回目錄重新選下一篇文章跳轉。

xxx.html

在電子書內容的編輯方面,主要以 xhtml 為主,其開發方式與 html 類似,大致內容如下:

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>BOOK TITLE</title>
    <link type="text/css" rel="stylesheet" href="stylesheet.css" />
  </head>
  <body>
    <!--  將書籍內容以 html 元素呈現 -->
  </body>
</html>

不過 epub 雖沒有對 xhtml 有特定規範,但與一般網頁開發相比還是有些要注意的地方,例如:

  • 使用圖片時盡可能參考本地端圖檔,避免從外部連結引入,否則當閱讀裝置連不到網路時,電子書的圖片便無法呈現。

  • epub 3.0 雖已可執行 javascript,但 epub 並未要求每個裝置都必須能夠支援執行 js,因此非必要時仍盡量避免使用 script 區域。

  • epub 並非完全支援所有 css 的效果等。

封裝電子書

將所有內容都開發好後,透過 zip 指令封裝,就可以完成一本 epub 電子書了。

$ zip -0 -X xxx.epub mimetype
$ zip -9 -r xxx.epub */

注意

封裝時,mimetype 必須是 zip 內的第一個檔案,且本身不可被壓縮。

流式版型 (Float Layout)

前面紀錄了電子書的規範跟架構,接下來紀錄下電子書中幾個常用的版型,最常見的就是——流式版型。

隨著視窗流動

流式版型的特色,就是讓電子書像網頁一般,在不同螢幕大小的裝置讓文字重新編排,以最適於該裝置的形式提供閱讀。因此,同樣一篇文章,在電腦螢幕可能只有四十行,每行三十個字;到了手機螢幕卻變成有八十行,每行則只有十五個字,以適應手機螢幕寬度較窄但高度較高的閱讀方式。

甚至,有些裝置的閱讀器還會提供調整字體大小的功能,即使是不同的字體大小,流式版型也會重新調整文字排列,不會讓文章超出版面。

那麼…

要怎麼設定讓電子書成為流式版型呢?

什麼都不用做 (喂)

預設就是流式版型

電子書的格式之所以被提出,就是為了讓書本內容在不同電子裝置上也能被舒適地閱讀;OPS 規範中明確定義書的內容必須以 xhtml 建構,以確保內容在各裝置的一致性。因此,我們並不需要做什麼特別的設定,要的僅僅是對一些例外情況做 CSS 調整:

比如說⋯⋯ 中文小說的『竪排右書』排版

向左走向右走

儘管在網頁的世界中,大部分中文網頁都已經是『橫排左書』的排版方式,我們也都已經習慣『由左至右、由上而下』的閱讀順序;但在中文書籍中(特別是小說類書籍)仍有多數內容使用『竪排右書』、也就是『由上而下、由右至左』的閱讀順序排版。

為了讓內容在電子書上面以竪排右書的方式呈現,我們需要對 CSS 進行一些設定。epub 3 支援 CSS 3,令許多原本不可能的事情一下成真——例如改變文字的排列方向,調整 CSS 設定的writing-model

@namespace "http://www.w3.org/1999/xhtml";
@namespace epub "http://www.idpf.org/2007/ops";
html {
  -ms-writing-mode: tb-rl;
  -epub-writing-mode: tb-rl;
  -webkit-writing-mode: tb-rl;
  writing-mode: tb-rl;
}

提示

t、b、r、l 即 top、bottom、right、left。

提醒

在設定 writing-model 時,必須特別注意『連號前後的順序』,tb-rl 與 rl-tb 代表的是完全不同的意思:

  • tb-rl 為『由上至下,再由右至左』,是中文小說的常見排版。

  • rl-tb 為『由右至左,再由上至下』,會變成從右邊開始書寫,完成一個『橫排』之後再寫下一個橫排的奇妙版型。

眼睛往哪看

文字排列的方向不同,連帶影響的是閱讀方向也不同,當然書籍頁面的方向也會不同。一般來說,橫排左書的書籍頁面習慣由左至右,上一頁在左邊,下一頁在右邊,翻頁時是由右往左翻頁;竪排右書的書籍 (或是其他如圖畫書、漫畫等) 則相反,頁面習慣由右至左,下一頁在上一頁的左邊,翻頁時則是由左至右翻頁。

如何設置電子書的頁面方向?

只要在 OEBPS/content.opf 檔案中,編輯 <spine> 的 page-progression-direction 屬性為 ltr(由左至右,預設)或 rtl(由右至左)即可。

...
<spine toc="ncx" page-progression-direction="rtl">
  <itemref idref="cover" linear="no"/>
  <itemref idref="ch1"/>
    ...
</spine>
...

其他的小設定

在一本書籍當中,封面是重要的一環,許多人會將封面設置在 <metadata> 中,一些閱讀器也會從這邊抓取封面,以此作為在閱讀器書籍清單中顯示的封面。

封面頁除了在閱讀器的書籍清單顯示之外,也會作為書籍內容的一部分顯示在書籍當中。但是,讀者在進入書籍內容前,早已在書籍清單中看過封面,實在不需要在翻開書後再看一次封面,因此可以在 <spine> 中作為封面頁的 <itemref> 設置 liner 屬性為 no,意思為此項目不會出現在讀者的閱讀順序中,讀者進入這本書時將會忽略此項目,直接進入下一個內容。

...
<metadata>
  ...
  <meta name="cover" content="img" />
</metadata>
<manifest>
  ...
</manifest>
<spine toc=”ncx” page-progression-direction="rtl">
  <itemref idref=”cover” linear=”no”/>
  ...
</spine>
...

提示

<meta>content 須與 <manifest> 中作為封面圖的 <item>id 一致。

固定版型 (Fixed Layout)

流式版型雖然有利於在不同裝置間閱讀,但對於版型的可控性很低,較適合以文字為主的內容;對於一些需高度依賴版型的內容(例如以圖畫為主的圖文書),則需要採用另一種固定版型 (Fixed Layout) 才行。

定住不許動

有些書籍內容(例如圖文書)不像流式版型的內容,適合跟著螢幕的大小跟比例而調動;圖跟文必須緊密相連,才能保留原本要傳達的意義。為了因應這些內容,epub 提供了固定版型的設定,讓創作者能夠更好地發揮。

內容設定

固定版型的內容同樣遵循 OPS 規範,由 xhtml 建構;但與流式版型不同的是,除了 xhtml 之外,固定版型也支援 svg、bitmap images 等組成內容,因此創作者也可將圖文輸出成圖片來呈現。

不論以哪種檔案類型來編輯內容,首先要定義 ICB (initial containing block) dimensions,可看作是定義版型的大小 / 比例,以此來固定版型。

若內容是以 xhtml 建構,須在 <head> 中定義 viewportmeta

<head>
   ...
   <meta name="viewport" content="width=1200, height=600"/>
   ...
</head>

而若是 svg,則定義其 viewBox

<svg xmlns="http://www.w3.org/2000/svg"
   version="1.1" width="100%" height="100%"
   viewBox="0 0 844 1200">
   ...
</svg>

提示

viewBox 的四個參數分別是 min-x、min-y、width、height。

最後若是 bitmap images,則會以圖片原始寬高來直接設定。

綁定內容順序

完成 OPS 所規範的內容之後,接著是 OPF 的部分,固定版型的 opf 檔與流式版型在設定方面有些許不同:

由於接下來在 <metadata> 中會設定 rendition 屬性,因此在 <package> 中加入 prefix 屬性,並將其對應到 http://www.idpf.org/vocab/rendition/ (當然原先在流式版型中的設定還是要有)。

<package ... 
   prefix="rendition: http://www.idpf.org/vocab/rendition/#">
   <metadata>
      ...
      <meta property="rendition:layout">pre-paginated</meta>
      <meta property="rendition:orientation">auto</meta>
      <meta property="rendition:spread">auto</meta>
   </metadata>
   ...
   <spine toc="ncx" page-progression-direction="rtl">
      ...
      <itemref idref="s4" properties="rendition:page-spread-left"/>
      ...
   </spine>
</package>

接著在 <metadata> 中設定 rendition,共有 layoutorientaionspread 三個面向:

  • rendition:layout

    主要設定書籍內容的分頁版型,有兩種:

    • reflowable

      書籍內容沒有被事先分頁,當螢幕足夠一次呈現兩頁時,系統會自動不斷地將下一頁遞補呈現。

    • pre-paginated

      書籍的部份內容 (spine item) 有被事先分頁,通常適用於一張圖版面過大,不得被拆開成兩頁呈現時,確保這兩頁必須在同一面呈現。

  • rendition:orientation

    設定閱讀裝置要以哪種方向開啟書籍內容:

    • auto

      原始設定,依閱讀裝置當前的方向來開啟書籍內容。

    • landscape

      強制閱讀裝置以水平模式開啟書籍內容。

    • portrait

      強制閱讀裝置以垂直模式開啟書籍內容。

  • rendition:spread

    設定當閱讀裝置為何種情況時,能夠雙頁顯示:

    • none

      設定裝置在不論何種情況下都只能單頁呈現,不會雙頁顯示。

    • landscape

      閱讀裝置只在水平模式下才會雙頁顯示。

    • portrait

      閱讀裝置只在垂直模式下才會雙頁顯示。

    • both

      不論閱讀裝置在何種情況下都能雙頁顯示。

    • auto

      由閱讀系統自行判斷裝置是否適合雙頁顯示。

編輯目錄

編輯完 opf 之後,這本書基本上就已經成形了,接著提供目錄便大功告成。相較於以文字為主的流式版型,固定版型多是以圖為主,層級也都是一頁一頁的單層結構,不像流式版型得動用到巢狀結構的目錄。

打開 ncx ,一般流式版型是透過支援巢狀結構的 <navMap> 來定義目錄:

<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
   ...    
   <navMap>
      <navPoint id="navpoint-1" playOrder="1">
         <navLabel><text>Chapter 1</text></navLabel>
         <content src="ch1.xhtml"/>
      </navPoint>
      ...
   </navMap> 
</ncx>

固定版型則是透過 <pageList> 來定義:

<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
   ...    
   <pageList>
      <pageTarget type="normal" value="1">
         <navLabel><text>1</text></navLabel>
         <content src="s1.svg"/>
      </pageTarget>
      ...
   </pageList> 
</ncx>

提示

pageTarget 中,value 指的是該頁的頁數,type 則有三種類型:

  • front 通常指目錄頁、前言使用的羅馬數字。
  • normal 是一般常用的阿拉伯數字。
  • special 指其他特殊數字。

至此,一本固定式版型的電子書完成,最後透過 OCF 規範將檔案以 zip 形式封裝成 epub 後就結束了。

2019 更新

先前開發的 ncx 已是 epub 2 時代的產物,epub 3 改用 Navigation Document 來取代,詳細可參考官方文件

Last Updated: 7/27/2019, 10:14:16 PM