/* gtkplotps - postscript driver * Copyright 1999-2001 Adrian E. Feiguin * * Some few lines of code borrowed from * DiaCanvas -- a technical canvas widget * Copyright (C) 1999 Arjan Molenaar * Dia -- an diagram creation/manipulation program * Copyright (C) 1998 Alexander Larsson * ISO Latin encoding by * Przemek Klosowski * przemek@rrdbartok.nist.gov * (borrowed from XMGR) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include "gtkplot.h" #include "gtkpsfont.h" #include "gtkplotpc.h" #include "gtkplotps.h" static void gtk_plot_ps_class_init (GtkPlotPSClass *klass); static void gtk_plot_ps_init (GtkPlotPS *ps); static void gtk_plot_ps_destroy (GtkObject *object); /*********************************************************************/ /* Postscript specific functions */ static gboolean psinit (GtkPlotPC *pc); static void pssetviewport (GtkPlotPC *pc, gdouble w, gdouble h); static void psleave (GtkPlotPC *pc); static void psgsave (GtkPlotPC *pc); static void psgrestore (GtkPlotPC *pc); static void psclip (GtkPlotPC *pc, const GdkRectangle *area); static void psclipmask (GtkPlotPC *pc, gdouble x, gdouble y, const GdkBitmap *mask); static void psdrawlines (GtkPlotPC *pc, GtkPlotPoint *points, gint numpoints); static void psdrawpoint (GtkPlotPC *pc, gdouble x, gdouble y); static void psdrawline (GtkPlotPC *pc, gdouble x0, gdouble y0, gdouble xf, gdouble yf); static void psdrawpolygon (GtkPlotPC *pc, gboolean filled, GtkPlotPoint *points, gint numpoints); static void psdrawrectangle (GtkPlotPC *pc, gboolean filled, gdouble x, gdouble y, gdouble width, gdouble height); static void psdrawcircle (GtkPlotPC *pc, gboolean filled, gdouble x, gdouble y, gdouble size); static void psdrawellipse (GtkPlotPC *pc, gboolean filled, gdouble x, gdouble y, gdouble width, gdouble height); static void pssetcolor (GtkPlotPC *pc, const GdkColor *color); static void pssetlineattr (GtkPlotPC *pc, gfloat line_width, GdkLineStyle line_style, GdkCapStyle cap_style, GdkJoinStyle join_style); 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 height, GtkJustification just, const gchar *text); static void pssetfont (GtkPlotPC *pc, GtkPSFont *psfont, gint height); static void pssetdash (GtkPlotPC *pc, gdouble offset, gdouble *values, gint num_values); static void psdrawpixmap (GtkPlotPC *pc, GdkPixmap *pixmap, GdkBitmap *mask, gint xsrc, gint ysrc, gint xdest, gint ydest, gint width, gint height, gdouble sx, gdouble sy); static void ps_reencode_font (FILE *file, char *fontname); static void color_to_hex (GdkColor color, gchar string[7]); /*********************************************************************/ static GtkPlotPCClass *parent_class = NULL; static gchar *locale = NULL; GtkType gtk_plot_ps_get_type (void) { static GtkType pc_type = 0; if (!pc_type) { GtkTypeInfo pc_info = { "GtkPlotPS", sizeof (GtkPlotPS), sizeof (GtkPlotPSClass), (GtkClassInitFunc) gtk_plot_ps_class_init, (GtkObjectInitFunc) gtk_plot_ps_init, /* reserved 1*/ NULL, /* reserved 2 */ NULL, (GtkClassInitFunc) NULL, }; pc_type = gtk_type_unique (GTK_TYPE_PLOT_PC, &pc_info); } return pc_type; } static void gtk_plot_ps_init (GtkPlotPS *ps) { ps->psname = NULL; ps->gsaved = FALSE; GTK_PLOT_PC(ps)->use_pixmap = FALSE; } static void gtk_plot_ps_class_init (GtkPlotPSClass *klass) { GtkObjectClass *object_class; GObjectClass *gobject_class; GtkPlotPCClass *pc_class; parent_class = gtk_type_class (gtk_plot_pc_get_type ()); object_class = (GtkObjectClass *) klass; gobject_class = (GObjectClass *) klass; pc_class = (GtkPlotPCClass *) klass; pc_class->init = psinit; pc_class->leave = psleave; pc_class->set_viewport = pssetviewport; pc_class->gsave = psgsave; pc_class->grestore = psgrestore; pc_class->clip = psclip; pc_class->clip_mask = psclipmask; pc_class->set_color = pssetcolor; pc_class->set_dash = pssetdash; pc_class->set_lineattr = pssetlineattr; pc_class->draw_point = psdrawpoint; pc_class->draw_line = psdrawline; pc_class->draw_lines = psdrawlines; pc_class->draw_rectangle = psdrawrectangle; pc_class->draw_polygon = psdrawpolygon; pc_class->draw_circle = psdrawcircle; pc_class->draw_ellipse = psdrawellipse; pc_class->set_font = pssetfont; pc_class->draw_string = psdrawstring; pc_class->draw_pixmap = psdrawpixmap; object_class->destroy = gtk_plot_ps_destroy; } static void gtk_plot_ps_destroy(GtkObject *object) { GtkPlotPS *ps; ps = GTK_PLOT_PS(object); if(ps->psname){ g_free(ps->psname); ps->psname = NULL; } } GtkObject * gtk_plot_ps_new (const gchar *psname, gint orientation, gint epsflag, gint page_size, gdouble scalex, gdouble scaley) { GtkObject *object; GtkPlotPS *ps; object = gtk_type_new(gtk_plot_ps_get_type()); ps = GTK_PLOT_PS(object); gtk_plot_ps_construct(ps, psname, orientation, epsflag, page_size, scalex, scaley); return (object); } void gtk_plot_ps_construct (GtkPlotPS *ps, const gchar *psname, gint orientation, gint epsflag, gint page_size, gdouble scalex, gdouble scaley) { gint width, height; ps->psname = g_strdup(psname); ps->orientation = orientation; ps->epsflag = epsflag; ps->page_size = page_size; ps->scalex = scalex; ps->scaley = scaley; switch (page_size){ case GTK_PLOT_LEGAL: width = GTK_PLOT_LEGAL_W; height = GTK_PLOT_LEGAL_H; break; case GTK_PLOT_A4: width = GTK_PLOT_A4_W; height = GTK_PLOT_A4_H; break; case GTK_PLOT_EXECUTIVE: width = GTK_PLOT_EXECUTIVE_W; height = GTK_PLOT_EXECUTIVE_H; break; case GTK_PLOT_LETTER: default: width = GTK_PLOT_LETTER_W; height = GTK_PLOT_LETTER_H; } gtk_plot_ps_set_size(ps, GTK_PLOT_PSPOINTS, width, height); } GtkObject * gtk_plot_ps_new_with_size (const gchar *psname, gint orientation, gint epsflag, gint units, gdouble width, gdouble height, gdouble scalex, gdouble scaley) { GtkObject *object; GtkPlotPS *ps; object = gtk_type_new(gtk_plot_ps_get_type()); ps = GTK_PLOT_PS(object); gtk_plot_ps_construct_with_size (ps, psname, orientation, epsflag, units, width, height, scalex, scaley); return object; } 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) { gtk_plot_ps_construct(ps, psname, orientation, epsflag, GTK_PLOT_CUSTOM, scalex, scaley); gtk_plot_ps_set_size(ps, units, width, height); } void gtk_plot_ps_set_size (GtkPlotPS *ps, gint units, gdouble width, gdouble height) { ps->units = units; ps->width = width; ps->height = height; switch(units){ case GTK_PLOT_MM: ps->page_width = (gdouble)width * 2.835; ps->page_height = (gdouble)height * 2.835; break; case GTK_PLOT_CM: ps->page_width = width * 28.35; ps->page_height = height * 28.35; break; case GTK_PLOT_INCHES: ps->page_width = width * 72; ps->page_height = height * 72; break; case GTK_PLOT_PSPOINTS: default: ps->page_width = width; ps->page_height = height; } if(ps->orientation == GTK_PLOT_PORTRAIT) gtk_plot_pc_set_viewport(GTK_PLOT_PC(ps), ps->page_width, ps->page_height); else gtk_plot_pc_set_viewport(GTK_PLOT_PC(ps), ps->page_height, ps->page_width); } void gtk_plot_ps_set_scale (GtkPlotPS *ps, gdouble scalex, gdouble scaley) { ps->scalex = scalex; ps->scaley = scaley; } static void pssetviewport (GtkPlotPC *pc, gdouble w, gdouble h) { } static void pssetlineattr (GtkPlotPC *pc, gfloat line_width, GdkLineStyle line_style, GdkCapStyle cap_style, GdkJoinStyle join_style) { FILE *psout = GTK_PLOT_PS(pc)->psfile; fprintf(psout, "%g slw\n", line_width); fprintf(psout, "%d slc\n", abs(cap_style - 1)); fprintf(psout, "%d slj\n", join_style); if(line_style == 0) fprintf(psout,"[] 0 sd\n"); /* solid line */ } static void pssetdash(GtkPlotPC *pc, gdouble offset, gdouble *values, gint num_values) { FILE *psout = GTK_PLOT_PS(pc)->psfile; switch(num_values){ case 0: fprintf(psout,"[] 0 sd\n"); break; case 2: fprintf(psout, "[%g %g] %g sd\n", values[0], values[1], offset); break; case 4: fprintf(psout, "[%g %g %g %g] %g sd\n", values[0], values[1], values[2], values[3], offset); break; case 6: fprintf(psout, "[%g %g %g %g %g %g] %g sd\n", values[0], values[1], values[2], values[3], values[4], values[5], offset); break; default: break; } } static void psleave(GtkPlotPC *pc) { fprintf(GTK_PLOT_PS(pc)->psfile, "showpage\n"); fprintf(GTK_PLOT_PS(pc)->psfile, "%%%%Trailer\n"); fprintf(GTK_PLOT_PS(pc)->psfile, "%%%%EOF\n"); fclose(GTK_PLOT_PS(pc)->psfile); setlocale(LC_NUMERIC, locale); g_free(locale); } static gboolean psinit (GtkPlotPC *pc) { time_t now; FILE *psout; GtkPlotPS *ps; now = time(NULL); locale = g_strdup(setlocale(LC_NUMERIC, NULL)); setlocale(LC_NUMERIC, "C"); ps = GTK_PLOT_PS(pc); psout = ps->psfile; if ((psout = fopen(ps->psname, "w")) == NULL){ g_warning("ERROR: Cannot open file: %s", ps->psname); return FALSE; } ps->psfile = psout; if(ps->epsflag) fprintf (psout, "%%!PS-Adobe-2.0 PCF-2.0\n"); else fprintf (psout, "%%!PS-Adobe-2.0\n"); fprintf (psout, "%%%%Title: %s\n" "%%%%Creator: %s v%s Copyright (c) 1999 Adrian E. Feiguin\n" "%%%%CreationDate: %s" "%%%%Magnification: 1.0000\n", ps->psname, "GtkPlot", "3.x", ctime (&now)); if(ps->orientation == GTK_PLOT_PORTRAIT) fprintf(psout,"%%%%Orientation: Portrait\n"); else fprintf(psout,"%%%%Orientation: Landscape\n"); /* if(ps->epsflag) */ fprintf (psout, "%%%%BoundingBox: 0 0 %d %d\n" "%%%%Pages: 1\n" "%%%%EndComments\n", ps->page_width, ps->page_height); fprintf (psout, "/cp {closepath} bind def\n" "/c {curveto} bind def\n" "/f {fill} bind def\n" "/a {arc} bind def\n" "/ef {eofill} bind def\n" "/ex {exch} bind def\n" "/gr {grestore} bind def\n" "/gs {gsave} bind def\n" "/sa {save} bind def\n" "/rs {restore} bind def\n" "/l {lineto} bind def\n" "/m {moveto} bind def\n" "/rm {rmoveto} bind def\n" "/n {newpath} bind def\n" "/s {stroke} bind def\n" "/sh {show} bind def\n" "/slc {setlinecap} bind def\n" "/slj {setlinejoin} bind def\n" "/slw {setlinewidth} bind def\n" "/srgb {setrgbcolor} bind def\n" "/rot {rotate} bind def\n" "/sc {scale} bind def\n" "/sd {setdash} bind def\n" "/ff {findfont} bind def\n" "/sf {setfont} bind def\n" "/scf {scalefont} bind def\n" "/sw {stringwidth pop} bind def\n" "/tr {translate} bind def\n" "/JR {\n" " neg 0\n" " rmoveto\n" "} bind def\n" "/JC {\n" " 2 div neg 0\n" " rmoveto\n" "} bind def\n" "\n/ellipsedict 8 dict def\n" "ellipsedict /mtrx matrix put\n" "/ellipse\n" "{ ellipsedict begin\n" " /endangle exch def\n" " /startangle exch def\n" " /yrad exch def\n" " /xrad exch def\n" " /y exch def\n" " /x exch def" " /savematrix mtrx currentmatrix def\n" " x y tr xrad yrad sc\n" " 0 0 1 startangle endangle arc\n" " savematrix setmatrix\n" " end\n" "} def\n\n" ); fprintf(psout, "[ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" "/.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n" "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one\n" "/two /three /four /five /six /seven /eight /nine /colon /semicolon\n" "/less /equal /greater /question /at /A /B /C /D /E\n" "/F /G /H /I /J /K /L /M /N /O\n" "/P /Q /R /S /T /U /V /W /X /Y\n" "/Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c\n" "/d /e /f /g /h /i /j /k /l /m\n" "/n /o /p /q /r /s /t /u /v /w\n" "/x /y /z /braceleft /bar /braceright /asciitilde /.notdef /.notdef /.notdef\n" "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright\n" "/ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior\n" "/acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf\n" "/threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n" "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde\n" "/Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex\n" "/Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring\n" "/ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n" "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave\n" "/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] /isolatin1encoding exch def\n"); ps_reencode_font(psout, "Times-Roman"); ps_reencode_font(psout, "Times-Italic"); ps_reencode_font(psout, "Times-Bold"); ps_reencode_font(psout, "Times-BoldItalic"); ps_reencode_font(psout, "AvantGarde-Book"); ps_reencode_font(psout, "AvantGarde-BookOblique"); ps_reencode_font(psout, "AvantGarde-Demi"); ps_reencode_font(psout, "AvantGarde-DemiOblique"); ps_reencode_font(psout, "Bookman-Light"); ps_reencode_font(psout, "Bookman-LightItalic"); ps_reencode_font(psout, "Bookman-Demi"); ps_reencode_font(psout, "Bookman-DemiItalic"); ps_reencode_font(psout, "Courier"); ps_reencode_font(psout, "Courier-Oblique"); ps_reencode_font(psout, "Courier-Bold"); ps_reencode_font(psout, "Courier-BoldOblique"); ps_reencode_font(psout, "Helvetica"); ps_reencode_font(psout, "Helvetica-Oblique"); ps_reencode_font(psout, "Helvetica-Bold"); ps_reencode_font(psout, "Helvetica-BoldOblique"); ps_reencode_font(psout, "Helvetica-Narrow"); ps_reencode_font(psout, "Helvetica-Narrow-Oblique"); ps_reencode_font(psout, "Helvetica-Narrow-Bold"); ps_reencode_font(psout, "Helvetica-Narrow-BoldOblique"); ps_reencode_font(psout, "NewCenturySchoolbook-Roman"); ps_reencode_font(psout, "NewCenturySchoolbook-Italic"); ps_reencode_font(psout, "NewCenturySchoolbook-Bold"); ps_reencode_font(psout, "NewCenturySchoolbook-BoldItalic"); ps_reencode_font(psout, "Palatino-Roman"); ps_reencode_font(psout, "Palatino-Italic"); ps_reencode_font(psout, "Palatino-Bold"); ps_reencode_font(psout, "Palatino-BoldItalic"); ps_reencode_font(psout, "Symbol"); ps_reencode_font(psout, "ZapfChancery-MediumItalic"); ps_reencode_font(psout, "ZapfDingbats"); fprintf(psout,"%%%%EndProlog\n%%%%BeginSetup\n" "%%%%PageBoundingBox: 0 0 %d %d\n" "%%%%PageOrientation: %s\n" "%%%%PaperSize: %d %d\n", ps->page_width, ps->page_height, (ps->orientation == GTK_PLOT_PORTRAIT) ? "Portrait":"Landscape", ps->page_width, ps->page_height); if(ps->orientation == GTK_PLOT_PORTRAIT) fprintf(psout, "%g %g scale\n", ps->scalex, ps->scaley); if(ps->orientation == GTK_PLOT_LANDSCAPE) fprintf(psout, "%g %g scale\n" "90 rotate \n" "0 %d translate\n", ps->scalex, ps->scaley, -ps->page_width); fprintf(psout,"%%%%EndSetup\n\n\n"); return TRUE; } static void ps_reencode_font(FILE *file, char *fontname) { /* Don't reencode the Symbol font, as it doesn't work in latin1 encoding. * Instead, just define Symbol-latin1 to be the same as Symbol. */ if (!strcmp(fontname, "Symbol")) fprintf(file, "/%s-latin1\n" " /%s findfont\n" "definefont pop\n", fontname, fontname); else fprintf(file, "/%s-latin1\n" " /%s findfont\n" " dup length dict begin\n" " {1 index /FID ne {def} {pop pop} ifelse} forall\n" " /Encoding isolatin1encoding def\n" " currentdict end\n" "definefont pop\n", fontname, fontname); } static void pssetcolor(GtkPlotPC *pc, const GdkColor *color) { FILE *psout = GTK_PLOT_PS(pc)->psfile; fprintf(psout, "%g %g %g setrgbcolor\n", (gdouble) color->red / 65535.0, (gdouble) color->green / 65535.0, (gdouble) color->blue / 65535.0); } static void psdrawpoint(GtkPlotPC *pc, gdouble x, gdouble y) { FILE *psout = GTK_PLOT_PS(pc)->psfile; y = GTK_PLOT_PS(pc)->page_height - y; fprintf(psout, "n\n"); fprintf(psout, "%g %g m\n", x, y); fprintf(psout, "%g %g l\n", x, y); fprintf(psout, "s\n"); } static void psdrawlines(GtkPlotPC *pc, GtkPlotPoint *points, gint numpoints) { gint i, page_height = GTK_PLOT_PS(pc)->page_height; FILE *psout = GTK_PLOT_PS(pc)->psfile; fprintf(psout,"n\n"); fprintf(psout,"%g %g m\n", points[0].x, page_height - points[0].y); for(i = 1; i < numpoints; i++) fprintf(psout,"%g %g l\n", points[i].x, page_height - points[i].y); fprintf(psout,"s\n"); } static void psdrawpolygon(GtkPlotPC *pc, gboolean filled, GtkPlotPoint *points, gint numpoints) { gint i, page_height = GTK_PLOT_PS(pc)->page_height; FILE *psout = GTK_PLOT_PS(pc)->psfile; fprintf(psout,"n\n"); fprintf(psout,"%g %g m\n", points[0].x, page_height - points[0].y); for(i = 1; i < numpoints; i++) fprintf(psout,"%g %g l\n", points[i].x, page_height - points[i].y); if(filled) fprintf(psout,"f\n"); else fprintf(psout,"cp\n"); fprintf(psout,"s\n"); } static void psdrawline(GtkPlotPC *pc, gdouble x0, gdouble y0, gdouble xf, gdouble yf) { FILE *psout = GTK_PLOT_PS(pc)->psfile; fprintf(psout, "%g %g m\n", x0, GTK_PLOT_PS(pc)->page_height - y0); fprintf(psout, "%g %g l\n", xf, GTK_PLOT_PS(pc)->page_height - yf); fprintf(psout, "s\n"); } static void psdrawrectangle(GtkPlotPC *pc, gboolean filled, gdouble x, gdouble y, gdouble width, gdouble height) { GtkPlotPoint point[4]; point[0].x = x; point[0].y = y; point[1].x = x + width; point[1].y = y; point[2].x = x + width; point[2].y = y + height; point[3].x = x; point[3].y = y + height; psdrawpolygon(pc, filled, point, 4); } static void psdrawcircle(GtkPlotPC *pc, gboolean filled, gdouble x, gdouble y, gdouble size) { FILE *psout = GTK_PLOT_PS(pc)->psfile; y = GTK_PLOT_PS(pc)->page_height - y; fprintf(psout,"n %g %g %g %g 0 360 ellipse\n", x, y, size / 2., size / 2.); if(filled) fprintf(psout,"f\n"); fprintf(psout,"s\n"); } static void psdrawellipse(GtkPlotPC *pc, gboolean filled, gdouble x, gdouble y, gdouble width, gdouble height) { FILE *psout = GTK_PLOT_PS(pc)->psfile; y = GTK_PLOT_PS(pc)->page_height - y; fprintf(psout,"n %g %g %g %g 0 360 ellipse\n", x+width/2., y-height/2., width/2., height/2.); if(filled) fprintf(psout,"f\n"); fprintf(psout,"s\n"); } static void psoutputstring (GtkPlotPC *pc, GtkPSFont *psfont, GtkPSFont *latin_psfont, gint height, const gchar *wstring, const gchar *addstring) { const gchar *p; gint curcode = 0; gchar begin[] = { 0, '(', '<' }; gchar end[] = { 0, ')', '>' }; GtkPSFont *fonts[3]; FILE *out = GTK_PLOT_PS(pc)->psfile; const gchar *c = NULL; fonts[0] = NULL; fonts[1] = latin_psfont; fonts[2] = psfont; p = wstring; if (psfont->i18n_latinfamily) { /* gint code; */ /* 0..neither 1..latin 2..i18n */ /* gchar wcs[2]; while (*p) { code = (*p >= 0 && *p <= 0x7f) ? 1 : 2; if (curcode && curcode != code) fprintf(out, "%c %s\n", end[curcode], addstring); if (curcode != code) { pssetfont(pc, fonts[code], height); fputc(begin[code], out); } curcode = code; wcs[0] = *p++; wcs[1] = 0; c = wcs; if (code == 2) { while (*c) fprintf(out, "%02x", (unsigned char)(*c++)); } else { if (*c == '(' || *c == ')') fputc('\\', out); fputc(*c, out); } } */ } else { c = wstring; pssetfont(pc, psfont, height); fputc(begin[1], out); curcode = 1; while (*c) { const gchar *aux2 = c; if (*c == '(' || *c == ')') fputc('\\', out); if(++aux2 != g_utf8_next_char(c)){ fprintf(out, ") show <%02x> show (", (unsigned char)(*++c)); c++; } else { fputc(*c, out); c = g_utf8_next_char(c); } } } if (curcode) fprintf(out, "%c %s\n", end[curcode], addstring); } 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) { gchar *currfont; const gchar *c; GtkPSFont *psfont, *base_psfont, *latin_psfont = NULL; gint curcnt = 0, offset = 0; gint numf; gdouble scale; gboolean italic, bold; gboolean special = FALSE; GList *family; FILE *psout; gint twidth, theight, tdescent, tascent; gint tx, ty, width, height; gint i; const gchar *aux, *xaux, *wtext, *lastchar = NULL; gchar *curstr, bkspchar[3]; gchar num[4]; if (text == NULL || strlen(text) == 0) return; psout = GTK_PLOT_PS(pc)->psfile; gtk_psfont_get_families(&family, &numf); base_psfont = psfont = gtk_psfont_get_by_name(font); italic = psfont->italic; bold = psfont->bold; currfont = psfont->psname; if (psfont->i18n_latinfamily) { latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic, bold); } gtk_plot_text_get_area(text, angle, justification, font, font_height, &tx, &ty, &width, &height); tx += x; ty += y; if(!transparent){ pssetcolor(pc, bg); gtk_plot_pc_draw_rectangle(pc, TRUE, tx - border_space, ty - border_space, width + 2*border_space, height + 2*border_space); } /* border */ pssetcolor(pc, fg); pssetdash(pc, 0, NULL, 0); pssetlineattr(pc, border_width, 0, 0, 0); switch(border){ case GTK_PLOT_BORDER_SHADOW: psdrawrectangle(pc, TRUE, tx - border_space + shadow_width, ty + height + border_space, width + 2 * border_space, shadow_width); psdrawrectangle(pc, TRUE, tx + width + border_space, ty - border_space + shadow_width, shadow_width, height + 2 * border_space); case GTK_PLOT_BORDER_LINE: psdrawrectangle(pc, FALSE, tx - border_space, ty - border_space, width + 2*border_space, height + 2*border_space); case GTK_PLOT_BORDER_NONE: default: break; } gtk_plot_text_get_size(text, angle, psfont->psname, font_height, &twidth, &theight, &tascent, &tdescent); psgsave(pc); fprintf(psout, "%d %d translate\n", x, GTK_PLOT_PS(pc)->page_height - y); fprintf(psout, "%d rotate\n", angle); fprintf(psout, "0 0 m\n"); if (psfont->i18n_latinfamily) special = TRUE; c = text; while(c && *c != '\0' && *c != '\n') { if(*c == '\\'){ c = g_utf8_next_char(c); switch(*c){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '9': case '8': case'g': case 'B': case 'b': case 'x': case 'N': case 's': case 'S': case 'i': case '-': case '+': case '^': special = TRUE; break; default: break; } } else { c = g_utf8_next_char(c); } } if(special){ switch (justification) { case GTK_JUSTIFY_LEFT: break; case GTK_JUSTIFY_RIGHT: if(angle == 0 || angle == 180) fprintf(psout, "%d JR\n", twidth); else fprintf(psout, "%d JR\n", theight); break; case GTK_JUSTIFY_CENTER: default: if(angle == 0 || angle == 180) fprintf(psout, "%d JC\n", twidth); else fprintf(psout, "%d JC\n", theight); break; } } else { pssetfont(pc, psfont, font_height); switch (justification) { case GTK_JUSTIFY_LEFT: break; case GTK_JUSTIFY_RIGHT: fprintf(psout, "(%s) sw JR\n", text); break; case GTK_JUSTIFY_CENTER: default: fprintf(psout, "(%s) sw JC\n", text); break; } fprintf(psout, "(%s) show\n", text); psgrestore(pc); fprintf(psout, "n\n"); return; } i = g_utf8_strlen(text, -1) + 2; curstr = g_malloc0(sizeof(gchar) * i); aux = wtext = text; scale = font_height; curcnt = 0; while(aux && *aux != '\0' && *aux != '\n') { if(*aux == '\\'){ aux = g_utf8_next_char(aux); switch(*aux){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '9': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; psfont = gtk_psfont_get_by_family((gchar *)g_list_nth_data(family, *aux-'0'), italic, bold); aux = g_utf8_next_char(aux); break; case '8':case 'g': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; psfont = gtk_psfont_get_by_family("Symbol", italic, bold); aux = g_utf8_next_char(aux); break; case 'B': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; bold = TRUE; psfont = gtk_psfont_get_by_family(psfont->family, italic, bold); if (psfont->i18n_latinfamily) latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic, bold); aux = g_utf8_next_char(aux); break; case 'x': xaux = aux + 1; for (i=0; i<3; i++){ if (xaux[i] >= '0' && xaux[i] <= '9') num[i] = xaux[i]; else break; } if (i < 3){ aux = g_utf8_next_char(aux); break; } num[3] = '\0'; i = atoi(num); g_snprintf(num, 4, "%o", i % (64 * 8)); curstr[curcnt++] = '\\'; i = 0; while (num[i]) { curstr[curcnt++] = num[i++]; } aux += 4; break; case 'i': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; italic = TRUE; psfont = gtk_psfont_get_by_family(psfont->family, italic, bold); if (psfont->i18n_latinfamily) latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic, bold); aux = g_utf8_next_char(aux); break; case 's':case '_': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; scale = 0.6 * font_height; offset -= (gint)scale / 2; fprintf(psout, "0 %d rmoveto\n", -((gint)scale / 2)); aux = g_utf8_next_char(aux); break; case 'S':case '^': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; scale = 0.6 * font_height; offset += 0.5*font_height; fprintf(psout, "0 %d rmoveto\n", (gint)(0.5*font_height)); aux = g_utf8_next_char(aux); break; case 'N': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; psfont = base_psfont; italic = psfont->italic; bold = psfont->bold; if (psfont->i18n_latinfamily) { latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic, bold); } scale = font_height; fprintf(psout, "0 %d rmoveto\n", -offset); offset = 0; aux = g_utf8_next_char(aux); break; case 'b': curstr[curcnt] = '\0'; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; if (lastchar) { const gchar *aux2 = lastchar; bkspchar[0] = *lastchar; lastchar = g_utf8_prev_char(lastchar); bkspchar[1] = 0; if(--aux2 != lastchar){ bkspchar[1] = *lastchar; lastchar = g_utf8_prev_char(lastchar); bkspchar[2] = 0; } } else { bkspchar[0] = 'X'; lastchar = NULL; } psoutputstring(pc, psfont, latin_psfont, (gint)scale, bkspchar, "stringwidth pop 0 exch neg exch rmoveto"); aux = g_utf8_next_char(aux); break; case '-': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; scale -= 3; if (scale < 6) { scale = 6; } aux = g_utf8_next_char(aux); break; case '+': curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); curcnt = 0; scale += 3; aux = g_utf8_next_char(aux); break; default: if(aux && *aux != '\0' && *aux != '\n'){ curstr[curcnt++] = *aux; aux = g_utf8_next_char(aux); } break; } } else { if(aux && *aux != '\0' && *aux != '\n'){ const gchar *aux2 = aux; if(g_utf8_next_char(aux) != ++aux2){ curstr[curcnt++] = *aux++; // aux = g_utf8_next_char(aux); curstr[curcnt++] = *aux++; } else { curstr[curcnt++] = *aux; lastchar = aux; aux = g_utf8_next_char(aux); } } } } curstr[curcnt] = 0; psoutputstring(pc, psfont, latin_psfont, (gint)scale, curstr, "show"); psgrestore(pc); fprintf(psout, "n\n"); g_free(curstr); } static void pssetfont(GtkPlotPC *pc, GtkPSFont *psfont, gint height) { FILE *psout = GTK_PLOT_PS(pc)->psfile; if (psfont->i18n_latinfamily && psfont->vertical) fprintf(psout, "/%s ff [0 1 -1 0 0 0.3] makefont [%d 0 0 %d 0 0] makefont sf\n", psfont->psname, height, height); else fprintf(psout, "/%s-latin1 ff %g scf sf\n", psfont->psname, (double)height); } static void psgsave(GtkPlotPC *pc) { GtkPlotPS *ps; FILE *psout; ps = GTK_PLOT_PS(pc); psout = ps->psfile; fprintf(psout,"gsave\n"); ps->gsaved = TRUE; } static void psgrestore(GtkPlotPC *pc) { GtkPlotPS *ps; FILE *psout; ps = GTK_PLOT_PS(pc); psout = ps->psfile; /* if(!ps->gsaved) return; */ fprintf(psout,"grestore\n"); ps->gsaved = FALSE; } static void psclipmask(GtkPlotPC *pc, gdouble x, gdouble y, const GdkBitmap *mask) { FILE *psout = GTK_PLOT_PS(pc)->psfile; gint width, height; gint px, py; gint npoints = 0; gint i, page_height = GTK_PLOT_PS(pc)->page_height; GtkPlotVector *points; GdkImage *image; if(!mask){ fprintf(psout,"grestore\n"); return; } gdk_window_get_size((GdkWindow *)mask, &width, &height); image = gdk_image_get((GdkWindow *)mask, 0, 0, width, height); points = (GtkPlotVector *)g_malloc(width*height*sizeof(GtkPlotVector)); for(px = 0; px < width; px++){ for(py = 0; py < height; py++){ if(gdk_image_get_pixel(image, px, py)){ points[npoints].x = px; points[npoints].y = py; npoints++; break; } } } for(py = points[npoints-1].y; py < height; py++){ for(px = width - 1; px >= 0; px--){ if(gdk_image_get_pixel(image, px, py)){ points[npoints].x = px; points[npoints].y = py; npoints++; break; } } } for(px = points[npoints-1].x; px >= 0; px--){ for(py = height - 1; py >= 0; py--){ if(gdk_image_get_pixel(image, px, py)){ points[npoints].x = px; points[npoints].y = py; npoints++; break; } } } for(py = points[npoints-1].y; py >= 0; py--){ for(px = 0; px < width; px++){ if(gdk_image_get_pixel(image, px, py)){ points[npoints].x = px; points[npoints].y = py; npoints++; break; } } } fprintf(psout,"gsave\n"); fprintf(psout,"n\n"); fprintf(psout,"%g %g m\n", x + points[0].x, page_height - y - points[0].y); for(i = 1; i < npoints; i++) fprintf(psout,"%g %g l\n", x + points[i].x, page_height - y - points[i].y); fprintf(psout,"cp\n"); fprintf(psout,"clip\n"); g_free(points); gdk_image_destroy(image); } static void psclip(GtkPlotPC *pc, const GdkRectangle *clip) { FILE *psout = GTK_PLOT_PS(pc)->psfile; if(!clip){ fprintf(psout,"grestore\n"); return; } fprintf(psout,"gsave\n"); fprintf(psout,"%d %d %d %d rectclip\n", clip->x, GTK_PLOT_PS(pc)->page_height - clip->y - clip->height, clip->width, clip->height); } /* TODO: FIXME */ 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) { FILE *psout = GTK_PLOT_PS(pc)->psfile; GdkColormap *colormap; colormap = gdk_colormap_get_system (); fprintf(psout, "gsave\n"); if(pixmap){ GdkImage *image; gint x, y; image = gdk_image_get(pixmap, xsrc, ysrc, width, height); if(mask) gtk_plot_pc_clip_mask(pc, xdest, ydest, mask); ydest = GTK_PLOT_PS(pc)->page_height - ydest - height; fprintf(psout, "%d %g translate\n", xdest, ydest + height * scale_y); fprintf(psout, "%g %g scale\n",width * scale_x, height * scale_y); fprintf(psout, "%d %d 8 [%d 0 0 %d 0 %d]\n",width, height, width, height, height); fprintf(psout, "/scanline %d 3 mul string def\n", width); fprintf(psout, "{ currentfile scanline readhexstring pop } false 3\n"); fprintf(psout, "colorimage\n"); for(y = height - 1; y >= 0; y--){ for(x = 0; x < width; x++){ GdkColor color; gchar string[7]; color.pixel = gdk_image_get_pixel(image, x, y); gdk_colormap_query_color(colormap, color.pixel, &color); color_to_hex(color, string); fprintf(psout,"%s",string); if(fmod(x + 1, 13) == 0) fprintf(psout, "\n"); } fprintf(psout,"\n"); } gdk_image_destroy(image); if(mask) gtk_plot_pc_clip_mask(pc, xdest, ydest, NULL); } fprintf(psout, "grestore\n"); } static void color_to_hex(GdkColor color, gchar string[7]) { gint n; gint aux; aux = color.red / 256; n=aux/16; aux-=n*16; if(n < 10) string[0]='0'+n; else string[0]='A'+n-10; n = aux; if(n < 10) string[1]='0'+n; else string[1]='A'+n-10; aux = color.green / 256; n=aux/16; aux-=n*16; if(n < 10) string[2]='0'+n; else string[2]='A'+n-10; n = aux; if(n < 10) string[3]='0'+n; else string[3]='A'+n-10; aux = color.blue / 256; n=aux/16; aux-=n*16; if(n < 10) string[4]='0'+n; else string[4]='A'+n-10; n = aux; if(n < 10) string[5]='0'+n; else string[5]='A'+n-10; string[6]='\0'; }