/* Dia -- an diagram creation/manipulation program * Copyright (C) 1998 Alexander Larsson * * render_svg.c - an SVG renderer for dia, based on render_eps.c * Copyright (C) 1999, 2000 James Henstridge * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include "geometry.h" #include "diasvgrenderer.h" #include "filter.h" #include "intl.h" #include "message.h" #include "diagramdata.h" #include "dia_xml_libxml.h" #include "object.h" G_BEGIN_DECLS #define SVG_TYPE_RENDERER (svg_renderer_get_type ()) #define SVG_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVG_TYPE_RENDERER, SvgRenderer)) #define SVG_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SVG_TYPE_RENDERER, SvgRendererClass)) #define SVG_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVG_TYPE_RENDERER)) #define SVG_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SVG_TYPE_RENDERER, SvgRendererClass)) GType svg_renderer_get_type (void) G_GNUC_CONST; typedef struct _SvgRenderer SvgRenderer; typedef struct _SvgRendererClass SvgRendererClass; struct _SvgRenderer { DiaSvgRenderer parent_instance; }; struct _SvgRendererClass { DiaSvgRendererClass parent_class; }; G_END_DECLS static DiaSvgRenderer *new_svg_renderer(DiagramData *data, const char *filename); static void draw_object (DiaRenderer *renderer, DiaObject *object); static void draw_rounded_rect (DiaRenderer *renderer, Point *ul_corner, Point *lr_corner, Color *colour, real rounding); static void fill_rounded_rect (DiaRenderer *renderer, Point *ul_corner, Point *lr_corner, Color *colour, real rounding); static void svg_renderer_class_init (SvgRendererClass *klass); static gpointer parent_class = NULL; GType svg_renderer_get_type (void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (SvgRendererClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) svg_renderer_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (SvgRenderer), 0, /* n_preallocs */ NULL /* init */ }; object_type = g_type_register_static (DIA_TYPE_SVG_RENDERER, "SvgRenderer", &object_info, 0); } return object_type; } static void svg_renderer_finalize (GObject *object) { G_OBJECT_CLASS (parent_class)->finalize (object); } static void svg_renderer_class_init (SvgRendererClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = svg_renderer_finalize; renderer_class->draw_object = draw_object; renderer_class->draw_rounded_rect = draw_rounded_rect; renderer_class->fill_rounded_rect = fill_rounded_rect; } static DiaSvgRenderer * new_svg_renderer(DiagramData *data, const char *filename) { DiaSvgRenderer *renderer; FILE *file; gchar buf[512]; time_t time_now; Rectangle *extent; const char *name; xmlDtdPtr dtd; file = g_fopen(filename, "w"); if (file==NULL) { message_error(_("Can't open output file %s: %s\n"), dia_message_filename(filename), strerror(errno)); return NULL; } fclose(file); /* we need access to our base object */ renderer = DIA_SVG_RENDERER (g_object_new(SVG_TYPE_RENDERER, NULL)); renderer->filename = g_strdup(filename); renderer->dash_length = 1.0; renderer->dot_length = 0.2; renderer->saved_line_style = LINESTYLE_SOLID; /* set up the root node */ renderer->doc = xmlNewDoc("1.0"); renderer->doc->encoding = xmlStrdup("UTF-8"); renderer->doc->standalone = FALSE; dtd = xmlCreateIntSubset(renderer->doc, "svg", "-//W3C//DTD SVG 1.0//EN", "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd"); xmlAddChild((xmlNodePtr) renderer->doc, (xmlNodePtr) dtd); renderer->root = xmlNewDocNode(renderer->doc, NULL, "svg", NULL); xmlAddSibling(renderer->doc->children, (xmlNodePtr) renderer->root); /* set the extents of the SVG document */ extent = &data->extents; g_snprintf(buf, sizeof(buf), "%dcm", (int)ceil((extent->right - extent->left))); xmlSetProp(renderer->root, "width", buf); g_snprintf(buf, sizeof(buf), "%dcm", (int)ceil((extent->bottom - extent->top))); xmlSetProp(renderer->root, "height", buf); g_snprintf(buf, sizeof(buf), "%d %d %d %d", (int)floor(extent->left), (int)floor(extent->top), (int)ceil(extent->right - extent->left), (int)ceil(extent->bottom - extent->top)); xmlSetProp(renderer->root, "viewBox", buf); time_now = time(NULL); name = g_get_user_name(); #if 0 /* some comments at the top of the file ... */ xmlAddChild(renderer->root, xmlNewText("\n")); xmlAddChild(renderer->root, xmlNewComment("Dia-Version: "VERSION)); xmlAddChild(renderer->root, xmlNewText("\n")); g_snprintf(buf, sizeof(buf), "File: %s", dia->filename); xmlAddChild(renderer->root, xmlNewComment(buf)); xmlAddChild(renderer->root, xmlNewText("\n")); g_snprintf(buf, sizeof(buf), "Date: %s", ctime(&time_now)); buf[strlen(buf)-1] = '\0'; /* remove the trailing new line */ xmlAddChild(renderer->root, xmlNewComment(buf)); xmlAddChild(renderer->root, xmlNewText("\n")); g_snprintf(buf, sizeof(buf), "For: %s", name); xmlAddChild(renderer->root, xmlNewComment(buf)); xmlAddChild(renderer->root, xmlNewText("\n\n")); xmlNewChild(renderer->root, NULL, "title", dia->filename); #endif return renderer; } static void draw_object(DiaRenderer *renderer, DiaObject *object) { /* TODO: wrap in */ object->ops->draw(object, renderer); } static void draw_rounded_rect(DiaRenderer *self, Point *ul_corner, Point *lr_corner, Color *colour, real rounding) { DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self); xmlNodePtr node; gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; node = xmlNewChild(renderer->root, NULL, "rect", NULL); xmlSetProp(node, "style", DIA_SVG_RENDERER_GET_CLASS(self)->get_draw_style(renderer, colour)); g_ascii_formatd(buf, sizeof(buf), "%g", ul_corner->x); xmlSetProp(node, "x", buf); g_ascii_formatd(buf, sizeof(buf), "%g", ul_corner->y); xmlSetProp(node, "y", buf); g_ascii_formatd(buf, sizeof(buf), "%g", lr_corner->x - ul_corner->x); xmlSetProp(node, "width", buf); g_ascii_formatd(buf, sizeof(buf), "%g", lr_corner->y - ul_corner->y); xmlSetProp(node, "height", buf); g_ascii_formatd(buf, sizeof(buf),"%g", rounding); xmlSetProp(node, "rx", buf); xmlSetProp(node, "ry", buf); } static void fill_rounded_rect(DiaRenderer *self, Point *ul_corner, Point *lr_corner, Color *colour, real rounding) { DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self); xmlNodePtr node; gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; node = xmlNewChild(renderer->root, NULL, "rect", NULL); xmlSetProp(node, "style", DIA_SVG_RENDERER_GET_CLASS(self)->get_fill_style(renderer, colour)); g_ascii_formatd(buf, sizeof(buf), "%g", ul_corner->x); xmlSetProp(node, "x", buf); g_ascii_formatd(buf, sizeof(buf), "%g", ul_corner->y); xmlSetProp(node, "y", buf); g_ascii_formatd(buf, sizeof(buf), "%g", lr_corner->x - ul_corner->x); xmlSetProp(node, "width", buf); g_ascii_formatd(buf, sizeof(buf), "%g", lr_corner->y - ul_corner->y); xmlSetProp(node, "height", buf); g_ascii_formatd(buf, sizeof(buf),"%g", rounding); xmlSetProp(node, "rx", buf); xmlSetProp(node, "ry", buf); } static void export_svg(DiagramData *data, const gchar *filename, const gchar *diafilename, void* user_data) { DiaSvgRenderer *renderer; if ((renderer = new_svg_renderer(data, filename))) { data_render(data, DIA_RENDERER(renderer), NULL, NULL, NULL); g_object_unref(renderer); } } static const gchar *extensions[] = { "svg", NULL }; DiaExportFilter svg_export_filter = { N_("Scalable Vector Graphics"), extensions, export_svg };