The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

ExportTool.vala in libbirdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/ExportTool.vala.
Merge ../birdfont-2.x
1 /* 2 Copyright (C) 2012 - 2016 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 using SvgBird; 17 18 namespace BirdFont { 19 20 public class ExportTool : GLib.Object { 21 22 public static string? error_message = null; 23 24 public ExportTool (string n) { 25 } 26 27 public static void set_output_directory () { 28 #if MAC 29 Font font = BirdFont.get_current_font (); 30 string? path = font.get_export_directory (); 31 32 FileChooser fc = new FileChooser (); 33 fc.file_selected.connect ((p) => { 34 path = p; 35 }); 36 37 if (path == null) { 38 File export_path_handle = File.new_for_path (path); 39 40 if (!can_write (export_path_handle)) { 41 MainWindow.file_chooser (t_("Export"), fc, FileChooser.LOAD | FileChooser.DIRECTORY); 42 } 43 } 44 45 font.export_directory = path; 46 #endif 47 } 48 49 public static string export_selected_paths_to_svg () { 50 return export_current_glyph_to_string (true); 51 } 52 53 public static string export_selected_paths_to_inkscape_clipboard () { 54 return export_current_glyph_to_inkscape_clipboard (true); 55 } 56 57 public static string export_current_glyph_to_string (bool only_selected_paths = false) { 58 return export_to_string (MainWindow.get_current_glyph (), only_selected_paths); 59 } 60 61 public static string export_to_string (Glyph glyph, bool only_selected_paths) { 62 string name; 63 StringBuilder s; 64 Font font; 65 66 font = BirdFont.get_current_font (); 67 name = XmlParser.encode (glyph.get_name ()); 68 s = new StringBuilder (); 69 70 s.append ("""<?xml version="1.0" encoding="utf-8"?> 71 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> 72 <svg version="1.0" 73 id="glyph_""" + name + """" 74 xmlns="http://www.w3.org/2000/svg" 75 xmlns:xlink="http://www.w3.org/1999/xlink" 76 x="0px" 77 y="0px" 78 width=""" + "\"" + @"$(glyph.get_width ())" + """px" 79 height=""" + "\"" + @"$(font.top_position - font.bottom_position)" + """px"> 80 """); 81 82 s.append (@"<g id=\"$(name)\">\n"); 83 84 s.append (get_svg_path_elements (glyph, only_selected_paths)); 85 86 s.append ("</g>\n"); 87 s.append ("</svg>"); 88 89 return s.str; 90 } 91 92 public static string export_current_glyph_to_inkscape_clipboard (bool only_selected_paths = false) { 93 return export_to_inkscape_clipboard (MainWindow.get_current_glyph (), only_selected_paths); 94 } 95 96 public static string export_to_inkscape_clipboard (Glyph glyph, bool only_selected_paths = false) { 97 StringBuilder s; 98 99 s = new StringBuilder (); 100 s.append ("""<?xml version="1.0" encoding="UTF-8" standalone="no"?>"""); 101 s.append ("\n"); 102 s.append ("<svg>\n"); 103 104 s.append ("""<inkscape:clipboard 105 id="clipboard3009" 106 style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" 107 min="0,0" 108 max="0,0" /> 109 """); 110 111 s.append (get_svg_path_elements (glyph, only_selected_paths)); 112 s.append ("</svg>"); 113 114 return s.str; 115 } 116 117 private static string get_svg_path_elements (Glyph glyph, bool only_selected_paths) { 118 string glyph_svg; 119 StringBuilder s; 120 string name; 121 int id = 0; 122 123 name = glyph.get_name (); 124 125 Gee.ArrayList<SvgBird.Object> pl; 126 127 s = new StringBuilder (); 128 glyph_svg = ""; 129 130 pl = only_selected_paths ? glyph.active_paths : glyph.get_visible_objects (); 131 132 foreach (SvgBird.Object o in pl) { 133 134 if (o is PathObject) { 135 Path p = ((PathObject) o).get_path (); 136 137 if (p.stroke > 0) { 138 s.append (@"<path "); 139 s.append (@"style=\""); 140 s.append (@"fill:none;"); 141 s.append (@"stroke:#000000;"); 142 s.append (@"stroke-width:$(p.stroke)px;"); 143 144 if (p.line_cap == LineCap.ROUND) { 145 s.append (@"stroke-linecap:round;"); 146 } else if (p.line_cap == LineCap.SQUARE) { 147 s.append (@"stroke-linecap:square;"); 148 } 149 150 s.append (@"\" "); 151 152 s.append (@"d=\"$(Svg.to_svg_path (p, glyph))\" id=\"path_$(name)_$(id)\" />\n"); 153 id++; 154 } 155 } else { 156 warning ("Copy and paste for other objects not implemented."); 157 } 158 } 159 160 if (only_selected_paths) { 161 foreach (SvgBird.Object p in glyph.active_paths) { 162 if (p is PathObject) { 163 Path path = ((PathObject) p).get_path (); 164 if (path.stroke == 0) { 165 glyph_svg += Svg.to_svg_path (path, glyph); 166 } 167 } else { 168 warning ("Not implemented"); 169 } 170 } 171 } else { 172 foreach (Path p in glyph.get_visible_paths ()) { 173 if (p.stroke == 0) { 174 glyph_svg += Svg.to_svg_path (p, glyph); 175 } 176 } 177 } 178 179 if (glyph_svg != "") { 180 s.append (@"<path "); 181 s.append (@"style=\"fill:#000000;stroke-width:0px\" "); 182 s.append (@"d=\"$(glyph_svg)\" id=\"path_$(name)_$(id)\" />\n"); 183 id++; 184 } 185 186 return s.str; 187 } 188 189 public static void export_current_glyph () { 190 FileChooser fc = new FileChooser (); 191 fc.file_selected.connect ((selected_file) => { 192 Glyph glyph = MainWindow.get_current_glyph (); 193 FontDisplay fd = MainWindow.get_current_display (); 194 string glyph_svg; 195 string svg_file; 196 File file; 197 DataOutputStream os; 198 string name; 199 string fn; 200 int i; 201 202 if (fd is GlyphTab || fd is Glyph) { 203 glyph = MainWindow.get_current_glyph (); 204 } else if (fd is OverView) { 205 OverView overview = MainWindow.get_overview (); 206 Glyph? g = overview.get_selected_glyph (); 207 208 if (g == null) { 209 warning("No glyph selected in overview."); 210 return; 211 } 212 213 glyph = (!) g; 214 } else { 215 return; 216 } 217 218 name = glyph.get_name (); 219 220 if (selected_file == null) { 221 warning ("No selected file."); 222 return; 223 } 224 225 svg_file = (!) selected_file; 226 227 try { 228 #if MAC 229 file = File.new_for_path (svg_file); 230 #else 231 i = 1; 232 fn = svg_file.replace (".svg", ""); 233 file = File.new_for_path (fn + ".svg"); 234 while (file.query_exists ()) { 235 file = File.new_for_path (fn + @"$i.svg"); 236 i++; 237 } 238 #endif 239 glyph_svg = export_to_string (glyph, false); 240 os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION)); 241 os.put_string (glyph_svg); 242 } catch (Error e) { 243 stderr.printf (@"Export \"$svg_file\" \n"); 244 critical (@"$(e.message)"); 245 } 246 }); 247 248 fc.add_extension ("svg"); 249 MainWindow.file_chooser (t_("Save"), fc, FileChooser.SAVE); 250 } 251 252 public static void generate_html_document (string html_file, Font font) { 253 File file = File.new_for_path (html_file); 254 DataOutputStream os; 255 string name; 256 257 #if MAC 258 name = ExportSettings.get_file_name_mac (font); 259 #else 260 name = ExportSettings.get_file_name (font); 261 #endif 262 try { 263 os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION)); 264 265 os.put_string ( 266 """<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 267 <html> 268 <head> 269 270 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 271 <title>Lorem ipsum</title> 272 273 <style type="text/css"> 274 275 body { 276 text-rendering: optimizeLegibility; 277 font-feature-settings: "kern"; 278 -moz-font-feature-settings: "kern=1"; 279 -ms-font-feature-settings: "kern"; 280 -webkit-font-feature-settings: "kern"; 281 -o-font-feature-settings: "kern"; 282 } 283 284 @font-face { 285 font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""SVG'; 286 src: url('"""); os.put_string (@"$(name).svg#$(name)"); os.put_string ("""') format('svg'); 287 } 288 """); 289 290 os.put_string (""" 291 @font-face { 292 font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""TTF'; 293 src: url('"""); os.put_string (@"$(name).ttf"); os.put_string ("""') format('truetype'); 294 } 295 """); 296 297 os.put_string (""" 298 @font-face { 299 font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""EOT'; 300 src: url('"""); os.put_string (@"$(name).eot"); os.put_string ("""'); 301 } 302 303 """); 304 305 os.put_string (""" 306 h1 { 307 font-weight:normal; 308 margin: 0 0 5px 0; 309 color: #afafaf; 310 } 311 312 h2 { 313 font-weight:normal; 314 margin: 0 0 5px 0; 315 color: #afafaf; 316 } 317 318 h3 { 319 font-weight:normal; 320 margin: 0 0 5px 0; 321 color: #afafaf; 322 } 323 324 h4 { 325 font-weight:normal; 326 margin: 0 0 5px 0; 327 color: #afafaf; 328 } 329 330 p { 331 margin: 0 0 5px 0; 332 color: #000000; 333 } 334 335 body { 336 margin: 30px 0 0 30px; 337 } 338 339 div { 340 font-family: """); 341 342 os.put_string ("'"); 343 os.put_string (@"$(name)"); 344 os.put_string ("EOT'"); 345 346 os.put_string (", '"); 347 os.put_string (@"$(name)"); 348 os.put_string ("TTF'"); 349 350 os.put_string (", '"); 351 os.put_string (@"$(name)"); 352 os.put_string ("SVG'"); 353 354 os.put_string (";"); 355 os.put_string (""" 356 margin: 0 0 30px 0; 357 } 358 359 h1.bigger { 360 font-size: 58pt; 361 } 362 363 h2.big { 364 font-size: 40pt; 365 } 366 367 h3.small { 368 font-size: 32pt; 369 } 370 371 h4.smaller { 372 font-size: 18pt; 373 } 374 375 h1.percent { 376 font-size: 100%; 377 } 378 379 p.bigger { 380 font-size: 32pt; 381 } 382 383 p.big { 384 font-size: 24pt; 385 } 386 387 p.small { 388 font-size: 18pt; 389 } 390 391 p.smaller { 392 font-size: 12pt; 393 } 394 395 span.swashes { 396 -moz-font-feature-settings: "swsh"; 397 -ms-font-feature-settings: "swsh"; 398 -webkit-font-feature-settings: "swsh"; 399 font-feature-settings: "swsh"; 400 } 401 402 span.alternates { 403 -moz-font-feature-settings: "salt" 1; 404 -ms-font-feature-settings: "salt" 1; 405 -webkit-font-feature-settings: "salt" 1; 406 font-feature-settings: "salt" 1; 407 } 408 409 span.smallcaps { 410 font-variant-caps: small-caps; 411 -moz-font-feature-settings: "smcp"; 412 -ms-font-feature-settings: "smcp"; 413 -webkit-font-feature-settings: "smcp"; 414 font-feature-settings: "smcp"; 415 } 416 417 span.capstosmallcaps { 418 font-variant-caps: all-small-caps; 419 -moz-font-feature-settings: "c2sc", "smcp"; 420 -ms-font-feature-settings: "c2sc", "smcp"; 421 -webkit-font-feature-settings: "c2sc", "smcp"; 422 font-feature-settings: "c2sc", "smcp"; 423 } 424 </style> 425 """); 426 427 os.put_string ( 428 """ 429 </head> 430 <body> 431 432 <div> 433 <h1 class="bigger">Lorem ipsum</h1> 434 <p class="bigger">Dolor sit amet!</p> 435 </div> 436 437 <div> 438 <h2 class="big">Hamburgerfonstiv</h2> 439 <p class="big">""" + name + """</p> 440 </div> 441 442 <div> 443 <h3 class="big"></h3> 444 <p class="big"> 445 <span class="capstosmallcaps">OTF</span> features, 446 <span class="swashes">like swashes </span> 447 <span class="alternates">alternates &amp; </span> small caps, can be added 448 to the font.</span> 449 </p> 450 </div> 451 452 <div> 453 <h4 class="smaller">Headline 16pt</h4> 454 <p class="smaller">Ett litet stycke svalhjärta.</p> 455 </div> 456 457 <div> 458 <h4 class="smaller">""" + t_("Alphabet") + """</h4> 459 <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> 460 <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> 461 <p class="smaller">0 1 2 3 4 5 6 7 8 9</p> 462 </div> 463 464 </body> 465 </html> 466 """); 467 468 } catch (GLib.Error e) { 469 warning (e.message); 470 } 471 } 472 473 public static string get_export_folder () { 474 Font font = BirdFont.get_current_font (); 475 string? d = font.get_export_directory (); 476 477 if (d == null) { 478 warning ("No export path is not set"); 479 return ""; 480 } 481 482 return (!) d; 483 } 484 485 static bool can_write (File folder) { 486 File test = get_child (folder, "text.tmp"); 487 bool writable = false; 488 489 try { 490 writable = FileUtils.set_contents (test.get_path (), "test"); 491 492 if (writable) { 493 FileUtils.remove (test.get_path ()); 494 } 495 } catch (GLib.Error e) { 496 writable = false; 497 } 498 499 return writable; 500 } 501 502 public static File get_export_dir () { 503 return File.new_for_path (get_export_folder ()); 504 } 505 506 public static bool export_ttf_font () { 507 File f = get_export_dir (); 508 Font font = BirdFont.get_current_font (); 509 510 try { 511 if (!f.query_exists ()) { 512 f.make_directory (); 513 } 514 } catch (GLib.Error e) { 515 warning(e.message); 516 } 517 518 printd (@"export_ttf_font:\n"); 519 printd (@"get_export_folder (): $(get_export_folder ())\n"); 520 printd (@"font.get_path (): $(font.get_path ())\n"); 521 printd (@"font.get_folder_path (): $(font.get_folder_path ())\n"); 522 printd (@"font.get_folder (): $((!) f.get_path ())\n"); 523 524 return export_ttf_font_path (f); 525 } 526 527 public static bool export_ttf_font_path (File folder, bool use_export_settings = true) { 528 Font current_font = BirdFont.get_current_font (); 529 File ttf_file; 530 File ttf_file_mac; 531 File eot_file; 532 bool done = true; 533 string ttf_name; 534 string ttf_name_mac; 535 536 try { 537 ttf_name = ExportSettings.get_file_name (current_font) + ".ttf"; 538 ttf_name_mac = ExportSettings.get_file_name_mac (current_font) + ".ttf"; 539 540 if (ttf_name == ttf_name_mac) { 541 warning ("Same file name for the two ttf files."); 542 ttf_name_mac = ExportSettings.get_file_name_mac (current_font) + " Mac.ttf"; 543 } 544 545 ttf_file = get_child (folder, ttf_name); 546 ttf_file_mac = get_child (folder, ttf_name_mac); 547 eot_file = get_child (folder, ExportSettings.get_file_name (current_font) + ".eot"); 548 549 printd (@"Writing TTF fonts to $((!) ttf_file.get_path ())\n"); 550 551 if (ttf_file.query_exists ()) { 552 ttf_file.delete (); 553 } 554 555 if (ttf_file_mac.query_exists ()) { 556 ttf_file_mac.delete (); 557 } 558 559 if (eot_file.query_exists ()) { 560 eot_file.delete (); 561 } 562 563 write_ttf ((!) ttf_file.get_path (), (!) ttf_file_mac.get_path ()); 564 565 if (!use_export_settings || ExportSettings.export_eot_setting (current_font)) { 566 write_eot ((!) ttf_file.get_path (), (!) eot_file.get_path ()); 567 } 568 569 if (use_export_settings && !ExportSettings.export_ttf_setting (current_font)) { 570 if (ttf_file.query_exists ()) { 571 ttf_file.delete (); 572 } 573 } 574 } catch (Error e) { 575 critical (@"$(e.message)"); 576 done = false; 577 } 578 579 return done; 580 } 581 582 public static bool export_svg_font () { 583 return export_svg_font_path (get_export_dir ()); 584 } 585 586 public static bool export_svg_font_path (File folder) { 587 Font font = BirdFont.get_current_font (); 588 string file_name = @"$(ExportSettings.get_file_name (font)).svg"; 589 File file; 590 SvgFontFormatWriter fo; 591 592 try { 593 file = get_child (folder, file_name); 594 595 if (file.query_exists ()) { 596 file.delete (); 597 } 598 599 fo = new SvgFontFormatWriter (); 600 fo.open (file); 601 fo.write_font_file (font); 602 fo.close (); 603 } catch (Error e) { 604 critical (@"$(e.message)"); 605 return false; 606 } 607 608 return true; 609 } 610 611 static void write_ttf (string ttf, string ttf_mac) { 612 Font f = BirdFont.get_current_font (); 613 OpenFontFormatWriter fo = new OpenFontFormatWriter (f.units_per_em); 614 615 File file = (!) File.new_for_path (ttf); 616 File file_mac = (!) File.new_for_path (ttf_mac); 617 618 error_message = null; 619 620 try { 621 fo.open (file, file_mac); 622 fo.write_ttf_font (f); 623 fo.close (); 624 } catch (Error e) { 625 warning (@"Can't create TTF font to $ttf"); 626 critical (@"$(e.message)"); 627 error_message = e.message; 628 f.export_directory = null; 629 } 630 } 631 632 static void write_eot (string ttf, string eot) { 633 EotWriter fo = new EotWriter (ttf, eot); 634 635 try { 636 fo.write (); 637 } catch (Error e) { 638 warning (@"EOF conversion falied, $ttf -> $eot"); 639 critical (@"$(e.message)"); 640 } 641 } 642 } 643 644 } 645