1 /* -*- Mode: C; c-basic-offset: 4 -*- */
2 /* Dia -- an diagram creation/manipulation program
3 * Copyright (C) 1998 Alexander Larsson
5 * cgm.c -- CGM plugin for dia
6 * Copyright (C) 1999-2000 James Henstridge.
7 * Copyright (C) 2000 Henk Jan Priester.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 #include "diarenderer.h"
40 #include "dia_image.h"
44 #define CGM_TYPE_RENDERER (cgm_renderer_get_type ())
45 #define CGM_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CGM_TYPE_RENDERER, CgmRenderer))
46 #define CGM_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CGM_TYPE_RENDERER, CgmRendererClass))
47 #define CGM_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CGM_TYPE_RENDERER))
48 #define CGM_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CGM_TYPE_RENDERER, CgmRendererClass))
50 GType
cgm_renderer_get_type (void) G_GNUC_CONST
;
52 typedef struct _CgmRenderer CgmRenderer
;
53 typedef struct _CgmRendererClass CgmRendererClass
;
55 struct _CgmRendererClass
57 DiaRendererClass parent_class
;
60 static const gchar
*dia_version_string
= "Dia-" VERSION
;
61 #define IS_ODD(n) (n & 0x01)
63 /* --- routines to write various quantities to the CGM stream. --- */
64 /* signed integers are stored in two complement this is common on Unix */
66 write_uint16(FILE *fp
, guint16 n
)
68 putc( (n
& 0xff00) >> 8, fp
);
73 write_int16(FILE *fp
, gint16 n
)
75 write_uint16(fp
, (guint16
)n
);
79 write_uint32(FILE *fp
, guint32 n
)
81 putc((n
>> 24) & 0xff, fp
);
82 putc((n
>> 16) & 0xff, fp
);
83 putc((n
>> 8) & 0xff, fp
);
88 write_int32(FILE *fp
, gint32 n
)
90 write_uint32(fp
, (guint32
) n
);
94 write_colour(FILE *fp
, Color
*c
)
96 putc((int)(c
->red
* 255), fp
);
97 putc((int)(c
->green
* 255), fp
);
98 putc((int)(c
->blue
* 255), fp
);
102 /* 32 bit fixed point real number */
103 /* stored as 16 bit signed (SI) number and a 16 bit unsigned (UI) for */
105 /* value is SI + UI / 2^16 */
107 write_real(FILE *fp
, double x
)
116 wholepart
= (gint32
)x
;
118 fraction
= (guint16
)((x
- wholepart
) * -65536);
122 fraction
= (guint16
)(65536 - fraction
);
124 n
= (guint32
)(wholepart
<< 16) | fraction
;
127 n
= (guint32
) (x
* (1 << 16));
132 write_elhead(FILE *fp
, int el_class
, int el_id
, int nparams
)
136 head
= (el_class
& 0x0f) << 12;
137 head
+= (el_id
& 0x7f) << 5;
140 /* use long header format */
142 write_uint16(fp
, head
);
143 write_int16(fp
, (gint16
)nparams
);
145 /* use short header format */
146 head
+= nparams
& 0x1f;
147 write_uint16(fp
, head
);
152 /* --- font stuff --- */
154 static gchar
*fontlist
;
155 static gint fontlistlen
;
156 static GHashTable
*fonthash
;
157 #define FONT_NUM(font) GPOINTER_TO_INT(g_hash_table_lookup(fonthash, \
158 dia_font_get_family(font)))
163 /* PANGO FIXME: this is probably broken to some extent now */
164 static gboolean alreadyrun
= FALSE
;
167 PangoContext
*context
;
168 PangoFontFamily
**families
;
170 const char *familyname
;
172 if (alreadyrun
) return;
175 context
= gdk_pango_context_get();
176 pango_context_list_families(context
,&families
,&n_families
);
178 fonthash
= g_hash_table_new(g_str_hash
, g_str_equal
);
179 str
= g_string_new(NULL
);
180 for (i
= 0; i
< n_families
; ++i
) {
181 familyname
= pango_font_family_get_name(families
[i
]);
183 g_string_append_c(str
, strlen(familyname
));
184 g_string_append(str
, familyname
);
185 g_hash_table_insert(fonthash
, (gpointer
)familyname
,
186 GINT_TO_POINTER(i
+1));
189 fontlistlen
= str
->len
;
190 g_string_free(str
, FALSE
);
193 /* --- CGM line attributes --- */
194 typedef struct _LineAttrCGM
204 /* --- CGM File/Edge attributes --- */
205 typedef struct _FillEdgeAttrCGM
208 int fill_style
; /* Fill style */
209 Color fill_color
; /* Fill color */
211 int edgevis
; /* Edge visibility */
212 int cap
; /* Edge cap */
213 int join
; /* Edge join */
214 int style
; /* Edge style */
215 real width
; /* Edge width */
216 Color color
; /* Edge color */
221 /* --- CGM Text attributes --- */
222 typedef struct _TextAttrCGM
231 /* --- the renderer --- */
235 DiaRenderer parent_instance
;
243 LineAttrCGM lcurrent
, linfile
;
245 FillEdgeAttrCGM fcurrent
, finfile
;
247 TextAttrCGM tcurrent
, tinfile
;
253 static void begin_render(DiaRenderer
*self
);
254 static void end_render(DiaRenderer
*self
);
255 static void set_linewidth(DiaRenderer
*self
, real linewidth
);
256 static void set_linecaps(DiaRenderer
*self
, LineCaps mode
);
257 static void set_linejoin(DiaRenderer
*self
, LineJoin mode
);
258 static void set_linestyle(DiaRenderer
*self
, LineStyle mode
);
259 static void set_dashlength(DiaRenderer
*self
, real length
);
260 static void set_fillstyle(DiaRenderer
*self
, FillStyle mode
);
261 static void set_font(DiaRenderer
*self
, DiaFont
*font
, real height
);
262 static void draw_line(DiaRenderer
*self
,
263 Point
*start
, Point
*end
,
265 static void draw_polyline(DiaRenderer
*self
,
266 Point
*points
, int num_points
,
268 static void draw_polygon(DiaRenderer
*self
,
269 Point
*points
, int num_points
,
271 static void fill_polygon(DiaRenderer
*self
,
272 Point
*points
, int num_points
,
274 static void draw_rect(DiaRenderer
*self
,
275 Point
*ul_corner
, Point
*lr_corner
,
277 static void fill_rect(DiaRenderer
*self
,
278 Point
*ul_corner
, Point
*lr_corner
,
280 static void draw_arc(DiaRenderer
*self
,
282 real width
, real height
,
283 real angle1
, real angle2
,
285 static void fill_arc(DiaRenderer
*self
,
287 real width
, real height
,
288 real angle1
, real angle2
,
290 static void draw_ellipse(DiaRenderer
*self
,
292 real width
, real height
,
294 static void fill_ellipse(DiaRenderer
*self
,
296 real width
, real height
,
298 static void draw_bezier(DiaRenderer
*self
,
302 static void fill_bezier(DiaRenderer
*self
,
303 BezPoint
*points
, /* Last point must be same as first point */
306 static void draw_string(DiaRenderer
*self
,
308 Point
*pos
, Alignment alignment
,
310 static void draw_image(DiaRenderer
*self
,
312 real width
, real height
,
316 init_attributes( CgmRenderer
*renderer
)
318 /* current values, (defaults) */
319 renderer
->lcurrent
.cap
= 3; /* round */
320 renderer
->lcurrent
.join
= 2; /* mitre */
321 renderer
->lcurrent
.style
= 1;
322 renderer
->lcurrent
.width
= 0.1;
323 renderer
->lcurrent
.color
.red
= 0;
324 renderer
->lcurrent
.color
.green
= 0;
325 renderer
->lcurrent
.color
.blue
= 0;
327 renderer
->linfile
.cap
= -1;
328 renderer
->linfile
.join
= -1;
329 renderer
->linfile
.style
= -1;
330 renderer
->linfile
.width
= -1.0;
331 renderer
->linfile
.color
.red
= -1;
332 renderer
->linfile
.color
.green
= -1;
333 renderer
->linfile
.color
.blue
= -1;
335 /* fill/edge defaults */
336 renderer
->fcurrent
.fill_style
= 1; /* solid */
337 renderer
->fcurrent
.fill_color
.red
= 0;
338 renderer
->fcurrent
.fill_color
.green
= 0;
339 renderer
->fcurrent
.fill_color
.blue
= 0;
341 renderer
->fcurrent
.edgevis
= 0;
342 renderer
->fcurrent
.cap
= 3; /* round */
343 renderer
->fcurrent
.join
= 2; /* mitre */
344 renderer
->fcurrent
.style
= 1;
345 renderer
->fcurrent
.width
= 0.1;
346 renderer
->fcurrent
.color
.red
= 0;
347 renderer
->fcurrent
.color
.green
= 0;
348 renderer
->fcurrent
.color
.blue
= 0;
350 renderer
->finfile
.fill_style
= -1;
351 renderer
->finfile
.fill_color
.red
= -1;
352 renderer
->finfile
.fill_color
.green
= -1;
353 renderer
->finfile
.fill_color
.blue
= -1;
355 renderer
->finfile
.edgevis
= -1;
356 renderer
->finfile
.cap
= -1;
357 renderer
->finfile
.join
= -1;
358 renderer
->finfile
.style
= -1;
359 renderer
->finfile
.width
= -1.;
360 renderer
->finfile
.color
.red
= -1.0;
361 renderer
->finfile
.color
.green
= -1.0;
362 renderer
->finfile
.color
.blue
= -1.0;
364 renderer
->tcurrent
.font_num
= 1;
365 renderer
->tcurrent
.font_height
= 0.1;
366 renderer
->tcurrent
.color
.red
= 0.0;
367 renderer
->tcurrent
.color
.green
= 0.0;
368 renderer
->tcurrent
.color
.blue
= 0.0;
370 renderer
->tinfile
.font_num
= -1;
371 renderer
->tinfile
.font_height
= -1.0;
372 renderer
->tinfile
.color
.red
= -1.0;
373 renderer
->tinfile
.color
.green
= -1.0;
374 renderer
->tinfile
.color
.blue
= -1.0;
381 swap_y( CgmRenderer
*renderer
, real y
)
383 return (renderer
->y0
+ renderer
->y1
- y
);
388 write_line_attributes( CgmRenderer
*renderer
, Color
*color
)
390 LineAttrCGM
*lnew
, *lold
;
392 lnew
= &renderer
->lcurrent
;
393 lold
= &renderer
->linfile
;
395 if ( lnew
->cap
!= lold
->cap
)
397 write_elhead(renderer
->file
, 5, 37, 4);
398 write_int16(renderer
->file
, lnew
->cap
);
399 write_int16(renderer
->file
, 3); /* cap of dashlines match */
401 lold
->cap
= lnew
->cap
;
403 if ( lnew
->join
!= lold
->join
)
405 write_elhead(renderer
->file
, 5, 38, 2);
406 write_int16(renderer
->file
, lnew
->join
);
407 lold
->join
= lnew
->join
;
409 if ( lnew
->style
!= lold
->style
)
411 write_elhead(renderer
->file
, 5, 2, 2);
412 write_int16(renderer
->file
, lnew
->style
);
413 lold
->style
= lnew
->style
;
415 if ( lnew
->width
!= lold
->width
)
417 write_elhead(renderer
->file
, 5, 3, REALSIZE
);
418 write_real(renderer
->file
, lnew
->width
);
419 lold
->width
= lnew
->width
;
421 lnew
->color
= *color
;
422 if ( lnew
->color
.red
!= lold
->color
.red
||
423 lnew
->color
.green
!= lold
->color
.green
||
424 lnew
->color
.blue
!= lold
->color
.blue
)
426 write_elhead(renderer
->file
, 5, 4, 3); /* line colour */
427 write_colour(renderer
->file
, &lnew
->color
);
428 putc(0, renderer
->file
);
429 lold
->color
= lnew
->color
;
435 ** Update the fill/edge attributes.
437 ** fill_color != NULL, style solid, interrior-color is fill_color
438 ** == NULL, style empty
440 ** edge_color != NULL, edge on with the color and the other
446 write_filledge_attributes( CgmRenderer
*renderer
, Color
*fill_color
,
449 FillEdgeAttrCGM
*fnew
, *fold
;
451 fnew
= &renderer
->fcurrent
;
452 fold
= &renderer
->finfile
;
454 ** Set the edge attributes
457 if ( edge_color
== NULL
)
459 fnew
->edgevis
= 0; /* edge off */
460 if ( fnew
->edgevis
!= fold
->edgevis
)
462 write_elhead(renderer
->file
, 5, 30, 2);
463 write_int16(renderer
->file
, fnew
->edgevis
);
464 fold
->edgevis
= fnew
->edgevis
;
469 fnew
->edgevis
= 1; /* edge on */
470 if ( fnew
->edgevis
!= fold
->edgevis
)
472 write_elhead(renderer
->file
, 5, 30, 2);
473 write_int16(renderer
->file
, fnew
->edgevis
);
474 fold
->edgevis
= fnew
->edgevis
;
476 if ( fnew
->cap
!= fold
->cap
)
478 write_elhead(renderer
->file
, 5, 44, 4);
479 write_int16(renderer
->file
, fnew
->cap
);
480 write_int16(renderer
->file
, 3); /* cap of dashlines match */
482 fold
->cap
= fnew
->cap
;
484 if ( fnew
->join
!= fold
->join
)
486 write_elhead(renderer
->file
, 5, 45, 2);
487 write_int16(renderer
->file
, fnew
->join
);
488 fold
->join
= fnew
->join
;
490 if ( fnew
->style
!= fold
->style
)
492 write_elhead(renderer
->file
, 5, 27, 2);
493 write_int16(renderer
->file
, fnew
->style
);
494 fold
->style
= fnew
->style
;
496 if ( fnew
->width
!= fold
->width
)
498 write_elhead(renderer
->file
, 5, 28, REALSIZE
);
499 write_real(renderer
->file
, fnew
->width
);
500 fold
->width
= fnew
->width
;
502 fnew
->color
= *edge_color
;
503 if ( fnew
->color
.red
!= fold
->color
.red
||
504 fnew
->color
.green
!= fold
->color
.green
||
505 fnew
->color
.blue
!= fold
->color
.blue
)
507 write_elhead(renderer
->file
, 5, 29, 3); /* line colour */
508 write_colour(renderer
->file
, &fnew
->color
);
509 putc(0, renderer
->file
);
510 fold
->color
= fnew
->color
;
514 if ( fill_color
== NULL
)
516 fnew
->fill_style
= 4; /* empty */
517 if ( fnew
->fill_style
!= fold
->fill_style
)
519 write_elhead(renderer
->file
, 5, 22, 2);
520 write_int16(renderer
->file
, fnew
->fill_style
);
521 fold
->fill_style
= fnew
->fill_style
;
526 fnew
->fill_style
= 1; /* solid fill */
527 if ( fnew
->fill_style
!= fold
->fill_style
)
529 write_elhead(renderer
->file
, 5, 22, 2);
530 write_int16(renderer
->file
, fnew
->fill_style
);
531 fold
->fill_style
= fnew
->fill_style
;
533 fnew
->fill_color
= *fill_color
;
534 if ( fnew
->fill_color
.red
!= fold
->fill_color
.red
||
535 fnew
->fill_color
.green
!= fold
->fill_color
.green
||
536 fnew
->fill_color
.blue
!= fold
->fill_color
.blue
)
538 write_elhead(renderer
->file
, 5, 23, 3); /* fill colour */
539 write_colour(renderer
->file
, &fnew
->fill_color
);
540 putc(0, renderer
->file
);
541 fold
->fill_color
= fnew
->fill_color
;
549 write_text_attributes( CgmRenderer
*renderer
, Color
*text_color
)
551 TextAttrCGM
*tnew
, *told
;
554 tnew
= &renderer
->tcurrent
;
555 told
= &renderer
->tinfile
;
557 ** Set the text attributes
559 if ( tnew
->font_num
!= told
->font_num
)
561 write_elhead(renderer
->file
, 5, 10, 2);
562 write_int16(renderer
->file
, tnew
->font_num
);
563 told
->font_num
= tnew
->font_num
;
566 if ( tnew
->font_height
!= told
->font_height
)
570 /* in CGM we need the base-cap height, I used the 0.9 to correct */
571 /* it because it was still to high. There might be a better way */
572 /* but for now.... */
574 h_basecap
= 0.9 * (tnew
->font_height
-
575 dia_font_descent("Aq",renderer
->font
,
577 write_elhead(renderer
->file
, 5, 15, REALSIZE
);
578 write_real(renderer
->file
, h_basecap
);
579 told
->font_height
= tnew
->font_height
;
582 tnew
->color
= *text_color
;
583 if ( tnew
->color
.red
!= told
->color
.red
||
584 tnew
->color
.green
!= told
->color
.green
||
585 tnew
->color
.blue
!= told
->color
.blue
)
587 write_elhead(renderer
->file
, 5, 14, 3); /* text colour */
588 write_colour(renderer
->file
, &tnew
->color
);
589 putc(0, renderer
->file
);
590 told
->color
= tnew
->color
;
596 begin_render(DiaRenderer
*self
)
601 end_render(DiaRenderer
*self
)
603 CgmRenderer
*renderer
= CGM_RENDERER(self
);
606 write_elhead(renderer
->file
, 0, 5, 0);
608 write_elhead(renderer
->file
, 0, 2, 0);
610 fclose(renderer
->file
);
614 set_linewidth(DiaRenderer
*self
, real linewidth
)
615 { /* 0 == hairline **/
616 CgmRenderer
*renderer
= CGM_RENDERER(self
);
618 /* update current line and edge width */
619 renderer
->lcurrent
.width
= renderer
->fcurrent
.width
= linewidth
;
623 set_linecaps(DiaRenderer
*self
, LineCaps mode
)
625 CgmRenderer
*renderer
= CGM_RENDERER(self
);
636 case LINECAPS_PROJECTING
:
643 renderer
->lcurrent
.cap
= renderer
->fcurrent
.cap
= cap
;
647 set_linejoin(DiaRenderer
*self
, LineJoin mode
)
649 CgmRenderer
*renderer
= CGM_RENDERER(self
);
667 renderer
->lcurrent
.join
= renderer
->fcurrent
.join
= join
;
671 set_linestyle(DiaRenderer
*self
, LineStyle mode
)
673 CgmRenderer
*renderer
= CGM_RENDERER(self
);
678 case LINESTYLE_DASHED
:
681 case LINESTYLE_DASH_DOT
:
684 case LINESTYLE_DASH_DOT_DOT
:
687 case LINESTYLE_DOTTED
:
690 case LINESTYLE_SOLID
:
695 renderer
->lcurrent
.style
= renderer
->fcurrent
.style
= style
;
699 set_dashlength(DiaRenderer
*self
, real length
)
700 { /* dot = 20% of len */
701 /* CGM doesn't support setting a dash length */
705 set_fillstyle(DiaRenderer
*self
, FillStyle mode
)
709 case FILLSTYLE_SOLID
:
710 write_elhead(renderer
->file
, 5, 22, 2);
711 write_int16(renderer
->file
, 1);
714 message_error("svg_renderer: Unsupported fill mode specified!\n");
720 set_font(DiaRenderer
*self
, DiaFont
*font
, real height
)
722 CgmRenderer
*renderer
= CGM_RENDERER(self
);
724 if (renderer
->font
!= NULL
)
725 dia_font_unref(renderer
->font
);
726 renderer
->font
= dia_font_ref(font
);
727 renderer
->tcurrent
.font_num
= FONT_NUM(font
);
728 renderer
->tcurrent
.font_height
= height
;
732 draw_line(DiaRenderer
*self
,
733 Point
*start
, Point
*end
,
736 CgmRenderer
*renderer
= CGM_RENDERER(self
);
738 write_line_attributes(renderer
, line_colour
);
740 write_elhead(renderer
->file
, 4, 1, 4 * REALSIZE
);
741 write_real(renderer
->file
, start
->x
);
742 write_real(renderer
->file
, swap_y(renderer
, start
->y
));
743 write_real(renderer
->file
, end
->x
);
744 write_real(renderer
->file
, swap_y(renderer
, end
->y
));
748 draw_polyline(DiaRenderer
*self
,
749 Point
*points
, int num_points
,
752 CgmRenderer
*renderer
= CGM_RENDERER(self
);
755 write_line_attributes(renderer
, line_colour
);
757 write_elhead(renderer
->file
, 4, 1, num_points
* 2 * REALSIZE
);
758 for (i
= 0; i
< num_points
; i
++) {
759 write_real(renderer
->file
, points
[i
].x
);
760 write_real(renderer
->file
, swap_y(renderer
, points
[i
].y
));
765 draw_polygon(DiaRenderer
*self
,
766 Point
*points
, int num_points
,
769 CgmRenderer
*renderer
= CGM_RENDERER(self
);
772 write_filledge_attributes(renderer
, NULL
, line_colour
);
774 write_elhead(renderer
->file
, 4, 7, num_points
* 2 * REALSIZE
);
775 for (i
= 0; i
< num_points
; i
++) {
776 write_real(renderer
->file
, points
[i
].x
);
777 write_real(renderer
->file
, swap_y(renderer
, points
[i
].y
));
782 fill_polygon(DiaRenderer
*self
,
783 Point
*points
, int num_points
,
786 CgmRenderer
*renderer
= CGM_RENDERER(self
);
789 write_filledge_attributes(renderer
, colour
, NULL
);
791 write_elhead(renderer
->file
, 4, 7, num_points
* 2 * REALSIZE
);
792 for (i
= 0; i
< num_points
; i
++) {
793 write_real(renderer
->file
, points
[i
].x
);
794 write_real(renderer
->file
, swap_y(renderer
, points
[i
].y
));
799 draw_rect(DiaRenderer
*self
,
800 Point
*ul_corner
, Point
*lr_corner
,
803 CgmRenderer
*renderer
= CGM_RENDERER(self
);
805 write_filledge_attributes(renderer
, NULL
, colour
);
807 write_elhead(renderer
->file
, 4, 11, 4 * REALSIZE
);
808 write_real(renderer
->file
, ul_corner
->x
);
809 write_real(renderer
->file
, swap_y(renderer
, ul_corner
->y
));
810 write_real(renderer
->file
, lr_corner
->x
);
811 write_real(renderer
->file
, swap_y(renderer
, lr_corner
->y
));
815 fill_rect(DiaRenderer
*self
,
816 Point
*ul_corner
, Point
*lr_corner
,
819 CgmRenderer
*renderer
= CGM_RENDERER(self
);
821 write_filledge_attributes(renderer
, colour
, NULL
);
823 write_elhead(renderer
->file
, 4, 11, 4 * REALSIZE
);
824 write_real(renderer
->file
, ul_corner
->x
);
825 write_real(renderer
->file
, swap_y(renderer
, ul_corner
->y
));
826 write_real(renderer
->file
, lr_corner
->x
);
827 write_real(renderer
->file
, swap_y(renderer
, lr_corner
->y
));
833 write_ellarc(CgmRenderer
*renderer
,
836 real width
, real height
,
837 real angle1
, real angle2
)
839 real rx
= width
/ 2, ry
= height
/ 2;
844 ** Angle's are in degrees, need to be converted to 2PI.
846 angle1
= (angle1
/ 360.0) * 2 * M_PI
;
847 angle2
= (angle2
/ 360.0) * 2 * M_PI
;
849 ynew
= swap_y(renderer
, center
->y
);
852 ** Elliptical Arc (18) or Elliptical Arc close (19).
854 len
= elemid
== 18 ? (10 * REALSIZE
) : (10 * REALSIZE
+ 2);
855 write_elhead(renderer
->file
, 4, elemid
, len
);
856 write_real(renderer
->file
, center
->x
); /* center */
857 write_real(renderer
->file
, ynew
);
858 write_real(renderer
->file
, center
->x
+ rx
); /* axes 1 */
859 write_real(renderer
->file
, ynew
);
860 write_real(renderer
->file
, center
->x
); /* axes 2 */
861 write_real(renderer
->file
, ynew
+ ry
);
863 write_real(renderer
->file
, cos(angle1
)); /* vector1 */
864 write_real(renderer
->file
, sin(angle1
));
865 write_real(renderer
->file
, cos(angle2
)); /* vector2 */
866 write_real(renderer
->file
, sin(angle2
));
869 ** Elliptical arc close, use PIE closure.
872 write_int16(renderer
->file
, 0);
877 draw_arc(DiaRenderer
*self
,
879 real width
, real height
,
880 real angle1
, real angle2
,
883 CgmRenderer
*renderer
= CGM_RENDERER(self
);
885 write_line_attributes(renderer
, colour
);
886 write_ellarc(renderer
, 18, center
, width
, height
, angle1
, angle2
);
890 fill_arc(DiaRenderer
*self
,
892 real width
, real height
,
893 real angle1
, real angle2
,
896 CgmRenderer
*renderer
= CGM_RENDERER(self
);
898 write_filledge_attributes(renderer
, colour
, NULL
);
899 write_ellarc(renderer
, 19, center
, width
, height
, angle1
, angle2
);
903 draw_ellipse(DiaRenderer
*self
,
905 real width
, real height
,
908 CgmRenderer
*renderer
= CGM_RENDERER(self
);
911 write_filledge_attributes(renderer
, NULL
, colour
);
913 ynew
= swap_y(renderer
, center
->y
);
914 write_elhead(renderer
->file
, 4, 17, 6 * REALSIZE
);
915 write_real(renderer
->file
, center
->x
); /* center */
916 write_real(renderer
->file
, ynew
);
917 write_real(renderer
->file
, center
->x
); /* axes 1 */
918 write_real(renderer
->file
, ynew
+ height
/2);
919 write_real(renderer
->file
, center
->x
+ width
/2); /* axes 2 */
920 write_real(renderer
->file
, ynew
);
924 fill_ellipse(DiaRenderer
*self
,
926 real width
, real height
,
929 CgmRenderer
*renderer
= CGM_RENDERER(self
);
932 write_filledge_attributes(renderer
, colour
, NULL
);
934 ynew
= swap_y(renderer
, center
->y
);
935 write_elhead(renderer
->file
, 4, 17, 6 * REALSIZE
);
936 write_real(renderer
->file
, center
->x
); /* center */
937 write_real(renderer
->file
, ynew
);
938 write_real(renderer
->file
, center
->x
); /* axes 1 */
939 write_real(renderer
->file
, ynew
+ height
/2);
940 write_real(renderer
->file
, center
->x
+ width
/2); /* axes 2 */
941 write_real(renderer
->file
, ynew
);
946 write_bezier(CgmRenderer
*renderer
,
953 if (points
[0].type
!= BEZ_MOVE_TO
)
954 g_warning("first BezPoint must be a BEZ_MOVE_TO");
956 current
.x
= points
[0].p1
.x
;
957 current
.y
= swap_y(renderer
, points
[0].p1
.y
);
959 for (i
= 1; i
< numpoints
; i
++)
961 switch (points
[i
].type
)
964 g_warning("only first BezPoint can be a BEZ_MOVE_TO");
967 write_elhead(renderer
->file
, 4, 1, 4 * REALSIZE
);
968 write_real(renderer
->file
, current
.x
);
969 write_real(renderer
->file
, current
.y
);
970 write_real(renderer
->file
, points
[i
].p1
.x
);
971 write_real(renderer
->file
, swap_y(renderer
, points
[i
].p1
.y
));
972 current
.x
= points
[i
].p1
.x
;
973 current
.y
= swap_y(renderer
, points
[i
].p1
.y
);
976 write_elhead(renderer
->file
, 4, 26, 8 * REALSIZE
+ 2);
977 write_int16(renderer
->file
, 1);
978 write_real(renderer
->file
, current
.x
);
979 write_real(renderer
->file
, current
.y
);
980 write_real(renderer
->file
, points
[i
].p1
.x
);
981 write_real(renderer
->file
, swap_y(renderer
, points
[i
].p1
.y
));
982 write_real(renderer
->file
, points
[i
].p2
.x
);
983 write_real(renderer
->file
, swap_y(renderer
, points
[i
].p2
.y
));
984 write_real(renderer
->file
, points
[i
].p3
.x
);
985 write_real(renderer
->file
, swap_y(renderer
, points
[i
].p3
.y
));
986 current
.x
= points
[i
].p3
.x
;
987 current
.y
= swap_y(renderer
, points
[i
].p3
.y
);
995 draw_bezier(DiaRenderer
*self
,
1000 CgmRenderer
*renderer
= CGM_RENDERER(self
);
1002 if ( numpoints
< 2 )
1005 write_line_attributes(renderer
, colour
);
1006 write_bezier(renderer
, points
, numpoints
);
1011 fill_bezier(DiaRenderer
*self
,
1012 BezPoint
*points
, /* Last point must be same as first point */
1016 CgmRenderer
*renderer
= CGM_RENDERER(self
);
1018 if ( numpoints
< 2 )
1021 write_filledge_attributes(renderer
, colour
, NULL
);
1024 ** A filled bezier is created by using it within a figure.
1026 write_elhead(renderer
->file
, 0, 8, 0); /* begin figure */
1027 write_bezier(renderer
, points
, numpoints
);
1028 write_elhead(renderer
->file
, 0, 9, 0); /* end figure */
1034 draw_string(DiaRenderer
*self
,
1036 Point
*pos
, Alignment alignment
,
1039 CgmRenderer
*renderer
= CGM_RENDERER(self
);
1040 double x
= pos
->x
, y
= swap_y(renderer
, pos
->y
);
1042 const gint maxfirstchunk
= 255 - 2 * REALSIZE
- 2 - 1;
1043 const gint maxappendchunk
= 255 - 2 - 1;
1045 /* check for empty strings */
1050 write_text_attributes(renderer
, colour
);
1052 switch (alignment
) {
1056 x
-= dia_font_string_width(text
, renderer
->font
,
1057 renderer
->tcurrent
.font_height
)/2;
1060 x
-= dia_font_string_width(text
, renderer
->font
,
1061 renderer
->tcurrent
.font_height
);
1064 /* work out size of first chunk of text */
1065 chunk
= MIN(maxfirstchunk
, len
);
1066 write_elhead(renderer
->file
, 4, 4, 2 * REALSIZE
+ 2 + 1 + chunk
);
1067 write_real(renderer
->file
, x
);
1068 write_real(renderer
->file
, y
);
1069 write_int16(renderer
->file
, (len
== chunk
)); /* last chunk? */
1070 putc(chunk
, renderer
->file
);
1071 fwrite(text
, sizeof(char), chunk
, renderer
->file
);
1073 putc(0, renderer
->file
);
1079 chunk
= MIN(maxappendchunk
, len
);
1080 write_elhead(renderer
->file
, 4, 6, 2 + 1 + chunk
);
1081 write_int16(renderer
->file
, (len
== chunk
));
1082 putc(chunk
, renderer
->file
);
1083 fwrite(text
, sizeof(char), chunk
, renderer
->file
);
1085 putc(0, renderer
->file
);
1094 draw_image(DiaRenderer
*self
,
1096 real width
, real height
,
1099 CgmRenderer
*renderer
= CGM_RENDERER(self
);
1100 const gint maxlen
= 32767 - 6 * REALSIZE
- 4 * 2;
1101 double x1
= point
->x
, y1
= swap_y(renderer
, point
->y
),
1102 x2
= x1
+width
, y2
= y1
-height
;
1103 gint rowlen
= dia_image_width(image
) * 3, lines
= dia_image_height(image
);
1104 double linesize
= (y1
- y2
) / lines
;
1105 gint chunk
, clines
= lines
;
1108 if (rowlen
> maxlen
) {
1109 message_error(_("Image row length larger than maximum cell array.\n"
1110 "Image not exported to CGM."));
1114 ptr
= pImg
= dia_image_rgb_data(image
);
1117 chunk
= MIN(rowlen
* lines
, maxlen
);
1118 clines
= chunk
/ rowlen
;
1119 chunk
= clines
* rowlen
;
1121 write_elhead(renderer
->file
, 4, 9, 6*REALSIZE
+ 8 + chunk
);
1122 write_real(renderer
->file
, x1
); /* first corner */
1123 write_real(renderer
->file
, y1
);
1124 write_real(renderer
->file
, x2
); /* second corner */
1125 write_real(renderer
->file
, y1
- linesize
*clines
/*y2*/);
1126 write_real(renderer
->file
, x2
); /* third corner */
1127 write_real(renderer
->file
, y1
);
1129 /* write image size */
1130 write_int16(renderer
->file
, dia_image_width(image
));
1131 write_int16(renderer
->file
, clines
);
1133 write_int16(renderer
->file
, 8); /* colour precision */
1134 write_int16(renderer
->file
, 1); /* packed encoding */
1136 fwrite(ptr
, sizeof(guint8
), chunk
, renderer
->file
);
1140 y1
-= clines
* linesize
;
1146 export_cgm(DiagramData
*data
, const gchar
*filename
,
1147 const gchar
*diafilename
, void* user_data
)
1149 CgmRenderer
*renderer
;
1154 file
= fopen(filename
, "wb");
1157 message_error(_("Can't open output file %s: %s\n"), filename
, strerror(errno
));
1161 renderer
= g_object_new(CGM_TYPE_RENDERER
, NULL
);
1163 renderer
->file
= file
;
1166 len
= strlen(dia_version_string
);
1167 write_elhead(file
, 0, 1, len
+ 1);
1169 fwrite(dia_version_string
, sizeof(char), len
, file
);
1173 /* write metafile version */
1174 write_elhead(file
, 1, 1, 2);
1175 write_uint16(file
, 3); /* use version 3 because we may use polybeziers */
1178 /* write metafile description -- use original dia filename */
1179 len
= strlen(diafilename
);
1180 write_elhead(file
, 1, 2, len
+ 1);
1182 fwrite(diafilename
, sizeof(char), len
, file
);
1187 /* set integer precision */
1188 write_elhead(file
, 1, 4, 2);
1189 write_int16(file
, 16);
1191 /* write element virtual device unit type */
1192 write_elhead(file
, 1, 3, 2);
1193 write_int16(file
, 1); /* real number */
1195 /* write the colour precision */
1196 write_elhead(file
, 1, 7, 2);
1197 write_int16(file
, 8); /* 8 bits per chanel */
1199 /* write element list command */
1200 write_elhead(file
, 1, 11, 6);
1201 write_int16(file
, 1);
1202 write_int16(file
, -1);
1203 write_int16(file
, 5);
1205 /* write font list */
1207 write_elhead(file
, 1, 13, fontlistlen
);
1208 fwrite(fontlist
, sizeof(char), fontlistlen
, file
);
1209 if (IS_ODD(fontlistlen
))
1213 len
= strlen(diafilename
);
1214 write_elhead(file
, 0, 3, len
+ 1);
1216 fwrite(diafilename
, sizeof(char), len
, file
);
1220 /* write the colour mode string */
1221 write_elhead(file
, 2, 2, 2);
1222 write_int16(file
, 1); /* direct colour mode (as opposed to indexed) */
1224 /* write edge width mode */
1225 write_elhead(file
, 2, 5, 2);
1226 write_int16(file
, 0); /* relative to virtual device coordinates */
1228 /* write line width mode */
1229 write_elhead(file
, 2, 3, 2);
1230 write_int16(file
, 0); /* relative to virtual device coordinates */
1232 extent
= &data
->extents
;
1235 ** Change the swap Y-coordinate in the CGM, to get a more
1239 write_elhead(file
, 2, 6, 4 * REALSIZE
);
1240 write_real(file
, extent
->left
);
1241 write_real(file
, extent
->top
);
1242 write_real(file
, extent
->right
);
1243 write_real(file
, extent
->bottom
);
1244 renderer
->y1
= extent
->top
;
1245 renderer
->y0
= extent
->bottom
;
1247 /* write back colour */
1248 write_elhead(file
, 2, 7, 3);
1249 write_colour(file
, &data
->bg_color
);
1252 /* begin the picture body */
1253 write_elhead(file
, 0, 4, 0);
1255 /* make text be the right way up */
1256 write_elhead(file
, 5, 16, 4 * REALSIZE
);
1257 write_real(file
, 0);
1258 write_real(file
, 1);
1259 write_real(file
, 1);
1260 write_real(file
, 0);
1262 /* set the text alignment to left/base */
1263 write_elhead(file
, 5, 18, 4 + 2 * REALSIZE
);
1264 write_int16(file
, 1); /* left */
1265 write_int16(file
, 4); /* base */
1266 write_real(file
, 0.0);
1267 write_real(file
, 0.0);
1269 init_attributes(renderer
);
1271 data_render(data
, DIA_RENDERER(renderer
), NULL
, NULL
, NULL
);
1273 dia_font_unref(renderer
->font
);
1274 g_object_unref(renderer
);
1278 static void cgm_renderer_class_init (CgmRendererClass
*klass
);
1280 static gpointer parent_class
= NULL
;
1283 cgm_renderer_get_type (void)
1285 static GType object_type
= 0;
1289 static const GTypeInfo object_info
=
1291 sizeof (CgmRendererClass
),
1292 (GBaseInitFunc
) NULL
,
1293 (GBaseFinalizeFunc
) NULL
,
1294 (GClassInitFunc
) cgm_renderer_class_init
,
1295 NULL
, /* class_finalize */
1296 NULL
, /* class_data */
1297 sizeof (CgmRenderer
),
1298 0, /* n_preallocs */
1302 object_type
= g_type_register_static (DIA_TYPE_RENDERER
,
1311 cgm_renderer_finalize (GObject
*object
)
1313 CgmRenderer
*cgm_renderer
= CGM_RENDERER (object
);
1315 G_OBJECT_CLASS (parent_class
)->finalize (object
);
1319 cgm_renderer_class_init (CgmRendererClass
*klass
)
1321 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1322 DiaRendererClass
*renderer_class
= DIA_RENDERER_CLASS (klass
);
1324 parent_class
= g_type_class_peek_parent (klass
);
1326 object_class
->finalize
= cgm_renderer_finalize
;
1328 renderer_class
->begin_render
= begin_render
;
1329 renderer_class
->end_render
= end_render
;
1331 renderer_class
->set_linewidth
= set_linewidth
;
1332 renderer_class
->set_linecaps
= set_linecaps
;
1333 renderer_class
->set_linejoin
= set_linejoin
;
1334 renderer_class
->set_linestyle
= set_linestyle
;
1335 renderer_class
->set_dashlength
= set_dashlength
;
1336 renderer_class
->set_fillstyle
= set_fillstyle
;
1337 renderer_class
->set_font
= set_font
;
1339 renderer_class
->draw_line
= draw_line
;
1340 renderer_class
->draw_polyline
= draw_polyline
;
1342 renderer_class
->draw_polygon
= draw_polygon
;
1343 renderer_class
->fill_polygon
= fill_polygon
;
1345 renderer_class
->draw_rect
= draw_rect
;
1346 renderer_class
->fill_rect
= fill_rect
;
1348 renderer_class
->draw_arc
= draw_arc
;
1349 renderer_class
->fill_arc
= fill_arc
;
1351 renderer_class
->draw_ellipse
= draw_ellipse
;
1352 renderer_class
->fill_ellipse
= fill_ellipse
;
1354 renderer_class
->draw_bezier
= draw_bezier
;
1355 renderer_class
->fill_bezier
= fill_bezier
;
1357 renderer_class
->draw_string
= draw_string
;
1359 renderer_class
->draw_image
= draw_image
;
1363 static const gchar
*extensions
[] = { "cgm", NULL
};
1364 static DiaExportFilter cgm_export_filter
= {
1365 N_("Computer Graphics Metafile"),
1371 /* --- dia plug-in interface --- */
1373 _plugin_can_unload (PluginInfo
*info
)
1379 _plugin_unload (PluginInfo
*info
)
1381 filter_unregister_export(&cgm_export_filter
);
1384 DIA_PLUGIN_CHECK_INIT
1387 dia_plugin_init(PluginInfo
*info
)
1389 if (!dia_plugin_info_init(info
, "CGM",
1390 _("Computer Graphics Metafile export filter"),
1393 return DIA_PLUGIN_INIT_ERROR
;
1395 filter_register_export(&cgm_export_filter
);
1397 return DIA_PLUGIN_INIT_OK
;