inkmake 0.1.1 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +5 -5
  2. data/lib/inkmake.rb +176 -75
  3. metadata +3 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: fdeb5f4c1fa671f1b808a4f52e29753beb8e4be9
4
- data.tar.gz: 169fdc73075e5fd42383a7db0fb6a8b7d92bb465
2
+ SHA256:
3
+ metadata.gz: e8f974d5799a2dad944fc34bc8ff9ee6357493f19166ccdf8baa93db3e76dac3
4
+ data.tar.gz: 03777d34d7aa798e57cb6f7a3ea55300284157c424636aa551ee6502eb9f4ddd
5
5
  SHA512:
6
- metadata.gz: a22adc571cfc31b553f149bc2c10205a577d4c6dbde966120642cd22f3fa142f620834fe6938c0283a57f3fcb65425ac98dbfe480ece43a015f3efb7d20577fb
7
- data.tar.gz: 8788db74b0632df20cec91427c1214ef034a83b8992db9e7c7abb563ae95f2b240a937978e805b67e694dc1d2b7ca1d6d9e0027114a3ca7c16851d5d04f4a9ec
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
- open
118
- probe_decimal_symbol
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
- @in, @out, @err = Open3.popen3(*[File.basename(self.class.path), "--shell"],
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
- @in, @out, @err = Open3.popen3(*[self.class.path, "--shell"])
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 command(args)
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 "> #{c}" if Inkmake.verbose
182
+ puts "< #{c}" if Inkmake.verbose
152
183
  @in.write "#{c}\n"
153
184
  @in.flush
154
185
  end
155
186
 
156
- def response
157
- o = @out.read(1)
158
- if o == ">"
159
- puts "< #{o}" if Inkmake.verbose
160
- return :prompt;
161
- end
162
- o = o + @out.readline
163
- puts "< #{o}" if Inkmake.verbose
164
- o
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
- # this is weird but is the least weird and most protable way i could come up with
168
- # to figuring out what decimal symbol to use.
169
- # forcing LC_NUMERIC=C seems hard to do in a portable way
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 response
187
- when :prompt then break
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 export(opts)
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]).gsub(".", @decimal_symbol)
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
- command(c)
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
- command({
238
- "--file" => file,
239
- "--query-all" => nil,
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
- command({"quit" => nil})
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/Resources/bin/inkscape",
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 (x86)\Inkscape\inkscape.exe'] +
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
- "#{OSX::NSWorkspace.sharedWorkspace.fullPathForApplication:"Inkscape"}/Contents/Resources/bin/inkscape"
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
- # *123, *1.23
307
- SCALE_RE = /^\*(\d+(?:\.\d+)?)$/
308
- # 180dpi
309
- DPI_RE = /^(\d+(?:\.\d+)?)dpi$/i
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
- # test.svg, test.SVG
313
- SVG_RE = /\.svg$/i
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
- # @x:y:w:h
321
- AREA_SPEC_RE = /^@(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):(\d+(?:\.\d+)?)$/
322
- # right, left, upsidedown
323
- ROTATE_RE = /^(right|left|upsidedown)$/
324
- # show/hide layer or id, "+Layer 1", +#id, -*
325
- SHOWHIDE_RE = /^([+-])(.+)$/
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
- class SyntaxError < StandardError
328
- end
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=\"file:///#{URI.escape(path)}\" />" +
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.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: 2015-05-01 00:00:00.000000000 Z
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
- rubyforge_project:
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