00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00030 #include "const.h"
00031
00032
00033
00034
00035
00036
00037 #define PDFMAX 14400
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
00080 cat_preamble(job, job->common->lib);
00081
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
00092
00093
00094
00095
00096
00097 if (!setupLatin1) {
00098 gvdevice_fputs(job, "setupLatin1\n");
00099 setupLatin1 = TRUE;
00100 }
00101
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
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
00154
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;
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
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,
00427 psgen_begin_layer,
00428 0,
00429 psgen_begin_page,
00430 psgen_end_page,
00431 psgen_begin_cluster,
00432 psgen_end_cluster,
00433 0,
00434 0,
00435 0,
00436 0,
00437 psgen_begin_node,
00438 psgen_end_node,
00439 psgen_begin_edge,
00440 psgen_end_edge,
00441 psgen_begin_anchor,
00442 0,
00443 psgen_textpara,
00444 0,
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.,
00459 NULL,
00460 0,
00461 HSVA_DOUBLE,
00462 };
00463
00464 static gvdevice_features_t device_features_ps = {
00465 GVDEVICE_DOES_PAGES
00466 | GVDEVICE_DOES_LAYERS,
00467 {36.,36.},
00468 {612.,792.},
00469 {72.,72.},
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 };