]> granicus.if.org Git - graphviz/commitdiff
Version 1.2 of xdot supporting images;
authorerg <devnull@localhost>
Thu, 22 Mar 2007 22:02:34 +0000 (22:02 +0000)
committererg <devnull@localhost>
Thu, 22 Mar 2007 22:02:34 +0000 (22:02 +0000)
fixes to image code - various calculations were incorrect,
use unscaled image.

lib/common/htmltable.c
lib/common/shapes.c
lib/gvc/gvcproc.h
lib/gvc/gvrender.c
lib/gvc/gvusershape.c
plugin/core/gvloadimage_core.c
plugin/core/gvrender_core_dot.c

index d642507d3524d0b818b41affb669e6595fc1f193..5c1da78d8ffae15eb3c2a355618e457ee56f81e8 100644 (file)
@@ -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
index b2e6309dee90c1c7fda4d93b78786f612a58db51..e83d5cc5874ff0d04181ef41cd758afed6bef017 100644 (file)
@@ -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];
index cb23e2677590f7d5257a219478787f45982fe02f..3cd1bf28c9db0ad5dc0b5adf9c023fb1df0f6db6 100644 (file)
@@ -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 */
 
index 048d918cc36e409a25a6b46615ec96d13a45e92c..7a8e9f0f132b27ec08315fe1c3b6808fa8d23b5f 100644 (file)
@@ -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);
index 5290caf4c34076d0c6b96bcc86ac4d9775952dcf..df1b8efede21635373b5f4ef218d267e4e7f2d4b 100644 (file)
@@ -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);
+}
index 312ffaa8c8e7b0d45767438b5374ce58255d568e..2de117eece00ffb0a288aca6d36c00d90914386d 100644 (file)
 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}
 };
index 14871258d5e6d642d85923607f86612febefb793..e3e11f40ebe06d4bd680db319e2cfcaba90606f1 100644 (file)
@@ -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}
 };