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