2010年8月11日 星期三

[Javascript] 把玩 Booktorious

EPUB


Booktorious 是一套純 Javascript 的 EPUB reader,單純接收一個 *.epub 檔案,接著用 Javascript 進行 unzip ,接著再依照 EPUB 格式進行 parsing ,最終則把 EPUB 的內容用多個 iframe 依序成列出來。這是一套 open source 的 framework,這陣子花了一點時間把玩,此預設一次把 EPUB 全部 parsing 完,而我想更改成挑選章節的解壓縮方式。


粗略筆記原先的過程:



  1. 透過 HTML5 的 FileReader 物件,將 user 端的檔案讀進 Javascript 裡處理

  2. 使用 JSEPUB 物件進行 EPUB 檔案的處理

  3. JSEPUB 物件接著會將整個 EPUB 進行初步 unzip 的處理,如果壓縮檔跟作者所撰寫的 ZIP 或 EPUB 格式不符,則會停下來

  4. 分析 EPUB 的 META-INF/container.xml 檔案,從中得知 content.opf 位置

  5. 分析 content.opf 資訊,得知 EPUB 內所有的檔案清單與格式

  6. 依照檔案格式,如 text/css 、application/xhtml+xml 進行處理,像 XHTML 部份,處理裡頭的連結位置,甚至用到的圖片資訊會從連結改用成內嵌的方式呈現 ( src="data,image/jpeg,....." ),並透過 new DOMParser().parseFromString() 轉成 DOM 物件

  7. 最後將各個 XHTML 之 DOM 模式,再透過 new XMLSerializer().serializeToString() 寫到 iframe 裡頭呈現於網頁


我想嘗試的,則是第三步起,不對整個 EPUB 檔案作解壓縮,只依序對 META-INF/container.xml、content.opf、toc.ncx 以及對該 EPUB 的第一章或封面進行解壓縮處理。


嘗試的成果,碰到問題



  • content.opf 和 toc.ncx 亂碼問題(如上圖左邊的書目)

  • toc.ncx 其中 href 使用 test.html#123 這種用 '#tag' 方式的連結問題


前者部份,由於是 xml 格式,雖然有標明 UTF-8 編碼等等,但我單純從 Javascript 讀 EPUB、解壓縮、拿到該 xml 資料、進行 dom parsing 等等動作,都是在 Javascript 以 binary 處理,處理完仍是亂碼。若這些檔案單純用 browser 去瀏覽,則可以顯示正確的編碼。不曉得是不是獨缺給 browser 碰一下的過程,因此無法顯示正確的編碼,但如果是以 xhtml 檔案,則都可以正確呈現;對於 toc.ncx 裡頭,有些章節並不是指到一檔案而已,而是某個 XHTML 檔案的某個段落,因此就要處理如何呈現到正確位置。請教米蟲大神後,得知既然是用 JS 產生 HTML ,那則可以對該物件進行 location 的操作,如 data.location = '#tag'; 的方式。只是我測試的結果,僅能對 webkit 成功,像 Firefox 的就無法正確處理。


上述中連結解法,片段程式:


var obj_div = document.getElementById( 'show' );  // <div id="show"></div>
var data = xhtml_dom_structure;                           // 一個 xhtml 檔案,已透過 DOMParser 處理
var iframe = document.createElement("iframe");    // 動態產生 iframe
var target = '#tag';                                                // 打算指到 test.xhtml#tag 位置

var doc = iframe.contentDocument ? iframe.contentDocument : iframe.contentWindow ? iframe.contentWindow : iframe.document ? iframe.document : null;

if(doc == null)
    throw "Document not initialized";

doc.open();
doc.write( new XMLSerializer().serializeToString(data) );
doc.close();

if( target && doc.defaultView && doc.defaultView.location )
    doc.defaultView.location = target;


因此也不算是解掉,僅能在 Google Chrome 或 Safari 使用。


原先只是單純想把 EPUB 解壓縮從全部解壓縮改成部份解壓縮,以此加速呈現,經過幾番測試,速度的確可以拉到 1 秒內完成,但這是在 AMD X4 945 的主機,並搭配 Google Chrome 的成果。以一個 1MB 的檔案,預設全解花 6.5 秒左右(使用Firefox約 13 秒),改成只解開必要的以及第一章約 0.2 秒就可以完工了!但是,移到 iPad 上測試卻要花 8 秒處理!更何況是 iPhone 3G 呢(事實上iPhone 3G + iOS4並未正常執行該程式,因此無法測試所需時間)。


最後,如果 EPUB 的壓縮格式有問題,可以試著解壓縮後重新壓縮,其指令如下:


$ unzip test.epub -d test
$ cd test
$ zip -0Xq ../new.epub mimetype
$ zip -Xr9D ../new.epub *


另外,也可以確認一下 mimetype 內容是否為 "application/epub+zip"


簡單的 bash


#!/bin/sh
if [ -z $1 ]; then
        echo ''
        echo 'This is a tool to zip current work dir in to an EPUB file'
        echo ''
        echo 'Usage>' $0 'output_path.epub'
        echo ' e.g. ' $0 '/tmp/out.epub'
        return
fi

if [ ! -e 'mimetype' ]; then
        echo '[Error] No mimetype'
        return
fi

if [ ! -e 'META-INF/container.xml' ]; then
        echo '[Error] No META-INF/container.xml'
        return
fi

zip -0Xq $1 mimetype
zip -Xr9D $1 *


1 則留言: