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 1723ecf..80ba5c4 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 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,13 +157,94 @@ end end end +# Nit module targeting the Gamnit framework +# +# Gamnit's `Texture` already manage the lazy loading, no need to do it here. +class GamnitImageSetSrc + super ImageSetSrc + + private fun attributes: Array[String] + do + # Separate the images from the arrays of images + var single_images = new Array[Image] + var arrays_of_images = new HashMap[String, Array[Image]] + + for image in images do + var nit_name = image.name + var last_char = nit_name.chars.last + if last_char.to_s.is_numeric then + + # Is an array + nit_name = nit_name.substring(0, nit_name.length-1) + if not arrays_of_images.keys.has(nit_name) then + # Create a new array + var array = new Array[Image] + arrays_of_images[nit_name] = array + end + + arrays_of_images[nit_name].add image + else + # Is a single image + single_images.add image + end + end + + # Attributes of the class + var attributes = new Array[String] + attributes.add "\tprivate var main_image = new Texture(\"images/{document.drawing_name}.png\")\n" + + # Add single images to Nit source file + for image in single_images do + # Adapt coordinates to new top left and scale + var coordinates = document.coordinates(image) + + attributes.add "\tvar {image.name}: Texture = main_image.subtexture({coordinates})\n" + end + + # Add array of images too + for name, images in arrays_of_images do + + var lines = new Array[String] + for image in images do + var coordinates = document.coordinates(image) + lines.add "\t\tmain_image.subtexture({coordinates})" + end + + attributes.add """ + var {{{name}}} = new Array[Texture].with_items( +{{{lines.join(",\n")}}}) +""" + end + + return attributes + end + + redef fun rendering + do + add """ +# File generated by svg_to_png_and_nit, do not modify, redef instead + +import gamnit::display + +class {{{document.nit_class_name}}} + +""" + add_all attributes + add """ +end +""" + 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 @@ -83,13 +253,14 @@ 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_gamnit = new OptionBool("Target the Gamnit framework (by default it targets Mnit)", "--gamnit", "-g") var opt_help = new OptionBool("Print this help message", "--help", "-h") var opt_context = new OptionContext -opt_context.add_option(opt_out_src, opt_assets, opt_scale, opt_help) +opt_context.add_option(opt_out_src, opt_assets, opt_scale, opt_gamnit, opt_help) opt_context.parse(args) var rest = opt_context.rest @@ -125,15 +296,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") @@ -141,7 +310,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 @@ -164,7 +333,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 @@ -177,7 +346,7 @@ 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] @@ -202,45 +371,26 @@ 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: ImageSetSrc + if opt_gamnit.value then + nit_src = new GamnitImageSetSrc(document, images) + else + nit_src = new MnitImageSetSrc(document, images) + end + + 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