.
1 /*
2 Copyright (C) 2012 2014 2015 Johan Mattsson
3
4 This library is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 3 of the
7 License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13 */
14
15 using B;
16
17 namespace BirdFont {
18
19 public class ExportTool : GLib.Object {
20
21 public ExportTool (string n) {
22 }
23
24 public static string export_selected_paths_to_svg () {
25 return export_current_glyph_to_string (true);
26 }
27
28 public static string export_selected_paths_to_inkscape_clipboard () {
29 return export_current_glyph_to_inkscape_clipboard (true);
30 }
31
32 public static string export_current_glyph_to_string (bool only_selected_paths = false) {
33 return export_to_string (MainWindow.get_current_glyph (), only_selected_paths);
34 }
35
36 public static string export_to_string (Glyph glyph, bool only_selected_paths) {
37 string name;
38 StringBuilder s;
39
40 name = XmlParser.encode (glyph.get_name ());
41 s = new StringBuilder ();
42
43 s.append ("""<?xml version="1.0" encoding="utf-8"?>
44 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
45 <svg version="1.0"
46 id="glyph_""" + name + """"
47 mlns="http://www.w3.org/2000/svg"
48 xmlns:xlink="http://www.w3.org/1999/xlink"
49 x="0px"
50 y="0px"
51 width=""" + "\"" + @"$(glyph.get_width ())" + """px"
52 height=""" + "\"" + @"$(glyph.get_height ())" + """px">
53 """);
54
55 s.append (@"<g id=\"$(name)\">\n");
56
57 s.append (get_svg_path_elements (glyph, only_selected_paths));
58
59 s.append ("</g>\n");
60 s.append ("</svg>");
61
62 return s.str;
63 }
64
65 public static string export_current_glyph_to_inkscape_clipboard (bool only_selected_paths = false) {
66 return export_to_inkscape_clipboard (MainWindow.get_current_glyph (), only_selected_paths);
67 }
68
69 public static string export_to_inkscape_clipboard (Glyph glyph, bool only_selected_paths = false) {
70 StringBuilder s;
71
72 s = new StringBuilder ();
73 s.append ("""<?xml version="1.0" encoding="UTF-8" standalone="no"?>""");
74 s.append ("\n");
75 s.append ("<svg>\n");
76
77 s.append ("""<inkscape:clipboard
78 id="clipboard3009"
79 style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
80 min="0,0"
81 max="0,0" />
82 """);
83
84 s.append (get_svg_path_elements (glyph, only_selected_paths));
85 s.append ("</svg>");
86
87 return s.str;
88 }
89
90 private static string get_svg_path_elements (Glyph glyph, bool only_selected_paths) {
91 string glyph_svg;
92 StringBuilder s;
93 string name;
94 int id = 0;
95
96 name = glyph.get_name ();
97
98 Gee.ArrayList<Path> pl;
99
100 s = new StringBuilder ();
101 glyph_svg = "";
102
103 pl = only_selected_paths ? glyph.active_paths : glyph.get_visible_paths ();
104 foreach (Path p in pl) {
105 if (p.stroke > 0) {
106 s.append (@"<path ");
107 s.append (@"style=\"");
108 s.append (@"fill:none;");
109 s.append (@"stroke:#000000;");
110 s.append (@"stroke-width:$(p.stroke)px;");
111
112 if (p.line_cap == LineCap.ROUND) {
113 s.append (@"stroke-linecap:round;");
114 } else if (p.line_cap == LineCap.SQUARE) {
115 s.append (@"stroke-linecap:square;");
116 }
117
118 s.append (@"\" ");
119
120 s.append (@"d=\"$(Svg.to_svg_path (p, glyph))\" id=\"path_$(name)_$(id)\" />\n");
121 id++;
122 }
123 }
124
125 if (only_selected_paths) {
126 foreach (Path p in glyph.active_paths) {
127 if (p.stroke == 0) {
128 glyph_svg += Svg.to_svg_path (p, glyph);
129 }
130 }
131 } else {
132 foreach (Path p in glyph.get_visible_paths ()) {
133 if (p.stroke == 0) {
134 glyph_svg += Svg.to_svg_path (p, glyph);
135 }
136 }
137 }
138
139 if (glyph_svg != "") {
140 s.append (@"<path ");
141 s.append (@"style=\"fill:#000000;stroke-width:0px\" ");
142 s.append (@"d=\"$(glyph_svg)\" id=\"path_$(name)_$(id)\" />\n");
143 id++;
144 }
145
146 return s.str;
147 }
148
149 public static void export_current_glyph () {
150 FileChooser fc = new FileChooser ();
151 fc.file_selected.connect ((f) => {
152 Glyph glyph = MainWindow.get_current_glyph ();
153 FontDisplay fd = MainWindow.get_current_display ();
154 string glyph_svg;
155 string svg_file;
156 File file;
157 DataOutputStream os;
158 string name;
159 string fn;
160 int i;
161
162 name = glyph.get_name ();
163
164 if (f == null) {
165 return;
166 }
167
168 svg_file = (!) f;
169
170 if (!(fd is Glyph)) {
171 return;
172 }
173
174 try {
175 i = 1;
176 fn = svg_file.replace (".svg", "");
177 file = File.new_for_path (fn + ".svg");
178 while (file.query_exists ()) {
179 file = File.new_for_path (fn + @"$i.svg");
180 i++;
181 }
182
183 glyph_svg = export_current_glyph_to_string ();
184 os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION));
185 os.put_string (glyph_svg);
186
187 } catch (Error e) {
188 stderr.printf (@"Export \"$svg_file\" \n");
189 critical (@"$(e.message)");
190 }
191 });
192
193 MainWindow.file_chooser (t_("Save"), fc, FileChooser.SAVE);
194 }
195
196 public static void generate_html_document (string html_file, Font font) {
197 File file = File.new_for_path (html_file);
198 DataOutputStream os;
199 string name;
200
201 #if MAC
202 name = ExportSettings.get_file_name_mac (font);
203 #else
204 name = ExportSettings.get_file_name (font);
205 #endif
206 try {
207 os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION));
208
209 os.put_string (
210 """<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
211 <html>
212 <head>
213
214 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
215 <title>Lorem ipsum</title>
216
217 <style type="text/css">
218
219 body {
220 text-rendering: optimizeLegibility;
221 font-feature-settings: "kern";
222 -moz-font-feature-settings: "kern=1";
223 -ms-font-feature-settings: "kern";
224 -webkit-font-feature-settings: "kern";
225 -o-font-feature-settings: "kern";
226 }
227
228 @font-face {
229 font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""SVG';
230 src: url('"""); os.put_string (@"$(name).svg#$(name)"); os.put_string ("""') format('svg');
231 }
232 """);
233
234 os.put_string ("""
235 @font-face {
236 font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""TTF';
237 src: url('"""); os.put_string (@"$(name).ttf"); os.put_string ("""') format('truetype');
238 }
239 """);
240
241 os.put_string ("""
242 @font-face {
243 font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""EOT';
244 src: url('"""); os.put_string (@"$(name).eot"); os.put_string ("""');
245 }
246
247 """);
248
249 os.put_string ("""
250 h1 {
251 font-weight:normal;
252 margin: 0 0 5px 0;
253 color: #afafaf;
254 }
255
256 h2 {
257 font-weight:normal;
258 margin: 0 0 5px 0;
259 color: #afafaf;
260 }
261
262 h3 {
263 font-weight:normal;
264 margin: 0 0 5px 0;
265 color: #afafaf;
266 }
267
268 h4 {
269 font-weight:normal;
270 margin: 0 0 5px 0;
271 color: #afafaf;
272 }
273
274 p {
275 margin: 0 0 5px 0;
276 color: #000000;
277 }
278
279 body {
280 margin: 30px 0 0 30px;
281 }
282
283 div {
284 font-family: """);
285
286 os.put_string ("'");
287 os.put_string (@"$(name)");
288 os.put_string ("EOT'");
289
290 os.put_string (", '");
291 os.put_string (@"$(name)");
292 os.put_string ("TTF'");
293
294 os.put_string (", '");
295 os.put_string (@"$(name)");
296 os.put_string ("SVG'");
297
298 os.put_string (";");
299 os.put_string ("""
300 margin: 0 0 30px 0;
301 }
302
303 h1.bigger {
304 font-size: 58pt;
305 }
306
307 h2.big {
308 font-size: 40pt;
309 }
310
311 h3.small {
312 font-size: 32pt;
313 }
314
315 h4.smaller {
316 font-size: 18pt;
317 }
318
319 h1.percent {
320 font-size: 100%;
321 }
322
323 p.bigger {
324 font-size: 32pt;
325 }
326
327 p.big {
328 font-size: 24pt;
329 }
330
331 p.small {
332 font-size: 18pt;
333 }
334
335 p.smaller {
336 font-size: 12pt;
337 }
338
339 span.swashes {
340 -moz-font-feature-settings: "swsh";
341 -ms-font-feature-settings: "swsh";
342 -webkit-font-feature-settings: "swsh";
343 font-feature-settings: "swsh";
344 }
345
346 span.alternates {
347 -moz-font-feature-settings: "salt" 1;
348 -ms-font-feature-settings: "salt" 1;
349 -webkit-font-feature-settings: "salt" 1;
350 font-feature-settings: "salt" 1;
351 }
352
353 span.smallcaps {
354 font-variant-caps: small-caps;
355 -moz-font-feature-settings: "smcp";
356 -ms-font-feature-settings: "smcp";
357 -webkit-font-feature-settings: "smcp";
358 font-feature-settings: "smcp";
359 }
360
361 span.capstosmallcaps {
362 font-variant-caps: all-small-caps;
363 -moz-font-feature-settings: "c2sc", "smcp";
364 -ms-font-feature-settings: "c2sc", "smcp";
365 -webkit-font-feature-settings: "c2sc", "smcp";
366 font-feature-settings: "c2sc", "smcp";
367 }
368 </style>
369 """);
370
371 os.put_string (
372 """
373 </head>
374 <body>
375
376 <div>
377 <h1 class="bigger">Lorem ipsum</h1>
378 <p class="bigger">Dolor sit amet!</p>
379 </div>
380
381 <div>
382 <h2 class="big">Hamburgerfonstiv</h2>
383 <p class="big">""" + name + """</p>
384 </div>
385
386 <div>
387 <h3 class="big"></h3>
388 <p class="big">
389 <span class="capstosmallcaps">OTF</span> features,
390 <span class="swashes">like swashes </span>
391 <span class="alternates">alternates & </span>
392 <span class="smallcaps">small caps</span>, can be added
393 to the font.</span>
394 </p>
395 </div>
396
397 <div>
398 <h4 class="smaller">Headline 16pt</h4>
399 <p class="smaller">Ett litet stycke svalhjärta.</p>
400 </div>
401
402 <div>
403 <h4 class="smaller">""" + t_("Alphabet") + """</h4>
404 <p class="smaller">""" + t_("a b c d e f g h i j k l m n o p q r s t u v w x y z") + """</p>
405 <p class="smaller">""" + t_("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z") + """</p>
406 <p class="smaller">0 1 2 3 4 5 6 7 8 9</p>
407 </div>
408
409 </body>
410 </html>
411 """);
412
413 } catch (GLib.Error e) {
414 warning (e.message);
415 }
416 }
417
418 public static bool export_ttf_font () {
419 Font font = BirdFont.get_current_font ();
420 File f = font.get_folder ();
421
422 printd (@"export_ttf_font:\n");
423 printd (@"font.get_path (): $(font.get_path ())\n");
424 printd (@"font.get_folder_path (): $(font.get_folder_path ())\n");
425 printd (@"font.get_folder (): $((!) f.get_path ())\n");
426
427 return export_ttf_font_path (f);
428 }
429
430 public static bool export_ttf_font_path (File folder, bool use_export_settings = true) {
431 Font current_font = BirdFont.get_current_font ();
432 File ttf_file;
433 File ttf_file_mac;
434 File eot_file;
435 bool done = true;
436 string ttf_name;
437 string ttf_name_mac;
438
439 try {
440 ttf_name = ExportSettings.get_file_name (current_font) + ".ttf";
441 ttf_name_mac = ExportSettings.get_file_name_mac (current_font) + ".ttf";
442
443 if (ttf_name == ttf_name_mac) {
444 warning ("Same file name for the two ttf files.");
445 ttf_name_mac = ExportSettings.get_file_name_mac (current_font) + " Mac.ttf";
446 }
447
448 ttf_file = get_child (folder, ttf_name);
449 ttf_file_mac = get_child (folder, ttf_name_mac);
450 eot_file = get_child (folder, ExportSettings.get_file_name (current_font) + ".eot");
451
452 printd (@"Writing TTF fonts to $((!) ttf_file.get_path ())\n");
453
454 if (ttf_file.query_exists ()) {
455 ttf_file.delete ();
456 }
457
458 if (ttf_file_mac.query_exists ()) {
459 ttf_file_mac.delete ();
460 }
461
462 if (eot_file.query_exists ()) {
463 eot_file.delete ();
464 }
465
466 write_ttf ((!) ttf_file.get_path (), (!) ttf_file_mac.get_path ());
467
468 if (!use_export_settings || ExportSettings.export_eot_setting (current_font)) {
469 write_eot ((!) ttf_file.get_path (), (!) eot_file.get_path ());
470 }
471
472 if (use_export_settings && !ExportSettings.export_ttf_setting (current_font)) {
473 if (ttf_file.query_exists ()) {
474 ttf_file.delete ();
475 }
476 }
477 } catch (Error e) {
478 critical (@"$(e.message)");
479 done = false;
480 }
481
482 return done;
483 }
484
485 public static bool export_svg_font () {
486 Font font = BirdFont.get_current_font ();
487 return export_svg_font_path (font.get_folder ());
488 }
489
490 public static bool export_svg_font_path (File folder) {
491 Font font = BirdFont.get_current_font ();
492 string file_name = @"$(ExportSettings.get_file_name (font)).svg";
493 File file;
494 SvgFontFormatWriter fo;
495
496 try {
497 file = get_child (folder, file_name);
498
499 if (file.query_exists ()) {
500 file.delete ();
501 }
502
503 fo = new SvgFontFormatWriter ();
504 fo.open (file);
505 fo.write_font_file (font);
506 fo.close ();
507 } catch (Error e) {
508 critical (@"$(e.message)");
509 return false;
510 }
511
512 return true;
513 }
514
515 static void write_ttf (string ttf, string ttf_mac) {
516 Font f = BirdFont.get_current_font ();
517 OpenFontFormatWriter fo = new OpenFontFormatWriter (f.units_per_em);
518
519 File file = (!) File.new_for_path (ttf);
520 File file_mac = (!) File.new_for_path (ttf_mac);
521
522 try {
523 fo.open (file, file_mac);
524 fo.write_ttf_font (f);
525 fo.close ();
526 } catch (Error e) {
527 warning (@"Can't write TTF font to $ttf");
528 critical (@"$(e.message)");
529 }
530 }
531
532 static void write_eot (string ttf, string eot) {
533 EotWriter fo = new EotWriter (ttf, eot);
534
535 try {
536 fo.write ();
537 } catch (Error e) {
538 warning (@"EOF conversion falied, $ttf -> $eot");
539 critical (@"$(e.message)");
540 }
541 }
542 }
543
544 }
545