1 /* gtkplotps - postscript driver
2  * Copyright 1999-2001  Adrian E. Feiguin <feiguin@ifir.edu.ar>
3  *
4  * Some few lines of code borrowed from
5  * DiaCanvas -- a technical canvas widget
6  * Copyright (C) 1999 Arjan Molenaar
7  * Dia -- an diagram creation/manipulation program
8  * Copyright (C) 1998 Alexander Larsson
9  * ISO Latin encoding by
10  * Przemek Klosowski
11  * przemek@rrdbartok.nist.gov
12  * (borrowed from XMGR)
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Library General Public
16  * License as published by the Free Software Foundation; either
17  * version 2 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public
25  * License along with this library; if not, write to the
26  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27  * Boston, MA 02111-1307, USA.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34 #include <ctype.h>
35 #include <time.h>
36 #include <gtk/gtk.h>
37 #include <locale.h>
38 
39 #include "gtkplot.h"
40 #include "gtkpsfont.h"
41 #include "gtkplotpc.h"
42 #include "gtkplotps.h"
43 
44 
45 static void gtk_plot_ps_class_init 		(GtkPlotPSClass *klass);
46 static void gtk_plot_ps_init 			(GtkPlotPS *ps);
47 static void gtk_plot_ps_destroy 		(GtkObject *object);
48 /*********************************************************************/
49 /* Postscript specific functions */
50 static gboolean psinit				(GtkPlotPC *pc);
51 static void pssetviewport			(GtkPlotPC *pc,
52 						 gdouble w, gdouble h);
53 static void psleave				(GtkPlotPC *pc);
54 static void psgsave				(GtkPlotPC *pc);
55 static void psgrestore				(GtkPlotPC *pc);
56 static void psclip				(GtkPlotPC *pc,
57 						 const GdkRectangle *area);
58 static void psclipmask				(GtkPlotPC *pc,
59 						 gdouble x, gdouble y,
60 						 const GdkBitmap *mask);
61 static void psdrawlines				(GtkPlotPC *pc,
62 						 GtkPlotPoint *points,
63 						 gint numpoints);
64 static void psdrawpoint				(GtkPlotPC *pc,
65                 				 gdouble x, gdouble y);
66 static void psdrawline				(GtkPlotPC *pc,
67 						 gdouble x0, gdouble y0,
68 						 gdouble xf, gdouble yf);
69 static void psdrawpolygon			(GtkPlotPC *pc,
70 						 gboolean filled,
71 						 GtkPlotPoint *points,
72 						 gint numpoints);
73 static void psdrawrectangle			(GtkPlotPC *pc,
74 						 gboolean filled,
75                 				 gdouble x, gdouble y,
76 						 gdouble width, gdouble height);
77 static void psdrawcircle			(GtkPlotPC *pc,
78 						 gboolean filled,
79                                                  gdouble x, gdouble y,
80 						 gdouble size);
81 static void psdrawellipse			(GtkPlotPC *pc,
82               					 gboolean filled,
83 						 gdouble x, gdouble y,
84 						 gdouble width, gdouble height);
85 static void pssetcolor				(GtkPlotPC *pc,
86 						 const GdkColor *color);
87 static void pssetlineattr			(GtkPlotPC *pc,
88                                                  gfloat line_width,
89                                                  GdkLineStyle line_style,
90                                                  GdkCapStyle cap_style,
91                                                  GdkJoinStyle join_style);
92 static void psdrawstring			(GtkPlotPC *pc,
93              					 gint x, gint y,
94                                                  gint angle,
95                                                  const GdkColor *fg,
96                                                  const GdkColor *bg,
97                                                  gboolean transparent,
98                                                  gint border,
99                                                  gint border_space,
100                                                  gint border_width,
101                                                  gint shadow_width,
102                                                  const gchar *font,
103                                                  gint height,
104                                                  GtkJustification just,
105                                                  const gchar *text);
106 static void pssetfont				(GtkPlotPC *pc,
107 						 GtkPSFont *psfont,
108 						 gint height);
109 static void pssetdash				(GtkPlotPC *pc,
110 						 gdouble offset,
111 						 gdouble *values,
112 						 gint num_values);
113 static void psdrawpixmap                        (GtkPlotPC *pc,
114                                                  GdkPixmap *pixmap,
115                                                  GdkBitmap *mask,
116                                                  gint xsrc, gint ysrc,
117                                                  gint xdest, gint ydest,
118                                                  gint width, gint height,
119                                                  gdouble sx, gdouble sy);
120 
121 static void ps_reencode_font			(FILE *file, char *fontname);
122 static void color_to_hex                        (GdkColor color,
123                                                  gchar string[7]);
124 
125 /*********************************************************************/
126 static GtkPlotPCClass *parent_class = NULL;
127 static gchar *locale = NULL;
128 
129 GtkType
gtk_plot_ps_get_type(void)130 gtk_plot_ps_get_type (void)
131 {
132   static GtkType pc_type = 0;
133 
134   if (!pc_type)
135     {
136       GtkTypeInfo pc_info =
137       {
138         "GtkPlotPS",
139         sizeof (GtkPlotPS),
140         sizeof (GtkPlotPSClass),
141         (GtkClassInitFunc) gtk_plot_ps_class_init,
142         (GtkObjectInitFunc) gtk_plot_ps_init,
143         /* reserved 1*/ NULL,
144         /* reserved 2 */ NULL,
145         (GtkClassInitFunc) NULL,
146       };
147 
148       pc_type = gtk_type_unique (GTK_TYPE_PLOT_PC, &pc_info);
149     }
150   return pc_type;
151 }
152 
153 static void
gtk_plot_ps_init(GtkPlotPS * ps)154 gtk_plot_ps_init (GtkPlotPS *ps)
155 {
156   ps->psname = NULL;
157   ps->gsaved = FALSE;
158   GTK_PLOT_PC(ps)->use_pixmap = FALSE;
159 }
160 
161 
162 static void
gtk_plot_ps_class_init(GtkPlotPSClass * klass)163 gtk_plot_ps_class_init (GtkPlotPSClass *klass)
164 {
165   GtkObjectClass *object_class;
166   GObjectClass *gobject_class;
167   GtkPlotPCClass *pc_class;
168 
169   parent_class = gtk_type_class (gtk_plot_pc_get_type ());
170 
171   object_class = (GtkObjectClass *) klass;
172   gobject_class = (GObjectClass *) klass;
173   pc_class = (GtkPlotPCClass *) klass;
174 
175   pc_class->init = psinit;
176   pc_class->leave = psleave;
177   pc_class->set_viewport = pssetviewport;
178   pc_class->gsave = psgsave;
179   pc_class->grestore = psgrestore;
180   pc_class->clip = psclip;
181   pc_class->clip_mask = psclipmask;
182   pc_class->set_color = pssetcolor;
183   pc_class->set_dash = pssetdash;
184   pc_class->set_lineattr = pssetlineattr;
185   pc_class->draw_point = psdrawpoint;
186   pc_class->draw_line = psdrawline;
187   pc_class->draw_lines = psdrawlines;
188   pc_class->draw_rectangle = psdrawrectangle;
189   pc_class->draw_polygon = psdrawpolygon;
190   pc_class->draw_circle = psdrawcircle;
191   pc_class->draw_ellipse = psdrawellipse;
192   pc_class->set_font = pssetfont;
193   pc_class->draw_string = psdrawstring;
194   pc_class->draw_pixmap = psdrawpixmap;
195 
196   object_class->destroy = gtk_plot_ps_destroy;
197 }
198 
199 static void
gtk_plot_ps_destroy(GtkObject * object)200 gtk_plot_ps_destroy(GtkObject *object)
201 {
202   GtkPlotPS *ps;
203 
204   ps = GTK_PLOT_PS(object);
205 
206   if(ps->psname){
207     g_free(ps->psname);
208     ps->psname = NULL;
209   }
210 }
211 
212 GtkObject *
gtk_plot_ps_new(const gchar * psname,gint orientation,gint epsflag,gint page_size,gdouble scalex,gdouble scaley)213 gtk_plot_ps_new                         (const gchar *psname,
214                                          gint orientation,
215                                          gint epsflag,
216                                          gint page_size,
217                                          gdouble scalex,
218 					 gdouble scaley)
219 {
220   GtkObject *object;
221   GtkPlotPS *ps;
222 
223   object = gtk_type_new(gtk_plot_ps_get_type());
224 
225   ps = GTK_PLOT_PS(object);
226 
227   gtk_plot_ps_construct(ps, psname, orientation, epsflag, page_size, scalex, scaley);
228 
229   return (object);
230 }
231 
232 void
gtk_plot_ps_construct(GtkPlotPS * ps,const gchar * psname,gint orientation,gint epsflag,gint page_size,gdouble scalex,gdouble scaley)233 gtk_plot_ps_construct                   (GtkPlotPS *ps,
234 					 const gchar *psname,
235                                          gint orientation,
236                                          gint epsflag,
237                                          gint page_size,
238                                          gdouble scalex,
239 					 gdouble scaley)
240 {
241   gint width, height;
242 
243   ps->psname = g_strdup(psname);
244   ps->orientation = orientation;
245   ps->epsflag = epsflag;
246   ps->page_size = page_size;
247   ps->scalex = scalex;
248   ps->scaley = scaley;
249 
250   switch (page_size){
251    case GTK_PLOT_LEGAL:
252         width = GTK_PLOT_LEGAL_W;
253         height = GTK_PLOT_LEGAL_H;
254         break;
255    case GTK_PLOT_A4:
256         width = GTK_PLOT_A4_W;
257         height = GTK_PLOT_A4_H;
258         break;
259    case GTK_PLOT_EXECUTIVE:
260         width = GTK_PLOT_EXECUTIVE_W;
261         height = GTK_PLOT_EXECUTIVE_H;
262         break;
263    case GTK_PLOT_LETTER:
264    default:
265         width = GTK_PLOT_LETTER_W;
266         height = GTK_PLOT_LETTER_H;
267   }
268 
269   gtk_plot_ps_set_size(ps, GTK_PLOT_PSPOINTS, width, height);
270 }
271 
272 GtkObject *
gtk_plot_ps_new_with_size(const gchar * psname,gint orientation,gint epsflag,gint units,gdouble width,gdouble height,gdouble scalex,gdouble scaley)273 gtk_plot_ps_new_with_size                       (const gchar *psname,
274                                                  gint orientation,
275                                                  gint epsflag,
276                                                  gint units,
277                                                  gdouble width, gdouble height,
278 						 gdouble scalex, gdouble scaley)
279 {
280   GtkObject *object;
281   GtkPlotPS *ps;
282 
283   object = gtk_type_new(gtk_plot_ps_get_type());
284 
285   ps = GTK_PLOT_PS(object);
286 
287   gtk_plot_ps_construct_with_size (ps, psname, orientation, epsflag, units, width, height, scalex, scaley);
288 
289   return object;
290 }
291 
292 void
gtk_plot_ps_construct_with_size(GtkPlotPS * ps,const gchar * psname,gint orientation,gint epsflag,gint units,gdouble width,gdouble height,gdouble scalex,gdouble scaley)293 gtk_plot_ps_construct_with_size                 (GtkPlotPS *ps,
294 						 const gchar *psname,
295                                                  gint orientation,
296                                                  gint epsflag,
297                                                  gint units,
298                                                  gdouble width, gdouble height,
299 						 gdouble scalex, gdouble scaley)
300 {
301   gtk_plot_ps_construct(ps, psname, orientation, epsflag, GTK_PLOT_CUSTOM, scalex, scaley);
302 
303   gtk_plot_ps_set_size(ps, units, width, height);
304 }
305 
306 void
gtk_plot_ps_set_size(GtkPlotPS * ps,gint units,gdouble width,gdouble height)307 gtk_plot_ps_set_size                            (GtkPlotPS *ps,
308                                                  gint units,
309                                                  gdouble width,
310                                                  gdouble height)
311 {
312   ps->units = units;
313   ps->width = width;
314   ps->height = height;
315 
316   switch(units){
317    case GTK_PLOT_MM:
318         ps->page_width = (gdouble)width * 2.835;
319         ps->page_height = (gdouble)height * 2.835;
320         break;
321    case GTK_PLOT_CM:
322         ps->page_width = width * 28.35;
323         ps->page_height = height * 28.35;
324         break;
325    case GTK_PLOT_INCHES:
326         ps->page_width = width * 72;
327         ps->page_height = height * 72;
328         break;
329    case GTK_PLOT_PSPOINTS:
330    default:
331         ps->page_width = width;
332         ps->page_height = height;
333    }
334 
335    if(ps->orientation == GTK_PLOT_PORTRAIT)
336      gtk_plot_pc_set_viewport(GTK_PLOT_PC(ps), ps->page_width, ps->page_height);
337    else
338      gtk_plot_pc_set_viewport(GTK_PLOT_PC(ps), ps->page_height, ps->page_width);
339 }
340 
341 void
gtk_plot_ps_set_scale(GtkPlotPS * ps,gdouble scalex,gdouble scaley)342 gtk_plot_ps_set_scale                           (GtkPlotPS *ps,
343                                                  gdouble scalex,
344                                                  gdouble scaley)
345 {
346   ps->scalex = scalex;
347   ps->scaley = scaley;
348 }
349 
pssetviewport(GtkPlotPC * pc,gdouble w,gdouble h)350 static void pssetviewport			(GtkPlotPC *pc,
351 						 gdouble w, gdouble h)
352 {
353 
354 }
355 
pssetlineattr(GtkPlotPC * pc,gfloat line_width,GdkLineStyle line_style,GdkCapStyle cap_style,GdkJoinStyle join_style)356 static void pssetlineattr			(GtkPlotPC *pc,
357                                                  gfloat line_width,
358                                                  GdkLineStyle line_style,
359                                                  GdkCapStyle cap_style,
360                                                  GdkJoinStyle join_style)
361 {
362     FILE *psout = GTK_PLOT_PS(pc)->psfile;
363 
364     fprintf(psout, "%g slw\n", line_width);
365     fprintf(psout, "%d slc\n", abs(cap_style - 1));
366     fprintf(psout, "%d slj\n", join_style);
367 
368     if(line_style == 0)
369             fprintf(psout,"[] 0 sd\n");  /* solid line */
370 }
371 
372 static void
pssetdash(GtkPlotPC * pc,gdouble offset,gdouble * values,gint num_values)373 pssetdash(GtkPlotPC *pc,
374           gdouble offset,
375           gdouble *values,
376           gint num_values)
377 {
378     FILE *psout = GTK_PLOT_PS(pc)->psfile;
379 
380     switch(num_values){
381       case 0:
382         fprintf(psout,"[] 0 sd\n");
383         break;
384       case 2:
385         fprintf(psout, "[%g %g] %g sd\n", values[0], values[1], offset);
386         break;
387       case 4:
388         fprintf(psout, "[%g %g %g %g] %g sd\n", values[0], values[1],
389                                                 values[2], values[3],
390                                                 offset);
391         break;
392       case 6:
393         fprintf(psout, "[%g %g %g %g %g %g] %g sd\n",  values[0], values[1],
394                                                        values[2], values[3],
395                                                        values[4], values[5],
396                                                        offset);
397         break;
398       default:
399         break;
400     }
401 }
402 
403 static void
psleave(GtkPlotPC * pc)404 psleave(GtkPlotPC *pc)
405 {
406     fprintf(GTK_PLOT_PS(pc)->psfile, "showpage\n");
407     fprintf(GTK_PLOT_PS(pc)->psfile, "%%%%Trailer\n");
408     fprintf(GTK_PLOT_PS(pc)->psfile, "%%%%EOF\n");
409     fclose(GTK_PLOT_PS(pc)->psfile);
410     setlocale(LC_NUMERIC, locale);
411     g_free(locale);
412 }
413 
414 static gboolean
psinit(GtkPlotPC * pc)415 psinit						(GtkPlotPC *pc)
416 {
417     time_t now;
418     FILE *psout;
419     GtkPlotPS *ps;
420 
421     now = time(NULL);
422 
423     locale = g_strdup(setlocale(LC_NUMERIC, NULL));
424     setlocale(LC_NUMERIC, "C");
425 
426     ps = GTK_PLOT_PS(pc);
427     psout = ps->psfile;
428 
429     if ((psout = fopen(ps->psname, "w")) == NULL){
430        g_warning("ERROR: Cannot open file: %s", ps->psname);
431        return FALSE;
432     }
433 
434     ps->psfile = psout;
435 
436     if(ps->epsflag)
437        fprintf (psout, "%%!PS-Adobe-2.0 PCF-2.0\n");
438     else
439        fprintf (psout, "%%!PS-Adobe-2.0\n");
440 
441     fprintf (psout,
442              "%%%%Title: %s\n"
443              "%%%%Creator: %s v%s Copyright (c) 1999 Adrian E. Feiguin\n"
444              "%%%%CreationDate: %s"
445              "%%%%Magnification: 1.0000\n",
446              ps->psname,
447              "GtkPlot", "3.x",
448              ctime (&now));
449 
450     if(ps->orientation == GTK_PLOT_PORTRAIT)
451              fprintf(psout,"%%%%Orientation: Portrait\n");
452     else
453              fprintf(psout,"%%%%Orientation: Landscape\n");
454 
455 /*
456     if(ps->epsflag)
457 */
458           fprintf (psout,
459                    "%%%%BoundingBox: 0 0 %d %d\n"
460                    "%%%%Pages: 1\n"
461                    "%%%%EndComments\n",
462                    ps->page_width,
463                    ps->page_height);
464 
465 
466     fprintf (psout,
467              "/cp {closepath} bind def\n"
468              "/c {curveto} bind def\n"
469              "/f {fill} bind def\n"
470              "/a {arc} bind def\n"
471              "/ef {eofill} bind def\n"
472              "/ex {exch} bind def\n"
473              "/gr {grestore} bind def\n"
474              "/gs {gsave} bind def\n"
475              "/sa {save} bind def\n"
476              "/rs {restore} bind def\n"
477              "/l {lineto} bind def\n"
478              "/m {moveto} bind def\n"
479              "/rm {rmoveto} bind def\n"
480              "/n {newpath} bind def\n"
481              "/s {stroke} bind def\n"
482              "/sh {show} bind def\n"
483              "/slc {setlinecap} bind def\n"
484              "/slj {setlinejoin} bind def\n"
485              "/slw {setlinewidth} bind def\n"
486              "/srgb {setrgbcolor} bind def\n"
487              "/rot {rotate} bind def\n"
488              "/sc {scale} bind def\n"
489              "/sd {setdash} bind def\n"
490              "/ff {findfont} bind def\n"
491              "/sf {setfont} bind def\n"
492              "/scf {scalefont} bind def\n"
493              "/sw {stringwidth pop} bind def\n"
494              "/tr {translate} bind def\n"
495 
496              "/JR {\n"
497              " neg 0\n"
498              " rmoveto\n"
499              "} bind def\n"
500 
501              "/JC {\n"
502              " 2 div neg 0\n"
503              " rmoveto\n"
504              "} bind def\n"
505 
506              "\n/ellipsedict 8 dict def\n"
507              "ellipsedict /mtrx matrix put\n"
508              "/ellipse\n"
509              "{ ellipsedict begin\n"
510              "   /endangle exch def\n"
511              "   /startangle exch def\n"
512              "   /yrad exch def\n"
513              "   /xrad exch def\n"
514              "   /y exch def\n"
515              "   /x exch def"
516              "   /savematrix mtrx currentmatrix def\n"
517              "   x y tr xrad yrad sc\n"
518              "   0 0 1 startangle endangle arc\n"
519              "   savematrix setmatrix\n"
520              "   end\n"
521              "} def\n\n"
522     );
523 
524     fprintf(psout,
525           "[ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
526           "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
527           "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
528           "/.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
529           "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one\n"
530           "/two /three /four /five /six /seven /eight /nine /colon /semicolon\n"          "/less /equal /greater /question /at /A /B /C /D /E\n"
531           "/F /G /H /I /J /K /L /M /N /O\n"
532           "/P /Q /R /S /T /U /V /W /X /Y\n"
533           "/Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c\n"
534           "/d /e /f /g /h /i /j /k /l /m\n"
535           "/n /o /p /q /r /s /t /u /v /w\n"
536           "/x /y /z /braceleft /bar /braceright /asciitilde /.notdef /.notdef /.notdef\n"
537           "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
538           "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
539           "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
540           "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright\n"
541           "/ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior\n"
542           "/acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf\n"
543           "/threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
544           "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde\n"
545           "/Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex\n"
546           "/Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring\n"
547           "/ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
548           "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave\n"
549           "/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] /isolatin1encoding exch def\n");
550 
551     ps_reencode_font(psout, "Times-Roman");
552     ps_reencode_font(psout, "Times-Italic");
553     ps_reencode_font(psout, "Times-Bold");
554     ps_reencode_font(psout, "Times-BoldItalic");
555     ps_reencode_font(psout, "AvantGarde-Book");
556     ps_reencode_font(psout, "AvantGarde-BookOblique");
557     ps_reencode_font(psout, "AvantGarde-Demi");
558     ps_reencode_font(psout, "AvantGarde-DemiOblique");
559     ps_reencode_font(psout, "Bookman-Light");
560     ps_reencode_font(psout, "Bookman-LightItalic");
561     ps_reencode_font(psout, "Bookman-Demi");
562     ps_reencode_font(psout, "Bookman-DemiItalic");
563     ps_reencode_font(psout, "Courier");
564     ps_reencode_font(psout, "Courier-Oblique");
565     ps_reencode_font(psout, "Courier-Bold");
566     ps_reencode_font(psout, "Courier-BoldOblique");
567     ps_reencode_font(psout, "Helvetica");
568     ps_reencode_font(psout, "Helvetica-Oblique");
569     ps_reencode_font(psout, "Helvetica-Bold");
570     ps_reencode_font(psout, "Helvetica-BoldOblique");
571     ps_reencode_font(psout, "Helvetica-Narrow");
572     ps_reencode_font(psout, "Helvetica-Narrow-Oblique");
573     ps_reencode_font(psout, "Helvetica-Narrow-Bold");
574     ps_reencode_font(psout, "Helvetica-Narrow-BoldOblique");
575     ps_reencode_font(psout, "NewCenturySchoolbook-Roman");
576     ps_reencode_font(psout, "NewCenturySchoolbook-Italic");
577     ps_reencode_font(psout, "NewCenturySchoolbook-Bold");
578     ps_reencode_font(psout, "NewCenturySchoolbook-BoldItalic");
579     ps_reencode_font(psout, "Palatino-Roman");
580     ps_reencode_font(psout, "Palatino-Italic");
581     ps_reencode_font(psout, "Palatino-Bold");
582     ps_reencode_font(psout, "Palatino-BoldItalic");
583     ps_reencode_font(psout, "Symbol");
584     ps_reencode_font(psout, "ZapfChancery-MediumItalic");
585     ps_reencode_font(psout, "ZapfDingbats");
586 
587     fprintf(psout,"%%%%EndProlog\n%%%%BeginSetup\n"
588                 "%%%%PageBoundingBox: 0 0 %d %d\n"
589                 "%%%%PageOrientation: %s\n"
590                 "%%%%PaperSize: %d %d\n",
591                  ps->page_width,
592                  ps->page_height,
593                 (ps->orientation == GTK_PLOT_PORTRAIT) ? "Portrait":"Landscape",
594                  ps->page_width,
595                  ps->page_height);
596 
597     if(ps->orientation == GTK_PLOT_PORTRAIT)
598              fprintf(psout, "%g %g scale\n",
599                             ps->scalex, ps->scaley);
600 
601     if(ps->orientation == GTK_PLOT_LANDSCAPE)
602              fprintf(psout, "%g %g scale\n"
603                             "90 rotate \n"
604                             "0 %d translate\n",
605                             ps->scalex, ps->scaley,
606                             -ps->page_width);
607 
608     fprintf(psout,"%%%%EndSetup\n\n\n");
609 
610     return TRUE;
611 }
612 
ps_reencode_font(FILE * file,char * fontname)613 static void ps_reencode_font(FILE *file, char *fontname)
614 {
615   /* Don't reencode the Symbol font, as it doesn't work in latin1 encoding.
616    * Instead, just define Symbol-latin1 to be the same as Symbol. */
617   if (!strcmp(fontname, "Symbol"))
618     fprintf(file,
619             "/%s-latin1\n"
620             "    /%s findfont\n"
621             "definefont pop\n", fontname, fontname);
622   else
623     fprintf(file,
624             "/%s-latin1\n"
625             "    /%s findfont\n"
626             "    dup length dict begin\n"
627             "   {1 index /FID ne {def} {pop pop} ifelse} forall\n"
628             "   /Encoding isolatin1encoding def\n"
629             "    currentdict end\n"
630             "definefont pop\n", fontname, fontname);
631 }
632 
pssetcolor(GtkPlotPC * pc,const GdkColor * color)633 static void pssetcolor(GtkPlotPC *pc, const GdkColor *color)
634 {
635     FILE *psout = GTK_PLOT_PS(pc)->psfile;
636 
637     fprintf(psout, "%g %g %g setrgbcolor\n",
638 	    (gdouble) color->red / 65535.0,
639 	    (gdouble) color->green / 65535.0,
640 	    (gdouble) color->blue / 65535.0);
641 }
642 
643 static void
psdrawpoint(GtkPlotPC * pc,gdouble x,gdouble y)644 psdrawpoint(GtkPlotPC *pc, gdouble x, gdouble y)
645 {
646   FILE *psout = GTK_PLOT_PS(pc)->psfile;
647 
648   y = GTK_PLOT_PS(pc)->page_height - y;
649   fprintf(psout, "n\n");
650   fprintf(psout, "%g %g m\n", x, y);
651   fprintf(psout, "%g %g l\n", x, y);
652   fprintf(psout, "s\n");
653 }
654 
655 static void
psdrawlines(GtkPlotPC * pc,GtkPlotPoint * points,gint numpoints)656 psdrawlines(GtkPlotPC *pc, GtkPlotPoint *points, gint numpoints)
657 {
658   gint i, page_height = GTK_PLOT_PS(pc)->page_height;
659   FILE *psout = GTK_PLOT_PS(pc)->psfile;
660 
661   fprintf(psout,"n\n");
662   fprintf(psout,"%g %g m\n", points[0].x, page_height - points[0].y);
663   for(i = 1; i < numpoints; i++)
664         fprintf(psout,"%g %g l\n", points[i].x, page_height - points[i].y);
665 
666   fprintf(psout,"s\n");
667 }
668 
669 static void
psdrawpolygon(GtkPlotPC * pc,gboolean filled,GtkPlotPoint * points,gint numpoints)670 psdrawpolygon(GtkPlotPC *pc, gboolean filled, GtkPlotPoint *points, gint numpoints)
671 {
672   gint i, page_height = GTK_PLOT_PS(pc)->page_height;
673   FILE *psout = GTK_PLOT_PS(pc)->psfile;
674 
675   fprintf(psout,"n\n");
676   fprintf(psout,"%g %g m\n", points[0].x, page_height - points[0].y);
677   for(i = 1; i < numpoints; i++)
678       fprintf(psout,"%g %g l\n", points[i].x, page_height - points[i].y);
679 
680   if(filled)
681      fprintf(psout,"f\n");
682   else
683      fprintf(psout,"cp\n");
684 
685   fprintf(psout,"s\n");
686 }
687 
psdrawline(GtkPlotPC * pc,gdouble x0,gdouble y0,gdouble xf,gdouble yf)688 static void psdrawline(GtkPlotPC *pc, gdouble x0, gdouble y0, gdouble xf, gdouble yf)
689 {
690   FILE *psout = GTK_PLOT_PS(pc)->psfile;
691 
692   fprintf(psout, "%g %g m\n", x0, GTK_PLOT_PS(pc)->page_height - y0);
693   fprintf(psout, "%g %g l\n", xf, GTK_PLOT_PS(pc)->page_height - yf);
694   fprintf(psout, "s\n");
695 }
696 
697 static void
psdrawrectangle(GtkPlotPC * pc,gboolean filled,gdouble x,gdouble y,gdouble width,gdouble height)698 psdrawrectangle(GtkPlotPC *pc, gboolean filled,
699                 gdouble x, gdouble y, gdouble width, gdouble height)
700 {
701   GtkPlotPoint point[4];
702 
703   point[0].x = x;
704   point[0].y = y;
705   point[1].x = x + width;
706   point[1].y = y;
707   point[2].x = x + width;
708   point[2].y = y + height;
709   point[3].x = x;
710   point[3].y = y + height;
711 
712   psdrawpolygon(pc, filled, point, 4);
713 }
714 
715 static void
psdrawcircle(GtkPlotPC * pc,gboolean filled,gdouble x,gdouble y,gdouble size)716 psdrawcircle(GtkPlotPC *pc, gboolean filled, gdouble x, gdouble y, gdouble size)
717 {
718   FILE *psout = GTK_PLOT_PS(pc)->psfile;
719 
720   y = GTK_PLOT_PS(pc)->page_height - y;
721   fprintf(psout,"n %g %g %g %g 0 360 ellipse\n",
722           x, y, size / 2., size / 2.);
723 
724   if(filled)
725      fprintf(psout,"f\n");
726 
727   fprintf(psout,"s\n");
728 }
729 
730 static void
psdrawellipse(GtkPlotPC * pc,gboolean filled,gdouble x,gdouble y,gdouble width,gdouble height)731 psdrawellipse(GtkPlotPC *pc,
732               gboolean filled,
733               gdouble x, gdouble y,
734               gdouble width, gdouble height)
735 {
736   FILE *psout = GTK_PLOT_PS(pc)->psfile;
737 
738   y = GTK_PLOT_PS(pc)->page_height - y;
739   fprintf(psout,"n %g %g %g %g 0 360 ellipse\n",
740           x+width/2., y-height/2.,
741           width/2., height/2.);
742 
743   if(filled)
744      fprintf(psout,"f\n");
745 
746   fprintf(psout,"s\n");
747 }
748 
749 static void
psoutputstring(GtkPlotPC * pc,GtkPSFont * psfont,GtkPSFont * latin_psfont,gint height,const gchar * wstring,const gchar * addstring)750 psoutputstring (GtkPlotPC *pc,
751 		GtkPSFont *psfont,
752 		GtkPSFont *latin_psfont,
753 		gint height,
754 		const gchar *wstring,
755 		const gchar *addstring)
756 {
757   const gchar *p;
758   gint curcode = 0;
759   gchar begin[] = { 0, '(', '<' };
760   gchar end[] = { 0, ')', '>' };
761   GtkPSFont *fonts[3];
762   FILE *out = GTK_PLOT_PS(pc)->psfile;
763   const gchar *c = NULL;
764 
765   fonts[0] = NULL;
766   fonts[1] = latin_psfont;
767   fonts[2] = psfont;
768 
769   p = wstring;
770 
771   if (psfont->i18n_latinfamily) {
772 /*    gint code; */ /* 0..neither 1..latin 2..i18n */
773 /*
774     gchar wcs[2];
775     while (*p) {
776       code = (*p >= 0 && *p <= 0x7f) ? 1 : 2;
777       if (curcode && curcode != code)
778 	fprintf(out, "%c %s\n", end[curcode], addstring);
779       if (curcode != code) {
780 	pssetfont(pc, fonts[code], height);
781 	fputc(begin[code], out);
782       }
783 
784       curcode = code;
785 
786       wcs[0] = *p++;
787       wcs[1] = 0;
788       c = wcs;
789 
790       if (code == 2) {
791 	while (*c)
792 	  fprintf(out, "%02x", (unsigned char)(*c++));
793       } else {
794 	if (*c == '(' || *c == ')')
795 	  fputc('\\', out);
796 	fputc(*c, out);
797       }
798     }
799 */
800   } else {
801     c = wstring;
802 
803     pssetfont(pc, psfont, height);
804     fputc(begin[1], out);
805     curcode = 1;
806 
807     while (*c) {
808       const gchar *aux2 = c;
809       if (*c == '(' || *c == ')')
810 	fputc('\\', out);
811 
812       if(++aux2 != g_utf8_next_char(c)){
813         fprintf(out, ") show <%02x> show (", (unsigned char)(*++c));
814         c++;
815       } else {
816         fputc(*c, out);
817         c = g_utf8_next_char(c);
818       }
819     }
820   }
821 
822   if (curcode)
823     fprintf(out, "%c %s\n", end[curcode], addstring);
824 }
825 
826 static void
psdrawstring(GtkPlotPC * pc,gint x,gint y,gint angle,const GdkColor * fg,const GdkColor * bg,gboolean transparent,gint border,gint border_space,gint border_width,gint shadow_width,const gchar * font,gint font_height,GtkJustification justification,const gchar * text)827 psdrawstring	(GtkPlotPC *pc,
828              	 gint x, gint y,
829                  gint angle,
830                  const GdkColor *fg,
831                  const GdkColor *bg,
832                  gboolean transparent,
833                  gint border,
834                  gint border_space,
835                  gint border_width,
836                  gint shadow_width,
837                  const gchar *font,
838                  gint font_height,
839                  GtkJustification justification,
840                  const gchar *text)
841 
842 {
843   gchar *currfont;
844   const gchar *c;
845   GtkPSFont *psfont, *base_psfont, *latin_psfont = NULL;
846   gint curcnt = 0, offset = 0;
847   gint numf;
848   gdouble scale;
849   gboolean italic, bold;
850   gboolean special = FALSE;
851   GList *family;
852   FILE *psout;
853   gint twidth, theight, tdescent, tascent;
854   gint tx, ty, width, height;
855   gint i;
856   const gchar *aux, *xaux, *wtext, *lastchar = NULL;
857   gchar *curstr, bkspchar[3];
858   gchar num[4];
859 
860   if (text == NULL || strlen(text) == 0) return;
861 
862   psout = GTK_PLOT_PS(pc)->psfile;
863 
864   gtk_psfont_get_families(&family, &numf);
865   base_psfont = psfont = gtk_psfont_get_by_name(font);
866   italic = psfont->italic;
867   bold = psfont->bold;
868 
869   currfont = psfont->psname;
870 
871   if (psfont->i18n_latinfamily) {
872     latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic,
873 					    bold);
874   }
875 
876   gtk_plot_text_get_area(text, angle, justification, font, font_height,
877                          &tx, &ty, &width, &height);
878 
879   tx += x;
880   ty += y;
881 
882   if(!transparent){
883     pssetcolor(pc, bg);
884     gtk_plot_pc_draw_rectangle(pc,
885                          TRUE,
886                          tx - border_space, ty - border_space,
887                          width + 2*border_space, height + 2*border_space);
888   }
889 /* border */
890 
891   pssetcolor(pc, fg);
892   pssetdash(pc, 0, NULL, 0);
893   pssetlineattr(pc, border_width, 0, 0, 0);
894 
895   switch(border){
896     case GTK_PLOT_BORDER_SHADOW:
897       psdrawrectangle(pc,
898                          TRUE,
899                          tx - border_space + shadow_width,
900                          ty + height + border_space,
901                          width + 2 * border_space, shadow_width);
902       psdrawrectangle(pc,
903                          TRUE,
904                          tx + width + border_space,
905                          ty - border_space + shadow_width,
906                          shadow_width, height + 2 * border_space);
907     case GTK_PLOT_BORDER_LINE:
908       psdrawrectangle(pc,
909                          FALSE,
910                          tx - border_space, ty - border_space,
911                          width + 2*border_space, height + 2*border_space);
912     case GTK_PLOT_BORDER_NONE:
913     default:
914         break;
915   }
916 
917 
918   gtk_plot_text_get_size(text, angle, psfont->psname, font_height,
919                          &twidth, &theight, &tascent, &tdescent);
920 
921   psgsave(pc);
922   fprintf(psout, "%d %d translate\n", x, GTK_PLOT_PS(pc)->page_height - y);
923   fprintf(psout, "%d rotate\n", angle);
924 
925   fprintf(psout, "0 0 m\n");
926 
927   if (psfont->i18n_latinfamily)
928     special = TRUE;
929 
930   c = text;
931   while(c && *c != '\0' && *c != '\n') {
932      if(*c == '\\'){
933          c = g_utf8_next_char(c);
934          switch(*c){
935            case '0': case '1': case '2': case '3':
936            case '4': case '5': case '6': case '7': case '9':
937            case '8': case'g': case 'B': case 'b': case 'x': case 'N':
938            case 's': case 'S': case 'i': case '-': case '+': case '^':
939              special = TRUE;
940              break;
941            default:
942              break;
943          }
944      } else {
945          c = g_utf8_next_char(c);
946      }
947   }
948 
949   if(special){
950     switch (justification) {
951       case GTK_JUSTIFY_LEFT:
952         break;
953       case GTK_JUSTIFY_RIGHT:
954         if(angle == 0 || angle == 180)
955                fprintf(psout, "%d JR\n", twidth);
956         else
957                fprintf(psout, "%d JR\n", theight);
958         break;
959       case GTK_JUSTIFY_CENTER:
960       default:
961         if(angle == 0 || angle == 180)
962                fprintf(psout, "%d JC\n", twidth);
963         else
964                fprintf(psout, "%d JC\n", theight);
965         break;
966     }
967   } else {
968     pssetfont(pc, psfont, font_height);
969 
970     switch (justification) {
971       case GTK_JUSTIFY_LEFT:
972         break;
973       case GTK_JUSTIFY_RIGHT:
974         fprintf(psout, "(%s) sw JR\n", text);
975         break;
976       case GTK_JUSTIFY_CENTER:
977       default:
978         fprintf(psout, "(%s) sw JC\n", text);
979         break;
980     }
981     fprintf(psout, "(%s) show\n", text);
982 
983     psgrestore(pc);
984     fprintf(psout, "n\n");
985     return;
986   }
987 
988   i = g_utf8_strlen(text, -1) + 2;
989   curstr = g_malloc0(sizeof(gchar) * i);
990   aux = wtext = text;
991 
992   scale = font_height;
993   curcnt = 0;
994 
995   while(aux && *aux != '\0' && *aux != '\n') {
996      if(*aux == '\\'){
997          aux = g_utf8_next_char(aux);
998          switch(*aux){
999            case '0': case '1': case '2': case '3':
1000            case '4': case '5': case '6': case '7': case '9':
1001                   curstr[curcnt] = 0;
1002 		  psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1003 				 curstr, "show");
1004                   curcnt = 0;
1005                   psfont = gtk_psfont_get_by_family((gchar *)g_list_nth_data(family, *aux-'0'), italic, bold);
1006 		  aux = g_utf8_next_char(aux);
1007                   break;
1008            case '8':case 'g':
1009                   curstr[curcnt] = 0;
1010                   psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1011 				 curstr, "show");
1012                   curcnt = 0;
1013                   psfont = gtk_psfont_get_by_family("Symbol", italic, bold);
1014                   aux = g_utf8_next_char(aux);
1015                   break;
1016            case 'B':
1017                   curstr[curcnt] = 0;
1018                   psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1019 				 curstr, "show");
1020                   curcnt = 0;
1021   		  bold = TRUE;
1022                   psfont = gtk_psfont_get_by_family(psfont->family, italic, bold);
1023 		  if (psfont->i18n_latinfamily)
1024 		    latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic, bold);
1025 		  aux = g_utf8_next_char(aux);
1026                   break;
1027            case 'x':
1028                   xaux = aux + 1;
1029                   for (i=0; i<3; i++){
1030 		    if (xaux[i] >= '0' && xaux[i] <= '9')
1031 		      num[i] = xaux[i];
1032 		    else
1033 		      break;
1034                   }
1035                   if (i < 3){
1036                      aux = g_utf8_next_char(aux);
1037                      break;
1038                   }
1039                   num[3] = '\0';
1040 
1041 		  i = atoi(num);
1042 		  g_snprintf(num, 4, "%o", i % (64 * 8));
1043 
1044 		  curstr[curcnt++] = '\\';
1045 		  i = 0;
1046 		  while (num[i]) {
1047 		    curstr[curcnt++] = num[i++];
1048 		  }
1049 
1050                   aux += 4;
1051                   break;
1052            case 'i':
1053 	          curstr[curcnt] = 0;
1054                   psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1055 				 curstr, "show");
1056                   curcnt = 0;
1057 		  italic = TRUE;
1058                   psfont = gtk_psfont_get_by_family(psfont->family, italic, bold);
1059 		  if (psfont->i18n_latinfamily)
1060 		    latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic, bold);
1061 		  aux = g_utf8_next_char(aux);
1062                   break;
1063            case 's':case '_':
1064                   curstr[curcnt] = 0;
1065                   psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1066 				 curstr, "show");
1067                   curcnt = 0;
1068                   scale = 0.6 * font_height;
1069 		  offset -= (gint)scale / 2;
1070                   fprintf(psout, "0 %d rmoveto\n", -((gint)scale / 2));
1071                   aux = g_utf8_next_char(aux);
1072                   break;
1073            case 'S':case '^':
1074                   curstr[curcnt] = 0;
1075                   psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1076 				 curstr, "show");
1077                   curcnt = 0;
1078                   scale = 0.6 * font_height;
1079 		  offset += 0.5*font_height;
1080                   fprintf(psout, "0 %d rmoveto\n", (gint)(0.5*font_height));
1081                   aux = g_utf8_next_char(aux);
1082                   break;
1083            case 'N':
1084                   curstr[curcnt] = 0;
1085                   psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1086 				 curstr, "show");
1087                   curcnt = 0;
1088 		  psfont = base_psfont;
1089 		  italic = psfont->italic;
1090 		  bold = psfont->bold;
1091 		  if (psfont->i18n_latinfamily) {
1092 		    latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily,
1093 							     italic, bold);
1094 		  }
1095                   scale = font_height;
1096                   fprintf(psout, "0 %d rmoveto\n", -offset);
1097                   offset = 0;
1098                   aux = g_utf8_next_char(aux);
1099                   break;
1100            case 'b':
1101                   curstr[curcnt] = '\0';
1102                   psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1103 				 curstr, "show");
1104                   curcnt = 0;
1105                   if (lastchar) {
1106                       const gchar *aux2 = lastchar;
1107                       bkspchar[0] = *lastchar;
1108                       lastchar = g_utf8_prev_char(lastchar);
1109 		      bkspchar[1] = 0;
1110                       if(--aux2 != lastchar){
1111                         bkspchar[1] = *lastchar;
1112                         lastchar = g_utf8_prev_char(lastchar);
1113 		        bkspchar[2] = 0;
1114                       }
1115                   } else {
1116                       bkspchar[0] = 'X';
1117                       lastchar = NULL;
1118                   }
1119 		  psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1120 				 bkspchar,
1121 				 "stringwidth pop 0 exch neg exch rmoveto");
1122                   aux = g_utf8_next_char(aux);
1123                   break;
1124            case '-':
1125                   curstr[curcnt] = 0;
1126 		  psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1127 				 curstr, "show");
1128                   curcnt = 0;
1129                   scale -= 3;
1130                   if (scale < 6) {
1131                       scale = 6;
1132                   }
1133                   aux = g_utf8_next_char(aux);
1134                   break;
1135            case '+':
1136                   curstr[curcnt] = 0;
1137 		  psoutputstring(pc, psfont, latin_psfont, (gint)scale,
1138 				 curstr, "show");
1139                   curcnt = 0;
1140                   scale += 3;
1141                   aux = g_utf8_next_char(aux);
1142                   break;
1143            default:
1144                   if(aux && *aux != '\0' && *aux != '\n'){
1145                     curstr[curcnt++] = *aux;
1146                     aux = g_utf8_next_char(aux);
1147                   }
1148                   break;
1149          }
1150      } else {
1151        if(aux && *aux != '\0' && *aux != '\n'){
1152                 const gchar *aux2 = aux;
1153                 if(g_utf8_next_char(aux) != ++aux2){
1154                   curstr[curcnt++] = *aux++;
1155 //                  aux = g_utf8_next_char(aux);
1156                   curstr[curcnt++] = *aux++;
1157                 } else {
1158                   curstr[curcnt++] = *aux;
1159 		  lastchar = aux;
1160                   aux = g_utf8_next_char(aux);
1161                 }
1162        }
1163      }
1164   }
1165   curstr[curcnt] = 0;
1166   psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show");
1167 
1168   psgrestore(pc);
1169   fprintf(psout, "n\n");
1170 
1171   g_free(curstr);
1172 }
1173 
1174 static void
pssetfont(GtkPlotPC * pc,GtkPSFont * psfont,gint height)1175 pssetfont(GtkPlotPC *pc, GtkPSFont *psfont, gint height)
1176 {
1177   FILE *psout = GTK_PLOT_PS(pc)->psfile;
1178 
1179   if (psfont->i18n_latinfamily && psfont->vertical)
1180     fprintf(psout,
1181 	    "/%s ff [0 1 -1 0 0 0.3] makefont [%d 0 0 %d 0 0] makefont sf\n",
1182 	    psfont->psname, height, height);
1183   else
1184     fprintf(psout, "/%s-latin1 ff %g scf sf\n", psfont->psname, (double)height);
1185 
1186 }
1187 
1188 
1189 static void
psgsave(GtkPlotPC * pc)1190 psgsave(GtkPlotPC *pc)
1191 {
1192   GtkPlotPS *ps;
1193   FILE *psout;
1194 
1195   ps = GTK_PLOT_PS(pc);
1196 
1197   psout = ps->psfile;
1198 
1199   fprintf(psout,"gsave\n");
1200   ps->gsaved = TRUE;
1201 }
1202 
1203 static void
psgrestore(GtkPlotPC * pc)1204 psgrestore(GtkPlotPC *pc)
1205 {
1206   GtkPlotPS *ps;
1207   FILE *psout;
1208 
1209   ps = GTK_PLOT_PS(pc);
1210 
1211   psout = ps->psfile;
1212 
1213 /*
1214   if(!ps->gsaved) return;
1215 */
1216 
1217   fprintf(psout,"grestore\n");
1218   ps->gsaved = FALSE;
1219 }
1220 
1221 static void
psclipmask(GtkPlotPC * pc,gdouble x,gdouble y,const GdkBitmap * mask)1222 psclipmask(GtkPlotPC *pc, gdouble x, gdouble y, const GdkBitmap *mask)
1223 {
1224   FILE *psout = GTK_PLOT_PS(pc)->psfile;
1225   gint width, height;
1226   gint px, py;
1227   gint npoints = 0;
1228   gint i, page_height = GTK_PLOT_PS(pc)->page_height;
1229   GtkPlotVector *points;
1230   GdkImage *image;
1231 
1232   if(!mask){
1233     fprintf(psout,"grestore\n");
1234     return;
1235   }
1236 
1237   gdk_window_get_size((GdkWindow *)mask, &width, &height);
1238   image = gdk_image_get((GdkWindow *)mask, 0, 0, width, height);
1239 
1240   points = (GtkPlotVector *)g_malloc(width*height*sizeof(GtkPlotVector));
1241 
1242   for(px = 0; px < width; px++){
1243     for(py = 0; py < height; py++){
1244       if(gdk_image_get_pixel(image, px, py)){
1245         points[npoints].x = px;
1246         points[npoints].y = py;
1247         npoints++;
1248         break;
1249       }
1250     }
1251   }
1252   for(py = points[npoints-1].y; py < height; py++){
1253     for(px = width - 1; px >= 0; px--){
1254       if(gdk_image_get_pixel(image, px, py)){
1255         points[npoints].x = px;
1256         points[npoints].y = py;
1257         npoints++;
1258         break;
1259       }
1260     }
1261   }
1262   for(px = points[npoints-1].x; px >= 0; px--){
1263     for(py = height - 1; py >= 0; py--){
1264       if(gdk_image_get_pixel(image, px, py)){
1265         points[npoints].x = px;
1266         points[npoints].y = py;
1267         npoints++;
1268         break;
1269       }
1270     }
1271   }
1272   for(py = points[npoints-1].y; py >= 0; py--){
1273     for(px = 0; px < width; px++){
1274       if(gdk_image_get_pixel(image, px, py)){
1275         points[npoints].x = px;
1276         points[npoints].y = py;
1277         npoints++;
1278         break;
1279       }
1280     }
1281   }
1282 
1283   fprintf(psout,"gsave\n");
1284 
1285   fprintf(psout,"n\n");
1286   fprintf(psout,"%g %g m\n", x + points[0].x, page_height - y - points[0].y);
1287   for(i = 1; i < npoints; i++)
1288       fprintf(psout,"%g %g l\n", x + points[i].x, page_height - y - points[i].y);
1289 
1290   fprintf(psout,"cp\n");
1291 
1292   fprintf(psout,"clip\n");
1293 
1294   g_free(points);
1295   gdk_image_destroy(image);
1296 }
1297 
1298 static void
psclip(GtkPlotPC * pc,const GdkRectangle * clip)1299 psclip(GtkPlotPC *pc, const GdkRectangle *clip)
1300 {
1301   FILE *psout = GTK_PLOT_PS(pc)->psfile;
1302 
1303   if(!clip){
1304     fprintf(psout,"grestore\n");
1305     return;
1306   }
1307 
1308   fprintf(psout,"gsave\n");
1309   fprintf(psout,"%d %d %d %d rectclip\n",
1310                   clip->x,
1311                   GTK_PLOT_PS(pc)->page_height - clip->y - clip->height,
1312                   clip->width,
1313                   clip->height);
1314 }
1315 
1316 /* TODO: FIXME */
1317 
1318 static void
psdrawpixmap(GtkPlotPC * pc,GdkPixmap * pixmap,GdkBitmap * mask,gint xsrc,gint ysrc,gint xdest,gint ydest,gint width,gint height,gdouble scale_x,gdouble scale_y)1319 psdrawpixmap  (GtkPlotPC *pc,
1320                GdkPixmap *pixmap,
1321                GdkBitmap *mask,
1322                gint xsrc, gint ysrc,
1323                gint xdest, gint ydest,
1324                gint width, gint height,
1325                gdouble scale_x, gdouble scale_y)
1326 {
1327   FILE *psout = GTK_PLOT_PS(pc)->psfile;
1328   GdkColormap *colormap;
1329 
1330   colormap = gdk_colormap_get_system ();
1331 
1332   fprintf(psout, "gsave\n");
1333   if(pixmap){
1334     GdkImage *image;
1335     gint x, y;
1336 
1337     image = gdk_image_get(pixmap,
1338                           xsrc, ysrc,
1339                           width, height);
1340 
1341     if(mask) gtk_plot_pc_clip_mask(pc, xdest, ydest, mask);
1342     ydest = GTK_PLOT_PS(pc)->page_height - ydest - height;
1343 
1344     fprintf(psout, "%d %g translate\n", xdest, ydest + height * scale_y);
1345     fprintf(psout, "%g %g scale\n",width * scale_x, height * scale_y);
1346     fprintf(psout, "%d %d 8 [%d 0 0 %d 0 %d]\n",width, height, width, height, height);
1347     fprintf(psout, "/scanline %d 3 mul string def\n", width);
1348     fprintf(psout, "{ currentfile scanline readhexstring pop } false 3\n");
1349     fprintf(psout, "colorimage\n");
1350 
1351     for(y = height - 1; y >= 0; y--){
1352       for(x = 0; x < width; x++){
1353         GdkColor color;
1354         gchar string[7];
1355 
1356         color.pixel = gdk_image_get_pixel(image, x, y);
1357 	gdk_colormap_query_color(colormap, color.pixel, &color);
1358         color_to_hex(color, string);
1359         fprintf(psout,"%s",string);
1360         if(fmod(x + 1, 13) == 0) fprintf(psout, "\n");
1361       }
1362       fprintf(psout,"\n");
1363     }
1364 
1365     gdk_image_destroy(image);
1366     if(mask) gtk_plot_pc_clip_mask(pc, xdest, ydest, NULL);
1367   }
1368 
1369   fprintf(psout, "grestore\n");
1370 }
1371 
1372 static void
color_to_hex(GdkColor color,gchar string[7])1373 color_to_hex(GdkColor color, gchar string[7])
1374 {
1375   gint n;
1376   gint aux;
1377 
1378   aux = color.red / 256;
1379   n=aux/16;
1380   aux-=n*16;
1381   if(n < 10)
1382     string[0]='0'+n;
1383   else
1384     string[0]='A'+n-10;
1385   n = aux;
1386   if(n < 10)
1387     string[1]='0'+n;
1388   else
1389     string[1]='A'+n-10;
1390 
1391   aux = color.green / 256;
1392   n=aux/16;
1393   aux-=n*16;
1394   if(n < 10)
1395     string[2]='0'+n;
1396   else
1397     string[2]='A'+n-10;
1398   n = aux;
1399   if(n < 10)
1400     string[3]='0'+n;
1401   else
1402     string[3]='A'+n-10;
1403 
1404   aux = color.blue / 256;
1405   n=aux/16;
1406   aux-=n*16;
1407   if(n < 10)
1408     string[4]='0'+n;
1409   else
1410     string[4]='A'+n-10;
1411   n = aux;
1412   if(n < 10)
1413     string[5]='0'+n;
1414   else
1415     string[5]='A'+n-10;
1416 
1417   string[6]='\0';
1418 }
1419 
1420 
1421