ExportTool.vala
/*
Copyright (C) 2012 2014 2015 2019 Johan Mattsson
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
*/
using B;
namespace BirdFont {
public class ExportTool : GLib.Object {
public static string? error_message = null;
public ExportTool (string n) {
}
public static void set_output_directory () {
#if MAC
Font font = BirdFont.get_current_font ();
string? path = font.get_export_directory ();
FileChooser fc = new FileChooser ();
fc.file_selected.connect ((p) => {
path = p;
});
if (path == null) {
File export_path_handle = File.new_for_path (path);
if (!can_write (export_path_handle)) {
MainWindow.file_chooser (t_("Export"), fc, FileChooser.LOAD | FileChooser.DIRECTORY);
}
}
font.export_directory = path;
#endif
}
public static string export_selected_paths_to_svg () {
return export_current_glyph_to_string (true);
}
public static string export_selected_paths_to_inkscape_clipboard () {
return export_current_glyph_to_inkscape_clipboard (true);
}
public static string export_current_glyph_to_string (bool only_selected_paths = false) {
return export_to_string (MainWindow.get_current_glyph (), only_selected_paths);
}
public static string export_to_string (Glyph glyph, bool only_selected_paths) {
string name;
StringBuilder s;
name = BirdFontFile.encode (glyph.get_name ());
s = new StringBuilder ();
s.append ("""<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0"
id="glyph_""" + name + """"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
width=""" + "\"" + @"$(glyph.get_width ())" + """px"
height=""" + "\"" + @"$(glyph.get_height ())" + """px">
""");
s.append (@"<g id=\"$(name)\">\n");
s.append (get_svg_path_elements (glyph, only_selected_paths));
s.append ("</g>\n");
s.append ("</svg>");
return s.str;
}
public static string export_current_glyph_to_inkscape_clipboard (bool only_selected_paths = false) {
return export_to_inkscape_clipboard (MainWindow.get_current_glyph (), only_selected_paths);
}
public static string export_to_inkscape_clipboard (Glyph glyph, bool only_selected_paths = false) {
StringBuilder s;
s = new StringBuilder ();
s.append ("""<?xml version="1.0" encoding="UTF-8" standalone="no"?>""");
s.append ("\n");
s.append ("<svg>\n");
s.append ("""<inkscape:clipboard
id="clipboard3009"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
min="0,0"
max="0,0" />
""");
s.append (get_svg_path_elements (glyph, only_selected_paths));
s.append ("</svg>");
return s.str;
}
private static string get_svg_path_elements (Glyph glyph, bool only_selected_paths) {
string glyph_svg;
StringBuilder s;
string name;
int id = 0;
name = glyph.get_name ();
Gee.ArrayList<Path> pl;
s = new StringBuilder ();
glyph_svg = "";
pl = only_selected_paths ? glyph.active_paths : glyph.get_visible_paths ();
foreach (Path p in pl) {
if (p.stroke > 0) {
s.append (@"<path ");
s.append (@"style=\"");
s.append (@"fill:none;");
s.append (@"stroke:#000000;");
s.append (@"stroke-width:$(p.stroke)px;");
if (p.line_cap == LineCap.ROUND) {
s.append (@"stroke-linecap:round;");
} else if (p.line_cap == LineCap.SQUARE) {
s.append (@"stroke-linecap:square;");
}
s.append (@"\" ");
s.append (@"d=\"$(Svg.to_svg_path (p, glyph))\" id=\"path_$(name)_$(id)\" />\n");
id++;
}
}
if (only_selected_paths) {
foreach (Path p in glyph.active_paths) {
if (p.stroke == 0) {
glyph_svg += Svg.to_svg_path (p, glyph);
}
}
} else {
foreach (Path p in glyph.get_visible_paths ()) {
if (p.stroke == 0) {
glyph_svg += Svg.to_svg_path (p, glyph);
}
}
}
if (glyph_svg != "") {
s.append (@"<path ");
s.append (@"style=\"fill:#000000;stroke-width:0px\" ");
s.append (@"d=\"$(glyph_svg)\" id=\"path_$(name)_$(id)\" />\n");
id++;
}
return s.str;
}
public static void export_current_glyph () {
FileChooser fc = new FileChooser ();
fc.file_selected.connect ((selected_file) => {
Glyph glyph = MainWindow.get_current_glyph ();
FontDisplay fd = MainWindow.get_current_display ();
string glyph_svg;
string svg_file;
File file;
DataOutputStream os;
string name;
string fn;
int i;
if (fd is GlyphTab || fd is Glyph) {
glyph = MainWindow.get_current_glyph ();
} else if (fd is Overview) {
Overview overview = MainWindow.get_overview ();
Glyph? g = overview.get_selected_glyph ();
if (g == null) {
warning("No glyph selected in overview.");
return;
}
glyph = (!) g;
} else {
return;
}
name = glyph.get_name ();
if (selected_file == null) {
warning ("No selected file.");
return;
}
svg_file = (!) selected_file;
try {
#if MAC
file = File.new_for_path (svg_file);
#else
i = 1;
fn = svg_file.replace (".svg", "");
file = File.new_for_path (fn + ".svg");
while (file.query_exists ()) {
file = File.new_for_path (fn + @"$i.svg");
i++;
}
#endif
glyph_svg = export_to_string (glyph, false);
os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION));
os.put_string (glyph_svg);
} catch (Error e) {
stderr.printf (@"Export \"$svg_file\" \n");
critical (@"$(e.message)");
}
});
fc.add_extension ("svg");
MainWindow.file_chooser (t_("Save"), fc, FileChooser.SAVE);
}
public static void generate_html_template () {
File config_dir = BirdFont.get_settings_directory ();
File file = get_child (config_dir, "preview.html");
string name = "_NAME_";
DataOutputStream os;
if (file.query_exists ()) {
printd("Preview template exists.\n");
return;
}
try {
os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION));
os.put_string (
"""<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Lorem ipsum</title>
<style type="text/css">
body {
text-rendering: optimizeLegibility;
font-feature-settings: "kern";
margin: 0 0 0 0;
}
@font-face {
font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""SVG';
src: url('"""); os.put_string (@"$(name).svg#$(name)"); os.put_string ("""') format('svg');
}
""");
os.put_string ("""
@font-face {
font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""OTF';
src: url('"""); os.put_string (@"$(name).otf"); os.put_string ("""') format('opentype');
}
""");
os.put_string ("""
@font-face {
font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""TTF';
src: url('"""); os.put_string (@"$(name).ttf"); os.put_string ("""') format('truetype');
}
""");
os.put_string ("""
@font-face {
font-family: '"""); os.put_string (@"$(name)"); os.put_string ("""EOT';
src: url('"""); os.put_string (@"$(name).eot"); os.put_string ("""');
}
""");
os.put_string ("""
section {
padding-left: 25px;
}
h1 {
font-weight:normal;
margin: 10px 0 5px 0;
color: #afafaf;
}
h2 {
font-weight:normal;
margin: 0 0 5px 0;
color: #afafaf;
}
h3 {
font-weight:normal;
margin: 0 0 5px 0;
color: #afafaf;
}
h4 {
font-weight:normal;
margin: 0 0 5px 0;
color: #afafaf;
}
p {
margin: 0 0 5px 0;
color: #000000;
}
div {
font-family: """);
os.put_string ("'");
os.put_string (@"$(name)");
os.put_string ("EOT'");
os.put_string (", '");
os.put_string (@"$(name)");
os.put_string ("OTF'");
os.put_string (", '");
os.put_string (@"$(name)");
os.put_string ("TTF'");
os.put_string (", '");
os.put_string (@"$(name)");
os.put_string ("SVG'");
os.put_string (";");
os.put_string ("""
margin: 0 0 30px 0;
}
h1.bigger {
font-size: 58pt;
}
h2.big {
font-size: 40pt;
}
h3.small {
font-size: 32pt;
}
h4.smaller {
font-size: 18pt;
}
h1.percent {
font-size: 100%;
}
p.bigger {
font-size: 32pt;
}
p.big {
font-size: 24pt;
}
p.small {
font-size: 18pt;
}
p.smaller {
font-size: 12pt;
}
span.swashes {
font-feature-settings: "swsh";
}
span.alternates {
font-feature-settings: "salt" 1;
}
span.smallcaps {
font-variant-caps: small-caps;
font-feature-settings: "smcp";
}
span.capstosmallcaps {
font-variant-caps: all-small-caps;
font-feature-settings: "c2sc", "smcp";
}
</style>
""");
os.put_string (
"""
</head>
<body>
<section>
<div>
<h1 class="bigger">Lorem ipsum</h1>
<p class="bigger">Dolor sit amet!</p>
</div>
<div>
<h2 class="big">Hamburgefonstiv</h2>
<p class="big">""" + name + """</p>
</div>
<div>
<h4 class="smaller">Headline 16pt</h4>
<p class="smaller">The quick brown fox jumps over the lazy dog</p>
</div>
<div>
<h4 class="smaller">""" + t_("Alphabet") + """</h4>
<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>
<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>
<p class="smaller">0 1 2 3 4 5 6 7 8 9</p>
</div>
</section>
</body>
</html>
""");
} catch (GLib.Error e) {
warning (e.message);
}
}
public static void generate_html_document (string html_file, Font font) {
File config_dir = BirdFont.get_settings_directory ();
File template = get_child (config_dir, "preview.html");
if (!template.query_exists ()) {
generate_html_template ();
get_child (config_dir, "preview.html");
} else {
print ("HTML template exits.");
}
if (!template.query_exists ()) {
warning ("Preview template does not exists.");
return;
}
string html_data;
try {
FileUtils.get_contents ((!) template.get_path (), out html_data);
} catch (FileError e) {
warning (e.message);
}
string name;
#if MAC
name = ExportSettings.get_file_name_mac (font);
#else
name = ExportSettings.get_file_name (font);
#endif
html_data = html_data.replace ("_NAME_", name);
try {
print(html_data);
FileUtils.set_contents (html_file, html_data);
} catch (FileError e) {
warning (e.message);
}
}
public static string get_export_folder () {
Font font = BirdFont.get_current_font ();
string? d = font.get_export_directory ();
if (d == null) {
warning ("No export path is not set");
return "";
}
return (!) d;
}
public static File get_export_dir () {
return File.new_for_path (get_export_folder ());
}
public static bool export_ttf_font () {
File f = get_export_dir ();
Font font = BirdFont.get_current_font ();
try {
if (!f.query_exists ()) {
f.make_directory ();
}
} catch (GLib.Error e) {
warning(e.message);
}
printd (@"export_ttf_font:\n");
printd (@"get_export_folder (): $(get_export_folder ())\n");
printd (@"font.get_path (): $(font.get_path ())\n");
printd (@"font.get_folder_path (): $(font.get_folder_path ())\n");
printd (@"font.get_folder (): $((!) f.get_path ())\n");
return export_ttf_font_path (f);
}
public static bool export_ttf_font_path (File folder, bool use_export_settings = true) {
Font current_font = BirdFont.get_current_font ();
File ttf_file;
File ttf_file_mac;
File eot_file;
bool done = true;
string ttf_name;
string ttf_name_mac;
try {
ttf_name = ExportSettings.get_file_name (current_font) + ".ttf";
ttf_name_mac = ExportSettings.get_file_name_mac (current_font) + ".ttf";
if (ttf_name == ttf_name_mac) {
warning ("Same file name for the two ttf files.");
ttf_name_mac = ExportSettings.get_file_name_mac (current_font) + " Mac.ttf";
}
ttf_file = get_child (folder, ttf_name);
ttf_file_mac = get_child (folder, ttf_name_mac);
eot_file = get_child (folder, ExportSettings.get_file_name (current_font) + ".eot");
printd (@"Writing TTF fonts to $((!) ttf_file.get_path ())\n");
if (ttf_file.query_exists ()) {
ttf_file.delete ();
}
if (ttf_file_mac.query_exists ()) {
ttf_file_mac.delete ();
}
if (eot_file.query_exists ()) {
eot_file.delete ();
}
write_ttf ((!) ttf_file.get_path (), (!) ttf_file_mac.get_path ());
if (!use_export_settings || ExportSettings.export_eot_setting (current_font)) {
write_eot ((!) ttf_file.get_path (), (!) eot_file.get_path ());
}
if (use_export_settings && !ExportSettings.export_ttf_setting (current_font)) {
if (ttf_file.query_exists ()) {
ttf_file.delete ();
}
}
} catch (Error e) {
critical (@"$(e.message)");
done = false;
}
return done;
}
public static bool export_svg_font () {
return export_svg_font_path (get_export_dir ());
}
public static bool export_svg_font_path (File folder) {
Font font = BirdFont.get_current_font ();
string file_name = @"$(ExportSettings.get_file_name (font)).svg";
File file;
SvgFontFormatWriter fo;
try {
file = get_child (folder, file_name);
if (file.query_exists ()) {
file.delete ();
}
fo = new SvgFontFormatWriter ();
fo.open (file);
fo.write_font_file (font);
fo.close ();
} catch (Error e) {
critical (@"$(e.message)");
return false;
}
return true;
}
static void write_ttf (string ttf, string ttf_mac) {
Font f = BirdFont.get_current_font ();
OpenFontFormatWriter fo = new OpenFontFormatWriter (f.units_per_em);
File file = (!) File.new_for_path (ttf);
File file_mac = (!) File.new_for_path (ttf_mac);
error_message = null;
try {
fo.open (file, file_mac);
fo.write_ttf_font (f);
fo.close ();
} catch (Error e) {
warning (@"Can't create TTF font to $ttf");
critical (@"$(e.message)");
error_message = e.message;
f.export_directory = null;
}
}
static void write_eot (string ttf, string eot) {
EotWriter fo = new EotWriter (ttf, eot);
try {
fo.write ();
} catch (Error e) {
warning (@"EOF conversion falied, $ttf -> $eot");
critical (@"$(e.message)");
}
}
/*
static bool can_write (File folder) {
File test = get_child (folder, "text.tmp");
bool writable = false;
try {
writable = FileUtils.set_contents ((!) test.get_path (), "test");
if (writable) {
FileUtils.remove ((!) test.get_path ());
}
} catch (GLib.Error e) {
writable = false;
}
return writable;
}
*/
}
}