Graphviz  2.29.20120524.0446
plugin/core/gvrender_core_hpgl.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 /* FIXME - incomplete replacement for codegen */
00015 
00016 #ifdef HAVE_CONFIG_H
00017 #include "config.h"
00018 #endif
00019 
00020 #include <stdarg.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <ctype.h>
00024 
00025 #ifdef WIN32
00026 #include <io.h>
00027 #include "compat.h"
00028 #endif
00029 
00030 #include "macros.h"
00031 #include "const.h"
00032 
00033 #include "gvdevice.h"
00034 #include "gvplugin_render.h"
00035 #include "gvplugin_device.h"
00036 #include "agxbuf.h"
00037 #include "utils.h"
00038 #include "color.h"
00039 
00040 /* Number of points to split splines into */
00041 #define BEZIERSUBDIVISION 6
00042 
00043 typedef enum { FORMAT_HPGL, } format_type;
00044 
00045 static int Depth;
00046 
00047 static void hpglptarray(GVJ_t *job, pointf * A, int n, int close)
00048 {
00049     int i;
00050     point p;
00051 
00052     for (i = 0; i < n; i++) {
00053         PF2P(A[i],p);
00054         gvprintf(job, " %d %d", p.x, p.y);
00055     }
00056     if (close) {
00057         PF2P(A[0],p);
00058         gvprintf(job, " %d %d", p.x, p.y);
00059     }
00060     gvputs(job, "\n");
00061 }
00062 
00063 static char *hpgl_string(char *s)
00064 {
00065     static char *buf = NULL;
00066     static int bufsize = 0;
00067     int pos = 0;
00068     char *p;
00069     unsigned char c;
00070 
00071     if (!buf) {
00072         bufsize = 64;
00073         buf = malloc(bufsize * sizeof(char));
00074     }
00075 
00076     p = buf;
00077     while ((c = *s++)) {
00078         if (pos > (bufsize - 8)) {
00079             bufsize *= 2;
00080             buf = realloc(buf, bufsize * sizeof(char));
00081             p = buf + pos;
00082         }
00083         if (isascii(c)) {
00084             if (c == '\\') {
00085                 *p++ = '\\';
00086                 pos++;
00087             }
00088             *p++ = c;
00089             pos++;
00090         } else {
00091             *p++ = '\\';
00092             sprintf(p, "%03o", c);
00093             p += 3;
00094             pos += 4;
00095         }
00096     }
00097     *p = '\0';
00098     return buf;
00099 }
00100 
00101 static int hpglColorResolve(int *new, int r, int g, int b)
00102 {
00103 #define maxColors 256
00104     static int top = 0;
00105     static short red[maxColors], green[maxColors], blue[maxColors];
00106     int c;
00107     int ct = -1;
00108     long rd, gd, bd, dist;
00109     long mindist = 3 * 255 * 255;       /* init to max poss dist */
00110 
00111     *new = 0;                   /* in case it is not a new color */
00112     for (c = 0; c < top; c++) {
00113         rd = (long) (red[c] - r);
00114         gd = (long) (green[c] - g);
00115         bd = (long) (blue[c] - b);
00116         dist = rd * rd + gd * gd + bd * bd;
00117         if (dist < mindist) {
00118             if (dist == 0)
00119                 return c;       /* Return exact match color */
00120             mindist = dist;
00121             ct = c;
00122         }
00123     }
00124     /* no exact match.  We now know closest, but first try to allocate exact */
00125     if (top++ == maxColors)
00126         return ct;              /* Return closest available color */
00127     red[c] = r;
00128     green[c] = g;
00129     blue[c] = b;
00130     *new = 1;                   /* flag new color */
00131     return c;                   /* Return newly allocated color */
00132 }
00133 
00134 /* this table is in xfig color index order */
00135 static char *hpglcolor[] = {
00136     "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", (char *) NULL
00137 };
00138 
00139 static void hpgl_resolve_color(GVJ_t *job, gvcolor_t * color)
00140 {
00141     int object_code = 0;        /* always 0 for color */
00142     int i, new;
00143 
00144     switch (color->type) {
00145         case COLOR_STRING:
00146             for (i = 0; hpglcolor[i]; i++) {
00147                 if (streq(hpglcolor[i], color->u.string)) {
00148                     color->u.index = i;
00149                     break;
00150                 }
00151             }
00152             break;
00153         case RGBA_BYTE:
00154             i = 32 + hpglColorResolve(&new,
00155                         color->u.rgba[0],
00156                         color->u.rgba[1],
00157                         color->u.rgba[2]);
00158             if (new)
00159                 gvprintf(job, "%d %d #%02x%02x%02x\n",
00160                         object_code, i,
00161                         color->u.rgba[0],
00162                         color->u.rgba[1],
00163                         color->u.rgba[2]);
00164             color->u.index = i;
00165             break;
00166         default:
00167             assert(0);  /* internal error */
00168     }
00169 
00170     color->type = COLOR_INDEX;
00171 }
00172 
00173 static void hpgl_line_style(obj_state_t *obj, int *line_style, double *style_val)
00174 {
00175     switch (obj->pen) {
00176         case PEN_DASHED: 
00177             *line_style = 1;
00178             *style_val = 10.;
00179             break;
00180         case PEN_DOTTED:
00181             *line_style = 2;
00182             *style_val = 10.;
00183             break;
00184         case PEN_SOLID:
00185         default:
00186             *line_style = 0;
00187             *style_val = 0.;
00188             break;
00189     }
00190 }
00191 
00192 static void hpgl_comment(GVJ_t *job, char *str)
00193 {
00194     gvprintf(job, "# %s\n", str);
00195 }
00196 
00197 static void hpgl_begin_graph(GVJ_t * job)
00198 {
00199     obj_state_t *obj = job->obj;
00200 
00201     gvputs(job, "#FIG 3.2\n");
00202     gvprintf(job, "# Generated by %s version %s (%s)\n",
00203         job->common->info[0], job->common->info[1], job->common->info[2]);
00204     gvprintf(job, "# Title: %s\n", obj->u.g->name);
00205     gvprintf(job, "# Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
00206     gvputs(job, "Portrait\n"); /* orientation */
00207     gvputs(job, "Center\n");   /* justification */
00208     gvputs(job, "Inches\n");   /* units */
00209     gvputs(job, "Letter\n");   /* papersize */
00210     gvputs(job, "100.00\n");   /* magnification % */
00211     gvputs(job, "Single\n");   /* multiple-page */
00212     gvputs(job, "-2\n");       /* transparent color (none) */
00213     gvputs(job, "1200");             /* resolution */
00214     gvputs(job, " 2\n");       /* coordinate system (upper left) */
00215 }
00216 
00217 static void hpgl_end_graph(GVJ_t * job)
00218 {
00219     gvputs(job, "# end of FIG file\n");
00220 }
00221 
00222 static void hpgl_begin_page(GVJ_t * job)
00223 {
00224     Depth = 2;
00225 }
00226 
00227 static void hpgl_begin_node(GVJ_t * job)
00228 {
00229     Depth = 1;
00230 }
00231 
00232 static void hpgl_end_node(GVJ_t * job)
00233 {
00234     Depth = 2;
00235 }
00236 
00237 static void hpgl_begin_edge(GVJ_t * job)
00238 {
00239     Depth = 0;
00240 }
00241 
00242 static void hpgl_end_edge(GVJ_t * job)
00243 {
00244     Depth = 2;
00245 }
00246 
00247 static void hpgl_textpara(GVJ_t * job, pointf p, textpara_t * para)
00248 {
00249     obj_state_t *obj = job->obj;
00250 
00251     int object_code = 4;        /* always 4 for text */
00252     int sub_type = 0;           /* text justification */
00253     int color = obj->pencolor.u.index;
00254     int depth = Depth;
00255     int pen_style = 0;          /* not used */
00256     int font = -1;              /* init to xfig's default font */
00257     double font_size = para->fontsize * job->zoom;
00258     double angle = job->rotation ? (M_PI / 2.0) : 0.0;
00259     int font_flags = 4;         /* PostScript font */
00260     double height = 0.0;
00261     double length = 0.0;
00262 
00263     if (para->postscript_alias) /* if it is a standard postscript font */
00264         font = para->postscript_alias->xfig_code; 
00265 
00266     switch (para->just) {
00267     case 'l':
00268         sub_type = 0;
00269         break;
00270     case 'r':
00271         sub_type = 2;
00272         break;
00273     default:
00274     case 'n':
00275         sub_type = 1;
00276         break;
00277     }
00278 
00279     gvprintf(job,
00280             "%d %d %d %d %d %d %.1f %.4f %d %.1f %.1f %d %d %s\\001\n",
00281             object_code, sub_type, color, depth, pen_style, font,
00282             font_size, angle, font_flags, height, length, ROUND(p.x), ROUND(p.y),
00283             hpgl_string(para->str));
00284 }
00285 
00286 static void hpgl_ellipse(GVJ_t * job, pointf * A, int filled)
00287 {
00288     obj_state_t *obj = job->obj;
00289 
00290     int object_code = 1;        /* always 1 for ellipse */
00291     int sub_type = 1;           /* ellipse defined by radii */
00292     int line_style;             /* solid, dotted, dashed */
00293     int thickness = obj->penwidth;
00294     int pen_color = obj->pencolor.u.index;
00295     int fill_color = obj->fillcolor.u.index;
00296     int depth = Depth;
00297     int pen_style = 0;          /* not used */
00298     int area_fill = filled ? 20 : -1;
00299     double style_val;
00300     int direction = 0;
00301     double angle = 0.0;
00302     int center_x, center_y, radius_x, radius_y;
00303     int start_x, start_y, end_x, end_y;
00304 
00305     hpgl_line_style(obj, &line_style, &style_val);
00306 
00307     start_x = center_x = ROUND(A[0].x);
00308     start_y = center_y = ROUND(A[0].y);
00309     radius_x = ROUND(A[1].x - A[0].x);
00310     radius_y = ROUND(A[1].y - A[0].y);
00311     end_x = ROUND(A[1].x);
00312     end_y = ROUND(A[1].y);
00313 
00314     gvprintf(job,
00315             "%d %d %d %d %d %d %d %d %d %.3f %d %.4f %d %d %d %d %d %d %d %d\n",
00316             object_code, sub_type, line_style, thickness, pen_color,
00317             fill_color, depth, pen_style, area_fill, style_val, direction,
00318             angle, center_x, center_y, radius_x, radius_y, start_x,
00319             start_y, end_x, end_y);
00320 }
00321 
00322 static void hpgl_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00323               int arrow_at_end, int filled)
00324 {
00325     obj_state_t *obj = job->obj;
00326 
00327     int object_code = 3;        /* always 3 for spline */
00328     int sub_type;
00329     int line_style;             /* solid, dotted, dashed */
00330     int thickness = obj->penwidth;
00331     int pen_color = obj->pencolor.u.index;
00332     int fill_color = obj->fillcolor.u.index;
00333     int depth = Depth;
00334     int pen_style = 0;          /* not used */
00335     int area_fill;
00336     double style_val;
00337     int cap_style = 0;
00338     int forward_arrow = 0;
00339     int backward_arrow = 0;
00340     int npoints = n;
00341     int i;
00342 
00343     pointf pf, V[4];
00344     point p;
00345     int j, step;
00346     int count = 0;
00347     int size;
00348 
00349     char *buffer;
00350     char *buf;
00351     buffer =
00352         malloc((npoints + 1) * (BEZIERSUBDIVISION +
00353                                 1) * 20 * sizeof(char));
00354     buf = buffer;
00355 
00356     hpgl_line_style(obj, &line_style, &style_val);
00357 
00358     if (filled) {
00359         sub_type = 5;     /* closed X-spline */
00360         area_fill = 20;   /* fully saturated color */
00361         fill_color = job->obj->fillcolor.u.index;
00362     }
00363     else {
00364         sub_type = 4;     /* opened X-spline */
00365         area_fill = -1;
00366         fill_color = 0;
00367     }
00368     V[3].x = A[0].x;
00369     V[3].y = A[0].y;
00370     /* Write first point in line */
00371     count++;
00372     PF2P(A[0], p);
00373     size = sprintf(buf, " %d %d", p.x, p.y);
00374     buf += size;
00375     /* write subsequent points */
00376     for (i = 0; i + 3 < n; i += 3) {
00377         V[0] = V[3];
00378         for (j = 1; j <= 3; j++) {
00379             V[j].x = A[i + j].x;
00380             V[j].y = A[i + j].y;
00381         }
00382         for (step = 1; step <= BEZIERSUBDIVISION; step++) {
00383             count++;
00384             pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
00385             PF2P(pf, p);
00386             size = sprintf(buf, " %d %d", p.x, p.y);
00387             buf += size;
00388         }
00389     }
00390 
00391     gvprintf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
00392             object_code,
00393             sub_type,
00394             line_style,
00395             thickness,
00396             pen_color,
00397             fill_color,
00398             depth,
00399             pen_style,
00400             area_fill,
00401             style_val, cap_style, forward_arrow, backward_arrow, count);
00402 
00403     gvprintf(job, " %s\n", buffer);      /* print points */
00404     free(buffer);
00405     for (i = 0; i < count; i++) {
00406         gvprintf(job, " %d", i % (count - 1) ? 1 : 0);   /* -1 on all */
00407     }
00408     gvputs(job, "\n");
00409 }
00410 
00411 static void hpgl_polygon(GVJ_t * job, pointf * A, int n, int filled)
00412 {
00413     obj_state_t *obj = job->obj;
00414 
00415     int object_code = 2;        /* always 2 for polyline */
00416     int sub_type = 3;           /* always 3 for polygon */
00417     int line_style;             /* solid, dotted, dashed */
00418     int thickness = obj->penwidth;
00419     int pen_color = obj->pencolor.u.index;
00420     int fill_color = obj->fillcolor.u.index;
00421     int depth = Depth;
00422     int pen_style = 0;          /* not used */
00423     int area_fill = filled ? 20 : -1;
00424     double style_val;
00425     int join_style = 0;
00426     int cap_style = 0;
00427     int radius = 0;
00428     int forward_arrow = 0;
00429     int backward_arrow = 0;
00430     int npoints = n + 1;
00431 
00432     hpgl_line_style(obj, &line_style, &style_val);
00433 
00434     gvprintf(job,
00435             "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
00436             object_code, sub_type, line_style, thickness, pen_color,
00437             fill_color, depth, pen_style, area_fill, style_val, join_style,
00438             cap_style, radius, forward_arrow, backward_arrow, npoints);
00439     hpglptarray(job, A, n, 1);        /* closed shape */
00440 }
00441 
00442 static void hpgl_polyline(GVJ_t * job, pointf * A, int n)
00443 {
00444     obj_state_t *obj = job->obj;
00445 
00446     int object_code = 2;        /* always 2 for polyline */
00447     int sub_type = 1;           /* always 1 for polyline */
00448     int line_style;             /* solid, dotted, dashed */
00449     int thickness = obj->penwidth;
00450     int pen_color = obj->pencolor.u.index;
00451     int fill_color = 0;
00452     int depth = Depth;
00453     int pen_style = 0;          /* not used */
00454     int area_fill = 0;
00455     double style_val;
00456     int join_style = 0;
00457     int cap_style = 0;
00458     int radius = 0;
00459     int forward_arrow = 0;
00460     int backward_arrow = 0;
00461     int npoints = n;
00462 
00463     hpgl_line_style(obj, &line_style, &style_val);
00464 
00465     gvprintf(job,
00466             "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
00467             object_code, sub_type, line_style, thickness, pen_color,
00468             fill_color, depth, pen_style, area_fill, style_val, join_style,
00469             cap_style, radius, forward_arrow, backward_arrow, npoints);
00470     hpglptarray(job, A, n, 0);        /* open shape */
00471 }
00472 
00473 gvrender_engine_t hpgl_engine = {
00474     0,                          /* hpgl_begin_job */
00475     0,                          /* hpgl_end_job */
00476     hpgl_begin_graph,
00477     hpgl_end_graph,
00478     0,                          /* hpgl_begin_layer */
00479     0,                          /* hpgl_end_layer */
00480     hpgl_begin_page,
00481     0,                          /* hpgl_end_page */
00482     0,                          /* hpgl_begin_cluster */
00483     0,                          /* hpgl_end_cluster */
00484     0,                          /* hpgl_begin_nodes */
00485     0,                          /* hpgl_end_nodes */
00486     0,                          /* hpgl_begin_edges */
00487     0,                          /* hpgl_end_edges */
00488     hpgl_begin_node,
00489     hpgl_end_node,
00490     hpgl_begin_edge,
00491     hpgl_end_edge,
00492     0,                          /* hpgl_begin_anchor */
00493     0,                          /* hpgl_end_anchor */
00494     0,                          /* hpgl_begin_label */
00495     0,                          /* hpgl_end_label */
00496     hpgl_textpara,
00497     hpgl_resolve_color,
00498     hpgl_ellipse,
00499     hpgl_polygon,
00500     hpgl_bezier,
00501     hpgl_polyline,
00502     hpgl_comment,
00503     0,                          /* hpgl_library_shape */
00504 };
00505 
00506 static gvrender_features_t render_features_hpgl = {
00507     0,                          /* flags */
00508     4.,                         /* default pad - graph units */
00509     NULL,                       /* knowncolors */
00510     0,                          /* sizeof knowncolors */
00511     HSVA_DOUBLE,                /* color_type */
00512 };
00513 
00514 static gvdevice_features_t device_features_hpgl = {
00515     0,                          /* flags */
00516     {0.,0.},                    /* default margin - points */
00517     {0.,0.},                    /* default page width, height - points */
00518     {72.,72.},                  /* default dpi */
00519 };
00520 
00521 gvplugin_installed_t gvrender_hpgl_types[] = {
00522     {FORMAT_HPGL, "hpgl", -1, &hpgl_engine, &render_features_hpgl},
00523     {0, NULL, 0, NULL, NULL}
00524 };
00525 
00526 gvplugin_installed_t gvdevice_hpgl_types[] = {
00527     {FORMAT_HPGL, "hpgl:hpgl", -1, NULL, &device_features_hpgl},
00528     {0, NULL, 0, NULL, NULL}
00529 };