The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Add birdfont paths to Svg table in OTF fonts

These changes was commited to the Birdfont repository Tue, 21 Jun 2016 14:14:50 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
author Johan Mattsson <johan.mattsson.m@gmail.com>
Tue, 21 Jun 2016 14:14:50 +0000 (16:14 +0200)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Tue, 21 Jun 2016 14:14:50 +0000 (16:14 +0200)
commit 45c9c3049b7344f2dd7637b452317591363f0641
tree 5dbdf099aec82e99bfb6b0fd411ab33a705c18d1
parent 7a080167168e6af12c5d3e80bba5dde9c4800730
Add birdfont paths to Svg table in OTF fonts

libbirdfont/BezierTool.vala
libbirdfont/OpenFontFormat/SvgTable.vala
libbirdfont/Svg.vala
libsvgbird/SvgFile.vala
--- a/libbirdfont/BezierTool.vala +++ b/libbirdfont/BezierTool.vala @@ -1,5 +1,5 @@ /* - Copyright (C) 2015 Johan Mattsson + Copyright (C) 2015 2016 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
--- a/libbirdfont/OpenFontFormat/SvgTable.vala +++ b/libbirdfont/OpenFontFormat/SvgTable.vala @@ -13,6 +13,7 @@ */ using B; + using SvgBird; namespace BirdFont { @@ -49,16 +50,18 @@ StringBuilder svg = new StringBuilder (); svg.append ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); + + svg.append ("""<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">"""); + svg.append ("\n\n"); + + svg.append ("<g id="); + svg.append ("\""); + svg.append ("glyph"); + svg.append (@"$gid"); + svg.append ("\" >"); foreach (EmbeddedSvg embedded in embedded_svg) { - svg.append ("""<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">"""); - svg.append ("\n\n"); - - svg.append ("<g id="); - svg.append ("\""); - svg.append ("glyph"); - svg.append (@"$gid"); - svg.append ("\" "); + svg.append ("<g "); // scale the internal coordinates from 100 units per em to the // number of units per em in this font and move the glyph @@ -74,10 +77,12 @@ append_svg_glyph (svg, embedded.svg_data, glyphs); - svg.append ("\n\n"); svg.append ("</g>\n"); - svg.append ("</svg>"); + svg.append ("\n\n"); } + + svg.append ("</g>\n"); + svg.append ("</svg>"); SvgTableEntry entry; entry = new SvgTableEntry ((uint16) gid, svg.str); @@ -93,16 +98,30 @@ Gee.ArrayList<EmbeddedSvg> get_embedded_svg (GlyphCollection glyphs) { Gee.ArrayList<EmbeddedSvg> svg = new Gee.ArrayList<EmbeddedSvg> (); + PathList path_list = new PathList (); - foreach (Object object in glyphs.get_current ().get_visible_objects ()) { + foreach (SvgBird.Object object in glyphs.get_current ().get_visible_objects ()) { if (object is EmbeddedSvg) { svg.add ((EmbeddedSvg) object); + } else if (object is PathObject) { + Path path = ((PathObject) object).get_path (); + + if (path.stroke > 0) { + path_list.append (path.get_completed_stroke ()); + } else { + path_list.add (path); + } } + } + + if (path_list.paths.size > 0) { + EmbeddedSvg svg_data = generate_svg (path_list, glyphs); + svg.add (svg_data); } return svg; } - + void append_svg_glyph (StringBuilder svg, string svg_data, GlyphCollection glyphs) { Gee.ArrayList<Tag> layer_content; Gee.ArrayList<Tag> svg_tags; @@ -238,7 +257,141 @@ this.font_data = fd; } + + public EmbeddedSvg generate_svg (PathList paths, GlyphCollection glyphs) { + StringBuilder svg = new StringBuilder (); + + svg.append ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); + svg.append ("""<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">"""); + + Glyph g = glyphs.get_current (); + Font font = OpenFontFormatWriter.get_current_font (); + svg.append (@"<g transform=\"translate(0, $(font.get_height ()))\">\n"); + svg.append (@"<g transform=\"translate($(-g.left_limit), $(-font.base_line))\">\n"); + + svg.append ("""<path style="fill:#000000;fill-opacity:1;" """); + svg.append ("d=\""); + + foreach (Path p in paths.paths) { + p.add_hidden_double_points (); + + + int i = 0; + EditPoint? n = null; + EditPoint m; + + if (p.points.size < 2) { + return new EmbeddedSvg (new SvgDrawing ()); + } + + p.create_list (); + + foreach (var e in p.points) { + if (i == 0) { + add_abs_start (e, svg); + i++; + n = e; + continue; + } + + m = (!) n; + + add_abs_next (m, e, svg); + + n = e; + i++; + } + + if (!p.is_open ()) { + m = p.get_first_point (); + add_abs_next ((!) n, m, svg); + close_path (svg); + } + } + svg.append ("\" />\n"); + + svg.append ("</g>\n"); + svg.append ("</g>\n"); + svg.append ("</svg>\n"); + + EmbeddedSvg embedded = new EmbeddedSvg (new SvgDrawing ()); + embedded.x = g.left_limit; + embedded.y = font.get_height (); + embedded.svg_data = svg.str; + + return embedded; + } + + public static void add_abs_next (EditPoint start, EditPoint end, StringBuilder svg) { + if (start.right_handle.type == PointType.LINE_QUADRATIC) { + add_abs_line_to (start, end, svg); + } else if (start.right_handle.type == PointType.LINE_CUBIC && end.left_handle.type == PointType.LINE_CUBIC) { + add_abs_line_to (start, end, svg); + } else if (end.left_handle.type == PointType.QUADRATIC || start.right_handle.type == PointType.QUADRATIC) { + add_quadratic_abs_path (start, end, svg); + } else if (end.left_handle.type == PointType.DOUBLE_CURVE || start.right_handle.type == PointType.DOUBLE_CURVE) { + add_double_quadratic_abs_path (start, end, svg); + } else { + add_cubic_abs_path (start, end, svg); + } + } + + private static void add_abs_start (EditPoint ep, StringBuilder svg) { + svg.append_printf ("M"); + svg.append_printf ("%s ", round (ep.x)); + svg.append_printf ("%s ", round (-ep.y)); + } + + public static void close_path (StringBuilder svg) { + svg.append ("z"); + } + + private static void add_abs_line_to (EditPoint start, EditPoint stop, StringBuilder svg) { + svg.append ("L"); + svg.append_printf ("%s ", round (stop.x)); + svg.append_printf ("%s ", round (-stop.y)); + } + + private static void add_double_quadratic_abs_path (EditPoint start, EditPoint end, StringBuilder svg) { + EditPoint middle; + double x, y; + + x = start.get_right_handle ().x + (end.get_left_handle ().x - start.get_right_handle ().x) / 2; + y = start.get_right_handle ().y + (end.get_left_handle ().y - start.get_right_handle ().y) / 2; + + middle = new EditPoint (x, y, PointType.QUADRATIC); + middle.right_handle = end.get_left_handle ().copy (); + + add_quadratic_abs_path (start, middle, svg); + add_quadratic_abs_path (middle, end, svg); + } + + private static void add_quadratic_abs_path (EditPoint start, EditPoint stop, StringBuilder svg) { + // cubic path + svg.append_printf ("Q"); + + svg.append_printf ("%s ", round (start.get_right_handle ().x)); + svg.append_printf ("%s ", round (-start.get_right_handle ().y)); + + svg.append_printf ("%s ", round (stop.x)); + svg.append_printf ("%s ", round (-stop.y)); + } + + private static void add_cubic_abs_path (EditPoint start, EditPoint stop, StringBuilder svg) { + // cubic path + svg.append_printf ("C"); + + svg.append_printf ("%s ", round (start.get_right_handle ().x)); + svg.append_printf ("%s ", round (-start.get_right_handle ().y)); + + svg.append_printf ("%s ", round (stop.get_left_handle ().x)); + svg.append_printf ("%s ", round (-stop.get_left_handle ().y)); + + svg.append_printf ("%s ", round (stop.x)); + svg.append_printf ("%s ", round (-stop.y)); + } + } }
--- a/libbirdfont/Svg.vala +++ b/libbirdfont/Svg.vala @@ -83,13 +83,13 @@ } if (!p.is_open ()) { - m = p.points.get (0); + m = p.get_first_point (); add_abs_next ((!) n, m, svg, g, do_glyph); close_path (svg); } } - private static void add_abs_next (EditPoint start, EditPoint end, StringBuilder svg, Glyph g, bool do_glyph) { + public static void add_abs_next (EditPoint start, EditPoint end, StringBuilder svg, Glyph g, bool do_glyph) { if (start.right_handle.type == PointType.LINE_QUADRATIC) { add_abs_line_to (start, end, svg, g, do_glyph); } else if (start.right_handle.type == PointType.LINE_CUBIC && end.left_handle.type == PointType.LINE_CUBIC) { @@ -119,7 +119,7 @@ } } - private static void close_path (StringBuilder svg) { + public static void close_path (StringBuilder svg) { svg.append ("z"); }
--- a/libsvgbird/SvgFile.vala +++ b/libsvgbird/SvgFile.vala @@ -636,7 +636,7 @@ param = param.replace (",", " "); while (param.index_of (" ") > -1) { - param.replace (" ", " "); + param = param.replace (" ", " "); } return param.strip();