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