review 4.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (259) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +35 -0
  3. data/.github/workflows/ruby-win.yml +19 -9
  4. data/.github/workflows/ruby.yml +7 -3
  5. data/.rubocop.yml +138 -34
  6. data/NEWS.ja.md +285 -0
  7. data/NEWS.md +285 -1
  8. data/README.md +7 -6
  9. data/Rakefile +7 -2
  10. data/bin/review +2 -4
  11. data/bin/review-catalog-converter +4 -4
  12. data/bin/review-check +8 -12
  13. data/bin/review-checkdep +2 -5
  14. data/bin/review-compile +18 -34
  15. data/bin/review-epub2html +1 -4
  16. data/bin/review-epubmaker +3 -4
  17. data/bin/review-idgxmlmaker +1 -3
  18. data/bin/review-index +5 -86
  19. data/bin/review-init +1 -4
  20. data/bin/review-pdfmaker +1 -3
  21. data/bin/review-preproc +30 -38
  22. data/bin/review-textmaker +1 -3
  23. data/bin/review-update +1 -4
  24. data/bin/review-validate +4 -4
  25. data/bin/review-vol +5 -82
  26. data/bin/review-webmaker +1 -3
  27. data/doc/config.yml.sample +45 -11
  28. data/doc/config.yml.sample-simple +3 -3
  29. data/doc/format.ja.md +103 -13
  30. data/doc/format.md +104 -16
  31. data/doc/makeindex.ja.md +2 -2
  32. data/doc/pdfmaker.ja.md +42 -0
  33. data/doc/pdfmaker.md +41 -0
  34. data/doc/quickstart.ja.md +19 -6
  35. data/doc/quickstart.md +18 -6
  36. data/doc/writing_vertical.ja.md +6 -0
  37. data/lib/review.rb +1 -1
  38. data/lib/review/book.rb +2 -2
  39. data/lib/review/book/base.rb +67 -29
  40. data/lib/review/book/bib.rb +21 -0
  41. data/lib/review/book/book_unit.rb +158 -0
  42. data/lib/review/book/chapter.rb +33 -26
  43. data/lib/review/book/index.rb +24 -185
  44. data/lib/review/book/index/item.rb +7 -1
  45. data/lib/review/book/page_metric.rb +7 -7
  46. data/lib/review/book/part.rb +26 -11
  47. data/lib/review/book/volume.rb +5 -5
  48. data/lib/review/builder.rb +121 -52
  49. data/lib/review/call_hook.rb +20 -0
  50. data/lib/review/catalog.rb +3 -2
  51. data/lib/review/compiler.rb +230 -111
  52. data/lib/review/configure.rb +91 -7
  53. data/lib/review/converter.rb +1 -1
  54. data/lib/review/epub2html.rb +6 -1
  55. data/lib/review/epubmaker.rb +124 -152
  56. data/lib/review/epubmaker/content.rb +113 -0
  57. data/lib/review/epubmaker/epubcommon.rb +372 -0
  58. data/lib/review/epubmaker/epubv2.rb +178 -0
  59. data/lib/review/epubmaker/epubv3.rb +231 -0
  60. data/lib/review/epubmaker/producer.rb +167 -0
  61. data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
  62. data/lib/review/epubmaker/zip_exporter.rb +84 -0
  63. data/lib/review/exception.rb +13 -0
  64. data/lib/review/htmlbuilder.rb +176 -89
  65. data/lib/review/htmlutils.rb +8 -11
  66. data/lib/review/i18n.rb +2 -1
  67. data/lib/review/idgxmlbuilder.rb +165 -75
  68. data/lib/review/idgxmlmaker.rb +24 -28
  69. data/lib/review/img_math.rb +238 -0
  70. data/lib/review/index_builder.rb +645 -0
  71. data/lib/review/init.rb +9 -17
  72. data/lib/review/latexbox.rb +58 -0
  73. data/lib/review/latexbuilder.rb +193 -75
  74. data/lib/review/latexutils.rb +9 -1
  75. data/lib/review/lineinput.rb +112 -2
  76. data/lib/review/loggable.rb +27 -0
  77. data/lib/review/logger.rb +90 -3
  78. data/lib/review/makerhelper.rb +17 -188
  79. data/lib/review/markdownbuilder.rb +54 -4
  80. data/lib/review/pdfmaker.rb +76 -84
  81. data/lib/review/plaintextbuilder.rb +106 -22
  82. data/lib/review/preprocessor.rb +107 -303
  83. data/lib/review/preprocessor/directive.rb +35 -0
  84. data/lib/review/preprocessor/line.rb +34 -0
  85. data/lib/review/preprocessor/repository.rb +177 -0
  86. data/lib/review/rstbuilder.rb +27 -8
  87. data/lib/review/sec_counter.rb +14 -0
  88. data/lib/review/template.rb +11 -1
  89. data/lib/review/textmaker.rb +27 -32
  90. data/lib/review/textutils.rb +3 -12
  91. data/lib/review/tocprinter.rb +242 -97
  92. data/lib/review/topbuilder.rb +98 -31
  93. data/lib/review/update.rb +12 -13
  94. data/lib/review/version.rb +1 -1
  95. data/lib/review/volumeprinter.rb +97 -0
  96. data/lib/review/webmaker.rb +40 -47
  97. data/lib/review/webtocprinter.rb +39 -35
  98. data/lib/review/yamlloader.rb +2 -1
  99. data/review.gemspec +5 -3
  100. data/samples/sample-book/src/config-epub2.yml +1 -1
  101. data/samples/sample-book/src/config.yml +3 -3
  102. data/samples/sample-book/src/lib/tasks/review.rake +19 -1
  103. data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +2 -1
  104. data/samples/syntax-book/Gemfile +1 -1
  105. data/samples/syntax-book/ch01.re +1 -1
  106. data/samples/syntax-book/ch02.re +21 -6
  107. data/samples/syntax-book/ch03.re +1 -1
  108. data/samples/syntax-book/config.yml +1 -1
  109. data/samples/syntax-book/images/img3-2.png +0 -0
  110. data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +2 -1
  111. data/templates/html/_colophon.html.erb +23 -0
  112. data/templates/html/_colophon_history.html.erb +9 -0
  113. data/templates/html/_cover.html.erb +10 -0
  114. data/templates/html/_part_body.html.erb +6 -0
  115. data/templates/html/_titlepage.html.erb +20 -0
  116. data/templates/html/layout-html5.html.erb +6 -0
  117. data/templates/html/layout-xhtml1.html.erb +6 -0
  118. data/templates/latex/config.erb +35 -23
  119. data/templates/latex/review-jlreq/README.md +3 -1
  120. data/templates/latex/review-jlreq/review-base.sty +36 -23
  121. data/templates/latex/review-jlreq/review-jlreq.cls +18 -25
  122. data/templates/latex/review-jlreq/review-style.sty +6 -1
  123. data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
  124. data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
  125. data/templates/latex/review-jsbook/README.md +7 -5
  126. data/templates/latex/review-jsbook/review-base.sty +40 -24
  127. data/templates/latex/review-jsbook/review-jsbook.cls +13 -3
  128. data/templates/latex/review-jsbook/review-style.sty +6 -1
  129. data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
  130. data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
  131. data/templates/opf/epubv2.opf.erb +7 -7
  132. data/templates/opf/epubv3.opf.erb +7 -7
  133. data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
  134. data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
  135. data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
  136. data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
  137. data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
  138. data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
  139. data/templates/web/html/layout-html5.html.erb +9 -8
  140. data/templates/web/html/layout-xhtml1.html.erb +6 -0
  141. data/test/assets/header_listener.html +35 -0
  142. data/test/assets/img_math/img1.png +0 -0
  143. data/test/assets/img_math/img2.png +0 -0
  144. data/test/assets/img_math/img3.png +0 -0
  145. data/test/assets/syntax_book_index_detail.txt +58 -0
  146. data/test/assets/test_template.tex +6 -3
  147. data/test/assets/test_template_backmatter.tex +6 -3
  148. data/test/book_test_helper.rb +11 -5
  149. data/test/run_test.rb +1 -1
  150. data/test/test_book.rb +54 -63
  151. data/test/test_book_chapter.rb +95 -54
  152. data/test/test_book_part.rb +3 -3
  153. data/test/test_builder.rb +29 -20
  154. data/test/test_catalog_converter_cmd.rb +1 -1
  155. data/test/test_converter.rb +1 -0
  156. data/test/test_epub3maker.rb +170 -126
  157. data/test/test_epubmaker.rb +254 -129
  158. data/test/test_epubmaker_cmd.rb +15 -4
  159. data/test/test_helper.rb +12 -5
  160. data/test/test_htmlbuilder.rb +926 -76
  161. data/test/test_htmlutils.rb +0 -12
  162. data/test/test_i18n.rb +33 -33
  163. data/test/test_idgxmlbuilder.rb +531 -20
  164. data/test/test_idgxmlmaker_cmd.rb +7 -3
  165. data/test/test_img_math.rb +111 -0
  166. data/test/test_index.rb +62 -52
  167. data/test/test_indexbuilder.rb +52 -0
  168. data/test/test_latexbuilder.rb +891 -20
  169. data/test/test_latexbuilder_v2.rb +56 -10
  170. data/test/test_lineinput.rb +20 -93
  171. data/test/test_logger.rb +7 -7
  172. data/test/test_makerhelper.rb +0 -12
  173. data/test/test_markdownbuilder.rb +32 -0
  174. data/test/test_pdfmaker.rb +100 -11
  175. data/test/test_pdfmaker_cmd.rb +3 -3
  176. data/test/test_plaintextbuilder.rb +546 -32
  177. data/test/test_preprocessor.rb +188 -1
  178. data/test/test_review_ext.rb +2 -1
  179. data/test/test_reviewheaderlistener.rb +49 -0
  180. data/test/test_rstbuilder.rb +25 -1
  181. data/test/test_sec_counter.rb +156 -0
  182. data/test/test_template.rb +12 -2
  183. data/test/test_textmaker_cmd.rb +5 -1
  184. data/test/test_tocprinter.rb +46 -0
  185. data/test/test_topbuilder.rb +324 -20
  186. data/test/test_update.rb +44 -44
  187. data/test/test_webtocprinter.rb +75 -43
  188. data/test/test_zip_exporter.rb +5 -6
  189. data/vendor/gentombow/LICENSE +1 -1
  190. data/vendor/gentombow/Makefile +0 -1
  191. data/vendor/gentombow/bounddvi-en.pdf +0 -0
  192. data/vendor/gentombow/bounddvi-en.tex +1 -0
  193. data/vendor/gentombow/bounddvi.pdf +0 -0
  194. data/vendor/gentombow/bounddvi.sty +30 -7
  195. data/vendor/gentombow/bounddvi.tex +1 -0
  196. data/vendor/gentombow/create_archive.sh +1 -0
  197. data/vendor/gentombow/gentombow-ja.pdf +0 -0
  198. data/vendor/gentombow/gentombow-ja.tex +9 -0
  199. data/vendor/gentombow/gentombow.pdf +0 -0
  200. data/vendor/gentombow/gentombow.sty +32 -10
  201. data/vendor/gentombow/gentombow.tex +8 -0
  202. data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
  203. data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
  204. data/vendor/jsclasses/Makefile +3 -2
  205. data/vendor/jsclasses/create_archive.sh +5 -5
  206. data/vendor/jsclasses/jis/Makefile +3 -2
  207. data/vendor/jsclasses/jis/jsarticle.cls +22 -18
  208. data/vendor/jsclasses/jis/jsbook.cls +22 -18
  209. data/vendor/jsclasses/jis/jsclasses.dtx +94 -13
  210. data/vendor/jsclasses/jis/jsclasses.ins +15 -5
  211. data/vendor/jsclasses/jis/jslogo.ins +9 -0
  212. data/vendor/jsclasses/jis/jslogo.sty +1 -13
  213. data/vendor/jsclasses/jis/jspf.cls +22 -18
  214. data/vendor/jsclasses/jis/jsreport.cls +22 -18
  215. data/vendor/jsclasses/jis/jsverb.ins +9 -0
  216. data/vendor/jsclasses/jis/jsverb.sty +1 -13
  217. data/vendor/jsclasses/jis/kiyou.cls +22 -18
  218. data/vendor/jsclasses/jis/minijs.sty +65 -22
  219. data/vendor/jsclasses/jis/okumacro.ins +9 -0
  220. data/vendor/jsclasses/jis/okumacro.sty +1 -13
  221. data/vendor/jsclasses/jis/okuverb.ins +9 -0
  222. data/vendor/jsclasses/jis/okuverb.sty +1 -13
  223. data/vendor/jsclasses/jis/winjis.sty +23 -19
  224. data/vendor/jsclasses/jsarticle.cls +22 -18
  225. data/vendor/jsclasses/jsbook.cls +22 -18
  226. data/vendor/jsclasses/jsclasses.dtx +94 -13
  227. data/vendor/jsclasses/jsclasses.ins +15 -5
  228. data/vendor/jsclasses/jsclasses.pdf +0 -0
  229. data/vendor/jsclasses/jslogo.ins +9 -0
  230. data/vendor/jsclasses/jslogo.pdf +0 -0
  231. data/vendor/jsclasses/jslogo.sty +1 -13
  232. data/vendor/jsclasses/jspf.cls +22 -18
  233. data/vendor/jsclasses/jsreport.cls +22 -18
  234. data/vendor/jsclasses/jsverb.ins +9 -0
  235. data/vendor/jsclasses/jsverb.pdf +0 -0
  236. data/vendor/jsclasses/jsverb.sty +1 -13
  237. data/vendor/jsclasses/kiyou.cls +22 -18
  238. data/vendor/jsclasses/minijs.sty +68 -22
  239. data/vendor/jsclasses/okumacro.ins +9 -0
  240. data/vendor/jsclasses/okumacro.pdf +0 -0
  241. data/vendor/jsclasses/okumacro.sty +1 -13
  242. data/vendor/jsclasses/okuverb.ins +9 -0
  243. data/vendor/jsclasses/okuverb.pdf +0 -0
  244. data/vendor/jsclasses/okuverb.sty +1 -13
  245. data/vendor/jsclasses/tests/relfont.tex +10 -0
  246. data/vendor/jsclasses/winjis.sty +23 -19
  247. metadata +106 -22
  248. data/.rubocop_todo.yml +0 -7
  249. data/lib/epubmaker.rb +0 -23
  250. data/lib/epubmaker/content.rb +0 -110
  251. data/lib/epubmaker/epubcommon.rb +0 -441
  252. data/lib/epubmaker/epubv2.rb +0 -143
  253. data/lib/epubmaker/epubv3.rb +0 -233
  254. data/lib/epubmaker/producer.rb +0 -375
  255. data/lib/epubmaker/zip_exporter.rb +0 -81
  256. data/lib/lineinput.rb +0 -155
  257. data/lib/review/book/compilable.rb +0 -178
  258. data/lib/review/tocparser.rb +0 -275
  259. data/test/test_tocparser.rb +0 -25
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2012-2020 Masanori Kado, Masayoshi Takahashi, Kenshi Muto
2
+ # Copyright (c) 2012-2021 Masanori Kado, Masayoshi Takahashi, Kenshi Muto
3
3
  #
4
4
  # This program is free software.
5
5
  # You can distribute or modify this program under the terms of
@@ -7,18 +7,19 @@
7
7
  # For details of the GNU LGPL, see the file "COPYING".
8
8
  #
9
9
  require 'securerandom'
10
+ require 'review/yamlloader'
10
11
 
11
12
  module ReVIEW
12
13
  class Configure < Hash
13
14
  attr_accessor :maker
14
15
 
15
- def self.values
16
+ def self.values # rubocop:disable Metrics/MethodLength
16
17
  conf = Configure[
17
18
  # These parameters can be overridden by YAML file.
18
19
  'bookname' => 'book', # it defines epub file name also
19
20
  'booktitle' => 'Re:VIEW Sample Book',
20
21
  'title' => nil,
21
- 'aut' => ['anonymous'], # author
22
+ 'aut' => nil, # author
22
23
  'prt' => nil, # printer(publisher)
23
24
  'asn' => nil, # associated name
24
25
  'ant' => nil, # bibliographic antecedent
@@ -31,7 +32,7 @@ module ReVIEW
31
32
  'date' => Time.now.strftime('%Y-%m-%d'), # publishing date
32
33
  'rights' => nil, # Copyright messages
33
34
  'description' => nil, # Description
34
- 'urnid' => "urn:uid:#{SecureRandom.uuid}", # Identifier
35
+ 'urnid' => "urn:uuid:#{SecureRandom.uuid}", # Identifier
35
36
  'stylesheet' => [], # stylesheet file
36
37
  'coverfile' => nil, # content file of body of cover page
37
38
  'mytoc' => nil, # whether make own table of contents or not
@@ -45,8 +46,7 @@ module ReVIEW
45
46
  'debug' => nil, # debug flag
46
47
  'catalogfile' => 'catalog.yml',
47
48
  'language' => 'ja', # XXX default language should be JA??
48
- 'mathml' => nil, # for HTML
49
- 'imgmath' => nil, # for HTML
49
+ 'math_format' => nil,
50
50
  'htmlext' => 'html',
51
51
  'htmlversion' => 5,
52
52
  'contentdir' => '.',
@@ -63,7 +63,8 @@ module ReVIEW
63
63
  'image_types' => %w[.ai .psd .eps .pdf .tif .tiff .png .bmp .jpg .jpeg .gif .svg],
64
64
  'bib_file' => 'bib.re',
65
65
  'words_file' => nil,
66
- 'colophon_order' => %w[aut csl trl dsr ill cov edt pbl contact prt],
66
+ 'colophon_order' => %w[aut csl trl dsr ill cov edt pbl contact prt pht],
67
+ 'chapterlink' => true,
67
68
  'externallink' => true,
68
69
  'join_lines_by_lang' => nil, # experimental. default should be nil
69
70
  'table_row_separator' => 'tabs',
@@ -106,12 +107,94 @@ module ReVIEW
106
107
  'lineheight' => 10 * 1.2,
107
108
  'pdfcrop_pixelize_cmd' => 'pdftocairo -%t -r 90 -f %p -l %p -singlefile %i %O',
108
109
  'dvipng_cmd' => 'dvipng -T tight -z 9 -p %p -l %p -o %o %i'
110
+ },
111
+ 'caption_position' => {
112
+ 'list' => 'top',
113
+ 'image' => 'bottom',
114
+ 'table' => 'top',
115
+ 'equation' => 'top'
116
+ },
117
+ # for EPUBMaker
118
+ 'modified' => Time.now.utc.strftime('%Y-%02m-%02dT%02H:%02M:%02SZ'),
119
+ 'isbn' => nil,
120
+ 'titlefile' => nil,
121
+ 'originaltitlefile' => nil,
122
+ 'profile' => nil,
123
+ 'direction' => 'ltr',
124
+ 'image_maxpixels' => 4_000_000,
125
+ 'font_ext' => %w[ttf woff otf],
126
+ 'epubmaker' => {
127
+ 'flattoc' => nil,
128
+ 'flattocindent' => true,
129
+ 'ncx_indent' => [],
130
+ 'zip_stage1' => 'zip -0Xq',
131
+ 'zip_stage2' => 'zip -Xr9Dq',
132
+ 'zip_addpath' => nil,
133
+ 'hook_beforeprocess' => nil,
134
+ 'hook_afterfrontmatter' => nil,
135
+ 'hook_afterbody' => nil,
136
+ 'hook_afterbackmatter' => nil,
137
+ 'hook_aftercopyimage' => nil,
138
+ 'hook_prepack' => nil,
139
+ 'rename_for_legacy' => nil,
140
+ 'verify_target_images' => nil,
141
+ 'force_include_images' => [],
142
+ 'cover_linear' => nil,
143
+ 'back_footnote' => nil
109
144
  }
110
145
  ]
111
146
  conf.maker = nil
112
147
  conf
113
148
  end
114
149
 
150
+ def self.create(maker: nil, yamlfile: nil, config: nil)
151
+ conf = self.values
152
+ conf.maker = maker
153
+
154
+ if yamlfile
155
+ begin
156
+ loader = ReVIEW::YAMLLoader.new
157
+ conf.deep_merge!(loader.load_file(yamlfile))
158
+ rescue => e
159
+ raise ReVIEW::ConfigError, "yaml error #{e.message}"
160
+ end
161
+ end
162
+
163
+ # YAML configs will be overridden by command line options.
164
+ if config
165
+ conf.deep_merge!(config)
166
+ end
167
+
168
+ conf.migrate_parameters
169
+
170
+ conf
171
+ end
172
+
173
+ def migrate_parameters
174
+ # string to array
175
+ %w[subject aut
176
+ 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
177
+ 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
178
+ adp ann arr art asn aut aqt aft aui ant bkp clb cmm dsr edt
179
+ ill lyr mdc mus nrt oth pht pbl prt red rev spn ths trc trl
180
+ stylesheet rights].each do |item|
181
+ if self[item] && self[item].is_a?(String)
182
+ self[item] = [self[item]]
183
+ end
184
+ end
185
+
186
+ # backward compatibility
187
+ if self['mathml']
188
+ warn '"mathml: true" is obsoleted. Please use "math_format: mathml"'
189
+ self['math_format'] = 'mathml'
190
+ end
191
+
192
+ if self['imgmath']
193
+ warn '"imgmath: true" is obsoleted. Please use "math_format: imgmath"'
194
+ self['math_format'] = 'imgmath'
195
+ end
196
+ end
197
+
115
198
  def [](key)
116
199
  maker = self.maker
117
200
  if maker && self.key?(maker) && self.fetch(maker) && self.fetch(maker).key?(key)
@@ -120,6 +203,7 @@ module ReVIEW
120
203
  if self.key?(key)
121
204
  return self.fetch(key)
122
205
  end
206
+
123
207
  nil
124
208
  end
125
209
 
@@ -17,7 +17,7 @@ module ReVIEW
17
17
  chap_name = File.basename(file, '.*')
18
18
  chap = @book.chapter(chap_name)
19
19
  result = @compiler.compile(chap)
20
- File.open(output_path, 'w') { |f| f.puts result }
20
+ File.write(output_path, result)
21
21
  end
22
22
  end
23
23
  end
@@ -8,10 +8,15 @@
8
8
 
9
9
  require 'zip'
10
10
  require 'rexml/document'
11
- require 'cgi'
12
11
  require 'optparse'
13
12
  require 'review/version'
14
13
 
14
+ begin
15
+ require 'cgi/escape'
16
+ rescue
17
+ require 'cgi/util'
18
+ end
19
+
15
20
  module ReVIEW
16
21
  class Epub2Html
17
22
  def self.execute(*args)
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2010-2020 Kenshi Muto and Masayoshi Takahashi
1
+ # Copyright (c) 2010-2021 Kenshi Muto and Masayoshi Takahashi
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -13,57 +13,35 @@ require 'review/book'
13
13
  require 'review/configure'
14
14
  require 'review/converter'
15
15
  require 'review/latexbuilder'
16
- require 'review/yamlloader'
17
16
  require 'review/version'
18
17
  require 'review/htmltoc'
19
18
  require 'review/htmlbuilder'
19
+ require 'review/img_math'
20
20
 
21
- require 'review/yamlloader'
22
21
  require 'rexml/document'
23
22
  require 'rexml/streamlistener'
24
- require 'epubmaker'
23
+ require 'review/call_hook'
24
+ require 'review/epubmaker/producer'
25
+ require 'review/epubmaker/content'
26
+ require 'review/epubmaker/epubv2'
27
+ require 'review/epubmaker/epubv3'
25
28
  require 'review/epubmaker/reviewheaderlistener'
26
29
  require 'review/makerhelper'
30
+ require 'review/loggable'
27
31
 
28
32
  module ReVIEW
29
33
  class EPUBMaker
30
- include ::EPUBMaker
31
- include REXML
32
34
  include MakerHelper
35
+ include Loggable
36
+ include ReVIEW::CallHook
33
37
 
34
38
  def initialize
35
39
  @producer = nil
36
40
  @htmltoc = nil
37
41
  @buildlogtxt = 'build-log.txt'
38
42
  @logger = ReVIEW.logger
39
- end
40
-
41
- def error(msg)
42
- @logger.error msg
43
- exit 1
44
- end
45
-
46
- def warn(msg)
47
- @logger.warn msg
48
- end
49
-
50
- def log(msg)
51
- @logger.debug(msg)
52
- end
53
-
54
- def load_yaml(yamlfile)
55
- loader = ReVIEW::YAMLLoader.new
56
- @config = ReVIEW::Configure.values
57
- begin
58
- @config.deep_merge!(loader.load_file(yamlfile))
59
- rescue => e
60
- error "yaml error #{e.message}"
61
- end
62
-
63
- @producer = Producer.new(@config)
64
- @producer.load(yamlfile)
65
- @config = @producer.config
66
- @config.maker = 'epubmaker'
43
+ @img_math = nil
44
+ @basedir = nil
67
45
  end
68
46
 
69
47
  def self.execute(*args)
@@ -94,23 +72,29 @@ module ReVIEW
94
72
  end
95
73
 
96
74
  def execute(*args)
97
- @config = ReVIEW::Configure.values
98
- @config.maker = 'epubmaker'
99
75
  cmd_config, yamlfile, exportfile = parse_opts(args)
100
- error "#{yamlfile} not found." unless File.exist?(yamlfile)
76
+ error! "#{yamlfile} not found." unless File.exist?(yamlfile)
101
77
 
102
- load_yaml(yamlfile)
103
- @config.deep_merge!(cmd_config)
78
+ @config = ReVIEW::Configure.create(maker: 'epubmaker',
79
+ yamlfile: yamlfile,
80
+ config: cmd_config)
81
+ @producer = ReVIEW::EPUBMaker::Producer.new(@config)
104
82
  update_log_level
105
- log("Loaded yaml file (#{yamlfile}).")
83
+ debug("Loaded yaml file (#{yamlfile}).")
84
+ @basedir = File.absolute_path(File.dirname(yamlfile))
106
85
 
107
86
  produce(yamlfile, exportfile)
108
87
  end
109
88
 
110
89
  def update_log_level
111
90
  if @config['debug']
112
- @logger.level = Logger::DEBUG
113
- else
91
+ if @logger.ttylogger?
92
+ ReVIEW.logger = nil
93
+ @logger = ReVIEW.logger(level: 'debug')
94
+ else
95
+ @logger.level = Logger::DEBUG
96
+ end
97
+ elsif !@logger.ttylogger?
114
98
  @logger.level = Logger::INFO
115
99
  end
116
100
  end
@@ -133,43 +117,41 @@ module ReVIEW
133
117
  bookname ||= @config['bookname']
134
118
  booktmpname = "#{bookname}-epub"
135
119
 
136
- begin
137
- @config.check_version(ReVIEW::VERSION)
138
- rescue ReVIEW::ConfigError => e
120
+ @img_math = ReVIEW::ImgMath.new(@config)
121
+ unless @config.check_version(ReVIEW::VERSION, exception: false)
139
122
  warn e.message
140
123
  end
141
- log("#{bookname}.epub will be created.")
124
+ debug("#{bookname}.epub will be created.")
142
125
 
143
126
  FileUtils.rm_f("#{bookname}.epub")
144
127
  if @config['debug']
145
128
  FileUtils.rm_rf(booktmpname)
146
129
  end
147
130
 
148
- cleanup_mathimg
131
+ @img_math.cleanup_mathimg
149
132
 
150
133
  basetmpdir = build_path
151
134
  begin
152
- log("Created first temporary directory as #{basetmpdir}.")
135
+ debug("Created first temporary directory as #{basetmpdir}.")
153
136
 
154
- call_hook('hook_beforeprocess', basetmpdir)
137
+ call_hook('hook_beforeprocess', basetmpdir, base_dir: @basedir)
155
138
 
156
139
  @htmltoc = ReVIEW::HTMLToc.new(basetmpdir)
157
140
  ## copy all files into basetmpdir
158
141
  copy_stylesheet(basetmpdir)
159
142
 
160
143
  copy_frontmatter(basetmpdir)
161
- call_hook('hook_afterfrontmatter', basetmpdir)
144
+ call_hook('hook_afterfrontmatter', basetmpdir, base_dir: @basedir)
162
145
 
163
146
  build_body(basetmpdir, yamlfile)
164
- call_hook('hook_afterbody', basetmpdir)
147
+ call_hook('hook_afterbody', basetmpdir, base_dir: @basedir)
165
148
 
166
149
  copy_backmatter(basetmpdir)
167
150
 
168
- math_dir = "./#{@config['imagedir']}/_review_math"
169
- if @config['imgmath'] && File.exist?(File.join(math_dir, '__IMGMATH_BODY__.tex'))
170
- make_math_images(math_dir)
151
+ if @config['math_format'] == 'imgmath'
152
+ @img_math.make_math_images
171
153
  end
172
- call_hook('hook_afterbackmatter', basetmpdir)
154
+ call_hook('hook_afterbackmatter', basetmpdir, base_dir: @basedir)
173
155
 
174
156
  ## push contents in basetmpdir into @producer
175
157
  push_contents(basetmpdir)
@@ -185,7 +167,7 @@ module ReVIEW
185
167
  copy_resources('adv', File.join(basetmpdir, @config['imagedir']))
186
168
  copy_resources(@config['fontdir'], File.join(basetmpdir, 'fonts'), @config['font_ext'])
187
169
 
188
- call_hook('hook_aftercopyimage', basetmpdir)
170
+ call_hook('hook_aftercopyimage', basetmpdir, base_dir: @basedir)
189
171
 
190
172
  @producer.import_imageinfo(File.join(basetmpdir, @config['imagedir']), basetmpdir)
191
173
  @producer.import_imageinfo(File.join(basetmpdir, 'fonts'), basetmpdir, @config['font_ext'])
@@ -197,35 +179,25 @@ module ReVIEW
197
179
  epubtmpdir = File.join(basetmpdir, booktmpname)
198
180
  Dir.mkdir(epubtmpdir)
199
181
  end
200
- log('Call ePUB producer.')
201
- @producer.produce("#{bookname}.epub", basetmpdir, epubtmpdir)
202
- log('Finished.')
182
+ debug('Call ePUB producer.')
183
+ @producer.produce("#{bookname}.epub", basetmpdir, epubtmpdir, base_dir: @basedir)
184
+ debug('Finished.')
185
+ @logger.success("built #{bookname}.epub")
203
186
  rescue ApplicationError => e
204
187
  raise if @config['debug']
205
- error(e.message)
188
+
189
+ error! e.message
206
190
  ensure
207
191
  FileUtils.remove_entry_secure(basetmpdir) unless @config['debug']
208
192
  end
209
193
  end
210
194
 
211
- def call_hook(hook_name, *params)
212
- filename = @config['epubmaker'][hook_name]
213
- log("Call #{hook_name}. (#{filename})")
214
- if filename.present? && File.exist?(filename) && FileTest.executable?(filename)
215
- if ENV['REVIEW_SAFE_MODE'].to_i & 1 > 0
216
- warn 'hook is prohibited in safe mode. ignored.'
217
- else
218
- system(filename, *params)
219
- end
220
- end
221
- end
222
-
223
195
  def verify_target_images(basetmpdir)
224
196
  @producer.contents.each do |content|
225
197
  case content.media
226
198
  when 'application/xhtml+xml'
227
199
  File.open("#{basetmpdir}/#{content.file}") do |f|
228
- Document.new(File.new(f)).each_element('//img') do |e|
200
+ REXML::Document.new(File.new(f)).each_element('//img') do |e|
229
201
  @config['epubmaker']['force_include_images'].push(e.attributes['src'])
230
202
  if e.attributes['src'] =~ /svg\Z/i
231
203
  content.properties.push('svg')
@@ -247,20 +219,21 @@ module ReVIEW
247
219
 
248
220
  def copy_images(resdir, destdir, allow_exts = nil)
249
221
  return nil unless File.exist?(resdir)
222
+
250
223
  allow_exts ||= @config['image_ext']
251
224
  FileUtils.mkdir_p(destdir)
252
225
  if @config['epubmaker']['verify_target_images'].present?
253
226
  @config['epubmaker']['force_include_images'].each do |file|
254
227
  unless File.exist?(file)
255
- if file !~ /\Ahttp[s]?:/
228
+ if file !~ /\Ahttps?:/
256
229
  warn "#{file} is not found, skip."
257
230
  end
258
231
  next
259
232
  end
260
233
  basedir = File.dirname(file)
261
234
  FileUtils.mkdir_p(File.join(destdir, basedir))
262
- log("Copy #{file} to the temporary directory.")
263
- FileUtils.cp(file, File.join(destdir, basedir))
235
+ debug("Copy #{file} to the temporary directory.")
236
+ FileUtils.cp(file, File.join(destdir, basedir), preserve: true)
264
237
  end
265
238
  else
266
239
  recursive_copy_files(resdir, destdir, allow_exts)
@@ -269,6 +242,7 @@ module ReVIEW
269
242
 
270
243
  def copy_resources(resdir, destdir, allow_exts = nil)
271
244
  return nil unless File.exist?(resdir)
245
+
272
246
  allow_exts ||= @config['image_ext']
273
247
  FileUtils.mkdir_p(destdir)
274
248
  recursive_copy_files(resdir, destdir, allow_exts)
@@ -278,12 +252,13 @@ module ReVIEW
278
252
  Dir.open(resdir) do |dir|
279
253
  dir.each do |fname|
280
254
  next if fname.start_with?('.')
255
+
281
256
  if FileTest.directory?(File.join(resdir, fname))
282
257
  recursive_copy_files(File.join(resdir, fname), File.join(destdir, fname), allow_exts)
283
258
  elsif fname =~ /\.(#{allow_exts.join('|')})\Z/i
284
259
  FileUtils.mkdir_p(destdir)
285
- log("Copy #{resdir}/#{fname} to the temporary directory.")
286
- FileUtils.cp(File.join(resdir, fname), destdir)
260
+ debug("Copy #{resdir}/#{fname} to the temporary directory.")
261
+ FileUtils.cp(File.join(resdir, fname), destdir, preserve: true)
287
262
  end
288
263
  end
289
264
  end
@@ -292,8 +267,7 @@ module ReVIEW
292
267
  def check_compile_status
293
268
  return unless @compile_errors
294
269
 
295
- $stderr.puts 'compile error, No EPUB file output.'
296
- exit 1
270
+ error! 'compile error, No EPUB file output.'
297
271
  end
298
272
 
299
273
  def build_body(basetmpdir, yamlfile)
@@ -307,9 +281,8 @@ module ReVIEW
307
281
 
308
282
  basedir = File.dirname(yamlfile)
309
283
  base_path = Pathname.new(basedir)
310
- book = ReVIEW::Book.load(basedir)
311
- book.config = @config
312
- @converter = ReVIEW::Converter.new(book, ReVIEW::HTMLBuilder.new)
284
+ book = ReVIEW::Book::Base.new(basedir, config: @config)
285
+ @converter = ReVIEW::Converter.new(book, ReVIEW::HTMLBuilder.new(img_math: @img_math))
313
286
  @compile_errors = nil
314
287
 
315
288
  book.parts.each do |part|
@@ -336,21 +309,15 @@ module ReVIEW
336
309
  end
337
310
 
338
311
  def build_part(part, basetmpdir, htmlfile)
339
- log("Create #{htmlfile} from a template.")
312
+ debug("Create #{htmlfile} from a template.")
340
313
  File.open(File.join(basetmpdir, htmlfile), 'w') do |f|
341
- @body = ''
342
- @body << %Q(<div class="part">\n)
343
- @body << %Q(<h1 class="part-number">#{CGI.escapeHTML(ReVIEW::I18n.t('part', part.number))}</h1>\n)
344
- if part.name.strip.present?
345
- @body << %Q(<h2 class="part-title">#{CGI.escapeHTML(part.name.strip)}</h2>\n)
346
- end
347
- @body << %Q(</div>\n)
314
+ @part_number = part.number
315
+ @part_title = part.name.strip
316
+ @body = ReVIEW::Template.generate(path: 'html/_part_body.html.erb', binding: binding)
348
317
 
349
318
  @language = @producer.config['language']
350
319
  @stylesheets = @producer.config['stylesheet']
351
- tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
352
- tmpl = ReVIEW::Template.load(tmplfile)
353
- f.write tmpl.result(binding)
320
+ f.write ReVIEW::Template.generate(path: template_name, binding: binding)
354
321
  end
355
322
  end
356
323
 
@@ -403,7 +370,7 @@ module ReVIEW
403
370
 
404
371
  htmlfile = "#{id}.#{@config['htmlext']}"
405
372
  write_buildlogtxt(basetmpdir, htmlfile, filename)
406
- log("Create #{htmlfile} from #{filename}.")
373
+ debug("Create #{htmlfile} from #{filename}.")
407
374
 
408
375
  if @config['params'].present?
409
376
  warn %Q('params:' in config.yml is obsoleted.)
@@ -417,8 +384,8 @@ module ReVIEW
417
384
  remove_hidden_title(basetmpdir, htmlfile)
418
385
  rescue => e
419
386
  @compile_errors = true
420
- warn "compile error in #{filename} (#{e.class})"
421
- warn e.message
387
+ error "compile error in #{filename} (#{e.class})"
388
+ error e.message
422
389
  end
423
390
  end
424
391
 
@@ -447,12 +414,19 @@ module ReVIEW
447
414
  properties
448
415
  end
449
416
 
450
- def write_info_body(basetmpdir, _id, filename, ispart = nil, chaptype = nil)
417
+ def parse_headlines(path)
451
418
  headlines = []
419
+
420
+ File.open(path) do |htmlio|
421
+ REXML::Document.parse_stream(htmlio, ReVIEWHeaderListener.new(headlines))
422
+ end
423
+
424
+ headlines
425
+ end
426
+
427
+ def write_info_body(basetmpdir, _id, filename, ispart = nil, chaptype = nil)
452
428
  path = File.join(basetmpdir, filename)
453
- htmlio = File.new(path)
454
- Document.parse_stream(htmlio, ReVIEWHeaderListener.new(headlines))
455
- htmlio.close
429
+ headlines = parse_headlines(path)
456
430
 
457
431
  if headlines.empty?
458
432
  warn "#{filename} is discarded because there is no heading. Use `=[notoc]' or `=[nodisp]' to exclude headlines from the table of contents."
@@ -491,70 +465,77 @@ module ReVIEW
491
465
  def push_contents(_basetmpdir)
492
466
  @htmltoc.each_item do |level, file, title, args|
493
467
  next if level.to_i > @config['toclevel'] && args[:force_include].nil?
494
- log("Push #{file} to ePUB contents.")
495
468
 
496
- hash = { 'file' => file,
497
- 'level' => level.to_i,
498
- 'title' => title,
499
- 'chaptype' => args[:chaptype] }
469
+ debug("Push #{file} to ePUB contents.")
470
+
471
+ params = { file: file,
472
+ level: level.to_i,
473
+ title: title,
474
+ chaptype: args[:chaptype] }
500
475
  if args[:id].present?
501
- hash['id'] = args[:id]
476
+ params[:id] = args[:id]
502
477
  end
503
478
  if args[:properties].present?
504
- hash['properties'] = args[:properties].split(' ')
479
+ params[:properties] = args[:properties].split(' ') # rubocop:disable Style/RedundantArgument
505
480
  end
506
481
  if args[:notoc].present?
507
- hash['notoc'] = args[:notoc]
482
+ params[:notoc] = args[:notoc]
508
483
  end
509
- @producer.contents.push(Content.new(hash))
484
+ @producer.contents.push(ReVIEW::EPUBMaker::Content.new(**params))
510
485
  end
511
486
  end
512
487
 
513
488
  def copy_stylesheet(basetmpdir)
514
489
  return if @config['stylesheet'].empty?
490
+
515
491
  @config['stylesheet'].each do |sfile|
516
492
  unless File.exist?(sfile)
517
- error "#{sfile} is not found."
493
+ error! "stylesheet: #{sfile} is not found."
518
494
  end
519
- FileUtils.cp(sfile, basetmpdir)
520
- @producer.contents.push(Content.new('file' => sfile))
495
+ FileUtils.cp(sfile, basetmpdir, preserve: true)
496
+ @producer.contents.push(ReVIEW::EPUBMaker::Content.new(file: sfile))
521
497
  end
522
498
  end
523
499
 
500
+ def copy_static_file(configname, destdir, destfilename: nil)
501
+ destfilename ||= @config[configname]
502
+ unless File.exist?(@config[configname])
503
+ error! "#{configname}: #{@config[configname]} is not found."
504
+ end
505
+ FileUtils.cp(@config[configname],
506
+ File.join(destdir, destfilename), preserve: true)
507
+ end
508
+
524
509
  def copy_frontmatter(basetmpdir)
525
510
  if @config['cover'].present? && File.exist?(@config['cover'])
526
- FileUtils.cp(@config['cover'],
527
- File.join(basetmpdir, File.basename(@config['cover'])))
511
+ copy_static_file('cover', basetmpdir)
528
512
  end
529
513
 
530
514
  if @config['titlepage']
531
515
  if @config['titlefile'].nil?
532
516
  build_titlepage(basetmpdir, "titlepage.#{@config['htmlext']}")
533
517
  else
534
- FileUtils.cp(@config['titlefile'],
535
- File.join(basetmpdir, "titlepage.#{@config['htmlext']}"))
518
+ copy_static_file('titlefile', basetmpdir, destfilename: "titlepage.#{@config['htmlext']}")
536
519
  end
537
520
  @htmltoc.add_item(1,
538
521
  "titlepage.#{@config['htmlext']}",
539
- @producer.res.v('titlepagetitle'),
522
+ ReVIEW::I18n.t('titlepagetitle'),
540
523
  chaptype: 'pre')
541
524
  end
542
525
 
543
- if @config['originaltitlefile'].present? && File.exist?(@config['originaltitlefile'])
544
- FileUtils.cp(@config['originaltitlefile'],
545
- File.join(basetmpdir, File.basename(@config['originaltitlefile'])))
526
+ if @config['originaltitlefile'].present?
527
+ copy_static_file('originaltitlefile', basetmpdir)
546
528
  @htmltoc.add_item(1,
547
529
  File.basename(@config['originaltitlefile']),
548
- @producer.res.v('originaltitle'),
530
+ ReVIEW::I18n.t('originaltitle'),
549
531
  chaptype: 'pre')
550
532
  end
551
533
 
552
- if @config['creditfile'].present? && File.exist?(@config['creditfile'])
553
- FileUtils.cp(@config['creditfile'],
554
- File.join(basetmpdir, File.basename(@config['creditfile'])))
534
+ if @config['creditfile'].present?
535
+ copy_static_file('creditfile', basetmpdir)
555
536
  @htmltoc.add_item(1,
556
537
  File.basename(@config['creditfile']),
557
- @producer.res.v('credittitle'),
538
+ ReVIEW::I18n.t('credittitle'),
558
539
  chaptype: 'pre')
559
540
  end
560
541
 
@@ -563,71 +544,60 @@ module ReVIEW
563
544
 
564
545
  def build_titlepage(basetmpdir, htmlfile)
565
546
  # TODO: should be created via epubcommon
566
- @title = CGI.escapeHTML(@config.name_of('booktitle'))
547
+ @title = h(@config.name_of('booktitle'))
567
548
  File.open(File.join(basetmpdir, htmlfile), 'w') do |f|
568
549
  @body = ''
569
550
  @body << %Q(<div class="titlepage">\n)
570
- @body << %Q(<h1 class="tp-title">#{CGI.escapeHTML(@config.name_of('booktitle'))}</h1>\n)
551
+ @body << %Q(<h1 class="tp-title">#{h(@config.name_of('booktitle'))}</h1>\n)
571
552
  if @config['subtitle']
572
- @body << %Q(<h2 class="tp-subtitle">#{CGI.escapeHTML(@config.name_of('subtitle'))}</h2>\n)
553
+ @body << %Q(<h2 class="tp-subtitle">#{h(@config.name_of('subtitle'))}</h2>\n)
573
554
  end
574
555
  if @config['aut']
575
- @body << %Q(<h2 class="tp-author">#{CGI.escapeHTML(@config.names_of('aut').join(ReVIEW::I18n.t('names_splitter')))}</h2>\n)
556
+ @body << %Q(<h2 class="tp-author">#{h(@config.names_of('aut').join(ReVIEW::I18n.t('names_splitter')))}</h2>\n)
576
557
  end
577
558
  if @config['pbl']
578
- @body << %Q(<h3 class="tp-publisher">#{CGI.escapeHTML(@config.names_of('pbl').join(ReVIEW::I18n.t('names_splitter')))}</h3>\n)
559
+ @body << %Q(<h3 class="tp-publisher">#{h(@config.names_of('pbl').join(ReVIEW::I18n.t('names_splitter')))}</h3>\n)
579
560
  end
580
561
  @body << '</div>'
581
562
 
582
563
  @language = @producer.config['language']
583
564
  @stylesheets = @producer.config['stylesheet']
584
- tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
585
- tmpl = ReVIEW::Template.load(tmplfile)
586
- f.write tmpl.result(binding)
565
+ f.write ReVIEW::Template.generate(path: template_name, binding: binding)
587
566
  end
588
567
  end
589
568
 
590
569
  def copy_backmatter(basetmpdir)
591
570
  if @config['profile']
592
- FileUtils.cp(@config['profile'],
593
- File.join(basetmpdir, File.basename(@config['profile'])))
571
+ copy_static_file('profile', basetmpdir)
594
572
  @htmltoc.add_item(1,
595
573
  File.basename(@config['profile']),
596
- @producer.res.v('profiletitle'),
574
+ ReVIEW::I18n.t('profiletitle'),
597
575
  chaptype: 'post')
598
576
  end
599
577
 
600
578
  if @config['advfile']
601
- FileUtils.cp(@config['advfile'],
602
- File.join(basetmpdir, File.basename(@config['advfile'])))
579
+ copy_static_file('advfile', basetmpdir)
603
580
  @htmltoc.add_item(1,
604
581
  File.basename(@config['advfile']),
605
- @producer.res.v('advtitle'),
582
+ ReVIEW::I18n.t('advtitle'),
606
583
  chaptype: 'post')
607
584
  end
608
585
 
609
586
  if @config['colophon']
610
- if @config['colophon'].is_a?(String) # FIXME: should let obsolete this style?
611
- FileUtils.cp(@config['colophon'],
612
- File.join(basetmpdir, "colophon.#{@config['htmlext']}"))
613
- else
614
- filename = File.join(basetmpdir, "colophon.#{@config['htmlext']}")
615
- File.open(filename, 'w') do |f|
616
- @producer.colophon(f)
617
- end
587
+ if @config['colophon'].is_a?(String)
588
+ copy_static_file('colophon', basetmpdir, destfilename: "colophon.#{@config['htmlext']}") # override pre-built colophon
618
589
  end
619
590
  @htmltoc.add_item(1,
620
591
  "colophon.#{@config['htmlext']}",
621
- @producer.res.v('colophontitle'),
592
+ ReVIEW::I18n.t('colophontitle'),
622
593
  chaptype: 'post')
623
594
  end
624
595
 
625
596
  if @config['backcover']
626
- FileUtils.cp(@config['backcover'],
627
- File.join(basetmpdir, File.basename(@config['backcover'])))
597
+ copy_static_file('backcover', basetmpdir)
628
598
  @htmltoc.add_item(1,
629
599
  File.basename(@config['backcover']),
630
- @producer.res.v('backcovertitle'),
600
+ ReVIEW::I18n.t('backcovertitle'),
631
601
  chaptype: 'post')
632
602
  end
633
603
 
@@ -653,8 +623,10 @@ module ReVIEW
653
623
  extre = Regexp.new(pat, Regexp::IGNORECASE)
654
624
  Find.find(basetmpdir) do |fname|
655
625
  next unless fname.match(extre)
626
+
656
627
  img = ImageSize.path(fname)
657
628
  next if img.width.nil? || img.width * img.height <= maxpixels
629
+
658
630
  h = Math.sqrt(img.height * maxpixels / img.width)
659
631
  w = maxpixels / h
660
632
  fname.sub!("#{basetmpdir}/", '')