/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/plugin/core/gvrender_core_ps.c

Go to the documentation of this file.
00001 /* $Id: gvrender_core_ps.c,v 1.63 2008/03/09 01:15:30 ellson Exp $ $Revision: 1.63 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020 
00021 #include <stdlib.h>
00022 #include <string.h>
00023 
00024 #include "gvplugin_render.h"
00025 #include "graph.h"
00026 #include "agxbuf.h"
00027 #include "utils.h"
00028 
00029 /* for CHAR_LATIN1  */
00030 #include "const.h"
00031 
00032 /*
00033  *     J$: added `pdfmark' URL embedding.  PostScript rendered from
00034  *         dot files with URL attributes will get active PDF links
00035  *         from Adobe's Distiller.
00036  */
00037 #define PDFMAX  14400           /*  Maximum size of PDF page  */
00038 
00039 extern void epsf_define(FILE * of);
00040 extern char *ps_string(char *ins, int latin);
00041 
00042 typedef enum { FORMAT_PS, FORMAT_PS2, } format_type;
00043 
00044 static int isLatin1;
00045 static char setupLatin1;
00046 
00047 static void psgen_begin_job(GVJ_t * job)
00048 {
00049     gvdevice_fputs(job, "%!PS-Adobe-2.0\n");
00050     gvdevice_printf(job, "%%%%Creator: %s version %s (%s)\n",
00051             job->common->info[0], job->common->info[1], job->common->info[2]);
00052     gvdevice_printf(job, "%%%%For: %s\n", job->common->user);
00053 }
00054 
00055 static void psgen_end_job(GVJ_t * job)
00056 {
00057     gvdevice_fputs(job, "%%Trailer\n");
00058     gvdevice_printf(job, "%%%%Pages: %d\n", job->common->viewNum);
00059     if (job->common->show_boxes == NULL)
00060         gvdevice_printf(job, "%%%%BoundingBox: %d %d %d %d\n",
00061             job->boundingBox.LL.x, job->boundingBox.LL.y,
00062             job->boundingBox.UR.x, job->boundingBox.UR.y);
00063     gvdevice_fputs(job, "end\nrestore\n");
00064     gvdevice_fputs(job, "%%EOF\n");
00065 }
00066 
00067 static void psgen_begin_graph(GVJ_t * job)
00068 {
00069     obj_state_t *obj = job->obj;
00070 
00071     setupLatin1 = FALSE;
00072 
00073     if (job->common->viewNum == 0) {
00074         gvdevice_printf(job, "%%%%Title: %s\n", obj->u.g->name);
00075         gvdevice_fputs(job, "%%Pages: (atend)\n");
00076         if (job->common->show_boxes == NULL)
00077             gvdevice_fputs(job, "%%BoundingBox: (atend)\n");
00078         gvdevice_fputs(job, "%%EndComments\nsave\n");
00079         /* include shape library */
00080         cat_preamble(job, job->common->lib);
00081         /* include epsf */
00082         epsf_define(job->output_file);
00083         if (job->common->show_boxes) {
00084             char* args[2];
00085             args[0] = job->common->show_boxes[0];
00086             args[1] = NULL;
00087             cat_libfile(job->output_file, NULL, args);
00088         }
00089     }
00090     isLatin1 = (GD_charset(obj->u.g) == CHAR_LATIN1);
00091     /* We always setup Latin1. The charset info is always output,
00092      * and installing it is cheap. With it installed, we can then
00093      * rely on ps_string to convert UTF-8 characters whose encoding
00094      * is in the range of Latin-1 into the Latin-1 equivalent and
00095      * get the expected PostScript output.
00096      */
00097     if (!setupLatin1) {
00098         gvdevice_fputs(job, "setupLatin1\n");   /* as defined in ps header */
00099         setupLatin1 = TRUE;
00100     }
00101     /*  Set base URL for relative links (for Distiller >= 3.0)  */
00102     if (obj->url)
00103         gvdevice_printf(job, "[ {Catalog} << /URI << /Base (%s) >> >>\n"
00104                 "/PUT pdfmark\n", obj->url);
00105 }
00106 
00107 static void psgen_begin_layer(GVJ_t * job, char *layername, int layerNum, int numLayers)
00108 {
00109     gvdevice_printf(job, "%d %d setlayer\n", layerNum, numLayers);
00110 }
00111 
00112 static void psgen_begin_page(GVJ_t * job)
00113 {
00114     box pbr = job->pageBoundingBox;
00115 
00116     gvdevice_printf(job, "%%%%Page: %d %d\n",
00117             job->common->viewNum + 1, job->common->viewNum + 1);
00118     if (job->common->show_boxes == NULL)
00119         gvdevice_printf(job, "%%%%PageBoundingBox: %d %d %d %d\n",
00120             pbr.LL.x, pbr.LL.y, pbr.UR.x, pbr.UR.y);
00121     gvdevice_printf(job, "%%%%PageOrientation: %s\n",
00122             (job->rotation ? "Landscape" : "Portrait"));
00123     if (job->render.id == FORMAT_PS2)
00124         gvdevice_printf(job, "<< /PageSize [%d %d] >> setpagedevice\n",
00125             pbr.UR.x, pbr.UR.y);
00126     gvdevice_printf(job, "%d %d %d beginpage\n",
00127             job->pagesArrayElem.x, job->pagesArrayElem.y, job->numPages);
00128     if (job->common->show_boxes == NULL)
00129         gvdevice_printf(job, "gsave\n%d %d %d %d boxprim clip newpath\n",
00130             pbr.LL.x, pbr.LL.y, pbr.UR.x-pbr.LL.x, pbr.UR.y-pbr.LL.y);
00131     gvdevice_printf(job, "%g %g set_scale %d rotate %g %g translate\n",
00132             job->scale.x, job->scale.y,
00133             job->rotation,
00134             job->translation.x, job->translation.y);
00135 
00136     /*  Define the size of the PS canvas  */
00137     if (job->render.id == FORMAT_PS2) {
00138         if (pbr.UR.x >= PDFMAX || pbr.UR.y >= PDFMAX)
00139             job->common->errorfn("canvas size (%d,%d) exceeds PDF limit (%d)\n"
00140                   "\t(suggest setting a bounding box size, see dot(1))\n",
00141                   pbr.UR.x, pbr.UR.y, PDFMAX);
00142         gvdevice_printf(job, "[ /CropBox [%d %d %d %d] /PAGES pdfmark\n",
00143                 pbr.LL.x, pbr.LL.y, pbr.UR.x, pbr.UR.y);
00144     }
00145 }
00146 
00147 static void psgen_end_page(GVJ_t * job)
00148 {
00149     if (job->common->show_boxes) {
00150         gvdevice_fputs(job, "0 0 0 edgecolor\n");
00151         cat_libfile(job->output_file, NULL, job->common->show_boxes + 1);
00152     }
00153     /* the showpage is really a no-op, but at least one PS processor
00154      * out there needs to see this literal token.  endpage does the real work.
00155      */
00156     gvdevice_fputs(job, "endpage\nshowpage\ngrestore\n");
00157     gvdevice_fputs(job, "%%PageTrailer\n");
00158     gvdevice_printf(job, "%%%%EndPage: %d\n", job->common->viewNum);
00159 }
00160 
00161 static void psgen_begin_cluster(GVJ_t * job)
00162 {
00163     obj_state_t *obj = job->obj;
00164 
00165     gvdevice_printf(job, "%% %s\n", obj->u.sg->name);
00166 
00167     gvdevice_fputs(job, "gsave\n");
00168 }
00169 
00170 static void psgen_end_cluster(GVJ_t * job)
00171 {
00172     gvdevice_fputs(job, "grestore\n");
00173 }
00174 
00175 static void psgen_begin_node(GVJ_t * job)
00176 {
00177     gvdevice_fputs(job, "gsave\n");
00178 }
00179 
00180 static void psgen_end_node(GVJ_t * job)
00181 {
00182     gvdevice_fputs(job, "grestore\n");
00183 }
00184 
00185 static void
00186 psgen_begin_edge(GVJ_t * job)
00187 {
00188     gvdevice_fputs(job, "gsave\n");
00189 }
00190 
00191 static void psgen_end_edge(GVJ_t * job)
00192 {
00193     gvdevice_fputs(job, "grestore\n");
00194 }
00195 
00196 static void psgen_begin_anchor(GVJ_t *job, char *url, char *tooltip, char *target)
00197 {
00198     obj_state_t *obj = job->obj;
00199 
00200     if (url && obj->url_map_p) {
00201         gvdevice_fputs(job, "[ /Rect [ ");
00202         gvdevice_printpointflist(job, obj->url_map_p, 2);
00203         gvdevice_fputs(job, " ]\n");
00204         gvdevice_printf(job, "  /Border [ 0 0 0 ]\n"
00205                 "  /Action << /Subtype /URI /URI %s >>\n"
00206                 "  /Subtype /Link\n"
00207                 "/ANN pdfmark\n",
00208                 ps_string(url, isLatin1));
00209     }
00210 }
00211 
00212 static void
00213 ps_set_pen_style(GVJ_t *job)
00214 {
00215     double penwidth = job->obj->penwidth;
00216     char *p, *line, **s = job->obj->rawstyle;
00217 
00218     gvdevice_printnum(job, penwidth);
00219     gvdevice_fputs(job," setlinewidth\n");
00220 
00221     while (s && (p = line = *s++)) {
00222         if (strcmp(line, "setlinewidth") == 0)
00223             continue;
00224         while (*p)
00225             p++;
00226         p++;
00227         while (*p) {
00228             gvdevice_printf(job,"%s ", p);
00229             while (*p)
00230                 p++;
00231             p++;
00232         }
00233         if (strcmp(line, "invis") == 0)
00234             job->obj->penwidth = 0;
00235         gvdevice_printf(job, "%s\n", line);
00236     }
00237 }
00238 
00239 static void ps_set_color(GVJ_t *job, gvcolor_t *color)
00240 {
00241     char *objtype;
00242 
00243     if (color) {
00244         switch (job->obj->type) {
00245             case ROOTGRAPH_OBJTYPE:
00246             case CLUSTER_OBJTYPE:
00247                 objtype = "graph";
00248                 break;
00249             case NODE_OBJTYPE:
00250                 objtype = "node";
00251                 break;
00252             case EDGE_OBJTYPE:
00253                 objtype = "edge";
00254                 break;
00255             default:
00256                 objtype = "sethsb";
00257                 break;
00258         }
00259         gvdevice_printf(job, "%.3f %.3f %.3f %scolor\n",
00260             color->u.HSVA[0], color->u.HSVA[1], color->u.HSVA[2], objtype);
00261     }
00262 }
00263 
00264 static void psgen_textpara(GVJ_t * job, pointf p, textpara_t * para)
00265 {
00266     char *str;
00267 
00268     if (job->obj->pencolor.u.HSVA[3] < .5)
00269         return;  /* skip transparent text */
00270 
00271     ps_set_color(job, &(job->obj->pencolor));
00272     gvdevice_printnum(job, para->fontsize);
00273     gvdevice_printf(job, " /%s set_font\n", para->fontname);
00274     str = ps_string(para->str,isLatin1);
00275     switch (para->just) {
00276     case 'r':
00277         p.x -= para->width;
00278         break;
00279     case 'l':
00280         p.x -= 0.0;
00281         break;
00282     case 'n':
00283     default:
00284         p.x -= para->width / 2.0;
00285         break;
00286     }
00287     p.y += para->yoffset_centerline;
00288     gvdevice_printpointf(job, p);
00289     gvdevice_fputs(job, " moveto ");
00290     gvdevice_printnum(job, para->width);
00291     gvdevice_printf(job, " %s alignedtext\n", str);
00292 }
00293 
00294 static void psgen_ellipse(GVJ_t * job, pointf * A, int filled)
00295 {
00296     /* A[] contains 2 points: the center and corner. */
00297     pointf AA[2];
00298 
00299     AA[0] = A[0];
00300     AA[1].x = A[1].x - A[0].x;
00301     AA[1].y = A[1].y - A[0].y;
00302 
00303     if (filled && job->obj->fillcolor.u.HSVA[3] > .5) {
00304         ps_set_color(job, &(job->obj->fillcolor));
00305         gvdevice_printpointflist(job, AA, 2);
00306         gvdevice_fputs(job, " ellipse_path fill\n");
00307     }
00308     if (job->obj->pencolor.u.HSVA[3] > .5) {
00309         ps_set_pen_style(job);
00310         ps_set_color(job, &(job->obj->pencolor));
00311         gvdevice_printpointflist(job, AA, 2);
00312         gvdevice_fputs(job, " ellipse_path stroke\n");
00313     }
00314 }
00315 
00316 static void
00317 psgen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00318              int arrow_at_end, int filled)
00319 {
00320     int j;
00321 
00322     if (filled && job->obj->fillcolor.u.HSVA[3] > .5) {
00323         ps_set_color(job, &(job->obj->fillcolor));
00324         gvdevice_fputs(job, "newpath ");
00325         gvdevice_printpointf(job, A[0]);
00326         gvdevice_fputs(job, " moveto\n");
00327         for (j = 1; j < n; j += 3) {
00328             gvdevice_printpointflist(job, &A[j], 3);
00329             gvdevice_fputs(job, " curveto\n");
00330         }
00331         gvdevice_fputs(job, "closepath fill\n");
00332     }
00333     if (job->obj->pencolor.u.HSVA[3] > .5) {
00334         ps_set_pen_style(job);
00335         ps_set_color(job, &(job->obj->pencolor));
00336         gvdevice_fputs(job, "newpath ");
00337         gvdevice_printpointf(job, A[0]);
00338         gvdevice_fputs(job, " moveto\n");
00339         for (j = 1; j < n; j += 3) {
00340             gvdevice_printpointflist(job, &A[j], 3);
00341             gvdevice_fputs(job, " curveto\n");
00342         }
00343         gvdevice_fputs(job, "stroke\n");
00344     }
00345 }
00346 
00347 static void psgen_polygon(GVJ_t * job, pointf * A, int n, int filled)
00348 {
00349     int j;
00350 
00351     if (filled && job->obj->fillcolor.u.HSVA[3] > .5) {
00352         ps_set_color(job, &(job->obj->fillcolor));
00353         gvdevice_fputs(job, "newpath ");
00354         gvdevice_printpointf(job, A[0]);
00355         gvdevice_fputs(job, " moveto\n");
00356         for (j = 1; j < n; j++) {
00357             gvdevice_printpointf(job, A[j]);
00358             gvdevice_fputs(job, " lineto\n");
00359         }
00360         gvdevice_fputs(job, "closepath fill\n");
00361     }
00362     if (job->obj->pencolor.u.HSVA[3] > .5) {
00363         ps_set_pen_style(job);
00364         ps_set_color(job, &(job->obj->pencolor));
00365         gvdevice_fputs(job, "newpath ");
00366         gvdevice_printpointf(job, A[0]);
00367         gvdevice_fputs(job, " moveto\n");
00368         for (j = 1; j < n; j++) {
00369             gvdevice_printpointf(job, A[j]);
00370             gvdevice_fputs(job, " lineto\n");
00371         }
00372         gvdevice_fputs(job, "closepath stroke\n");
00373     }
00374 }
00375 
00376 static void psgen_polyline(GVJ_t * job, pointf * A, int n)
00377 {
00378     int j;
00379 
00380     if (job->obj->pencolor.u.HSVA[3] > .5) {
00381         ps_set_pen_style(job);
00382         ps_set_color(job, &(job->obj->pencolor));
00383         gvdevice_fputs(job, "newpath ");
00384         gvdevice_printpointf(job, A[0]);
00385         gvdevice_fputs(job, " moveto\n");
00386         for (j = 1; j < n; j++) {
00387             gvdevice_printpointf(job, A[j]);
00388             gvdevice_fputs(job, " lineto\n");
00389         }
00390         gvdevice_fputs(job, "stroke\n");
00391     }
00392 }
00393 
00394 static void psgen_comment(GVJ_t * job, char *str)
00395 {
00396     gvdevice_fputs(job, "% ");
00397     gvdevice_fputs(job, str);
00398     gvdevice_fputs(job, "\n");
00399 }
00400 
00401 static void psgen_library_shape(GVJ_t * job, char *name, pointf * A, int n, int filled)
00402 {
00403     if (filled && job->obj->fillcolor.u.HSVA[3] > .5) {
00404         ps_set_color(job, &(job->obj->fillcolor));
00405         gvdevice_fputs(job, "[ ");
00406         gvdevice_printpointflist(job, A, n);
00407         gvdevice_fputs(job, " ");
00408         gvdevice_printpointf(job, A[0]);
00409         gvdevice_printf(job, " ]  %d true %s\n", n, name);
00410     }
00411     if (job->obj->pencolor.u.HSVA[3] > .5) {
00412         ps_set_pen_style(job);
00413         ps_set_color(job, &(job->obj->pencolor));
00414         gvdevice_fputs(job, "[ ");
00415         gvdevice_printpointflist(job, A, n);
00416         gvdevice_fputs(job, " ");
00417         gvdevice_printpointf(job, A[0]);
00418         gvdevice_printf(job, " ]  %d false %s\n", n, name);
00419     }
00420 }
00421 
00422 static gvrender_engine_t psgen_engine = {
00423     psgen_begin_job,
00424     psgen_end_job,
00425     psgen_begin_graph,
00426     0,                          /* psgen_end_graph */
00427     psgen_begin_layer,
00428     0,                          /* psgen_end_layer */
00429     psgen_begin_page,
00430     psgen_end_page,
00431     psgen_begin_cluster,
00432     psgen_end_cluster,
00433     0,                          /* psgen_begin_nodes */
00434     0,                          /* psgen_end_nodes */
00435     0,                          /* psgen_begin_edges */
00436     0,                          /* psgen_end_edges */
00437     psgen_begin_node,
00438     psgen_end_node,
00439     psgen_begin_edge,
00440     psgen_end_edge,
00441     psgen_begin_anchor,
00442     0,                          /* psgen_end_anchor */
00443     psgen_textpara,
00444     0,                          /* psgen_resolve_color */
00445     psgen_ellipse,
00446     psgen_polygon,
00447     psgen_bezier,
00448     psgen_polyline,
00449     psgen_comment,
00450     psgen_library_shape,
00451 };
00452 
00453 static gvrender_features_t render_features_ps = {
00454     GVRENDER_DOES_TRANSFORM
00455         | GVRENDER_DOES_MAPS
00456         | GVRENDER_NO_BG
00457         | GVRENDER_DOES_MAP_RECTANGLE,
00458     4.,                         /* default pad - graph units */
00459     NULL,                       /* knowncolors */
00460     0,                          /* sizeof knowncolors */
00461     HSVA_DOUBLE,                /* color_type */
00462 };
00463 
00464 static gvdevice_features_t device_features_ps = {
00465     GVDEVICE_DOES_PAGES
00466         | GVDEVICE_DOES_LAYERS, /* flags */
00467     {36.,36.},                  /* default margin - points */
00468     {612.,792.},                /* default page width, height - points */
00469     {72.,72.},                  /* default dpi */
00470 };
00471 
00472 gvplugin_installed_t gvrender_ps_types[] = {
00473     {FORMAT_PS, "ps", 1, &psgen_engine, &render_features_ps},
00474     {0, NULL, 0, NULL, NULL}
00475 };
00476 
00477 gvplugin_installed_t gvdevice_ps_types[] = {
00478     {FORMAT_PS, "ps:ps", 1, NULL, &device_features_ps},
00479     {FORMAT_PS2, "ps2:ps", 1, NULL, &device_features_ps},
00480     {0, NULL, 0, NULL, NULL}
00481 };

Generated on Mon Mar 31 19:03:28 2008 for Graphviz by  doxygen 1.5.1