購買kindle以後,天然欣喜萬分,不來自於工具自己,而來自於發現本身可以靜下心來閱讀長篇和複雜的文字了,可喜可賀。更重要的是,kindle減輕了我眼睛的莫大的壓力。但立刻就出現幾個問題:html
可能有人說,用手機看不就得了?用手機看花邊娛樂新聞固然很好,但是當看數學推導時,推送欄上面妹子發來的消息,會直接把你的思路所有打亂。沒用過kindle的人,是有些難以體會那種接近於紙張的質感的。OK,既然是程序員,咱們就嘗試解決這些問題。python
kindlegen是亞馬遜官方出品的一個電子書生成工具。但它明顯就沒打算讓普通用戶使用,命令行界面,幾乎沒有任何像樣的文檔。只是在實例樣例裏給了幾個生成電子書的文件。我就由於沒有文檔兜了大彎,翻遍國外各大網站,才慢慢摸清kindlegen的使用細節。
能夠這麼理解,KG是將一組HTML和相關文件,打包成mobi文件的工具。git
最簡單的例子,隨意編寫一個HTML文件,送給KG,會生成對應的mobi。基本有title,h1,h2,正文,kindle渲染就差很少了。若是須要修改樣式,能夠提供CSS文件。
可是,這樣的作法,沒有圖片,沒有超連接,沒法提供目錄,若是輸入單一的大型HTML文件,kindle的渲染性能就不足了。程序員
所以,須要生成層級化,多文件形式的html文件夾,然而kg並不能直接識別html文件夾,仍是須要一些元數據描述。github
要想解決這個問題,就須要編寫兩個文件,opf和ncx, 他們能夠理解爲KG的makefile, KG經過這兩個文件索引HTML,目錄和其餘多媒體資源。介紹以下:編程
值得注意的是,全部的文件都應該保存在本地,尤爲是jpg, html中的圖片超連接,須要重定向到本地的jpg文件,若是依然在服務器上,據我所知,kg是不負責渲染下載的。服務器
因爲opf文件很是重要,咱們下面就講解opf的格式:網絡
<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="BookId"> <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf"> <dc:title>電子書標題</dc:title> <dc:language>en-us</dc:language> </metadata> <manifest> <!-- table of contents [mandatory] --> <item id="tochtml" media-type="application/xhtml+xml" href="toc.html"/> <item id="item0" media-type="application/xhtml+xml" href="Artical-1277621753.html"/> ... <!--下面是圖片--> <item id="0.368541311142" media-type="image/jpg" href="Images/-1720404282.jpg"/> </manifest> <spine toc="desertfire"> <!-- 下面描述了KG生成電子書後文本的順序 --> <itemref idref="toc"/> <itemref idref="tochtml"/> <itemref idref="item31"/> </spine> <guide> <reference type="toc" title="Table of Contents" href="toc.html"></reference> <reference type="text" title="Welcome" href="toc.html"></reference> </guide> </package> ```
須要注意的有如下幾點:app
最終,KG的命令行目標,不是目錄HTML,而是OPF文件!將全部的文件放入一個文件夾後,啓動KG命令行,最後KG會在該目錄下生成你心儀已久的mobi!ide
知道其原理後,主要的任務是填充HTML和OPF文件,幾頁內容還好,若是內容繁多,不管是手工( ⊙ o ⊙ ),仍是編程字符串拼接,都會變得異常低效。
此時,就須要模板引擎出手了,python推薦使用Jinja2, 資料衆多,功能強大,性能尚可。生成opf的模板文件,基本就長下面這個樣子:
<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="BookId"> <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf"> <dc:title>{{ title }}</dc:title> <dc:language>en-us</dc:language> </metadata> <manifest> <!-- table of contents [mandatory] --> <item id="toc" media-type="application/x-dtbncx+xml" href="toc.ncx"/> <item id="tochtml" media-type="application/xhtml+xml" href="toc.html"/> {% for item in navigation %} <item id="{{ item.id }}" media-type="application/xhtml+xml" href="{{ item.href }}"/> {% endfor %} {% for item in media %} <item id="{{ item.id }}" media-type="image/{{ item.format}}" href="{{ item.href}}"/> {% endfor %} </manifest> <spine toc="{{ title }}"> <!-- the spine defines the linear reading order of the book --> <itemref idref="toc"/> <itemref idref="tochtml"/> {% for item in navigation %} <itemref idref="{{ item.id }}"/> {% endfor %} </spine> <guide> <reference type="toc" title="Table of Contents" href="toc.html"></reference> <reference type="text" title="Welcome" href="toc.html"></reference> </guide> </package>
我在此處就不費事講解jinja2的語法了。這樣,就能解決閱讀網頁新聞和HTML資源的問題了。
下一個問題,是如何閱讀掃描版的PDF,如電子書和論文。有如下幾類初始想法:
權衡以後,咱們選用第二種方案。PDF分爲兩類,一種是一頁一欄,如電子書,另外一種是一頁兩欄,如論文。
那麼,爲了保證質量,有如下的步驟:
若是使用python,則有一些類庫可使用,如imagemagick和一系列相關類庫。
但這些類庫安裝比較麻煩,所以筆者使用了軟件生成,此處強烈推薦一款軟件:
AP PDF to IMAGE 國產軟件?的驕傲!不須要其餘任何類庫,體積小,性能穩定,生成圖片尺寸可調,可批量處理,很是清晰!
百度可搜索各種綠色版下載,我都想給做者支付寶捐錢了。
若是你是PS大神,固然可使用宏和批量命令完成這些,此處咱們用的仍是python,使用著名的PIL類庫,下面貼出代碼:
# coding=utf-8 import os import Image as img import jinja2 as jj import extends import libs.kindlestrip as kp # 要PDF轉JPG時,若是用python的方案,則須要安裝一堆庫 # 用現成的工具,則難以與Python集成,並且速度很慢,目前仍是採用現成的工具吧 # 當生成論文時,第一頁的上半部分,單獨抽出,剩下的分爲四頁導出。設置以下 horizon = 2 vertic = 2 firstpage = True # 生成普通橫版PDF時,則爲以下設置: # horizon = 1 # vertic = 2 # firstpage=False topblood = 0.05; sideblood = 0.06; booktitle = u"Paper"; author = "zhaoyiming" outputfolder = "pdf2mobi/"; imgTypes = ['.png', '.jpg', '.bmp'] kindlegen = r"Tools/kindlegen.exe" # kindlegen position shouldsplit = 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了。
這些代碼花了我一個下午的時間,不過與爬蟲配合,生成各位大神的博客,效果然是很是贊!
媽媽不再用擔憂個人眼睛了!終於能夠隨時隨地,沒有廣告地批量看大神們的博客了!
有任何問題,歡迎隨時討論。