Graphviz  2.29.20120524.0446
plugin/core/gvrender_core_pic.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017 
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <stdarg.h>
00021 #include <ctype.h>
00022 
00023 #include "gvplugin_render.h"
00024 #include "gvplugin_device.h"
00025 #include "gvio.h"
00026 #include "agxbuf.h"
00027 #include "utils.h"
00028 #include "color.h"
00029 
00030 #include "const.h"
00031 
00032 /* Number of points to split splines into */
00033 #define BEZIERSUBDIVISION 6
00034 
00035 #define PIC_COORDS_PER_LINE (16)        /* to avoid stdio BUF overflow */
00036 
00037 typedef enum { FORMAT_PIC, } format_type;
00038 
00039 static int BezierSubdivision = 10;
00040 static int onetime = TRUE;
00041 static double Fontscale;
00042 
00043 /* There are a couple of ways to generate output: 
00044     1. generate for whatever size is given by the bounding box
00045        - the drawing at its "natural" size might not fit on a physical page
00046          ~ dot size specification can be used to scale the drawing
00047          ~ and it's not difficult for user to scale the pic output to fit (multiply 4 (3 distinct) numbers on 3 lines by a scale factor)
00048        - some troff implementations may clip large graphs
00049          ~ handle by scaling to manageable size
00050        - give explicit width and height as parameters to .PS
00051        - pic scale variable is reset to 1.0
00052        - fonts are printed as size specified by caller, modified by user scaling
00053     2. scale to fit on a physical page
00054        - requires an assumption of page size (GNU pic assumes 8.5x11.0 inches)
00055          ~ any assumption is bound to be wrong more often than right
00056        - requires separate scaling of font point sizes since pic's scale variable doesn't affect text
00057          ~ possible, as above
00058        - likewise for line thickness
00059        - GNU pic does this (except for fonts) if .PS is used without explicit width or height; DWB pic does not
00060          ~ pic variants likely to cause trouble
00061   The first approach is used here.
00062 */
00063 
00064 static const char *EscComment = ".\\\" ";       /* troff comment */
00065 static const char picgen_msghdr[] = "dot pic plugin: ";
00066 
00067 static void unsupported(char *s)
00068 {
00069     agerr(AGWARN, "%s%s unsupported\n", picgen_msghdr, s);
00070 }
00071 static void warn(char *s)
00072 {
00073     agerr(AGWARN, "%s%s\n", picgen_msghdr, s);
00074 }
00075 
00076 /* troff font mapping */
00077 typedef struct {
00078     char trname[3], *psname;
00079 } fontinfo;
00080 
00081 static fontinfo fonttab[] = {
00082     {"AB", "AvantGarde-Demi"},
00083     {"AI", "AvantGarde-BookOblique"},
00084     {"AR", "AvantGarde-Book"},
00085     {"AX", "AvantGarde-DemiOblique"},
00086     {"B ", "Times-Bold"},
00087     {"BI", "Times-BoldItalic"},
00088     {"CB", "Courier-Bold"},
00089     {"CO", "Courier"},
00090     {"CX", "Courier-BoldOblique"},
00091     {"H ", "Helvetica"},
00092     {"HB", "Helvetica-Bold"},
00093     {"HI", "Helvetica-Oblique"},
00094     {"HX", "Helvetica-BoldOblique"},
00095     {"Hb", "Helvetica-Narrow-Bold"},
00096     {"Hi", "Helvetica-Narrow-Oblique"},
00097     {"Hr", "Helvetica-Narrow"},
00098     {"Hx", "Helvetica-Narrow-BoldOblique"},
00099     {"I ", "Times-Italic"},
00100     {"KB", "Bookman-Demi"},
00101     {"KI", "Bookman-LightItalic"},
00102     {"KR", "Bookman-Light"},
00103     {"KX", "Bookman-DemiItalic"},
00104     {"NB", "NewCenturySchlbk-Bold"},
00105     {"NI", "NewCenturySchlbk-Italic"},
00106     {"NR", "NewCenturySchlbk-Roman"},
00107     {"NX", "NewCenturySchlbk-BoldItalic"},
00108     {"PA", "Palatino-Roman"},
00109     {"PB", "Palatino-Bold"},
00110     {"PI", "Palatino-Italic"},
00111     {"PX", "Palatino-BoldItalic"},
00112     {"R ", "Times-Roman"},
00113     {"S ", "Symbol"},
00114     {"ZD", "ZapfDingbats"},
00115     {"\000\000", (char *) 0}
00116 };
00117 
00118 static char *picfontname(char *psname)
00119 {
00120     char *rv;
00121     fontinfo *p;
00122 
00123     for (p = fonttab; p->psname; p++)
00124         if (strcmp(p->psname, psname) == 0)
00125             break;
00126     if (p->psname)
00127         rv = p->trname;
00128     else {
00129         agerr(AGERR, "%s%s is not a troff font\n", picgen_msghdr, psname);
00130         /* try base font names, e.g. Helvetica-Outline-Oblique -> Helvetica-Outline -> Helvetica */
00131         if ((rv = strrchr(psname, '-'))) {
00132             *rv = '\0';         /* psname is not specified as const ... */
00133             rv = picfontname(psname);
00134         } else
00135             rv = "R";
00136     }
00137     return rv;
00138 }
00139 
00140 static void pic_set_color(GVJ_t *job, char *name)
00141 {
00142     gvcolor_t color;
00143 
00144     colorxlate(name, &color, HSVA_DOUBLE);
00145     /* just v used to set grayscale value */
00146     gvprintf(job, "setfillval %f\n", color.u.HSVA[2]);
00147 }
00148 
00149 static void pic_set_style(GVJ_t *job, char **s)
00150 {
00151     const char *line, *p;
00152     char skip = 0;
00153     char buf[BUFSIZ];
00154 
00155     buf[0] = '\0';
00156     gvprintf(job, "define attrs%d %%", 0);
00157     while ((p = line = *s++)) {
00158         while (*p)
00159             p++;
00160         p++;
00161         while (*p) {
00162             if (!strcmp(line, "setlinewidth")) {        /* a hack to handle the user-defined (PS) style spec in proc3d.gv */
00163                 long n = atol(p);
00164 
00165                 sprintf(buf,
00166                         "oldlinethick = linethick;linethick = %ld * scalethickness / %.0f\n",
00167                         n, Fontscale);
00168                 skip = 1;
00169             } else
00170                 gvprintf(job, " %s", p);
00171             while (*p)
00172                 p++;
00173             p++;
00174         }
00175         if (!skip)
00176             gvprintf(job, " %s", line);
00177         skip = 0;
00178     }
00179     gvprintf(job, " %%\n");
00180     gvprintf(job, "%s", buf);
00181 }
00182 
00183 static void picptarray(GVJ_t *job, pointf * A, int n, int close)
00184 {
00185     int i;
00186     point p;
00187 
00188     for (i = 0; i < n; i++) {
00189         PF2P(A[i],p);
00190         gvprintf(job, " %d %d", p.x, p.y);
00191     }
00192     if (close) {
00193         PF2P(A[0],p);
00194         gvprintf(job, " %d %d", p.x, p.y);
00195     }
00196     gvputs(job, "\n");
00197 }
00198 
00199 static char *pic_string(char *s)
00200 {
00201     static char *buf = NULL;
00202     static int bufsize = 0;
00203     int pos = 0;
00204     char *p;
00205     unsigned char c;
00206 
00207     if (!buf) {
00208         bufsize = 64;
00209         buf = malloc(bufsize * sizeof(char));
00210     }
00211 
00212     p = buf;
00213     while ((c = *s++)) {
00214         if (pos > (bufsize - 8)) {
00215             bufsize *= 2;
00216             buf = realloc(buf, bufsize * sizeof(char));
00217             p = buf + pos;
00218         }
00219         if (isascii(c)) {
00220             if (c == '\\') {
00221                 *p++ = '\\';
00222                 pos++;
00223             }
00224             *p++ = c;
00225             pos++;
00226         } else {
00227             *p++ = '\\';
00228             sprintf(p, "%03o", c);
00229             p += 3;
00230             pos += 4;
00231         }
00232     }
00233     *p = '\0';
00234     return buf;
00235 }
00236 
00237 static int picColorResolve(int *new, int r, int g, int b)
00238 {
00239 #define maxColors 256
00240     static int top = 0;
00241     static short red[maxColors], green[maxColors], blue[maxColors];
00242     int c;
00243     int ct = -1;
00244     long rd, gd, bd, dist;
00245     long mindist = 3 * 255 * 255;       /* init to max poss dist */
00246 
00247     *new = 0;                   /* in case it is not a new color */
00248     for (c = 0; c < top; c++) {
00249         rd = (long) (red[c] - r);
00250         gd = (long) (green[c] - g);
00251         bd = (long) (blue[c] - b);
00252         dist = rd * rd + gd * gd + bd * bd;
00253         if (dist < mindist) {
00254             if (dist == 0)
00255                 return c;       /* Return exact match color */
00256             mindist = dist;
00257             ct = c;
00258         }
00259     }
00260     /* no exact match.  We now know closest, but first try to allocate exact */
00261     if (top++ == maxColors)
00262         return ct;              /* Return closest available color */
00263     red[c] = r;
00264     green[c] = g;
00265     blue[c] = b;
00266     *new = 1;                   /* flag new color */
00267     return c;                   /* Return newly allocated color */
00268 }
00269 
00270 static void pic_line_style(obj_state_t *obj, int *line_style, double *style_val)
00271 {
00272     switch (obj->pen) {
00273         case PEN_DASHED: 
00274             *line_style = 1;
00275             *style_val = 10.;
00276             break;
00277         case PEN_DOTTED:
00278             *line_style = 2;
00279             *style_val = 10.;
00280             break;
00281         case PEN_SOLID:
00282         default:
00283             *line_style = 0;
00284             *style_val = 0.;
00285             break;
00286     }
00287 }
00288 
00289 static void pic_comment(GVJ_t *job, char *str)
00290 {
00291     gvprintf(job, "%s %s\n", EscComment, str);
00292 }
00293 
00294 static void pic_begin_graph(GVJ_t * job)
00295 {
00296     obj_state_t *obj = job->obj;
00297 
00298     gvprintf(job, "%s Creator: %s version %s (%s)\n",
00299         EscComment, job->common->info[0], job->common->info[1], job->common->info[2]);
00300     gvprintf(job, "%s Title: %s\n", EscComment, agnameof(obj->u.g));
00301     gvprintf(job,
00302             "%s save point size and font\n.nr .S \\n(.s\n.nr DF \\n(.f\n",
00303             EscComment);
00304 }
00305 
00306 static void pic_end_graph(GVJ_t * job)
00307 {
00308     gvprintf(job,
00309             "%s restore point size and font\n.ps \\n(.S\n.ft \\n(DF\n",
00310             EscComment);
00311 }
00312 
00313 static void pic_begin_page(GVJ_t * job)
00314 {
00315     box pbr = job->pageBoundingBox;
00316     double height, width;
00317 
00318     if (onetime && job->rotation && (job->rotation != 90)) {
00319         unsupported("rotation");
00320         onetime = FALSE;
00321     }
00322     height = PS2INCH((double) (pbr.UR.y) - (double) (pbr.LL.y));
00323     width = PS2INCH((double) (pbr.UR.x) - (double) (pbr.LL.x));
00324     if (job->rotation == 90) {
00325         double temp = width;
00326         width = height;
00327         height = temp;
00328     }
00329     gvprintf(job, ".PS %.5f %.5f\n", width, height);
00330     gvprintf(job,
00331             "%s to change drawing size, multiply the width and height on the .PS line above and the number on the two lines below (rounded to the nearest integer) by a scale factor\n",
00332             EscComment);
00333     if (width > 0.0) {
00334         Fontscale = log10(width);
00335         Fontscale += 3.0 - (int) Fontscale;     /* between 3.0 and 4.0 */
00336     } else
00337         Fontscale = 3.0;
00338     Fontscale = pow(10.0, Fontscale);   /* a power of 10 times width, between 1000 and 10000 */
00339     gvprintf(job, ".nr SF %.0f\nscalethickness = %.0f\n", Fontscale,
00340             Fontscale);
00341     gvprintf(job,
00342             "%s don't change anything below this line in this drawing\n",
00343             EscComment);
00344     gvprintf(job,
00345             "%s non-fatal run-time pic version determination, version 2\n",
00346             EscComment);
00347     gvprintf(job,
00348             "boxrad=2.0 %s will be reset to 0.0 by gpic only\n",
00349             EscComment);
00350     gvprintf(job, "scale=1.0 %s required for comparisons\n",
00351             EscComment);
00352     gvprintf(job,
00353             "%s boxrad is now 0.0 in gpic, else it remains 2.0\n",
00354             EscComment);
00355     gvprintf(job,
00356             "%s dashwid is 0.1 in 10th Edition, 0.05 in DWB 2 and in gpic\n",
00357             EscComment);
00358     gvprintf(job,
00359             "%s fillval is 0.3 in 10th Edition (fill 0 means black), 0.5 in gpic (fill 0 means white), undefined in DWB 2\n",
00360             EscComment);
00361     gvprintf(job,
00362             "%s fill has no meaning in DWB 2, gpic can use fill or filled, 10th Edition uses fill only\n",
00363             EscComment);
00364     gvprintf(job,
00365             "%s DWB 2 doesn't use fill and doesn't define fillval\n",
00366             EscComment);
00367     gvprintf(job,
00368             "%s reset works in gpic and 10th edition, but isn't defined in DWB 2\n",
00369             EscComment);
00370     gvprintf(job, "%s DWB 2 compatibility definitions\n",
00371             EscComment);
00372     gvprintf(job,
00373             "if boxrad > 1.0 && dashwid < 0.075 then X\n\tfillval = 1;\n\tdefine fill Y Y;\n\tdefine solid Y Y;\n\tdefine reset Y scale=1.0 Y;\nX\n");
00374     gvprintf(job, "reset %s set to known state\n", EscComment);
00375     gvprintf(job, "%s GNU pic vs. 10th Edition d\\(e'tente\n",
00376             EscComment);
00377     gvprintf(job,
00378             "if fillval > 0.4 then X\n\tdefine setfillval Y fillval = 1 - Y;\n\tdefine bold Y thickness 2 Y;\n");
00379     gvprintf(job,
00380             "\t%s if you use gpic and it barfs on encountering \"solid\",\n",
00381             EscComment);
00382     gvprintf(job,
00383             "\t%s\tinstall a more recent version of gpic or switch to DWB or 10th Edition pic;\n",
00384             EscComment);
00385     gvprintf(job,
00386             "\t%s\tsorry, the groff folks changed gpic; send any complaint to them;\n",
00387             EscComment);
00388     gvprintf(job,
00389             "X else Z\n\tdefine setfillval Y fillval = Y;\n\tdefine bold Y Y;\n\tdefine filled Y fill Y;\nZ\n");
00390     gvprintf(job,
00391             "%s arrowhead has no meaning in DWB 2, arrowhead = 7 makes filled arrowheads in gpic and in 10th Edition\n",
00392             EscComment);
00393     gvprintf(job,
00394             "%s arrowhead is undefined in DWB 2, initially 1 in gpic, 2 in 10th Edition\n",
00395             EscComment);
00396     gvprintf(job, "arrowhead = 7 %s not used by graphviz\n",
00397             EscComment);
00398     gvprintf(job,
00399             "%s GNU pic supports a boxrad variable to draw boxes with rounded corners; DWB and 10th Ed. do not\n",
00400             EscComment);
00401     gvprintf(job, "boxrad = 0 %s no rounded corners in graphviz\n",
00402             EscComment);
00403     gvprintf(job,
00404             "%s GNU pic supports a linethick variable to set line thickness; DWB and 10th Ed. do not\n",
00405             EscComment);
00406     gvprintf(job, "linethick = 0; oldlinethick = linethick\n");
00407     gvprintf(job,
00408             "%s .PS w/o args causes GNU pic to scale drawing to fit 8.5x11 paper; DWB does not\n",
00409             EscComment);
00410     gvprintf(job,
00411             "%s maxpsht and maxpswid have no meaning in DWB 2.0, set page boundaries in gpic and in 10th Edition\n",
00412             EscComment);
00413     gvprintf(job,
00414             "%s maxpsht and maxpswid are predefined to 11.0 and 8.5 in gpic\n",
00415             EscComment);
00416     gvprintf(job, "maxpsht = %f\nmaxpswid = %f\n", height, width);
00417     gvprintf(job, "Dot: [\n");
00418     gvprintf(job,
00419             "define attrs0 %% %%; define unfilled %% %%; define rounded %% %%; define diagonals %% %%\n");
00420 }
00421 
00422 static void pic_end_page(GVJ_t * job)
00423 {
00424     gvprintf(job,
00425         "]\n.PE\n");
00426 }
00427 
00428 static void pic_textpara(GVJ_t * job, pointf p, textpara_t * para)
00429 {
00430     static char *lastname;
00431     static int lastsize;
00432     int sz;
00433 
00434     switch (para->just) {
00435     case 'l': 
00436         break;
00437     case 'r': 
00438         p.x -= para->width;
00439         break;
00440     default:
00441     case 'n': 
00442         p.x -= para->width / 2;
00443         break;
00444     }
00445 #ifdef NOTDEF
00446     /* Why on earth would we want this? SCN  11/29/2001 */
00447     p.y -= para->fontsize / (5.0 * POINTS_PER_INCH);
00448 #endif
00449     /* Why on earth would we do this either. But it works. SCN 2/26/2002 */
00450     p.y += para->fontsize / (3.0 * POINTS_PER_INCH);
00451     p.x += para->width / (2.0 * POINTS_PER_INCH);
00452 
00453     if (para->fontname && (!(lastname) || strcmp(lastname, para->fontname))) {
00454         gvprintf(job, ".ft %s\n", picfontname(para->fontname));
00455         lastname = para->fontname;
00456     }
00457     if ((sz = (int)para->fontsize) < 1);
00458         sz = 1;
00459     if (sz != lastsize) {
00460         gvprintf(job, ".ps %d*\\n(SFu/%.0fu\n", sz, Fontscale);
00461         lastsize = sz;
00462     }
00463     gvprintf(job, "\"%s\" at (%.5f,%.5f);\n",
00464             pic_string(para->str), p.x, p.y);
00465 }
00466 
00467 static void pic_ellipse(GVJ_t * job, pointf * A, int filled)
00468 {
00469     /* A[] contains 2 points: the center and corner. */
00470 
00471     gvprintf(job,
00472                 "ellipse attrs%d %swid %.5f ht %.5f at (%.5f,%.5f);\n", 1,
00473                 filled ? "fill " : "",
00474                 PS2INCH(2*(A[1].x - A[0].x)),
00475                 PS2INCH(2*(A[1].y - A[0].y)),
00476                 PS2INCH(A[0].x),
00477                 PS2INCH(A[0].y));
00478 }
00479 
00480 static void pic_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00481 //            start_y, end_x, end_y);
00482               int arrow_at_end, int filled)
00483 {
00484     obj_state_t *obj = job->obj;
00485 
00486     int object_code = 3;        /* always 3 for spline */
00487     int sub_type;
00488     int line_style;             /* solid, dotted, dashed */
00489     int thickness = obj->penwidth;
00490     int pen_color = obj->pencolor.u.index;
00491     int fill_color = obj->fillcolor.u.index;
00492     int pen_style = 0;          /* not used */
00493     int area_fill;
00494     double style_val;
00495     int cap_style = 0;
00496     int forward_arrow = 0;
00497     int backward_arrow = 0;
00498     int npoints = n;
00499     int i;
00500 
00501     pointf pf, V[4];
00502     point p;
00503     int j, step;
00504     int count = 0;
00505     int size;
00506 
00507     char *buffer;
00508     char *buf;
00509     buffer =
00510         malloc((npoints + 1) * (BEZIERSUBDIVISION +
00511                                 1) * 20 * sizeof(char));
00512     buf = buffer;
00513 
00514     pic_line_style(obj, &line_style, &style_val);
00515 
00516     if (filled) {
00517         sub_type = 5;     /* closed X-spline */
00518         area_fill = 20;   /* fully saturated color */
00519         fill_color = job->obj->fillcolor.u.index;
00520     }
00521     else {
00522         sub_type = 4;     /* opened X-spline */
00523         area_fill = -1;
00524         fill_color = 0;
00525     }
00526     V[3].x = A[0].x;
00527     V[3].y = A[0].y;
00528     /* Write first point in line */
00529     count++;
00530     PF2P(A[0], p);
00531     size = sprintf(buf, " %d %d", p.x, p.y);
00532     buf += size;
00533     /* write subsequent points */
00534     for (i = 0; i + 3 < n; i += 3) {
00535         V[0] = V[3];
00536         for (j = 1; j <= 3; j++) {
00537             V[j].x = A[i + j].x;
00538             V[j].y = A[i + j].y;
00539         }
00540         for (step = 1; step <= BEZIERSUBDIVISION; step++) {
00541             count++;
00542             pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
00543             PF2P(pf, p);
00544             size = sprintf(buf, " %d %d", p.x, p.y);
00545             buf += size;
00546         }
00547     }
00548 
00549 //    gvprintf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
00550 //            object_code,
00551 //            sub_type,
00552 //            line_style,
00553 //            thickness,
00554 //            pen_color,
00555 //            fill_color,
00556 //            depth,
00557 //            pen_style,
00558 //            area_fill,
00559 //            style_val, cap_style, forward_arrow, backward_arrow, count);
00560 
00561     gvprintf(job, " %s\n", buffer);      /* print points */
00562     free(buffer);
00563     for (i = 0; i < count; i++) {
00564         gvprintf(job, " %d", i % (count - 1) ? 1 : 0);   /* -1 on all */
00565     }
00566     gvputs(job, "\n");
00567 }
00568 
00569 static void pic_polygon(GVJ_t * job, pointf * A, int n, int filled)
00570 {
00571     obj_state_t *obj = job->obj;
00572 
00573     int object_code = 2;        /* always 2 for polyline */
00574     int sub_type = 3;           /* always 3 for polygon */
00575     int line_style;             /* solid, dotted, dashed */
00576     int thickness = obj->penwidth;
00577     int pen_color = obj->pencolor.u.index;
00578     int fill_color = obj->fillcolor.u.index;
00579     int pen_style = 0;          /* not used */
00580     int area_fill = filled ? 20 : -1;
00581     double style_val;
00582     int join_style = 0;
00583     int cap_style = 0;
00584     int radius = 0;
00585     int forward_arrow = 0;
00586     int backward_arrow = 0;
00587     int npoints = n + 1;
00588 
00589     pic_line_style(obj, &line_style, &style_val);
00590 
00591 //    gvprintf(job,
00592 //            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
00593 //            object_code, sub_type, line_style, thickness, pen_color,
00594 //            fill_color, depth, pen_style, area_fill, style_val, join_style,
00595 //            cap_style, radius, forward_arrow, backward_arrow, npoints);
00596     picptarray(job, A, n, 1);        /* closed shape */
00597 }
00598 
00599 static void pic_polyline(GVJ_t * job, pointf * A, int n)
00600 {
00601     obj_state_t *obj = job->obj;
00602 
00603     int object_code = 2;        /* always 2 for polyline */
00604     int sub_type = 1;           /* always 1 for polyline */
00605     int line_style;             /* solid, dotted, dashed */
00606     int thickness = obj->penwidth;
00607     int pen_color = obj->pencolor.u.index;
00608     int fill_color = 0;
00609     int pen_style = 0;          /* not used */
00610     int area_fill = 0;
00611     double style_val;
00612     int join_style = 0;
00613     int cap_style = 0;
00614     int radius = 0;
00615     int forward_arrow = 0;
00616     int backward_arrow = 0;
00617     int npoints = n;
00618 
00619     pic_line_style(obj, &line_style, &style_val);
00620 
00621 //    gvprintf(job,
00622 //            "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
00623 //            object_code, sub_type, line_style, thickness, pen_color,
00624 //            fill_color, depth, pen_style, area_fill, style_val, join_style,
00625 //            cap_style, radius, forward_arrow, backward_arrow, npoints);
00626     picptarray(job, A, n, 0);        /* open shape */
00627 }
00628 
00629 gvrender_engine_t pic_engine = {
00630     0,                          /* pic_begin_job */
00631     0,                          /* pic_end_job */
00632     pic_begin_graph,
00633     pic_end_graph,
00634     0,                          /* pic_begin_layer */
00635     0,                          /* pic_end_layer */
00636     pic_begin_page,
00637     pic_end_page,
00638     0,                          /* pic_begin_cluster */
00639     0,                          /* pic_end_cluster */
00640     0,                          /* pic_begin_nodes */
00641     0,                          /* pic_end_nodes */
00642     0,                          /* pic_begin_edges */
00643     0,                          /* pic_end_edges */
00644     0,                          /* pic_begin_node */
00645     0,                          /* pic_end_node */
00646     0,                          /* pic_begin_edge */
00647     0,                          /* pic_end_edge */
00648     0,                          /* pic_begin_anchor */
00649     0,                          /* pic_end_anchor */
00650     0,                          /* pic_begin_label */
00651     0,                          /* pic_end_label */
00652     pic_textpara,
00653     0,                          /* pic_resolve_color */
00654     pic_ellipse,
00655     pic_polygon,
00656     pic_bezier,
00657     pic_polyline,
00658     pic_comment,
00659     0,                          /* pic_library_shape */
00660 };
00661 
00662 
00663 static gvrender_features_t render_features_pic = {
00664     0,                          /* flags */
00665     4.,                         /* default pad - graph units */
00666     NULL,                       /* knowncolors */
00667     0,                          /* sizeof knowncolors */
00668     HSVA_DOUBLE,                /* color_type */
00669 };
00670 
00671 static gvdevice_features_t device_features_pic = {
00672     0,                          /* flags */
00673     {0.,0.},                    /* default margin - points */
00674     {0.,0.},                    /* default page width, height - points */
00675     {72.,72.},                  /* default dpi */
00676 };
00677 
00678 gvplugin_installed_t gvrender_pic_types[] = {
00679     {FORMAT_PIC, "pic", -1, &pic_engine, &render_features_pic},
00680     {0, NULL, 0, NULL, NULL}
00681 };
00682 
00683 gvplugin_installed_t gvdevice_pic_types[] = {
00684     {FORMAT_PIC, "pic:pic", -1, NULL, &device_features_pic},
00685     {0, NULL, 0, NULL, NULL}
00686 };