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