isodoc 1.7.4 → 1.7.7

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.
@@ -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