Skip to content

Commit 15e66c8

Browse files
authored
Merge pull request #1158 from metanorma/features/altmedia
Features/altmedia
2 parents 612f076 + bca0b61 commit 15e66c8

File tree

8 files changed

+255
-104
lines changed

8 files changed

+255
-104
lines changed

lib/metanorma/cleanup/image.rb

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,38 +55,95 @@ def svgmap_target(nodeset)
5555
end
5656

5757
def img_cleanup(xmldoc)
58-
if @datauriimage
59-
xmldoc.xpath("//image").each do |i|
60-
# do not datauri encode SVG, we need to deduplicate its IDs
61-
unless read_in_if_svg(i, @localdir)
62-
i["src"] = Vectory::Utils::datauri(i["src"], @localdir)
63-
end
64-
end
65-
end
58+
altmedia_cleanup(xmldoc)
59+
@datauriimage and datauri_image(xmldoc)
6660
svg_cleanup(xmldoc)
6761
xmldoc
6862
end
6963

64+
def datauri_image(xmldoc)
65+
xmldoc.xpath("//image | //altsource").each do |i|
66+
# do not datauri encode SVG, we need to deduplicate its IDs
67+
unless read_in_if_svg?(i, @localdir)
68+
i["src"] &&= Vectory::Utils::datauri(i["src"], @localdir)
69+
end
70+
end
71+
end
72+
73+
def altmedia_cleanup(xmldoc)
74+
xmldoc.xpath("//image[@altmedia]").each do |i|
75+
altmedia_root_cleanup(i)
76+
d = altmedia_prep(i)
77+
d or next
78+
altsource_populate(i, d)
79+
end
80+
end
81+
82+
def altsource_populate(img, dlist)
83+
dlist.each do |e|
84+
e[:dd].nil? and next
85+
img << "<altsource tag='#{e[:dt]}'/>"
86+
image_attr_copy(e[:dd], img.elements.last)
87+
altsource_attr_copy(e[:dd], img.elements.last, img)
88+
end
89+
end
90+
91+
def image_attr_copy(src, dest)
92+
%w(src mimetype filename alt).each do |k|
93+
src[k] and dest[k] = src[k]
94+
end
95+
end
96+
97+
def altsource_attr_copy(src, dest, img)
98+
%w(media).each do |k|
99+
src[k] and dest[k] = src[k]
100+
end
101+
%w(height width).each do |k|
102+
dest[k] = img[k]
103+
src[k] or next
104+
src[k] == "auto" and next
105+
dest[k] = src[k]
106+
end
107+
end
108+
109+
def altmedia_root_cleanup(img)
110+
%w(altmedia src filename mimetype).each do |k|
111+
img.delete(k)
112+
end
113+
end
114+
115+
def altmedia_prep(img)
116+
dl = img.at("./dl") or return
117+
d = extract_symbols_list(dl.remove).map do |e|
118+
{ dt: e[:dt].text, dd: e[:dd].at(".//image") }
119+
end
120+
unless d.detect { |e| e[:dt] == "default" }
121+
d << d.first.dup
122+
d[-1][:dt] = "default"
123+
end
124+
d
125+
end
126+
70127
def svg_cleanup(xmldoc)
71128
svg_uniqueids(xmldoc)
72129
svg_classupdate(xmldoc)
73130
end
74131

75-
def read_in_if_svg(img, localdir)
132+
def read_in_if_svg?(img, localdir)
76133
img["src"] or return false
77134
path = Vectory::Utils.svgmap_rewrite0_path(img["src"], localdir)
78135
File.file?(path) or return false
79136
types = MIME::Types.type_for(path) or return false
80137
types.first == "image/svg+xml" or return false
81138
svg = File.read(path, encoding: "utf-8") or return false
82-
img.children = (Nokogiri::XML(svg).root)
139+
img.add_first_child Nokogiri::XML(svg).root
83140
true
84141
end
85142

86143
def svg_classupdate(xmldoc)
87144
xmldoc.xpath("//m:svg[m:style]", "m" => SVG_NS)
88145
.each_with_index do |s, i|
89-
svg_classupdate1(s, s.at("./m:style", "m" => SVG_NS), i)
146+
svg_classupdate1(s, s.at("./m:style", "m" => SVG_NS), i)
90147
end
91148
end
92149

@@ -101,7 +158,7 @@ def svg_classupdate1(svg, style, idx)
101158
end
102159

103160
def svg_suffix_css_style(node, idx)
104-
node[:node] == :style_rule && /\./.match?(node[:selector][:value]) or
161+
(node[:node] == :style_rule && /\./.match?(node[:selector][:value])) or
105162
return
106163
v = node[:selector][:value]
107164
.gsub(/([^.\s]*\.\S+)/, "\\1_inject_#{idx}")
@@ -149,7 +206,7 @@ def svg_uniqueids1(svg, idx, ids)
149206
svg_uniqueids2(svg, iri_properties, idx, ids)
150207
new_ids = id_elems.map { |x| x["id"] }
151208
.map { |x| x + (ids[x] ? "_inject_#{idx}" : "") }
152-
ids.merge(new_ids.each.map { |value| [value, true] }.to_h)
209+
ids.merge(new_ids.each.to_h { |value| [value, true] })
153210
end
154211

155212
def svg_uniqueids2(svg, iri_properties, idx, ids)

lib/metanorma/converter/blocks.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require "uri"
2-
require_relative "./blocks_notes_examples"
3-
require_relative "./blocks_image"
2+
require_relative "blocks_notes"
3+
require_relative "blocks_examples"
4+
require_relative "blocks_image"
45

56
module Metanorma
67
module Standoc
@@ -42,6 +43,7 @@ def open(node)
4243
role == "definition" and return termdefinition(node)
4344
role == "boilerplate" and return boilerplate_note(node)
4445
role == "key" and return key_block(node)
46+
role == "altmedia" and return altmedia_block(node)
4547
open1(node)
4648
end
4749

lib/metanorma/converter/blocks_image.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def figure_example(node)
2828
def figure_attrs(node)
2929
attr_code(id_unnum_attrs(node).merge(keep_attrs(node))
3030
.merge(class: node.attr("class"),
31+
height: node.attr("height"),
3132
width: node.attr("width")))
3233
end
3334

@@ -39,6 +40,17 @@ def image(node)
3940
end
4041
end
4142
end
43+
44+
def altmedia_block(node)
45+
noko do |xml|
46+
xml.figure **figure_attrs(node) do |f|
47+
block_title(node, f)
48+
f.image **image_attributes(node, src: false, altmedia: true) do |i|
49+
i << node.content
50+
end
51+
end
52+
end
53+
end
4254
end
4355
end
4456
end

lib/metanorma/converter/blocks_notes_examples.rb renamed to lib/metanorma/converter/blocks_notes.rb

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -120,66 +120,6 @@ def admonition_alternatives(node)
120120
node.attr("name") == "todo" and return todo(node)
121121
nil
122122
end
123-
124-
def term_example(node)
125-
noko do |xml|
126-
xml.termexample **attr_code(id_attr(node)
127-
.merge(keepasterm: node.option?("termexample") || nil)) do |ex|
128-
wrap_in_para(node, ex)
129-
end
130-
end
131-
end
132-
133-
def example(node)
134-
role = node.role || node.attr("style")
135-
ret = example_to_requirement(node, role) ||
136-
example_by_role(node, role) and return ret
137-
(in_terms? || node.option?("termexample")) and return term_example(node)
138-
reqt_subpart?(role) and return requirement_subpart(node)
139-
example_proper(node)
140-
end
141-
142-
def example_by_role(node, role)
143-
case role
144-
when "pseudocode" then pseudocode_example(node)
145-
when "svgmap" then svgmap_example(node)
146-
when "form" then form(node)
147-
when "definition" then termdefinition(node)
148-
when "figure" then figure_example(node)
149-
end
150-
end
151-
152-
def example_to_requirement(node, role)
153-
@reqt_models.requirement_roles.key?(role&.to_sym) or return
154-
# need to call here for proper recursion ordering
155-
select_requirement_model(node)
156-
requirement(node,
157-
@reqt_models.requirement_roles[role.to_sym], role)
158-
end
159-
160-
# prevent A's and other subs inappropriate for pseudocode
161-
def pseudocode_example(node)
162-
node.blocks.each { |b| b.remove_sub(:replacements) }
163-
noko do |xml|
164-
xml.figure **example_attrs(node).merge(class: "pseudocode") do |ex|
165-
block_title(node, ex)
166-
wrap_in_para(node, ex)
167-
end
168-
end
169-
end
170-
171-
def example_attrs(node)
172-
attr_code(id_unnum_attrs(node).merge(keep_attrs(node)))
173-
end
174-
175-
def example_proper(node)
176-
noko do |xml|
177-
xml.example **example_attrs(node) do |ex|
178-
block_title(node, xml)
179-
wrap_in_para(node, ex)
180-
end
181-
end
182-
end
183123
end
184124
end
185125
end

lib/metanorma/converter/inline.rb

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ def stem_parse(text, xml, style, node)
4444
attrs, text = stem_attrs(node, text)
4545
if /&lt;([^:>&]+:)?math(\s+[^>&]+)?&gt; |
4646
<([^:>&]+:)?math(\s+[^>&]+)?>/x.match? text
47-
xml.stem **attrs.merge(type: "MathML") do |s|
47+
xml.stem **attrs, type: "MathML" do |s|
4848
s << xml_encode(text)
4949
end
5050
elsif style == :latexmath then latex_parse(text, xml, attrs)
5151
else
5252
xml.stem text&.gsub("&amp;#", "&#") || "",
53-
**attrs.merge(type: "AsciiMath")
53+
**attrs, type: "AsciiMath"
5454
end
5555
end
5656

@@ -69,8 +69,8 @@ def stem_attrs(node, text)
6969

7070
def latex_parse(text, xml, attr)
7171
latex = latex_parse1(text, attr[:block]) or
72-
return xml.stem **attr.merge(type: "MathML")
73-
xml.stem **attr.merge(type: "MathML") do |s|
72+
return xml.stem **attr, type: "MathML"
73+
xml.stem **attr, type: "MathML" do |s|
7474
math = Nokogiri::XML.fragment(latex.sub(/<\?[^>]+>/, ""))
7575
.elements[0]
7676
math.delete("alttext")
@@ -138,12 +138,14 @@ def image_mimetype(uri)
138138
types.first.to_s
139139
end
140140

141-
def image_attributes(node)
142-
sourceuri = image_src_uri(node)
143-
uri = sourceuri
144-
type = image_mimetype(uri)
145-
uri = uri.sub(%r{^data:image/\*;}, "data:#{type};")
146-
image_attributes1(node, uri, sourceuri, type)
141+
def image_attributes(node, src: true, altmedia: nil)
142+
if src
143+
sourceuri = image_src_uri(node)
144+
uri = sourceuri
145+
type = image_mimetype(uri)
146+
uri = uri.sub(%r{^data:image/\*;}, "data:#{type};")
147+
end
148+
image_attributes1(node, uri, sourceuri, type, altmedia)
147149
end
148150

149151
def image_src_uri(node)
@@ -158,14 +160,16 @@ def image_src_uri(node)
158160
uri
159161
end
160162

161-
def image_attributes1(node, uri, sourceuri, type)
163+
def image_attributes1(node, uri, sourceuri, type, altmedia)
162164
/^data:/.match?(sourceuri) and sourceuri = nil
163165
attr_code(id_attr(node)
164166
.merge(src: uri, mimetype: type,
165167
height: node.attr("height") || "auto",
166168
width: node.attr("width") || "auto",
167169
filename: node.attr("filename") || sourceuri,
168170
title: node.attr("titleattr"),
171+
media: node.attr("media"),
172+
altmedia: altmedia,
169173
alt: node.alt == node.attr("default-alt") ? nil : node.alt))
170174
end
171175

spec/assets/odf.svg

Lines changed: 1 addition & 0 deletions
Loading

spec/cleanup/blocks_spec.rb

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,58 @@
22
require "fileutils"
33

44
RSpec.describe Metanorma::Standoc do
5+
it "expands svg" do
6+
input = <<~INPUT
7+
#{ASCIIDOC_BLANK_HDR.sub(':data-uri-image: false', ':data-uri-image: true')}
8+
9+
[altmedia]
10+
--
11+
doc:: image:spec/assets/odf.svg[]
12+
html:: image:spec/assets/odf.svg[]
13+
--
14+
15+
image::spec/assets/odf.svg[]
16+
INPUT
17+
output = <<~OUTPUT
18+
#{BLANK_HDR}
19+
<sections>
20+
<figure id="_">
21+
<image id="_" height="auto" width="auto" alt="">
22+
<altsource tag="doc" src="spec/assets/odf.svg" mimetype="image/svg+xml" height="auto" width="auto" filename="spec/assets/odf.svg">
23+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
24+
<circle fill="#009" r="45" cx="50" cy="50"/>
25+
<path d="M33,26H78A37,37,0,0,1,33,83V57H59V43H33Z" fill="#FFF"/>
26+
</svg>
27+
</altsource>
28+
<altsource tag="html" src="spec/assets/odf.svg" mimetype="image/svg+xml" height="auto" width="auto" filename="spec/assets/odf.svg">
29+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
30+
<circle fill="#009" r="45" cx="50" cy="50"/>
31+
<path d="M33,26H78A37,37,0,0,1,33,83V57H59V43H33Z" fill="#FFF"/>
32+
</svg>
33+
</altsource>
34+
<altsource tag="default" src="spec/assets/odf.svg" mimetype="image/svg+xml" height="auto" width="auto" filename="spec/assets/odf.svg">
35+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
36+
<circle fill="#009" r="45" cx="50" cy="50"/>
37+
<path d="M33,26H78A37,37,0,0,1,33,83V57H59V43H33Z" fill="#FFF"/>
38+
</svg>
39+
</altsource>
40+
</image>
41+
</figure>
42+
<figure id="_">
43+
<image id="_" src="spec/assets/odf.svg" mimetype="image/svg+xml" height="auto" width="auto" filename="spec/assets/odf.svg">
44+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
45+
<circle fill="#009" r="45" cx="50" cy="50"/>
46+
<path d="M33,26H78A37,37,0,0,1,33,83V57H59V43H33Z" fill="#FFF"/>
47+
</svg>
48+
</image>
49+
</figure>
50+
</sections>
51+
</metanorma>
52+
OUTPUT
53+
expect(strip_guid(Canon.format_xml(Asciidoctor.convert(input, *OPTIONS))))
54+
.to be_equivalent_to Canon.format_xml(output)
55+
end
56+
557
it "processes svgmap" do
658
FileUtils.cp "spec/fixtures/action_schemaexpg1.svg",
759
"action_schemaexpg1.svg"
@@ -1008,7 +1060,7 @@
10081060

10091061
it "deduplicates identifiers in embedded SVGs" do
10101062
input = <<~INPUT
1011-
#{ASCIIDOC_BLANK_HDR.sub(/:data-uri-image: false/, ':data-uri-image: true')}
1063+
#{ASCIIDOC_BLANK_HDR.sub(':data-uri-image: false', ':data-uri-image: true')}
10121064
10131065
[height=100,width=100]
10141066
image::spec/fixtures/action_schemaexpg1.svg[]
@@ -1021,7 +1073,7 @@
10211073
output = <<~OUTPUT
10221074
#{BLANK_HDR}
10231075
<sections>
1024-
<figure id="_" width="100">
1076+
<figure id="_" height="100" width="100">
10251077
<image src="spec/fixtures/action_schemaexpg1.svg" filename="spec/fixtures/action_schemaexpg1.svg" mimetype="image/svg+xml" id="_" height="100" width="100">
10261078
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
10271079
<style/>
@@ -1659,5 +1711,4 @@
16591711
expect(strip_guid(Canon.format_xml(Asciidoctor.convert(input, *OPTIONS))))
16601712
.to be_equivalent_to Canon.format_xml(output)
16611713
end
1662-
16631714
end

0 commit comments

Comments
 (0)