vectory 0.1.0 → 0.3.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/.github/workflows/rake.yml +1 -1
- data/.github/workflows/release.yml +24 -0
- data/.gitignore +4 -0
- data/Gemfile +3 -1
- data/README.adoc +307 -1
- data/Rakefile +4 -0
- data/bin/vectory +9 -0
- data/emf.emf +1 -0
- data/lib/vectory/cli.rb +140 -0
- data/lib/vectory/datauri.rb +48 -0
- data/lib/vectory/emf.rb +31 -0
- data/lib/vectory/eps.rb +31 -0
- data/lib/vectory/file_magic.rb +53 -0
- data/lib/vectory/image.rb +27 -0
- data/lib/vectory/inkscape_converter.rb +99 -0
- data/lib/vectory/ps.rb +25 -0
- data/lib/vectory/svg.rb +110 -0
- data/lib/vectory/svg_mapping.rb +118 -0
- data/lib/vectory/system_call.rb +58 -0
- data/lib/vectory/utils.rb +165 -0
- data/lib/vectory/vector.rb +75 -0
- data/lib/vectory/version.rb +1 -1
- data/lib/vectory.rb +35 -1
- data/spec/examples/emf2eps/img.emf +0 -0
- data/spec/examples/emf2eps/img.emf.datauri +1 -0
- data/spec/examples/emf2eps/ref.eps +88 -0
- data/spec/examples/emf2ps/img.emf +0 -0
- data/spec/examples/emf2ps/ref.ps +125 -0
- data/spec/examples/emf2svg/img.emf +0 -0
- data/spec/examples/emf2svg/ref.svg +9 -0
- data/spec/examples/eps2emf/img.eps +199 -0
- data/spec/examples/eps2emf/img.eps.datauri +1 -0
- data/spec/examples/eps2emf/ref.emf +0 -0
- data/spec/examples/eps2ps/img.eps +199 -0
- data/spec/examples/eps2ps/ref.ps +549 -0
- data/spec/examples/eps2svg/img.eps +199 -0
- data/spec/examples/eps2svg/ref.svg +173 -0
- data/spec/examples/eps_but_svg_extension.svg +199 -0
- data/spec/examples/img.jpg +0 -0
- data/spec/examples/ps2emf/img.ps +549 -0
- data/spec/examples/ps2emf/img.ps.datauri +1 -0
- data/spec/examples/ps2emf/ref.emf +0 -0
- data/spec/examples/ps2eps/img.ps +549 -0
- data/spec/examples/ps2eps/ref.eps +844 -0
- data/spec/examples/ps2svg/img.ps +549 -0
- data/spec/examples/ps2svg/ref.svg +476 -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/examples/svg2emf/img.svg +1 -0
- data/spec/examples/svg2emf/img.svg.datauri +1 -0
- data/spec/examples/svg2emf/ref.emf +0 -0
- data/spec/examples/svg2eps/img.svg +1 -0
- data/spec/examples/svg2eps/ref.eps +88 -0
- data/spec/examples/svg2ps/img.svg +1 -0
- data/spec/examples/svg2ps/ref.ps +125 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/matchers.rb +39 -0
- data/spec/support/text_matcher.rb +63 -0
- data/spec/support/vectory_helper.rb +31 -0
- data/spec/vectory/cli_spec.rb +214 -0
- data/spec/vectory/datauri_spec.rb +101 -0
- data/spec/vectory/emf_spec.rb +38 -0
- data/spec/vectory/eps_spec.rb +40 -0
- data/spec/vectory/file_magic_spec.rb +24 -0
- data/spec/vectory/inkscape_converter_spec.rb +43 -0
- data/spec/vectory/ps_spec.rb +33 -0
- data/spec/vectory/svg_mapping_spec.rb +42 -0
- data/spec/vectory/svg_spec.rb +41 -0
- data/spec/vectory/vector_spec.rb +60 -0
- data/tmp/.keep +0 -0
- data/vectory.gemspec +6 -3
- metadata +116 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 865823bf5ac58c0780cdffc76abf7d396c2b481bcf292c807e419c0983f44646
|
|
4
|
+
data.tar.gz: cd29b9a6f1c3a851e37fa207427474a60656ad8a1ba6f27d954d08d2ded47f5d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 01ee6626bca7c7a61f14dffa639355171e052637f9b1c58d4dfb39721a7b7a815e6b11cd5c1deb76b4faecba37abf873e45661c16ebd2eaf7434cb9031a6deff
|
|
7
|
+
data.tar.gz: 6706861380815c36d273445cc970db3b01693024208596c8072e9661ab301908db5c6c81e7d707826b501263aac8dbcc4b65f553fc62857a773cb45404d53de4
|
data/.github/workflows/rake.yml
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
|
2
|
+
# See https://github.com/metanorma/cimas
|
|
3
|
+
name: release
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
next_version:
|
|
9
|
+
description: |
|
|
10
|
+
Next release version. Possible values: x.y.z, major, minor, patch or pre|rc|etc
|
|
11
|
+
required: true
|
|
12
|
+
default: 'skip'
|
|
13
|
+
push:
|
|
14
|
+
tags: [ v* ]
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
release:
|
|
18
|
+
uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
|
|
19
|
+
with:
|
|
20
|
+
next_version: ${{ github.event.inputs.next_version }}
|
|
21
|
+
secrets:
|
|
22
|
+
rubygems-api-key: ${{ secrets.METANORMA_CI_RUBYGEMS_API_KEY }}
|
|
23
|
+
pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
|
24
|
+
|
data/.gitignore
ADDED
data/Gemfile
CHANGED
data/README.adoc
CHANGED
|
@@ -11,6 +11,11 @@ image:https://img.shields.io/github/commits-since/metanorma/vectory/latest.svg["
|
|
|
11
11
|
Vectory is a Ruby gem that performs pairwise vector image conversions for common
|
|
12
12
|
vector image formats (EPS, PS, EMF, SVG).
|
|
13
13
|
|
|
14
|
+
[quote]
|
|
15
|
+
____
|
|
16
|
+
Vectory shall give you a glorious vectory over EPS files.
|
|
17
|
+
____
|
|
18
|
+
|
|
14
19
|
|
|
15
20
|
== Installation
|
|
16
21
|
|
|
@@ -20,6 +25,10 @@ Vectory relies on the following software to be installed:
|
|
|
20
25
|
|
|
21
26
|
* https://github.com/metanorma/emf2svg-ruby[emf2svg-ruby]
|
|
22
27
|
* https://inkscape.org[Inkscape]
|
|
28
|
+
* https://www.ghostscript.com/[Ghostscript]
|
|
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.
|
|
23
32
|
|
|
24
33
|
|
|
25
34
|
=== Gem install
|
|
@@ -43,7 +52,304 @@ Where,
|
|
|
43
52
|
|
|
44
53
|
`format`:: the desired output format (one of: `svg`, `eps`, `ps`, `emf`)
|
|
45
54
|
`input-file-name`:: file path to the input file
|
|
46
|
-
`output-file-name`:: file path to the desired output file (with the
|
|
55
|
+
`output-file-name`:: file path to the desired output file (with the
|
|
56
|
+
file extension) (default: writes to a current directory by the input filename
|
|
57
|
+
with an extension changed to a desired format)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
=== Using the Ruby library
|
|
61
|
+
|
|
62
|
+
Some examples:
|
|
63
|
+
|
|
64
|
+
Take EMF as a path to a file and return SVG as a string:
|
|
65
|
+
|
|
66
|
+
[source,ruby]
|
|
67
|
+
----
|
|
68
|
+
path = "path/to/file.emf"
|
|
69
|
+
|
|
70
|
+
Vectory::Emf.from_path(path).to_svg.content
|
|
71
|
+
----
|
|
72
|
+
|
|
73
|
+
Take EPS as a string and return EMF as a path to a file:
|
|
74
|
+
|
|
75
|
+
[source,ruby]
|
|
76
|
+
----
|
|
77
|
+
# NOTE: content is shortened for readability
|
|
78
|
+
content = "%!PS-Adobe-3.0 EPSF-3.0\n ... %%Trailer"
|
|
79
|
+
|
|
80
|
+
Vectory::Eps.from_content(content).to_emf.write.path
|
|
81
|
+
----
|
|
82
|
+
|
|
83
|
+
Take SVG as a datauri and return EMF as a datauri:
|
|
84
|
+
|
|
85
|
+
[source,ruby]
|
|
86
|
+
----
|
|
87
|
+
# NOTE: datauri is shortened for readability
|
|
88
|
+
uri = "data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0 ... GRkYiLz48L3N2Zz4="
|
|
89
|
+
|
|
90
|
+
Vectory::Datauri.new(uri).to_vector.to_emf.to_uri.content
|
|
91
|
+
----
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
==== What is supported?
|
|
95
|
+
|
|
96
|
+
There are several vector classes which support conversion between each other:
|
|
97
|
+
|
|
98
|
+
[source,ruby]
|
|
99
|
+
----
|
|
100
|
+
Vectory::Eps
|
|
101
|
+
Vectory::Ps
|
|
102
|
+
Vectory::Emf
|
|
103
|
+
Vectory::Svg
|
|
104
|
+
----
|
|
105
|
+
|
|
106
|
+
Each of them can be instantiated in several ways:
|
|
107
|
+
|
|
108
|
+
[source,ruby]
|
|
109
|
+
----
|
|
110
|
+
Vectory::Eps.from_path("images/img.eps")
|
|
111
|
+
Vectory::Eps.from_content("%!PS-Adobe-3.0...")
|
|
112
|
+
----
|
|
113
|
+
|
|
114
|
+
Converting to other formats:
|
|
115
|
+
|
|
116
|
+
[source,ruby]
|
|
117
|
+
----
|
|
118
|
+
Vectory::Eps.from_content(content).to_ps
|
|
119
|
+
Vectory::Eps.from_content(content).to_emf
|
|
120
|
+
Vectory::Eps.from_content(content).to_svg
|
|
121
|
+
----
|
|
122
|
+
|
|
123
|
+
Several ways of getting content of an object:
|
|
124
|
+
|
|
125
|
+
[source,ruby]
|
|
126
|
+
----
|
|
127
|
+
Vectory::Eps.from_content(content).to_svg.content
|
|
128
|
+
Vectory::Eps.from_content(content).to_svg.to_uri.content # as datauri
|
|
129
|
+
Vectory::Eps.from_content(content).to_svg.write.path
|
|
130
|
+
----
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
==== Datauri
|
|
134
|
+
|
|
135
|
+
Also there is the `Vectory::Datauri` class which represents vectory images in
|
|
136
|
+
the datauri format.
|
|
137
|
+
|
|
138
|
+
Convert an SVG datauri to a plain SVG:
|
|
139
|
+
|
|
140
|
+
[source,ruby]
|
|
141
|
+
----
|
|
142
|
+
# NOTE: datauri is shortened for readability
|
|
143
|
+
uri = "data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0 ... GRkYiLz48L3N2Zz4="
|
|
144
|
+
Vectory::Datauri.new(uri).to_vector.content
|
|
145
|
+
----
|
|
146
|
+
|
|
147
|
+
Convert an EPS file to its datauri representation:
|
|
148
|
+
|
|
149
|
+
[source,ruby]
|
|
150
|
+
----
|
|
151
|
+
eps = Vectory::Eps.from_path("img.eps")
|
|
152
|
+
Vectory::Datauri.from_vector(eps).content
|
|
153
|
+
----
|
|
154
|
+
|
|
155
|
+
There is also a simplified API for this case:
|
|
156
|
+
|
|
157
|
+
[source,ruby]
|
|
158
|
+
----
|
|
159
|
+
Vectory::Eps.from_path("img.eps").to_uri.content
|
|
160
|
+
----
|
|
161
|
+
|
|
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
|
+
|
|
288
|
+
==== File system operations
|
|
289
|
+
|
|
290
|
+
An image object contains information where it is written. It can be obtained
|
|
291
|
+
with the `#path` API:
|
|
292
|
+
|
|
293
|
+
[source,ruby]
|
|
294
|
+
----
|
|
295
|
+
vector = Vectory::Eps.from_path("img.eps")
|
|
296
|
+
vector.path
|
|
297
|
+
----
|
|
298
|
+
|
|
299
|
+
Before the first write it raises the `NotWrittenToDiskError` error:
|
|
300
|
+
|
|
301
|
+
[source,ruby]
|
|
302
|
+
----
|
|
303
|
+
vector.path # => raise NotWrittenToDiskError
|
|
304
|
+
----
|
|
305
|
+
|
|
306
|
+
After writing it returns a path of the image on a disk:
|
|
307
|
+
|
|
308
|
+
[source,ruby]
|
|
309
|
+
----
|
|
310
|
+
vector.write
|
|
311
|
+
vector.path # => "/tmp/xxx/yyy"
|
|
312
|
+
----
|
|
313
|
+
|
|
314
|
+
By default it writes to a temporary directory but it can be changed by
|
|
315
|
+
providing an argument with a desired path:
|
|
316
|
+
|
|
317
|
+
[source,ruby]
|
|
318
|
+
----
|
|
319
|
+
vector.write("images/img.eps")
|
|
320
|
+
vector.path # => "images/img.eps"
|
|
321
|
+
----
|
|
322
|
+
|
|
323
|
+
Since an image can be initially read from a disk, it also keeps an initial
|
|
324
|
+
path. To avoid accidental overwrite, this path is used only for read-only
|
|
325
|
+
purposes.
|
|
326
|
+
|
|
327
|
+
[source,ruby]
|
|
328
|
+
----
|
|
329
|
+
vector.initial_path # => "storage/images/img.eps"
|
|
330
|
+
----
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
== Development
|
|
334
|
+
|
|
335
|
+
=== Releasing
|
|
336
|
+
|
|
337
|
+
Releasing is done automatically with GitHub Actions. Just bump and tag with
|
|
338
|
+
`gem-release`.
|
|
339
|
+
|
|
340
|
+
For a patch release (0.0.x) use:
|
|
341
|
+
|
|
342
|
+
[source,sh]
|
|
343
|
+
----
|
|
344
|
+
gem bump --version patch --tag --push
|
|
345
|
+
----
|
|
346
|
+
|
|
347
|
+
For a minor release (0.x.0) use:
|
|
348
|
+
|
|
349
|
+
[source,sh]
|
|
350
|
+
----
|
|
351
|
+
gem bump --version minor --tag --push
|
|
352
|
+
----
|
|
47
353
|
|
|
48
354
|
|
|
49
355
|
== Contributing
|
data/Rakefile
CHANGED
data/bin/vectory
ADDED
data/emf.emf
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AQAAAMgAAAAAAAAAAAAAAPsEAAD7BAAAAAAAAAAAAACLCgAAiwoAACBFTUYAAAEAJAQAACgAAAACAAAALgAAAGwAAAAAAAAA3ScAAH0zAADYAAAAFwEAAAAAAAAAAAAAAAAAAMBLAwDYQQQASQBuAGsAcwBjAGEAcABlACAAMQAuADAAIAAoADQAMAAzADUAYQA0AGYALAAgADIAMAAyADAALQAwADUALQAwADEAKQAgAAAAbwBkAGYALgBlAG0AZgAAAAAAAAARAAAADAAAAAEAAAAkAAAAJAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAIAAABGAAAALAAAACAAAABTY3JlZW49MTAyMDV4MTMxODFweCwgMjE2eDI3OW1tAEYAAAAwAAAAIwAAAERyYXdpbmc9MTAwLjB4MTAwLjBweCwgMjYuNXgyNi41bW0AABIAAAAMAAAAAQAAABMAAAAMAAAAAgAAABYAAAAMAAAAGAAAABgAAAAMAAAAAAAAABQAAAAMAAAADQAAACcAAAAYAAAAAQAAAAAAAAAAAJkABgAAACUAAAAMAAAAAQAAADsAAAAIAAAAGwAAABAAAACkBAAAcQIAAAUAAAA0AAAAAAAAAAAAAAD//////////wMAAACkBAAAqAMAAKgDAACkBAAAcQIAAKQEAAAFAAAANAAAAAAAAAAAAAAA//////////8DAAAAOgEAAKQEAAA/AAAAqAMAAD8AAABxAgAABQAAADQAAAAAAAAAAAAAAP//////////AwAAAD8AAAA6AQAAOgEAAD8AAABxAgAAPwAAAAUAAAA0AAAAAAAAAAAAAAD//////////wMAAACoAwAAPwAAAKQEAAA6AQAApAQAAHECAAA9AAAACAAAADwAAAAIAAAAPgAAABgAAAAAAAAAAAAAAP//////////JQAAAAwAAAAFAACAKAAAAAwAAAABAAAAJwAAABgAAAABAAAAAAAAAP///wAGAAAAJQAAAAwAAAABAAAAOwAAAAgAAAAbAAAAEAAAAJ0BAABFAQAANgAAABAAAADPAwAARQEAAAUAAAA0AAAAAAAAAAAAAAD//////////wMAAABfBAAA7QEAAGQEAADjAgAA2wMAAJEDAAAFAAAANAAAAAAAAAAAAAAA//////////8DAAAAUgMAAD4EAABhAgAAcwQAAJ0BAAAOBAAANgAAABAAAACdAQAAyQIAADYAAAAQAAAA4gIAAMkCAAA2AAAAEAAAAOICAAAaAgAANgAAABAAAACdAQAAGgIAAD0AAAAIAAAAPAAAAAgAAAA+AAAAGAAAAAAAAAAAAAAA//////////8lAAAADAAAAAUAAIAoAAAADAAAAAEAAAAOAAAAFAAAAAAAAAAAAAAAJAQAAA==
|
data/lib/vectory/cli.rb
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
require "thor"
|
|
2
|
+
require_relative "../vectory"
|
|
3
|
+
require_relative "file_magic"
|
|
4
|
+
|
|
5
|
+
module Vectory
|
|
6
|
+
class CLI < Thor
|
|
7
|
+
STATUS_SUCCESS = 0
|
|
8
|
+
STATUS_UNKNOWN_ERROR = 1
|
|
9
|
+
STATUS_UNSUPPORTED_INPUT_FORMAT_ERROR = 2
|
|
10
|
+
STATUS_UNSUPPORTED_OUTPUT_FORMAT_ERROR = 3
|
|
11
|
+
STATUS_CONVERSION_ERROR = 4
|
|
12
|
+
STATUS_SYSTEM_CALL_ERROR = 5
|
|
13
|
+
STATUS_INKSCAPE_NOT_FOUND_ERROR = 6
|
|
14
|
+
|
|
15
|
+
MAP_ERROR_TO_STATUS = {
|
|
16
|
+
Vectory::ConversionError => STATUS_CONVERSION_ERROR,
|
|
17
|
+
Vectory::InkscapeNotFoundError => STATUS_INKSCAPE_NOT_FOUND_ERROR,
|
|
18
|
+
Vectory::SystemCallError => STATUS_SYSTEM_CALL_ERROR,
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
module SupportedInputFormats
|
|
22
|
+
EPS = :eps
|
|
23
|
+
PS = :ps
|
|
24
|
+
SVG = :svg
|
|
25
|
+
EMF = :emf
|
|
26
|
+
|
|
27
|
+
def self.all
|
|
28
|
+
constants.map { |x| const_get(x) }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module SupportedOutputFormats
|
|
33
|
+
EPS = "eps".freeze
|
|
34
|
+
PS = "ps".freeze
|
|
35
|
+
SVG = "svg".freeze
|
|
36
|
+
EMF = "emf".freeze
|
|
37
|
+
|
|
38
|
+
def self.all
|
|
39
|
+
constants.map { |x| const_get(x) }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.exit_on_failure?
|
|
44
|
+
false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
desc "convert INPUT_FILE_NAME",
|
|
48
|
+
"Perform pairwise vector image conversions for common vector image " \
|
|
49
|
+
"formats (EPS, PS, EMF, SVG)"
|
|
50
|
+
option :format,
|
|
51
|
+
aliases: :f,
|
|
52
|
+
required: true,
|
|
53
|
+
desc: "the desired output format (one of: svg, eps, ps, emf)"
|
|
54
|
+
|
|
55
|
+
option :output,
|
|
56
|
+
aliases: :o,
|
|
57
|
+
desc: "file path to the desired output file (with the file " \
|
|
58
|
+
"extension)"
|
|
59
|
+
def convert(file)
|
|
60
|
+
unless supported_format?(options[:format])
|
|
61
|
+
return unsupported_format_error(options[:format])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
input_format = detect_input_format(file)
|
|
65
|
+
unless supported_input_format?(input_format)
|
|
66
|
+
return unsupported_input_format_error
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
object = source_object(file, input_format)
|
|
70
|
+
|
|
71
|
+
convert_to_format(object, options)
|
|
72
|
+
end
|
|
73
|
+
default_task :convert
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def supported_format?(format)
|
|
78
|
+
SupportedOutputFormats.all.include?(format)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def unsupported_format_error(format)
|
|
82
|
+
formats = SupportedOutputFormats.all.map { |v| "'#{v}'" }.join(", ")
|
|
83
|
+
|
|
84
|
+
Vectory.ui.error(
|
|
85
|
+
"Unsupported output format '#{format}'. " \
|
|
86
|
+
"Please choose one of: #{formats}.",
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
STATUS_UNSUPPORTED_OUTPUT_FORMAT_ERROR
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def detect_input_format(file)
|
|
93
|
+
FileMagic.detect(file)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def supported_input_format?(format)
|
|
97
|
+
SupportedInputFormats.all.include?(format)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def unsupported_input_format_error
|
|
101
|
+
formats = SupportedInputFormats.all.map { |v| "'#{v}'" }.join(", ")
|
|
102
|
+
Vectory.ui.error(
|
|
103
|
+
"Could not detect input format. " \
|
|
104
|
+
"Please provide file of the following formats: #{formats}.",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
STATUS_UNSUPPORTED_INPUT_FORMAT_ERROR
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def source_object(file, format)
|
|
111
|
+
Vectory.const_get(format.capitalize).from_path(file)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def convert_to_format(object, options)
|
|
115
|
+
path = options[:output] || current_dir_path(object.initial_path,
|
|
116
|
+
options[:format])
|
|
117
|
+
to_format(object, options[:format]).write(path)
|
|
118
|
+
Vectory.ui.info("Output file was written to #{path}")
|
|
119
|
+
|
|
120
|
+
STATUS_SUCCESS
|
|
121
|
+
rescue Vectory::Error => e
|
|
122
|
+
handle_vectory_error(e)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def handle_vectory_error(exception)
|
|
126
|
+
Vectory.ui.error(exception.message)
|
|
127
|
+
|
|
128
|
+
MAP_ERROR_TO_STATUS[exception.class] || raise(exception)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def current_dir_path(input_path, output_format)
|
|
132
|
+
File.join(Dir.pwd, "#{File.basename(input_path, '.*')}.#{output_format}")
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def to_format(object, format)
|
|
136
|
+
method_name = "to_#{format}"
|
|
137
|
+
object.public_send(method_name)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "base64"
|
|
2
|
+
|
|
3
|
+
module Vectory
|
|
4
|
+
class Datauri < Image
|
|
5
|
+
REGEX = %r{^
|
|
6
|
+
data:
|
|
7
|
+
(?<mimetype>[^;]+);
|
|
8
|
+
(?:charset=[^;]+;)?
|
|
9
|
+
base64,
|
|
10
|
+
(?<data>.+)
|
|
11
|
+
$}x.freeze
|
|
12
|
+
|
|
13
|
+
def self.from_vector(vector)
|
|
14
|
+
mimetype = vector.class.mimetype
|
|
15
|
+
content = vector.content.gsub("\r\n", "\n")
|
|
16
|
+
data = Base64.strict_encode64(content)
|
|
17
|
+
|
|
18
|
+
new("data:#{mimetype};base64,#{data}")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_vector
|
|
22
|
+
match = parse_datauri(@content)
|
|
23
|
+
content = Base64.strict_decode64(match[:data])
|
|
24
|
+
image_class = detect_image_class(match[:mimetype])
|
|
25
|
+
|
|
26
|
+
image_class.from_content(content)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def parse_datauri(uri)
|
|
32
|
+
match = REGEX.match(uri)
|
|
33
|
+
return match if match
|
|
34
|
+
|
|
35
|
+
raise ConversionError, "Could not parse datauri: '#{uri.slice(0, 30)}'."
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def detect_image_class(image_type)
|
|
39
|
+
case image_type
|
|
40
|
+
when Eps.mimetype then return Eps
|
|
41
|
+
when Emf.mimetype then return Emf
|
|
42
|
+
when Svg.mimetype then return Svg
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
raise ConversionError, "Could not detect image type '#{image_type}'."
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/vectory/emf.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf2svg"
|
|
4
|
+
|
|
5
|
+
module Vectory
|
|
6
|
+
class Emf < Vector
|
|
7
|
+
def self.default_extension
|
|
8
|
+
"emf"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.mimetype
|
|
12
|
+
"image/emf"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_svg
|
|
16
|
+
with_file("emf") do |input_path|
|
|
17
|
+
content = Emf2svg.from_file(input_path).sub(/<\?[^>]+>/, "")
|
|
18
|
+
|
|
19
|
+
Svg.from_content(content)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_eps
|
|
24
|
+
convert_with_inkscape("--export-type=eps", Eps)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_ps
|
|
28
|
+
convert_with_inkscape("--export-type=ps", Ps)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/vectory/eps.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Vectory
|
|
4
|
+
class Eps < Vector
|
|
5
|
+
def self.default_extension
|
|
6
|
+
"eps"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.mimetype
|
|
10
|
+
"application/postscript"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_ps
|
|
14
|
+
convert_with_inkscape("--export-type=ps", Ps)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_svg
|
|
18
|
+
convert_with_inkscape("--export-plain-svg --export-type=svg", Svg)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_emf
|
|
22
|
+
convert_with_inkscape("--export-type=emf", Emf)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def imgfile_suffix(uri, suffix)
|
|
28
|
+
"#{File.join(File.dirname(uri), File.basename(uri, '.*'))}.#{suffix}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|