review 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +9 -0
- data/ChangeLog +326 -0
- data/Rakefile +3 -5
- data/VERSION +1 -1
- data/bin/review-compile +50 -50
- data/bin/review-epubmaker +62 -75
- data/bin/review-epubmaker-ng +185 -0
- data/bin/review-index +2 -1
- data/bin/review-pdfmaker +158 -101
- data/bin/review-vol +6 -2
- data/doc/format.rdoc +111 -46
- data/doc/libepubmaker/sample.yaml +90 -0
- data/doc/quickstart.rdoc +188 -0
- data/doc/sample.yaml +8 -0
- data/lib/epubmaker.rb +28 -0
- data/lib/epubmaker/content.rb +82 -0
- data/lib/epubmaker/epubv2.rb +419 -0
- data/lib/epubmaker/epubv3.rb +249 -0
- data/lib/epubmaker/producer.rb +204 -0
- data/lib/epubmaker/resource.rb +66 -0
- data/lib/review.rb +1 -1
- data/lib/review/book.rb +27 -4
- data/lib/review/builder.rb +153 -20
- data/lib/review/compiler.rb +61 -10
- data/lib/review/ewbbuilder.rb +3 -2
- data/lib/review/htmlbuilder.rb +174 -67
- data/lib/review/i18n.rb +30 -0
- data/lib/review/i18n.yaml +23 -0
- data/lib/review/idgxmlbuilder.rb +110 -63
- data/lib/review/index.rb +34 -12
- data/lib/review/latexbuilder.rb +128 -33
- data/lib/review/latexutils.rb +18 -1
- data/lib/review/textbuilder.rb +17 -0
- data/lib/review/tocparser.rb +3 -1
- data/lib/review/tocprinter.rb +1 -0
- data/lib/review/topbuilder.rb +397 -198
- data/review.gemspec +101 -100
- data/test/test_book.rb +27 -0
- data/test/test_epubmaker.rb +507 -0
- data/test/test_helper.rb +8 -0
- data/test/test_htmlbuilder.rb +295 -10
- data/test/test_i18n.rb +64 -0
- data/test/test_idgxmlbuilder.rb +268 -10
- data/test/test_latexbuilder.rb +316 -20
- data/test/test_preprocessor.rb +23 -0
- data/test/test_topbuilder.rb +246 -0
- metadata +46 -53
- data/doc/format.re +0 -505
- data/test/test_index.rb +0 -15
@@ -0,0 +1,90 @@
|
|
1
|
+
# YAMLファイルのサンプル
|
2
|
+
# このファイルはUTF-8エンコーディングで記述してください
|
3
|
+
|
4
|
+
# ブック名(ファイル名になるもの。ASCII範囲の文字を使用)
|
5
|
+
bookname: sample
|
6
|
+
# 記述言語
|
7
|
+
language: ja
|
8
|
+
# 書名
|
9
|
+
title: ReVIEW EPUBのサンプル
|
10
|
+
|
11
|
+
# 固有IDに使用するドメイン。指定しない場合には、時刻に基づくランダムUUIDが入る
|
12
|
+
# urnid: urn:uid:http://example.com/some-book-title/1.0.2/
|
13
|
+
|
14
|
+
# isbn: ISBN。省略した場合はランダム生成したUUIDが入る
|
15
|
+
|
16
|
+
# 著者名。複数人いる場合はYAMLの配列形式で指定できる
|
17
|
+
aut: Kenshi Muto
|
18
|
+
|
19
|
+
# 以下はオプション(配列書式で複数指定可能)。a-が付いているものはcreator側、
|
20
|
+
# 付いていないものはcontributor側(二次協力者)に入る
|
21
|
+
# a-adp, adp: 異なるメディア向けに作り直した者
|
22
|
+
# a-ann, ann: 注釈記述者
|
23
|
+
# a-arr, arr: アレンジした者
|
24
|
+
# a-art, art: グラフィックデザインおよび芸術家
|
25
|
+
# a-asn, asn: 関連・かつての所有者・関係者
|
26
|
+
# a-aqt, aqt: 大きく引用された人物
|
27
|
+
# a-aft, aft: 後書き・奥付の責任者
|
28
|
+
# a-aui, aui: 序論・序文・前書きの責任者
|
29
|
+
# a-ant, ant: 目録責任者
|
30
|
+
# a-bkp, bkp: メディア制作責任者
|
31
|
+
# a-clb, clb: 限定参加または補足者
|
32
|
+
# a-cmm, cmm: 解釈・分析・考察者
|
33
|
+
# a-dsr, dsr: デザイナ
|
34
|
+
# a-edt, edt: 編集者
|
35
|
+
# a-ill, ill: イラストレータ
|
36
|
+
# a-lyr, lyr: 歌詞作成者
|
37
|
+
# a-mdc, mdc: メタデータセットの一次的責任者
|
38
|
+
# a-mus, mus: 音楽家
|
39
|
+
# a-nrt, nrt: 語り手
|
40
|
+
# a-oth, oth: その他
|
41
|
+
# a-pht, pht: 撮影責任者
|
42
|
+
# a-prt, prt: 出版社
|
43
|
+
# a-red, red: 項目の枠組起草者
|
44
|
+
# a-rev, rev: 評論者
|
45
|
+
# a-spn, spn: 援助者
|
46
|
+
# a-ths, ths: 監督者
|
47
|
+
# a-trc, trc: 筆記・タイプ作業者
|
48
|
+
# a-trl, trl: 翻訳者
|
49
|
+
|
50
|
+
# rights: 権利表記
|
51
|
+
# date: 刊行日(省略した場合は実行時の日付)
|
52
|
+
# description: 説明
|
53
|
+
# subject: 短い説明用タグ。配列で複数指定可
|
54
|
+
# type: 書籍のカテゴリーなど(複数指定可)
|
55
|
+
# format: メディアタイプおよび特徴(複数指定可)
|
56
|
+
# source: 出版物生成の重要なリソース情報(複数指定可)
|
57
|
+
# relation: 補助的リソース(複数指定可)
|
58
|
+
# coverage: 内容の範囲や領域(複数指定可)
|
59
|
+
|
60
|
+
# htmlext: HTMLファイルの拡張子(省略した場合はhtml)
|
61
|
+
# cover: カバーページのファイル名(省略した場合はbookname.xhtmlになる)
|
62
|
+
#
|
63
|
+
# coverimage: カバー用画像
|
64
|
+
#
|
65
|
+
# CSSファイル(配列で複数指定することも可)
|
66
|
+
#stylesheet: stylesheet.css
|
67
|
+
|
68
|
+
# 目次として抽出するレベル
|
69
|
+
toclevel: 3
|
70
|
+
# セクション番号を表示するレベル
|
71
|
+
secnolevel: 2
|
72
|
+
# NCX目次の見出しレベルごとの飾り(配列で設定)
|
73
|
+
ncxindent:
|
74
|
+
-
|
75
|
+
- -
|
76
|
+
|
77
|
+
# EPUB標準の目次以外に目次を作成するか
|
78
|
+
mytoc:
|
79
|
+
# mytocがtrueの場合に作成する目次ファイル名(省略するとtoc.xhtml)
|
80
|
+
# tocfile: toc.xhtml
|
81
|
+
|
82
|
+
# 表紙の後に権利表記ページを作成するか。デフォルトでは作成されない。ファイル名を指定するとそのファイルが使われる(data配列にも指定しておく必要がある)
|
83
|
+
# titlepage: title.xhtml
|
84
|
+
|
85
|
+
# 奥付を作成するか。デフォルトでは作成されない。trueを指定するとデフォルトの奥付、ファイル名を指定するとそれがcolophon.xhtmlとしてコピーされる(data配列にも指定しておく必要がある)
|
86
|
+
# colophon: true
|
87
|
+
# pubhistory: 奥付履歴
|
88
|
+
|
89
|
+
# XHTML生成後に実行するプログラム。$1:HTMLの生成されたディレクトリ $2:ReVIEWファイルのあるディレクトリ $3:起動時指定のyamlファイル名
|
90
|
+
# posthook: hook.sh
|
data/doc/quickstart.rdoc
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
= ReVIEWクイックスタートガイド
|
2
|
+
|
3
|
+
ReVIEW は、EWB や RD あるいは Wiki に似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。
|
4
|
+
|
5
|
+
平易な文法ながらも、コンピュータ関係のドキュメント作成のための多くの機能を備えており、テキスト、LaTeX、HTML、XML といった形式に変換できます。独自のカスタマイズも簡単です。
|
6
|
+
|
7
|
+
ReVIEW は GNU Lesser General Public License Version 2.1 に基づいて配布されており、自由に利用、改変、再配布できます。このライセンスは、ReVIEW を使ってあなたが作成しようとする文書とは無関係であり、あなたの文書はこのライセンスに強制されることはありません。ReVIEW のツールセットあるいは ReVIEW を組み込んだシステムを配布あるいは販売しようとしているときには、ライセンスファイル COPYING をよく確認してください。
|
8
|
+
|
9
|
+
このドキュメントでは、ReVIEW のセットアップから変換の例までを簡単に説明します。
|
10
|
+
|
11
|
+
== セットアップ
|
12
|
+
|
13
|
+
ReVIEW は Ruby 言語で記述されており、Linux/Unix 互換システムで動作します。Mac OS X および Windows Cygwin でも動作可能です。Ruby gem、Git、Subversion のいずれかを使ってダウンロード・展開します。
|
14
|
+
|
15
|
+
なお、ReVIEW フォーマット自体は文字で表現されたタグが付いている以外は単なるテキストファイルなので、エディタ、OS についてはまったく制限はありません。
|
16
|
+
|
17
|
+
=== Ruby gemを使う場合
|
18
|
+
|
19
|
+
機能セットがまとまった区切りごとに、ReVIEW の開発チームが ReVIEW の gem を更新しています。
|
20
|
+
|
21
|
+
次のように ReVIEW の gem をインストールします。
|
22
|
+
|
23
|
+
gem install review
|
24
|
+
|
25
|
+
Ruby gem の bin ディレクトリにパスを通すようにしておいてください。
|
26
|
+
|
27
|
+
インストール後、最新の gem に追従するには次のようにします。
|
28
|
+
|
29
|
+
gem update review
|
30
|
+
|
31
|
+
=== Gitを使う場合
|
32
|
+
|
33
|
+
ReVIEW は GitHub で開発されており、バージョン管理ツールの Git を使って最新の ReVIEW コードを入手できます。Git は分岐が容易なので、独自のカスタマイズを施すのにも向いています。
|
34
|
+
|
35
|
+
初めて取得するときには、次のようにします (コピーを作っています)。
|
36
|
+
|
37
|
+
git clone git://github.com/kmuto/review.git
|
38
|
+
|
39
|
+
review というディレクトリに展開されるので、review/bin にパスを通すようにしておいてください。
|
40
|
+
|
41
|
+
最新の開発に追従するには次のようにします。
|
42
|
+
|
43
|
+
git pull
|
44
|
+
|
45
|
+
=== Subversionを使う場合
|
46
|
+
|
47
|
+
Git の最新コピーは、別のバージョン管理ツールの Subversion 向けにも提供しています (古い環境では Subversion のクライアントしか入っていないことがあります)。
|
48
|
+
|
49
|
+
初めて取得するときには、次のようにします (コピーを作っています)。
|
50
|
+
|
51
|
+
svn co https://kmuto.jp/svn/review/trunk review
|
52
|
+
|
53
|
+
review というディレクトリに展開されるので、review/bin にパスを通すようにしておいてください。
|
54
|
+
|
55
|
+
最新の開発に追従するには次のようにします。
|
56
|
+
|
57
|
+
svn up
|
58
|
+
|
59
|
+
= ReVIEW テキストの作成と変換
|
60
|
+
|
61
|
+
セットアップを終えたら、ReVIEW フォーマットのテキストを作り、変換できるようになります。次に ReVIEW フォーマットテキストの簡単な例を示します。これを sample.re といった名前で保存します (拡張子も自由ですが、.re 拡張子を推奨します)。
|
62
|
+
|
63
|
+
= はじめてのReVIEW
|
64
|
+
|
65
|
+
//lead{
|
66
|
+
「Hello, ReVIEW.」
|
67
|
+
//}
|
68
|
+
|
69
|
+
== ReVIEWとは
|
70
|
+
|
71
|
+
@<b>{ReVIEW}は、EWBやRDあるいはWikiに似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。
|
72
|
+
|
73
|
+
平易な文法ながらも、コンピュータ関係のドキュメント作成のための多くの機能を備えており、次のような形式に変換できます。
|
74
|
+
|
75
|
+
* テキスト(指示タグ付き)
|
76
|
+
* LaTeX
|
77
|
+
* HTML
|
78
|
+
* XML
|
79
|
+
|
80
|
+
現在入手手段としては次の3つがあります。
|
81
|
+
|
82
|
+
1. Ruby gem
|
83
|
+
2. Git
|
84
|
+
3. Subversion
|
85
|
+
|
86
|
+
ホームページは@<tt>{https://github.com/kmuto/review/wiki/}です。
|
87
|
+
|
88
|
+
テキストファイルの文字エンコーディングには、UTF-8 を使うことをお勧めします。ReVIEW は日本語文字エンコーディングとして UTF-8、EUC-JP、Shift-JIS、JIS を扱うことができ、入力ファイルについては自動判別、出力ファイルについても選択可能 (デフォルトは UTF-8) ですが、入力・出力のいずれにおいても、使用可能な文字についての制限が少ない UTF-8 が最適です。
|
89
|
+
|
90
|
+
次に、章構成ファイルの CHAPS ファイルを同じディレクトリに用意します。このファイルには、ReVIEW フォーマットファイルの名前を格納します。
|
91
|
+
|
92
|
+
sample.re
|
93
|
+
|
94
|
+
CHAPS ファイルの1行目に書いたものが第1章、2行目に書いたものが第2章、……と構成されます (CHAPS に似たものとして、前付けを列挙する PREDEF ファイル、後付けを列挙する POSTDEF ファイルがあります)。
|
95
|
+
|
96
|
+
sample.re から目的の形式に変換するには、review-compile コマンドを使います。
|
97
|
+
|
98
|
+
review-compile --target text sample.re > sample.txt ←テキストにする
|
99
|
+
review-compile --target html sample.re > sample.html ←HTMLにする
|
100
|
+
review-compile --target latex sample.re > sample.tex ←LaTeXにする
|
101
|
+
review-compile --target idgxml sample.re > sample.xml ←XMLにする
|
102
|
+
|
103
|
+
上記では各ファイル個別に変換することを想定して、標準出力をリダイレクトする書式を掲載していますが、-a オプションを付ければ、CHAPS、PREDEF、POSTDEF に従ってすべてのファイルを変換できます。
|
104
|
+
|
105
|
+
review-compile --target html -a ←すべてのファイルをHTMLにする
|
106
|
+
|
107
|
+
sample.re を HTML に変換すると、次のようになります。
|
108
|
+
|
109
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
110
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
111
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ops="http://www.idpf.org/2007/ops" xml:lang="ja">
|
112
|
+
<head>
|
113
|
+
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
|
114
|
+
<meta http-equiv="Content-Style-Type" content="text/css" />
|
115
|
+
<meta name="generator" content="ReVIEW" />
|
116
|
+
<title>はじめてのReVIEW</title>
|
117
|
+
</head>
|
118
|
+
<body>
|
119
|
+
<h1><a id="h1" />第1章 はじめてのReVIEW</h1>
|
120
|
+
<div class="lead">
|
121
|
+
<p>「Hello, ReVIEW.」</p>
|
122
|
+
</div>
|
123
|
+
|
124
|
+
<h2><a id="h1-1" />1.1 ReVIEWとは</h2>
|
125
|
+
<p><b>ReVIEW</b>は、EWBやRDあるいはWikiに似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。</p>
|
126
|
+
<p>平易な文法ながらも、コンピュータ関係のドキュメント作成のための多くの機能を備えており、次のような形式に変換できます。</p>
|
127
|
+
<ul>
|
128
|
+
<li>テキスト(指示タグ付き)</li>
|
129
|
+
<li>LaTeX</li>
|
130
|
+
<li>HTML</li>
|
131
|
+
<li>XML</li>
|
132
|
+
</ul>
|
133
|
+
<p>現在入手手段としては次の3つがあります。</p>
|
134
|
+
<ol>
|
135
|
+
<li>Ruby gem</li>
|
136
|
+
<li>Git</li>
|
137
|
+
<li>Subversion</li>
|
138
|
+
</ol>
|
139
|
+
<p>ホームページは<tt>https://github.com/kmuto/review/wiki/</tt>です。</p>
|
140
|
+
</body>
|
141
|
+
</html>
|
142
|
+
|
143
|
+
ReVIEW フォーマットについての詳細は、format.rdoc (オンラインでは [[https://github.com/kmuto/review/blob/master/doc/format.rdoc]] ) を参照してください。
|
144
|
+
|
145
|
+
review-compile を含め、ほとんどのコマンドは --help オプションを付けるとオプションについてのヘルプが表示されます。review-compile には多数のオプションがあるので確認してください。
|
146
|
+
|
147
|
+
なお、--target で毎回指定するのは面倒なので、review-compile に対するシンボリックリンクを作成しておくとよいでしょう。「review2...」のコマンド名で呼び出せるようになります。
|
148
|
+
|
149
|
+
cd ReVIEWのインストールされたパス/bin
|
150
|
+
ln -s review-compile review2text
|
151
|
+
ln -s review-compile review2html
|
152
|
+
ln -s review-compile review2latex
|
153
|
+
ln -s review-compile review2idgxml
|
154
|
+
|
155
|
+
== プリプロセッサ、ボリューム表示
|
156
|
+
|
157
|
+
#@mapfile、#@maprange、#@mapoutput のタグを使って、指定のファイルの内容あるいはコマンドの実行結果を挿入できます。挿入・更新を行うには、プリプロセッサとなる review-preproc コマンドを使います。
|
158
|
+
|
159
|
+
review-preproc ファイル > 結果ファイル ←標準出力をリダイレクト
|
160
|
+
または
|
161
|
+
review-preproc --replace ファイル ←ファイルを更新したもので上書き
|
162
|
+
|
163
|
+
各章の分量などを表示するには、review-vol コマンドを使います。
|
164
|
+
|
165
|
+
review-vol
|
166
|
+
|
167
|
+
より細かな見出し一覧などを出したいときには、review-index コマンドを使うのもよいでしょう。
|
168
|
+
|
169
|
+
review-index --level 掘り下げる見出しレベル数 -a
|
170
|
+
|
171
|
+
== PDF 化と EPUB 化
|
172
|
+
|
173
|
+
review-pdfmaker コマンドで PDF ブックの作成、review-epubmaker コマンドで EPUB ファイルの作成ができます。
|
174
|
+
|
175
|
+
PDF を作成するには、pTeXLive2009 以上の環境が必要です。EPUB を作成するには、zip コマンドが必要です (MathML も使いたいときには、[[http://www.hinet.mydns.jp/?mathml.rb]] の MathML ライブラリも必要です)。
|
176
|
+
|
177
|
+
いずれのコマンドも、必要な設定情報を記した YAML ファイルを引数に指定して実行します。YAML ファイルのサンプルは、sample.yaml (オンラインでは[[https://github.com/kmuto/review/blob/master/doc/sample.yaml]]) としてこのドキュメントと同じディレクトリに収録しています。
|
178
|
+
|
179
|
+
review-pdfmaker YAMLファイル ←PDFの作成
|
180
|
+
review-epubmaker YAMLファイル ←EPUBの作成
|
181
|
+
|
182
|
+
== クレジット
|
183
|
+
|
184
|
+
ReVIEW は、青木峰郎によって最初に作成されました。武藤健志がこの開発・保守を引き継ぎ、2010年12月時点では、武藤健志、高橋征義、角征典が開発・保守を継続しています。
|
185
|
+
|
186
|
+
バグ・パッチの報告、開発者用メーリングリストなどについての情報は、
|
187
|
+
[[https://github.com/kmuto/review/wiki]]
|
188
|
+
を参照してください。
|
data/doc/sample.yaml
CHANGED
@@ -34,16 +34,24 @@ aut: 吟遊詩人
|
|
34
34
|
stylesheet: stylesheet.css
|
35
35
|
# LaTeX用のスタイルファイル(styディレクトリ以下に置くこと)
|
36
36
|
# texstyle: samplemacro
|
37
|
+
# LaTeX用のdocumentclassを指定する
|
38
|
+
# texdocumentclass: ["jsarticle", "b5paper,oneside"]
|
37
39
|
# 目次として抽出するレベル
|
38
40
|
toclevel: 3
|
39
41
|
# セクション番号を表示するレベル
|
40
42
|
secnolevel: 2
|
43
|
+
# EPUBのバージョン(現時点では2または3。デフォルトは2)
|
44
|
+
epubversion: 2
|
45
|
+
# HTMLのバージョン(現時点では4または5。デフォルトは4。epubversionを3にした場合は自動で5に設定される)
|
46
|
+
htmlversion: 4
|
41
47
|
# EPUB標準の目次以外に目次を作成するか
|
42
48
|
# mytoc: nil
|
43
49
|
# 奥付を作成するか。デフォルトでは作成されない。trueを指定するとデフォルトの奥付、ファイル名を指定するとそれがcolophon.htmlとしてコピーされる
|
44
50
|
# colophon: true
|
45
51
|
# XHTML生成後に実行するプログラム。$1:HTMLの生成されたディレクトリ $2:ReVIEWファイルのあるディレクトリ $3:起動時指定のyamlファイル名
|
46
52
|
# posthook: hook.sh
|
53
|
+
# EPUBで表紙をコンテンツに含めるか。デフォルト(no)では作成されない。yesにするとiBooks等でも最初に表紙が表示されるようになる
|
54
|
+
# cover_linear: yes
|
47
55
|
# review-compileに渡すパラメータ
|
48
56
|
params: --stylesheet=sample.css
|
49
57
|
# デバッグフラグ。nilでないときには一時ファイルをカレントディレクトリに作成し、削除もしない
|
data/lib/epubmaker.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# = epubmaker.rb -- EPUB production set.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010 Kenshi Muto
|
5
|
+
#
|
6
|
+
# This program is free software.
|
7
|
+
# You can distribute or modify this program under the terms of
|
8
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
9
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
10
|
+
#
|
11
|
+
# == Quick usage
|
12
|
+
# (If you put xhtml files on current directory and put figures in
|
13
|
+
# images subdirectory)
|
14
|
+
#
|
15
|
+
# require 'epubmaker'
|
16
|
+
# epub = EPUBMaker::Producer.new
|
17
|
+
# params = epub.load("config.yaml")
|
18
|
+
# epub.contents.push(EPUBMaker::Content.new({"file" => "ch01.xhtml"}))
|
19
|
+
# epub.contents.push(EPUBMaker::Content.new({"file" => "ch02.xhtml"}))
|
20
|
+
# ...
|
21
|
+
# epub.importImageInfo("images")
|
22
|
+
# epub.produce
|
23
|
+
|
24
|
+
require 'epubmaker/producer'
|
25
|
+
require 'epubmaker/resource'
|
26
|
+
require 'epubmaker/content'
|
27
|
+
require 'epubmaker/epubv2'
|
28
|
+
require 'epubmaker/epubv3'
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# = content.rb -- Content object for EPUBMaker.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010 Kenshi Muto
|
5
|
+
#
|
6
|
+
# This program is free software.
|
7
|
+
# You can distribute or modify this program under the terms of
|
8
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
9
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
10
|
+
#
|
11
|
+
|
12
|
+
module EPUBMaker
|
13
|
+
|
14
|
+
# EPUBMaker::Content describes a content data for EPUBMaker. EPUBMaker#contents takes an array of Content.
|
15
|
+
class Content
|
16
|
+
# ID
|
17
|
+
attr_accessor :id
|
18
|
+
# File path (can accept #<anchor> suffix also)
|
19
|
+
attr_accessor :file
|
20
|
+
# MIME type
|
21
|
+
attr_accessor :media
|
22
|
+
# Title
|
23
|
+
attr_accessor :title
|
24
|
+
# Header level (from 1)
|
25
|
+
attr_accessor :level
|
26
|
+
# Show in TOC? nil:No.
|
27
|
+
attr_accessor :notoc
|
28
|
+
|
29
|
+
# :call-seq:
|
30
|
+
# initialize(file, id, media, title, level, notoc)
|
31
|
+
# initialize(hash)
|
32
|
+
# Construct Content object by passing a sequence of parameters or hash.
|
33
|
+
# Keys of +hash+ relate with each parameters.
|
34
|
+
# +file+ (or +hash+["file"]) is required. Others are optional.
|
35
|
+
def initialize(fileorhash, id=nil, media=nil, title=nil, level=nil, notoc=nil)
|
36
|
+
if fileorhash.instance_of?(Hash)
|
37
|
+
@id = fileorhash["id"]
|
38
|
+
@file = fileorhash["file"]
|
39
|
+
@media = fileorhash["media"]
|
40
|
+
@title = fileorhash["title"]
|
41
|
+
@level = fileorhash["level"]
|
42
|
+
@notoc = fileorhash["notoc"]
|
43
|
+
else
|
44
|
+
@file = fileorhash
|
45
|
+
@id = id
|
46
|
+
@media = media
|
47
|
+
@title = title
|
48
|
+
@level = level
|
49
|
+
@notoc = notoc
|
50
|
+
end
|
51
|
+
complement
|
52
|
+
end
|
53
|
+
|
54
|
+
def ==(obj)
|
55
|
+
if self.class != obj.class
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
[self.id, self.file, self.media, self.title, self.level, self.notoc] ==
|
59
|
+
[obj.id, obj.file, obj.media, obj.title, obj.level, obj.notoc]
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Complement other parameters from file parameter.
|
65
|
+
def complement
|
66
|
+
@id = @file.gsub(/[\\\/\.]/, '-') if @id.nil?
|
67
|
+
@media = @file.sub(/.+\./, '').downcase if !@file.nil? && @media.nil?
|
68
|
+
|
69
|
+
@media = "application/xhtml+xml" if @media == "xhtml" || @media == "xml" || @media == "html"
|
70
|
+
@media = "text/css" if @media == "css"
|
71
|
+
@media = "image/jpeg" if @media == "jpg" || @media == "jpeg" || @media == "image/jpg"
|
72
|
+
@media = "image/png" if @media == "png"
|
73
|
+
@media = "image/gif" if @media == "gif"
|
74
|
+
@media = "image/svg" if @media == "svg"
|
75
|
+
@media = "image/svg+xml" if @media == "svg" || @media == "image/svg"
|
76
|
+
|
77
|
+
if @id.nil? || @file.nil? || @media.nil?
|
78
|
+
raise "Type error: #{id}, #{file}, #{media}, #{title}, #{notoc}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,419 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# = epubv2.rb -- EPUB version 2 producer.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010 Kenshi Muto and Masayoshi Takahashi
|
5
|
+
#
|
6
|
+
# This program is free software.
|
7
|
+
# You can distribute or modify this program under the terms of
|
8
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
9
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'epubmaker/producer'
|
13
|
+
|
14
|
+
module EPUBMaker
|
15
|
+
|
16
|
+
# EPUBv2 is EPUB version 2 producer.
|
17
|
+
class EPUBv2
|
18
|
+
# Construct object with parameter hash +params+ and message resource hash +res+.
|
19
|
+
def initialize(producer)
|
20
|
+
@producer = producer
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return mimetype content.
|
24
|
+
def mimetype
|
25
|
+
return <<EOT
|
26
|
+
application/epub+zip
|
27
|
+
EOT
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return opf file content.
|
31
|
+
def opf
|
32
|
+
s = <<EOT
|
33
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
34
|
+
<package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="BookId">
|
35
|
+
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
|
36
|
+
EOT
|
37
|
+
%w[title language date type format source description relation coverage subject rights].each do |item|
|
38
|
+
next if @producer.params[item].nil?
|
39
|
+
if @producer.params[item].instance_of?(Array)
|
40
|
+
s << @producer.params[item].map {|i| %Q[ <dc:#{item}>#{i}</dc:#{item}>\n]}.join
|
41
|
+
else
|
42
|
+
s << %Q[ <dc:#{item}>#{@producer.params[item]}</dc:#{item}>\n]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# ID
|
47
|
+
if @producer.params["isbn"].nil?
|
48
|
+
s << %Q[ <dc:identifier id="BookId">#{@producer.params["urnid"]}</dc:identifier>\n]
|
49
|
+
else
|
50
|
+
s << %Q[ <dc:identifier id="BookId" opf:scheme="ISBN">#{@producer.params["isbn"]}</dc:identifier>\n]
|
51
|
+
end
|
52
|
+
|
53
|
+
# creator
|
54
|
+
%w[aut a-adp a-ann a-arr a-art a-asn a-aqt a-aft a-aui a-ant a-bkp a-clb a-cmm a-dsr a-edt a-ill a-lyr a-mdc a-mus a-nrt a-oth a-pht a-prt a-red a-rev a-spn a-ths a-trc a-trl].each do |role|
|
55
|
+
next if @producer.params[role].nil?
|
56
|
+
@producer.params[role].each do |v|
|
57
|
+
s << %Q[ <dc:creator opf:role="#{role.sub('a-', '')}">#{v}</dc:creator>\n]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
# contributor
|
61
|
+
%w[adp ann arr art asn aqt aft aui ant bkp clb cmm dsr edt ill lyr mdc mus nrt oth pht prt red rev spn ths trc trl].each do |role|
|
62
|
+
next if @producer.params[role].nil?
|
63
|
+
@producer.params[role].each do |v|
|
64
|
+
s << %Q[ <dc:contributor opf:role="#{role}">#{v}</dc:contributor>\n]
|
65
|
+
if role == "prt"
|
66
|
+
s << %Q[ <dc:publisher>#{v}</dc:publisher>\n]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if @producer.params["coverimage"]
|
72
|
+
@producer.contents.each do |item|
|
73
|
+
if item.media =~ /\Aimage/ && item.file =~ /#{@producer.params["coverimage"]}\Z/
|
74
|
+
s << %Q[ <meta name="cover" content="#{item.id}"/>\n]
|
75
|
+
break
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
s << %Q[ </metadata>\n]
|
81
|
+
|
82
|
+
# manifest
|
83
|
+
s << <<EOT
|
84
|
+
<manifest>
|
85
|
+
<item id="ncx" href="#{@producer.params["bookname"]}.ncx" media-type="application/x-dtbncx+xml"/>
|
86
|
+
<item id="#{@producer.params["bookname"]}" href="#{@producer.params["cover"]}" media-type="application/xhtml+xml"/>
|
87
|
+
EOT
|
88
|
+
|
89
|
+
s << %Q[ <item id="toc" href="#{@producer.params["tocfile"]}" media-type="application/xhtml+xml"/>\n] unless @producer.params["mytoc"].nil?
|
90
|
+
|
91
|
+
@producer.contents.each do |item|
|
92
|
+
next if item.file =~ /#/ # skip subgroup
|
93
|
+
s << %Q[ <item id="#{item.id}" href="#{item.file}" media-type="#{item.media}"/>\n]
|
94
|
+
end
|
95
|
+
s << %Q[ </manifest>\n]
|
96
|
+
|
97
|
+
# tocx
|
98
|
+
s << %Q[ <spine toc="ncx">\n]
|
99
|
+
s << %Q[ <itemref idref="#{@producer.params["bookname"]}" linear="no"/>\n]
|
100
|
+
s << %Q[ <itemref idref="toc" />\n] unless @producer.params["mytoc"].nil?
|
101
|
+
|
102
|
+
@producer.contents.each do |item|
|
103
|
+
next if item.media !~ /xhtml\+xml/ # skip non XHTML
|
104
|
+
s << %Q[ <itemref idref="#{item.id}"/>\n] if item.notoc.nil?
|
105
|
+
end
|
106
|
+
s << %Q[ </spine>\n]
|
107
|
+
|
108
|
+
# guide
|
109
|
+
s << %Q[ <guide>\n]
|
110
|
+
s << %Q[ <reference type="cover" title="#{@producer.res.v("covertitle")}" href="#{@producer.params["cover"]}"/>\n]
|
111
|
+
s << %Q[ <reference type="title-page" title="#{@producer.res.v("titlepagetitle")}" href="#{@producer.params["titlepage"]}"/>\n] unless @producer.params["titlepage"].nil?
|
112
|
+
s << %Q[ <reference type="toc" title="#{@producer.res.v("toctitle")}" href="#{@producer.params["tocfile"]}"/>\n] unless @producer.params["mytoc"].nil?
|
113
|
+
s << %Q[ <reference type="colophon" title="#{@producer.res.v("colophontitle")}" href="colophon.#{@producer.params["htmlext"]}"/>\n] unless @producer.params["colophon"].nil? # FIXME: path
|
114
|
+
s << %Q[ </guide>\n]
|
115
|
+
s << %Q[</package>\n]
|
116
|
+
return s
|
117
|
+
end
|
118
|
+
|
119
|
+
# Return ncx content. +indentarray+ defines prefix string for each level.
|
120
|
+
def ncx(indentarray)
|
121
|
+
s = <<EOT
|
122
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
123
|
+
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
|
124
|
+
<head>
|
125
|
+
<meta name="dtb:depth" content="1"/>
|
126
|
+
<meta name="dtb:totalPageCount" content="0"/>
|
127
|
+
<meta name="dtb:maxPageNumber" content="0"/>
|
128
|
+
EOT
|
129
|
+
if @producer.params["isbn"].nil?
|
130
|
+
s << %Q[ <meta name="dtb:uid" content="#{@producer.params["urnid"]}"/>\n]
|
131
|
+
else
|
132
|
+
s << %Q[ <meta name="dtb:uid" content="#{@producer.params["isbn"]}"/>\n]
|
133
|
+
end
|
134
|
+
|
135
|
+
s << <<EOT
|
136
|
+
</head>
|
137
|
+
<docTitle>
|
138
|
+
<text>#{@producer.params["title"]}</text>
|
139
|
+
</docTitle>
|
140
|
+
<docAuthor>
|
141
|
+
<text>#{@producer.params["aut"].nil? ? "" : @producer.params["aut"].join(", ")}</text>
|
142
|
+
</docAuthor>
|
143
|
+
<navMap>
|
144
|
+
<navPoint id="top" playOrder="1">
|
145
|
+
<navLabel>
|
146
|
+
<text>#{@producer.params["title"]}</text>
|
147
|
+
</navLabel>
|
148
|
+
<content src="#{@producer.params["cover"]}"/>
|
149
|
+
</navPoint>
|
150
|
+
EOT
|
151
|
+
|
152
|
+
nav_count = 2
|
153
|
+
|
154
|
+
unless @producer.params["mytoc"].nil?
|
155
|
+
s << <<EOT
|
156
|
+
<navPoint id="toc" playOrder="#{nav_count}">
|
157
|
+
<navLabel>
|
158
|
+
<text>#{@producer.res.v("toctitle")}</text>
|
159
|
+
</navLabel>
|
160
|
+
<content src="#{@producer.params["tocfile"]}"/>
|
161
|
+
</navPoint>
|
162
|
+
EOT
|
163
|
+
nav_count += 1
|
164
|
+
end
|
165
|
+
|
166
|
+
@producer.contents.each do |item|
|
167
|
+
next if item.title.nil?
|
168
|
+
indent = indentarray.nil? ? [""] : indentarray
|
169
|
+
level = item.level.nil? ? 0 : (item.level - 1)
|
170
|
+
level = indent.size - 1 if level >= indent.size
|
171
|
+
s << <<EOT
|
172
|
+
<navPoint id="nav-#{nav_count}" playOrder="#{nav_count}">
|
173
|
+
<navLabel>
|
174
|
+
<text>#{indent[level]}#{item.title}</text>
|
175
|
+
</navLabel>
|
176
|
+
<content src="#{item.file}"/>
|
177
|
+
</navPoint>
|
178
|
+
EOT
|
179
|
+
nav_count += 1
|
180
|
+
end
|
181
|
+
|
182
|
+
s << <<EOT
|
183
|
+
</navMap>
|
184
|
+
</ncx>
|
185
|
+
EOT
|
186
|
+
return s
|
187
|
+
end
|
188
|
+
|
189
|
+
# Return container content.
|
190
|
+
def container
|
191
|
+
s = <<EOT
|
192
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
193
|
+
<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
|
194
|
+
<rootfiles>
|
195
|
+
<rootfile full-path="OEBPS/#{@producer.params["bookname"]}.opf" media-type="application/oebps-package+xml" />
|
196
|
+
</rootfiles>
|
197
|
+
</container>
|
198
|
+
EOT
|
199
|
+
return s
|
200
|
+
end
|
201
|
+
|
202
|
+
# Return cover content.
|
203
|
+
def cover
|
204
|
+
s = common_header
|
205
|
+
s << <<EOT
|
206
|
+
<title>#{@producer.params["title"]}</title>
|
207
|
+
</head>
|
208
|
+
<body>
|
209
|
+
EOT
|
210
|
+
if @producer.params["coverimage"].nil?
|
211
|
+
s << <<EOT
|
212
|
+
<h1 class="cover-title">#{@producer.params["title"]}</h1>
|
213
|
+
EOT
|
214
|
+
else
|
215
|
+
file = nil
|
216
|
+
@producer.contents.each do |item|
|
217
|
+
if item.media =~ /\Aimage/ && item.file =~ /#{@producer.params["coverimage"]}\Z/ # /
|
218
|
+
file = item.file
|
219
|
+
break
|
220
|
+
end
|
221
|
+
end
|
222
|
+
raise "coverimage #{@producer.params["coverimage"]} not found. Abort." if file.nil?
|
223
|
+
s << <<EOT
|
224
|
+
<div id="cover-image" class="cover-image">
|
225
|
+
<img src="#{file}" alt="#{@producer.params["title"]}" class="max"/>
|
226
|
+
</div>
|
227
|
+
EOT
|
228
|
+
end
|
229
|
+
|
230
|
+
s << <<EOT
|
231
|
+
</body>
|
232
|
+
</html>
|
233
|
+
EOT
|
234
|
+
return s
|
235
|
+
end
|
236
|
+
|
237
|
+
# Return title (copying) content.
|
238
|
+
def titlepage
|
239
|
+
s = common_header
|
240
|
+
s << <<EOT
|
241
|
+
<title>#{@producer.params["title"]}</title>
|
242
|
+
</head>
|
243
|
+
<body>
|
244
|
+
<h1 class="tp-title">#{@producer.params["title"]}</h1>
|
245
|
+
EOT
|
246
|
+
|
247
|
+
if @producer.params["aut"]
|
248
|
+
s << <<EOT
|
249
|
+
<p>
|
250
|
+
<br />
|
251
|
+
<br />
|
252
|
+
</p>
|
253
|
+
<h2 class="tp-author">#{@producer.params["aut"]}</h2>
|
254
|
+
EOT
|
255
|
+
end
|
256
|
+
|
257
|
+
if @producer.params["prt"]
|
258
|
+
s << <<EOT
|
259
|
+
<p>
|
260
|
+
<br />
|
261
|
+
<br />
|
262
|
+
<br />
|
263
|
+
<br />
|
264
|
+
</p>
|
265
|
+
<h3 class="tp-publisher">#{@producer.params["prt"]}</h3>
|
266
|
+
EOT
|
267
|
+
end
|
268
|
+
|
269
|
+
s << <<EOT
|
270
|
+
</body>
|
271
|
+
</html>
|
272
|
+
EOT
|
273
|
+
return s
|
274
|
+
end
|
275
|
+
|
276
|
+
# Return colophon content.
|
277
|
+
def colophon
|
278
|
+
s = common_header
|
279
|
+
s << <<EOT
|
280
|
+
<title>#{@producer.res.v("colophontitle")}</title>
|
281
|
+
</head>
|
282
|
+
<body>
|
283
|
+
<div class="colophon">
|
284
|
+
<p class="title">#{@producer.params["title"]}</p>
|
285
|
+
EOT
|
286
|
+
|
287
|
+
if @producer.params["pubhistory"]
|
288
|
+
s << %Q[ <div class="pubhistory">\n <p>#{@producer.params["pubhistory"].gsub(/\n/, "<br />")}</p>\n </div>\n] # FIXME: should be array?
|
289
|
+
end
|
290
|
+
|
291
|
+
s << %Q[ <table class="colophon">\n]
|
292
|
+
s << %Q[ <tr><th>#{@producer.res.v("c-aut")}</th><td>#{@producer.params["aut"]}</td></tr>\n] if @producer.params["aut"]
|
293
|
+
s << %Q[ <tr><th>#{@producer.res.v("c-dsr")}</th><td>#{@producer.params["dsr"]}</td></tr>\n] if @producer.params["dsr"]
|
294
|
+
s << %Q[ <tr><th>#{@producer.res.v("c-ill")}</th><td>#{@producer.params["ill"]}</td></tr>\n] if @producer.params["ill"]
|
295
|
+
s << %Q[ <tr><th>#{@producer.res.v("c-edt")}</th><td>#{@producer.params["edt"]}</td></tr>\n] if @producer.params["edt"]
|
296
|
+
s << %Q[ <tr><th>#{@producer.res.v("c-prt")}</th><td>#{@producer.params["prt"]}</td></tr>\n] if @producer.params["prt"]
|
297
|
+
s << <<EOT
|
298
|
+
</table>
|
299
|
+
</div>
|
300
|
+
</body>
|
301
|
+
</html>
|
302
|
+
EOT
|
303
|
+
return s
|
304
|
+
end
|
305
|
+
|
306
|
+
# Return own toc content.
|
307
|
+
def mytoc
|
308
|
+
s = common_header
|
309
|
+
s << <<EOT
|
310
|
+
<title>#{@producer.res.v("toctitle")}</title>
|
311
|
+
</head>
|
312
|
+
<body>
|
313
|
+
<h1 class="toc-title">#{@producer.res.v("toctitle")}</h1>
|
314
|
+
<ul class="toc-h1">
|
315
|
+
EOT
|
316
|
+
|
317
|
+
# FIXME: indent
|
318
|
+
current = 1
|
319
|
+
init_item = true
|
320
|
+
@producer.contents.each do |item|
|
321
|
+
next if !item.notoc.nil? || item.level.nil? || item.file.nil? || item.title.nil? || item.level > @producer.params["toclevel"].to_i
|
322
|
+
if item.level > current
|
323
|
+
s << %Q[\n<ul class="toc-h#{item.level}">\n]
|
324
|
+
current = item.level
|
325
|
+
elsif item.level < current
|
326
|
+
(current - 1).downto(item.level) do |n|
|
327
|
+
s << %Q[</li>\n</ul>\n]
|
328
|
+
end
|
329
|
+
s << %Q[</li>\n]
|
330
|
+
current = item.level
|
331
|
+
elsif init_item
|
332
|
+
# noop
|
333
|
+
else
|
334
|
+
s << %Q[</li>\n]
|
335
|
+
end
|
336
|
+
s << %Q[<li><a href="#{item.file}">#{item.title}</a>]
|
337
|
+
init_item = false
|
338
|
+
end
|
339
|
+
|
340
|
+
(current - 1).downto(1) do |n|
|
341
|
+
s << %Q[</li>\n</ul>\n]
|
342
|
+
end
|
343
|
+
if !init_item
|
344
|
+
s << %Q[</li>\n]
|
345
|
+
end
|
346
|
+
s << <<EOT
|
347
|
+
</ul>
|
348
|
+
</body>
|
349
|
+
</html>
|
350
|
+
EOT
|
351
|
+
return s
|
352
|
+
end
|
353
|
+
|
354
|
+
# Produce EPUB file +epubfile+.
|
355
|
+
# +basedir+ points the directory has contents.
|
356
|
+
# +tmpdir+ defines temporary directory.
|
357
|
+
def produce(epubfile, basedir, tmpdir)
|
358
|
+
File.open("#{tmpdir}/mimetype", "w") {|f| @producer.mimetype(f) }
|
359
|
+
|
360
|
+
Dir.mkdir("#{tmpdir}/META-INF") unless File.exist?("#{tmpdir}/META-INF")
|
361
|
+
File.open("#{tmpdir}/META-INF/container.xml", "w") {|f| @producer.container(f) }
|
362
|
+
|
363
|
+
Dir.mkdir("#{tmpdir}/OEBPS") unless File.exist?("#{tmpdir}/OEBPS")
|
364
|
+
File.open("#{tmpdir}/OEBPS/#{@producer.params["bookname"]}.opf", "w") {|f| @producer.opf(f) }
|
365
|
+
File.open("#{tmpdir}/OEBPS/#{@producer.params["bookname"]}.ncx", "w") {|f| @producer.ncx(f, @producer.params["ncxindent"]) }
|
366
|
+
File.open("#{tmpdir}/OEBPS/#{@producer.params["tocfile"]}", "w") {|f| @producer.mytoc(f) } unless @producer.params["mytoc"].nil?
|
367
|
+
|
368
|
+
if File.exist?("#{basedir}/#{@producer.params["cover"]}")
|
369
|
+
FileUtils.cp("#{basedir}/#{@producer.params["cover"]}", "#{tmpdir}/OEBPS")
|
370
|
+
else
|
371
|
+
File.open("#{tmpdir}/OEBPS/#{@producer.params["cover"]}", "w") {|f| @producer.cover(f) }
|
372
|
+
end
|
373
|
+
|
374
|
+
# FIXME:colophon and titlepage should be included in @producer.contents.
|
375
|
+
|
376
|
+
@producer.contents.each do |item|
|
377
|
+
next if item.file =~ /#/ # skip subgroup
|
378
|
+
fname = "#{basedir}/#{item.file}"
|
379
|
+
raise "#{fname} doesn't exist. Abort." unless File.exist?(fname)
|
380
|
+
FileUtils.mkdir_p(File.dirname("#{tmpdir}/OEBPS/#{item.file}")) unless File.exist?(File.dirname("#{tmpdir}/OEBPS/#{item.file}"))
|
381
|
+
FileUtils.cp(fname, "#{tmpdir}/OEBPS/#{item.file}")
|
382
|
+
end
|
383
|
+
|
384
|
+
fork {
|
385
|
+
Dir.chdir(tmpdir) {|d|
|
386
|
+
exec("zip -0X #{epubfile} mimetype")
|
387
|
+
}
|
388
|
+
}
|
389
|
+
Process.waitall
|
390
|
+
fork {
|
391
|
+
Dir.chdir(tmpdir) {|d|
|
392
|
+
exec("zip -Xr9D #{epubfile} META-INF OEBPS")
|
393
|
+
}
|
394
|
+
}
|
395
|
+
Process.waitall
|
396
|
+
end
|
397
|
+
|
398
|
+
private
|
399
|
+
|
400
|
+
# Return common XHTML headder
|
401
|
+
def common_header
|
402
|
+
s =<<EOT
|
403
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
404
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
405
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ops="http://www.idpf.org/2007/ops" xml:lang="#{@producer.params["language"]}">
|
406
|
+
<head>
|
407
|
+
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
408
|
+
<meta http-equiv="Content-Style-Type" content="text/css"/>
|
409
|
+
<meta name="generator" content="EPUBMaker::Producer"/>
|
410
|
+
EOT
|
411
|
+
|
412
|
+
@producer.params["stylesheet"].each do |file|
|
413
|
+
s << %Q[ <link rel="stylesheet" type="text/css" href="#{file}"/>\n]
|
414
|
+
end
|
415
|
+
return s
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
end
|