Clone in a terminal:
Commit f17a0ce
Johan Mattsson - 2016-07-16T20:12:29+00:00
f17a0ce0a03cd87282ae994695bac5ad48d1e0dfjohan.mattsson.m@gmail.com

Draw text items in SVG files

Changed files (3)

Diff

diff --git a/libsvgbird/SvgFile.vala b/libsvgbird/SvgFile.valaindex 4b13a80..dbe4848 100644--- a/libsvgbird/SvgFile.vala+++ b/libsvgbird/SvgFile.vala@@ -410,6 +410,10 @@ public class SvgFile : GLib.Object { 			parse_line (layer, parent_style, tag); 		} 		+		if (name == "text") {+			parse_text (layer, parent_style, tag);+		}+		 		if (name == "svg") { 			SvgDrawing embedded = parse_svg_file (tag, format); 			layer.add_object (embedded);@@ -602,6 +606,35 @@ public class SvgFile : GLib.Object { 		set_object_properties (line, parent_style, tag); 		layer.add_object (line); 	}++	private void parse_text (Layer layer, SvgStyle parent_style, XmlElement tag) {+		Text text = new Text ();+		+		foreach (Attribute attr in tag.get_attributes ()) {+			string name = attr.get_name ();+			+			if (name == "font-size") {+				text.font_size = (int) parse_number (attr.get_content ());+			}++			if (name == "font-family") {+				text.font_family = attr.get_content ();+			}++			if (name == "x") {+				text.x = parse_number (attr.get_content ());+			}+			+			if (name == "y") {+				text.y = parse_number (attr.get_content ());+			}+		}+		+		text.set_text (tag.get_content ());+		+		set_object_properties (text, parent_style, tag);+		layer.add_object (text);+	} 	 	// FIXME: reverse order? 	public static SvgTransforms parse_transform (string transforms) {@@ -611,6 +644,10 @@ public class SvgFile : GLib.Object { 		 		transform_functions = new SvgTransforms (); 		+		if (transforms == "") {+			return transform_functions;+		}+		 		transform = transform.replace ("\t", " "); 		transform = transform.replace ("\n", " "); 		transform = transform.replace ("\r", " ");@@ -621,7 +658,7 @@ public class SvgFile : GLib.Object { 		} 		 		if (unlikely (transform.index_of (")") == -1)) {-			warning ("No parenthesis in transform function.");+			warning (@"No parenthesis in transform function: $transform"); 			return transform_functions; 		} 		diff --git a/libsvgbird/Text.vala b/libsvgbird/Text.valanew file mode 100644index 0000000..2888fe8--- /dev/null+++ b/libsvgbird/Text.vala@@ -0,0 +1,82 @@+/*+	Copyright (C) 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 +	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 Cairo;+using Math;++extern class svg_bird_font_item {}+extern void svg_bird_draw_text (Context cr, svg_bird_font_item* font, string text);++extern void svg_bird_font_item_delete (svg_bird_font_item* item);+extern svg_bird_font_item svg_bird_font_item_create (string font_file, int font_size);++namespace SvgBird {++public class Text : Object {+	public string font_family = "";+	public int font_size = 12;+	public double x = 0;+	public double y = 0;+	public string content;+	+	svg_bird_font_item* font;+	+	public Text () {+		font = svg_bird_font_item_create ("resources/Roboto-Regular.ttf", 34);+	}++	~Text () {+		svg_bird_font_item_delete (font);+	}++	public void set_text (string t) {+		content = t.replace ("\n", " ");+		content = content.replace ("\t", " ");+		+		while (content.index_of ("  ") > -1) {+			content = content.replace ("  ", " ");+		}+		+		content = content.strip ();+	}++	public Text.create_copy (Text c) {+		Object.copy_attributes (c, this);+		font_family = c.font_family;+		x = c.x;+		y = c.y;+		font_size = c.font_size;+	}+	+	public override void draw_outline (Context cr) {+		cr.save ();+		cr.translate (x, y);+		svg_bird_draw_text (cr, font, content);+		cr.restore ();+	}++	public override bool is_empty () {+		return false;+	}+	+	public override Object copy () {+		return new Text.create_copy (this);+	}++	public override string to_string () {+		return "Text";+	}+}++}diff --git a/libsvgbird/text_helpers.c b/libsvgbird/text_helpers.cnew file mode 100644index 0000000..5826e95--- /dev/null+++ b/libsvgbird/text_helpers.c@@ -0,0 +1,137 @@+#include <stdlib.h>+#include <glib.h>+#include <stdio.h>+#include <math.h>+#include <harfbuzz/hb.h>+#include <harfbuzz/hb-ft.h>+#include <cairo.h>+#include <cairo-ft.h>++#define FONT_SIZE 36+#define MARGIN (FONT_SIZE * .5)++typedef struct svg_bird_font_item_t {+	int font_size;+	FT_Library ft_library;+	FT_Face ft_face;+	hb_font_t *hb_font;+} svg_bird_font_item;++svg_bird_font_item* svg_bird_font_item_create (const char* font_file, int font_size) {+	FT_Error ft_error;++	svg_bird_font_item* font = malloc (sizeof (svg_bird_font_item));++	font->font_size = font_size;++	if ((ft_error = FT_Init_FreeType (&font->ft_library))) {+		g_warning ("Can't init freetype");+		return NULL;+	}+	+	if ((ft_error = FT_New_Face (font->ft_library, font_file, 0, &font->ft_face))) {+		g_warning ("Can't init freetype font.");+		return NULL;+	}+	+	if ((ft_error = FT_Set_Char_Size (font->ft_face, font_size * 64, font_size * 64, 0, 0)))  {+		g_warning ("Can't set font size.");+		return NULL;+	}++	font->hb_font = hb_ft_font_create (font->ft_face, NULL);++}++void svg_bird_font_item_delete (svg_bird_font_item* item) {+	if (item != NULL) {+		FT_Done_Face (item->ft_face);+		FT_Done_FreeType (item->ft_library);+		hb_font_destroy (item->hb_font);+		free (item);+	}+}++void svg_bird_draw_text (cairo_t* cr, svg_bird_font_item* font, const char* text) {+	cairo_save (cr);+	+	hb_buffer_t *hb_buffer;	++	hb_buffer = hb_buffer_create ();+	hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1);+	hb_buffer_guess_segment_properties (hb_buffer);++	hb_shape (font->hb_font, hb_buffer, NULL, 0);++	unsigned int len = hb_buffer_get_length (hb_buffer);+	hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL);+	hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);+	+	double current_x = 0;+	double current_y = 0;+	for (unsigned int i = 0; i < len; i++) {+		hb_codepoint_t gid   = info[i].codepoint;+		unsigned int cluster = info[i].cluster;+		double x_position = current_x + pos[i].x_offset / 64.;+		double y_position = current_y + pos[i].y_offset / 64.;+		+		current_x += pos[i].x_advance / 64.;+		current_y += pos[i].y_advance / 64.;+	}++	double width = 0;+	double height = 0;+	for (unsigned int i = 0; i < len; i++) {+		width  += pos[i].x_advance / 64.;+		height -= pos[i].y_advance / 64.;+	}+	+	if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer)))+		height += font->font_size;+	else+		width += font->font_size;++	cairo_font_face_t *cairo_face;+	cairo_face = cairo_ft_font_face_create_for_ft_face (font->ft_face, 0);+	cairo_set_font_face (cr, cairo_face);+	cairo_set_font_size (cr, font->font_size);++	if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer))) {+		cairo_font_extents_t font_extents;+		cairo_font_extents (cr, &font_extents);+		double baseline = (font->font_size - font_extents.height) * .5 + font_extents.ascent;+		cairo_translate (cr, 0, baseline);+	} else {+		cairo_translate (cr, font->font_size * .5, 0);+	}+	+	cairo_glyph_t *cairo_glyphs = cairo_glyph_allocate (len);+	current_x = 0;+	current_y = 0;+	+	cairo_matrix_t matrix;+	cairo_get_matrix (cr, &matrix);+	cairo_matrix_invert (&matrix);+	+	for (unsigned int i = 0; i < len; i++) {+		cairo_glyphs[i].index = info[i].codepoint;+		cairo_glyphs[i].x = current_x + pos[i].x_offset / 64.;+		cairo_glyphs[i].y = -(current_y + pos[i].y_offset / 64.);+		+		double dx = pos[i].x_advance / 64.0;+		double dy = pos[i].y_advance / 64.0;+		+		cairo_matrix_transform_distance (&matrix, &dx, &dy);+		+		current_x += dx;+		current_y += dy;+	}+	+	cairo_show_glyphs (cr, cairo_glyphs, len);+	cairo_glyph_free (cairo_glyphs);++	cairo_font_face_destroy (cairo_face);++	hb_buffer_destroy (hb_buffer);+	cairo_restore (cr);+}

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112