inkmake 0.1.1 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/inkmake.rb +176 -75
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e8f974d5799a2dad944fc34bc8ff9ee6357493f19166ccdf8baa93db3e76dac3
|
4
|
+
data.tar.gz: 03777d34d7aa798e57cb6f7a3ea55300284157c424636aa551ee6502eb9f4ddd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddf8cdeefbfbf3b7f3aff2cfcebfb48cc8f6916d96f56794fabec3470e9e382fa12eeb65c14a016aeb0c12406542ba98255d62c8c677979166f531abcf1cd5c7
|
7
|
+
data.tar.gz: f68bb1b2b9229aee3d8f64038dfcccf5ea615b2770115419e049741c9ce31b77ceefca1801afef005feae83f3a683ee1ff4f73d5db67d48827ded5754289b0cf
|
data/lib/inkmake.rb
CHANGED
@@ -113,9 +113,11 @@ class Inkmake
|
|
113
113
|
end
|
114
114
|
|
115
115
|
class InkscapeRemote
|
116
|
+
attr_reader :inkscape_version
|
117
|
+
|
116
118
|
def initialize
|
117
|
-
|
118
|
-
|
119
|
+
@inkscape_version = probe_inkscape_version
|
120
|
+
open_shell
|
119
121
|
yield self
|
120
122
|
ensure
|
121
123
|
quit
|
@@ -125,14 +127,38 @@ class Inkmake
|
|
125
127
|
@is_windows ||= (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/) != nil
|
126
128
|
end
|
127
129
|
|
128
|
-
def open
|
130
|
+
def open(args)
|
129
131
|
if is_windows
|
130
|
-
# Inkscape on Windows for some reason needs to run from its binary dir
|
131
|
-
|
132
|
+
# Inkscape on Windows for some reason needs to run from its binary dir.
|
133
|
+
# popen2e so get stdout and stderr in one pipe. inkscape 1 shell seems to
|
134
|
+
# use both as output and we need to read to not block it.
|
135
|
+
Open3.popen2e(*[File.basename(self.class.path)] + args,
|
132
136
|
:chdir => File.dirname(self.class.path))
|
133
137
|
else
|
134
|
-
|
138
|
+
Open3.popen2e(*[self.class.path] + args)
|
135
139
|
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def response
|
143
|
+
if @inkscape_version == 0
|
144
|
+
o = @out.getc
|
145
|
+
if o == ">"
|
146
|
+
puts "1> #{o}" if Inkmake.verbose
|
147
|
+
return :prompt;
|
148
|
+
end
|
149
|
+
else
|
150
|
+
o = @out.getc + @out.getc
|
151
|
+
if o == "> "
|
152
|
+
puts "1> #{o}" if Inkmake.verbose
|
153
|
+
return :prompt;
|
154
|
+
end
|
155
|
+
end
|
156
|
+
o = o + @out.readline
|
157
|
+
puts "2> '#{o}'" if Inkmake.verbose
|
158
|
+
o
|
159
|
+
end
|
160
|
+
|
161
|
+
def wait_prompt
|
136
162
|
loop do
|
137
163
|
case response
|
138
164
|
when :prompt then break
|
@@ -140,7 +166,12 @@ class Inkmake
|
|
140
166
|
end
|
141
167
|
end
|
142
168
|
|
143
|
-
def
|
169
|
+
def open_shell
|
170
|
+
@in, @out = open(["--shell"])
|
171
|
+
wait_prompt
|
172
|
+
end
|
173
|
+
|
174
|
+
def command0(args)
|
144
175
|
c = args.collect do |key, value|
|
145
176
|
if value
|
146
177
|
"\"#{key}=#{self.class.escape value.to_s}\""
|
@@ -148,54 +179,42 @@ class Inkmake
|
|
148
179
|
key
|
149
180
|
end
|
150
181
|
end.join(" ")
|
151
|
-
puts "
|
182
|
+
puts "< #{c}" if Inkmake.verbose
|
152
183
|
@in.write "#{c}\n"
|
153
184
|
@in.flush
|
154
185
|
end
|
155
186
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
187
|
+
def command1(args)
|
188
|
+
c = args.collect do |key, value|
|
189
|
+
if value
|
190
|
+
"#{key}:#{value.to_s}"
|
191
|
+
else
|
192
|
+
"#{key}:"
|
193
|
+
end
|
194
|
+
end.join("\n")
|
195
|
+
puts "< #{c}" if Inkmake.verbose
|
196
|
+
@in.write "#{c}\n"
|
197
|
+
@in.flush
|
165
198
|
end
|
166
199
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
# trying to use env inkmake is running in is also not so portable (windows?)
|
171
|
-
def probe_decimal_symbol
|
172
|
-
svg =
|
173
|
-
"<?xml version=\"1.0\"?>" +
|
174
|
-
"<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"1\" height=\"1\">" +
|
175
|
-
"</svg>"
|
176
|
-
f = Tempfile.new("inkmake")
|
177
|
-
f.write(svg)
|
178
|
-
f.flush
|
200
|
+
def probe_inkscape_version
|
201
|
+
_in, out = open(["--version"])
|
202
|
+
version = 0
|
179
203
|
begin
|
180
|
-
command({
|
181
|
-
"--file" => f.path,
|
182
|
-
"--export-png" => Tempfile.new("inkmake").path,
|
183
|
-
"--export-area" => "0.0:0.0:1.0:1.0",
|
184
|
-
})
|
185
204
|
loop do
|
186
|
-
case
|
187
|
-
when
|
205
|
+
case out.readline()
|
206
|
+
when /^\s*Inkscape 1\..*$/ then
|
207
|
+
version = 1
|
208
|
+
when /^\s*Inkscape 0\..*$/ then
|
209
|
+
version = 0
|
188
210
|
end
|
189
211
|
end
|
190
|
-
@decimal_symbol = "."
|
191
212
|
rescue EOFError
|
192
|
-
@decimal_symbol = ","
|
193
|
-
# restart inkscape
|
194
|
-
open
|
195
213
|
end
|
214
|
+
version
|
196
215
|
end
|
197
216
|
|
198
|
-
def
|
217
|
+
def export0(opts)
|
199
218
|
c = {
|
200
219
|
"--file" => opts[:svg_path],
|
201
220
|
"--export-#{opts[:format]}" => opts[:out_path]
|
@@ -209,41 +228,109 @@ class Inkmake
|
|
209
228
|
c["--export-dpi"] = opts[:dpi]
|
210
229
|
end
|
211
230
|
if opts[:area].kind_of? Array
|
212
|
-
c["--export-area"] = ("%f:%f:%f:%f" % opts[:area])
|
231
|
+
c["--export-area"] = ("%f:%f:%f:%f" % opts[:area])
|
213
232
|
elsif opts[:area] == :drawing
|
214
233
|
c["--export-area-drawing"] = nil
|
215
234
|
elsif opts[:area].kind_of? String
|
216
235
|
c["--export-id"] = opts[:area]
|
217
236
|
end
|
218
|
-
|
237
|
+
command0(c)
|
238
|
+
width, height = [0, 0]
|
239
|
+
loop do
|
240
|
+
case response
|
241
|
+
when /^Area .* exported to (\d+) x (\d+) pixels.*$/ then
|
242
|
+
width = $1
|
243
|
+
height = $2
|
244
|
+
when :prompt then break
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
[width, height]
|
249
|
+
end
|
250
|
+
|
251
|
+
def export1(opts)
|
252
|
+
c = [
|
253
|
+
["file-open", opts[:svg_path]],
|
254
|
+
["export-type", opts[:format]],
|
255
|
+
["export-filename", opts[:out_path]]
|
256
|
+
]
|
257
|
+
if opts[:res]
|
258
|
+
s = opts[:rotate_scale_hack] ? 2 : 1
|
259
|
+
c += [["export-width", opts[:res].width.to_pixels(opts[:dpi] || 90) * s]]
|
260
|
+
c += [["export-height", opts[:res].height.to_pixels(opts[:dpi] || 90) * s]]
|
261
|
+
else
|
262
|
+
c += [["export-width", ""]]
|
263
|
+
c += [["export-height", ""]]
|
264
|
+
end
|
265
|
+
if opts[:dpi]
|
266
|
+
c += [["export-dpi", opts[:dpi]]]
|
267
|
+
end
|
268
|
+
|
269
|
+
c += [["export-area", ""]]
|
270
|
+
c += [["export-area-drawing", "false"]]
|
271
|
+
c += [["export-id", ""]]
|
272
|
+
c += [["export-area-page", "false"]]
|
273
|
+
|
274
|
+
if opts[:area].kind_of? Array
|
275
|
+
c += [["export-area", ("%f:%f:%f:%f" % opts[:area])]]
|
276
|
+
elsif opts[:area] == :drawing
|
277
|
+
c += [["export-area-drawing", "true"]]
|
278
|
+
elsif opts[:area].kind_of? String
|
279
|
+
c += [["export-id", opts[:area]]]
|
280
|
+
else
|
281
|
+
c += [["export-area-page", "true"]]
|
282
|
+
end
|
283
|
+
c.each do |a|
|
284
|
+
command1([a])
|
285
|
+
wait_prompt
|
286
|
+
end
|
287
|
+
|
288
|
+
command1([["export-do"]])
|
219
289
|
width, height = [0, 0]
|
220
|
-
out = nil
|
221
290
|
loop do
|
222
291
|
case response
|
223
|
-
when /^Bitmap saved as: (.*)$/ then
|
224
|
-
out = $1
|
225
292
|
when /^Area .* exported to (\d+) x (\d+) pixels.*$/ then
|
226
293
|
width = $1
|
227
294
|
height = $2
|
228
295
|
when :prompt then break
|
229
296
|
end
|
230
297
|
end
|
298
|
+
command1([["file-close"]])
|
299
|
+
wait_prompt
|
231
300
|
|
232
301
|
[width, height]
|
233
302
|
end
|
234
303
|
|
304
|
+
def export(opts)
|
305
|
+
if @inkscape_version == 0 then
|
306
|
+
export0(opts)
|
307
|
+
else
|
308
|
+
export1(opts)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
235
312
|
def query_all(file)
|
236
313
|
ids = []
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
314
|
+
if @inkscape_version == 0 then
|
315
|
+
command0({
|
316
|
+
"--file" => file,
|
317
|
+
"--query-all" => nil,
|
318
|
+
})
|
319
|
+
else
|
320
|
+
command1([["file-open", file]])
|
321
|
+
wait_prompt
|
322
|
+
command1([["query-all", file]])
|
323
|
+
end
|
241
324
|
loop do
|
242
325
|
case response
|
243
326
|
when /^(.*),(.*),(.*),(.*),(.*)$/ then ids << [$1, $2.to_f, $3.to_f, $4.to_f, $5.to_f]
|
244
327
|
when :prompt then break
|
245
328
|
end
|
246
329
|
end
|
330
|
+
if @inkscape_version == 1 then
|
331
|
+
command1([["file-close", file]])
|
332
|
+
wait_prompt
|
333
|
+
end
|
247
334
|
ids
|
248
335
|
end
|
249
336
|
|
@@ -256,23 +343,30 @@ class Inkmake
|
|
256
343
|
end
|
257
344
|
|
258
345
|
def quit
|
259
|
-
|
346
|
+
if @inkscape_version == 0 then
|
347
|
+
command0({"quit" => nil})
|
348
|
+
else
|
349
|
+
@in.close
|
350
|
+
end
|
260
351
|
@out.read
|
261
352
|
nil
|
262
353
|
end
|
263
354
|
|
264
355
|
def self.escape(s)
|
265
|
-
s.gsub(/(["'])/, '\\\\\1')
|
356
|
+
s.gsub(/([\\"'])/, '\\\\\1')
|
266
357
|
end
|
267
358
|
|
268
359
|
def self.path
|
269
360
|
return Inkmake.inkscape_path if Inkmake.inkscape_path
|
270
361
|
|
271
362
|
# try to figure out inkscape path
|
272
|
-
p = (
|
273
|
-
(["/Applications/Inkscape.app/Contents/
|
363
|
+
p = (
|
364
|
+
(["/Applications/Inkscape.app/Contents/MacOS/inkscape",
|
365
|
+
"/Applications/Inkscape.app/Contents/Resources/bin/inkscape",
|
274
366
|
'c:\Program Files\Inkscape\inkscape.exe',
|
275
|
-
'c:\Program Files
|
367
|
+
'c:\Program Files\Inkscape\bin\inkscape.exe',
|
368
|
+
'c:\Program Files (x86)\Inkscape\inkscape.exe',
|
369
|
+
'c:\Program Files (x86)\Inkscape\bin\inkscape.exe'] +
|
276
370
|
(ENV['PATH'].split(':').map {|p| File.join(p, "inkscape")}))
|
277
371
|
.select do |path|
|
278
372
|
File.exists? path
|
@@ -283,7 +377,12 @@ class Inkmake
|
|
283
377
|
else
|
284
378
|
begin
|
285
379
|
require "osx/cocoa"
|
286
|
-
|
380
|
+
app_path = OSX::NSWorkspace.sharedWorkspace.fullPathForApplication:"Inkscape"
|
381
|
+
["#{app_path}/Contents/MacOS/inkscape",
|
382
|
+
"#{app_path}/Contents/Resources/bin/inkscape"]
|
383
|
+
.select do |path|
|
384
|
+
File.exists? path
|
385
|
+
end
|
287
386
|
rescue NameError, LoadError
|
288
387
|
nil
|
289
388
|
end
|
@@ -303,29 +402,29 @@ class Inkmake
|
|
303
402
|
}
|
304
403
|
# 123x123, 12.3cm*12.3cm
|
305
404
|
RES_RE = /^(\d+(?:\.\d+)?(?:px|pt|pc|mm|cm|dm|m|in|ft|uu)?)[x*](\d+(?:\.\d+)?(?:px|pt|pc|mm|cm|dm|m|in|ft|uu)?)$/
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
405
|
+
# *123, *1.23
|
406
|
+
SCALE_RE = /^\*(\d+(?:\.\d+)?)$/
|
407
|
+
# 180dpi
|
408
|
+
DPI_RE = /^(\d+(?:\.\d+)?)dpi$/i
|
310
409
|
# (prefix)[(...)](suffix)
|
311
410
|
DEST_RE = /^([^\[]*)(?:\[(.*)\])?(.*)$/
|
312
|
-
|
313
|
-
|
411
|
+
# test.svg, test.SVG
|
412
|
+
SVG_RE = /\.svg$/i
|
314
413
|
# ext to format, supported inkscape output formats
|
315
414
|
EXT_RE = /\.(png|pdf|ps|eps)$/i
|
316
415
|
# supported inkscape output formats
|
317
416
|
FORMAT_RE = /^(png|pdf|ps|eps)$/i
|
318
417
|
# @name
|
319
418
|
AREA_NAME_RE = /^@(.*)$/
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
419
|
+
# @x:y:w:h
|
420
|
+
AREA_SPEC_RE = /^@(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):(\d+(?:\.\d+)?)$/
|
421
|
+
# right, left, upsidedown
|
422
|
+
ROTATE_RE = /^(right|left|upsidedown)$/
|
423
|
+
# show/hide layer or id, "+Layer 1", +#id, -*
|
424
|
+
SHOWHIDE_RE = /^([+-])(.+)$/
|
326
425
|
|
327
|
-
|
328
|
-
|
426
|
+
class SyntaxError < StandardError
|
427
|
+
end
|
329
428
|
|
330
429
|
class ProcessError < StandardError
|
331
430
|
end
|
@@ -360,10 +459,11 @@ class Inkmake
|
|
360
459
|
|
361
460
|
def parse_split_line(line)
|
362
461
|
# changed CSV API in ruby 1.9
|
462
|
+
# - [nil] to remove empty fields
|
363
463
|
if RUBY_VERSION.start_with? "1.8"
|
364
|
-
CSV::parse_line(line, fs = " ")
|
464
|
+
CSV::parse_line(line, fs = " ") - [nil]
|
365
465
|
else
|
366
|
-
CSV::parse_line(line, {:col_sep => " "})
|
466
|
+
CSV::parse_line(line, **{:col_sep => " "}) - [nil]
|
367
467
|
end
|
368
468
|
end
|
369
469
|
|
@@ -468,16 +568,17 @@ class Inkmake
|
|
468
568
|
else
|
469
569
|
out_width, out_height = width, height
|
470
570
|
end
|
571
|
+
file_href = "file://#{path}"
|
471
572
|
svg =
|
472
573
|
"<?xml version=\"1.0\"?>" +
|
473
574
|
"<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"#{out_width}\" height=\"#{out_height}\">" +
|
474
575
|
"<g>" +
|
475
576
|
"<image transform=\"translate(#{out_width/2} #{out_height/2}) rotate(#{degrees})\"" +
|
476
577
|
" width=\"#{width}\" height=\"#{height}\" x=\"#{-width/2}\" y=\"#{-height/2}\"" +
|
477
|
-
" xlink:href
|
578
|
+
" xlink:href=#{file_href.encode(:xml => :attr)} />" +
|
478
579
|
"</g>" +
|
479
580
|
"</svg>"
|
480
|
-
f = Tempfile.new("inkmake")
|
581
|
+
f = Tempfile.new(["inkmake", ".svg"])
|
481
582
|
f.write(svg)
|
482
583
|
f.flush
|
483
584
|
f.seek(0)
|
@@ -679,7 +780,7 @@ class Inkmake
|
|
679
780
|
end
|
680
781
|
end
|
681
782
|
|
682
|
-
f = Tempfile.new("inkmake")
|
783
|
+
f = Tempfile.new(["inkmake", ".svg"])
|
683
784
|
doc.write(:output => f)
|
684
785
|
f.flush
|
685
786
|
f
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inkmake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mattias Wadman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: mattias.wadman@gmail.com
|
@@ -38,8 +38,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0'
|
40
40
|
requirements: []
|
41
|
-
|
42
|
-
rubygems_version: 2.2.2
|
41
|
+
rubygems_version: 3.0.3
|
43
42
|
signing_key:
|
44
43
|
specification_version: 4
|
45
44
|
summary: Makefile inspired export from SVG files using Inkscape as backend with some
|