1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
3 *
4 * diapsrenderer.c -- implements the base class for Postscript rendering
5 * It is mostly refactoring of render_eps.c (some stuff not from the
6 * latest version but from 1.24) before PS rendering became multi-pass
7 * and text rendering became (necessary) complicated.
8 * Refatoring: Copyright (C) 2002 Hans Breuer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25 #include <config.h>
26
27 #include <string.h>
28 #include <time.h>
29
30 #include "diapsrenderer.h"
31 #include "message.h"
32 #include "dia_image.h"
33 #include "font.h"
34 #include "textline.h"
35
36 #define DTOSTR_BUF_SIZE G_ASCII_DTOSTR_BUF_SIZE
37 #define psrenderer_dtostr(buf,d) \
38 g_ascii_formatd(buf, sizeof(buf), "%f", d)
39
40 /* Returns TRUE if this file is an encapsulated postscript file
41 * (including e.g. epsi).
42 */
renderer_is_eps(DiaPsRenderer * renderer)43 static gboolean renderer_is_eps(DiaPsRenderer *renderer) {
44 return renderer->pstype == PSTYPE_EPS ||
45 renderer->pstype == PSTYPE_EPSI;
46 }
47
48 /** Returns TRUE if this file is an EPSI file */
renderer_is_epsi(DiaPsRenderer * renderer)49 static gboolean renderer_is_epsi(DiaPsRenderer *renderer) {
50 return renderer->pstype == PSTYPE_EPSI;
51 }
52
53 void
lazy_setcolor(DiaPsRenderer * renderer,Color * color)54 lazy_setcolor(DiaPsRenderer *renderer,
55 Color *color)
56 {
57 gchar r_buf[DTOSTR_BUF_SIZE];
58 gchar g_buf[DTOSTR_BUF_SIZE];
59 gchar b_buf[DTOSTR_BUF_SIZE];
60
61 if (!color_equals(color, &(renderer->lcolor))) {
62 renderer->lcolor = *color;
63 fprintf(renderer->file, "%s %s %s srgb\n",
64 psrenderer_dtostr(r_buf, (gdouble) color->red),
65 psrenderer_dtostr(g_buf, (gdouble) color->green),
66 psrenderer_dtostr(b_buf, (gdouble) color->blue) );
67 }
68 }
69
70 static void
begin_render(DiaRenderer * self)71 begin_render(DiaRenderer *self)
72 {
73 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
74 time_t time_now;
75
76 g_assert (renderer->file != NULL);
77
78 time_now = time(NULL);
79
80 if (renderer_is_eps(renderer))
81 fprintf(renderer->file,
82 "%%!PS-Adobe-2.0 EPSF-2.0\n");
83 else
84 fprintf(renderer->file,
85 "%%!PS-Adobe-2.0\n");
86 fprintf(renderer->file,
87 "%%%%Title: %s\n"
88 "%%%%Creator: Dia v%s\n"
89 "%%%%CreationDate: %s"
90 "%%%%For: %s\n"
91 "%%%%Orientation: %s\n",
92 renderer->title ? renderer->title : "(NULL)" ,
93 VERSION,
94 ctime(&time_now),
95 g_get_user_name(),
96 renderer->is_portrait ? "Portrait" : "Landscape");
97
98 if (renderer_is_epsi(renderer)) {
99 g_assert(!"Preview image not implmented");
100 /* but it *may* belong here ... */
101 }
102 if (renderer_is_eps(renderer))
103 fprintf(renderer->file,
104 "%%%%Magnification: 1.0000\n"
105 "%%%%BoundingBox: 0 0 %d %d\n",
106 (int) ceil( (renderer->extent.right - renderer->extent.left)
107 * renderer->scale),
108 (int) ceil( (renderer->extent.bottom - renderer->extent.top)
109 * renderer->scale) );
110
111 else
112 fprintf(renderer->file,
113 "%%%%DocumentPaperSizes: %s\n",
114 renderer->paper ? renderer->paper : "(NULL)");
115
116 fprintf(renderer->file,
117 "%%%%BeginSetup\n");
118 fprintf(renderer->file,
119 "%%%%EndSetup\n"
120 "%%%%EndComments\n");
121
122 DIA_PS_RENDERER_GET_CLASS(self)->begin_prolog(renderer);
123 /* get our font definitions */
124 DIA_PS_RENDERER_GET_CLASS(self)->dump_fonts(renderer);
125 /* done it */
126 DIA_PS_RENDERER_GET_CLASS(self)->end_prolog(renderer);
127 }
128
129 static void
end_render(DiaRenderer * self)130 end_render(DiaRenderer *self)
131 {
132 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
133
134 if (renderer_is_eps(renderer))
135 fprintf(renderer->file, "showpage\n");
136
137 if (self->font != NULL) {
138 dia_font_unref(self->font);
139 self->font = NULL;
140 }
141 }
142
143 static void
set_linewidth(DiaRenderer * self,real linewidth)144 set_linewidth(DiaRenderer *self, real linewidth)
145 { /* 0 == hairline **/
146 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
147 gchar lw_buf[DTOSTR_BUF_SIZE];
148
149 /* Adobe's advice: Set to very small but fixed size, to avoid changes
150 * due to different resolution output. */
151 /* .01 cm becomes <5 dots on 1200 DPI */
152 if (linewidth == 0.0) linewidth=.01;
153 fprintf(renderer->file, "%s slw\n",
154 psrenderer_dtostr(lw_buf, (gdouble) linewidth) );
155 }
156
157 static void
set_linecaps(DiaRenderer * self,LineCaps mode)158 set_linecaps(DiaRenderer *self, LineCaps mode)
159 {
160 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
161 int ps_mode;
162
163 switch(mode) {
164 case LINECAPS_BUTT:
165 ps_mode = 0;
166 break;
167 case LINECAPS_ROUND:
168 ps_mode = 1;
169 break;
170 case LINECAPS_PROJECTING:
171 ps_mode = 2;
172 break;
173 default:
174 ps_mode = 0;
175 }
176
177 fprintf(renderer->file, "%d slc\n", ps_mode);
178 }
179
180 static void
set_linejoin(DiaRenderer * self,LineJoin mode)181 set_linejoin(DiaRenderer *self, LineJoin mode)
182 {
183 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
184 int ps_mode;
185
186 switch(mode) {
187 case LINEJOIN_MITER:
188 ps_mode = 0;
189 break;
190 case LINEJOIN_ROUND:
191 ps_mode = 1;
192 break;
193 case LINEJOIN_BEVEL:
194 ps_mode = 2;
195 break;
196 default:
197 ps_mode = 0;
198 }
199
200 fprintf(renderer->file, "%d slj\n", ps_mode);
201 }
202
203 static void
set_linestyle(DiaRenderer * self,LineStyle mode)204 set_linestyle(DiaRenderer *self, LineStyle mode)
205 {
206 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
207 real hole_width;
208 gchar dashl_buf[DTOSTR_BUF_SIZE];
209 gchar dotl_buf[DTOSTR_BUF_SIZE];
210 gchar holew_buf[DTOSTR_BUF_SIZE];
211
212 renderer->saved_line_style = mode;
213
214 switch(mode) {
215 case LINESTYLE_SOLID:
216 fprintf(renderer->file, "[] 0 sd\n");
217 break;
218 case LINESTYLE_DASHED:
219 fprintf(renderer->file, "[%s] 0 sd\n",
220 psrenderer_dtostr(dashl_buf, renderer->dash_length) );
221 break;
222 case LINESTYLE_DASH_DOT:
223 hole_width = (renderer->dash_length - renderer->dot_length) / 2.0;
224 psrenderer_dtostr(holew_buf, hole_width);
225 psrenderer_dtostr(dashl_buf, renderer->dash_length);
226 psrenderer_dtostr(dotl_buf, renderer->dot_length);
227 fprintf(renderer->file, "[%s %s %s %s] 0 sd\n",
228 dashl_buf,
229 holew_buf,
230 dotl_buf,
231 holew_buf );
232 break;
233 case LINESTYLE_DASH_DOT_DOT:
234 hole_width = (renderer->dash_length - 2.0*renderer->dot_length) / 3.0;
235 psrenderer_dtostr(holew_buf, hole_width);
236 psrenderer_dtostr(dashl_buf, renderer->dash_length);
237 psrenderer_dtostr(dotl_buf, renderer->dot_length);
238 fprintf(renderer->file, "[%s %s %s %s %s %s] 0 sd\n",
239 dashl_buf,
240 holew_buf,
241 dotl_buf,
242 holew_buf,
243 dotl_buf,
244 holew_buf );
245 break;
246 case LINESTYLE_DOTTED:
247 fprintf(renderer->file, "[%s] 0 sd\n",
248 psrenderer_dtostr(dotl_buf, renderer->dot_length) );
249 break;
250 }
251 }
252
253 static void
set_dashlength(DiaRenderer * self,real length)254 set_dashlength(DiaRenderer *self, real length)
255 { /* dot = 20% of len */
256 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
257
258 if (length<0.001)
259 length = 0.001;
260
261 renderer->dash_length = length;
262 renderer->dot_length = length*0.2;
263
264 set_linestyle(self, renderer->saved_line_style);
265 }
266
267 static void
set_fillstyle(DiaRenderer * self,FillStyle mode)268 set_fillstyle(DiaRenderer *self, FillStyle mode)
269 {
270 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
271
272 switch(mode) {
273 case FILLSTYLE_SOLID:
274 break;
275 default:
276 message_error("%s : Unsupported fill mode specified!\n",
277 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
278 }
279 }
280
281 static void
set_font(DiaRenderer * self,DiaFont * font,real height)282 set_font(DiaRenderer *self, DiaFont *font, real height)
283 {
284 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
285 gchar h_buf[DTOSTR_BUF_SIZE];
286
287 if (font != self->font || height != self->font_height) {
288 DiaFont *old_font;
289
290 fprintf(renderer->file, "/%s-latin1 ff %s scf sf\n",
291 dia_font_get_psfontname(font),
292 psrenderer_dtostr(h_buf, (gdouble) height*0.7) );
293 old_font = self->font;
294 self->font = font;
295 dia_font_ref(self->font);
296 if (old_font != NULL) {
297 dia_font_unref(old_font);
298 }
299 self->font_height = height;
300 }
301 }
302
303 static void
draw_line(DiaRenderer * self,Point * start,Point * end,Color * line_color)304 draw_line(DiaRenderer *self,
305 Point *start, Point *end,
306 Color *line_color)
307 {
308 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
309 gchar sx_buf[DTOSTR_BUF_SIZE];
310 gchar sy_buf[DTOSTR_BUF_SIZE];
311 gchar ex_buf[DTOSTR_BUF_SIZE];
312 gchar ey_buf[DTOSTR_BUF_SIZE];
313
314 lazy_setcolor(renderer,line_color);
315
316 fprintf(renderer->file, "n %s %s m %s %s l s\n",
317 psrenderer_dtostr(sx_buf, start->x),
318 psrenderer_dtostr(sy_buf, start->y),
319 psrenderer_dtostr(ex_buf, end->x),
320 psrenderer_dtostr(ey_buf, end->y) );
321 }
322
323 static void
draw_polyline(DiaRenderer * self,Point * points,int num_points,Color * line_color)324 draw_polyline(DiaRenderer *self,
325 Point *points, int num_points,
326 Color *line_color)
327 {
328 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
329 int i;
330 gchar px_buf[DTOSTR_BUF_SIZE];
331 gchar py_buf[DTOSTR_BUF_SIZE];
332
333 lazy_setcolor(renderer,line_color);
334
335 fprintf(renderer->file, "n %s %s m ",
336 psrenderer_dtostr(px_buf, points[0].x),
337 psrenderer_dtostr(py_buf, points[0].y) );
338
339 for (i=1;i<num_points;i++) {
340 fprintf(renderer->file, "%s %s l ",
341 psrenderer_dtostr(px_buf, points[i].x),
342 psrenderer_dtostr(py_buf, points[i].y) );
343 }
344
345 fprintf(renderer->file, "s\n");
346 }
347
348 static void
psrenderer_polygon(DiaPsRenderer * renderer,Point * points,gint num_points,Color * line_color,gboolean filled)349 psrenderer_polygon(DiaPsRenderer *renderer,
350 Point *points,
351 gint num_points,
352 Color *line_color,
353 gboolean filled)
354 {
355 gint i;
356 gchar px_buf[DTOSTR_BUF_SIZE];
357 gchar py_buf[DTOSTR_BUF_SIZE];
358
359 lazy_setcolor(renderer, line_color);
360
361 fprintf(renderer->file, "n %s %s m ",
362 psrenderer_dtostr(px_buf, points[0].x),
363 psrenderer_dtostr(py_buf, points[0].y) );
364
365
366 for (i=1;i<num_points;i++) {
367 fprintf(renderer->file, "%s %s l ",
368 psrenderer_dtostr(px_buf, points[i].x),
369 psrenderer_dtostr(py_buf, points[i].y) );
370 }
371 if (filled)
372 fprintf(renderer->file, "ef\n");
373 else
374 fprintf(renderer->file, "cp s\n");
375 }
376
377 static void
draw_polygon(DiaRenderer * self,Point * points,int num_points,Color * line_color)378 draw_polygon(DiaRenderer *self,
379 Point *points, int num_points,
380 Color *line_color)
381 {
382 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
383 psrenderer_polygon(renderer, points, num_points, line_color, FALSE);
384 }
385
386 static void
fill_polygon(DiaRenderer * self,Point * points,int num_points,Color * fill_color)387 fill_polygon(DiaRenderer *self,
388 Point *points, int num_points,
389 Color *fill_color)
390 {
391 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
392 psrenderer_polygon(renderer, points, num_points, fill_color, TRUE);
393 }
394
395 static void
psrenderer_rect(DiaPsRenderer * renderer,Point * ul_corner,Point * lr_corner,Color * color,gboolean filled)396 psrenderer_rect(DiaPsRenderer *renderer,
397 Point *ul_corner,
398 Point *lr_corner,
399 Color *color,
400 gboolean filled)
401 {
402 gchar ulx_buf[DTOSTR_BUF_SIZE];
403 gchar uly_buf[DTOSTR_BUF_SIZE];
404 gchar lrx_buf[DTOSTR_BUF_SIZE];
405 gchar lry_buf[DTOSTR_BUF_SIZE];
406
407 lazy_setcolor(renderer,color);
408
409 psrenderer_dtostr(ulx_buf, (gdouble) ul_corner->x);
410 psrenderer_dtostr(uly_buf, (gdouble) ul_corner->y);
411 psrenderer_dtostr(lrx_buf, (gdouble) lr_corner->x);
412 psrenderer_dtostr(lry_buf, (gdouble) lr_corner->y);
413
414 fprintf(renderer->file, "n %s %s m %s %s l %s %s l %s %s l %s\n",
415 ulx_buf, uly_buf,
416 ulx_buf, lry_buf,
417 lrx_buf, lry_buf,
418 lrx_buf, uly_buf,
419 filled ? "f" : "cp s" );
420 }
421
422 static void
draw_rect(DiaRenderer * self,Point * ul_corner,Point * lr_corner,Color * color)423 draw_rect(DiaRenderer *self,
424 Point *ul_corner, Point *lr_corner,
425 Color *color)
426 {
427 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
428 psrenderer_rect(renderer, ul_corner, lr_corner, color, FALSE);
429 }
430
431 static void
fill_rect(DiaRenderer * self,Point * ul_corner,Point * lr_corner,Color * color)432 fill_rect(DiaRenderer *self,
433 Point *ul_corner, Point *lr_corner,
434 Color *color)
435 {
436 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
437 psrenderer_rect(renderer, ul_corner, lr_corner, color, TRUE);
438 }
439
440 static void
psrenderer_arc(DiaPsRenderer * renderer,Point * center,real width,real height,real angle1,real angle2,Color * color,gboolean filled)441 psrenderer_arc(DiaPsRenderer *renderer,
442 Point *center,
443 real width, real height,
444 real angle1, real angle2,
445 Color *color,
446 gboolean filled)
447 {
448 gchar cx_buf[DTOSTR_BUF_SIZE];
449 gchar cy_buf[DTOSTR_BUF_SIZE];
450 gchar a1_buf[DTOSTR_BUF_SIZE];
451 gchar a2_buf[DTOSTR_BUF_SIZE];
452 gchar w_buf[DTOSTR_BUF_SIZE];
453 gchar h_buf[DTOSTR_BUF_SIZE];
454
455 lazy_setcolor(renderer, color);
456
457 psrenderer_dtostr(cx_buf, (gdouble) center->x);
458 psrenderer_dtostr(cy_buf, (gdouble) center->y);
459 psrenderer_dtostr(a1_buf, (gdouble) 360.0 - angle1);
460 psrenderer_dtostr(a2_buf, (gdouble) 360.0 - angle2);
461 psrenderer_dtostr(w_buf, (gdouble) width / 2.0);
462 psrenderer_dtostr(h_buf, (gdouble) height / 2.0);
463
464 fprintf(renderer->file, "n ");
465
466 if (filled)
467 fprintf(renderer->file, "%s %s m ", cx_buf, cy_buf);
468
469 fprintf(renderer->file, "%s %s %s %s %s %s ellipse %s\n",
470 cx_buf, cy_buf, w_buf, h_buf, a2_buf, a1_buf,
471 filled ? "f" : "s" );
472 }
473
474
475 static void
draw_arc(DiaRenderer * self,Point * center,real width,real height,real angle1,real angle2,Color * color)476 draw_arc(DiaRenderer *self,
477 Point *center,
478 real width, real height,
479 real angle1, real angle2,
480 Color *color)
481 {
482 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
483 psrenderer_arc(renderer, center, width, height, angle1, angle2, color, FALSE);
484 }
485
486 static void
fill_arc(DiaRenderer * self,Point * center,real width,real height,real angle1,real angle2,Color * color)487 fill_arc(DiaRenderer *self,
488 Point *center,
489 real width, real height,
490 real angle1, real angle2,
491 Color *color)
492 {
493 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
494 psrenderer_arc(renderer, center, width, height, angle1, angle2, color, TRUE);
495 }
496
497 static void
psrenderer_ellipse(DiaPsRenderer * renderer,Point * center,real width,real height,Color * color,gboolean filled)498 psrenderer_ellipse(DiaPsRenderer *renderer,
499 Point *center,
500 real width, real height,
501 Color *color,
502 gboolean filled)
503 {
504 gchar cx_buf[DTOSTR_BUF_SIZE];
505 gchar cy_buf[DTOSTR_BUF_SIZE];
506 gchar w_buf[DTOSTR_BUF_SIZE];
507 gchar h_buf[DTOSTR_BUF_SIZE];
508
509 lazy_setcolor(renderer,color);
510
511 fprintf(renderer->file, "n %s %s %s %s 0 360 ellipse %s\n",
512 psrenderer_dtostr(cx_buf, (gdouble) center->x),
513 psrenderer_dtostr(cy_buf, (gdouble) center->y),
514 psrenderer_dtostr(w_buf, (gdouble) width / 2.0),
515 psrenderer_dtostr(h_buf, (gdouble) height / 2.0),
516 filled ? "f" : "cp s" );
517 }
518
519 static void
draw_ellipse(DiaRenderer * self,Point * center,real width,real height,Color * color)520 draw_ellipse(DiaRenderer *self,
521 Point *center,
522 real width, real height,
523 Color *color)
524 {
525 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
526 psrenderer_ellipse(renderer, center, width, height, color, FALSE);
527 }
528
529 static void
fill_ellipse(DiaRenderer * self,Point * center,real width,real height,Color * color)530 fill_ellipse(DiaRenderer *self,
531 Point *center,
532 real width, real height,
533 Color *color)
534 {
535 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
536 psrenderer_ellipse(renderer, center, width, height, color, TRUE);
537 }
538
539 static void
psrenderer_bezier(DiaPsRenderer * renderer,BezPoint * points,gint numpoints,Color * color,gboolean filled)540 psrenderer_bezier(DiaPsRenderer *renderer,
541 BezPoint *points,
542 gint numpoints,
543 Color *color,
544 gboolean filled)
545 {
546 gint i;
547 gchar p1x_buf[DTOSTR_BUF_SIZE];
548 gchar p1y_buf[DTOSTR_BUF_SIZE];
549 gchar p2x_buf[DTOSTR_BUF_SIZE];
550 gchar p2y_buf[DTOSTR_BUF_SIZE];
551 gchar p3x_buf[DTOSTR_BUF_SIZE];
552 gchar p3y_buf[DTOSTR_BUF_SIZE];
553
554 lazy_setcolor(renderer,color);
555
556 if (points[0].type != BEZ_MOVE_TO)
557 g_warning("first BezPoint must be a BEZ_MOVE_TO");
558
559 fprintf(renderer->file, "n %s %s m",
560 psrenderer_dtostr(p1x_buf, (gdouble) points[0].p1.x),
561 psrenderer_dtostr(p1y_buf, (gdouble) points[0].p1.y) );
562
563 for (i = 1; i < numpoints; i++)
564 switch (points[i].type) {
565 case BEZ_MOVE_TO:
566 g_warning("only first BezPoint can be a BEZ_MOVE_TO");
567 break;
568 case BEZ_LINE_TO:
569 fprintf(renderer->file, " %s %s l",
570 psrenderer_dtostr(p1x_buf, (gdouble) points[i].p1.x),
571 psrenderer_dtostr(p1y_buf, (gdouble) points[i].p1.y) );
572 break;
573 case BEZ_CURVE_TO:
574 fprintf(renderer->file, " %s %s %s %s %s %s c",
575 psrenderer_dtostr(p1x_buf, (gdouble) points[i].p1.x),
576 psrenderer_dtostr(p1y_buf, (gdouble) points[i].p1.y),
577 psrenderer_dtostr(p2x_buf, (gdouble) points[i].p2.x),
578 psrenderer_dtostr(p2y_buf, (gdouble) points[i].p2.y),
579 psrenderer_dtostr(p3x_buf, (gdouble) points[i].p3.x),
580 psrenderer_dtostr(p3y_buf, (gdouble) points[i].p3.y) );
581 break;
582 }
583
584 if (filled)
585 fprintf(renderer->file, " ef\n");
586 else
587 fprintf(renderer->file, " s\n");
588 }
589
590 static void
draw_bezier(DiaRenderer * self,BezPoint * points,int numpoints,Color * color)591 draw_bezier(DiaRenderer *self,
592 BezPoint *points,
593 int numpoints, /* numpoints = 4+3*n, n=>0 */
594 Color *color)
595 {
596 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
597 psrenderer_bezier(renderer, points, numpoints, color, FALSE);
598 }
599
600 static void
fill_bezier(DiaRenderer * self,BezPoint * points,int numpoints,Color * color)601 fill_bezier(DiaRenderer *self,
602 BezPoint *points, /* Last point must be same as first point */
603 int numpoints,
604 Color *color)
605 {
606 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
607 psrenderer_bezier(renderer, points, numpoints, color, TRUE);
608 }
609
610 static char*
ps_convert_string(const char * text)611 ps_convert_string(const char *text)
612 {
613 char *buffer;
614 gchar *localestr;
615 const gchar *str;
616 gint len;
617 GError * error = NULL;
618
619 localestr = g_convert(text, -1, "LATIN1", "UTF-8", NULL, NULL, &error);
620
621 if (localestr == NULL) {
622 message_error("Can't convert string %s: %s\n", text, error->message);
623 localestr = g_strdup(text);
624 }
625
626 /* Escape all '(' and ')': */
627 buffer = g_malloc(2*strlen(localestr)+1);
628 *buffer = 0;
629 str = localestr;
630 while (*str != 0) {
631 len = strcspn(str,"()\\");
632 strncat(buffer, str, len);
633 str += len;
634 if (*str != 0) {
635 strcat(buffer,"\\");
636 strncat(buffer, str, 1);
637 str++;
638 }
639 }
640 g_free(localestr);
641 return buffer;
642 }
643
644 static void
put_text_alignment(DiaPsRenderer * renderer,Alignment alignment,Point * pos)645 put_text_alignment (DiaPsRenderer *renderer,
646 Alignment alignment,
647 Point *pos)
648 {
649 gchar px_buf[DTOSTR_BUF_SIZE];
650 gchar py_buf[DTOSTR_BUF_SIZE];
651
652 switch (alignment) {
653 case ALIGN_LEFT:
654 fprintf(renderer->file, "%s %s m\n",
655 psrenderer_dtostr(px_buf, pos->x),
656 psrenderer_dtostr(py_buf, pos->y) );
657 break;
658 case ALIGN_CENTER:
659 fprintf(renderer->file, "dup sw 2 div %s ex sub %s m\n",
660 psrenderer_dtostr(px_buf, pos->x),
661 psrenderer_dtostr(py_buf, pos->y) );
662 break;
663 case ALIGN_RIGHT:
664 fprintf(renderer->file, "dup sw %s ex sub %s m\n",
665 psrenderer_dtostr(px_buf, pos->x),
666 psrenderer_dtostr(py_buf, pos->y) );
667 break;
668 }
669 }
670
671 static void
draw_string(DiaRenderer * self,const char * text,Point * pos,Alignment alignment,Color * color)672 draw_string(DiaRenderer *self,
673 const char *text,
674 Point *pos, Alignment alignment,
675 Color *color)
676 {
677 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
678 Point pos_adj;
679 gchar *buffer;
680
681 if (1 > strlen(text))
682 return;
683
684 lazy_setcolor(renderer,color);
685
686 buffer = ps_convert_string(text);
687
688 fprintf(renderer->file, "(%s) ", buffer);
689 g_free(buffer);
690
691 pos_adj.x = pos->x;
692 pos_adj.y = pos->y - dia_font_descent("", self->font, self->font_height);
693 put_text_alignment (renderer, alignment, &pos_adj);
694
695 fprintf(renderer->file, " gs 1 -1 sc sh gr\n");
696 }
697
698 static void
draw_image(DiaRenderer * self,Point * point,real width,real height,DiaImage * image)699 draw_image(DiaRenderer *self,
700 Point *point,
701 real width, real height,
702 DiaImage *image)
703 {
704 DiaPsRenderer *renderer = DIA_PS_RENDERER(self);
705 int img_width, img_height, img_rowstride;
706 int x, y;
707 real ratio;
708 guint8 *rgb_data;
709 guint8 *mask_data;
710 gchar d1_buf[DTOSTR_BUF_SIZE];
711 gchar d2_buf[DTOSTR_BUF_SIZE];
712
713 img_width = dia_image_width(image);
714 img_rowstride = dia_image_rowstride(image);
715 img_height = dia_image_height(image);
716
717 rgb_data = dia_image_rgb_data(image);
718 mask_data = dia_image_mask_data(image);
719
720 ratio = height/width;
721
722 fprintf(renderer->file, "gs\n");
723
724 /* color output only */
725 fprintf(renderer->file, "/pix %i string def\n", img_width * 3);
726 fprintf(renderer->file, "%i %i 8\n", img_width, img_height);
727 fprintf(renderer->file, "%s %s tr\n",
728 psrenderer_dtostr(d1_buf, point->x),
729 psrenderer_dtostr(d2_buf, point->y) );
730 fprintf(renderer->file, "%s %s sc\n",
731 psrenderer_dtostr(d1_buf, width),
732 psrenderer_dtostr(d2_buf, height) );
733 fprintf(renderer->file, "[%i 0 0 %i 0 0]\n", img_width, img_height);
734
735 fprintf(renderer->file, "{currentfile pix readhexstring pop}\n");
736 fprintf(renderer->file, "false 3 colorimage\n");
737 fprintf(renderer->file, "\n");
738
739 if (mask_data) {
740 for (y = 0; y < img_height; y++) {
741 for (x = 0; x < img_width; x++) {
742 int i = y*img_rowstride+x*3;
743 int m = y*img_width+x;
744 fprintf(renderer->file, "%02x", 255-(mask_data[m]*(255-rgb_data[i])/255));
745 fprintf(renderer->file, "%02x", 255-(mask_data[m]*(255-rgb_data[i+1])/255));
746 fprintf(renderer->file, "%02x", 255-(mask_data[m]*(255-rgb_data[i+2])/255));
747 }
748 fprintf(renderer->file, "\n");
749 }
750 } else {
751 for (y = 0; y < img_height; y++) {
752 for (x = 0; x < img_width; x++) {
753 int i = y*img_rowstride+x*3;
754 fprintf(renderer->file, "%02x", (int)(rgb_data[i]));
755 fprintf(renderer->file, "%02x", (int)(rgb_data[i+1]));
756 fprintf(renderer->file, "%02x", (int)(rgb_data[i+2]));
757 }
758 fprintf(renderer->file, "\n");
759 }
760 }
761 fprintf(renderer->file, "gr\n");
762 fprintf(renderer->file, "\n");
763
764 g_free(rgb_data);
765 g_free(mask_data);
766 }
767
768 static void
begin_prolog(DiaPsRenderer * renderer)769 begin_prolog (DiaPsRenderer *renderer)
770 {
771 g_assert(renderer->file != NULL);
772
773 fprintf(renderer->file, "%%%%BeginProlog\n");
774 fprintf(renderer->file,
775 "[ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
776 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
777 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
778 "/.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
779 "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one\n"
780 "/two /three /four /five /six /seven /eight /nine /colon /semicolon\n"
781 "/less /equal /greater /question /at /A /B /C /D /E\n"
782 "/F /G /H /I /J /K /L /M /N /O\n"
783 "/P /Q /R /S /T /U /V /W /X /Y\n"
784 "/Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c\n"
785 "/d /e /f /g /h /i /j /k /l /m\n"
786 "/n /o /p /q /r /s /t /u /v /w\n"
787 "/x /y /z /braceleft /bar /braceright /asciitilde /.notdef /.notdef /.notdef\n"
788 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
789 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
790 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
791 "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright\n"
792 "/ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior\n"
793 "/acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf\n"
794 "/threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
795 "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde\n"
796 "/Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex\n"
797 "/Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring\n"
798 "/ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
799 "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave\n"
800 "/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] /isolatin1encoding exch def\n");
801
802 fprintf(renderer->file,
803 "/cp {closepath} bind def\n"
804 "/c {curveto} bind def\n"
805 "/f {fill} bind def\n"
806 "/a {arc} bind def\n"
807 "/ef {eofill} bind def\n"
808 "/ex {exch} bind def\n"
809 "/gr {grestore} bind def\n"
810 "/gs {gsave} bind def\n"
811 "/sa {save} bind def\n"
812 "/rs {restore} bind def\n"
813 "/l {lineto} bind def\n"
814 "/m {moveto} bind def\n"
815 "/rm {rmoveto} bind def\n"
816 "/n {newpath} bind def\n"
817 "/s {stroke} bind def\n"
818 "/sh {show} bind def\n"
819 "/slc {setlinecap} bind def\n"
820 "/slj {setlinejoin} bind def\n"
821 "/slw {setlinewidth} bind def\n"
822 "/srgb {setrgbcolor} bind def\n"
823 "/rot {rotate} bind def\n"
824 "/sc {scale} bind def\n"
825 "/sd {setdash} bind def\n"
826 "/ff {findfont} bind def\n"
827 "/sf {setfont} bind def\n"
828 "/scf {scalefont} bind def\n"
829 "/sw {stringwidth pop} bind def\n"
830 "/tr {translate} bind def\n"
831
832 "\n/ellipsedict 8 dict def\n"
833 "ellipsedict /mtrx matrix put\n"
834 "/ellipse\n"
835 "{ ellipsedict begin\n"
836 " /endangle exch def\n"
837 " /startangle exch def\n"
838 " /yrad exch def\n"
839 " /xrad exch def\n"
840 " /y exch def\n"
841 " /x exch def"
842 " /savematrix mtrx currentmatrix def\n"
843 " x y tr xrad yrad sc\n"
844 " 0 0 1 startangle endangle arc\n"
845 " savematrix setmatrix\n"
846 " end\n"
847 "} def\n\n"
848 "/mergeprocs {\n"
849 "dup length\n"
850 "3 -1 roll\n"
851 "dup\n"
852 "length\n"
853 "dup\n"
854 "5 1 roll\n"
855 "3 -1 roll\n"
856 "add\n"
857 "array cvx\n"
858 "dup\n"
859 "3 -1 roll\n"
860 "0 exch\n"
861 "putinterval\n"
862 "dup\n"
863 "4 2 roll\n"
864 "putinterval\n"
865 "} bind def\n");
866
867 }
868
869 /* helper function */
870 static void
print_reencode_font(FILE * file,char * fontname)871 print_reencode_font(FILE *file, char *fontname)
872 {
873 /* Don't reencode the Symbol font, as it doesn't work in latin1 encoding.
874 * Instead, just define Symbol-latin1 to be the same as Symbol. */
875 if (!strcmp(fontname, "Symbol"))
876 fprintf(file,
877 "/%s-latin1\n"
878 " /%s findfont\n"
879 "definefont pop\n", fontname, fontname);
880 else
881 fprintf(file,
882 "/%s-latin1\n"
883 " /%s findfont\n"
884 " dup length dict begin\n"
885 " {1 index /FID ne {def} {pop pop} ifelse} forall\n"
886 " /Encoding isolatin1encoding def\n"
887 " currentdict end\n"
888 "definefont pop\n", fontname, fontname);
889 }
890
891 static void
dump_fonts(DiaPsRenderer * renderer)892 dump_fonts (DiaPsRenderer *renderer)
893 {
894 print_reencode_font(renderer->file, "Times-Roman");
895 print_reencode_font(renderer->file, "Times-Italic");
896 print_reencode_font(renderer->file, "Times-Bold");
897 print_reencode_font(renderer->file, "Times-BoldItalic");
898 print_reencode_font(renderer->file, "AvantGarde-Gothic");
899 print_reencode_font(renderer->file, "AvantGarde-BookOblique");
900 print_reencode_font(renderer->file, "AvantGarde-Demi");
901 print_reencode_font(renderer->file, "AvantGarde-DemiOblique");
902 print_reencode_font(renderer->file, "Bookman-Light");
903 print_reencode_font(renderer->file, "Bookman-LightItalic");
904 print_reencode_font(renderer->file, "Bookman-Demi");
905 print_reencode_font(renderer->file, "Bookman-DemiItalic");
906 print_reencode_font(renderer->file, "Courier");
907 print_reencode_font(renderer->file, "Courier-Oblique");
908 print_reencode_font(renderer->file, "Courier-Bold");
909 print_reencode_font(renderer->file, "Courier-BoldOblique");
910 print_reencode_font(renderer->file, "Helvetica");
911 print_reencode_font(renderer->file, "Helvetica-Oblique");
912 print_reencode_font(renderer->file, "Helvetica-Bold");
913 print_reencode_font(renderer->file, "Helvetica-BoldOblique");
914 print_reencode_font(renderer->file, "Helvetica-Narrow");
915 print_reencode_font(renderer->file, "Helvetica-Narrow-Oblique");
916 print_reencode_font(renderer->file, "Helvetica-Narrow-Bold");
917 print_reencode_font(renderer->file, "Helvetica-Narrow-BoldOblique");
918 print_reencode_font(renderer->file, "NewCenturySchlbk-Roman");
919 print_reencode_font(renderer->file, "NewCenturySchlbk-Italic");
920 print_reencode_font(renderer->file, "NewCenturySchlbk-Bold");
921 print_reencode_font(renderer->file, "NewCenturySchlbk-BoldItalic");
922 print_reencode_font(renderer->file, "Palatino-Roman");
923 print_reencode_font(renderer->file, "Palatino-Italic");
924 print_reencode_font(renderer->file, "Palatino-Bold");
925 print_reencode_font(renderer->file, "Palatino-BoldItalic");
926 print_reencode_font(renderer->file, "Symbol");
927 print_reencode_font(renderer->file, "ZapfChancery-MediumItalic");
928 print_reencode_font(renderer->file, "ZapfDingbats");
929 }
930
931 static void
end_prolog(DiaPsRenderer * renderer)932 end_prolog (DiaPsRenderer *renderer)
933 {
934 gchar d1_buf[DTOSTR_BUF_SIZE];
935 gchar d2_buf[DTOSTR_BUF_SIZE];
936
937 if (renderer_is_eps(renderer)) {
938 fprintf(renderer->file,
939 "%s %s scale\n",
940 psrenderer_dtostr(d1_buf, renderer->scale),
941 psrenderer_dtostr(d2_buf, -renderer->scale) );
942 fprintf(renderer->file,
943 "%s %s translate\n",
944 psrenderer_dtostr(d1_buf, -renderer->extent.left),
945 psrenderer_dtostr(d2_buf, -renderer->extent.bottom) );
946 } else {
947 /* done by BoundingBox above */
948 }
949
950 fprintf(renderer->file,
951 "%%%%EndProlog\n\n\n");
952 }
953
954 /* constructor */
955 static void
ps_renderer_init(GTypeInstance * instance,gpointer g_class)956 ps_renderer_init (GTypeInstance *instance, gpointer g_class)
957 {
958 DiaPsRenderer *renderer = DIA_PS_RENDERER (instance);
959
960 renderer->file = NULL;
961
962 renderer->lcolor.red = -1.0;
963
964 renderer->dash_length = 1.0;
965 renderer->dot_length = 0.2;
966 renderer->saved_line_style = LINESTYLE_SOLID;
967 renderer->is_portrait = TRUE;
968
969 renderer->scale = 28.346;
970 }
971
972 /* GObject stuff */
973 static void dia_ps_renderer_class_init (DiaPsRendererClass *klass);
974
975 static gpointer parent_class = NULL;
976
977 GType
dia_ps_renderer_get_type(void)978 dia_ps_renderer_get_type (void)
979 {
980 static GType object_type = 0;
981
982 if (!object_type)
983 {
984 static const GTypeInfo object_info =
985 {
986 sizeof (DiaPsRendererClass),
987 (GBaseInitFunc) NULL,
988 (GBaseFinalizeFunc) NULL,
989 (GClassInitFunc) dia_ps_renderer_class_init,
990 NULL, /* class_finalize */
991 NULL, /* class_data */
992 sizeof (DiaPsRenderer),
993 0, /* n_preallocs */
994 ps_renderer_init /* init */
995 };
996
997 object_type = g_type_register_static (DIA_TYPE_RENDERER,
998 "DiaPsRenderer",
999 &object_info, 0);
1000 }
1001
1002 return object_type;
1003 }
1004
1005 static void
dia_ps_renderer_finalize(GObject * object)1006 dia_ps_renderer_finalize (GObject *object)
1007 {
1008 DiaPsRenderer *renderer = DIA_PS_RENDERER (object);
1009
1010 g_free(renderer->title);
1011 /* fclose(renderer->file);*/
1012
1013 G_OBJECT_CLASS (parent_class)->finalize (object);
1014 }
1015
1016 static void
dia_ps_renderer_class_init(DiaPsRendererClass * klass)1017 dia_ps_renderer_class_init (DiaPsRendererClass *klass)
1018 {
1019 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1020 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
1021 DiaPsRendererClass *ps_renderer_class = DIA_PS_RENDERER_CLASS (klass);
1022
1023 parent_class = g_type_class_peek_parent (klass);
1024
1025 object_class->finalize = dia_ps_renderer_finalize;
1026
1027 renderer_class->begin_render = begin_render;
1028 renderer_class->end_render = end_render;
1029
1030 renderer_class->set_linewidth = set_linewidth;
1031 renderer_class->set_linecaps = set_linecaps;
1032 renderer_class->set_linejoin = set_linejoin;
1033 renderer_class->set_linestyle = set_linestyle;
1034 renderer_class->set_dashlength = set_dashlength;
1035 renderer_class->set_fillstyle = set_fillstyle;
1036 renderer_class->set_font = set_font;
1037
1038 renderer_class->draw_line = draw_line;
1039 renderer_class->fill_polygon = fill_polygon;
1040 renderer_class->draw_arc = draw_arc;
1041 renderer_class->fill_arc = fill_arc;
1042 renderer_class->draw_ellipse = draw_ellipse;
1043 renderer_class->fill_ellipse = fill_ellipse;
1044 renderer_class->draw_string = draw_string;
1045 renderer_class->draw_image = draw_image;
1046
1047 /* medium level functions */
1048 renderer_class->draw_bezier = draw_bezier;
1049 renderer_class->fill_bezier = fill_bezier;
1050 renderer_class->draw_rect = draw_rect;
1051 renderer_class->fill_rect = fill_rect;
1052 renderer_class->draw_polyline = draw_polyline;
1053 renderer_class->draw_polygon = draw_polygon;
1054
1055 /* ps specific */
1056 ps_renderer_class->begin_prolog = begin_prolog;
1057 ps_renderer_class->dump_fonts = dump_fonts;
1058 ps_renderer_class->end_prolog = end_prolog;
1059 }
1060
1061