Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

imgmathの挙動拡張 #1138

Merged
merged 8 commits into from
Oct 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ Metrics/AbcSize:
### shoud be < 25
Metrics/BlockLength:
CountComments: false # count full line comments?
Max: 50
Max: 62
Exclude:
- 'Rakefile'
- '**/*.rake'
Expand Down
98 changes: 96 additions & 2 deletions doc/format.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,9 +573,103 @@ LaTeX の式を挿入するには、`//texequation{ 〜 //}` を使います。
//}
```

インライン命令では `@<m>{〜}` を使います。インライン命令の式中に「}」を含む場合、`\}` とエスケープする必要があることに注意してください(`{` はエスケープ不要)。
インライン命令では `@<m>{〜}` を使います。インライン命令の式中に「}」を含む場合、`\}` とエスケープする必要があることに注意してください(`{` はエスケープ不要)。「インライン命令のフェンス記法」も参照してください。

LaTeX の数式が正常に整形されるかどうかは処理系に依存します。たとえば TeX PDF であれば問題なく利用できるでしょうが、EPUB では MathML 変換を有効にしても妥当な結果にならないことがあります。確実を期すならば、画像で表現するほうが適切です。
LaTeX の数式が正常に整形されるかどうかは処理系に依存します。LaTeX を利用する PDFMaker では問題なく利用できます。

EPUBMaker および WEBMaker では、MathML に変換する方法と、画像化する方法のどちらかを選べます。

### MathML の場合
MathML ライブラリをインストールしておきます(`gem install math_ml`)。

さらに config.yml に以下のように指定します。

```
mathml: true
```

なお、MathML で正常に表現されるかどうかは、ビューアやブラウザに依存します。

### 画像化の場合

LaTeX を内部で呼び出し、外部ツールを使って画像化する方法です。画像化された数式は、`images/_review_math` フォルダに配置されます。

TeXLive などの LaTeX 環境が必要です。必要に応じて config.yml の `texcommand`、`texoptions`、`dvicommand`、`dvioptions` のパラメータを調整します。

さらに、画像化するための外部ツールも用意します。現在、以下の2つのやり方をサポートしています。

- `pdfcrop`:TeXLive に収録されている `pdfcrop` コマンドを使用して数式部分を切り出し、さらに PDF から画像化します。デフォルトでは画像化には Poppler ライブラリに収録されている `pdftocairo` コマンドを使用します(コマンドラインで利用可能であれば、別のツールに変更することもできます)。
- `dvipng`:[dvipng](https://ctan.org/pkg/dvipng) を使用します。OS のパッケージまたは `tlmgr install dvipng` でインストールできます。数式中に日本語は使えません。

config.yml で以下のように設定すると、

```
imgmath: true
```

デフォルト値として以下が使われます。

```
imgmath_options:
# 使用する画像拡張子。通常は「png」か「svg」(svgの場合は、pdfcrop_pixelize_cmdの-pngも-svgにする)
format: png
# 変換手法。pdfcrop または dvipng
converter: pdfcrop
# プリアンブルの内容を上書きするファイルを指定する(デフォルトはupLaTeX+jsarticle.clsを前提とした、lib/review/makerhelper.rbのdefault_imgmath_preambleメソッドの内容)
preamble_file: null
# 基準のフォントサイズ
fontsize: 10
# 基準の行間
lineheight: 12
# pdfcropコマンドのコマンドライン。プレースホルダは
# %i: 入力ファイル、%o: 出力ファイル
pdfcrop_cmd: "pdfcrop --hires %i %o"
# PDFから画像化するコマンドのコマンドライン。プレースホルダは
# %i: 入力ファイル、%o: 出力ファイル、%O: 出力ファイルから拡張子を除いたもの
# %p: 対象ページ番号
pdfcrop_pixelize_cmd: "pdftocairo -png -r 90 -f %p -l %p -singlefile %i %O"
# pdfcrop_pixelize_cmdが複数ページの処理に対応していない場合に単ページ化するか
extract_singlepage: null
# 単ページ化するコマンドのコマンドライン
pdfextract_cmd: "pdfjam -q --outfile %o %i %p"
# dvipngコマンドのコマンドライン
dvipng_cmd: "dvipng -T tight -z 9 -p %p -l %p -o %o %i"
```

たとえば SVG を利用するには、次のようにします。

```
imgmath: true
imgmath_options:
format: svg
pdfcrop_pixelize_cmd: "pdftocairo -svg -r 90 -f %p -l %p -singlefile %i %o"
```

デフォルトでは、pdfcrop_pixelize_cmd に指定するコマンドは、1ページあたり1数式からなる複数ページの PDF のファイル名を `%i` プレースホルダで受け取り、`%p` プレースホルダのページ数に基づいて `%o`(拡張子あり)または `%O`(拡張子なし)の画像ファイルに書き出す、という仕組みになっています。

単一のページの処理を前提とする `sips` コマンドや `magick` コマンドを使う場合、入力 PDF から指定のページを抽出するように `extract_singlepage: true` として挙動を変更します。単一ページの抽出はデフォルトで TeXLive の `pdfjam` コマンドが使われます。

```
imgmath: true
imgmath_options:
extract_singlepage: true
# pdfjamの代わりに外部ツールのpdftkを使う場合(Windowsなど)
pdfextract_cmd: "pdftk A=%i cat A%p output %o"
# ImageMagickを利用する例
pdfcrop_pixelize_cmd: "magick -density 200x200 %i %o"
# sipsを利用する例
pdfcrop_pixelize_cmd: "sips -s format png --out %o %i"
```

Re:VIEW 2 以前の dvipng の設定に合わせるには、次のようにします。

```
imgmath: true
imgmath_options:
converter: dvipng
fontsize: 12
lineheight: 14.3
```

## 字下げの制御

Expand Down
99 changes: 98 additions & 1 deletion doc/format.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,6 @@ The rule of finding images is same as image command.
//}
```


## Quoting Text

You can use `//quote{ ... //}` as quotations.
Expand Down Expand Up @@ -618,6 +617,104 @@ Usage:
//}
```

There is `@<m>{ ... }` for inline (see "Fence notation for inline commands" section also).

Whether LaTeX formula is correctly displayed or not depends on the processing system. PDFMaker uses LaTeX internally, so there is no problem.

EPUBMaker and WEBMaker use either MathML transformation or imaging.

### MathML case
Install MathML library (`gem install math_ml`).

Specify in config.yml as follows:

```
mathml: true
```

Whether it is displayed properly in MathML depends on your viewer or browser.

### imaging case

This way calls LaTeX internally and images it with an external tool. Image files will be placed in `images/_review_math` folder.

You need TeXLive or other LaTeX environment. Modify the parameters of `texcommand`,` texoptions`, `dvicommand`,` dvioptions` in config.yml as necessary.

In addition, external tools for image conversion are also needed. Currently, it supports the following two methods.

- `pdfcrop`: cut out the formula using `pdfcrop` command (included in TeXLive) and image it. By default, `pdftocairo` command is used (included in Poppler library). You can change it to another tool if available on the command line.
- `dvipng`: it uses [dvipng](https://ctan.org/pkg/dvipng) to cut out and to image. You can install with OS package or `tlmgr install dvipng`.

By setting in config.yml,

```
imgmath: true
```

it is set as follows:

```
imgmath_options:
# format. png|svg
format: png
# conversion method. pdfcrop|dvipng
converter: pdfcrop
# custom preamble file (default: for upLaTeX+jsarticle.cls, see lib/review/makerhelper.rb#default_imgmath_preamble)
preamble_file: null
# default font size
fontsize: 10
# default line height
lineheight: 12
# pdfcrop command.
# %i: filename for input %o: filename for output
pdfcrop_cmd: "pdfcrop --hires %i %o"
# imaging command.
# %i: filename for input %o: filename for output %O: filename for output without the extension
# %p: page number
pdfcrop_pixelize_cmd: "pdftocairo -png -r 90 -f %p -l %p -singlefile %i %O"
# whether to generate a single PDF page for pdfcrop_pixelize_cmd.
extract_singlepage: null
# command line to generate a single PDF page file.
pdfextract_cmd: "pdfjam -q --outfile %o %i %p"
# dvipng command.
dvipng_cmd: "dvipng -T tight -z 9 -p %p -l %p -o %o %i"
```

For example, to make SVG:

```
imgmath: true
imgmath_options:
format: svg
pdfcrop_pixelize_cmd: "pdftocairo -svg -r 90 -f %p -l %p -singlefile %i %o"
```

By default, the command specified in `pdfcrop_pixelize_cmd` takes the filename of multi-page PDF consisting of one formula per page.

If you want to use the `sips` command or the` magick` command, they can only process a single page, so you need to set `extract_singlepage: true` to extract the specified page from the input PDF. `pdfjam` command (in TeXLive) is used to extract pages.

```
imgmath: true
imgmath_options:
extract_singlepage: true
# use pdftk instead of default pdfjam (for Windows)
pdfextract_cmd: "pdftk A=%i cat A%p output %o"
# use ImageMagick
pdfcrop_pixelize_cmd: "magick -density 200x200 %i %o"
# use sips
pdfcrop_pixelize_cmd: "sips -s format png --out %o %i"
```

To set the same setting as Re:VIEW 2:

```
imgmath: true
imgmath_options:
converter: dvipng
fontsize: 12
lineheight: 14.3
```

## Spacing

`//noindent` is a tag for spacing.
Expand Down
12 changes: 12 additions & 0 deletions lib/review/configure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ def self.values
'makeindex_dic' => nil,
'makeindex_mecab' => true,
'makeindex_mecab_opts' => '-Oyomi'
},
'imgmath_options' => {
'format' => 'png',
'converter' => 'pdfcrop', # dvipng | pdfcrop
'pdfcrop_cmd' => 'pdfcrop --hires %i %o',
'extract_singlepage' => nil,
'pdfextract_cmd' => 'pdfjam -q --outfile %o %i %p',
'preamble_file' => nil,
'fontsize' => 10,
'lineheight' => 10 * 1.2,
'pdfcrop_pixelize_cmd' => 'pdftocairo -png -r 90 -f %p -l %p -singlefile %i %O',
'dvipng_cmd' => 'dvipng -T tight -z 9 -p %p -l %p -o %o %i'
}
]
conf.maker = nil
Expand Down
14 changes: 10 additions & 4 deletions lib/review/epubmaker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
require 'rexml/streamlistener'
require 'epubmaker'
require 'review/epubmaker/reviewheaderlistener'
require 'review/makerhelper'

module ReVIEW
class EPUBMaker
include ::EPUBMaker
include REXML
include MakerHelper

def initialize
@producer = nil
Expand Down Expand Up @@ -103,10 +105,8 @@ def produce(yamlfile, bookname = nil)
if @config['debug']
FileUtils.rm_rf(booktmpname)
end
math_dir = "./#{@config['imagedir']}/_review_math"
if @config['imgmath'] && Dir.exist?(math_dir)
FileUtils.rm_rf(math_dir)
end

cleanup_mathimg

basetmpdir = build_path
begin
Expand All @@ -125,6 +125,11 @@ def produce(yamlfile, bookname = nil)
call_hook('hook_afterbody', basetmpdir)

copy_backmatter(basetmpdir)

math_dir = "./#{@config['imagedir']}/_review_math"
if @config['imgmath'] && File.exist?("#{math_dir}/__IMGMATH_BODY__.tex")
make_math_images(math_dir)
end
call_hook('hook_afterbackmatter', basetmpdir)

## push contents in basetmpdir into @producer
Expand Down Expand Up @@ -267,6 +272,7 @@ def build_body(basetmpdir, yamlfile)
book.config = @config
@converter = ReVIEW::Converter.new(book, ReVIEW::HTMLBuilder.new)
@compile_errors = nil

book.parts.each do |part|
if part.name.present?
if part.file?
Expand Down
40 changes: 31 additions & 9 deletions lib/review/htmlbuilder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,19 @@ def texequation(lines)
elsif @book.config['imgmath']
math_str = "\\begin{equation*}\n" + unescape(lines.join("\n")) + "\n\\end{equation*}\n"
key = Digest::SHA256.hexdigest(math_str)
math_dir = "./#{@book.config['imagedir']}/_review_math"
math_dir = File.join(@book.config['imagedir'], '_review_math')
Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
img_path = "./#{math_dir}/_gen_#{key}.png"
make_math_image(math_str, img_path)
puts %Q(<img src="#{img_path}" />)
img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
if @book.config.check_version('2', exception: false)
make_math_image(math_str, img_path)
puts %Q(<img src="#{img_path}" />)
else
defer_math_image(math_str, img_path, key)
puts %Q(<img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(lines.join(' '))}" />)
end
else
print '<pre>'
puts lines.join("\n")
puts escape(lines.join("\n"))
puts '</pre>'
end
puts '</div>'
Expand Down Expand Up @@ -924,11 +929,16 @@ def inline_m(str)
elsif @book.config['imgmath']
math_str = '$' + str + '$'
key = Digest::SHA256.hexdigest(str)
math_dir = "./#{@book.config['imagedir']}/_review_math"
math_dir = File.join(@book.config['imagedir'], '_review_math')
Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
img_path = "./#{math_dir}/_gen_#{key}.png"
make_math_image(math_str, img_path)
%Q(<span class="equation"><img src="#{img_path}" /></span>)
img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
if @book.config.check_version('2', exception: false)
make_math_image(math_str, img_path)
%Q(<span class="equation"><img src="#{img_path}" /></span>)
else
defer_math_image(math_str, img_path, key)
%Q(<span class="equation"><img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(str)}" /></span>)
end
else
%Q(<span class="equation">#{escape(str)}</span>)
end
Expand Down Expand Up @@ -1192,7 +1202,19 @@ def olnum(num)
@ol_num = num.to_i
end

def defer_math_image(str, path, key)
# for Re:VIEW >3
File.open(File.join(File.dirname(path), '__IMGMATH_BODY__.tex'), 'a+') do |f|
f.puts str
f.puts '\\clearpage'
end
File.open(File.join(File.dirname(path), '__IMGMATH_BODY__.map'), 'a+') do |f|
f.puts key
end
end

def make_math_image(str, path, fontsize = 12)
# Re:VIEW 2 compatibility
fontsize2 = (fontsize * 1.2).round.to_i
texsrc = <<-EOB
\\documentclass[12pt]{article}
Expand Down
Loading