class Inkmake::InkFile

Constants

AREA_NAME_RE

@name

AREA_SPEC_RE

@x:y:w:h

DEST_RE

(prefix)(suffix)

DPI_RE

180dpi

DefaultVariants
EXT_RE

ext to format, supported inkscape output formats

FORMAT_RE

supported inkscape output formats

RES_RE

123x123, 12.3cm*12.3cm

ROTATE_RE

right, left, upsidedown

Rotations
SCALE_RE

*123, *1.23

SHOWHIDE_RE

show/hide layer or id, “+Layer 1”, +#id, -*

SVG_RE

test.svg, test.SVG

Attributes

out_path[R]
svg_path[R]

Public Class Methods

new(file, opts) click to toggle source
# File lib/inkmake.rb, line 432
def initialize(file, opts)
  @file = file
  @images = []
  @force = opts[:force]

  svg_path = nil
  out_path = nil
  File.read(file).lines.each_with_index do |line, index|
    line.strip!
    next if line.empty? or line.start_with? "#"
    begin
      case line
      when /^svg:(.*)/i then svg_path = File.expand_path($1.strip, File.dirname(file))
      when /^out:(.*)/i then out_path = File.expand_path($1.strip, File.dirname(file))
      else
        @images << InkImage.new(self, parse_line(line))
      end
    rescue SyntaxError => e
      puts "#{file}:#{index+1}: #{e.message}"
      exit
    end
  end

  # order is: argument, config in inkfile, inkfile directory
  @svg_path = opts[:svg_path] || svg_path || File.dirname(file)
  @out_path = opts[:out_path] || out_path || File.dirname(file)
end

Public Instance Methods

parse_line(line) click to toggle source
# File lib/inkmake.rb, line 470
def parse_line(line)
  cols = nil
  begin
    cols = parse_split_line(line)
  rescue CSV::MalformedCSVError => e
    raise SyntaxError, e.message
  end
  raise SyntaxError, "Invalid number of columns" if cols.count < 1

  if not DEST_RE.match(cols[0])
    raise SyntaxError, "Invalid destination format \"#{cols[0]}\""
  end

  opts = {}
  opts[:prefix] = $1
  variants = $2
  opts[:suffix] = $3
  opts[:format] = $1.downcase if EXT_RE.match(opts[:prefix] + opts[:suffix])

  cols[1..-1].each do |col|
    case col
    when RES_RE then opts[:res] = InkscapeResolution.new($1, $2, "px")
    when SVG_RE then opts[:svg] = col
    when AREA_SPEC_RE then opts[:area] = [$1.to_f, $2.to_f, $3.to_f, $4.to_f]
    when AREA_NAME_RE then opts[:area] = $1
    when /^drawing$/ then opts[:area] = :drawing
    when FORMAT_RE then opts[:format] = $1.downcase
    when ROTATE_RE then opts[:rotate] = Rotations[$1]
    when SCALE_RE then opts[:scale] = $1.to_f
    when DPI_RE then opts[:dpi] = $1.to_f
    when SHOWHIDE_RE
      op = $1 == "+" ? :show : :hide
      if $2.start_with? "#"
        type = :id
        name= $2[1..-1]
      else
        type = :layer
        name = $2 == "*" ? :all : $2
      end
      (opts[:showhide] ||= []).push({:op => op, :type => type, :name => name})
    else
      raise SyntaxError, "Unknown column \"#{col}\""
    end
  end

  if not opts[:format]
    raise SyntaxError, "Unknown or no output format could be determined"
  end

  variants = (variants.split("|") if variants) || []
  opts[:variants] = variants.collect do |variant|
    name, options = variant.split("=", 2)
    if options
      options = Hash[
        options.split(",").map do |option|
        case option
        when ROTATE_RE then [:rotate, Rotations[$1]]
        when RES_RE then [:res, InkscapeResolution.new($1, $2, "px")]
        when SCALE_RE then [:scale, $1.to_f]
        when DPI_RE then [:dpi, $1.to_f]
        else
          raise SyntaxError, "Invalid variant option \"#{option}\""
        end
        end
      ]
    else
      options = DefaultVariants[name]
      raise SyntaxError, "Invalid default variant \"#{name}\"" if not options
    end

    [name, options]
  end

  opts
end
parse_split_line(line) click to toggle source
# File lib/inkmake.rb, line 460
def parse_split_line(line)
  # changed CSV API in ruby 1.9
  # - [nil] to remove empty fields
  if RUBY_VERSION.start_with? "1.8"
    CSV::parse_line(line, fs = " ") - [nil]
  else
    CSV::parse_line(line, **{:col_sep => " "}) - [nil]
  end
end
process() click to toggle source
# File lib/inkmake.rb, line 588
def process
  variants = variants_to_generate
  if variants.empty?
    return false
  end

  idfilemap = {}
  InkscapeRemote.new do |inkscape|
    variants.each do |variant|
      if not File.exists? variant.image.svg_path
        raise ProcessError, "Source SVG file #{variant.image.svg_path} does not exist"
      end

      out_res = nil
      # order: 200x200, @id/area, svg res
      if variant.image.res
        out_res = variant.image.res
      elsif variant.image.area == :drawing
        res = inkscape.drawing_area(variant.image.svg_path)
        out_res = InkscapeResolution.new(res[2], res[3], "uu")
      elsif variant.image.area
        if variant.image.area.kind_of? String
          if not idfilemap.has_key? variant.image.svg_path
            idfilemap[variant.image.svg_path] = inkscape.ids(variant.image.svg_path)
          end

          if not idfilemap[variant.image.svg_path].has_key? variant.image.area
            raise ProcessError, "Unknown id \"#{variant.image.area}\" in file #{variant.image.svg_path} when exporting #{variant.out_path}"
          end

          res = idfilemap[variant.image.svg_path][variant.image.area]
          out_res = InkscapeResolution.new(res[2], res[3], "uu")
        else
          a = variant.image.area
          # x0:y0:x1:y1
          out_res = InkscapeResolution.new(a[2]-a[0], a[3]-a[1], "uu")
        end
      else
        out_res = variant.image.svg_res
      end

      scale = variant.options[:scale]
      if scale
        out_res = out_res.scale(scale)
      end

      out_res = variant.options[:res] if variant.options[:res]

      rotate = (variant.image.format == "png" and variant.options[:rotate])

      FileUtils.mkdir_p File.dirname(variant.out_path)

      svg_path = variant.image.svg_path
      if variant.image.showhide
        svg_path = variant.image.svg_showhide_file.path
      end

      res = inkscape.export({
        :svg_path => svg_path,
        :out_path => variant.out_path,
        :res => out_res,
        :dpi => variant.options[:dpi],
        :format => variant.image.format,
        :area => variant.image.area,
        :rotate_scale_hack => rotate
      })

      if rotate
        tmp, width, height = temp_rotate_svg(variant.out_path, rotate, res[0].to_i, res[1].to_i)
        res = inkscape.export({
          :svg_path => tmp.path,
          :out_path => variant.out_path,
          :res => InkscapeResolution.new(width / 2, height / 2, "px"),
          :format => variant.image.format
        })
        tmp.close!
      end

      rel_path = Pathname.new(variant.out_path).relative_path_from(Pathname.new(Dir.pwd))
      if variant.image.format == "png"
        puts "#{rel_path} #{res[0]}x#{res[1]}"
      else
        puts rel_path
      end
    end
  end

  return true
end
temp_rotate_svg(path, degrees, width, height) click to toggle source
# File lib/inkmake.rb, line 565
def temp_rotate_svg(path, degrees, width, height)
  if degrees != 180
    out_width, out_height = height, width
  else
    out_width, out_height = width, height
  end
  file_href = "file://#{path}"
  svg =
    "<?xml version=\"1.0\"?>" +
    "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"#{out_width}\" height=\"#{out_height}\">" +
    "<g>" +
    "<image transform=\"translate(#{out_width/2} #{out_height/2}) rotate(#{degrees})\"" +
    "  width=\"#{width}\" height=\"#{height}\" x=\"#{-width/2}\" y=\"#{-height/2}\"" +
      "  xlink:href=#{file_href.encode(:xml => :attr)} />" +
    "</g>" +
      "</svg>"
    f = Tempfile.new(["inkmake", ".svg"])
    f.write(svg)
    f.flush
    f.seek(0)
    [f, out_width, out_height]
end
variants_to_generate() click to toggle source
# File lib/inkmake.rb, line 546
def variants_to_generate
  l = []
  @images.each do |image|
    image.variants.each do |variant|
      next if not @force and
      File.exists? variant.out_path and
      File.mtime(variant.out_path) > File.mtime(image.svg_path) and
      File.mtime(variant.out_path) > File.mtime(@file)
      if variant.out_path == image.svg_path
        raise ProcessError, "Avoiding overwriting source SVG file #{image.svg_path}"
      end

      l << variant
    end
  end

  l
end