1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  *
4  * hpgl.c -- HPGL export plugin for dia
5  * Copyright (C) 2000, Hans Breuer, <Hans@Breuer.Org>
6  *   based on dummy.c
7  *   based on CGM plug-in Copyright (C) 1999 James Henstridge.
8  *
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.
13  *
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.
18  *
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.
22  */
23 
24 /*
25  * ToDo:
26  * - move draw_ellipse_by_arc into libdia to make it available for other
27  *   interested renderers ?
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37 #include <errno.h>
38 
39 #include <glib.h>
40 #include <glib/gstdio.h>
41 
42 #include "intl.h"
43 #include "message.h"
44 #include "geometry.h"
45 #include "diarenderer.h"
46 #include "filter.h"
47 #include "plug-ins.h"
48 
49 /* #DEFINE DEBUG_HPGL */
50 
51 /* format specific */
52 #define HPGL_MAX_PENS 8
53 
54 #define PEN_HAS_COLOR (1 << 0)
55 #define PEN_HAS_WIDTH (1 << 1)
56 
57 /* GObject boiler plate */
58 #define HPGL_TYPE_RENDERER           (hpgl_renderer_get_type ())
59 #define HPGL_RENDERER(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), HPGL_TYPE_RENDERER, HpglRenderer))
60 #define HPGL_RENDERER_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), HPGL_TYPE_RENDERER, HpglRendererClass))
61 #define HPGL_IS_RENDERER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), HPGL_TYPE_RENDERER))
62 #define HPGL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), HPGL_TYPE_RENDERER, HpglRendererClass))
63 
64 GType hpgl_renderer_get_type (void) G_GNUC_CONST;
65 
66 typedef struct _HpglRenderer HpglRenderer;
67 typedef struct _HpglRendererClass HpglRendererClass;
68 
69 struct _HpglRenderer
70 {
71   DiaRenderer parent_instance;
72 
73   FILE *file;
74 
75   /*
76    * The number of pens is limited. This is used to select one.
77    */
78   struct {
79     Color color;
80     float width;
81     int   has_it;
82   } pen[HPGL_MAX_PENS];
83   int last_pen;
84   real dash_length;
85   real font_height;
86 
87   Point size;  /* extent size */
88   real scale;
89   real offset; /* in dia units */
90 };
91 
92 struct _HpglRendererClass
93 {
94   DiaRendererClass parent_class;
95 };
96 
97 #ifdef DEBUG_HPGL
98 #  define DIAG_NOTE(action) action
99 #else
100 #  define DIAG_NOTE(action)
101 #endif
102 
103 /* hpgl helpers */
104 static void
hpgl_select_pen(HpglRenderer * renderer,Color * color,real width)105 hpgl_select_pen(HpglRenderer* renderer, Color* color, real width)
106 {
107     int nPen = 0;
108     int i;
109     /* look if this pen is defined already */
110     if (0.0 != width) {
111         /* either width ... */
112         for (i = 0; i < HPGL_MAX_PENS; i++) {
113             if (!(renderer->pen[i].has_it & PEN_HAS_WIDTH)) {
114                 nPen = i;
115                 break;
116             }
117             if (width == renderer->pen[i].width) {
118                 nPen = i;
119                 break;
120             }
121         }
122     }
123 
124     if (NULL != color) {
125         for (i = nPen; i < HPGL_MAX_PENS; i++) {
126             if (!(renderer->pen[i].has_it & PEN_HAS_COLOR)) {
127                 nPen = i;
128                 break;
129             }
130             if (   (color->red == renderer->pen[i].color.red)
131                 && (color->green == renderer->pen[i].color.green)
132                 && (color->blue == renderer->pen[i].color.blue)) {
133                 nPen = i;
134                 break;
135             }
136         }
137     }
138     /* "create" new pen ... */
139     if ((nPen < HPGL_MAX_PENS) && (-1 < nPen)) {
140         if (0.0 != width) {
141             renderer->pen[nPen].width = width;
142             renderer->pen[nPen].has_it |= PEN_HAS_WIDTH;
143         }
144         if (NULL != color) {
145             renderer->pen[nPen].color = *color;
146             renderer->pen[nPen].has_it |= PEN_HAS_COLOR;
147         }
148     }
149     /* ... or use best fitting one */
150     else if (-1 == nPen) {
151         nPen = 0; /* TODO: */
152     }
153 
154     if (renderer->last_pen != nPen)
155         fprintf(renderer->file, "SP%d;\n", nPen+1);
156     renderer->last_pen = nPen;
157 }
158 
159 static int
hpgl_scale(HpglRenderer * renderer,real val)160 hpgl_scale(HpglRenderer *renderer, real val)
161 {
162     return (int)((val + renderer->offset) * renderer->scale);
163 }
164 
165 /* render functions */
166 static void
begin_render(DiaRenderer * object)167 begin_render(DiaRenderer *object)
168 {
169     HpglRenderer *renderer = HPGL_RENDERER (object);
170     int i;
171 
172     DIAG_NOTE(g_message("begin_render"));
173 
174     /* initialize pens */
175     for (i = 0; i < HPGL_MAX_PENS; i++) {
176         renderer->pen[i].color = color_black;
177         renderer->pen[i].width = 0.0;
178         renderer->pen[i].has_it = 0;
179     }
180     renderer->last_pen = -1;
181     renderer->dash_length = 0.0;
182 }
183 
184 static void
end_render(DiaRenderer * object)185 end_render(DiaRenderer *object)
186 {
187     HpglRenderer *renderer = HPGL_RENDERER (object);
188 
189     DIAG_NOTE(g_message("end_render"));
190     fclose(renderer->file);
191 }
192 
193 static void
set_linewidth(DiaRenderer * object,real linewidth)194 set_linewidth(DiaRenderer *object, real linewidth)
195 {
196     HpglRenderer *renderer = HPGL_RENDERER (object);
197 
198     DIAG_NOTE(g_message("set_linewidth %f", linewidth));
199 
200     hpgl_select_pen(renderer, NULL, linewidth);
201 }
202 
203 static void
set_linecaps(DiaRenderer * object,LineCaps mode)204 set_linecaps(DiaRenderer *object, LineCaps mode)
205 {
206     DIAG_NOTE(g_message("set_linecaps %d", mode));
207 
208     switch(mode) {
209     case LINECAPS_BUTT:
210 	break;
211     case LINECAPS_ROUND:
212 	break;
213     case LINECAPS_PROJECTING:
214 	break;
215     default:
216 	message_error("HpglRenderer: Unsupported fill mode specified!\n");
217     }
218 }
219 
220 static void
set_linejoin(DiaRenderer * object,LineJoin mode)221 set_linejoin(DiaRenderer *object, LineJoin mode)
222 {
223     DIAG_NOTE(g_message("set_join %d", mode));
224 
225     switch(mode) {
226     case LINEJOIN_MITER:
227 	break;
228     case LINEJOIN_ROUND:
229 	break;
230     case LINEJOIN_BEVEL:
231 	break;
232     default:
233 	message_error("HpglRenderer : Unsupported fill mode specified!\n");
234     }
235 }
236 
237 static void
set_linestyle(DiaRenderer * object,LineStyle mode)238 set_linestyle(DiaRenderer *object, LineStyle mode)
239 {
240     HpglRenderer *renderer = HPGL_RENDERER (object);
241 
242     DIAG_NOTE(g_message("set_linestyle %d", mode));
243 
244     /* line type */
245     switch (mode) {
246     case LINESTYLE_SOLID:
247       fprintf(renderer->file, "LT;\n");
248       break;
249     case LINESTYLE_DASHED:
250       if (renderer->dash_length > 0.5) /* ??? unit of dash_lenght ? */
251           fprintf(renderer->file, "LT2;\n"); /* short */
252       else
253           fprintf(renderer->file, "LT3;\n"); /* long */
254       break;
255     case LINESTYLE_DASH_DOT:
256       fprintf(renderer->file, "LT4;\n");
257       break;
258     case LINESTYLE_DASH_DOT_DOT:
259       fprintf(renderer->file, "LT5;\n"); /* ??? Mittellinie? */
260       break;
261     case LINESTYLE_DOTTED:
262       fprintf(renderer->file, "LT1;\n");
263       break;
264     default:
265 	message_error("HpglRenderer : Unsupported fill mode specified!\n");
266     }
267 }
268 
269 static void
set_dashlength(DiaRenderer * object,real length)270 set_dashlength(DiaRenderer *object, real length)
271 {
272     HpglRenderer *renderer = HPGL_RENDERER (object);
273 
274     DIAG_NOTE(diag_note("set_dashlength %f", length));
275 
276     /* dot = 20% of len */
277     renderer->dash_length = length;
278 }
279 
280 static void
set_fillstyle(DiaRenderer * object,FillStyle mode)281 set_fillstyle(DiaRenderer *object, FillStyle mode)
282 {
283     DIAG_NOTE(g_message("set_fillstyle %d", mode));
284 
285     switch(mode) {
286     case FILLSTYLE_SOLID:
287 	break;
288     default:
289 	message_error("HpglRenderer : Unsupported fill mode specified!\n");
290     }
291 }
292 
293 static void
set_font(DiaRenderer * object,DiaFont * font,real height)294 set_font(DiaRenderer *object, DiaFont *font, real height)
295 {
296     HpglRenderer *renderer = HPGL_RENDERER (object);
297 
298     DIAG_NOTE(g_message("set_font %f", height));
299     renderer->font_height = height;
300 }
301 
302 /* Need to translate coord system:
303  *
304  *   Dia x,y -> Hpgl x,-y
305  *
306  * doing it before scaling.
307  */
308 static void
draw_line(DiaRenderer * object,Point * start,Point * end,Color * line_colour)309 draw_line(DiaRenderer *object,
310           Point *start, Point *end,
311           Color *line_colour)
312 {
313     HpglRenderer *renderer = HPGL_RENDERER (object);
314 
315     DIAG_NOTE(g_message("draw_line %f,%f -> %f, %f",
316               start->x, start->y, end->x, end->y));
317     hpgl_select_pen(renderer, line_colour, 0.0);
318     fprintf (renderer->file,
319              "PU%d,%d;PD%d,%d;\n",
320              hpgl_scale(renderer, start->x), hpgl_scale(renderer, -start->y),
321              hpgl_scale(renderer, end->x), hpgl_scale(renderer, -end->y));
322 }
323 
324 static void
draw_polyline(DiaRenderer * object,Point * points,int num_points,Color * line_colour)325 draw_polyline(DiaRenderer *object,
326 	      Point *points, int num_points,
327 	      Color *line_colour)
328 {
329     HpglRenderer *renderer = HPGL_RENDERER (object);
330     int i;
331 
332     DIAG_NOTE(g_message("draw_polyline n:%d %f,%f ...",
333               num_points, points->x, points->y));
334 
335     g_return_if_fail(1 < num_points);
336 
337     hpgl_select_pen(renderer, line_colour, 0.0);
338     fprintf (renderer->file, "PU%d,%d;PD;PA",
339              hpgl_scale(renderer, points[0].x),
340              hpgl_scale(renderer, -points[0].y));
341     /* absolute movement */
342     for (i = 1; i < num_points-1; i++)
343         fprintf(renderer->file, "%d,%d,",
344                 hpgl_scale(renderer, points[i].x),
345                 hpgl_scale(renderer, -points[i].y));
346     i = num_points - 1;
347     fprintf(renderer->file, "%d,%d;\n",
348             hpgl_scale(renderer, points[i].x),
349             hpgl_scale(renderer, -points[i].y));
350 }
351 
352 static void
draw_polygon(DiaRenderer * object,Point * points,int num_points,Color * line_colour)353 draw_polygon(DiaRenderer *object,
354 	     Point *points, int num_points,
355 	     Color *line_colour)
356 {
357     DIAG_NOTE(g_message("draw_polygon n:%d %f,%f ...",
358               num_points, points->x, points->y));
359     draw_polyline(object,points,num_points,line_colour);
360     /* last to first */
361     draw_line(object, &points[num_points-1], &points[0], line_colour);
362 }
363 
364 static void
fill_polygon(DiaRenderer * object,Point * points,int num_points,Color * colour)365 fill_polygon(DiaRenderer *object,
366 	     Point *points, int num_points,
367 	     Color *colour)
368 {
369     DIAG_NOTE(g_message("fill_polygon n:%d %f,%f ...",
370               num_points, points->x, points->y));
371     draw_polyline(object,points,num_points,colour);
372 }
373 
374 static void
draw_rect(DiaRenderer * object,Point * ul_corner,Point * lr_corner,Color * colour)375 draw_rect(DiaRenderer *object,
376 	  Point *ul_corner, Point *lr_corner,
377 	  Color *colour)
378 {
379     HpglRenderer *renderer = HPGL_RENDERER (object);
380 
381     DIAG_NOTE(g_message("draw_rect %f,%f -> %f,%f",
382               ul_corner->x, ul_corner->y, lr_corner->x, lr_corner->y));
383     hpgl_select_pen(renderer, colour, 0.0);
384     fprintf (renderer->file, "PU%d,%d;PD;EA%d,%d;\n",
385              hpgl_scale(renderer, ul_corner->x),
386              hpgl_scale(renderer, -ul_corner->y),
387              hpgl_scale(renderer, lr_corner->x),
388              hpgl_scale(renderer, -lr_corner->y));
389 }
390 
391 static void
fill_rect(DiaRenderer * object,Point * ul_corner,Point * lr_corner,Color * colour)392 fill_rect(DiaRenderer *object,
393 	  Point *ul_corner, Point *lr_corner,
394 	  Color *colour)
395 {
396     DIAG_NOTE(g_message("fill_rect %f,%f -> %f,%f",
397               ul_corner->x, ul_corner->y, lr_corner->x, lr_corner->y));
398 #if 0
399     HpglRenderer *renderer = HPGL_RENDERER (object);
400 
401     hpgl_select_pen(renderer, colour, 0.0);
402     fprintf (renderer->file, "PU%d,%d;PD;RA%d,%d;\n",
403              hpgl_scale(renderer, ul_corner->x),
404              hpgl_scale(renderer, -ul_corner->y),
405              hpgl_scale(renderer, lr_corner->x),
406              hpgl_scale(renderer, -lr_corner->y));
407 #else
408     /* the fill modes aren't really compatible ... */
409    draw_rect(object, ul_corner, lr_corner, colour);
410 #endif
411 }
412 
413 static void
draw_arc(DiaRenderer * object,Point * center,real width,real height,real angle1,real angle2,Color * colour)414 draw_arc(DiaRenderer *object,
415 	 Point *center,
416 	 real width, real height,
417 	 real angle1, real angle2,
418 	 Color *colour)
419 {
420     HpglRenderer *renderer = HPGL_RENDERER (object);
421     Point start;
422 
423     DIAG_NOTE(g_message("draw_arc %fx%f <%f,<%f",
424               width, height, angle1, angle2));
425     hpgl_select_pen(renderer, colour, 0.0);
426 
427     /* move to start point */
428     start.x = center->x + (width / 2.0)  * cos((M_PI / 180.0) * angle1);
429     start.y = - center->y + (height / 2.0) * sin((M_PI / 180.0) * angle1);
430     fprintf (renderer->file, "PU%d,%d;PD;",
431              hpgl_scale(renderer, start.x),
432              hpgl_scale(renderer, start.y));
433     /* Arc Absolute - around center */
434     fprintf (renderer->file, "AA%d,%d,%d;",
435              hpgl_scale(renderer, center->x),
436              hpgl_scale(renderer, - center->y),
437              (int)floor(360.0 - angle1 + angle2));
438 }
439 
440 static void
fill_arc(DiaRenderer * object,Point * center,real width,real height,real angle1,real angle2,Color * colour)441 fill_arc(DiaRenderer *object,
442 	 Point *center,
443 	 real width, real height,
444 	 real angle1, real angle2,
445 	 Color *colour)
446 {
447     HpglRenderer *renderer = HPGL_RENDERER (object);
448 
449     DIAG_NOTE(g_message("fill_arc %fx%f <%f,<%f",
450               width, height, angle1, angle2));
451     g_assert (width == height);
452 
453     /* move to center */
454     fprintf (renderer->file, "PU%d,%d;PD;",
455              hpgl_scale(renderer, center->x),
456              hpgl_scale(renderer, -center->y));
457     /* Edge Wedge */
458     fprintf (renderer->file, "EW%d,%d,%d;",
459              hpgl_scale(renderer, width),
460              (int)angle1, (int)(angle2-angle1));
461 }
462 
463 /* may go into lib/diarenderer.c if another renderer would be interested */
464 /* Draw an ellipse approximation consisting out of
465  * four arcs.
466  */
467 static void
draw_ellipse_by_arc(DiaRenderer * renderer,Point * center,real width,real height,Color * colour)468 draw_ellipse_by_arc (DiaRenderer *renderer,
469                      Point *center,
470                      real width, real height,
471                      Color *colour)
472 {
473   real a, b, e, d, alpha, c, x, y;
474   real g, gamma, r;
475   Point pt;
476   real angle;
477 
478   a = width / 2;
479   b = height / 2;
480   e = sqrt(a*a - b*b);
481 
482   alpha = 0.25*M_PI - dia_asin((e/a) * sin(0.75*M_PI));
483   d = 2*a*sin(alpha);
484 
485   c = (sin(0.25*M_PI) * (2*e + d)) / sin(0.75*M_PI - alpha);
486 
487   y = c * sin (alpha);
488   x = c * cos (alpha) - e;
489 
490   /* draw arcs */
491   g = sqrt((a-x)*(a-x) + y*y);
492   gamma = dia_acos((a-x)/g);
493   r = (sin(gamma) * g) / sin(M_PI-2*gamma);
494 
495   pt.y = center->y;
496   angle = (180 * (M_PI-2*gamma)) / M_PI;
497   pt.x = center->x + a - r; /* right */
498   draw_arc(renderer, &pt, 2*r, 2*r, 360-angle, angle, colour);
499   pt.x = center->x - a + r; /* left */
500   draw_arc(renderer, &pt, 2*r, 2*r, 180-angle, 180+angle, colour);
501 
502 
503   g = sqrt((b-y)*(b-y) + x*x);
504   gamma = dia_acos((b-y)/g);
505   r = (sin(gamma) * g) / sin(M_PI-2*gamma);
506 
507   pt.x = center->x;
508   angle = (180 * (M_PI-2*gamma)) / M_PI;
509   pt.y = center->y - b + r; /* top */
510   draw_arc(renderer, &pt, 2*r, 2*r, 90-angle, 90+angle, colour);
511   pt.y = center->y + b - r; /* bottom */
512   draw_arc(renderer, &pt, 2*r, 2*r, 270-angle, 270+angle, colour);
513 }
514 
515 static void
draw_ellipse(DiaRenderer * object,Point * center,real width,real height,Color * colour)516 draw_ellipse(DiaRenderer *object,
517 	     Point *center,
518 	     real width, real height,
519 	     Color *colour)
520 {
521   HpglRenderer *renderer = HPGL_RENDERER (object);
522 
523   DIAG_NOTE(g_message("draw_ellipse %fx%f center @ %f,%f",
524             width, height, center->x, center->y));
525 
526   if (width != height)
527     {
528       draw_ellipse_by_arc(object, center, width, height, colour);
529     }
530   else
531     {
532       hpgl_select_pen(renderer, colour, 0.0);
533 
534       fprintf (renderer->file, "PU%d,%d;CI%d;\n",
535                hpgl_scale(renderer, center->x),
536                hpgl_scale(renderer, -center->y),
537                hpgl_scale(renderer, width / 2.0));
538     }
539 }
540 
541 static void
fill_ellipse(DiaRenderer * object,Point * center,real width,real height,Color * colour)542 fill_ellipse(DiaRenderer *object,
543 	     Point *center,
544 	     real width, real height,
545 	     Color *colour)
546 {
547     DIAG_NOTE(g_message("fill_ellipse %fx%f center @ %f,%f",
548               width, height, center->x, center->y));
549 }
550 
551 static void
draw_string(DiaRenderer * object,const char * text,Point * pos,Alignment alignment,Color * colour)552 draw_string(DiaRenderer *object,
553 	    const char *text,
554 	    Point *pos, Alignment alignment,
555 	    Color *colour)
556 {
557     HpglRenderer *renderer = HPGL_RENDERER (object);
558     real width, height;
559 
560     DIAG_NOTE(g_message("draw_string %f,%f %s",
561               pos->x, pos->y, text));
562 
563     /* set position */
564     fprintf(renderer->file, "PU%d,%d;",
565             hpgl_scale(renderer, pos->x), hpgl_scale(renderer, -pos->y));
566 
567     switch (alignment) {
568     case ALIGN_LEFT:
569         fprintf (renderer->file, "LO1;\n");
570 	break;
571     case ALIGN_CENTER:
572         fprintf (renderer->file, "LO4;\n");
573 	break;
574     case ALIGN_RIGHT:
575         fprintf (renderer->file, "LO7;\n");
576 	break;
577     }
578     hpgl_select_pen(renderer,colour,0.0);
579 
580 #if 0
581     /*
582      * SR - Relative Character Size >0.0 ... 127.999
583      *    set the capital letter box width and height as a percentage of
584      *    P2X-P1X  and P2Y-P1Y
585      */
586     height = (127.999 * renderer->font_height * renderer->scale) / renderer->size.y;
587     width  = 0.75 * height; /* FIXME: */
588     fprintf(renderer->file, "SR%d.%03d,%d.%03d;",
589             (int)width, (int)((width * 1000) % 1000),
590             (int)height, (int)((height * 1000) % 1000));
591 #else
592     /*
593      * SI - character size absolute
594      *    size needed in centimeters
595      */
596     width = renderer->font_height * renderer->scale * 0.75 * 0.0025;
597     height = renderer->font_height * renderer->scale * 0.0025;
598     fprintf(renderer->file, "SI%d.%03d,%d.%03d;",
599             (int)width, ((int)(width * 1000) % 1000),
600             (int)height, ((int)(height * 1000) % 1000));
601 #endif
602     fprintf(renderer->file, "DT\003;" /* Terminator */
603             "LB%s\003;\n", text);
604 }
605 
606 static void
draw_image(DiaRenderer * object,Point * point,real width,real height,DiaImage * image)607 draw_image(DiaRenderer *object,
608 	   Point *point,
609 	   real width, real height,
610 	   DiaImage *image)
611 {
612     DIAG_NOTE(g_message("draw_image %fx%f @%f,%f",
613               width, height, point->x, point->y));
614     g_warning("HPGL: images unsupported!");
615 }
616 
617 /* overwrite vtable */
618 static void hpgl_renderer_class_init (HpglRendererClass *klass);
619 
620 static gpointer parent_class = NULL;
621 
622 GType
hpgl_renderer_get_type(void)623 hpgl_renderer_get_type (void)
624 {
625   static GType object_type = 0;
626 
627   if (!object_type)
628     {
629       static const GTypeInfo object_info =
630       {
631         sizeof (HpglRendererClass),
632         (GBaseInitFunc) NULL,
633         (GBaseFinalizeFunc) NULL,
634         (GClassInitFunc) hpgl_renderer_class_init,
635         NULL,           /* class_finalize */
636         NULL,           /* class_data */
637         sizeof (HpglRenderer),
638         0,              /* n_preallocs */
639 	NULL            /* init */
640       };
641 
642       object_type = g_type_register_static (DIA_TYPE_RENDERER,
643                                             "HpglRenderer",
644                                             &object_info, 0);
645     }
646 
647   return object_type;
648 }
649 
650 static void
hpgl_renderer_finalize(GObject * object)651 hpgl_renderer_finalize (GObject *object)
652 {
653   G_OBJECT_CLASS (parent_class)->finalize (object);
654 }
655 
656 static void
hpgl_renderer_class_init(HpglRendererClass * klass)657 hpgl_renderer_class_init (HpglRendererClass *klass)
658 {
659   GObjectClass *object_class = G_OBJECT_CLASS (klass);
660   DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
661 
662   parent_class = g_type_class_peek_parent (klass);
663 
664   object_class->finalize = hpgl_renderer_finalize;
665 
666   /* renderer members */
667   renderer_class->begin_render = begin_render;
668   renderer_class->end_render   = end_render;
669 
670   renderer_class->set_linewidth  = set_linewidth;
671   renderer_class->set_linecaps   = set_linecaps;
672   renderer_class->set_linejoin   = set_linejoin;
673   renderer_class->set_linestyle  = set_linestyle;
674   renderer_class->set_dashlength = set_dashlength;
675   renderer_class->set_fillstyle  = set_fillstyle;
676 
677   renderer_class->set_font  = set_font;
678 
679   renderer_class->draw_line    = draw_line;
680   renderer_class->fill_polygon = fill_polygon;
681   renderer_class->draw_rect    = draw_rect;
682   renderer_class->fill_rect    = fill_rect;
683   renderer_class->draw_arc     = draw_arc;
684   renderer_class->fill_arc     = fill_arc;
685   renderer_class->draw_ellipse = draw_ellipse;
686   renderer_class->fill_ellipse = fill_ellipse;
687 
688   renderer_class->draw_string  = draw_string;
689   renderer_class->draw_image   = draw_image;
690 
691   /* medium level functions */
692   renderer_class->draw_rect = draw_rect;
693   renderer_class->draw_polyline  = draw_polyline;
694   renderer_class->draw_polygon   = draw_polygon;
695 }
696 
697 /* plug-in interface : export function */
698 static void
export_data(DiagramData * data,const gchar * filename,const gchar * diafilename,void * user_data)699 export_data(DiagramData *data, const gchar *filename,
700             const gchar *diafilename, void* user_data)
701 {
702     HpglRenderer *renderer;
703     FILE *file;
704     Rectangle *extent;
705     real width, height;
706 
707     file = g_fopen(filename, "w"); /* "wb" for binary! */
708 
709     if (file == NULL) {
710 	message_error(_("Can't open output file %s: %s\n"),
711 		      dia_message_filename(filename), strerror(errno));
712 	return;
713     }
714 
715     renderer = g_object_new(HPGL_TYPE_RENDERER, NULL);
716 
717     renderer->file = file;
718 
719     extent = &data->extents;
720 
721     /* use extents */
722     DIAG_NOTE(g_message("export_data extents %f,%f -> %f,%f",
723               extent->left, extent->top, extent->right, extent->bottom));
724 
725     width  = extent->right - extent->left;
726     height = extent->bottom - extent->top;
727     renderer->scale = 0.001;
728     if (width > height)
729         while (renderer->scale * width < 3276.7) renderer->scale *= 10.0;
730     else
731         while (renderer->scale * height < 3276.7) renderer->scale *= 10.0;
732     renderer->offset = 0.0; /* just to have one */
733 
734     renderer->size.x = width * renderer->scale;
735     renderer->size.y = height * renderer->scale;
736 #if 0
737     /* OR: set page size and scale */
738     fprintf(renderer->file, "PS0;SC%d,%d,%d,%d;\n",
739             hpgl_scale(renderer, extent->left),
740             hpgl_scale(renderer, extent->right),
741             hpgl_scale(renderer, extent->bottom),
742             hpgl_scale(renderer, extent->top));
743 #endif
744     data_render(data, DIA_RENDERER(renderer), NULL, NULL, NULL);
745 
746     g_object_unref(renderer);
747 }
748 
749 static const gchar *extensions[] = { "plt", "hpgl", NULL };
750 static DiaExportFilter my_export_filter = {
751     N_("HP Graphics Language"),
752     extensions,
753     export_data
754 };
755 
756 
757 /* --- dia plug-in interface --- */
758 static gboolean
_plugin_can_unload(PluginInfo * info)759 _plugin_can_unload (PluginInfo *info)
760 {
761     return TRUE;
762 }
763 
764 static void
_plugin_unload(PluginInfo * info)765 _plugin_unload (PluginInfo *info)
766 {
767     filter_unregister_export(&my_export_filter);
768 }
769 
770 DIA_PLUGIN_CHECK_INIT
771 
772 PluginInitResult
dia_plugin_init(PluginInfo * info)773 dia_plugin_init(PluginInfo *info)
774 {
775     if (!dia_plugin_info_init(info, "HPGL",
776                               _("HP Graphics Language export filter"),
777 			      _plugin_can_unload,
778                               _plugin_unload))
779 	return DIA_PLUGIN_INIT_ERROR;
780 
781     filter_register_export(&my_export_filter);
782 
783     return DIA_PLUGIN_INIT_OK;
784 }
785