X-Git-Url: http://nitlanguage.org diff --git a/contrib/inkscape_tools/src/svg_to_png_and_nit.nit b/contrib/inkscape_tools/src/svg_to_png_and_nit.nit index f1de678..6b2d70f 100644 --- a/contrib/inkscape_tools/src/svg_to_png_and_nit.nit +++ b/contrib/inkscape_tools/src/svg_to_png_and_nit.nit @@ -1,6 +1,6 @@ # This file is part of NIT ( http://www.nitlanguage.org ). # -# Copyright 2012-2014 Alexis Laferrière +# Copyright 2012-2015 Alexis Laferrière # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,51 +14,140 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This script extracts pngs from a single svg for all objects with ids -# beginning by 0. Requires Inkscape. +# Extract images of objects from an SVG file using Inkscape module svg_to_png_and_nit import opts import template +# Image information extracted from the SVG file class Image + # Name extracted from the object ID minus the `0` prefix and Nit safe var name: String + + # Left border var x: Int + + # Top border var y: Int + + # Image width var w: Int + + # Image height var h: Int + + # Right border fun right: Int do return x+w + + # Bottom border fun bottom: Int do return y+h redef fun to_s do return name end -# The Nit source file to retreive all images -class ImageSetSrc +# Document being processed, concerns both the source and the target +class Document + # Name of the source file + var drawing_name: String + + # Name of the class to generate + var nit_class_name: String = drawing_name.capitalized + "Images" is lazy + + # Scaling to apply to the exported image + var scale: Float + + # Source minimum X + var min_x: Int + + # Source maximum X + var max_x: Int + + # Source minimum Y + var min_y: Int + + # Source maximum Y + var max_y: Int + + # Get the coordinates for `image` as `"x, y, w, h"` + fun coordinates(image: Image): String + do + var x = image.x.adapt(min_x, scale) + var y = image.y.adapt(min_y, scale) + var w = (image.w.to_f*scale).to_i + var h = (image.h.to_f*scale).to_i + + return "{x}, {y}, {w}, {h}" + end +end + +# Nit module with a single class to retrieve to access the extracted images +abstract class ImageSetSrc super Template - var name: String - init(name: String) do self.name = name + # Target document + var document: Document - var attributes = new Array[String] - var load_exprs = new Array[String] + # Images found in the source document + var images: Array[Image] +end + +# Nit module targeting the MNit framework +class MnitImageSetSrc + super ImageSetSrc redef fun rendering do + # Known array of images + var arrays_of_images = new Array[String] + + # Attributes of the generated class + var attributes = new Array[String] + + # Statements for the generated `load_all` method + var load_exprs = new Array[String] + + # Add images to Nit source file + for image in images do + # Adapt coordinates to new top left and scale + var coordinates = document.coordinates(image) + + var nit_name = image.name + var last_char = nit_name.chars.last + if last_char.to_s.is_numeric then + # Array of images + # TODO support more than 10 images in an array + + nit_name = nit_name.substring(0, nit_name.length-1) + if not arrays_of_images.has(nit_name) then + # Create class attribute to store Array + arrays_of_images.add(nit_name) + attributes.add "\tvar {nit_name} = new Array[Image]\n" + end + load_exprs.add "\t\t{nit_name}.add(main_image.subimage({coordinates}))\n" + else + # Single image + attributes.add "\tvar {nit_name}: Image is noinit\n" + load_exprs.add "\t\t{nit_name} = main_image.subimage({coordinates})\n" + end + end + add """ -# file generated by svg_to_png, do not modify, redef instead +# File generated by svg_to_png_and_nit, do not modify, redef instead -import generated_image_set +import mnit::image_set -class {{{name}}} +class {{{document.nit_class_name}}} super ImageSet + private var main_image: Image is noinit """ add_all attributes add """ redef fun load_all(app: App) do + main_image = app.load_image(\"images/{{{document.drawing_name}}}.png\") """ add_all load_exprs add """ @@ -68,21 +157,15 @@ end end end -redef class String - fun to_i_strip_e: Int - do - if has_substring("e-", 0) then return 0 - return to_i - end -end - redef class Int - fun adapt(d: Int, scale: Float): Int + # Magic adaption of this coordinates to the given `margin` and `scale` + fun adapt(margin: Int, scale: Float): Int do - var corrected = self-d + var corrected = self-margin return (corrected.to_f*scale).to_i end + # The first power of to equal or greater than `self` fun next_pow2: Int do var p = 2 @@ -91,9 +174,9 @@ redef class Int end end -var opt_out_src = new OptionString("Path to output source file", "--src", "-s") +var opt_out_src = new OptionString("Path to output source file (folder or file)", "--src", "-s") var opt_assets = new OptionString("Path to assert dir where to put PNG files", "--assets", "-a") -var opt_scale = new OptionFloat("Apply scaling to exported images (defaut at 1.0 of 90dpi)", 1.0, "--scale", "-x") +var opt_scale = new OptionFloat("Apply scaling to exported images (default at 1.0 of 90dpi)", 1.0, "--scale", "-x") var opt_help = new OptionBool("Print this help message", "--help", "-h") var opt_context = new OptionContext @@ -111,6 +194,11 @@ if not errors.is_empty or opt_help.value then exit 1 end +if not "inkscape".program_is_in_path then + print "This tool needs the external program `inkscape`, make sure it is installed and in your PATH." + exit 1 +end + var drawings = rest for drawing in drawings do if not drawing.file_exists then @@ -128,15 +216,13 @@ end var src_path = opt_out_src.value if src_path == null then src_path = "src" -if not src_path.file_exists then +if not src_path.file_exists and src_path.file_extension != "nit" then stderr.write "Source dir '{src_path}' does not exist (use --src)\n" exit 1 end var scale = opt_scale.value -var arrays_of_images = new Array[String] - for drawing in drawings do var drawing_name = drawing.basename(".svg") @@ -144,7 +230,7 @@ for drawing in drawings do # Inkscape doesn't give us this information var page_width = -1 var page_height = -1 - var svg_file = new IFStream.open(drawing) + var svg_file = new FileReader.open(drawing) while not svg_file.eof do var line = svg_file.read_line @@ -152,12 +238,12 @@ for drawing in drawings do var words = line.split("=") var n = words[1] n = n.substring(1, n.length-2) # remove "" - page_width = n.to_i_strip_e + page_width = n.to_f.ceil.to_i else if page_height == -1 and line.search("height") != null then var words = line.split("=") var n = words[1] n = n.substring(1, n.length-2) # remove "" - page_height = n.to_i_strip_e + page_height = n.to_f.ceil.to_i end end svg_file.close @@ -167,7 +253,7 @@ for drawing in drawings do # Query Inkscape var prog = "inkscape" - var proc = new IProcess.from_a(prog, ["--without-gui", "--query-all", drawing]) + var proc = new ProcessReader.from_a(prog, ["--without-gui", "--query-all", drawing]) var min_x = 1000000 var min_y = 1000000 @@ -180,14 +266,14 @@ for drawing in drawings do while not proc.eof do var line = proc.read_line var words = line.split(",") - + if words.length == 5 then var id = words[0] - var x = words[1].to_i_strip_e - var y = words[2].to_i_strip_e - var w = words[3].to_i_strip_e - var h = words[4].to_i_strip_e + var x = words[1].to_f.floor.to_i + var y = words[2].to_f.floor.to_i + var w = words[3].to_f.ceil.to_i+1 + var h = words[4].to_f.ceil.to_i+1 if id.has_prefix("0") then var nit_name = id.substring_from(1) @@ -205,45 +291,21 @@ for drawing in drawings do end proc.close - # Nit class - var nit_class_name = drawing_name.chars.first.to_s.to_upper + drawing_name.substring_from(1) + "Images" - var nit_src = new ImageSetSrc(nit_class_name) - nit_src.attributes.add "\tprivate var main_image: Image\n" - nit_src.load_exprs.add "\t\tmain_image = app.load_image(\"images/{drawing_name}.png\")\n" # Sort images by name, it prevents Array errors and looks better alpha_comparator.sort(images) - # Add images to Nit source file - for image in images do - # Adapt coordinates to new top left and scale - var x = image.x.adapt(min_x, scale) - var y = image.y.adapt(min_y, scale) - var w = (image.w.to_f*scale).to_i - var h = (image.h.to_f*scale).to_i + var document = new Document(drawing_name, scale, min_x, max_x, min_y, max_y) - var nit_name = image.name - var last_char = nit_name.chars.last - if last_char.to_s.is_numeric then - # Array of images - # TODO support more than 10 images in an array - - nit_name = nit_name.substring(0, nit_name.length-1) - if not arrays_of_images.has(nit_name) then - # Create class attribute to store Array - arrays_of_images.add(nit_name) - nit_src.attributes.add "\tvar {nit_name} = new Array[Image]\n" - end - nit_src.load_exprs.add "\t\t{nit_name}.add(main_image.subimage({x}, {y}, {w}, {h}))\n" - else - # Single image - nit_src.attributes.add "\tvar {nit_name}: Image\n" - nit_src.load_exprs.add "\t\t{nit_name} = main_image.subimage({x}, {y}, {w}, {h})\n" - end + # Nit class + var nit_src = new MnitImageSetSrc(document, images) + + if not src_path.file_extension == "nit" then + src_path = src_path/drawing_name+".nit" end # Output source file - var src_file = new OFStream.open("{src_path}/{drawing_name}.nit") + var src_file = new FileWriter.open(src_path) nit_src.write_to(src_file) src_file.close