class Inkmake::InkscapeRemote

Attributes

inkscape_version[R]

Public Class Methods

escape(s) click to toggle source
# File lib/inkmake.rb, line 355
def self.escape(s)
  s.gsub(/([\\"'])/, '\\\\\1')
end
new() { |self| ... } click to toggle source
# File lib/inkmake.rb, line 118
def initialize
  @inkscape_version = probe_inkscape_version
  open_shell
  yield self
ensure
  quit
end
path() click to toggle source
# File lib/inkmake.rb, line 359
def self.path
  return Inkmake.inkscape_path if Inkmake.inkscape_path

  # try to figure out inkscape path
  p = ( 
    (["/Applications/Inkscape.app/Contents/MacOS/inkscape",
      "/Applications/Inkscape.app/Contents/Resources/bin/inkscape",
      'c:\Program Files\Inkscape\inkscape.exe',
      'c:\Program Files\Inkscape\bin\inkscape.exe',
      'c:\Program Files (x86)\Inkscape\inkscape.exe',
      'c:\Program Files (x86)\Inkscape\bin\inkscape.exe'] +
      (ENV['PATH'].split(':').map {|p| File.join(p, "inkscape")}))
    .select do |path|
      File.exists? path
    end)
  .first
  if p
    p
  else
    begin
      require "osx/cocoa"
      app_path = OSX::NSWorkspace.sharedWorkspace.fullPathForApplication:"Inkscape"
      ["#{app_path}/Contents/MacOS/inkscape",
       "#{app_path}/Contents/Resources/bin/inkscape"]
      .select do |path|
        File.exists? path
      end
    rescue NameError, LoadError
      nil
    end
  end
end

Public Instance Methods

command0(args) click to toggle source
# File lib/inkmake.rb, line 174
def command0(args)
  c = args.collect do |key, value|
    if value
      "\"#{key}=#{self.class.escape value.to_s}\""
    else
      key
    end
  end.join(" ")
  puts "< #{c}" if Inkmake.verbose
  @in.write "#{c}\n"
  @in.flush
end
command1(args) click to toggle source
# File lib/inkmake.rb, line 187
def command1(args)
  c = args.collect do |key, value|
    if value
      "#{key}:#{value.to_s}"
    else
      "#{key}:"
    end
  end.join("\n")
  puts "< #{c}" if Inkmake.verbose
  @in.write "#{c}\n"
  @in.flush
end
drawing_area(file) click to toggle source
# File lib/inkmake.rb, line 341
def drawing_area(file)
  query_all(file).first[1..-1]
end
export(opts) click to toggle source
# File lib/inkmake.rb, line 304
def export(opts)
  if @inkscape_version == 0 then
    export0(opts)
  else
    export1(opts)
  end
end
export0(opts) click to toggle source
# File lib/inkmake.rb, line 217
def export0(opts)
  c = {
    "--file" => opts[:svg_path],
    "--export-#{opts[:format]}" => opts[:out_path]
  }
  if opts[:res]
    s = opts[:rotate_scale_hack] ? 2 : 1
    c["--export-width"] = opts[:res].width.to_pixels(opts[:dpi] || 90) * s
    c["--export-height"] = opts[:res].height.to_pixels(opts[:dpi] || 90) * s
  end
  if opts[:dpi]
    c["--export-dpi"] = opts[:dpi]
  end
  if opts[:area].kind_of? Array
    c["--export-area"] = ("%f:%f:%f:%f" % opts[:area])
  elsif opts[:area] == :drawing
    c["--export-area-drawing"] = nil
  elsif opts[:area].kind_of? String
    c["--export-id"] = opts[:area]
  end
  command0(c)
  width, height = [0, 0]
  loop do
    case response
    when /^Area .* exported to (\d+) x (\d+) pixels.*$/ then
      width = $1
      height = $2
    when :prompt then break
    end
  end

  [width, height]
end
export1(opts) click to toggle source
# File lib/inkmake.rb, line 251
def export1(opts)
  c = [
    ["file-open", opts[:svg_path]],
    ["export-type", opts[:format]],
    ["export-filename", opts[:out_path]]
  ]
  if opts[:res]
    s = opts[:rotate_scale_hack] ? 2 : 1
    c += [["export-width", opts[:res].width.to_pixels(opts[:dpi] || 90) * s]]
    c += [["export-height", opts[:res].height.to_pixels(opts[:dpi] || 90) * s]]
  else
    c += [["export-width", ""]]
    c += [["export-height", ""]]
  end
  if opts[:dpi]
    c += [["export-dpi", opts[:dpi]]]
  end

  c += [["export-area", ""]]
  c += [["export-area-drawing", "false"]]
  c += [["export-id", ""]]
  c += [["export-area-page", "false"]]

  if opts[:area].kind_of? Array
    c += [["export-area", ("%f:%f:%f:%f" % opts[:area])]]
  elsif opts[:area] == :drawing
    c += [["export-area-drawing", "true"]]
  elsif opts[:area].kind_of? String
    c += [["export-id", opts[:area]]]
  else
    c += [["export-area-page", "true"]]
  end
  c.each do |a|
    command1([a])
    wait_prompt
  end

  command1([["export-do"]])
  width, height = [0, 0]
  loop do
    case response
    when /^Area .* exported to (\d+) x (\d+) pixels.*$/ then
      width = $1
      height = $2
    when :prompt then break
    end
  end
  command1([["file-close"]])
  wait_prompt

  [width, height]
end
ids(file) click to toggle source
# File lib/inkmake.rb, line 337
def ids(file)
  Hash[query_all(file).map {|l| [l[0], l[1..-1]]}]
end
is_windows() click to toggle source
# File lib/inkmake.rb, line 126
def is_windows
  @is_windows ||= (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/) != nil
end
open(args) click to toggle source
# File lib/inkmake.rb, line 130
def open(args)
  if is_windows
    # Inkscape on Windows for some reason needs to run from its binary dir.
    # popen2e so get stdout and stderr in one pipe. inkscape 1 shell seems to
    # use both as output and we need to read to not block it.
    Open3.popen2e(*[File.basename(self.class.path)] + args,
                                   :chdir => File.dirname(self.class.path))
  else
    Open3.popen2e(*[self.class.path] + args)
  end
end
open_shell() click to toggle source
# File lib/inkmake.rb, line 169
def open_shell
  @in, @out = open(["--shell"])
  wait_prompt
end
probe_inkscape_version() click to toggle source
# File lib/inkmake.rb, line 200
def probe_inkscape_version
  _in, out = open(["--version"])
  version = 0
  begin
    loop do
      case out.readline()
      when /^\s*Inkscape 1\..*$/ then
        version = 1
      when /^\s*Inkscape 0\..*$/ then
        version = 0
      end
    end
  rescue EOFError
  end
  version
end
query_all(file) click to toggle source
# File lib/inkmake.rb, line 312
def query_all(file)
  ids = []
  if @inkscape_version == 0 then
    command0({
      "--file" => file,
      "--query-all" => nil,
    })
  else
    command1([["file-open", file]])
    wait_prompt
    command1([["query-all", file]])
  end
  loop do
    case response
    when /^(.*),(.*),(.*),(.*),(.*)$/ then ids << [$1, $2.to_f, $3.to_f, $4.to_f, $5.to_f]
    when :prompt then break
    end
  end
  if @inkscape_version == 1 then
    command1([["file-close", file]])
    wait_prompt
  end
  ids
end
quit() click to toggle source
# File lib/inkmake.rb, line 345
def quit
  if @inkscape_version == 0 then
    command0({"quit" => nil})
  else
    @in.close
  end
  @out.read
  nil
end
response() click to toggle source
# File lib/inkmake.rb, line 142
def response
  if @inkscape_version == 0
    o = @out.getc
    if o == ">"
      puts "1> #{o}" if Inkmake.verbose
      return :prompt;
    end
  else
    o = @out.getc + @out.getc
    if o == "> "
      puts "1> #{o}" if Inkmake.verbose
      return :prompt;
    end
  end
  o = o + @out.readline
  puts "2> '#{o}'" if Inkmake.verbose
  o
end
wait_prompt() click to toggle source
# File lib/inkmake.rb, line 161
def wait_prompt
  loop do
    case response
    when :prompt then break
    end
  end
end