epub 概述
PS:上面的提醒是我手动加的。因为文章是从旧博客迁移过来的,更新时间达不到博客自带提醒的触发条件。
什么是 EPUB
EPUB 是一种自由开放的电子书格式,最初由国际数字出版论坛(International Digital Publishing Forum,简称 IDPF)推动制定,后来相关标准的维护工作转移到了 W3C。
EPUB 可以用来呈现固定布局的文档,也可以实现内容自动重排。所谓内容重排,就是电子书内容能够根据阅读设备的屏幕尺寸、字体大小、排版设置等自动调整显示方式。这也是 EPUB 相比许多固定版式文档更适合电子书阅读的原因之一。
EPUB 的发展可以追溯到 1999 年开放电子图书论坛(Open eBook Forum,简称 OeBF)提出的 OEBPS(Open eBook Publication Structure)。后来 OeBF 改名为 IDPF,OEBPS 也逐渐发展为 EPUB 标准的基础。
1999 年 9 月,OeBF 发布了 OEBPS 1.0。随后,OEBPS 又经历了 1.0.1 和 1.2 两次更新。2006 年,IDPF 发布 OCF 1.0(Open Container Format),用于定义 EPUB 的容器格式。2007 年,IDPF 发布 OPF 2.0(Open Packaging Format)和 OPS 2.0(Open Publication Structure),这也就是 EPUB 2.0 标准的重要组成部分。
2010 年,EPUB 2.0.1 发布。2011 年,EPUB 3.0 发布,进一步增强了对 HTML5、CSS、音频、视频、脚本和国际化排版等能力的支持。2014 年,EPUB 3.0.1 发布,作为 EPUB 3.0 的维护版本。2017 年,EPUB 3.1 发布。后来,随着 IDPF 与 W3C 合并,EPUB 标准的维护逐渐转移到 W3C 体系下。
目前常见的 EPUB 主要可以分为 EPUB 2 和 EPUB 3 两类。实际制作和拆包分析时,经常会遇到 EPUB 2 的结构;而较新的规范则以 EPUB 3 为主。本文主要以一个 EPUB 2 电子书文件为例,说明 EPUB 的基本文件结构。
EPUB 的文件结构
EPUB 文件本质上是一个 ZIP 压缩包。用 WinHex 或其它十六进制编辑器打开 EPUB 文件,可以看到 ZIP 文件常见的文件头,例如:
50 4B 03 04
因此,很多 EPUB 文件都可以直接把后缀名从 .epub 改成 .zip,然后用压缩软件解压查看内部结构。
EPUB 通常以 XML、CSS、XHTML 以及图片、字体等资源为基础。其中:
- XML 用于描述电子书的元数据、目录、文件清单等信息;
- XHTML 用于存放正文内容;
- CSS 用于控制排版和样式;
- 图片、字体等资源用于显示封面、插图和自定义字体。
以 [乙野四方字].我会呼唤你的名字.epub 为例,将文件重命名为 [乙野四方字].我会呼唤你的名字.zip,解压后可以看到类似下面的文件结构。为了便于展示,部分文件已省略:
│ mimetype
│
├─META-INF
│ container.xml
│
└─OEBPS
│ content.opf
│ toc.ncx
│
├─Fonts
│ ziti1-1.ttf
│ ...
│
├─Images
│ cover.jpg
│ note.png
│
├─Styles
│ style.css
│
└─Text
contents.xhtml
...
其中,mimetype 和 META-INF/container.xml 是 EPUB 中非常重要的两个文件。一般情况下,它们都是固定存在的。
需要注意的是,OEBPS 这个文件夹并不是强制要求使用的名称,只是一种常见约定。真正决定电子书主配置文件位置的,是 META-INF/container.xml 中的路径声明。
mimetype 文件
mimetype 是一个纯文本文件,内容固定为:
application/epub+zip
它用于标识这个 ZIP 容器是一个 EPUB 文件。
在标准 EPUB 文件中,mimetype 通常需要作为压缩包中的第一个文件,并且不应被压缩。这样阅读器或检测工具可以更快识别文件类型。
META-INF 文件夹
META-INF 文件夹用于存放 EPUB 容器相关的信息。默认情况下,该目录中至少会包含一个 container.xml 文件。
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>
其中,rootfile 元素的 full-path 属性指定了 OPF 文件的位置。阅读器会根据这个路径找到 EPUB 的主配置文件。
除了 container.xml 外,META-INF 中还可能出现以下文件:
manifest.xml:文件列表;metadata.xml:元数据;signatures.xml:数字签名;encryption.xml:加密信息;rights.xml:权限管理信息。
这些文件并不是每本 EPUB 都必须包含的内容,普通 EPUB 制作或拆包查看时不必过于关注。
OEBPS 文件夹
在许多 EPUB 文件中,OEBPS 文件夹用于存放真正的图书内容,包括:
content.opf:电子书的主配置文件;toc.ncx:目录文件;- XHTML 正文文件;
- CSS 样式文件;
- 字体文件;
- 图片文件。
常见的资源文件夹命名如下:
Fonts:字体文件;Images:图片文件;Styles:CSS 样式文件;Text:XHTML 正文文件。
这些文件夹名称并不是强制规定,只是常见的组织方式。只要在 OPF 文件中正确声明路径,阅读器就可以找到对应资源。
OPF 文件
OPF 文件是 EPUB 中最重要的文件之一,本质上是一个 XML 文件。它负责描述电子书的元数据、文件清单、阅读顺序等信息。
OPF 文件的根元素是 <package>,常见属性如下:
xmlns:指定 XML 命名空间,EPUB 2 中通常为http://www.idpf.org/2007/opf;version:指定 EPUB 规范版本,例如2.0或3.0;unique-identifier:指定电子书的唯一标识符,对应<metadata>中某个<dc:identifier>的id。
例如:
<package version="2.0" unique-identifier="BookId" xmlns="http://www.idpf.org/2007/opf">
其中,BookId 实际上是一个标识符 ID,需要在后面的 <metadata> 中定义。
OPF 文件通常由以下几部分组成:
<metadata>:元数据;<manifest>:文件清单;<spine>:阅读顺序;<guide>:特殊页面索引,EPUB 2 中常见;<tour>:导读信息,较少使用。
metadata:元数据
<metadata> 用于描述电子书的基本信息,例如标题、作者、语言、主题、出版日期等。
它通常会使用 Dublin Core 元数据元素,也就是常见的 dc:title、dc:creator、dc:language 等标签。
常见元素如下:
<dc:title>用于描述书名。
<dc:title>Introduction to XML</dc:title><dc:creator>用于描述作者。
<dc:creator>John Doe</dc:creator><dc:subject>用于描述主题或关键词。
<dc:subject>XML</dc:subject><dc:description>用于描述简介、摘要或说明。
<dc:description>This document provides an introduction to XML.</dc:description><dc:publisher>用于描述出版商或发行者。
<dc:publisher>XYZ Publications</dc:publisher><dc:contributor>用于描述贡献者,例如编辑、译者、校对者等。
<dc:contributor>Editor: Jane Smith</dc:contributor><dc:date>用于描述日期,通常是创建日期、出版日期或修改日期。
<dc:date>2022-01-21</dc:date><dc:type>用于描述资源类型。
<dc:type>Text</dc:type><dc:format>用于描述资源格式。
<dc:format>application/epub+zip</dc:format><dc:identifier>用于描述资源的唯一标识符,可以是 UUID、URL、ISBN 等。
<dc:identifier id="BookId">urn:uuid:5208e6bb-5d25-45b0-a7fd-b97d79a85fd4</dc:identifier><dc:source>用于描述资源来源。
<dc:source>https://example.com/collection</dc:source><dc:language>用于描述语言。
<dc:language>zh</dc:language><dc:relation>用于描述与其它资源之间的关系。
<dc:relation>Is Part Of: XYZ Series</dc:relation><dc:rights>用于描述版权和使用权限。
<dc:rights>Copyright © 2022, All Rights Reserved</dc:rights>
除了 Dublin Core 元素外,metadata 中还可以出现 <meta> 标签,用于补充一些扩展信息。例如:
<meta name="cover" content="cover.jpg"/>
需要注意的是,这里的 cover.jpg 通常不是文件路径,而是 <manifest> 中声明的某个文件 ID。
例如:
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title>我会呼唤你的名字</dc:title>
<dc:creator opf:file-as="末影服" opf:role="aut">乙野四方字</dc:creator>
<dc:language>zh</dc:language>
<dc:subject>轻小说</dc:subject>
<dc:description>EPUB制作:末影服</dc:description>
<dc:date opf:event="modification">2022-10-07</dc:date>
<meta content="1.7.0" name="Sigil version"/>
<dc:identifier id="BookId" opf:scheme="UUID">urn:uuid:5208e6bb-5d25-45b0-a7fd-b97d79a85fd4</dc:identifier>
<meta name="cover" content="cover.jpg"/>
</metadata>
manifest:文件清单
<manifest> 用于列举电子书中包含的所有资源文件,例如 XHTML 文档、图片、样式表、字体文件等。
每个文件通过一个 <item> 元素声明。例如:
<item id="cover.jpg" href="Images/cover.jpg" media-type="image/jpeg"/>
其中:
id:文件 ID,在 EPUB 内部用于引用该资源;href:文件的相对路径;media-type:文件的媒体类型。
示例:
<manifest>
<item id="Section001.xhtml" href="Text/Section001.xhtml" media-type="application/xhtml+xml"/>
<item id="Section002.xhtml" href="Text/Section002.xhtml" media-type="application/xhtml+xml"/>
<item id="Section003.xhtml" href="Text/Section003.xhtml" media-type="application/xhtml+xml"/>
<item id="Summary.xhtml" href="Text/Summary.xhtml" media-type="application/xhtml+xml"/>
<item id="contents.xhtml" href="Text/contents.xhtml" media-type="application/xhtml+xml"/>
<item id="cover.jpg" href="Images/cover.jpg" media-type="image/jpeg"/>
<item id="cover.xhtml" href="Text/cover.xhtml" media-type="application/xhtml+xml"/>
<item id="message.xhtml" href="Text/message.xhtml" media-type="application/xhtml+xml"/>
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
<item id="note.png" href="Images/note.png" media-type="image/png"/>
<item id="style.css" href="Styles/style.css" media-type="text/css"/>
<item id="title.xhtml" href="Text/title.xhtml" media-type="application/xhtml+xml"/>
<item id="ziti2.ttf" href="Fonts/ziti2.ttf" media-type="font/ttf"/>
<item id="ziti3.ttf" href="Fonts/ziti3.ttf" media-type="font/ttf"/>
</manifest>
spine:阅读顺序
<spine> 用于定义电子书正文的阅读顺序。阅读器通常会按照 <spine> 中的顺序依次显示内容。
<spine> 由多个 <itemref> 子元素组成。例如:
<itemref idref="cover.xhtml"/>
其中,idref 对应的是 <manifest> 中某个 <item> 的 id。
示例:
<spine toc="ncx">
<itemref idref="cover.xhtml" properties="duokan-page-fullscreen"/>
<itemref idref="title.xhtml"/>
<itemref idref="message.xhtml"/>
<itemref idref="Summary.xhtml"/>
<itemref idref="contents.xhtml"/>
<itemref idref="Section001.xhtml"/>
<itemref idref="Section002.xhtml"/>
</spine>
在 EPUB 2 中,toc="ncx" 用于指定 NCX 目录文件的 ID。这个 ID 需要在 <manifest> 中提前声明:
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
guide:特殊页面索引
<guide> 用于列出电子书中的特殊页面,例如封面、目录、正文起始页等。该部分在 EPUB 2 中比较常见,但不是必须存在。
例如:
<guide>
<reference type="toc" title="Table Of Contents" href="Text/contents.xhtml"/>
<reference type="cover" title="Cover" href="Text/cover.xhtml"/>
</guide>
其中:
type:页面类型;title:页面标题;href:对应文件路径。
tour:导读
<tour> 用于按照一定顺序组织电子书中的部分页面,形成导读路径。这个元素较少见,普通 EPUB 制作中基本不会使用。
NCX 文件
NCX 文件是 EPUB 2 中常见的目录文件,通常命名为 toc.ncx。它本质上也是一个 XML 文件,用于描述电子书的目录结构。
需要注意的是,EPUB 3 中主要使用 XHTML 格式的导航文档,也就是常见的 nav.xhtml。不过为了兼容旧阅读器,有些 EPUB 3 文件中仍然会保留 toc.ncx。
下面以解压 [乙野四方字].我会呼唤你的名字.epub 后得到的 toc.ncx 为例进行说明。
head:目录头部信息
toc.ncx 中的 <head> 通常类似下面这样:
<head>
<meta name="dtb:uid" content="urn:uuid:5208e6bb-5d25-45b0-a7fd-b97d79a85fd4"/>
<meta name="dtb:depth" content="2"/>
<meta name="dtb:totalPageCount" content="0"/>
<meta name="dtb:maxPageNumber" content="0"/>
</head>
其中:
dtb:uid:电子书的唯一标识符,通常与 OPF 文件中的<dc:identifier>保持一致;dtb:depth:目录层级深度;dtb:totalPageCount:总页数,普通 EPUB 中通常为0;dtb:maxPageNumber:最大页码,普通 EPUB 中通常为0。
严格来说,dtb:uid 与 OPF 文件中的标识符最好保持一致。即使不一致,某些阅读器也可能正常打开,但不建议这样做。
docTitle:目录标题
<docTitle> 用于描述目录文件对应的书名,通常写法如下:
<docTitle>
<text>作品名</text>
</docTitle>
这里的书名最好与 OPF 文件中的 <dc:title> 保持一致。即使不一致,阅读器通常也会以 OPF 中的书名为准。
navMap:目录结构
NCX 文件中最主要的节点是 <navMap>。
<navMap> 由多个 <navPoint> 节点组成。每个 <navPoint> 表示一个目录项,可以对应封面、制作信息、章节、后记等内容。
<navPoint> 中常见的子节点包括:
<navLabel>:目录显示名称;<content>:目录项指向的文件路径。
其中,playOrder 属性用于定义当前目录项在目录中的顺序,content 节点的 src 属性用于定义章节文件的位置。
<navPoint> 之间也可以嵌套,从而形成多级目录结构。
示例:
<navMap>
<navPoint id="navPoint-1" playOrder="1">
<navLabel>
<text>封面</text>
</navLabel>
<content src="Text/cover.xhtml"/>
</navPoint>
<navPoint id="navPoint-2" playOrder="2">
<navLabel>
<text>制作信息</text>
</navLabel>
<content src="Text/message.xhtml"/>
</navPoint>
<!-- 中间部分省略 -->
<navPoint id="navPoint-29" playOrder="29">
<navLabel>
<text>终章,又或是在世界的某处</text>
</navLabel>
<content src="Text/Section009.xhtml"/>
</navPoint>
</navMap>
小结
简单来说,EPUB 可以理解为一个按照特定规则组织起来的 ZIP 压缩包。它的核心结构大致如下:
EPUB 文件
├─ mimetype
├─ META-INF
│ └─ container.xml
└─ 图书内容目录
├─ content.opf
├─ toc.ncx / nav.xhtml
├─ XHTML 正文
├─ CSS 样式
├─ 图片
└─ 字体
其中:
mimetype用于声明文件类型;container.xml用于指向 OPF 文件;content.opf用于描述元数据、文件清单和阅读顺序;toc.ncx或nav.xhtml用于描述目录;- XHTML、CSS、图片、字体等文件共同组成电子书的正文和资源。
理解这些文件之间的关系之后,再去拆包、修改、制作 EPUB 就会清晰很多。