博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
生成Kindle可读的mobi和PDF电子书
阅读量:6677 次
发布时间:2019-06-25

本文共 6775 字,大约阅读时间需要 22 分钟。

购买kindle之后,自然欣喜万分,不来自于工具本身,而来自于发现自己能够静下心来阅读长篇和复杂的文字了,可喜可贺。更重要的是,kindle减轻了我眼睛的莫大的压力。但马上就出现几个问题:

  • 不是所有的电子书都有kindle,最常见的是扫描PDF
  • 大量的论文无法阅读,这和上面的问题一致
  • 网络上很多精彩的博客,新闻,都是没法阅读的

可能有人说,用手机看不就得了?用手机看花边娱乐新闻当然很好,可是当看数学推导时,推送栏上面妹子发来的消息,会直接把你的思路全部打乱。没用过kindle的人,是有些难以体会那种接近于纸张的质感的。OK,既然是程序员,我们就尝试解决这些问题。

有关kindlegen和HTML

kindlegen是亚马逊官方出品的一个电子书生成工具。但它明显就没打算让普通用户使用,命令行界面,几乎没有任何像样的文档。只是在实例样例里给了几个生成电子书的文件。我就因为没有文档兜了大弯,翻遍国外各大网站,才慢慢摸清kindlegen的使用细节。

可以这么理解,KG是将一组HTML和相关文件,打包成mobi文件的工具。

最简单的例子,随意编写一个HTML文件,送给KG,会生成对应的mobi。基本有title,h1,h2,正文,kindle渲染就差不多了。如果需要修改样式,可以提供CSS文件。

但是,这样的做法,没有图片,没有超链接,无法提供目录,如果输入单一的大型HTML文件,kindle的渲染性能就不足了。

因此,需要生成层级化,多文件形式的html文件夹,然而kg并不能直接识别html文件夹,还是需要一些元数据描述。

编写元数据文件

要想解决这个问题,就需要编写两个文件,opf和ncx, 他们可以理解为KG的makefile, KG通过这两个文件索引HTML,目录和其他多媒体资源。介绍如下:

值得注意的是,所有的文件都应该保存在本地,尤其是jpg, html中的图片超链接,需要重定向到本地的jpg文件,如果依然在服务器上,据我所知,kg是不负责渲染下载的。

资源聚合文件: opf和ncx

由于opf文件非常重要,我们下面就讲解opf的格式:

复制代码
电子书标题
en-us
...
```
复制代码

需要注意的有以下几点:

  • 所有资源都需要一个id,命名任意,但不能重复
  • media-type描述了资源的类型,记住两类基本就够用了,"application/xhtml+xml"代表HTML文件,"image/jpg"或 "image/png"代表图片。
  • 其他都可以省略,只是会影响电子书完整性。
    由于这两个文件内部其实都是html,所以修改编辑都很容易。

最终,KG的命令行目标,不是目录HTML,而是OPF文件!将所有的文件放入一个文件夹后,启动KG命令行,最后KG会在该目录下生成你心仪已久的mobi!

编辑HTML和OPF文件

知道其原理后,主要的任务是填充HTML和OPF文件,几页内容还好,如果内容繁多,不论是手工( ⊙ o ⊙ ),还是编程字符串拼接,都会变得异常低效。

此时,就需要模板引擎出手了,python推荐使用Jinja2, 资料众多,功能强大,性能尚可。生成opf的模板文件,基本就长下面这个样子:

复制代码
{
{ title }}
en-us
{% for item in navigation %}
{% endfor %} {% for item in media %}
{% endfor %}
{% for item in navigation %}
{% endfor %}
复制代码

我在此处就不费事讲解jinja2的语法了。这样,就能解决阅读网页新闻和HTML资源的问题了。

生成扫描版MOBI

下一个问题,是如何阅读扫描版的PDF,如电子书和论文。有以下几类初始想法:

权衡之后,我们选用第二种方案。PDF分为两类,一种是一页一栏,如电子书,另一种是一页两栏,如论文。

那么,为了保证质量,有以下的步骤:

将PDF转换为图片

如果使用python,则有一些类库可以使用,如imagemagick和一系列相关类库。

但这些类库安装比较麻烦,因此笔者使用了软件生成,此处强烈推荐一款软件:
AP PDF to IMAGE 国产软件?的骄傲!不需要其他任何类库,体积小,性能稳定,生成图片尺寸可调,可批量处理,非常清晰!
百度可搜索各类绿色版下载,我都想给作者支付宝捐钱了。

图片处理

如果你是PS大神,当然可以使用宏和批量命令完成这些,此处我们用的还是python,使用著名的PIL类库,下面贴出代码:

复制代码
# coding=utf-8import osimport Image as imgimport jinja2 as jjimport extendsimport libs.kindlestrip as kp# 要PDF转JPG时,如果用python的方案,则需要安装一堆库# 用现成的工具,则难以与Python集成,而且速度很慢,目前还是采用现成的工具吧# 当生成论文时,第一页的上半部分,单独抽出,剩下的分为四页导出。设置如下horizon = 2vertic = 2firstpage = True# 生成普通横版PDF时,则为如下设置:# horizon = 1# vertic  = 2# firstpage=Falsetopblood = 0.05;sideblood = 0.06;booktitle = u"Paper";author = "zhaoyiming"outputfolder = "pdf2mobi/";imgTypes = ['.png', '.jpg', '.bmp']kindlegen = r"Tools/kindlegen.exe"  # kindlegen positionshouldsplit = True;imagefolders = outputfolder + 'raw';splitfolder = outputfolder + 'split'docs = [];pageindex = 0;if shouldsplit == True:    for root, dirs, files in os.walk(imagefolders):        index = 0;        for currentFile in files:            crtFile = root + '\\' + currentFile            format = crtFile[crtFile.rindex('.'):].lower();            if format not in imgTypes:                continue;            crtIm = img.open(crtFile)            crtW, crtH = crtIm.size            hStep = crtW * (1 - 2 * sideblood) // horizon            vStep = crtH * (1 - 2 * topblood) // vertic            hstart = crtW * sideblood            vstart = crtH * topblood;            if (firstpage == True and pageindex == 0):                crtOutFileName = 'pdf2mobi/split/' + str(index) + format,                box = (hstart, vstart, crtW, crtH // 3)                box = list((int(x) for x in box));                cropped = crtIm.crop(box)                cropped.save(crtOutFileName[0])                myimg = {};                myimg["href"] = "split/" + str(index) + format;                myimg["id"] = index;                myimg["format"] = format;                myimg["width"] = box[2] - box[0];                myimg["height"] = box[3] - box[1];                docs.append(myimg)                index += 1;            for j in range(horizon):                for i in range(vertic):                    crtOutFileName = 'pdf2mobi/split/' + str(index) + format,                    box = (hstart + j * hStep, vstart + i * vStep, hstart + (j + 1) * hStep, vstart + (i + 1) * vStep)                    box = (int(x) for x in box);                    cropped = crtIm.crop(box)                    cropped.save(crtOutFileName[0])                    myimg = {};                    myimg["href"] = "split/" + str(index) + format;                    myimg["id"] = index;                    myimg["format"] = format;                    myimg["width"] = hStep;                    myimg["height"] = vStep;                    docs.append(myimg)                    index += 1;            pageindex += 1;else:    for root, dirs, files in os.walk(imagefolders):        index = 0;        for currentFile in files:            crtFile = root + '\\' + currentFile            format = crtFile[crtFile.rindex('.'):].lower();            if format not in imgTypes:                continue;            myimg = {};            myimg["href"] = "split/" + str(index) + format;            myimg["id"] = index;            myimg["format"] = format;            myimg["width"] = "1347";            myimg["height"] = "1023";            docs.append(myimg)            index += 1;images = [];env = jj.Environment(loader=jj.FileSystemLoader([r"templates/"]))articaltemplate = env.get_template('jpgs.html')opftemplate = env.get_template('opf.html')ncxtemplate = env.get_template('ncx.html')extends.SaveFile(outputfolder + "toc.html", articaltemplate.render(navigation=docs, title=booktitle, author=author));extends.SaveFile(outputfolder + booktitle + ".opf",                 opftemplate.render(navigation=docs, title=booktitle, author=author, media=images));extends.SaveFile(outputfolder + "toc.ncx", ncxtemplate.render(navigation=docs, title=booktitle, author=author));currentPath = os.getcwd() + "\\" + outputfolder.replace("/", "\\") + booktitle + ".opf";mobipath = outputfolder.replace("/", "\\") + booktitle + ".mobi";kindlepath = os.getcwd() + "\\" + kindlegen.replace("/", "\\");cmd = kindlepath + " " + currentPath;cmd = cmd.encode();print cmd;os.system(cmd);kp.Convert(mobipath, mobipath)
复制代码

(我觉得我应该把代码上传到github上,恩,一会再说)

这样,就能生成可读的漂亮的PDF转mobi了。

最终效果

这些代码花了我一个下午的时间,不过与爬虫配合,生成各位大神的博客,效果真是非常赞!

妈妈再也不用担心我的眼睛了!终于可以随时随地,没有广告地批量看大神们的博客了!

有任何问题,欢迎随时讨论。

作者:
出处:
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类:
本文转自FerventDesert博客园博客,原文链接:http://www.cnblogs.com/buptzym/p/5249662.html,如需转载请自行联系原作者
你可能感兴趣的文章
word2vec 中的数学原理详解
查看>>
BZOJ 4128 Matrix BSGS+矩阵求逆
查看>>
内存管理:栈区,堆区,全局区,文字常量区,程序代码区
查看>>
《影响力》6个使人顺从的武器之一互惠原理深入剖析
查看>>
Guava学习之Preconditions
查看>>
移动电力猫HG260GT pon实现路由拨号
查看>>
linux 系统获得当前文件夹下存在的所有文件 scandir函数和struct dirent **namelist结构体[转]...
查看>>
iOS 11开发教程(十四)iOS11应用代码添加视图
查看>>
Quartz使用
查看>>
sql server 2014登录账号
查看>>
Solr6 Suggest(智能提示)
查看>>
关于inodes占用100%的问题及解决方法
查看>>
golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息
查看>>
eclipse maven Cannot change version of project facet Dynamic web module to 3.0
查看>>
微信支付错误:201 商户订单号重复
查看>>
多媒体技术 有损压缩算法之Huffman和自适应Huffman算法
查看>>
nvidia驱动安装
查看>>
git 版本历史
查看>>
XHTML 教程(摘录自 W3C School)
查看>>
Directx11教程(50) 输出depth/stencil buffer的内容
查看>>