isodoc 1.7.4 → 1.7.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,129 +1,139 @@
1
1
  require "fileutils"
2
2
  require "base64"
3
3
 
4
- module IsoDoc::HtmlFunction
5
- module Html
6
- def convert1(docxml, filename, dir)
7
- noko do |xml|
8
- xml.html **{ lang: @lang.to_s } do |html|
9
- info docxml, nil
10
- populate_css
11
- html.head { |head| define_head head, filename, dir }
12
- make_body(html, docxml)
13
- end
14
- end.join("\n")
15
- end
4
+ module IsoDoc
5
+ module HtmlFunction
6
+ module Html
7
+ def convert1(docxml, filename, dir)
8
+ noko do |xml|
9
+ xml.html **{ lang: @lang.to_s } do |html|
10
+ info docxml, nil
11
+ populate_css
12
+ html.head { |head| define_head head, filename, dir }
13
+ make_body(html, docxml)
14
+ end
15
+ end.join("\n")
16
+ end
16
17
 
17
- def make_body1(body, _docxml)
18
- return if @bare
18
+ def make_body1(body, _docxml)
19
+ return if @bare
19
20
 
20
- body.div **{ class: "title-section" } do |div1|
21
- div1.p { |p| p << "&nbsp;" } # placeholder
21
+ body.div **{ class: "title-section" } do |div1|
22
+ div1.p { |p| p << "&nbsp;" } # placeholder
23
+ end
24
+ section_break(body)
22
25
  end
23
- section_break(body)
24
- end
25
26
 
26
- def make_body2(body, _docxml)
27
- return if @bare
27
+ def make_body2(body, _docxml)
28
+ return if @bare
28
29
 
29
- body.div **{ class: "prefatory-section" } do |div2|
30
- div2.p { |p| p << "&nbsp;" } # placeholder
30
+ body.div **{ class: "prefatory-section" } do |div2|
31
+ div2.p { |p| p << "&nbsp;" } # placeholder
32
+ end
33
+ section_break(body)
31
34
  end
32
- section_break(body)
33
- end
34
35
 
35
- def make_body3(body, docxml)
36
- body.div **{ class: "main-section" } do |div3|
37
- boilerplate docxml, div3
38
- preface_block docxml, div3
39
- abstract docxml, div3
40
- foreword docxml, div3
41
- introduction docxml, div3
42
- preface docxml, div3
43
- acknowledgements docxml, div3
44
- middle docxml, div3
45
- footnotes div3
46
- comments div3
36
+ def make_body3(body, docxml)
37
+ body.div **{ class: "main-section" } do |div3|
38
+ boilerplate docxml, div3
39
+ preface_block docxml, div3
40
+ abstract docxml, div3
41
+ foreword docxml, div3
42
+ introduction docxml, div3
43
+ preface docxml, div3
44
+ acknowledgements docxml, div3
45
+ middle docxml, div3
46
+ footnotes div3
47
+ comments div3
48
+ end
47
49
  end
48
- end
49
50
 
50
- def googlefonts
51
- <<~HEAD.freeze
52
- <link href="https://fonts.googleapis.com/css?family=Overpass:300,300i,600,900" rel="stylesheet">
53
- <link href="https://fonts.googleapis.com/css?family=Lato:400,400i,700,900" rel="stylesheet">
54
- HEAD
55
- end
51
+ def googlefonts
52
+ <<~HEAD.freeze
53
+ <link href="https://fonts.googleapis.com/css?family=Overpass:300,300i,600,900" rel="stylesheet">
54
+ <link href="https://fonts.googleapis.com/css?family=Lato:400,400i,700,900" rel="stylesheet">
55
+ HEAD
56
+ end
56
57
 
57
- def html_head
58
- <<~HEAD.freeze
59
- <title>#{@meta&.get&.dig(:doctitle)}</title>
60
- <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
61
-
62
- <!--TOC script import-->
63
- <script type="text/javascript" src="https://cdn.rawgit.com/jgallen23/toc/0.3.2/dist/toc.min.js"></script>
64
- <script type="text/javascript">#{toclevel}</script>
65
-
66
- <!--Google fonts-->
67
- <link rel="preconnect" href="https://fonts.gstatic.com">#{' '}
68
- #{googlefonts}
69
- <!--Font awesome import for the link icon-->
70
- <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/solid.css" integrity="sha384-v2Tw72dyUXeU3y4aM2Y0tBJQkGfplr39mxZqlTBDUZAb9BGoC40+rdFCG0m10lXk" crossorigin="anonymous">
71
- <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/fontawesome.css" integrity="sha384-q3jl8XQu1OpdLgGFvNRnPdj5VIlCvgsDQTQB6owSOHWlAurxul7f+JpUOVdAiJ5P" crossorigin="anonymous">
72
- <style class="anchorjs"></style>
73
- HEAD
74
- end
58
+ def html_head
59
+ <<~HEAD.freeze
60
+ <title>#{@meta&.get&.dig(:doctitle)}</title>
61
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
62
+
63
+ <!--TOC script import-->
64
+ <script type="text/javascript" src="https://cdn.rawgit.com/jgallen23/toc/0.3.2/dist/toc.min.js"></script>
65
+ <script type="text/javascript">#{toclevel}</script>
66
+
67
+ <!--Google fonts-->
68
+ <link rel="preconnect" href="https://fonts.gstatic.com">#{' '}
69
+ #{googlefonts}
70
+ <!--Font awesome import for the link icon-->
71
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/solid.css" integrity="sha384-v2Tw72dyUXeU3y4aM2Y0tBJQkGfplr39mxZqlTBDUZAb9BGoC40+rdFCG0m10lXk" crossorigin="anonymous">
72
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/fontawesome.css" integrity="sha384-q3jl8XQu1OpdLgGFvNRnPdj5VIlCvgsDQTQB6owSOHWlAurxul7f+JpUOVdAiJ5P" crossorigin="anonymous">
73
+ <style class="anchorjs"></style>
74
+ HEAD
75
+ end
75
76
 
76
- def html_button
77
- return "" if @bare
77
+ def html_button
78
+ return "" if @bare
78
79
 
79
- '<button onclick="topFunction()" id="myBtn" '\
80
+ '<button onclick="topFunction()" id="myBtn" '\
80
81
  'title="Go to top">Top</button>'.freeze
81
- end
82
+ end
82
83
 
83
- def html_main(docxml)
84
- docxml.at("//head").add_child(html_head)
85
- d = docxml.at('//div[@class="main-section"]')
86
- d.name = "main"
87
- d.children.empty? or d.children.first.previous = html_button
88
- end
84
+ def html_main(docxml)
85
+ docxml.at("//head").add_child(html_head)
86
+ d = docxml.at('//div[@class="main-section"]')
87
+ d.name = "main"
88
+ d.children.empty? or d.children.first.previous = html_button
89
+ end
89
90
 
90
- def sourcecodelang(lang)
91
- return unless lang
92
-
93
- case lang.downcase
94
- when "javascript" then "lang-js"
95
- when "c" then "lang-c"
96
- when "c+" then "lang-cpp"
97
- when "console" then "lang-bsh"
98
- when "ruby" then "lang-rb"
99
- when "html" then "lang-html"
100
- when "java" then "lang-java"
101
- when "xml" then "lang-xml"
102
- when "perl" then "lang-perl"
103
- when "python" then "lang-py"
104
- when "xsl" then "lang-xsl"
105
- else
106
- ""
91
+ def sourcecodelang(lang)
92
+ return unless lang
93
+
94
+ case lang.downcase
95
+ when "javascript" then "lang-js"
96
+ when "c" then "lang-c"
97
+ when "c+" then "lang-cpp"
98
+ when "console" then "lang-bsh"
99
+ when "ruby" then "lang-rb"
100
+ when "html" then "lang-html"
101
+ when "java" then "lang-java"
102
+ when "xml" then "lang-xml"
103
+ when "perl" then "lang-perl"
104
+ when "python" then "lang-py"
105
+ when "xsl" then "lang-xsl"
106
+ else
107
+ ""
108
+ end
107
109
  end
108
- end
109
110
 
110
- def sourcecode_parse(node, out)
111
- name = node.at(ns("./name"))
112
- class1 = "prettyprint #{sourcecodelang(node&.at(ns('./@lang'))&.value)}"
113
- out.pre **sourcecode_attrs(node).merge(class: class1) do |div|
114
- @sourcecode = true
115
- node.children.each { |n| parse(n, div) unless n.name == "name" }
116
- @sourcecode = false
111
+ def sourcecode_parse(node, out)
112
+ name = node.at(ns("./name"))
113
+ class1 = "prettyprint #{sourcecodelang(node&.at(ns('./@lang'))&.value)}"
114
+ out.pre **sourcecode_attrs(node).merge(class: class1) do |div|
115
+ @sourcecode = true
116
+ node.children.each { |n| parse(n, div) unless n.name == "name" }
117
+ @sourcecode = false
118
+ end
119
+ sourcecode_name_parse(node, out, name)
117
120
  end
118
- sourcecode_name_parse(node, out, name)
119
- end
120
121
 
121
- def underline_parse(node, out)
122
- out.span **{ style: "text-decoration: underline;" } do |e|
123
- node.children.each { |n| parse(n, e) }
122
+ def underline_parse(node, out)
123
+ out.span **{ style: "text-decoration: underline;" } do |e|
124
+ node.children.each { |n| parse(n, e) }
125
+ end
124
126
  end
125
- end
126
127
 
127
- def table_long_strings_cleanup(docxml); end
128
+ def table_long_strings_cleanup(docxml); end
129
+
130
+ def image_parse(node, out, caption)
131
+ if svg = node.at("./m:svg", "m" => "http://www.w3.org/2000/svg")
132
+ svg_parse(svg, out)
133
+ return
134
+ end
135
+ super
136
+ end
137
+ end
128
138
  end
129
139
  end
@@ -1,55 +1,24 @@
1
- require "base64"
1
+ require_relative "./image"
2
2
 
3
3
  module IsoDoc
4
4
  class PresentationXMLConvert < ::IsoDoc::Convert
5
- def lower2cap(s)
6
- return s if /^[[:upper:]][[:upper:]]/.match?(s)
5
+ def lower2cap(text)
6
+ return text if /^[[:upper:]][[:upper:]]/.match?(text)
7
7
 
8
- s.capitalize
8
+ text.capitalize
9
9
  end
10
10
 
11
- def figure(docxml)
12
- docxml.xpath(ns("//image")).each { |f| svg_extract(f) }
13
- docxml.xpath(ns("//figure")).each { |f| figure1(f) }
14
- docxml.xpath(ns("//svgmap")).each do |s|
15
- if f = s.at(ns("./figure")) then s.replace(f)
16
- else
17
- s.remove
18
- end
19
- end
20
- end
21
-
22
- def svg_extract(elem)
23
- return unless %r{^data:image/svg\+xml;base64,}.match?(elem["src"])
24
-
25
- svg = Base64.strict_decode64(elem["src"]
26
- .sub(%r{^data:image/svg\+xml;base64,}, ""))
27
- x = Nokogiri::XML.fragment(svg.sub(/<\?xml[^>]*>/, "")) do |config|
28
- config.huge
29
- end
30
- elem.replace(x)
31
- end
32
-
33
- def figure1(f)
34
- return sourcecode1(f) if f["class"] == "pseudocode" || f["type"] == "pseudocode"
35
- return if labelled_ancestor(f) && f.ancestors("figure").empty?
36
- return if f.at(ns("./figure")) and !f.at(ns("./name"))
37
-
38
- lbl = @xrefs.anchor(f['id'], :label, false) or return
39
- prefix_name(f, "&nbsp;&mdash; ",
40
- l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
41
- end
42
-
43
- def prefix_name(f, delim, number, elem)
11
+ def prefix_name(node, delim, number, elem)
44
12
  return if number.nil? || number.empty?
45
13
 
46
- unless name = f.at(ns("./#{elem}"))
47
- f.children.empty? and f.add_child("<#{elem}></#{elem}>") or
48
- f.children.first.previous = "<#{elem}></#{elem}>"
49
- name = f.children.first
14
+ unless name = node.at(ns("./#{elem}"))
15
+ node.children.empty? and node.add_child("<#{elem}></#{elem}>") or
16
+ node.children.first.previous = "<#{elem}></#{elem}>"
17
+ name = node.children.first
18
+ end
19
+ if name.children.empty? then name.add_child(number)
20
+ else (name.children.first.previous = "#{number}#{delim}")
50
21
  end
51
- name.children.empty? ? name.add_child(number) :
52
- ( name.children.first.previous = "#{number}#{delim}" )
53
22
  end
54
23
 
55
24
  def sourcecode(docxml)
@@ -58,12 +27,13 @@ module IsoDoc
58
27
  end
59
28
  end
60
29
 
61
- def sourcecode1(f)
62
- return if labelled_ancestor(f)
63
- return unless f.ancestors("example").empty?
30
+ def sourcecode1(elem)
31
+ return if labelled_ancestor(elem)
32
+ return unless elem.ancestors("example").empty?
64
33
 
65
- lbl = @xrefs.anchor(f['id'], :label, false) or return
66
- prefix_name(f, "&nbsp;&mdash; ", l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
34
+ lbl = @xrefs.anchor(elem["id"], :label, false) or return
35
+ prefix_name(elem, "&nbsp;&mdash; ",
36
+ l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
67
37
  end
68
38
 
69
39
  def formula(docxml)
@@ -73,9 +43,9 @@ module IsoDoc
73
43
  end
74
44
 
75
45
  # introduce name element
76
- def formula1(f)
77
- lbl = @xrefs.anchor(f['id'], :label, false)
78
- prefix_name(f, "", lbl, "name")
46
+ def formula1(elem)
47
+ lbl = @xrefs.anchor(elem["id"], :label, false)
48
+ prefix_name(elem, "", lbl, "name")
79
49
  end
80
50
 
81
51
  def example(docxml)
@@ -90,11 +60,14 @@ module IsoDoc
90
60
  end
91
61
  end
92
62
 
93
- def example1(f)
94
- n = @xrefs.get[f["id"]]
95
- lbl = (n.nil? || n[:label].nil? || n[:label].empty?) ? @i18n.example:
96
- l10n("#{@i18n.example} #{n[:label]}")
97
- prefix_name(f, "&nbsp;&mdash; ", lbl, "name")
63
+ def example1(elem)
64
+ n = @xrefs.get[elem["id"]]
65
+ lbl = if n.nil? || n[:label].nil? || n[:label].empty?
66
+ @i18n.example
67
+ else
68
+ l10n("#{@i18n.example} #{n[:label]}")
69
+ end
70
+ prefix_name(elem, "&nbsp;&mdash; ", lbl, "name")
98
71
  end
99
72
 
100
73
  def note(docxml)
@@ -104,13 +77,16 @@ module IsoDoc
104
77
  end
105
78
 
106
79
  # introduce name element
107
- def note1(f)
108
- return if f.parent.name == "bibitem"
80
+ def note1(elem)
81
+ return if elem.parent.name == "bibitem"
109
82
 
110
- n = @xrefs.get[f["id"]]
111
- lbl = (@i18n.note if n.nil? || n[:label].nil? || n[:label].empty?) ?
112
- @i18n.note: l10n("#{@i18n.note} #{n[:label]}")
113
- prefix_name(f, "", lbl, "name")
83
+ n = @xrefs.get[elem["id"]]
84
+ lbl = if n.nil? || n[:label].nil? || n[:label].empty?
85
+ @i18n.note
86
+ else
87
+ l10n("#{@i18n.note} #{n[:label]}")
88
+ end
89
+ prefix_name(elem, "", lbl, "name")
114
90
  end
115
91
 
116
92
  def termnote(docxml)
@@ -120,9 +96,27 @@ module IsoDoc
120
96
  end
121
97
 
122
98
  # introduce name element
123
- def termnote1(f)
124
- lbl = l10n(@xrefs.anchor(f["id"], :label) || "???")
125
- prefix_name(f, "", lower2cap(lbl), "name")
99
+ def termnote1(elem)
100
+ lbl = l10n(@xrefs.anchor(elem["id"], :label) || "???")
101
+ prefix_name(elem, "", lower2cap(lbl), "name")
102
+ end
103
+
104
+ def termdefinition(docxml)
105
+ docxml.xpath(ns("//term[definition]")).each do |f|
106
+ termdefinition1(f)
107
+ end
108
+ end
109
+
110
+ def termdefinition1(elem)
111
+ return unless elem.xpath(ns("./definition")).size > 1
112
+
113
+ d = elem.at(ns("./definition"))
114
+ d = d.replace("<ol><li>#{d.children.to_xml}</li></ol>").first
115
+ elem.xpath(ns("./definition")).each do |f|
116
+ f = f.replace("<li>#{f.children.to_xml}</li>").first
117
+ d << f
118
+ end
119
+ d.wrap("<definition></definition>")
126
120
  end
127
121
 
128
122
  def recommendation(docxml)
@@ -144,10 +138,10 @@ module IsoDoc
144
138
  end
145
139
 
146
140
  # introduce name element
147
- def recommendation1(f, type)
148
- n = @xrefs.anchor(f["id"], :label, false)
141
+ def recommendation1(elem, type)
142
+ n = @xrefs.anchor(elem["id"], :label, false)
149
143
  lbl = (n.nil? ? type : l10n("#{type} #{n}"))
150
- prefix_name(f, "", lbl, "name")
144
+ prefix_name(elem, "", lbl, "name")
151
145
  end
152
146
 
153
147
  def table(docxml)
@@ -156,12 +150,13 @@ module IsoDoc
156
150
  end
157
151
  end
158
152
 
159
- def table1(f)
160
- return if labelled_ancestor(f)
161
- return if f["unnumbered"] && !f.at(ns("./name"))
153
+ def table1(elem)
154
+ return if labelled_ancestor(elem)
155
+ return if elem["unnumbered"] && !elem.at(ns("./name"))
162
156
 
163
- n = @xrefs.anchor(f["id"], :label, false)
164
- prefix_name(f, "&nbsp;&mdash; ", l10n("#{lower2cap @i18n.table} #{n}"), "name")
157
+ n = @xrefs.anchor(elem["id"], :label, false)
158
+ prefix_name(elem, "&nbsp;&mdash; ", l10n("#{lower2cap @i18n.table} #{n}"),
159
+ "name")
165
160
  end
166
161
 
167
162
  # we use this to eliminate the semantic amend blocks from rendering
@@ -171,11 +166,11 @@ module IsoDoc
171
166
  end
172
167
  end
173
168
 
174
- def amend1(f)
175
- f.xpath(ns("./autonumber")).each(&:remove)
176
- f.xpath(ns("./newcontent")).each { |a| a.name = "quote" }
177
- f.xpath(ns("./description")).each { |a| a.replace(a.children) }
178
- f.replace(f.children)
169
+ def amend1(elem)
170
+ elem.xpath(ns("./autonumber")).each(&:remove)
171
+ elem.xpath(ns("./newcontent")).each { |a| a.name = "quote" }
172
+ elem.xpath(ns("./description")).each { |a| a.replace(a.children) }
173
+ elem.replace(elem.children)
179
174
  end
180
175
  end
181
176
  end
@@ -0,0 +1,68 @@
1
+ module IsoDoc
2
+ class PresentationXMLConvert < ::IsoDoc::Convert
3
+ def concept(docxml)
4
+ docxml.xpath(ns("//concept")).each { |f| concept1(f) }
5
+ end
6
+
7
+ def concept1(node)
8
+ xref = node&.at(ns("./xref/@target"))&.text or
9
+ return concept_render(node, ital: node["ital"] || "true",
10
+ ref: node["ref"] || "true",
11
+ linkref: node["linkref"] || "true",
12
+ linkmention: node["linkmention"] || "false")
13
+ if node.at(ns("//definitions//dt[@id = '#{xref}']"))
14
+ concept_render(node, ital: node["ital"] || "false",
15
+ ref: node["ref"] || "false",
16
+ linkref: node["linkref"] || "true",
17
+ linkmention: node["linkmention"] || "false")
18
+ else concept_render(node, ital: node["ital"] || "true",
19
+ ref: node["ref"] || "true",
20
+ linkref: node["linkref"] || "true",
21
+ linkmention: node["linkmention"] || "false")
22
+ end
23
+ end
24
+
25
+ def concept_render(node, opts)
26
+ node&.at(ns("./refterm"))&.remove
27
+ r = node.at(ns("./renderterm"))
28
+ ref = node.at(ns("./xref | ./eref | ./termref"))
29
+ ref && opts[:ref] != "false" and r&.next = " "
30
+ opts[:ital] == "true" and r&.name = "em"
31
+ if opts[:linkmention] == "true" && !r.nil? && !ref.nil?
32
+ ref2 = ref.clone
33
+ r2 = r.clone
34
+ r.replace(ref2).children = r2
35
+ end
36
+ concept1_ref(node, ref, opts)
37
+ if opts[:ital] == "false"
38
+ r = node.at(ns(".//renderterm"))
39
+ r&.replace(r&.children)
40
+ end
41
+ node.replace(node.children)
42
+ end
43
+
44
+ def concept1_ref(_node, ref, opts)
45
+ ref.nil? and return
46
+ return ref.remove if opts[:ref] == "false"
47
+
48
+ r = concept1_ref_content(ref)
49
+ ref = r.at("./descendant-or-self::xmlns:xref | "\
50
+ "./descendant-or-self::xmlns:eref | "\
51
+ "./descendant-or-self::xmlns:termref")
52
+ %w(xref eref).include? ref&.name and get_linkend(ref)
53
+ if opts[:linkref] == "false" && %w(xref eref).include?(ref&.name)
54
+ ref.replace(ref.children)
55
+ end
56
+ end
57
+
58
+ def concept1_ref_content(ref)
59
+ if non_locality_elems(ref).select do |c|
60
+ !c.text? || /\S/.match(c)
61
+ end.empty?
62
+ ref.replace(@i18n.term_defined_in.sub(/%/,
63
+ ref.to_xml))
64
+ else ref.replace("[#{ref.to_xml}]")
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,112 @@
1
+ require "base64"
2
+ require "emf2svg"
3
+
4
+ module IsoDoc
5
+ class PresentationXMLConvert < ::IsoDoc::Convert
6
+ def figure(docxml)
7
+ docxml.xpath(ns("//image")).each { |f| svg_extract(f) }
8
+ docxml.xpath(ns("//figure")).each { |f| figure1(f) }
9
+ docxml.xpath(ns("//svgmap")).each do |s|
10
+ if f = s.at(ns("./figure")) then s.replace(f)
11
+ else s.remove
12
+ end
13
+ end
14
+ docxml.xpath(ns("//image")).each { |f| svg_emf_double(f) }
15
+ end
16
+
17
+ def svg_extract(elem)
18
+ return unless %r{^data:image/svg\+xml;}.match?(elem["src"])
19
+
20
+ svg = Base64.strict_decode64(elem["src"]
21
+ .sub(%r{^data:image/svg\+xml;(charset=[^;]+;)?base64,}, ""))
22
+ x = Nokogiri::XML.fragment(svg.sub(/<\?xml[^>]*>/, "")) do |config|
23
+ config.huge
24
+ end
25
+ elem["src"] = ""
26
+ elem.children = x
27
+ end
28
+
29
+ def figure1(elem)
30
+ return sourcecode1(elem) if elem["class"] == "pseudocode" ||
31
+ elem["type"] == "pseudocode"
32
+ return if labelled_ancestor(elem) && elem.ancestors("figure").empty? ||
33
+ elem.at(ns("./figure")) && !elem.at(ns("./name"))
34
+
35
+ lbl = @xrefs.anchor(elem["id"], :label, false) or return
36
+ prefix_name(elem, "&nbsp;&mdash; ",
37
+ l10n("#{lower2cap @i18n.figure} #{lbl}"), "name")
38
+ end
39
+
40
+ def svg_emf_double(img)
41
+ if emf?(img["mimetype"])
42
+ img = emf_encode(img)
43
+ img.children.first.previous = emf_to_svg(img)
44
+ elsif img["mimetype"] == "image/svg+xml"
45
+ src = svg_to_emf(img) and img << "<emf src='#{src}'/>"
46
+ end
47
+ end
48
+
49
+ def emf_encode(img)
50
+ img["mimetype"] = "image/svg+xml"
51
+ unless %r{^data:image}.match?(img["src"])
52
+ img["src"] = Metanorma::Utils::datauri(img["src"])
53
+ end
54
+ img.children = "<emf src='#{img['src']}'/>"
55
+ img["src"] = ""
56
+ img
57
+ end
58
+
59
+ def emf_to_svg(img)
60
+ emf = Metanorma::Utils::save_dataimage(img.at(ns("./emf/@src")).text)
61
+ Emf2svg.from_file(emf).sub(/<\?[^>]+>/, "")
62
+ end
63
+
64
+ def svg_to_emf(node)
65
+ uri = svg_to_emf_uri(node)
66
+ ret = svg_to_emf_filename(uri)
67
+ File.exists?(ret) and return ret
68
+ exe = inkscape_installed? or return nil
69
+ uri = Metanorma::Utils::external_path uri
70
+ exe = Metanorma::Utils::external_path exe
71
+ system(%(#{exe} --export-type="emf" #{uri})) and
72
+ return Metanorma::Utils::datauri(ret)
73
+
74
+ warn %(Fail on #{exe} --export-type="emf" #{uri})
75
+
76
+ nil
77
+ end
78
+
79
+ def svg_to_emf_uri(node)
80
+ uri = if node&.elements&.first&.name == "svg"
81
+ a = Base64.strict_encode64(node.children.to_xml)
82
+ "data:image/svg+xml;base64,#{a}"
83
+ else node["src"]
84
+ end
85
+ if %r{^data:}.match?(uri)
86
+ uri = save_dataimage(uri)
87
+ @tempfile_cache << uri
88
+ end
89
+ uri
90
+ end
91
+
92
+ def svg_to_emf_filename(uri)
93
+ "#{File.join(File.dirname(uri), File.basename(uri, '.*'))}.emf"
94
+ end
95
+
96
+ def emf_to_svgfilename(uri)
97
+ "#{File.join(File.dirname(uri), File.basename(uri, '.*'))}.svg"
98
+ end
99
+
100
+ def inkscape_installed?
101
+ cmd = "inkscape"
102
+ exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
103
+ ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
104
+ exts.each do |ext|
105
+ exe = File.join(path, "#{cmd}#{ext}")
106
+ return exe if File.executable?(exe) && !File.directory?(exe)
107
+ end
108
+ end
109
+ nil
110
+ end
111
+ end
112
+ end