1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012-2014 Alexis Laferrière <alexis.laf@xymus.net>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # This script extracts pngs from a single svg for all objects with ids
18 # beginning by 0. Requires Inkscape.
19 module svg_to_png_and_nit
30 fun right
: Int do return x
+w
31 fun bottom
: Int do return y
+h
33 redef fun to_s
do return name
36 # The Nit source file to retreive all images
41 init(name
: String) do self.name
= name
43 var attributes
= new Array[String]
44 var load_exprs
= new Array[String]
49 # file generated by svg_to_png, do not modify, redef instead
51 import mnit::image_set
60 redef fun load_all(app: App)
72 fun adapt
(d
: Int, scale
: Float): Int
74 var corrected
= self-d
75 return (corrected
.to_f
*scale
).to_i
81 while p
< self do p
= p
*2
86 var opt_out_src
= new OptionString("Path to output source file", "--src", "-s")
87 var opt_assets
= new OptionString("Path to assert dir where to put PNG files", "--assets", "-a")
88 var opt_scale
= new OptionFloat("Apply scaling to exported images (defaut at 1.0 of 90dpi)", 1.0, "--scale", "-x")
89 var opt_help
= new OptionBool("Print this help message", "--help", "-h")
91 var opt_context
= new OptionContext
92 opt_context
.add_option
(opt_out_src
, opt_assets
, opt_scale
, opt_help
)
94 opt_context
.parse
(args
)
95 var rest
= opt_context
.rest
96 var errors
= opt_context
.errors
97 if rest
.is_empty
and not opt_help
.value
then errors
.add
"You must specify at least one source drawing file"
98 if not errors
.is_empty
or opt_help
.value
then
99 print errors
.join
("\n")
100 print
"Usage: svg_to_png_and_nit [Options] drawing.svg [Other files]"
107 for drawing
in drawings
do
108 if not drawing
.file_exists
then
109 stderr
.write
"Source drawing file '{drawing}' does not exist."
114 var assets_path
= opt_assets
.value
115 if assets_path
== null then assets_path
= "assets"
116 if not assets_path
.file_exists
then
117 stderr
.write
"Assets dir '{assets_path}' does not exist (use --assets)\n"
121 var src_path
= opt_out_src
.value
122 if src_path
== null then src_path
= "src"
123 if not src_path
.file_exists
then
124 stderr
.write
"Source dir '{src_path}' does not exist (use --src)\n"
128 var scale
= opt_scale
.value
130 var arrays_of_images
= new Array[String]
132 for drawing
in drawings
do
133 var drawing_name
= drawing
.basename
(".svg")
135 # Get the page dimensions
136 # Inkscape doesn't give us this information
139 var svg_file
= new IFStream.open
(drawing
)
140 while not svg_file
.eof
do
141 var line
= svg_file
.read_line
143 if page_width
== -1 and line
.search
("width") != null then
144 var words
= line
.split
("=")
146 n
= n
.substring
(1, n
.length-2
) # remove ""
147 page_width
= n
.to_f
.ceil
.to_i
148 else if page_height
== -1 and line
.search
("height") != null then
149 var words
= line
.split
("=")
151 n
= n
.substring
(1, n
.length-2
) # remove ""
152 page_height
= n
.to_f
.ceil
.to_i
157 assert page_width
!= -1
158 assert page_height
!= -1
161 var prog
= "inkscape"
162 var proc
= new IProcess.from_a
(prog
, ["--without-gui", "--query-all", drawing
])
168 var images
= new Array[Image]
170 # Gather all images beginning with 0
171 # also get the bounding box of all images
172 while not proc
.eof
do
173 var line
= proc
.read_line
174 var words
= line
.split
(",")
176 if words
.length
== 5 then
179 var x
= words
[1].to_f
.floor
.to_i
180 var y
= words
[2].to_f
.floor
.to_i
181 var w
= words
[3].to_f
.ceil
.to_i
182 var h
= words
[4].to_f
.ceil
.to_i
184 if id
.has_prefix
("0") then
185 var nit_name
= id
.substring_from
(1)
186 nit_name
= nit_name
.replace
('-', "_")
188 var image
= new Image(nit_name
, x
, y
, w
, h
)
191 max_x
= max_x
.max
(image
.right
)
192 max_y
= max_y
.max
(image
.bottom
)
201 var nit_class_name
= drawing_name
.chars
.first
.to_s
.to_upper
+ drawing_name
.substring_from
(1) + "Images"
202 var nit_src
= new ImageSetSrc(nit_class_name
)
203 nit_src
.attributes
.add
"\tprivate var main_image: Image\n"
204 nit_src
.load_exprs
.add
"\t\tmain_image = app.load_image(\"images
/{drawing_name}.png\
")\n"
206 # Sort images by name, it prevents Array errors and looks better
207 alpha_comparator
.sort
(images
)
209 # Add images to Nit source file
210 for image
in images
do
211 # Adapt coordinates to new top left and scale
212 var x
= image
.x
.adapt
(min_x
, scale
)
213 var y
= image
.y
.adapt
(min_y
, scale
)
214 var w
= (image
.w
.to_f
*scale
).to_i
215 var h
= (image
.h
.to_f
*scale
).to_i
217 var nit_name
= image
.name
218 var last_char
= nit_name
.chars
.last
219 if last_char
.to_s
.is_numeric
then
221 # TODO support more than 10 images in an array
223 nit_name
= nit_name
.substring
(0, nit_name
.length-1
)
224 if not arrays_of_images
.has
(nit_name
) then
225 # Create class attribute to store Array
226 arrays_of_images
.add
(nit_name
)
227 nit_src
.attributes
.add
"\tvar {nit_name} = new Array[Image]\n"
229 nit_src
.load_exprs
.add
"\t\t{nit_name}.add(main_image.subimage({x}, {y}, {w}, {h}))\n"
232 nit_src
.attributes
.add
"\tvar {nit_name}: Image\n"
233 nit_src
.load_exprs
.add
"\t\t{nit_name} = main_image.subimage({x}, {y}, {w}, {h})\n"
238 var src_file
= new OFStream.open
("{src_path}/{drawing_name}.nit")
239 nit_src
.write_to
(src_file
)
242 # Find closest power of 2
243 var dx
= max_x
- min_x
244 max_x
= dx
.next_pow2
+ min_x
246 var dy
= max_y
- min_y
247 max_y
= dy
.next_pow2
+ min_y
249 # Inkscape's --export-area inverts the Y axis. It uses the lower left corner of
250 # the drawing area where as queries return coordinates from the top left.
251 var y0
= page_height
- max_y
252 var y1
= page_height
- min_y
254 # Output png file to assets
255 var png_path
= "{assets_path}/images/{drawing_name}.png"
256 var proc2
= new Process.from_a
(prog
, [drawing
, "--without-gui",
257 "--export-dpi={(90.0*scale).to_i}",
258 "--export-png={png_path}",
259 "--export-area={min_x}:{y0}:{max_x}:{y1}",
260 "--export-background=#000000", "--export-background-opacity=0.0"])