Commit 45c9c30
Add birdfont paths to Svg table in OTF fonts
Changed files (4)
modifiedlibbirdfont/BezierTool.valamodifiedlibbirdfont/OpenFontFormat/SvgTable.valamodifiedlibbirdfont/Svg.valamodifiedlibsvgbird/SvgFile.vala
Diff
@@ -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 @@ -13,6 +13,7 @@ */ using B;+using SvgBird; namespace BirdFont { @@ -49,16 +50,18 @@ public class SvgTable : OtfTable { 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 @@ public class SvgTable : OtfTable { 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 @@ public class SvgTable : OtfTable { 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,6 +257,140 @@ public class SvgTable : OtfTable { 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));+ }+ } }@@ -83,13 +83,13 @@ public class Svg { } 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 @@ public class Svg { } } - private static void close_path (StringBuilder svg) {+ public static void close_path (StringBuilder svg) { svg.append ("z"); } @@ -636,7 +636,7 @@ public class SvgFile : GLib.Object { param = param.replace (",", " "); while (param.index_of (" ") > -1) {- param.replace (" ", " ");+ param = param.replace (" ", " "); } return param.strip();