vectory 0.2.0 → 0.4.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 +4 -4
- data/Gemfile +3 -1
- data/README.adoc +167 -0
- data/lib/vectory/datauri.rb +13 -0
- data/lib/vectory/image.rb +4 -0
- data/lib/vectory/inkscape_converter.rb +82 -11
- data/lib/vectory/svg.rb +84 -1
- data/lib/vectory/svg_mapping.rb +118 -0
- data/lib/vectory/system_call.rb +10 -2
- data/lib/vectory/utils.rb +111 -0
- data/lib/vectory/vector.rb +25 -2
- data/lib/vectory/version.rb +1 -1
- data/lib/vectory.rb +3 -0
- data/spec/examples/svg/action_schemaexpg1.svg +124 -0
- data/spec/examples/svg/action_schemaexpg2.svg +124 -0
- data/spec/examples/svg/doc-ref.xml +109 -0
- data/spec/examples/svg/doc.xml +51 -0
- data/spec/examples/svg/doc2-ref.xml +59 -0
- data/spec/examples/svg/doc2.xml +28 -0
- data/spec/support/matchers.rb +12 -0
- data/spec/support/vectory_helper.rb +14 -0
- data/spec/vectory/cli_spec.rb +15 -14
- data/spec/vectory/datauri_spec.rb +80 -0
- data/spec/vectory/emf_spec.rb +27 -3
- data/spec/vectory/eps_spec.rb +36 -9
- data/spec/vectory/file_magic_spec.rb +3 -3
- data/spec/vectory/inkscape_converter_spec.rb +11 -6
- data/spec/vectory/ps_spec.rb +28 -3
- data/spec/vectory/svg_mapping_spec.rb +42 -0
- data/spec/vectory/svg_spec.rb +43 -3
- data/spec/vectory/vector_spec.rb +37 -0
- data/vectory.gemspec +0 -4
- metadata +22 -70
- /data/spec/examples/emf2eps/{img.eps → ref.eps} +0 -0
- /data/spec/examples/emf2ps/{img.ps → ref.ps} +0 -0
- /data/spec/examples/emf2svg/{img.svg → ref.svg} +0 -0
- /data/spec/examples/eps2emf/{img.emf → ref.emf} +0 -0
- /data/spec/examples/eps2ps/{img.ps → ref.ps} +0 -0
- /data/spec/examples/eps2svg/{img.svg → ref.svg} +0 -0
- /data/spec/examples/ps2emf/{img.emf → ref.emf} +0 -0
- /data/spec/examples/ps2eps/{img.eps → ref.eps} +0 -0
- /data/spec/examples/ps2svg/{img.svg → ref.svg} +0 -0
- /data/spec/examples/svg2emf/{img.emf → ref.emf} +0 -0
- /data/spec/examples/svg2eps/{img.eps → ref.eps} +0 -0
- /data/spec/examples/svg2ps/{img.ps → ref.ps} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f51d610adc333c06f92e8e28ca9722a890f12b03668bf12e96ce057d2574dea
|
4
|
+
data.tar.gz: 792bc815a0b86a6211b83268f16b9abe7a138aba0081a2d7a95242c5e9a7af82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 249d3f2fa7df2d216cdf5d046647507b81a55bd5db56a603a90a3890501adb10e8a03f41b272385c65a8de48c50b8b52db743ec5ddc20be88e4e5aab6ed21ca6
|
7
|
+
data.tar.gz: 5ed331050b3c4a3231cabc7ba061695f017de5ea44a3056bf01537144b12c96cf5587c0a52793d3d435d961052210aefed73a52c4afc9c3563695fca8e23c91d
|
data/Gemfile
CHANGED
data/README.adoc
CHANGED
@@ -27,6 +27,9 @@ Vectory relies on the following software to be installed:
|
|
27
27
|
* https://inkscape.org[Inkscape]
|
28
28
|
* https://www.ghostscript.com/[Ghostscript]
|
29
29
|
|
30
|
+
NOTE: Inkscape 1.3.1 does not work properly with EPS/PS on Windows. To avoid
|
31
|
+
this issue, the 1.3.0 version of Inkscape can be used.
|
32
|
+
|
30
33
|
|
31
34
|
=== Gem install
|
32
35
|
|
@@ -157,6 +160,131 @@ Vectory::Eps.from_path("img.eps").to_uri.content
|
|
157
160
|
----
|
158
161
|
|
159
162
|
|
163
|
+
==== SVG mapping (for the metanorma project)
|
164
|
+
|
165
|
+
Vectory can integrate SVG files into XML or HTML, respecting internal id and
|
166
|
+
link references:
|
167
|
+
|
168
|
+
[source,ruby]
|
169
|
+
----
|
170
|
+
xml_string = Vectory::SvgMapping.from_path("doc.xml").call
|
171
|
+
----
|
172
|
+
|
173
|
+
In order to do that an initial XML should support the `svgmap` tag with links
|
174
|
+
mapping. For example, it can convert XML like this:
|
175
|
+
|
176
|
+
[source,xml]
|
177
|
+
----
|
178
|
+
<svgmap id="_4072bdcb-5895-4821-b636-5795b96787cb">
|
179
|
+
<figure><image src="action_schemaexpg1.svg"/></figure>
|
180
|
+
<target href="mn://action_schema">
|
181
|
+
<xref target="ref1">Computer</xref>
|
182
|
+
</target>
|
183
|
+
<target href="http://www.example.com">
|
184
|
+
<link target="http://www.example.com">Phone</link><
|
185
|
+
/target>
|
186
|
+
</svgmap>
|
187
|
+
----
|
188
|
+
|
189
|
+
.action_schemaexpg1.svg
|
190
|
+
[source,xml]
|
191
|
+
----
|
192
|
+
<?xml version="1.0" encoding="utf-8"?>
|
193
|
+
<!-- Generator: Adobe Illustrator 25.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
194
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
195
|
+
viewBox="0 0 595.28 841.89" style="enable-background:new 0 0 595.28 841.89;" xml:space="preserve">
|
196
|
+
<style type="text/css">
|
197
|
+
#Layer_1 { fill:none }
|
198
|
+
svg[id = 'Layer_1'] { fill:none }
|
199
|
+
.st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
|
200
|
+
</style>
|
201
|
+
<image style="overflow:visible;" width="368" height="315" xlink:href="data:image/gif;base64,R0lG..ommited to save space" transform="matrix(1 0 0 1 114 263.8898)">
|
202
|
+
</image>
|
203
|
+
<a xlink:href="mn://action_schema" xlink:dummy="Layer_1">
|
204
|
+
<rect x="123.28" y="273.93" class="st0" width="88.05" height="41.84"/>
|
205
|
+
</a>
|
206
|
+
<a xlink:href="mn://basic_attribute_schema" >
|
207
|
+
<rect x="324.69" y="450.52" class="st0" width="132.62" height="40.75"/>
|
208
|
+
</a>
|
209
|
+
<a xlink:href="mn://support_resource_schema" >
|
210
|
+
<rect x="324.69" y="528.36" class="st0" width="148.16" height="40.75"/>
|
211
|
+
</a>
|
212
|
+
</svg>
|
213
|
+
----
|
214
|
+
|
215
|
+
into XML containing inline SVG tags. Notice changes in the `id` attributes and
|
216
|
+
the `a` tags:
|
217
|
+
|
218
|
+
[source,xml]
|
219
|
+
----
|
220
|
+
<figure>
|
221
|
+
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' id='Layer_1_000000001' x='0px' y='0px' viewBox='0 0 595.28 841.89' style='enable-background:new 0 0 595.28 841.89;' xml:space='preserve'>
|
222
|
+
<style> ..ommited to save space </style>
|
223
|
+
<image> ..ommited </image>
|
224
|
+
<a xlink:href='#ref1' xlink:dummy='Layer_1_000000001'>
|
225
|
+
<rect x='123.28' y='273.93' class='st0' width='88.05' height='41.84'/>
|
226
|
+
</a>
|
227
|
+
<a xlink:href='mn://basic_attribute_schema'>
|
228
|
+
<rect x='324.69' y='450.52' class='st0' width='132.62' height='40.75'/>
|
229
|
+
</a>
|
230
|
+
<a xlink:href='mn://support_resource_schema'>
|
231
|
+
<rect x='324.69' y='528.36' class='st0' width='148.16' height='40.75'/>
|
232
|
+
</a>
|
233
|
+
</svg>
|
234
|
+
</figure>
|
235
|
+
----
|
236
|
+
|
237
|
+
It also supports SVG in a form of an inline tag:
|
238
|
+
|
239
|
+
[source,xml]
|
240
|
+
----
|
241
|
+
<svgmap id="_60dadf08-48d4-4164-845c-b4e293e00abd">
|
242
|
+
<figure>
|
243
|
+
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' 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'>
|
244
|
+
<a href="mn://action_schema" >
|
245
|
+
<rect x="123.28" y="273.93" class="st0" width="88.05" height="41.84"/>
|
246
|
+
</a>
|
247
|
+
<a href="mn://basic_attribute_schema" >
|
248
|
+
<rect x="324.69" y="450.52" class="st0" width="132.62" height="40.75"/>
|
249
|
+
</a>
|
250
|
+
<a xlink:href="mn://support_resource_schema" >
|
251
|
+
<rect x="324.69" y="528.36" class="st0" width="148.16" height="40.75"/>
|
252
|
+
</a>
|
253
|
+
</svg>
|
254
|
+
</figure>
|
255
|
+
<target href="mn://action_schema">
|
256
|
+
<xref target="ref1">Computer</xref>
|
257
|
+
</target>
|
258
|
+
<target href="http://www.example.com">
|
259
|
+
<link target="http://www.example.com">Phone</link>
|
260
|
+
</target>
|
261
|
+
</svgmap>
|
262
|
+
----
|
263
|
+
|
264
|
+
and datauri:
|
265
|
+
|
266
|
+
[source,xml]
|
267
|
+
----
|
268
|
+
<svgmap id="_60dadf08-48d4-4164-845c-b4e293e00abd">
|
269
|
+
<figure>
|
270
|
+
<image src='data:image/svg+xml;base64,PD94..ommited to save space' id='__ISO_17301-1_2016' mimetype='image/svg+xml' height='auto' width='auto' alt='Workmap1'/>
|
271
|
+
</figure>
|
272
|
+
<target href="href1.htm">
|
273
|
+
<xref target="ref1">Computer</xref>
|
274
|
+
</target>
|
275
|
+
<target href="mn://basic_attribute_schema">
|
276
|
+
<link target="http://www.example.com">Phone</link>
|
277
|
+
</target>
|
278
|
+
<target href="mn://support_resource_schema">
|
279
|
+
<eref type="express" bibitemid="express_action_schema" citeas="">
|
280
|
+
<localityStack><locality type="anchor"><referenceFrom>action_schema.basic</referenceFrom></locality></localityStack>
|
281
|
+
Coffee
|
282
|
+
</eref>
|
283
|
+
</target>
|
284
|
+
</svgmap>
|
285
|
+
----
|
286
|
+
|
287
|
+
|
160
288
|
==== File system operations
|
161
289
|
|
162
290
|
An image object contains information where it is written. It can be obtained
|
@@ -201,6 +329,45 @@ purposes.
|
|
201
329
|
vector.initial_path # => "storage/images/img.eps"
|
202
330
|
----
|
203
331
|
|
332
|
+
==== Additional properties
|
333
|
+
|
334
|
+
The following additional properties are supported:
|
335
|
+
|
336
|
+
[source,ruby]
|
337
|
+
----
|
338
|
+
Datauri#mime
|
339
|
+
Datauri#height
|
340
|
+
Datauri#width
|
341
|
+
Vector (Eps, Ps, Svg, Emf)
|
342
|
+
Vector#mime
|
343
|
+
Vector#size
|
344
|
+
Vector#file_size
|
345
|
+
Vector#height
|
346
|
+
Vector#width
|
347
|
+
----
|
348
|
+
|
349
|
+
|
350
|
+
== Development
|
351
|
+
|
352
|
+
=== Releasing
|
353
|
+
|
354
|
+
Releasing is done automatically with GitHub Actions. Just bump and tag with
|
355
|
+
`gem-release`.
|
356
|
+
|
357
|
+
For a patch release (0.0.x) use:
|
358
|
+
|
359
|
+
[source,sh]
|
360
|
+
----
|
361
|
+
gem bump --version patch --tag --push
|
362
|
+
----
|
363
|
+
|
364
|
+
For a minor release (0.x.0) use:
|
365
|
+
|
366
|
+
[source,sh]
|
367
|
+
----
|
368
|
+
gem bump --version minor --tag --push
|
369
|
+
----
|
370
|
+
|
204
371
|
|
205
372
|
== Contributing
|
206
373
|
|
data/lib/vectory/datauri.rb
CHANGED
@@ -18,6 +18,19 @@ module Vectory
|
|
18
18
|
new("data:#{mimetype};base64,#{data}")
|
19
19
|
end
|
20
20
|
|
21
|
+
def mime
|
22
|
+
match = parse_datauri(@content)
|
23
|
+
match[:mimetype]
|
24
|
+
end
|
25
|
+
|
26
|
+
def height
|
27
|
+
to_vector.height
|
28
|
+
end
|
29
|
+
|
30
|
+
def width
|
31
|
+
to_vector.width
|
32
|
+
end
|
33
|
+
|
21
34
|
def to_vector
|
22
35
|
match = parse_datauri(@content)
|
23
36
|
content = Base64.strict_decode64(match[:data])
|
data/lib/vectory/image.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "singleton"
|
4
|
+
require "tmpdir"
|
4
5
|
require_relative "system_call"
|
5
6
|
|
6
7
|
module Vectory
|
@@ -12,43 +13,78 @@ module Vectory
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def convert(uri, output_extension, option)
|
15
|
-
exe = inkscape_path_or_raise_error
|
16
|
+
exe = inkscape_path_or_raise_error
|
16
17
|
uri = external_path uri
|
17
18
|
exe = external_path exe
|
18
19
|
cmd = %(#{exe} #{option} #{uri})
|
19
20
|
|
20
21
|
call = SystemCall.new(cmd).call
|
21
22
|
|
22
|
-
output_path =
|
23
|
-
raise_conversion_error(call) unless
|
23
|
+
output_path = find_output(uri, output_extension)
|
24
|
+
raise_conversion_error(call) unless output_path
|
24
25
|
|
25
26
|
# and return Vectory::Utils::datauri(file)
|
26
27
|
|
27
28
|
output_path
|
28
29
|
end
|
29
30
|
|
31
|
+
def height(content, format)
|
32
|
+
query_integer(content, format, "--query-height")
|
33
|
+
end
|
34
|
+
|
35
|
+
def width(content, format)
|
36
|
+
query_integer(content, format, "--query-width")
|
37
|
+
end
|
38
|
+
|
30
39
|
private
|
31
40
|
|
32
|
-
def inkscape_path_or_raise_error
|
41
|
+
def inkscape_path_or_raise_error
|
33
42
|
inkscape_path or raise(InkscapeNotFoundError,
|
34
43
|
"Inkscape missing in PATH, unable to " \
|
35
|
-
"convert image
|
44
|
+
"convert image. Aborting.")
|
36
45
|
end
|
37
46
|
|
38
47
|
def inkscape_path
|
39
|
-
|
40
|
-
|
48
|
+
@inkscape_path ||= find_inkscape
|
49
|
+
end
|
41
50
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
51
|
+
def find_inkscape
|
52
|
+
cmds.each do |cmd|
|
53
|
+
extensions.each do |ext|
|
54
|
+
paths.each do |path|
|
55
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
56
|
+
|
57
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
58
|
+
end
|
46
59
|
end
|
47
60
|
end
|
48
61
|
|
49
62
|
nil
|
50
63
|
end
|
51
64
|
|
65
|
+
def cmds
|
66
|
+
["inkscapecom", "inkscape"]
|
67
|
+
end
|
68
|
+
|
69
|
+
def extensions
|
70
|
+
ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
|
71
|
+
end
|
72
|
+
|
73
|
+
def paths
|
74
|
+
ENV["PATH"].split(File::PATH_SEPARATOR)
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_output(source_path, output_extension)
|
78
|
+
basenames = [File.basename(source_path, ".*"),
|
79
|
+
File.basename(source_path)]
|
80
|
+
|
81
|
+
paths = basenames.map do |basename|
|
82
|
+
"#{File.join(File.dirname(source_path), basename)}.#{output_extension}"
|
83
|
+
end
|
84
|
+
|
85
|
+
paths.find { |p| File.exist?(p) }
|
86
|
+
end
|
87
|
+
|
52
88
|
def raise_conversion_error(call)
|
53
89
|
raise Vectory::ConversionError,
|
54
90
|
"Could not convert with Inkscape. " \
|
@@ -68,5 +104,40 @@ module Vectory
|
|
68
104
|
path
|
69
105
|
end
|
70
106
|
end
|
107
|
+
|
108
|
+
def query_integer(content, format, options)
|
109
|
+
query(content, format, options).to_f.round
|
110
|
+
end
|
111
|
+
|
112
|
+
def query(content, format, options)
|
113
|
+
exe = inkscape_path_or_raise_error
|
114
|
+
|
115
|
+
with_file(content, format) do |path|
|
116
|
+
cmd = "#{external_path(exe)} #{options} #{external_path(path)}"
|
117
|
+
|
118
|
+
call = SystemCall.new(cmd).call
|
119
|
+
raise_query_error(call) if call.stdout.empty?
|
120
|
+
|
121
|
+
call.stdout
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def with_file(content, extension)
|
126
|
+
Dir.mktmpdir do |dir|
|
127
|
+
path = File.join(dir, "image.#{extension}")
|
128
|
+
File.binwrite(path, content)
|
129
|
+
|
130
|
+
yield path
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def raise_query_error(call)
|
135
|
+
raise Vectory::InkscapeQueryError,
|
136
|
+
"Could not query with Inkscape. " \
|
137
|
+
"Inkscape cmd: '#{call.cmd}',\n" \
|
138
|
+
"status: '#{call.status}',\n" \
|
139
|
+
"stdout: '#{call.stdout.strip}',\n" \
|
140
|
+
"stderr: '#{call.stderr.strip}'."
|
141
|
+
end
|
71
142
|
end
|
72
143
|
end
|
data/lib/vectory/svg.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "nokogiri"
|
4
|
+
|
3
5
|
module Vectory
|
4
6
|
class Svg < Vector
|
5
|
-
|
7
|
+
SVG_NS = "http://www.w3.org/2000/svg"
|
6
8
|
|
7
9
|
def self.default_extension
|
8
10
|
"svg"
|
@@ -12,6 +14,10 @@ module Vectory
|
|
12
14
|
"image/svg+xml"
|
13
15
|
end
|
14
16
|
|
17
|
+
def content
|
18
|
+
@document&.to_xml || @content
|
19
|
+
end
|
20
|
+
|
15
21
|
def to_emf
|
16
22
|
convert_with_inkscape("--export-type=emf", Emf)
|
17
23
|
end
|
@@ -23,5 +29,82 @@ module Vectory
|
|
23
29
|
def to_ps
|
24
30
|
convert_with_inkscape("--export-type=ps", Ps)
|
25
31
|
end
|
32
|
+
|
33
|
+
def namespace(suffix, links, xpath_to_remove)
|
34
|
+
remap_links(links)
|
35
|
+
suffix_ids(suffix)
|
36
|
+
remove_xpath(xpath_to_remove)
|
37
|
+
end
|
38
|
+
|
39
|
+
def remap_links(map)
|
40
|
+
document.xpath(".//m:a", "m" => SVG_NS).each do |a|
|
41
|
+
href_attrs = ["xlink:href", "href"]
|
42
|
+
href_attrs.each do |p|
|
43
|
+
a[p] and x = map[File.expand_path(a[p])] and a[p] = x
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def suffix_ids(suffix)
|
51
|
+
ids = collect_ids
|
52
|
+
return if ids.empty?
|
53
|
+
|
54
|
+
update_ids_attrs(ids, suffix)
|
55
|
+
update_ids_css(ids, suffix)
|
56
|
+
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_xpath(xpath)
|
61
|
+
document.xpath(xpath).remove
|
62
|
+
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def content=(content)
|
69
|
+
if @document
|
70
|
+
@document = Nokogiri::XML(content)
|
71
|
+
else
|
72
|
+
@content = content
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def document
|
77
|
+
@document ||= begin
|
78
|
+
doc = Nokogiri::XML(@content)
|
79
|
+
@content = nil
|
80
|
+
doc
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def collect_ids
|
85
|
+
document.xpath("./@id | .//@id").map(&:value)
|
86
|
+
end
|
87
|
+
|
88
|
+
def update_ids_attrs(ids, suffix)
|
89
|
+
document.xpath(". | .//*[@*]").each do |a|
|
90
|
+
a.attribute_nodes.each do |x|
|
91
|
+
ids.include?(x.value) and x.value += sprintf("_%09d", suffix)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def update_ids_css(ids, suffix)
|
97
|
+
document.xpath("//m:style", "m" => SVG_NS).each do |s|
|
98
|
+
c = s.children.to_xml
|
99
|
+
ids.each do |i|
|
100
|
+
c = c.gsub(%r[##{i}\b],
|
101
|
+
sprintf("#%<id>s_%<suffix>09d", id: i, suffix: suffix))
|
102
|
+
.gsub(%r(\[id\s*=\s*['"]?#{i}['"]?\]),
|
103
|
+
sprintf("[id='%<id>s_%<suffix>09d']", id: i, suffix: suffix))
|
104
|
+
end
|
105
|
+
|
106
|
+
s.children = c
|
107
|
+
end
|
108
|
+
end
|
26
109
|
end
|
27
110
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require_relative "svg"
|
2
|
+
|
3
|
+
module Vectory
|
4
|
+
class SvgMapping
|
5
|
+
class Namespace
|
6
|
+
def initialize(xmldoc)
|
7
|
+
@namespace = xmldoc.root.namespace
|
8
|
+
end
|
9
|
+
|
10
|
+
def ns(path)
|
11
|
+
return path if @namespace.nil?
|
12
|
+
|
13
|
+
path.gsub(%r{/([a-zA-z])}, "/xmlns:\\1")
|
14
|
+
.gsub(%r{::([a-zA-z])}, "::xmlns:\\1")
|
15
|
+
.gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1")
|
16
|
+
.gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
SVG_NS = "http://www.w3.org/2000/svg".freeze
|
21
|
+
PROCESSING_XPATH =
|
22
|
+
"processing-instruction()|.//processing-instruction()".freeze
|
23
|
+
|
24
|
+
def self.from_path(path)
|
25
|
+
new(File.read(path))
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(xml, local_directory = "")
|
29
|
+
@xml = xml
|
30
|
+
@local_directory = local_directory
|
31
|
+
end
|
32
|
+
|
33
|
+
def call
|
34
|
+
xmldoc = Nokogiri::XML(@xml)
|
35
|
+
@namespace = Namespace.new(xmldoc)
|
36
|
+
|
37
|
+
xmldoc.xpath(@namespace.ns("//svgmap")).each_with_index do |svgmap, index|
|
38
|
+
process_svgmap(svgmap, index)
|
39
|
+
end
|
40
|
+
|
41
|
+
xmldoc.to_xml
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def process_svgmap(svgmap, suffix)
|
47
|
+
image = extract_image_tag(svgmap)
|
48
|
+
return unless image
|
49
|
+
|
50
|
+
content = generate_content(image, svgmap, suffix)
|
51
|
+
return unless content
|
52
|
+
|
53
|
+
image.replace(content)
|
54
|
+
|
55
|
+
simplify_svgmap(svgmap)
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_image_tag(svgmap)
|
59
|
+
image = svgmap.at(@namespace.ns(".//image"))
|
60
|
+
return image if image && image["src"] && !image["src"].empty?
|
61
|
+
|
62
|
+
svgmap.at(".//m:svg", "m" => SVG_NS)
|
63
|
+
end
|
64
|
+
|
65
|
+
def generate_content(image, svgmap, suffix)
|
66
|
+
vector = build_vector(image)
|
67
|
+
return unless vector
|
68
|
+
|
69
|
+
links_map = from_targets_to_links_map(svgmap)
|
70
|
+
vector.namespace(suffix, links_map, PROCESSING_XPATH)
|
71
|
+
|
72
|
+
vector.content
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_vector(image)
|
76
|
+
return Vectory::Svg.from_content(image.to_xml) if image.name == "svg"
|
77
|
+
|
78
|
+
return unless image.name == "image"
|
79
|
+
|
80
|
+
src = image["src"]
|
81
|
+
return Vectory::Datauri.new(src).to_vector if /^data:/.match?(src)
|
82
|
+
|
83
|
+
path = @local_directory.empty? ? src : File.join(@local_directory, src)
|
84
|
+
return unless File.exist?(path)
|
85
|
+
|
86
|
+
Vectory::Svg.from_path(path)
|
87
|
+
end
|
88
|
+
|
89
|
+
def from_targets_to_links_map(svgmap)
|
90
|
+
targets = svgmap.xpath(@namespace.ns("./target"))
|
91
|
+
targets.each_with_object({}) do |target_tag, m|
|
92
|
+
target = link_target(target_tag)
|
93
|
+
next unless target
|
94
|
+
|
95
|
+
href = File.expand_path(target_tag["href"])
|
96
|
+
m[href] = target
|
97
|
+
|
98
|
+
target_tag.remove
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def link_target(target_tag)
|
103
|
+
xref = target_tag.at(@namespace.ns("./xref"))
|
104
|
+
return "##{xref['target']}" if xref
|
105
|
+
|
106
|
+
link = target_tag.at(@namespace.ns("./link"))
|
107
|
+
return unless link
|
108
|
+
|
109
|
+
link["target"]
|
110
|
+
end
|
111
|
+
|
112
|
+
def simplify_svgmap(svgmap)
|
113
|
+
return if svgmap.at(@namespace.ns("./target/eref"))
|
114
|
+
|
115
|
+
svgmap.replace(svgmap.at(@namespace.ns("./figure")))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/vectory/system_call.rb
CHANGED
@@ -2,10 +2,13 @@ require "open3"
|
|
2
2
|
|
3
3
|
module Vectory
|
4
4
|
class SystemCall
|
5
|
+
TIMEOUT = 60
|
6
|
+
|
5
7
|
attr_reader :status, :stdout, :stderr, :cmd
|
6
8
|
|
7
|
-
def initialize(cmd)
|
9
|
+
def initialize(cmd, timeout = TIMEOUT)
|
8
10
|
@cmd = cmd
|
11
|
+
@timeout = timeout
|
9
12
|
end
|
10
13
|
|
11
14
|
def call
|
@@ -27,7 +30,12 @@ module Vectory
|
|
27
30
|
end
|
28
31
|
|
29
32
|
def execute(cmd)
|
30
|
-
|
33
|
+
result = Utils.capture3_with_timeout(cmd,
|
34
|
+
timeout: @timeout,
|
35
|
+
kill_after: @timeout)
|
36
|
+
@stdout = result[:stdout]
|
37
|
+
@stderr = result[:stderr]
|
38
|
+
@status = result[:status]
|
31
39
|
rescue Errno::ENOENT => e
|
32
40
|
raise SystemCallError, e.inspect
|
33
41
|
end
|