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