Archive for the ‘EPUB’ Tag

newLISP で EPUB を表示させる(改良編)

 Googleの電子書籍サービス「Google eBooks」が開始されたとのこと。
 日本は、まだ対応外なのですが、google アカウントを使って、無料の本を見ることができます。
 試しに、Charles Dickens の “Bleak House” を EPUB 形式でダウンロードして、EPUB を zip 解凍すると、

META-INF - container.xml
OEBPS    - content
         - data
         - _toc_ncx_.ncx
         - volume.opf
mimetype

 こんな感じに展開されます。ブクログにある拙作の書籍の構造とは、少し違うようです。
 また、書籍の本体は、content フォルダの下に content-XXXX.xml というファイル名になっていました。
 ということで、さっそく、拙作 EPUB-Viewer を対応させました。
 

; utility
(define *newlispDir* (env "NEWLISPDIR"))
(load (append *newlispDir* "/guiserver.lsp")) 

; define macro
(module "macro.lsp")
(macro (parse-path P) (parse P {\\|/} 0))

; define handler
(define *fileDir* (real-path))
(define *fileNames* '())
(define *index* 0)
(define *filemask* "html xhtml xml")
(define *description* "HTML file")
(define (book-display file)
  (when (file? file)
    (let (ptmp (parse-path file)
          book (replace {<\?.+\?>} (read-file file) "" 0))
      (gs:set-text 'fileLabel (ptmp -1))
      (unless (null? book)
        (replace {<meta http-equiv[^>]*>} book "" 4)
        (replace {src="../} 
                 book 
                 (string {src="file:///} (join (chop ptmp 2) "/" true)))
        (gs:set-text 'OutputArea book)))))
(define (next-action id)
  (let (f-max (length *fileNames*))
    ((if (starts-with ((parse id) -1) "pre") -- ++) *index*)
    (if (< *index*) (setq *index* (i- f-max))
        (< *index* f-max) nil
      (setq *index* 0))
    (book-display (append *fileDir* (*fileNames* *index*)))))
(define (openfile-action id op file)
  (when file
    (setq *fileDir* (base64-dec file))
    (if (directory? *fileDir*)
        (setq *fileDir* (append *fileDir* "/"))
      (let (tmp (parse-path *fileDir*))
        (setq *fileDir* (append  (join (chop tmp) "/" true)))
        (setq *fileName* (tmp -1))))
    (gs:set-text 'Status *fileDir*)
    (setq *fileNames* (sort (directory *fileDir* "html*$|xml$" 1)))
    (setq *index* 0)
    (if *fileName* (setq *index* (find *fileName* *fileNames*))
      (setq  *fileName* (*fileNames* 0)))
    (book-display (append *fileDir* (*fileNames* *index*)))))
(define (open-file-dialog)
  (gs:open-file-dialog 'Frame 'openfile-action *fileDir* *filemask* *description*))

; initialization
(gs:init)
(define FPosX 100)
(define FPosY 50)
(define FWidth 640)
(define FHeight 480)
(gs:frame 'Frame FPosX FPosY FWidth FHeight "Simple EPUB Viewer")
(gs:panel 'ButtonPanel)
(gs:panel 'StatusPanel)
(gs:label 'Status (real-path))
(gs:label 'fileLabel "")
(gs:button 'preBtn 'next-action "<")
(gs:button 'nextBtn 'next-action ">")
(gs:button 'fileButton 'open-file-dialog "File")
(gs:text-pane 'OutputArea 'gs:no-action "text/html")
(gs:add-to 'ButtonPanel 'preBtn 'fileLabel 'nextBtn)
(gs:add-to 'StatusPanel 'fileButton 'Status)

; mount all on frame
(gs:set-border-layout 'Frame)
(gs:set-flow-layout 'ButtonPanel "center")
(gs:set-flow-layout 'StatusPanel "left")
(gs:add-to 'Frame 'ButtonPanel "north" 'OutputArea "center" 'StatusPanel "south")
(gs:set-visible 'Frame true)

; main routine
(gs:listen)
(exit)

 主な変更点は、対応ファイル拡張子(xml)の追加です(笑)。ついでに、画像の表示も。
 これを実行し、File ボタンを押して、zip 解凍しておいた先程の content フォルダを指定すれば、

 一応、対応している画像ファイルはずが、、、何故か、うまく表示されません。
 でも、本文を読むだけなら、

 問題なさそうです。
 あとは、zip 解凍か、、、(汗)

 以上、如何でしょうか?

newLISP で GUI する。。。または、EPUB を表示させる?(解説編)

newLISP で GUI する。。。または、EPUB を表示させる?(解説編)

 前回の EPUB Viewer は、如何だったでしょうか?
  EPUB の本体は、XHTML のサブセットですが、そのままでは、gs:text-pane で表示できません。
 <head></head> タグが邪魔しているようなのです。
 そのためスクリプトでは、

(letn (str (read-file file)
           book ((find {} str) str))
      (gs:set-text 'OutputArea (0 (+ (find {} book) 7) book)))

 こんな感じで、本文が入っている <body></body> を抜き出して表示させています。
 本来に立ち戻って、<head></head> タグだけを削除するなら、

(letn (str (replace {} (read-file file) "" 0)
           book1 (aif (find {} str) (0 it str) str)
           book2 (aif (find {} str) ((+ it 7) str) "")
           book (append book1 book2))
      (gs:set-text 'OutputArea book))

 こうすべきでした。先頭の削除宣言文は、xhtml の宣言文(?)の削除です。gs:text-pane では、そのまま表示されてしまうので。
 また、ファイル名を取得するには、組込directory の正規表現オプションを使って、

(directory *fileDir* "[^.+]" 1)

 としていました。これは、"."".." 以外のファイル名を取り込みます。
 HTMLファイルだけを取り込むようにするには、

(directory *fileDir* "html*$" 1)

 こんな感じ。ドットを付加しなかったのは、をEPUB の拡張子が .xhtml だから。
 私の場合、あんまり、正規表現にこだわると、失敗するので(汗)。
 これらを、前回の EPUB Viewer に適用すると、
(include は init.lsp に、aif は newlisp-utility.lsp に定義してあります。)

; utility
(define *newlispDir* (env "NEWLISPDIR"))
(load (append *newlispDir* "/guiserver.lsp")) 
(include "macro.lsp")

; define sub-routine
(macro (parse-path P)
  (parse P {\\|/} 0))

; define handler
(define *fileDir* (real-path))
(define *fileNames* '())
(define *index* 0)
(define *filemask* "html xhtml")
(define *description* "HTML file")
(define (book-display file)
  (when (file? file)
    (gs:set-text 'fileLabel ((parse-path file) -1))
    (letn (str (replace {<\?.+\?>} (read-file file) "" 0)
           book1 (aif (find {<head>} str) (0 it str) str)
           book2 (aif (find {</head>} str) ((+ it 7) str) "")
           book (append book1 book2))
      (replace {src="../} 
               book 
               (string {src="file:///} (join (chop (parse-path *fileDir*)) "/" true)))
      (gs:set-text 'OutputArea book))))
(define (next-action id)
  (let (f-max (length *fileNames*))
    ((if (starts-with ((parse id) -1) "pre") -- ++) *index*)
    (if (< *index*) (setq *index* (i- f-max))
        (< *index* f-max) nil
      (setq *index* 0))
    (book-display (append *fileDir* (*fileNames* *index*)))))
(define (openfile-action id op file)
  (when file
    (setq *fileDir* (base64-dec file))
    (if (directory? *fileDir*)
        (setq *fileDir* (append *fileDir* "/"))
      (let (tmp (parse-path *fileDir*))
        (setq *fileDir* (append  (join (chop tmp) "/" true)))
        (setq *fileName* (tmp -1))))
    (gs:set-text 'Status *fileDir*)
    (setq *fileNames* (sort (directory *fileDir* "html*$" 1)))
    (setq *index* 0)
    (if *fileName* (setq *index* (find *fileName* *fileNames*))
      (setq  *fileName* (*fileNames* 0)))
    (book-display (append *fileDir* (*fileNames* *index*)))))
(define (open-file-dialog)
  (gs:open-file-dialog 'Frame 'openfile-action *fileDir* *filemask* *description*))

; initialization
(gs:init)
(define FPosX 100)
(define FPosY 50)
(define FWidth 640)
(define FHeight 480)
(gs:frame 'Frame FPosX FPosY FWidth FHeight "EPUB Viewer")
(gs:panel 'ButtonPanel)
(gs:panel 'StatusPanel)
(gs:label 'Status (real-path))
(gs:label 'fileLabel "")
(gs:button 'preBtn 'next-action "<")
(gs:button 'nextBtn 'next-action ">")
(gs:button 'fileButton 'open-file-dialog "File")
;(gs:text-pane 'OutputArea 'gs:no-action  "text/plain")
(gs:text-pane 'OutputArea 'gs:no-action "text/html")
(gs:add-to 'ButtonPanel 'preBtn 'fileLabel 'nextBtn)
(gs:add-to 'StatusPanel 'fileButton 'Status)

; mount all on frame
(gs:set-border-layout 'Frame)
(gs:set-flow-layout 'ButtonPanel "center")
(gs:set-flow-layout 'StatusPanel "left")
(gs:add-to 'Frame 'ButtonPanel "north" 'OutputArea "center" 'StatusPanel "south")
(gs:set-visible 'Frame true)

; main routine
(gs:listen)
(exit)

 こうなります。
 これなら、EPUB Viewer としてだけではなく、簡易 HTML Viewer としても使える?

 以上、如何でしょうか?

newLISP で GUI する。。。または、EPUB を表示させる?

 手前味噌ですが、前の blog で short short story として書きためたものをブクログで紹介しています
 そこから、ダウンロードできるフォーマットの一つが、EPUB。
 調べてみると EPUB は、最近話題(?)の電子書籍の一種で、XHTMLのサブセット的なファイル・フォーマットで ZIP 圧縮されたもの。
 これなら、newLISP で表示できそうだと始めてみました。
 本来なら、zip 解凍から始めるべきですが、まだ目処が付いていないので、解凍後のファイルの表示用です。
 EPUB を zip 解凍すると、

META-INF - container.xml
OEBPS    - css
         - image
         - text
         - content.opf
         - toc.ncx
mimetype

 こんな感じに展開されます。
 お目当て(笑)の short short story は、text フォルダの下に XXX.xhtml のファイル名であります。
 今回のスクリプトは、この text フォルダを指定して、中のファイルを表示するスクリプトです。

; utility
(define *newlispDir* (env "NEWLISPDIR"))
(load (append *newlispDir* "/guiserver.lsp")) 

; define sub-routine
; define handler
(define *fileDir* (real-path))
(define *fileNames* '())
(define *index* 0)
(define *filemask* "html xhtml")
(define *description* "HTML file")
(define (book-display file)
  (when (file? file)
    (gs:set-text 'Status file)
    (letn (str (read-file file)
           book ((find {<body>} str) str))
      (gs:set-text 'OutputArea (0 (+ (find {</body>} book) 7) book)))))
(define (next-action id)
  (let (f-max (length *fileNames*))
    ((if (starts-with ((parse id) -1) "pre") -- ++) *index*)
    (if (< *index*) (setq *index* (i- f-max))
        (< *index* f-max) nil
      (setq *index* 0))
    (book-display (append *fileDir* (*fileNames* *index*)))))
(define (openfile-action id op file)
  (when file
    (setq *fileDir* (base64-dec file))
    (if (directory? *fileDir*)
        (setq *fileDir* (append  *fileDir* "\\"))
      (let (tmp (parse *fileDir* {\\|/} 0))
        (setq *fileDir* (append  (join (chop tmp) "/" true)))
        (setq *fileName* (tmp -1))))
    (setq *fileNames* (sort (directory *fileDir* "[^.+]" 1)))
    (setq *index* 0)
    (if *fileName* (setq *index* (find *fileName* *fileNames*))
      (setq  *fileName* (*fileNames* 0)))
    (book-display (append *fileDir* (*fileNames* *index*)))))
(define (open-file-dialog)
  (gs:open-file-dialog 'Frame 'openfile-action *fileDir* *filemask* *description*))

; initialization
(gs:init)
(define FPosX 100)
(define FPosY 50)
(define FWidth 640)
(define FHeight 480)
(gs:frame 'Frame FPosX FPosY FWidth FHeight "EPUB Viewer")
(gs:panel 'ButtonPanel)
(gs:panel 'StatusPanel)
(gs:label 'Status (real-path))
(gs:button 'preBtn 'next-action "<")
(gs:button 'nextBtn 'next-action ">")
(gs:button 'fileButton 'open-file-dialog "File")
;(gs:text-pane 'OutputArea 'gs:no-action  "text/plain")
(gs:text-pane 'OutputArea 'gs:no-action "text/html")
(gs:add-to 'ButtonPanel 'preBtn 'nextBtn) 
(gs:add-to 'StatusPanel 'fileButton 'Status) 
; mount all on frame
(gs:set-border-layout 'Frame)
(gs:set-flow-layout 'ButtonPanel "center")
(gs:set-flow-layout 'StatusPanel "left")
(gs:add-to 'Frame 'ButtonPanel "north" 'OutputArea "center" 'StatusPanel "south")
(gs:set-visible 'Frame true)
; main routine
(gs:listen)
(exit)

 これを実行し、File ボタンを押して、解凍しておいた先程の text フォルダを指定すれば、

 といった具合に表示されます。
 ただし、テキスト・コードは、UTF-8です。つまり、UTF-8 版 newLISP で実行する必要があります。
 まだ、テキスト内容だけで、イメージ・ファイルまでは、表示できませんが(汗)。
 それに、zip 解凍も、、、

 以上、如何でしょうか?