asciidoctor-pdf-mathjax 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 953f3afce27ff482bfcae64ac333e262c1282f6c50d0bdb8317064f3d60b888d
4
- data.tar.gz: ea179ece644755ef9834f2ed4da39b21008917004b2d6ff7f2cbbca82495e6c8
3
+ metadata.gz: 3fc66d0f0c7026c39d6363d44464ad9c5f430aed3202b344de302604679d3166
4
+ data.tar.gz: 62009314bb1e5e72e759e2251ce7eaa7ffc14bb123a365a9c0f88dcc58d04bac
5
5
  SHA512:
6
- metadata.gz: c671beb46e4bd786b0deceb6af5108430b9417ff1ea4a585b83efb3c77910bffe6b3b1384a47fa7e876708be13485ae7521b43b50dcf64155c748b4cf814a28b
7
- data.tar.gz: 2d76424a66dc155b0078f1b91ba327e2b19f89a41de049c834dc90bf0af5f5609420a193492433d043b1f92e0fd57cc2d0b3c155e18e13808150e4cfba27d9e3
6
+ metadata.gz: 5234f95491bf7ec6320942e21c009f77575567a4312b1651e13736f19b1cb85d8eeee8cd9b3e443e483628c0b1e7d18847384cb98e9b4cab5efafb539973bcc8
7
+ data.tar.gz: 7e89244f2911bc889e4f2a3cdd2d34fc31fde201bacac64a0d995ddcbfbd14afe367e98c20922c828ce80bed93e0e05877cd2dbfb81fd655adda92e5c396a6e0
data/bin/render.js CHANGED
@@ -2,10 +2,17 @@
2
2
 
3
3
  const mj = require('mathjax-node');
4
4
 
5
- const latex = process.argv[2];
6
- const format = process.argv[3];
7
- const pixels_per_ex = parseInt(process.argv[4]);
8
- const font = process.argv[5];
5
+ // Two modes:
6
+ // render.js <latex> <format> <pixels_per_ex> <font>
7
+ // renders one formula, prints the SVG and exits.
8
+ // render.js --server <font>
9
+ // starts MathJax once and renders one formula per line of stdin,
10
+ // {"math": "...", "format": "TeX", "ex": 6}, answering with one line
11
+ // per formula, {"svg": "..."} or {"error": "..."}.
12
+ // Starting MathJax takes seconds; the server mode pays that once per font
13
+ // instead of once per formula.
14
+ const server = process.argv[2] === '--server';
15
+ const font = server ? process.argv[3] : process.argv[5];
9
16
 
10
17
  mj.config({
11
18
  MathJax: {
@@ -26,6 +33,26 @@ async function convertToSvg(latex, format, pixels_per_ex) {
26
33
  return data.svg;
27
34
  }
28
35
 
29
- convertToSvg(latex, format, pixels_per_ex).then(svg => {
30
- console.log(svg);
31
- }).catch(err => console.error(err));
36
+ if (server) {
37
+ let queue = Promise.resolve();
38
+ require('readline').createInterface({ input: process.stdin }).on('line', line => {
39
+ queue = queue.then(async () => {
40
+ let answer;
41
+ try {
42
+ const request = JSON.parse(line);
43
+ answer = { svg: await convertToSvg(request.math, request.format, request.ex) };
44
+ } catch (err) {
45
+ answer = { error: String(err) };
46
+ }
47
+ process.stdout.write(JSON.stringify(answer) + '\n');
48
+ });
49
+ });
50
+ } else {
51
+ const latex = process.argv[2];
52
+ const format = process.argv[3];
53
+ const pixels_per_ex = parseInt(process.argv[4]);
54
+
55
+ convertToSvg(latex, format, pixels_per_ex).then(svg => {
56
+ console.log(svg);
57
+ }).catch(err => console.error(err));
58
+ }
@@ -1,5 +1,6 @@
1
1
  require 'asciidoctor-pdf' unless Asciidoctor::Converter.for 'pdf'
2
2
  require 'open3'
3
+ require 'json'
3
4
  require 'tempfile'
4
5
  require 'rexml/document'
5
6
  require 'ttfunk'
@@ -97,7 +98,7 @@ class AsciidoctorPDFExtensions < (Asciidoctor::Converter.for 'pdf')
97
98
  tmp_svg.close
98
99
 
99
100
  logger.debug "Successfully embedded stem inline #{node.text} with font #{math_font} as SVG image"
100
- quoted_text = "<img src=\"#{tmp_svg.path}\" format=\"svg\" width=\"#{svg_width}\" alt=\"#{node.text}\">"
101
+ quoted_text = "<img src=\"#{tmp_svg.path}\" format=\"svg\" width=\"#{svg_width}\" alt=\"#{node.text.gsub('"', '&quot;')}\">"
101
102
  node.id ? %(<a id="#{node.id}">#{DummyText}</a>#{quoted_text}) : quoted_text
102
103
  rescue => e
103
104
  logger.warn "Failed to process SVG: #{e.message}"
@@ -124,19 +125,62 @@ class AsciidoctorPDFExtensions < (Asciidoctor::Converter.for 'pdf')
124
125
  end
125
126
 
126
127
  def stem_to_svg(latex_content, is_inline, math_font)
127
- js_script = File.join(File.dirname(__FILE__), '../bin/render.js')
128
- svg_output, error = nil, nil
129
128
  format = is_inline ? 'inline-TeX' : 'TeX'
130
- begin
131
- Open3.popen3('node', js_script, latex_content, format, POINTS_PER_EX.to_s, math_font) do |_, stdout, stderr, wait_thr|
132
- svg_output = stdout.read
133
- error = stderr.read unless wait_thr.value.success?
134
- end
129
+ MathJaxServer.for(math_font).render(latex_content, format)
130
+ end
131
+
132
+ # One long-running render.js process per math font. Starting node and MathJax takes
133
+ # seconds, rendering a formula takes milliseconds, so a document pays the start once.
134
+ class MathJaxServer
135
+ JS_SCRIPT = File.join(File.dirname(__FILE__), '../bin/render.js')
136
+
137
+ @servers = {}
138
+
139
+ def self.for(math_font)
140
+ @servers[math_font] ||= new(math_font)
141
+ end
142
+
143
+ def initialize(math_font)
144
+ @math_font = math_font
145
+ end
146
+
147
+ def render(latex_content, format)
148
+ start unless @stdin
149
+ @stdin.puts JSON.generate('math' => latex_content, 'format' => format, 'ex' => POINTS_PER_EX)
150
+ @stdin.flush
151
+ answer = read_answer
152
+ [answer['svg'], answer['error']]
135
153
  rescue Errno::ENOENT => e
136
- error = "Node.js executable 'node' was not found. Please install Node.js and ensure 'node' is available on your PATH. Original error: #{e.message}"
137
- svg_output = nil
154
+ [nil, "Node.js executable 'node' was not found. Please install Node.js and ensure 'node' is available on your PATH. Original error: #{e.message}"]
155
+ rescue IOError, SystemCallError => e
156
+ stop
157
+ [nil, "MathJax process for font #{@math_font} failed: #{e.message}"]
158
+ end
159
+
160
+ private
161
+
162
+ def start
163
+ @stdin, @stdout, @wait_thr = Open3.popen2('node', JS_SCRIPT, '--server', @math_font)
164
+ at_exit { stop }
165
+ end
166
+
167
+ # Skips anything else a dependency may print to stdout.
168
+ def read_answer
169
+ while (line = @stdout.gets)
170
+ answer = JSON.parse(line) rescue nil
171
+ return answer if answer.is_a?(Hash) && (answer.key?('svg') || answer.key?('error'))
172
+ end
173
+ raise IOError, 'render.js ended without an answer'
174
+ end
175
+
176
+ def stop
177
+ return unless @stdin
178
+ @stdin.close unless @stdin.closed?
179
+ Process.kill('KILL', @wait_thr.pid) unless @wait_thr.join(5)
180
+ @stdin = @stdout = @wait_thr = nil
181
+ rescue SystemCallError
182
+ @stdin = @stdout = @wait_thr = nil
138
183
  end
139
- [svg_output, error]
140
184
  end
141
185
 
142
186
  def adjust_svg_to_match_text(svg_content, font)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-pdf-mathjax
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Crown0815