ePub 阅读/转换

ePub→PDF/Mobi/TXT

413 次访问
EPUB READER · LOCAL

ePub 在线阅读器

上传 .epub 浏览器内阅读 · 目录 / 翻页 / 字号 / 暗色 · 基于 epub.js

📚
点击 / 拖拽 ePub 文件

关于 ePub

ePub(Electronic Publication)是国际数字图书馆联盟(IDPF)2007 年制定的电子书标准,基于 HTML + XML + CSS,本质是 ZIP 压缩包。

支持设备:iBooks / Kindle (转 MOBI) / Calibre / Adobe Digital Editions / 多看阅读 / 微信读书 / 几乎所有电子书阅读器。

本地阅读:基于 epub.js 浏览器解析,文件永不上传,隐私安全。适合临时查看 / 试读。

DRM 加密:本工具不支持 Adobe DRM 加密的 ePub(亚马逊 / Google Play Books 等付费书需破解)。

关于本工具

了解工具定位 · 使用场景 · 对比优势

使用场景

📖

Kindle 阅读迁移

Kindle 用户购买了大量 ePub 电子书,但 Kindle 原生只支持 Mobi/AZW3。将 ePub 批量转换为 Mobi 格式后,可直接通过邮件推送至 Kindle 设备或 App,保留原书目录、字体样式和图片排版,无需在电脑上安装 Calibre 等重型软件。

🎓

学术批注整理

研究生阅读大量学术 ePub 文献,但 iPad 上做笔记时 PDF 的批注工具更成熟。将 ePub 转为 PDF 后,可在 GoodNotes / Notability 中直接划线、写批注、导出高亮摘要,同时保留原书页码和脚注链接,避免手动翻页定位。

💻

离线文档存档

运营人员需要将公司内部的 ePub 培训手册转为纯文本 TXT 格式,以便在老旧工控机、Linux 终端或仅支持纯文本的阅读器上查看。转换后文件体积缩小 90% 以上,且无需安装任何 ePub 阅读软件,直接 cat 或 notepad 即可浏览。

📱

微信读书导入

微信读书支持导入 ePub 但部分自制书排版异常(字体过小、章节错乱)。先将 ePub 转为标准 PDF,再导入微信读书,可强制锁定字体大小和行间距,避免 App 端重新排版导致的格式崩坏,尤其适合带代码块或表格的技术类电子书。

🖨️

纸质书打印排版

设计师需要将 ePub 格式的电子书打印为纸质样书,但直接打印 ePub 会丢失页眉页码、边距过窄。转为 PDF 后在打印前可自定义纸张尺寸(A5/B5)、设置对称页边距、添加裁剪标记,输出可直接送印厂的标准印刷文件。

对比矩阵本工具 vs 竞品 vs 传统方法

维度本工具CalibreSigil
操作方式在线转换,上传即转需下载安装桌面软件需下载安装桌面软件
处理速度秒级完成秒级完成分钟级(需手动编辑)
转换格式范围ePub → PDF / Mobi / TXTePub ↔ 几乎所有格式仅编辑 ePub,不直接转换
学习成本零学习,即开即用中等,功能复杂需学习较高,需了解 HTML/CSS
适用场景快速转换单一文件批量转换、管理电子书库深度编辑 ePub 源码

使用指南

上手步骤 · 输入输出 · 避坑提示

输入输出示例7 个典型场景,覆盖常规、边界与易错

输入输出说明
example.epubexample.pdf典型场景:将 ePub 转换为 PDF 格式
example.epubexample.mobi典型场景:将 ePub 转换为 Kindle 支持的 Mobi 格式
example.epubexample.txt典型场景:提取纯文本内容,去除排版和图片
large_book.epub (50MB)large_book.pdf (处理时间约 10 秒)边界 case:大文件转换,测试性能上限
no_cover.epubno_cover.pdf (无封面页)边界 case:ePub 缺少封面元数据时的输出
corrupted.epub错误:文件格式损坏,无法解析易错 case:损坏的 ePub 文件导致转换失败
empty.epub错误:文件中无有效内容易错 case:空文件或仅有空章节的 ePub

常见错误对照8 个常踩的坑 · 错误 → 修复

1. 把 EPUB 文件重命名为 .zip 再上传

错误
将 .epub 文件手动改为 .zip 扩展名后上传到工具
修复
直接上传原始的 .epub 文件,无需任何重命名操作

EPUB 本质是 ZIP 压缩包,但工具已内置解压逻辑;重命名会破坏文件签名,导致工具无法识别为有效 EPUB 文件。

2. 上传带 DRM 加密的 EPUB 文件

错误
上传从 Amazon/Kobo 购买的受 DRM 保护的 .epub 文件
修复
仅上传无 DRM 的 EPUB 文件(如自出版、古登堡计划、开源电子书)

DRM 加密的 EPUB 内部文件被加密锁住,工具无法解密读取;需先通过合法手段(如 Calibre + DeDRM 插件)去除 DRM 后再转换。

3. 用 TXT 输出保留 EPUB 的排版样式

错误
选择输出格式为 TXT,抱怨转换后丢失了加粗、斜体、图片
修复
需要保留排版样式时,选择输出格式为 PDF 或 Mobi;TXT 仅保留纯文本内容

TXT 格式不支持任何富文本(字体、颜色、图片、表格),这是纯文本格式的固有约束,非工具缺陷。

4. 上传 EPUB 文件但期望输出包含字体嵌入

错误
上传包含特殊艺术字体的 EPUB,转换后 PDF 中字体显示为默认宋体/黑体
修复
若需保留特定字体,确保 EPUB 内嵌了字体文件(.otf/.ttf),且转换时选择 PDF 格式

EPUB 中引用系统字体在 PDF 转换时可能找不到;只有内嵌字体才能被 PDF 渲染引擎正确使用。

5. 使用 Mobi 输出但在 Kindle 上遇到排版错乱

错误
将复杂排版的 EPUB(多栏、浮动图片)转为 Mobi 后发送到 Kindle
修复
对于复杂排版的 EPUB,优先选择 PDF 输出;或先用工具转为 Mobi 再在 Kindle Previewer 中预览

Mobi 格式对 CSS 支持有限(尤其是浮动、多栏、SVG),Kindle 渲染引擎会降级处理,导致布局变形。

6. 上传超大 EPUB 文件(>50MB)导致转换超时

错误
上传包含大量高清图片的 EPUB(如漫画、扫描本),文件大小超过 100MB
修复
将 EPUB 中的图片压缩至 1-2MB/张后再上传;或分章节转换

浏览器端/服务端对上传文件大小有默认限制(通常 50MB),且大文件转换耗时过长可能触发超时。

7. 误以为 EPUB 转 PDF 后仍可编辑文字

错误
将 EPUB 转为 PDF 后,用 PDF 阅读器选中文字却发现无法复制/搜索
修复
转换后检查 PDF 是否为「扫描版」;若原 EPUB 是纯文本排版,PDF 应保留可选中文字;若原 EPUB 是图片扫描本,PDF 也是图片

PDF 的「可选中文字」取决于源文件是否包含文本层;若 EPUB 本身是图片扫描件(如 PDF 转 EPUB),转换后 PDF 仍为图片。

8. 使用 EPUB 转 TXT 后得到乱码或空白

错误
上传中文 EPUB 文件,选择 TXT 输出,下载后打开显示乱码
修复
确认 EPUB 文件的编码为 UTF-8(大多数现代 EPUB 默认),且文本阅读器也设置为 UTF-8 编码

部分老旧 EPUB 使用 GBK/GB2312 编码,TXT 输出默认 UTF-8 会导致乱码;可先用工具查看 EPUB 内部文件编码再转换。

工作原理

公式推导 · 流程图解 · 依据出处

核心公式

转换过程无单一数学公式,核心为 EPUB 内部 XHTML/CSS 到目标格式(PDF/Mobi/TXT)的解析与重排。

示例

示例:一个 EPUB 文件包含 10 个 XHTML 章节,每个章节有 2000 字中文和 5 张图片。转换为 PDF 时,工具解析每个 XHTML 的 DOM 树,提取文本流和图片引用,按 A4 页面尺寸(210mm × 297mm)重新排版,生成 30 页 PDF。转换为 TXT 时,仅提取纯文本,丢弃所有样式和图片,输出约 20000 字的纯文本文件。转换为 Mobi 时,将 XHTML 转换为 Kindle 支持的 KF8 格式,保留基本排版(标题、段落、斜体)。

适用范围

适用于标准 EPUB 2/3 格式文件,不适用于加密(DRM)EPUB 或包含复杂交互脚本(JavaScript)的 EPUB。转换质量取决于 EPUB 内部标记的规范性。

原理图

上传 ePub 文件.epub 格式服务端解析解压 XML / XHTML提取文本与样式重构排版布局格式转换PDF / Mobi/ TXT下载结果文件说明• 文件仅暂存于服务端内存,转换完成后立即删除,不保留任何副本• 支持批量上传,单次最大 50MB
用户输入 服务端处理 格式转换 输出结果

开发者集成

3 种主流语言 · 复制即用

import zipfile
import xml.etree.ElementTree as ET
from pathlib import Path

# 解析 ePub(本质是 ZIP 包),提取纯文本内容
epub_path = "example.epub"
with zipfile.ZipFile(epub_path, "r") as z:
    # 读取容器文件获取 OPF 路径
    container = ET.fromstring(z.read("META-INF/container.xml"))
    ns = {"c": "urn:oasis:names:tc:opendocument:xmlns:container"}
    opf_path = container.find(".//c:rootfile", ns).get("full-path")

    # 解析 OPF 获取所有 HTML 文件列表
    opf = ET.fromstring(z.read(opf_path))
    pkg_ns = {"p": "http://www.idpf.org/2007/opf"}
    manifest = opf.find("p:manifest", pkg_ns)
    spine = opf.find("p:spine", pkg_ns)
    id_to_href = {item.get("id"): item.get("href") for item in manifest.findall("p:item", pkg_ns)}
    base_dir = Path(opf_path).parent

    # 按 spine 顺序提取文本
    texts = []
    for itemref in spine.findall("p:itemref", pkg_ns):
        href = id_to_href[itemref.get("idref")]
        content = z.read(str(base_dir / href)).decode("utf-8")
        # 简单去除 HTML 标签
        import re
        text = re.sub(r"<[^>]+>", "", content)
        texts.append(text.strip())

    print("\n".join(texts)[:500])  # 输出前 500 字符
package main

import (
	"archive/zip"
	"encoding/xml"
	"fmt"
	"io"
	"path/filepath"
	"regexp"
	"strings"
)

// 解析 ePub 容器文件
func main() {
	r, _ := zip.OpenReader("example.epub")
	defer r.Close()

	// 读取 META-INF/container.xml 获取 OPF 路径
	var container struct {
		Rootfiles []struct {
			FullPath string `xml:"full-path,attr"`
		} `xml:"rootfiles>rootfile"`
	}
	data, _ := readFileInZip(r, "META-INF/container.xml")
	xml.Unmarshal(data, &container)
	opfPath := container.Rootfiles[0].FullPath

	// 读取 OPF 获取 spine 顺序
	opfData, _ := readFileInZip(r, opfPath)
	type Opf struct {
		Manifest []struct {
			ID   string `xml:"id,attr"`
			Href string `xml:"href,attr"`
		} `xml:"manifest>item"`
		Spine []struct {
			IDref string `xml:"idref,attr"`
		} `xml:"spine>itemref"`
	}
	var opf Opf
	xml.Unmarshal(opfData, &opf)

	idToHref := make(map[string]string)
	for _, item := range opf.Manifest {
		idToHref[item.ID] = item.Href
	}

	baseDir := filepath.Dir(opfPath)
	re := regexp.MustCompile(`<[^>]+>`)
	for _, ref := range opf.Spine {
		href := idToHref[ref.IDref]
		content, _ := readFileInZip(r, filepath.Join(baseDir, href))
		text := re.ReplaceAllString(string(content), "")
		fmt.Println(strings.TrimSpace(text)[:200])
	}
}

func readFileInZip(r *zip.ReadCloser, name string) ([]byte, error) {
	for _, f := range r.File {
		if f.Name == name {
			rc, _ := f.Open()
			defer rc.Close()
			return io.ReadAll(rc)
		}
	}
	return nil, fmt.Errorf("file not found: %s", name)
}
// 浏览器端用 JSZip 解析 ePub 并提取纯文本
const JSZip = require('jszip');
const fs = require('fs');

async function extractEpubText(filePath) {
  const data = fs.readFileSync(filePath);
  const zip = await JSZip.loadAsync(data);

  // 读取容器文件
  const containerXml = await zip.file('META-INF/container.xml').async('string');
  const opfPath = containerXml.match(/full-path="([^"]+)"/)[1];

  // 读取 OPF 获取 spine 顺序
  const opfXml = await zip.file(opfPath).async('string');
  const idRefs = [...opfXml.matchAll(/<itemref[^>]+idref="([^"]+)"/g)].map(m => m[1]);
  const items = [...opfXml.matchAll(/<item[^>]+id="([^"]+)"[^>]+href="([^"]+)"/g)];
  const idToHref = Object.fromEntries(items.map(m => [m[1], m[2]]));

  const baseDir = opfPath.substring(0, opfPath.lastIndexOf('/') + 1);
  const texts = [];

  for (const id of idRefs) {
    const href = idToHref[id];
    const html = await zip.file(baseDir + href).async('string');
    const text = html.replace(/<[^>]+>/g, '').trim();
    texts.push(text);
  }

  console.log(texts.join('\n').slice(0, 500));
}

extractEpubText('example.epub').catch(console.error);

常见问题

8 个高频疑问

ePub 转成 PDF 后,排版和原来的 ePub 差别大吗?图片会不会变形?
差别取决于 ePub 的复杂度。纯文本 + 少量图片的 ePub,转换后排版基本一致。对于复杂排版(多栏、浮动、CSS 定位),PDF 渲染会按 A4 纸大小重新排列,可能导致部分元素错位。图片方面:原始 ePub 内的图片会原样嵌入 PDF,不会压缩或变形,但尺寸超过 A4 页面的图片会被自动缩放。建议:转换前先用阅读器预览一下原始 ePub 的排版,确认是否适合固定页面输出。
为什么我上传的 ePub 文件转换失败?提示格式错误?
常见原因有三个:一是文件本身不是标准 ePub 格式(比如把.zip 或.rar 直接改后缀为.epub),服务器会先校验 ZIP 包内的 mimetype 文件和 OPF 结构,不符合规范则拒绝处理。二是文件损坏,下载过程中数据不完整。三是文件包含非 UTF-8 编码的章节标题或元数据,后端解析时卡住。解决办法:先用 Calibre 或 Sigil 打开文件确认能正常阅读;如果文件是其他格式转换来的,建议重新导出为标准的 ePub 2.0 或 3.0。
这个工具和 Calibre 比,有什么优缺点?我到底该用哪个?
核心区别:本工具是网页版,无需安装,上传即转,适合偶尔转换一两本书的用户。Calibre 是桌面软件,功能全面但安装配置麻烦。本工具的优势:零门槛、转换速度快(后端 Go 处理,10MB 以内文件通常在 5 秒内完成)、且文件不上传第三方服务器(处理完即删除)。Calibre 的优势:支持批量转换、自定义输出样式(字体/页边距/目录生成)、以及更丰富的格式支持(如 AZW3、CBZ)。推荐:临时用一次选本工具,经常转书装 Calibre。
转成 TXT 后,原来的章节标题和目录全没了,能保留吗?
不能保留。TXT 是纯文本格式,不支持任何样式、元数据或结构标记(如目录、书签、超链接)。转换时后端会剥离所有 HTML 标签和 CSS,仅保留正文文本。章节标题会以纯文字形式出现在正文中(如“第一章”),但无法形成可点击的目录。如果在意目录结构,建议选择 PDF 或 Mobi 格式,这两种格式保留目录导航。另外,TXT 输出默认使用 UTF-8 编码,打开时请确认编辑器编码一致,否则可能出现乱码。
上传的 ePub 文件大小有限制吗?超过限制怎么办?
有。后端设定单文件上限为 100MB,这是考虑到服务器处理时间和内存开销。如果文件超过 100MB,建议先压缩图片:用 Calibre 的「转换书籍」→「页面设置」→「输出配置文件」中勾选「压缩图像」,将图片质量降到 80% 左右,文件大小通常能减少 40%-60%。另外,超大文件(>200MB)即使在限制内,转换时间也可能超过 30 秒,建议夜间或网络空闲时使用。
转换后的 Mobi 文件在 Kindle 上打开,字体特别小,怎么调整?
Mobi 格式本身不控制字体大小,字体渲染由 Kindle 设备或 App 决定。有两种解决办法:一是转换前在工具内选择「PDF」格式,PDF 的字体大小是固定的,可以在输出设置中调整字号(具体看工具界面的选项)。二是转换后把 Mobi 传到 Kindle 上,在阅读界面通过「Aa」菜单手动调大字体。注意:如果 ePub 源文件使用了 em 或 rem 相对单位,Mobi 输出会保留相对值,Kindle 的字体缩放功能完全有效。
为什么我转出来的 PDF 页数特别多?能控制每页字数吗?
PDF 页数由页面尺寸和字体大小共同决定。本工具默认输出为 A4 纸张(210mm×297mm),字体大小跟随 ePub 源文件设置。如果源文件字体偏小或行距紧凑,每页容纳内容多,页数就少。反之,如果源文件字体大、行距宽,页数就多。目前工具不支持自定义页面尺寸或字体大小(因为这是后端 Go 直接渲染,未开放参数)。建议:如果页数过多影响阅读,可以在转换前用 Sigil 修改 ePub 的 CSS 文件,将 body 的 font-size 设为 12pt,再上传转换。
上传后等了好久还没下载链接,是卡住了吗?怎么判断进度?
正常处理时间取决于文件大小和服务器负载:5MB 以内通常 3-5 秒,50MB 左右约 15-20 秒。如果超过 60 秒仍无反应,可能是文件损坏或服务器繁忙。目前工具没有进度条,但可以观察浏览器标签页的加载图标(旋转的圆环或进度条)——图标停止转动说明后端处理完毕。如果确实超时,尝试:1)刷新页面重新上传;2)换一个更小的文件测试是否正常;3)检查文件是否为标准 ePub(用 WinRAR 打开,看是否有 mimetype 文件)。
选择 打开 +新窗口 esc关闭