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