From: erg Date: Thu, 22 Mar 2007 22:02:34 +0000 (+0000) Subject: Version 1.2 of xdot supporting images; X-Git-Tag: LAST_LIBGRAPH~32^2~5610 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=50624d78c63977f14f18c64823e6cfad5dd044e1;p=graphviz Version 1.2 of xdot supporting images; fixes to image code - various calculations were incorrect, use unscaled image. --- diff --git a/lib/common/htmltable.c b/lib/common/htmltable.c index d642507d3..5c1da78d8 100644 --- a/lib/common/htmltable.c +++ b/lib/common/htmltable.c @@ -409,7 +409,7 @@ emit_html_img(GVJ_t * job, htmlimg_t * cp, htmlenv_t * env) A[3].x = A[0].x; A[3].y = A[2].y; - gvrender_usershape(job, cp->src, A, 4, TRUE); + gvrender_usershape(job, cp->src, A, 4, TRUE, 0); } static void diff --git a/lib/common/shapes.c b/lib/common/shapes.c index b2e6309de..e83d5cc58 100644 --- a/lib/common/shapes.c +++ b/lib/common/shapes.c @@ -564,8 +564,8 @@ static void poly_init(node_t * n) else { imagesize.x = imagesize.y = 0; } - dimen.x = MAX(dimen.x, imagesize.x); - dimen.y = MAX(dimen.y, imagesize.y); + dimen.x = MAX(dimen.x, imagesize.x+2); + dimen.y = MAX(dimen.y, imagesize.y+2); } } @@ -1261,7 +1261,41 @@ static void poly_gencode(GVJ_t * job, node_t * n) pencolor(job, n); /* emit pen color */ } + /* if no boundary but filled, set boundary color to fill color */ + if ((peripheries == 0) && filled) { + char *color; + peripheries = 1; + color = findFill(n); + if (color[0]) + gvrender_set_pencolor(job, color); + } if (ND_shape(n)->usershape) { + int shapefilled = filled; + if (filled) { + for (i = 0; i < sides; i++) { + P = vertices[i]; + AF[i].x = P.x * xsize; + AF[i].y = P.y * ysize; + if (sides > 2) { + AF[i].x += (double)ND_coord_i(n).x; + AF[i].y += (double)ND_coord_i(n).y; + } + } + if (sides <= 2) { + pointf PF; + + P2PF(ND_coord_i(n), PF); + gvrender_ellipse(job, PF, AF[0].x, AF[0].y, filled); + if (style & DIAGONALS) { + Mcircle_hack(job, n); + } + } else if (style & (ROUNDED | DIAGONALS)) { + node_round_corners(job, n, AF, sides, style); + } else { + gvrender_polygon(job, AF, sides, filled); + } + filled = FALSE; + } for (i = 0; i < sides; i++) { P = vertices[i]; AF[i].x = P.x * xsize; @@ -1274,17 +1308,9 @@ static void poly_gencode(GVJ_t * job, node_t * n) name = ND_shape(n)->name; if (streq(name, "custom")) name = agget(n, "shapefile"); - gvrender_usershape(job, name, AF, sides, filled); - filled = FALSE; - } - /* if no boundary but filled, set boundary color to fill color */ - if ((peripheries == 0) && filled) { - char *color; - peripheries = 1; - color = findFill(n); - if (color[0]) - gvrender_set_pencolor(job, color); + gvrender_usershape(job, name, AF, sides, shapefilled, FALSE); } + for (j = 0; j < peripheries; j++) { for (i = 0; i < sides; i++) { P = vertices[i + j * sides]; diff --git a/lib/gvc/gvcproc.h b/lib/gvc/gvcproc.h index cb23e2677..3cd1bf28c 100644 --- a/lib/gvc/gvcproc.h +++ b/lib/gvc/gvcproc.h @@ -63,6 +63,7 @@ extern "C" { extern void gvloadimage(GVJ_t *job, usershape_t *us, boxf b, boolean filled, char *target); /* usershapes */ + extern point gvusershape_size_dpi(usershape_t*, pointf); extern point gvusershape_size(graph_t *g, char *name); extern usershape_t *gvusershape_find(char *name); @@ -116,7 +117,7 @@ extern "C" { int arrow_at_start, int arrow_at_end, boolean filled); extern void gvrender_polyline(GVJ_t * job, pointf * AF, int n); extern void gvrender_comment(GVJ_t * job, char *str); - extern void gvrender_usershape(GVJ_t * job, char *name, pointf * AF, int n, boolean filled); + extern void gvrender_usershape(GVJ_t * job, char *name, pointf * AF, int n, boolean filled, boolean expand); /* layout */ diff --git a/lib/gvc/gvrender.c b/lib/gvc/gvrender.c index 048d918cc..7a8e9f0f1 100644 --- a/lib/gvc/gvrender.c +++ b/lib/gvc/gvrender.c @@ -911,15 +911,20 @@ void gvrender_comment(GVJ_t * job, char *str) #endif } -void gvrender_usershape(GVJ_t * job, char *name, pointf * a, int n, boolean filled) +/* gvrender_usershape: + * If expand is true, if necessary expand user image to fill polygon a, + * maintaining aspect ratio. + */ +void gvrender_usershape(GVJ_t * job, char *name, pointf * a, int n, + boolean filled, boolean expand) { gvrender_engine_t *gvre = job->render.engine; usershape_t *us; - double iw, ih, pw, ph, tw, th; + double iw, ih, pw, ph; double scalex, scaley; /* scale factors */ boxf b; /* target box */ int i; - pointf *af; + point isz; if (! (us = gvusershape_find(name))) { if (find_user_shape(name)) { @@ -929,48 +934,58 @@ void gvrender_usershape(GVJ_t * job, char *name, pointf * a, int n, boolean fill return; } - if (job->flags & GVRENDER_DOES_TRANSFORM) - af = a; - else { - if (sizeAF < n) { - sizeAF = n+10; - AF = grealloc(AF, sizeAF * sizeof(pointf)); - } - gvrender_ptf_A(job, a, AF, n); - af = AF; - } + isz = gvusershape_size_dpi (us, job->dpi); + if ((isz.x <= 0) && (isz.y <= 0)) return; /* compute bb of polygon */ - b.LL = b.UR = af[0]; + b.LL = b.UR = a[0]; for (i = 1; i < n; i++) { - EXPANDBP(b, af[i]); + EXPANDBP(b, a[i]); } - ih = (double)us->h; - iw = (double)us->w; pw = b.UR.x - b.LL.x; ph = b.UR.y - b.LL.y; - scalex = pw / iw; - scaley = ph / ih; - + ih = (double)isz.y; + iw = (double)isz.x; + if (expand) { + scalex = pw / iw; + scaley = ph / ih; /* keep aspect ratio fixed by just using the smaller scale */ - if (scalex < scaley) { - tw = iw * scalex; - th = ih * scalex; - } else { - tw = iw * scaley; - th = ih * scaley; + if (scalex < scaley) { + iw *= scalex; + ih *= scalex; + } else { + iw *= scaley; + ih *= scaley; + } } + /* if image is smaller than target area then center it */ - if (tw < pw) { - b.LL.x += (pw - tw) / 2.0; - b.UR.x -= (pw - tw) / 2.0; + if (iw < pw) { + b.LL.x += (pw - iw) / 2.0; + b.UR.x -= (pw - iw) / 2.0; + } + if (ih < ph) { + b.LL.y += (ph - ih) / 2.0; + b.UR.y -= (ph - ih) / 2.0; } - if (th < ph) { - b.LL.y += (ph - th) / 2.0; - b.UR.y -= (ph - th) / 2.0; + + /* convert from graph to device coordinates */ + if (!(job->flags & GVRENDER_DOES_TRANSFORM)) { + b.LL = gvrender_ptf(job, b.LL); + b.UR = gvrender_ptf(job, b.UR); } + if (b.LL.x > b.UR.x) { + double d = b.LL.x; + b.LL.x = b.UR.x; + b.UR.x = d; + } + if (b.LL.y > b.UR.y) { + double d = b.LL.y; + b.LL.y = b.UR.y; + b.UR.y = d; + } if (gvre) { if (job->render.features->loadimage_target) gvloadimage(job, us, b, filled, job->render.features->loadimage_target); diff --git a/lib/gvc/gvusershape.c b/lib/gvc/gvusershape.c index 5290caf4c..df1b8efed 100644 --- a/lib/gvc/gvusershape.c +++ b/lib/gvc/gvusershape.c @@ -109,7 +109,7 @@ static void png_size (usershape_t *us) { unsigned int w, h; - us->dpi = DEFAULT_DPI; + us->dpi = 0; fseek(us->f, 16, SEEK_SET); if (get_int_msb_first(us->f, 4, &w) && get_int_msb_first(us->f, 4, &h)) { us->w = w; @@ -121,7 +121,7 @@ static void gif_size (usershape_t *us) { unsigned int w, h; - us->dpi = DEFAULT_DPI; + us->dpi = 0; fseek(us->f, 6, SEEK_SET); if (get_int_lsb_first(us->f, 2, &w) && get_int_lsb_first(us->f, 2, &h)) { us->w = w; @@ -132,7 +132,7 @@ static void gif_size (usershape_t *us) static void bmp_size (usershape_t *us) { unsigned int size_x_msw, size_x_lsw, size_y_msw, size_y_lsw; - us->dpi = DEFAULT_DPI; + us->dpi = 0; fseek (us->f, 16, SEEK_SET); if ( get_int_lsb_first (us->f, 2, &size_x_msw) && get_int_lsb_first (us->f, 2, &size_x_lsw) && @@ -159,7 +159,7 @@ static void jpeg_size (usershape_t *us) { 0 }; - us->dpi = DEFAULT_DPI; + us->dpi = 0; while (TRUE) { /* Now we must be at a 0xff or at a series of 0xff's. * If that is not the case, or if we're at EOF, then there's @@ -328,23 +328,46 @@ static usershape_t *gvusershape_open (char *name) return us; } -point gvusershape_size(graph_t * g, char *name) +/* gvusershape_size_dpi: + * Return image size in points. + */ +point +gvusershape_size_dpi (usershape_t* us, pointf dpi) { point rv; - usershape_t *us; - double dpi; - dpi = GD_drawing(g)->dpi; - if (dpi < 1.0) - dpi = POINTS_PER_INCH; - - /* no shape file, no shape size */ - if (!name || (*name == '\0') || !(us = gvusershape_open (name))) { + if (!us) { rv.x = rv.y = -1; } else { - rv.x = us->w * dpi / us->dpi; - rv.y = us->h * dpi / us->dpi; + if (us->dpi != 0) { + dpi.x = dpi.y = us->dpi; + } + rv.x = us->w * POINTS_PER_INCH / dpi.x; + rv.y = us->h * POINTS_PER_INCH / dpi.y; } return rv; } + +/* gvusershape_size: + * Loads user image from file name if not already loaded. + * Return image size in points. + */ +point gvusershape_size(graph_t * g, char *name) +{ + point rv; + pointf dpi; + + /* no shape file, no shape size */ + if (!name || (*name == '\0')) { + rv.x = rv.y = -1; + return rv; + } + + if ((dpi.y = GD_drawing(g)->dpi) >= 1.0) + dpi.x = dpi.y; + else + dpi.x = dpi.y = (double)DEFAULT_DPI; + + return gvusershape_size_dpi (gvusershape_open (name), dpi); +} diff --git a/plugin/core/gvloadimage_core.c b/plugin/core/gvloadimage_core.c index 312ffaa8c..2de117eec 100644 --- a/plugin/core/gvloadimage_core.c +++ b/plugin/core/gvloadimage_core.c @@ -39,11 +39,13 @@ extern void core_fputs(GVJ_t * job, char *s); extern void core_printf(GVJ_t * job, const char *format, ...); +extern void core_loadimage_xdot(GVJ_t*, usershape_t*, boxf, boolean); extern void epsf_emit_body(usershape_t *us, FILE *of); extern shape_desc *find_user_shape(char *name); typedef enum { FORMAT_PNG_SVG, FORMAT_GIF_SVG, FORMAT_JPEG_SVG, + FORMAT_PNG_XDOT, FORMAT_GIF_XDOT, FORMAT_JPEG_XDOT, FORMAT_PNG_FIG, FORMAT_GIF_FIG, FORMAT_JPEG_FIG, FORMAT_PNG_VRML, FORMAT_GIF_VRML, FORMAT_JPEG_VRML, FORMAT_PS_PS, FORMAT__PS, @@ -274,6 +276,10 @@ static gvloadimage_engine_t engine_pslib = { core_loadimage_pslib }; +static gvloadimage_engine_t engine_xdot = { + core_loadimage_xdot +}; + gvplugin_installed_t gvloadimage_core_types[] = { {FORMAT_PNG_SVG, "png2svg", 1, &engine_svg, NULL}, {FORMAT_GIF_SVG, "gif2svg", 1, &engine_svg, NULL}, @@ -286,5 +292,8 @@ gvplugin_installed_t gvloadimage_core_types[] = { {FORMAT_JPEG_VRML, "jpeg2vrml", 1, &engine_vrml, NULL}, {FORMAT_PS_PS, "ps2ps", 1, &engine_ps, NULL}, {FORMAT__PS, "2ps", 1, &engine_pslib, NULL}, + {FORMAT_PNG_XDOT, "png2xdot", 1, &engine_xdot, NULL}, + {FORMAT_GIF_XDOT, "gif2xdot", 1, &engine_xdot, NULL}, + {FORMAT_JPEG_XDOT, "jpeg2xdot", 1, &engine_xdot, NULL}, {0, NULL, 0, NULL, NULL} }; diff --git a/plugin/core/gvrender_core_dot.c b/plugin/core/gvrender_core_dot.c index 14871258d..e3e11f40e 100644 --- a/plugin/core/gvrender_core_dot.c +++ b/plugin/core/gvrender_core_dot.c @@ -45,7 +45,7 @@ extern void output_point(agxbuf *xbuf, pointf p); typedef enum { FORMAT_DOT, FORMAT_CANON, FORMAT_PLAIN, FORMAT_PLAIN_EXT, FORMAT_XDOT } format_type; -#define XDOTVERSION "1.1" +#define XDOTVERSION "1.2" #define NUMXBUFS (EMIT_HLABEL+1) /* There are as many xbufs as there are values of emit_state_t. @@ -392,6 +392,18 @@ static void xdot_polyline(GVJ_t * job, pointf * A, int n) xdot_points(job, 'L', A, n); } +void core_loadimage_xdot(GVJ_t * job, usershape_t *us, boxf b, boolean filled) +{ + emit_state_t emit_state = job->obj->emit_state; + char buf[BUFSIZ]; + + agxbput(xbufs[emit_state], "I "); + output_point(xbufs[emit_state], b.LL); + sprintf(buf, "%d %d ", ROUND(b.UR.x - b.LL.x), ROUND(b.UR.y - b.LL.y)); + agxbput(xbufs[emit_state], buf); + xdot_str (job, "", us->name); +} + gvrender_engine_t dot_engine = { 0, /* dot_begin_job */ 0, /* dot_end_job */ @@ -480,11 +492,24 @@ gvrender_features_t dot_features = { NULL, /* gvloadimage target for usershapes */ }; +gvrender_features_t xdot_features = { + GVRENDER_DOES_TRANSFORM, /* not really - uses raw graph coords */ + 0., /* default margin - points */ + 0., /* default pad - graph units */ + {0.,0.}, /* default page width, height - points */ + {72.,72.}, /* default dpi */ + NULL, /* knowncolors */ + 0, /* sizeof knowncolors */ + COLOR_STRING, /* color_type */ + NULL, /* device */ + "xdot", /* gvloadimage target for usershapes */ +}; + gvplugin_installed_t gvrender_core_dot_types[] = { {FORMAT_DOT, "dot", 1, &dot_engine, &dot_features}, {FORMAT_CANON, "canon", 1, &dot_engine, &canon_features}, {FORMAT_PLAIN, "plain", 1, &dot_engine, &dot_features}, {FORMAT_PLAIN_EXT, "plain-ext", 1, &dot_engine, &dot_features}, - {FORMAT_XDOT, "xdot", 1, &xdot_engine, &dot_features}, + {FORMAT_XDOT, "xdot", 1, &xdot_engine, &xdot_features}, {0, NULL, 0, NULL, NULL} };