* lib/text.h: Added text_get_line() declaration
[dia.git] / plug-ins / vdx / vdx-export.c
blob2e03e257e6339f129ced91e04bbd020e46a59951
1 /* -*- Mode: C; c-basic-offset: 4 -*- */
2 /* Dia -- a diagram creation/manipulation program
3 * Copyright (C) 1998 Alexander Larsson
5 * vdx-export.c: Visio XML export filter for dia
6 * Copyright (C) 2006 Ian Redfern
7 * based on the xfig filter code
8 * Copyright (C) 2001 Lars Clausen
9 * based on the dxf filter code
10 * Copyright (C) 2000 James Henstridge, Steffen Macke
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
31 #include <stdio.h>
33 #include <string.h>
34 #include <math.h>
35 #include <glib.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <locale.h>
39 #include <glib/gstdio.h>
41 #include "intl.h"
42 #include "message.h"
43 #include "geometry.h"
44 #include "diarenderer.h"
45 #include "filter.h"
46 #include "object.h"
47 #include "properties.h"
48 #include "dia_image.h"
49 #include "group.h"
51 #include "vdx.h"
52 #include "visio-types.h"
54 /* Following code taken from xfig-export.c */
56 #define VDX_TYPE_RENDERER (vdx_renderer_get_type ())
57 #define VDX_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VDX_TYPE_RENDERER, VDXRenderer))
58 #define VDX_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VDX_TYPE_RENDERER, VDXRendererClass))
59 #define VDX_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VDX_TYPE_RENDERER))
60 #define VDX_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VDX_TYPE_RENDERER, VDXRendererClass))
62 GType vdx_renderer_get_type (void) G_GNUC_CONST;
64 typedef struct _VDXRenderer VDXRenderer;
65 typedef struct _VDXRendererClass VDXRendererClass;
67 struct _VDXRendererClass
69 DiaRendererClass parent_class;
72 struct _VDXRenderer
74 DiaRenderer parent_instance;
76 FILE *file;
78 int depth;
80 real linewidth;
81 LineCaps capsmode;
82 LineJoin joinmode;
83 LineStyle stylemode;
84 real dashlength;
85 FillStyle fillmode;
86 DiaFont *font;
87 real fontheight;
89 /* Additions for VDX */
91 gboolean first_pass; /* When we make table of colours and fonts */
92 GArray *Colors; /* Table of colours */
93 GArray *Fonts; /* Table of fonts */
94 unsigned int shapeid; /* Shape counter */
95 unsigned int version; /* Visio version */
96 unsigned int xml_depth; /* Pretty-printer */
100 static void begin_render(DiaRenderer *self);
101 static void end_render(DiaRenderer *renderer);
102 static void set_linewidth(DiaRenderer *self, real linewidth);
103 static void set_linecaps(DiaRenderer *self, LineCaps mode);
104 static void set_linejoin(DiaRenderer *self, LineJoin mode);
105 static void set_linestyle(DiaRenderer *self, LineStyle mode);
106 static void set_dashlength(DiaRenderer *self, real length);
107 static void set_fillstyle(DiaRenderer *self, FillStyle mode);
108 static void set_font(DiaRenderer *self, DiaFont *font, real height);
109 static void draw_line(DiaRenderer *self,
110 Point *start, Point *end,
111 Color *color);
112 static void draw_polyline(DiaRenderer *self,
113 Point *points, int num_points,
114 Color *color);
115 static void draw_polygon(DiaRenderer *self,
116 Point *points, int num_points,
117 Color *color);
118 static void fill_polygon(DiaRenderer *self,
119 Point *points, int num_points,
120 Color *color);
121 static void draw_rect(DiaRenderer *self,
122 Point *ul_corner, Point *lr_corner,
123 Color *color);
124 static void fill_rect(DiaRenderer *self,
125 Point *ul_corner, Point *lr_corner,
126 Color *color);
127 static void draw_arc(DiaRenderer *self,
128 Point *center,
129 real width, real height,
130 real angle1, real angle2,
131 Color *color);
132 static void fill_arc(DiaRenderer *self,
133 Point *center,
134 real width, real height,
135 real angle1, real angle2,
136 Color *color);
137 static void draw_ellipse(DiaRenderer *self,
138 Point *center,
139 real width, real height,
140 Color *color);
141 static void fill_ellipse(DiaRenderer *self,
142 Point *center,
143 real width, real height,
144 Color *color);
145 static void draw_string(DiaRenderer *self,
146 const char *text,
147 Point *pos, Alignment alignment,
148 Color *color);
149 static void draw_image(DiaRenderer *self,
150 Point *point,
151 real width, real height,
152 DiaImage image);
154 static void vdx_renderer_class_init (VDXRendererClass *klass);
156 static void
157 export_vdx(DiagramData *data, const gchar *filename,
158 const gchar *diafilename, void* user_data);
160 static int
161 vdxCheckColor(VDXRenderer *renderer, Color *color);
163 static gpointer parent_class = NULL;
166 /** Renderer type handler
167 * @returns renderer type
170 GType
171 vdx_renderer_get_type (void)
173 static GType object_type = 0;
175 if (!object_type)
177 static const GTypeInfo object_info =
179 sizeof (VDXRendererClass),
180 (GBaseInitFunc) NULL,
181 (GBaseFinalizeFunc) NULL,
182 (GClassInitFunc) vdx_renderer_class_init,
183 NULL, /* class_finalize */
184 NULL, /* class_data */
185 sizeof (VDXRenderer),
186 0, /* n_preallocs */
187 NULL /* init */
190 object_type = g_type_register_static (DIA_TYPE_RENDERER,
191 "VDXRenderer",
192 &object_info, 0);
195 return object_type;
198 /** Finalise a renderer
199 * @param object a renderer
202 static void
203 vdx_renderer_finalize (GObject *object)
205 G_OBJECT_CLASS (parent_class)->finalize (object);
208 /** Class constructor for renderer
209 * @param klass a renderer
212 static void
213 vdx_renderer_class_init (VDXRendererClass *klass)
215 GObjectClass *object_class = G_OBJECT_CLASS (klass);
216 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
218 parent_class = g_type_class_peek_parent (klass);
220 object_class->finalize = vdx_renderer_finalize;
222 renderer_class->begin_render = begin_render;
223 renderer_class->end_render = end_render;
225 renderer_class->set_linewidth = set_linewidth;
226 renderer_class->set_linecaps = set_linecaps;
227 renderer_class->set_linejoin = set_linejoin;
228 renderer_class->set_linestyle = set_linestyle;
229 renderer_class->set_dashlength = set_dashlength;
230 renderer_class->set_fillstyle = set_fillstyle;
231 renderer_class->set_font = set_font;
233 renderer_class->draw_line = draw_line;
234 renderer_class->draw_polyline = draw_polyline;
236 renderer_class->draw_polygon = draw_polygon;
237 renderer_class->fill_polygon = fill_polygon;
239 renderer_class->draw_rect = draw_rect;
240 renderer_class->fill_rect = fill_rect;
242 renderer_class->draw_arc = draw_arc;
243 renderer_class->fill_arc = fill_arc;
245 renderer_class->draw_ellipse = draw_ellipse;
246 renderer_class->fill_ellipse = fill_ellipse;
248 /* Until we have NURBS, let Dia use lines */
249 /* renderer_class->draw_bezier = draw_bezier; */
250 /* renderer_class->fill_bezier = fill_bezier; */
251 /* renderer_class->draw_bezier_with_arrows = draw_bezier_with_arrows; */
253 renderer_class->draw_string = draw_string;
255 renderer_class->draw_image = draw_image;
257 /* Believe these are never used or are unnecessary */
258 /* renderer_class->draw_line_with_arrows = draw_line_with_arrows; */
259 /* renderer_class->draw_polyline_with_arrows = draw_polyline_with_arrows; */
260 /* renderer_class->draw_arc_with_arrows = draw_arc_with_arrows; */
261 /* renderer_class->draw_object = draw_object; */
265 /** Initialises VDXrenderer
266 * @param self a renderer
269 static void
270 begin_render(DiaRenderer *self)
272 VDXRenderer *renderer = VDX_RENDERER(self);
273 Color c;
275 renderer->depth = 0;
277 renderer->linewidth = 0;
278 renderer->capsmode = 0;
279 renderer->joinmode = 0;
280 renderer->stylemode = 0;
281 renderer->dashlength = 0;
282 renderer->fillmode = 0;
283 renderer->font = NULL;
284 renderer->fontheight = 1;
286 /* Specific to VDX */
288 renderer->Colors = g_array_new(FALSE, TRUE, sizeof (Color));
289 renderer->Fonts = g_array_new(FALSE, TRUE, sizeof (char *));
290 renderer->shapeid = 0;
291 /* renderer->version = 0; */
293 /* Black and white are 0 and 1 respectively */
294 c.red = 0.0; c.green = 0.0; c.blue = 0.0;
295 vdxCheckColor(renderer, &c);
296 c.red = 1.0; c.green = 1.0; c.blue = 1.0;
297 vdxCheckColor(renderer, &c);
300 /** Destructor for renderer
301 * @param self a renderer
304 static void
305 end_render(DiaRenderer *self)
307 VDXRenderer *renderer = VDX_RENDERER(self);
309 /* Specific to VDX */
310 g_array_free(renderer->Colors, TRUE);
311 g_array_free(renderer->Fonts, TRUE);
314 /** Convert a Dia point to a Visio one
315 * @param p a Dia-space point
316 * @returns a Visio-space point
319 static Point
320 visio_point(Point p)
322 Point q;
323 q.x = p.x/vdx_Point_Scale;
324 q.y = (p.y - vdx_Y_Offset)/vdx_Y_Flip/vdx_Point_Scale;
325 return q;
328 /** Convert a Dia absolute length to a Visio one
329 * @param length a length
330 * @returns length in Visio space
333 static double
334 visio_length(double length)
336 return length/vdx_Point_Scale;
339 /** Set line width
340 * @param self a renderer
341 * @param linewidth new line width
344 static void
345 set_linewidth(DiaRenderer *self, real linewidth)
347 VDXRenderer *renderer = VDX_RENDERER(self);
349 renderer->linewidth = linewidth;
352 /** Set line caps
353 * @param self a renderer
354 * @param mode new line caps
357 static void
358 set_linecaps(DiaRenderer *self, LineCaps mode)
360 VDXRenderer *renderer = VDX_RENDERER(self);
362 renderer->capsmode = mode;
365 /** Set line join
366 * @param self a renderer
367 * @param mode new line join
370 static void
371 set_linejoin(DiaRenderer *self, LineJoin mode)
373 VDXRenderer *renderer = VDX_RENDERER(self);
375 renderer->joinmode = mode;
378 /** Set line style
379 * @param self a renderer
380 * @param mode new line style
383 static void
384 set_linestyle(DiaRenderer *self, LineStyle mode)
386 VDXRenderer *renderer = VDX_RENDERER(self);
388 renderer->stylemode = mode;
391 /** Set dash length
392 * @param self a renderer
393 * @param mode new dash length
396 static void
397 set_dashlength(DiaRenderer *self, real length)
399 VDXRenderer *renderer = VDX_RENDERER(self);
401 renderer->dashlength = length;
404 /** Set fill style
405 * @param self a renderer
406 * @param mode new file style
409 static void
410 set_fillstyle(DiaRenderer *self, FillStyle mode)
412 VDXRenderer *renderer = VDX_RENDERER(self);
414 renderer->fillmode = mode;
417 /** Set font
418 * @param self a renderer
419 * @param font new font
420 * @param height new font height
423 static void
424 set_font(DiaRenderer *self, DiaFont *font, real height)
426 VDXRenderer *renderer = VDX_RENDERER(self);
428 renderer->font = font;
429 renderer->fontheight = height;
432 /** Get colour number from colour table
433 * @param renderer a renderer
434 * @param color the colour
435 * @returns a colour index (black=0)
438 static int
439 vdxCheckColor(VDXRenderer *renderer, Color *color)
441 int i;
443 Color cmp_color;
444 for (i = 0; i < renderer->Colors->len; i++)
446 cmp_color = g_array_index(renderer->Colors, Color, i);
447 if (color_equals(color, &cmp_color)) return i;
449 /* Grow table */
450 g_array_append_val(renderer->Colors, *color);
451 return renderer->Colors->len;
454 /** Get font number from font table
455 * @param renderer a renderer
456 * @returns a font index (from 0)
459 static int
460 vdxCheckFont(VDXRenderer *renderer)
462 int i;
464 const char *cmp_font;
465 const char *font = dia_font_get_legacy_name(renderer->font);
466 for (i = 0; i < renderer->Fonts->len; i++)
468 cmp_font = g_array_index(renderer->Fonts, char *, i);
469 if (!strcmp(cmp_font, font)) return i;
471 /* Grow table */
472 g_array_append_val(renderer->Fonts, font);
473 return renderer->Fonts->len;
476 /** Create a Visio line style object
477 * @param self a VDXRenderer
478 * @param color a colour
479 * @param Line a Line object
480 * @param start_arrow optional start arrow
481 * @param end_arrow optional end arrow
482 * @todo join, caps, dashlength
485 static void
486 create_Line(VDXRenderer *renderer, Color *color, struct vdx_Line *Line,
487 Arrow *start_arrow, Arrow *end_arrow)
489 /* A Line (colour etc) */
490 memset(Line, 0, sizeof(*Line));
491 Line->type = vdx_types_Line;
492 switch (renderer->stylemode)
494 case LINESTYLE_DASHED:
495 Line->LinePattern = 2;
496 break;
497 case LINESTYLE_DOTTED:
498 Line->LinePattern = 3;
499 break;
500 case LINESTYLE_DASH_DOT:
501 Line->LinePattern = 4;
502 break;
503 case LINESTYLE_DASH_DOT_DOT:
504 Line->LinePattern = 5;
505 break;
506 default:
507 case LINESTYLE_SOLID:
508 Line->LinePattern = 1;
509 break;
511 Line->LineColor = *color;
512 Line->LineWeight = renderer->linewidth / vdx_Line_Scale;
513 if (start_arrow || end_arrow)
515 g_debug("create_Line (ARROWS)");
520 /** Create a Visio fill style object
521 * @param self a VDXRenderer
522 * @param color a colour
523 * @todo fillstyle
526 static void
527 create_Fill(VDXRenderer *renderer, Color *color, struct vdx_Fill *Fill)
529 /* A Fill (colour etc) */
530 memset(Fill, 0, sizeof(*Fill));
531 Fill->type = vdx_types_Fill;
532 Fill->FillForegnd = *color;
533 Fill->FillPattern = 1; /* Solid fill */
537 /** Render a Dia line
538 * @param self a renderer
539 * @param start start of line
540 * @param end end of line
541 * @param color line colour
544 static void
545 draw_line(DiaRenderer *self, Point *start, Point *end, Color *color)
547 VDXRenderer *renderer = VDX_RENDERER(self);
548 Point a, b;
549 struct vdx_Shape Shape;
550 struct vdx_XForm XForm;
551 struct vdx_XForm1D XForm1D;
552 struct vdx_Geom Geom;
553 struct vdx_MoveTo MoveTo;
554 struct vdx_LineTo LineTo;
555 struct vdx_Line Line;
556 char NameU[VDX_NAMEU_LEN];
558 /* First time through, just construct the colour table */
559 if (renderer->first_pass)
561 vdxCheckColor(renderer, color);
562 return;
565 g_debug("draw_line((%f,%f), (%f,%f))", start->x, start->y, end->x, end->y);
567 /* Setup the standard shape object */
568 memset(&Shape, 0, sizeof(Shape));
569 Shape.type = vdx_types_Shape;
570 Shape.ID = renderer->shapeid++;
571 Shape.Type = "Shape";
572 sprintf(NameU, "Line.%d", Shape.ID);
573 Shape.NameU = NameU;
574 Shape.LineStyle_exists = 1;
575 Shape.FillStyle_exists = 1;
576 Shape.TextStyle_exists = 1;
578 /* An XForm */
579 memset(&XForm, 0, sizeof(XForm));
580 XForm.type = vdx_types_XForm;
581 a = visio_point(*start);
582 b = visio_point(*end);
583 XForm.PinX = a.x; /* Start */
584 XForm.PinY = a.y;
585 XForm.Width = fabs(b.x - a.x); /* Must be non-negative */
586 XForm.Height = fabs(b.y - a.y); /* Must be non-negative */
587 XForm.LocPinX = 0.0;
588 XForm.LocPinY = 0.0;
589 XForm.Angle = 0.0;
591 /* Lines must have an XForm1D as well */
592 memset(&XForm1D, 0, sizeof(XForm1D));
593 XForm1D.type = vdx_types_XForm1D;
594 XForm1D.BeginX = a.x;
595 XForm1D.BeginY = a.y;
596 XForm1D.EndX = b.x;
597 XForm1D.EndY = b.y;
599 /* Standard Geom object */
600 memset(&Geom, 0, sizeof(Geom));
601 Geom.NoFill = 1;
602 Geom.type = vdx_types_Geom;
604 /* Two children - MoveTo(start) and LineTo(end) */
605 memset(&MoveTo, 0, sizeof(MoveTo));
606 MoveTo.type = vdx_types_MoveTo;
607 MoveTo.IX = 1;
608 MoveTo.X = 0;
609 MoveTo.Y = 0;
611 memset(&LineTo, 0, sizeof(LineTo));
612 LineTo.type = vdx_types_LineTo;
613 LineTo.IX = 2;
614 LineTo.X = b.x-a.x;
615 LineTo.Y = b.y-a.y;
617 /* A Line (colour etc) */
618 create_Line(renderer, color, &Line, 0, 0);
620 /* Setup children */
621 Geom.children = g_slist_append(Geom.children, &MoveTo);
622 Geom.children = g_slist_append(Geom.children, &LineTo);
624 Shape.children = g_slist_append(Shape.children, &XForm);
625 Shape.children = g_slist_append(Shape.children, &XForm1D);
626 Shape.children = g_slist_append(Shape.children, &Line);
627 Shape.children = g_slist_append(Shape.children, &Geom);
629 /* Write out XML */
630 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
632 /* Free up list entries */
633 g_slist_free(Geom.children);
634 g_slist_free(Shape.children);
638 /** Render a Dia polyline
639 * @param self a renderer
640 * @param points the points
641 * @param num_points how many points
642 * @param color line colour
645 static void draw_polyline(DiaRenderer *self, Point *points, int num_points,
646 Color *color)
648 VDXRenderer *renderer = VDX_RENDERER(self);
649 Point a, b;
650 struct vdx_Shape Shape;
651 struct vdx_XForm XForm;
652 struct vdx_Geom Geom;
653 struct vdx_MoveTo MoveTo;
654 struct vdx_LineTo* LineTo;
655 struct vdx_Line Line;
656 char NameU[VDX_NAMEU_LEN];
657 unsigned int i;
658 double minX, minY, maxX, maxY;
660 /* First time through, just construct the colour table */
661 if (renderer->first_pass)
663 vdxCheckColor(renderer, color);
664 return;
667 g_debug("draw_polyline(%d)", num_points);
669 /* Setup the standard shape object */
670 memset(&Shape, 0, sizeof(Shape));
671 Shape.type = vdx_types_Shape;
672 Shape.ID = renderer->shapeid++;
673 Shape.Type = "Shape";
674 sprintf(NameU, "PolyLine.%d", Shape.ID);
675 Shape.NameU = NameU;
676 Shape.LineStyle_exists = 1;
677 Shape.FillStyle_exists = 1;
678 Shape.TextStyle_exists = 1;
680 /* An XForm */
681 memset(&XForm, 0, sizeof(XForm));
682 XForm.type = vdx_types_XForm;
683 a = visio_point(points[0]);
685 /* Find width and height */
686 minX = points[0].x; minY = points[0].y;
687 maxX = points[0].x; maxY = points[0].y;
688 for (i=1; i<num_points; i++)
690 if (points[i].x < minX) minX = points[i].x;
691 if (points[i].x > maxX) maxX = points[i].x;
692 if (points[i].y < minY) minY = points[i].y;
693 if (points[i].y > maxY) maxY = points[i].y;
695 XForm.Width = visio_length(maxX - minX);
696 XForm.Height = visio_length(maxY - minY);
698 XForm.PinX = a.x; /* Start */
699 XForm.PinY = a.y;
700 XForm.LocPinX = 0.0;
701 XForm.LocPinY = 0.0;
702 XForm.Angle = 0.0;
704 /* Standard Geom object */
705 memset(&Geom, 0, sizeof(Geom));
706 Geom.NoFill = 1;
707 Geom.type = vdx_types_Geom;
709 /* Multiple children - MoveTo(start) and LineTo(others) */
710 memset(&MoveTo, 0, sizeof(MoveTo));
711 MoveTo.type = vdx_types_MoveTo;
712 MoveTo.IX = 1;
713 MoveTo.X = 0;
714 MoveTo.Y = 0;
716 LineTo = g_new0(struct vdx_LineTo, num_points-1);
717 for (i=0; i<num_points-1; i++)
719 LineTo[i].type = vdx_types_LineTo;
720 LineTo[i].IX = i+2;
721 b = visio_point(points[i+1]);
722 LineTo[i].X = b.x-a.x;
723 LineTo[i].Y = b.y-a.y;
726 /* A Line (colour etc) */
727 create_Line(renderer, color, &Line, 0, 0);
729 /* Setup children */
730 Geom.children = g_slist_append(Geom.children, &MoveTo);
731 for (i=0; i<num_points-1; i++)
733 Geom.children = g_slist_append(Geom.children, &LineTo[i]);
736 Shape.children = g_slist_append(Shape.children, &XForm);
737 Shape.children = g_slist_append(Shape.children, &Line);
738 Shape.children = g_slist_append(Shape.children, &Geom);
740 /* Write out XML */
741 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
743 /* Free up list entries */
744 g_slist_free(Geom.children);
745 g_slist_free(Shape.children);
746 g_free(LineTo);
749 /** Render a Dia polygon
750 * @param self a renderer
751 * @param points corners of polygon
752 * @param num_points number of points
753 * @param color line colour
756 static void draw_polygon(DiaRenderer *self,
757 Point *points, int num_points,
758 Color *color)
760 Point *more_points = g_new0(Point, num_points+1);
761 memcpy(more_points, points, num_points*sizeof(Point));
762 more_points[num_points] = more_points[0];
763 g_debug("draw_polygon -> draw_polyline");
764 draw_polyline(self, more_points, num_points+1, color);
765 g_free(more_points);
768 /** Render a Dia filled polygon
769 * @param self a renderer
770 * @param points corners of polygon
771 * @param num_points number of points
772 * @param color line colour
775 static void fill_polygon(DiaRenderer *self,
776 Point *points, int num_points,
777 Color *color)
779 VDXRenderer *renderer = VDX_RENDERER(self);
780 Point a, b;
781 struct vdx_Shape Shape;
782 struct vdx_XForm XForm;
783 struct vdx_Geom Geom;
784 struct vdx_MoveTo MoveTo;
785 struct vdx_LineTo* LineTo;
786 struct vdx_Fill Fill;
787 char NameU[VDX_NAMEU_LEN];
788 unsigned int i;
789 double minX, minY, maxX, maxY;
791 /* First time through, just construct the colour table */
792 if (renderer->first_pass)
794 vdxCheckColor(renderer, color);
795 return;
798 g_debug("fill_polygon(%d)", num_points);
800 /* Setup the standard shape object */
801 memset(&Shape, 0, sizeof(Shape));
802 Shape.type = vdx_types_Shape;
803 Shape.ID = renderer->shapeid++;
804 Shape.Type = "Shape";
805 sprintf(NameU, "FillPolygon.%d", Shape.ID);
806 Shape.NameU = NameU;
807 Shape.LineStyle_exists = 1;
808 Shape.FillStyle_exists = 1;
809 Shape.TextStyle_exists = 1;
811 /* An XForm */
812 memset(&XForm, 0, sizeof(XForm));
813 XForm.type = vdx_types_XForm;
814 a = visio_point(points[0]);
816 /* Find width and height */
817 minX = points[0].x; minY = points[0].y;
818 maxX = points[0].x; maxY = points[0].y;
819 for (i=1; i<num_points; i++)
821 if (points[i].x < minX) minX = points[i].x;
822 if (points[i].x > maxX) maxX = points[i].x;
823 if (points[i].y < minY) minY = points[i].y;
824 if (points[i].y > maxY) maxY = points[i].y;
826 XForm.Width = visio_length(maxX - minX);
827 XForm.Height = visio_length(maxY - minY);
829 XForm.PinX = a.x; /* Start */
830 XForm.PinY = a.y;
831 XForm.LocPinX = 0.0;
832 XForm.LocPinY = 0.0;
833 XForm.Angle = 0.0;
835 /* Standard Geom object */
836 memset(&Geom, 0, sizeof(Geom));
837 Geom.type = vdx_types_Geom;
839 /* Multiple children - MoveTo(start) and LineTo(others) */
840 memset(&MoveTo, 0, sizeof(MoveTo));
841 MoveTo.type = vdx_types_MoveTo;
842 MoveTo.IX = 1;
843 MoveTo.X = 0;
844 MoveTo.Y = 0;
846 LineTo = g_new0(struct vdx_LineTo, num_points);
847 for (i=0; i<num_points; i++)
849 LineTo[i].type = vdx_types_LineTo;
850 LineTo[i].IX = i+2;
851 /* Last point = first */
852 if (i == num_points-1) b = a;
853 else b = visio_point(points[i+1]);
854 LineTo[i].X = b.x-a.x;
855 LineTo[i].Y = b.y-a.y;
858 /* A Line (colour etc) */
859 create_Fill(renderer, color, &Fill);
861 /* Setup children */
862 Geom.children = g_slist_append(Geom.children, &MoveTo);
863 for (i=0; i<num_points; i++)
865 Geom.children = g_slist_append(Geom.children, &LineTo[i]);
868 Shape.children = g_slist_append(Shape.children, &XForm);
869 Shape.children = g_slist_append(Shape.children, &Fill);
870 Shape.children = g_slist_append(Shape.children, &Geom);
872 /* Write out XML */
873 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
875 /* Free up list entries */
876 g_slist_free(Geom.children);
877 g_slist_free(Shape.children);
878 g_free(LineTo);
881 /** Render a Dia rectangle
882 * @param self a renderer
883 * @param ul_corner Upper-left corner
884 * @param lr_corner Loower-right corner
885 * @param color line colour
888 static void draw_rect(DiaRenderer *self,
889 Point *ul_corner, Point *lr_corner,
890 Color *color)
892 Point points[5]; /* 5 so we close path */
894 g_debug("draw_rect((%f,%f), (%f,%f)) -> draw_polyline",
895 ul_corner->x, ul_corner->y, lr_corner->x, lr_corner->y);
896 points[0].x = ul_corner->x; points[0].y = lr_corner->y;
897 points[1] = *lr_corner;
898 points[2].x = lr_corner->x; points[2].y = ul_corner->y;
899 points[3] = *ul_corner;
900 points[4] = points[0];
902 draw_polygon(self, points, 5, color);
905 /** Render a Dia filled rectangle
906 * @param self a renderer
907 * @param ul_corner Upper-left corner
908 * @param lr_corner Lower-right corner
909 * @param color line colour
912 static void fill_rect(DiaRenderer *self,
913 Point *ul_corner, Point *lr_corner,
914 Color *color)
916 Point points[5]; /* 5 so we close path */
918 g_debug("fill_rect -> fill_polygon");
919 points[0].x = ul_corner->x; points[0].y = lr_corner->y;
920 points[1] = *lr_corner;
921 points[2].x = lr_corner->x; points[2].y = ul_corner->y;
922 points[3] = *ul_corner;
923 points[4] = points[0];
925 fill_polygon(self, points, 5, color);
928 /** Render a Dia arc
929 * @param self a renderer
930 * @param center centre of arc
931 * @param width width of ellipse
932 * @param height height of ellipse (= width for Dia circular arcs)
933 * @param angle1 start angle to x axis in degrees
934 * @param angle2 end angle to x axis in degrees
935 * @param color line colour
936 * @todo Not done yet
939 static void draw_arc(DiaRenderer *self,
940 Point *center,
941 real width, real height,
942 real angle1, real angle2,
943 Color *color)
945 VDXRenderer *renderer = VDX_RENDERER(self);
946 Point a;
947 struct vdx_Shape Shape;
948 struct vdx_XForm XForm;
949 struct vdx_Geom Geom;
950 struct vdx_EllipticalArcTo EllipticalArcTo;
951 struct vdx_MoveTo MoveTo;
952 struct vdx_Line Line;
953 char NameU[VDX_NAMEU_LEN];
954 Point start, control, end;
955 float control_angle;
957 /* First time through, just construct the colour table */
958 if (renderer->first_pass)
960 vdxCheckColor(renderer, color);
961 return;
964 g_debug("draw_arc((%f,%f),%f,%f;%f,%f)", center->x, center->y,
965 width, height, angle1, angle2);
967 /* Setup the standard shape object */
968 memset(&Shape, 0, sizeof(Shape));
969 Shape.type = vdx_types_Shape;
970 Shape.ID = renderer->shapeid++;
971 Shape.Type = "Shape";
972 sprintf(NameU, "Arc.%d", Shape.ID);
973 Shape.NameU = NameU;
974 Shape.LineStyle_exists = 1;
975 Shape.FillStyle_exists = 1;
976 Shape.TextStyle_exists = 1;
978 /* An XForm */
979 memset(&XForm, 0, sizeof(XForm));
980 XForm.type = vdx_types_XForm;
982 /* Find the start of the arc */
983 start = *center;
984 start.x += (width/2.0)*cos(angle1*DEG_TO_RAD);
985 start.y -= (height/2.0)*sin(angle1*DEG_TO_RAD);
986 g_debug("start(%f,%f)", start.x, start.y);
987 start = visio_point(start);
989 /* Find a control point at the midpoint of the arc */
990 control = *center;
991 control_angle = (angle1 + angle2)/2.0;
992 if (angle1 > angle2)
994 /* Arc goes antclockwise - allow for this */
995 control_angle -= 180;
997 control.x += (width/2.0)*cos(control_angle*DEG_TO_RAD);
998 control.y -= (height/2.0)*sin(control_angle*DEG_TO_RAD);
999 g_debug("control(%f,%f @ %f)", control.x, control.y, control_angle);
1000 control = visio_point(control);
1002 /* And the endpoint */
1003 end = *center;
1004 end.x += (width/2.0)*cos(angle2*DEG_TO_RAD);
1005 end.y -= (height/2.0)*sin(angle2*DEG_TO_RAD);
1006 g_debug("end(%f,%f)", end.x, end.y);
1007 end = visio_point(end);
1009 a = start;
1010 XForm.PinX = a.x; /* Start */
1011 XForm.PinY = a.y;
1012 XForm.Width = visio_length(width);
1013 XForm.Height = visio_length(height);
1014 XForm.LocPinX = 0;
1015 XForm.LocPinY = 0;
1016 XForm.Angle = 0.0;
1018 /* Standard Geom object */
1019 memset(&Geom, 0, sizeof(Geom));
1020 Geom.NoFill = 1;
1021 Geom.type = vdx_types_Geom;
1023 memset(&MoveTo, 0, sizeof(MoveTo));
1024 MoveTo.type = vdx_types_MoveTo;
1025 MoveTo.IX = 1;
1026 MoveTo.X = 0;
1027 MoveTo.Y = 0;
1029 /* Second child - EllipticalArcTo */
1030 memset(&EllipticalArcTo, 0, sizeof(EllipticalArcTo));
1031 EllipticalArcTo.type = vdx_types_EllipticalArcTo;
1032 EllipticalArcTo.IX = 2;
1034 /* X and Y are the end point
1035 A and B are a control point on the arc
1036 C is the angle of the major axis
1037 D is the ratio of the major to minor axes */
1039 /* Need to fix these */
1040 EllipticalArcTo.X = end.x - a.x;
1041 EllipticalArcTo.Y = end.y - a.y;
1042 EllipticalArcTo.A = control.x - a.x;
1043 EllipticalArcTo.B = control.y - a.y;
1044 EllipticalArcTo.C = 0.0; /* Dia major axis always x axis */
1045 if (fabs(height) > EPSILON)
1046 EllipticalArcTo.D = width/height; /* Always 1 for Dia */
1047 else
1048 EllipticalArcTo.D = 1/EPSILON;
1050 /* A Line (colour etc) */
1051 create_Line(renderer, color, &Line, 0, 0);
1053 /* Setup children */
1054 Geom.children = g_slist_append(Geom.children, &MoveTo);
1055 Geom.children = g_slist_append(Geom.children, &EllipticalArcTo);
1057 Shape.children = g_slist_append(Shape.children, &XForm);
1058 Shape.children = g_slist_append(Shape.children, &Line);
1059 Shape.children = g_slist_append(Shape.children, &Geom);
1061 /* Write out XML */
1062 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1064 /* Free up list entries */
1065 g_slist_free(Geom.children);
1066 g_slist_free(Shape.children);
1069 /** Render a Dia filled arc
1070 * @param self a renderer
1071 * @param center centre of arc
1072 * @param width width of bounding box
1073 * @param height height of bounding box
1074 * @param angle1 start angle
1075 * @param angle2 end angle
1076 * @param color line colour
1077 * @todo Not done yet - believe unused
1080 static void fill_arc(DiaRenderer *self,
1081 Point *center,
1082 real width, real height,
1083 real angle1, real angle2,
1084 Color *color)
1086 VDXRenderer *renderer = VDX_RENDERER(self);
1088 if (renderer->first_pass)
1090 vdxCheckColor(renderer, color);
1091 return;
1093 g_debug("fill_arc (TODO)");
1096 /** Render a Dia ellipse (parallel to axes)
1097 * @param self a renderer
1098 * @param center centre of ellipse
1099 * @param width width of bounding box
1100 * @param height height of bounding box
1101 * @param color line colour
1104 static void draw_ellipse(DiaRenderer *self,
1105 Point *center,
1106 real width, real height,
1107 Color *color)
1109 VDXRenderer *renderer = VDX_RENDERER(self);
1110 Point a;
1111 struct vdx_Shape Shape;
1112 struct vdx_XForm XForm;
1113 struct vdx_Geom Geom;
1114 struct vdx_Ellipse Ellipse;
1115 struct vdx_Line Line;
1116 char NameU[VDX_NAMEU_LEN];
1118 /* First time through, just construct the colour table */
1119 if (renderer->first_pass)
1121 vdxCheckColor(renderer, color);
1122 return;
1125 g_debug("draw_ellipse");
1127 /* Setup the standard shape object */
1128 memset(&Shape, 0, sizeof(Shape));
1129 Shape.type = vdx_types_Shape;
1130 Shape.ID = renderer->shapeid++;
1131 Shape.Type = "Shape";
1132 sprintf(NameU, "Ellipse.%d", Shape.ID);
1133 Shape.NameU = NameU;
1134 Shape.LineStyle_exists = 1;
1135 Shape.FillStyle_exists = 1;
1136 Shape.TextStyle_exists = 1;
1138 /* An XForm */
1139 memset(&XForm, 0, sizeof(XForm));
1140 XForm.type = vdx_types_XForm;
1141 a = visio_point(*center);
1142 XForm.PinX = a.x; /* Start */
1143 XForm.PinY = a.y;
1144 XForm.Width = visio_length(width);
1145 XForm.Height = visio_length(height);
1146 XForm.LocPinX = XForm.Width/2.0;
1147 XForm.LocPinY = XForm.Height/2.0;
1148 XForm.Angle = 0.0;
1150 /* Standard Geom object */
1151 memset(&Geom, 0, sizeof(Geom));
1152 Geom.NoFill = 1;
1153 Geom.type = vdx_types_Geom;
1155 /* One child - Ellipse */
1156 memset(&Ellipse, 0, sizeof(Ellipse));
1157 Ellipse.type = vdx_types_Ellipse;
1158 Ellipse.IX = 1;
1159 Ellipse.X = XForm.Width/2.0;
1160 Ellipse.Y = XForm.Height/2.0;
1161 Ellipse.A = XForm.Width;
1162 Ellipse.B = XForm.Height/2.0;
1163 Ellipse.C = XForm.Width/2.0;
1164 Ellipse.D = XForm.Height;
1166 /* A Line (colour etc) */
1167 create_Line(renderer, color, &Line, 0, 0);
1169 /* Setup children */
1170 Geom.children = g_slist_append(Geom.children, &Ellipse);
1172 Shape.children = g_slist_append(Shape.children, &XForm);
1173 Shape.children = g_slist_append(Shape.children, &Line);
1174 Shape.children = g_slist_append(Shape.children, &Geom);
1176 /* Write out XML */
1177 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1179 /* Free up list entries */
1180 g_slist_free(Geom.children);
1181 g_slist_free(Shape.children);
1184 /** Render a Dia filled ellipse (parallel to axes)
1185 * @param self a renderer
1186 * @param center centre of ellipse
1187 * @param width width of bounding box
1188 * @param height height of bounding box
1189 * @param color line colour
1192 static void fill_ellipse(DiaRenderer *self,
1193 Point *center,
1194 real width, real height,
1195 Color *color)
1197 VDXRenderer *renderer = VDX_RENDERER(self);
1198 Point a;
1199 struct vdx_Shape Shape;
1200 struct vdx_XForm XForm;
1201 struct vdx_Geom Geom;
1202 struct vdx_Ellipse Ellipse;
1203 struct vdx_Fill Fill;
1204 char NameU[VDX_NAMEU_LEN];
1206 /* First time through, just construct the colour table */
1207 if (renderer->first_pass)
1209 vdxCheckColor(renderer, color);
1210 return;
1213 g_debug("fill_ellipse");
1215 /* Setup the standard shape object */
1216 memset(&Shape, 0, sizeof(Shape));
1217 Shape.type = vdx_types_Shape;
1218 Shape.ID = renderer->shapeid++;
1219 Shape.Type = "Shape";
1220 sprintf(NameU, "FillEllipse.%d", Shape.ID);
1221 Shape.NameU = NameU;
1222 Shape.LineStyle_exists = 1;
1223 Shape.FillStyle_exists = 1;
1224 Shape.TextStyle_exists = 1;
1226 /* An XForm */
1227 memset(&XForm, 0, sizeof(XForm));
1228 XForm.type = vdx_types_XForm;
1229 a = visio_point(*center);
1230 XForm.PinX = a.x; /* Start */
1231 XForm.PinY = a.y;
1232 XForm.Width = visio_length(width);
1233 XForm.Height = visio_length(height);
1234 XForm.LocPinX = XForm.Width/2.0;
1235 XForm.LocPinY = XForm.Height/2.0;
1236 XForm.Angle = 0.0;
1238 /* Standard Geom object */
1239 memset(&Geom, 0, sizeof(Geom));
1240 Geom.type = vdx_types_Geom;
1242 /* One child - Ellipse */
1243 memset(&Ellipse, 0, sizeof(Ellipse));
1244 Ellipse.type = vdx_types_Ellipse;
1245 Ellipse.IX = 1;
1246 Ellipse.X = XForm.Width/2.0;
1247 Ellipse.Y = XForm.Height/2.0;
1248 Ellipse.A = XForm.Width;
1249 Ellipse.B = XForm.Height/2.0;
1250 Ellipse.C = XForm.Width/2.0;
1251 Ellipse.D = XForm.Height;
1253 /* A Fill (colour etc) */
1254 create_Fill(renderer, color, &Fill);
1256 /* Setup children */
1257 Geom.children = g_slist_append(Geom.children, &Ellipse);
1259 Shape.children = g_slist_append(Shape.children, &XForm);
1260 Shape.children = g_slist_append(Shape.children, &Fill);
1261 Shape.children = g_slist_append(Shape.children, &Geom);
1263 /* Write out XML */
1264 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1266 /* Free up list entries */
1267 g_slist_free(Geom.children);
1268 g_slist_free(Shape.children);
1271 /** Render a Dia string
1272 * @param self a renderer
1273 * @param text the string
1274 * @param pos start (or centre etc.)
1275 * @param alignment alignment
1276 * @param color line colour
1277 * @todo Alignment, colour
1278 * @bug Bounding box incorrect
1281 static void draw_string(DiaRenderer *self,
1282 const char *text,
1283 Point *pos, Alignment alignment,
1284 Color *color)
1286 VDXRenderer *renderer = VDX_RENDERER(self);
1287 Point a;
1288 struct vdx_Shape Shape;
1289 struct vdx_XForm XForm;
1290 struct vdx_Char Char;
1291 struct vdx_Text Text;
1292 struct vdx_text my_text;
1293 char NameU[VDX_NAMEU_LEN];
1295 if (renderer->first_pass)
1297 /* Add to colour and font tables */
1298 vdxCheckColor(renderer, color);
1299 vdxCheckFont(renderer);
1300 return;
1303 g_debug("draw_string");
1304 /* Standard shape */
1305 memset(&Shape, 0, sizeof(Shape));
1306 Shape.type = vdx_types_Shape;
1307 Shape.ID = renderer->shapeid++;
1308 Shape.Type = "Shape";
1309 sprintf(NameU, "Text.%d", Shape.ID);
1310 Shape.NameU = NameU;
1311 Shape.LineStyle_exists = 1;
1312 Shape.FillStyle_exists = 1;
1313 Shape.TextStyle_exists = 1;
1315 /* XForm describes bounding box */
1316 memset(&XForm, 0, sizeof(XForm));
1317 XForm.type = vdx_types_XForm;
1318 a = visio_point(*pos);
1319 XForm.PinX = a.x;
1320 XForm.PinY = a.y;
1321 XForm.Angle = 0;
1322 /* Hack to give it an approximate bounding box */
1323 XForm.Height = renderer->fontheight/vdx_Font_Size_Conversion;
1324 XForm.Width = strlen(text)*renderer->fontheight/vdx_Font_Size_Conversion;
1326 /* Character properties */
1327 memset(&Char, 0, sizeof(Char));
1328 Char.type = vdx_types_Char;
1329 Char.Font = vdxCheckFont(renderer);
1330 Char.Color = *color;
1331 Char.FontScale = 1;
1332 Char.Size = renderer->fontheight/vdx_Font_Size_Conversion;
1334 /* Text object - no attributes */
1335 memset(&Text, 0, sizeof(Text));
1336 Text.type = vdx_types_Text;
1338 /* text object (XML pseudo-tag) - no attributes */
1339 memset(&my_text, 0, sizeof(my_text));
1340 my_text.type = vdx_types_text;
1341 my_text.text = (char *)text;
1343 /* Construct the children */
1344 Text.children = g_slist_append(Text.children, &my_text);
1346 Shape.children = g_slist_append(Shape.children, &XForm);
1347 Shape.children = g_slist_append(Shape.children, &Char);
1348 Shape.children = g_slist_append(Shape.children, &Text);
1350 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1352 g_slist_free(Text.children);
1353 g_slist_free(Shape.children);
1356 /** Reads binary file and converts to Base64 data
1357 * @param filename file to read
1358 * @returns Base64 encoded data (or NULL if problem)
1359 * @note glibc 2.12 offers g_base64_encode()
1362 static char *
1363 read_base64_file(const char *filename)
1365 FILE *f;
1366 char *b64 = 0;
1367 char *s = 0;
1368 int c = 0;
1369 char map[64];
1370 unsigned int buf_len = 0;
1371 unsigned char buf[3];
1372 struct stat stat_buf;
1374 if (g_stat(filename, &stat_buf))
1376 message_error(_("Couldn't read file %s"), filename);
1377 return 0;
1379 b64 = g_new0(char, stat_buf.st_size*4/3+5);
1380 s = b64;
1382 f = g_fopen(filename, "r+b");
1383 if (!f)
1385 message_error(_("Couldn't read file %s"), filename);
1386 return 0;
1389 /* Construct Base64 mapping table */
1390 for(c=0; c<26; c++) map[c] = 'A' + c;
1391 for(c=0; c<26; c++) map[c+26] = 'a' + c;
1392 for(c=0; c<10; c++) map[c+52] = '0' + c;
1393 map[62] = '+';
1394 map[63] = '/';
1396 while((c = fgetc(f)) != EOF)
1398 buf[buf_len++] = (unsigned char)c;
1399 if (buf_len == 3)
1401 *s++ = map[buf[0] >> 2];
1402 *s++ = map[((buf[0] & 3) << 4) + (buf[1] >> 4)];
1403 *s++ = map[((buf[1] & 15) << 2) + (buf[2] >> 6)];
1404 *s++ = map[buf[2] & 63];
1405 buf_len = 0;
1409 if (buf_len == 1)
1411 *s++ = map[buf[0] >> 2];
1412 *s++ = map[((buf[0] & 3) << 4)];
1413 *s++ = '=';
1414 *s++ = '=';
1416 if (buf_len == 2)
1418 *s++ = map[buf[0] >> 2];
1419 *s++ = map[((buf[0] & 3) << 4) + (buf[1] >> 4)];
1420 *s++ = map[((buf[1] & 15) << 2)];
1421 *s++ = '=';
1424 fclose(f);
1425 *s = 0;
1426 return b64;
1428 /* Deal with any chunks left over */
1429 if (buf_len)
1431 fputc(buf[0] << 2 | buf[1] >> 4, f);
1432 if (buf_len > 1)
1434 fputc(buf[1] << 4 | buf[2] >> 2, f);
1435 if (buf_len > 2)
1437 /* This one can't happen */
1438 fputc(buf[2] << 6 | buf[3], f);
1443 fclose(f);
1446 /** Render a Dia bitmap
1447 * @param self a renderer
1448 * @param point top left
1449 * @param width width
1450 * @param height height
1453 static void draw_image(DiaRenderer *self,
1454 Point *point,
1455 real width, real height,
1456 DiaImage image)
1458 VDXRenderer *renderer = VDX_RENDERER(self);
1459 Point a, bottom_left;
1460 struct vdx_Shape Shape;
1461 struct vdx_XForm XForm;
1462 struct vdx_Geom Geom;
1463 struct vdx_Foreign Foreign;
1464 struct vdx_ForeignData ForeignData;
1465 struct vdx_text text;
1466 char NameU[VDX_NAMEU_LEN];
1467 const char *filename = NULL;
1468 const char *suffix = NULL;
1470 if (renderer->first_pass)
1472 return;
1475 g_debug("draw_image((%f,%f), %f, %f, %s", point->x, point->y,
1476 width, height, dia_image_filename(image));
1477 /* Setup the standard shape object */
1478 memset(&Shape, 0, sizeof(Shape));
1479 Shape.type = vdx_types_Shape;
1480 Shape.ID = renderer->shapeid++;
1481 Shape.Type = "Foreign";
1482 sprintf(NameU, "Foreign.%d", Shape.ID);
1483 Shape.NameU = NameU;
1484 Shape.LineStyle_exists = 1;
1485 Shape.FillStyle_exists = 1;
1486 Shape.TextStyle_exists = 1;
1488 /* An XForm */
1489 memset(&XForm, 0, sizeof(XForm));
1490 XForm.type = vdx_types_XForm;
1491 bottom_left.x = point->x;
1492 bottom_left.y = point->y + height;
1493 a = visio_point(bottom_left);
1494 XForm.PinX = a.x; /* Start */
1495 XForm.PinY = a.y;
1496 XForm.Width = visio_length(width);
1497 XForm.Height = visio_length(height);
1498 XForm.LocPinX = 0;
1499 XForm.LocPinY = 0;
1500 XForm.Angle = 0.0;
1502 /* Standard Geom object */
1503 memset(&Geom, 0, sizeof(Geom));
1504 Geom.type = vdx_types_Geom;
1505 /* We don't use it, but our decoder needs it */
1507 /* And a Foreign */
1508 memset(&Foreign, 0, sizeof(Foreign));
1509 Foreign.type = vdx_types_Foreign;
1510 Foreign.ImgOffsetX = 0;
1511 Foreign.ImgOffsetY = 0;
1512 Foreign.ImgHeight = visio_length(height);
1513 Foreign.ImgWidth = visio_length(width);
1515 /* And a ForeignData */
1516 memset(&ForeignData, 0, sizeof(ForeignData));
1517 ForeignData.type = vdx_types_ForeignData;
1518 ForeignData.ForeignType = "Bitmap";
1519 ForeignData.CompressionType = "JPEG";
1520 ForeignData.CompressionLevel = 1.0;
1521 ForeignData.ObjectHeight = visio_length(height);
1522 ForeignData.ObjectWidth = visio_length(width);
1524 filename = dia_image_filename(image);
1525 if ((suffix = strrchr(filename, '.')))
1527 suffix++;
1528 if (!g_ascii_strncasecmp(suffix, "png", 3)) { ForeignData.CompressionType = "PNG"; }
1529 if (!g_ascii_strncasecmp(suffix, "gif", 3)) { ForeignData.CompressionType = "GIF"; }
1530 if (!g_ascii_strncasecmp(suffix, "jpg", 3) || !g_ascii_strncasecmp(suffix, "jpeg", 4))
1531 { ForeignData.CompressionType = "JPEG"; }
1532 if (!g_ascii_strncasecmp(suffix, "tif", 3) || !g_ascii_strncasecmp(suffix, "tiff", 4))
1533 { ForeignData.CompressionType = "TIFF"; }
1536 /* And the data itself */
1537 memset(&text, 0, sizeof(text));
1538 text.type = vdx_types_text;
1539 text.text = read_base64_file(filename);
1540 if (!text.text) return; /* Problem reading file */
1542 /* Setup children */
1543 Shape.children = g_slist_append(Shape.children, &XForm);
1544 Shape.children = g_slist_append(Shape.children, &Geom);
1545 Shape.children = g_slist_append(Shape.children, &Foreign);
1546 Shape.children = g_slist_append(Shape.children, &ForeignData);
1547 ForeignData.children = g_slist_append(ForeignData.children, &text);
1549 /* Write out XML */
1550 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1552 /* Free up list entries */
1553 g_slist_free(ForeignData.children);
1554 g_slist_free(Shape.children);
1556 /* And the Base64 data */
1557 g_free(text.text);
1560 /** Convert Dia colour to hex string
1561 * @param c a colour
1562 * @returns string in form #000000
1563 * @note static buffer overwritten with next call; not thread-safe
1566 const char *
1567 vdx_string_color(Color c)
1569 static char buf[8];
1570 sprintf(buf, "#%.2X%.2X%.2X",
1571 (int)(c.red*255), (int)(c.green*255), (int)(c.blue*255));
1572 return buf;
1575 /** Return string XML-encoded
1576 * @param s a string
1577 * @returns encoded string
1578 * @note uses static buffer so can be used as inline filter in printf
1581 const char *
1582 vdx_convert_xml_string(const char *s)
1584 static char *out = 0;
1585 char *c;
1587 /* If (as almost always) no change required, return intact */
1588 if (strcspn(s, "&<>\"'") == strlen(s)) return s;
1590 /* Ensure we have enough space, even if all the string is quotes */
1591 out = realloc(out, 6*strlen(s)+1);
1592 c = out;
1594 while(*s)
1596 switch(*s)
1598 case '&':
1599 strcpy(c, "&amp;"); c += 5;
1600 break;
1601 case '<':
1602 strcpy(c, "&lt;"); c += 4;
1603 break;
1604 case '>':
1605 strcpy(c, "&gt;"); c += 4;
1606 break;
1607 case '\"':
1608 case '\'':
1609 strcpy(c, "&quot;"); c += 6;
1610 break;
1611 default:
1612 *c++ = *s;
1614 s++;
1616 *c = 0;
1617 return out;
1620 /** Write VDX file header
1621 * @param data diagram data
1622 * @param renderer a renderer
1623 * @note Must know if 2002 or 2003 before start
1624 * @todo paper size, orientation, metadata, 2003 font attributes
1627 static void
1628 write_header(DiagramData *data, VDXRenderer *renderer)
1630 FILE *file = renderer->file;
1631 Color c;
1632 const char *f;
1633 unsigned int i;
1634 struct vdx_StyleSheet StyleSheet;
1635 struct vdx_StyleProp StyleProp;
1636 struct vdx_Line Line;
1637 struct vdx_Fill Fill;
1638 struct vdx_TextBlock TextBlock;
1639 struct vdx_Char Char;
1640 struct vdx_Para Para;
1641 struct vdx_Tabs Tabs;
1642 static Color color_black = {0,0,0};
1644 g_debug("write_header");
1646 /* Basic XML identifying info */
1648 fprintf(file, "<?xml version='1.0' encoding='utf-8'?>\n");
1649 fprintf(file, "<!-- Created by Dia -->\n");
1650 if (renderer->version == 2002)
1652 fprintf(file,
1653 "<VisioDocument "
1654 "xmlns='urn:schemas-microsoft-com:office:visio'>\n");
1656 if (renderer->version == 2003)
1658 fprintf(file, "<VisioDocument "
1659 "xmlns='http://schemas.microsoft.com/visio/2003/core' "
1660 "start='190' metric='0' "
1661 "DocLangID='1033' version='11.0' xml:space='preserve'>\n");
1664 /* Skipping DocumentProperties, DocumentSettings - observed unnecessary */
1666 /* Other fields that may be useful:
1667 fprintf(file, (data->paper.is_portrait?"Portrait\n":"Landscape\n"));
1668 fprintf(file, "%s\n", data->paper.name);
1669 fprintf(file, "%f\n", data->paper.scaling*100.0);
1672 /* Colour table */
1674 fprintf(file, " <Colors>\n");
1675 for (i = 0; i < renderer->Colors->len; i++)
1677 c = g_array_index(renderer->Colors, Color, i);
1678 fprintf(file, " <ColorEntry IX='%d' RGB='%s'/>\n",
1679 i, vdx_string_color(c));
1681 fprintf(file, " </Colors>\n");
1683 /* Font table - different between the two versions (alas) */
1685 if (renderer->version == 2002)
1687 fprintf(file, " <Fonts>\n");
1688 for (i = 0; i < renderer->Fonts->len; i++)
1690 struct vdx_FontEntry Font;
1691 memset(&Font, 0, sizeof(Font));
1692 Font.type = vdx_types_FontEntry;
1693 f = g_array_index(renderer->Fonts, char *, i);
1695 /* Assume want stndard fonts names converted */
1696 if (!strcmp(f, "Helvetica")) f = "Arial";
1697 if (!strcmp(f, "Times")) f = "Times New Roman";
1699 Font.Name = (char *)f;
1700 /* Sensible defaults */
1701 Font.CharSet = 0;
1702 Font.CharSet_exists = 1;
1703 Font.PitchAndFamily = 18;
1704 Font.PitchAndFamily_exists = 1;
1705 Font.Attributes = 23040;
1706 Font.Attributes_exists = 1;
1707 Font.Weight = 0;
1708 Font.Unicode = 0;
1710 /* Some observed values */
1711 if (!strcmp(f, "Arial")) Font.PitchAndFamily = 32;
1712 if (!strcmp(f, "Wingdings") || !strcmp(f, "Monotype Sorts") ||
1713 !strcmp(f, "Symbol")) Font.CharSet = 2;
1714 if (!strcmp(f, "Monotype Sorts")) Font.Attributes = 4096;
1715 if (!strcmp(f, "Wingdings") || !strcmp(f, "Monotype Sorts"))
1716 Font.PitchAndFamily = 2;
1717 vdx_write_object(renderer->file, 2, &Font);
1719 fprintf(file, " </Fonts>\n");
1721 if (renderer->version == 2003)
1723 fprintf(file, " <FaceNames>\n");
1724 for (i = 0; i < renderer->Fonts->len; i++)
1726 f = g_array_index(renderer->Fonts, char *, i);
1728 /* Assume want stndard fonts names converted */
1729 if (!strcmp(f, "Helvetica")) f = "Arial";
1730 if (!strcmp(f, "Times")) f = "Times New Roman";
1732 /* Missing attrs UnicodeRanges="31367 -2147483648 8 0"
1733 CharSets="1073742335 -65536"
1734 Panos="2 11 6 4 2 2 2 2 2 4" Flags="325" */
1735 fprintf(file, " <FaceName ID='%d' Name='%s'/>\n",
1736 i, f);
1738 fprintf(file, " </FaceNames>\n");
1741 /* An initial stylesheet (mandatory) */
1742 memset(&StyleSheet, 0, sizeof(StyleSheet));
1743 StyleSheet.type = vdx_types_StyleSheet;
1744 StyleSheet.NameU = "No Style";
1746 /* All these values observed */
1747 memset(&StyleProp, 0, sizeof(StyleProp));
1748 StyleProp.type = vdx_types_StyleProp;
1749 StyleProp.EnableLineProps = 1;
1750 StyleProp.EnableFillProps = 1;
1751 StyleProp.EnableTextProps = 1;
1753 memset(&Line, 0, sizeof(Line));
1754 Line.type = vdx_types_Line;
1755 Line.LineWeight = 0.01;
1756 Line.LinePattern = 1;
1758 memset(&Fill, 0, sizeof(Fill));
1759 Fill.type = vdx_types_Fill;
1760 Fill.FillForegnd = color_black;
1761 Fill.FillPattern = 1;
1763 memset(&TextBlock, 0, sizeof(TextBlock));
1764 TextBlock.type = vdx_types_TextBlock;
1765 TextBlock.VerticalAlign = 1;
1766 TextBlock.DefaultTabStop = 0.59055118110236;
1768 memset(&Char, 0, sizeof(Char));
1769 Char.type = vdx_types_Char;
1770 Char.FontScale = 1;
1771 Char.Size = 0.16666666666667;
1773 memset(&Para, 0, sizeof(Para));
1774 Para.type = vdx_types_Para;
1775 Para.SpLine = -1.2;
1776 Para.HorzAlign = 1;
1777 Para.BulletStr = "&#xe000;";
1779 memset(&Tabs, 0, sizeof(Tabs));
1780 Tabs.type = vdx_types_Tabs;
1782 /* Setup children */
1783 StyleSheet.children = g_slist_append(StyleSheet.children, &StyleProp);
1784 StyleSheet.children = g_slist_append(StyleSheet.children, &Line);
1785 StyleSheet.children = g_slist_append(StyleSheet.children, &Fill);
1786 StyleSheet.children = g_slist_append(StyleSheet.children, &TextBlock);
1787 StyleSheet.children = g_slist_append(StyleSheet.children, &Char);
1788 StyleSheet.children = g_slist_append(StyleSheet.children, &Para);
1789 StyleSheet.children = g_slist_append(StyleSheet.children, &Tabs);
1791 fprintf(file, " <StyleSheets>\n");
1792 vdx_write_object(renderer->file, 2, &StyleSheet);
1793 fprintf(file, " </StyleSheets>\n");
1795 g_slist_free(StyleSheet.children);
1797 /* Following attributes observed */
1798 fprintf(file, " <Pages>\n");
1799 fprintf(file, " <Page ID='0' NameU='Page-1' ViewScale='-1' "
1800 "ViewCenterX='5.8425196850394' ViewCenterY='3.7244094488189'>\n");
1801 fprintf(file, " <Shapes>\n");
1802 renderer->xml_depth = 4;
1803 renderer->shapeid = 1;
1805 /* Exit nested <VisioDocument><Pages><Page><Shapes> */
1808 /** Write VDX file trailer
1809 * @param data diagram data
1810 * @param renderer a renderer
1813 static void
1814 write_trailer(DiagramData *data, VDXRenderer *renderer)
1816 FILE *file = renderer->file;
1818 g_debug("write_trailer");
1820 /* Enter nested <VisioDocument><Pages><Page><Shapes> */
1822 fprintf(file, " </Shapes>\n");
1823 fprintf(file, " </Page>\n");
1824 fprintf(file, " </Pages>\n");
1825 fprintf(file, "</VisioDocument>\n");
1828 /** Write VDX file
1829 * @param data diagram data
1830 * @param filename output file (should check suffix)
1831 * @param diafilename input filename (unused)
1832 * @param user_data user data (unused)
1833 * @note Must know if 2002 or 2003 before start
1836 static void
1837 export_vdx(DiagramData *data, const gchar *filename,
1838 const gchar *diafilename, void* user_data)
1840 FILE *file;
1841 VDXRenderer *renderer;
1842 int i;
1843 Layer *layer;
1845 file = fopen(filename, "w");
1847 if (file == NULL) {
1848 message_error(_("Can't open output file %s: %s\n"),
1849 dia_message_filename(filename), strerror(errno));
1850 return;
1853 /* Create and initialise our renderer */
1854 renderer = g_object_new(VDX_TYPE_RENDERER, NULL);
1856 renderer->file = file;
1858 renderer->first_pass = TRUE;
1860 renderer->version = 2002; /* For now */
1862 DIA_RENDERER_GET_CLASS(renderer)->begin_render(DIA_RENDERER(renderer));
1864 /* First run through without drawing to setup tables */
1865 for (i=0; i<data->layers->len; i++)
1867 layer = (Layer *) g_ptr_array_index(data->layers, i);
1868 layer_render(layer, DIA_RENDERER(renderer), NULL, NULL, data, 0);
1869 renderer->depth++;
1872 write_header(data, renderer);
1874 DIA_RENDERER_GET_CLASS(renderer)->end_render(DIA_RENDERER(renderer));
1876 renderer->first_pass = FALSE;
1878 DIA_RENDERER_GET_CLASS(renderer)->begin_render(DIA_RENDERER(renderer));
1880 /* Now render */
1882 for (i=0; i<data->layers->len; i++)
1884 layer = (Layer *) g_ptr_array_index(data->layers, i);
1885 layer_render(layer, DIA_RENDERER(renderer), NULL, NULL, data, 0);
1886 renderer->depth++;
1889 DIA_RENDERER_GET_CLASS(renderer)->end_render(DIA_RENDERER(renderer));
1891 /* Done */
1893 write_trailer(data, renderer);
1895 g_object_unref(renderer);
1897 fclose(file);
1900 /* interface from filter.h */
1902 static const gchar *extensions[] = { "vdx", NULL };
1903 DiaExportFilter vdx_export_filter = {
1904 N_("Visio XML format"),
1905 extensions,
1906 export_vdx
1909 #if 0
1911 /* The following are not provided by vdx-export.c so we use the defaults.
1912 If they become necessary after testing, we can reinstate them */
1914 /** Render a Dia line with arrows
1915 * @param self a renderer
1916 * @param start start of line
1917 * @param end end of line
1918 * @param line_width width of line
1919 * @param color line colour
1920 * @param start_arrow start arrow
1921 * @param end_arrow end arrow
1924 static void draw_line_with_arrows(DiaRenderer *self,
1925 Point *start, Point *end,
1926 real line_width,
1927 Color *color,
1928 Arrow *start_arrow,
1929 Arrow *end_arrow)
1931 VDXRenderer *renderer = VDX_RENDERER(self);
1932 Point a, b;
1933 struct vdx_Shape Shape;
1934 struct vdx_XForm XForm;
1935 struct vdx_XForm1D XForm1D;
1936 struct vdx_Geom Geom;
1937 struct vdx_MoveTo MoveTo;
1938 struct vdx_LineTo LineTo;
1939 struct vdx_Line Line;
1940 char NameU[VDX_NAMEU_LEN];
1942 /* Exactly as draw_line for now */
1944 if (renderer->first_pass)
1946 vdxCheckColor(renderer, color);
1947 return;
1950 g_debug("draw_line_with_arrows");
1951 memset(&Shape, 0, sizeof(Shape));
1952 Shape.type = vdx_types_Shape;
1953 Shape.ID = renderer->shapeid++;
1954 Shape.Type = "Shape";
1955 sprintf(NameU, "ArrowLine.%d", Shape.ID);
1956 Shape.NameU = NameU;
1957 Shape.LineStyle_exists = 1;
1958 Shape.FillStyle_exists = 1;
1959 Shape.TextStyle_exists = 1;
1961 memset(&XForm, 0, sizeof(XForm));
1962 XForm.type = vdx_types_XForm;
1963 a = visio_point(*start);
1964 b = visio_point(*end);
1965 XForm.PinX = a.x;
1966 XForm.PinY = a.y;
1967 XForm.Width = fabs(b.x - a.x);
1968 XForm.Height = fabs(b.y - a.y);
1969 XForm.LocPinX = 0.0;
1970 XForm.LocPinY = 0.0;
1971 XForm.Angle = 0.0;
1973 memset(&XForm1D, 0, sizeof(XForm1D));
1974 XForm1D.type = vdx_types_XForm1D;
1975 XForm1D.BeginX = a.x;
1976 XForm1D.BeginY = a.y;
1977 XForm1D.EndX = b.x;
1978 XForm1D.EndY = b.y;
1980 memset(&Geom, 0, sizeof(Geom));
1981 Geom.NoFill = 1;
1982 Geom.type = vdx_types_Geom;
1984 memset(&MoveTo, 0, sizeof(MoveTo));
1985 MoveTo.type = vdx_types_MoveTo;
1986 MoveTo.IX = 1;
1987 MoveTo.X = 0;
1988 MoveTo.Y = 0;
1990 memset(&LineTo, 0, sizeof(LineTo));
1991 LineTo.type = vdx_types_LineTo;
1992 LineTo.IX = 2;
1993 LineTo.X = b.x-a.x;
1994 LineTo.Y = b.y-a.y;
1996 create_Line(renderer, color, &Line, start_arrow, end_arrow);
1998 Geom.children = g_slist_append(Geom.children, &MoveTo);
1999 Geom.children = g_slist_append(Geom.children, &LineTo);
2001 Shape.children = g_slist_append(Shape.children, &XForm);
2002 Shape.children = g_slist_append(Shape.children, &XForm1D);
2003 Shape.children = g_slist_append(Shape.children, &Line);
2004 Shape.children = g_slist_append(Shape.children, &Geom);
2006 vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
2008 g_slist_free(Geom.children);
2009 g_slist_free(Shape.children);
2012 /** Render a Dia polyline with arrows
2013 * @param self a renderer
2014 * @param points points on line
2015 * @param num_points number of points
2016 * @param line_width width of line
2017 * @param color line colour
2018 * @param start_arrow start arrow
2019 * @param end_arrow end arrow
2020 * @todo Not done yet
2023 static void draw_polyline_with_arrows(DiaRenderer *self,
2024 Point *points, int num_points,
2025 real line_width,
2026 Color *color,
2027 Arrow *start_arrow,
2028 Arrow *end_arrow)
2030 VDXRenderer *renderer = VDX_RENDERER(self);
2032 if (renderer->first_pass)
2034 vdxCheckColor(renderer, color);
2035 return;
2037 g_debug("draw_polyline_with_arrows (UNUSED)");
2040 /** Render a Dia arc with arrows
2041 * @param self a renderer
2042 * @param startpoint start of arc
2043 * @param endpoint end of arc
2044 * @param midpoint middle of arc
2045 * @param line_width line width
2046 * @param color line colour
2047 * @param start_arrow start arrow
2048 * @param end_arrow end arrow
2049 * @todo Not done yet - believe unused
2052 static void draw_arc_with_arrows(DiaRenderer *self,
2053 Point *startpoint,
2054 Point *endpoint,
2055 Point *midpoint,
2056 real line_width,
2057 Color *color,
2058 Arrow *start_arrow,
2059 Arrow *end_arrow)
2061 VDXRenderer *renderer = VDX_RENDERER(self);
2063 if (renderer->first_pass)
2065 vdxCheckColor(renderer, color);
2066 return;
2068 g_debug("draw_arc_with_arrows (TODO)");
2071 /** Render a Dia Bezier
2072 * @param self a renderer
2073 * @param points list of Bezier points
2074 * @param numpoints number of points
2075 * @param color line colour
2076 * @todo Not done yet - either convert to arcs or NURBS (Visio 2003)
2079 static void draw_bezier(DiaRenderer *self,
2080 BezPoint *points,
2081 int numpoints,
2082 Color *color)
2084 VDXRenderer *renderer = VDX_RENDERER(self);
2086 if (renderer->first_pass)
2088 vdxCheckColor(renderer, color);
2089 return;
2091 g_debug("draw_bezier (TODO)");
2094 /** Render a Dia Bezier with arrows
2095 * @param self a renderer
2096 * @param points list of Bezier points
2097 * @param numpoints number of points
2098 * @param line_width line width
2099 * @param color line colour
2100 * @param start_arrow start arrow
2101 * @param end_arrow end arrow
2102 * @todo Not done yet - either convert to arcs or NURBS (Visio 2003)
2105 static void draw_bezier_with_arrows(DiaRenderer *self,
2106 BezPoint *points,
2107 int numpoints,
2108 real line_width,
2109 Color *color,
2110 Arrow *start_arrow,
2111 Arrow *end_arrow)
2113 VDXRenderer *renderer = VDX_RENDERER(self);
2115 if (renderer->first_pass)
2117 vdxCheckColor(renderer, color);
2118 return;
2120 g_debug("draw_bezier_with_arrows (TODO)");
2123 /** Render a Dia filled Bezier
2124 * @param self a renderer
2125 * @param points list of Bezier points (last = first)
2126 * @param numpoints number of points
2127 * @param color line colour
2128 * @todo Not done yet - either convert to arcs or NURBS (Visio 2003)
2131 static void fill_bezier(DiaRenderer *self,
2132 BezPoint *points,
2133 int numpoints,
2134 Color *color)
2136 VDXRenderer *renderer = VDX_RENDERER(self);
2138 if (renderer->first_pass)
2140 vdxCheckColor(renderer, color);
2141 return;
2144 g_debug("fill_bezier (TODO)");
2147 /** Render a Dia object
2148 * @param self a renderer
2149 * @param object an object
2150 * @note No work done here - perhaps should push/pop renderer state
2153 static void draw_object(DiaRenderer *self,
2154 DiaObject *object)
2156 VDXRenderer *renderer = VDX_RENDERER(self);
2158 g_debug("draw_object -> renderer");
2159 /* Get the object to draw itself */
2160 object->ops->draw(object, DIA_RENDERER(renderer));
2164 #endif