| 1 | /* $Id$ $Revision$ */ |
| 2 | /* vim:set shiftwidth=4 ts=8: */ |
| 3 | |
| 4 | /************************************************************************* |
| 5 | * Copyright (c) 2011 AT&T Intellectual Property |
| 6 | * All rights reserved. This program and the accompanying materials |
| 7 | * are made available under the terms of the Eclipse Public License v1.0 |
| 8 | * which accompanies this distribution, and is available at |
| 9 | * http://www.eclipse.org/legal/epl-v10.html |
| 10 | * |
| 11 | * Contributors: See CVS logs. Details at http://www.graphviz.org/ |
| 12 | *************************************************************************/ |
| 13 | |
| 14 | #include "config.h" |
| 15 | |
| 16 | #include <stdlib.h> |
| 17 | #include <sys/types.h> |
| 18 | #include <sys/stat.h> |
| 19 | #ifdef HAVE_SYS_MMAN_H |
| 20 | #include <sys/mman.h> |
| 21 | #endif |
| 22 | #ifdef _MSC_VER |
| 23 | #include <io.h> |
| 24 | #endif |
| 25 | |
| 26 | #include "gvplugin_loadimage.h" |
| 27 | #include "agxbuf.h" |
| 28 | #include "utils.h" |
| 29 | #include "gvio.h" |
| 30 | |
| 31 | extern void core_loadimage_xdot(GVJ_t*, usershape_t*, boxf, boolean); |
| 32 | extern shape_desc *find_user_shape(char *name); |
| 33 | |
| 34 | typedef enum { |
| 35 | FORMAT_PNG_XDOT, FORMAT_GIF_XDOT, FORMAT_JPEG_XDOT, FORMAT_SVG_XDOT, FORMAT_PS_XDOT, |
| 36 | FORMAT_PNG_DOT, FORMAT_GIF_DOT, FORMAT_JPEG_DOT, FORMAT_SVG_DOT, FORMAT_PS_DOT, |
| 37 | FORMAT_PNG_MAP, FORMAT_GIF_MAP, FORMAT_JPEG_MAP, FORMAT_SVG_MAP, FORMAT_PS_MAP, |
| 38 | FORMAT_PNG_SVG, FORMAT_GIF_SVG, FORMAT_JPEG_SVG, FORMAT_SVG_SVG, |
| 39 | FORMAT_PNG_FIG, FORMAT_GIF_FIG, FORMAT_JPEG_FIG, |
| 40 | FORMAT_PNG_VRML, FORMAT_GIF_VRML, FORMAT_JPEG_VRML, |
| 41 | FORMAT_PS_PS, FORMAT_PSLIB_PS, |
| 42 | FORMAT_PNG_VML, FORMAT_GIF_VML, FORMAT_JPEG_VML, |
| 43 | FORMAT_GIF_TK, |
| 44 | } format_type; |
| 45 | |
| 46 | static void core_loadimage_svg(GVJ_t * job, usershape_t *us, boxf b, boolean filled) |
| 47 | { |
| 48 | |
| 49 | double width = (b.UR.x-b.LL.x); |
| 50 | double height = (b.UR.y-b.LL.y); |
| 51 | double originx = (b.UR.x+b.LL.x - width)/2; |
| 52 | double originy = (b.UR.y+b.LL.y + height)/2; |
| 53 | assert(job); |
| 54 | assert(us); |
| 55 | assert(us->name); |
| 56 | |
| 57 | gvputs(job, "<image xlink:href=\"" ); |
| 58 | gvputs(job, us->name); |
| 59 | if (job->rotation) { |
| 60 | |
| 61 | // FIXME - this is messed up >>> |
| 62 | gvprintf (job, "\" width=\"%gpx\" height=\"%gpx\" preserveAspectRatio=\"xMidYMid meet\" x=\"%g\" y=\"%g\"" , |
| 63 | height, width, originx, -originy); |
| 64 | gvprintf (job, " transform=\"rotate(%d %g %g)\"" , |
| 65 | job->rotation, originx, -originy); |
| 66 | // <<< |
| 67 | } |
| 68 | else { |
| 69 | gvprintf (job, "\" width=\"%gpx\" height=\"%gpx\" preserveAspectRatio=\"xMinYMin meet\" x=\"%g\" y=\"%g\"" , |
| 70 | width, height, originx, -originy); |
| 71 | } |
| 72 | gvputs(job, "/>\n" ); |
| 73 | } |
| 74 | |
| 75 | static void core_loadimage_fig(GVJ_t * job, usershape_t *us, boxf bf, boolean filled) |
| 76 | { |
| 77 | int object_code = 2; /* always 2 for polyline */ |
| 78 | int sub_type = 5; /* always 5 for image */ |
| 79 | int line_style = 0; /* solid, dotted, dashed */ |
| 80 | int thickness = 0; |
| 81 | int pen_color = 0; |
| 82 | int fill_color = -1; |
| 83 | int depth = 1; |
| 84 | int pen_style = -1; /* not used */ |
| 85 | int area_fill = 0; |
| 86 | double style_val = 0.0; |
| 87 | int join_style = 0; |
| 88 | int cap_style = 0; |
| 89 | int radius = 0; |
| 90 | int forward_arrow = 0; |
| 91 | int backward_arrow = 0; |
| 92 | int npoints = 5; |
| 93 | int flipped = 0; |
| 94 | |
| 95 | box b; |
| 96 | |
| 97 | assert(job); |
| 98 | assert(us); |
| 99 | assert(us->name); |
| 100 | |
| 101 | BF2B(bf, b); |
| 102 | |
| 103 | gvprintf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n %d %s\n" , |
| 104 | object_code, sub_type, line_style, thickness, pen_color, |
| 105 | fill_color, depth, pen_style, area_fill, style_val, join_style, |
| 106 | cap_style, radius, forward_arrow, backward_arrow, npoints, |
| 107 | flipped, us->name); |
| 108 | gvprintf(job," %d %d %d %d %d %d %d %d %d %d\n" , |
| 109 | b.LL.x, b.LL.y, |
| 110 | b.LL.x, b.UR.y, |
| 111 | b.UR.x, b.UR.y, |
| 112 | b.UR.x, b.LL.y, |
| 113 | b.LL.x, b.LL.y); |
| 114 | } |
| 115 | |
| 116 | static void core_loadimage_vrml(GVJ_t * job, usershape_t *us, boxf b, boolean filled) |
| 117 | { |
| 118 | obj_state_t *obj; |
| 119 | node_t *n; |
| 120 | |
| 121 | assert(job); |
| 122 | obj = job->obj; |
| 123 | assert(obj); |
| 124 | assert(us); |
| 125 | assert(us->name); |
| 126 | |
| 127 | n = job->obj->u.n; |
| 128 | assert(n); |
| 129 | |
| 130 | gvprintf(job, "Shape {\n" ); |
| 131 | gvprintf(job, " appearance Appearance {\n" ); |
| 132 | gvprintf(job, " material Material {\n" ); |
| 133 | gvprintf(job, " ambientIntensity 0.33\n" ); |
| 134 | gvprintf(job, " diffuseColor 1 1 1\n" ); |
| 135 | gvprintf(job, " }\n" ); |
| 136 | gvprintf(job, " texture ImageTexture { url \"%s\" }\n" , us->name); |
| 137 | gvprintf(job, " }\n" ); |
| 138 | gvprintf(job, "}\n" ); |
| 139 | } |
| 140 | |
| 141 | static void ps_freeimage(usershape_t *us) |
| 142 | { |
| 143 | #ifdef HAVE_SYS_MMAN_H |
| 144 | munmap(us->data, us->datasize); |
| 145 | #else |
| 146 | free(us->data); |
| 147 | #endif |
| 148 | } |
| 149 | |
| 150 | /* usershape described by a postscript file */ |
| 151 | static void core_loadimage_ps(GVJ_t * job, usershape_t *us, boxf b, boolean filled) |
| 152 | { |
| 153 | assert(job); |
| 154 | assert(us); |
| 155 | assert(us->name); |
| 156 | |
| 157 | if (us->data) { |
| 158 | if (us->datafree != ps_freeimage) { |
| 159 | us->datafree(us); /* free incompatible cache data */ |
| 160 | us->data = NULL; |
| 161 | us->datafree = NULL; |
| 162 | us->datasize = 0; |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | if (!us->data) { /* read file into cache */ |
| 167 | int fd; |
| 168 | struct stat statbuf; |
| 169 | |
| 170 | if (!gvusershape_file_access(us)) |
| 171 | return; |
| 172 | fd = fileno(us->f); |
| 173 | switch (us->type) { |
| 174 | case FT_PS: |
| 175 | case FT_EPS: |
| 176 | fstat(fd, &statbuf); |
| 177 | us->datasize = statbuf.st_size; |
| 178 | #ifdef HAVE_SYS_MMAN_H |
| 179 | us->data = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); |
| 180 | if (us->data == MAP_FAILED) |
| 181 | us->data = NULL; |
| 182 | #else |
| 183 | us->data = malloc(statbuf.st_size); |
| 184 | read(fd, us->data, statbuf.st_size); |
| 185 | #endif |
| 186 | us->must_inline = TRUE; |
| 187 | break; |
| 188 | default: |
| 189 | break; |
| 190 | } |
| 191 | if (us->data) |
| 192 | us->datafree = ps_freeimage; |
| 193 | gvusershape_file_release(us); |
| 194 | } |
| 195 | |
| 196 | if (us->data) { |
| 197 | gvprintf(job, "gsave %g %g translate newpath\n" , |
| 198 | b.LL.x - (double)(us->x), b.LL.y - (double)(us->y)); |
| 199 | if (us->must_inline) |
| 200 | epsf_emit_body(job, us); |
| 201 | else |
| 202 | gvprintf(job, "user_shape_%d\n" , us->macro_id); |
| 203 | gvprintf(job, "grestore\n" ); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | /* usershape described by a member of a postscript library */ |
| 208 | static void core_loadimage_pslib(GVJ_t * job, usershape_t *us, boxf b, boolean filled) |
| 209 | { |
| 210 | int i; |
| 211 | pointf AF[4]; |
| 212 | shape_desc *shape; |
| 213 | |
| 214 | assert(job); |
| 215 | assert(us); |
| 216 | assert(us->name); |
| 217 | |
| 218 | if ((shape = (shape_desc*)us->data)) { |
| 219 | AF[0] = b.LL; |
| 220 | AF[2] = b.UR; |
| 221 | AF[1].x = AF[0].x; |
| 222 | AF[1].y = AF[2].y; |
| 223 | AF[3].x = AF[2].x; |
| 224 | AF[3].y = AF[0].y; |
| 225 | if (filled) { |
| 226 | // ps_begin_context(); |
| 227 | // ps_set_color(S[SP].fillcolor); |
| 228 | gvprintf(job, "[ " ); |
| 229 | for (i = 0; i < 4; i++) |
| 230 | gvprintf(job, "%g %g " , AF[i].x, AF[i].y); |
| 231 | gvprintf(job, "%g %g " , AF[0].x, AF[0].y); |
| 232 | gvprintf(job, "] %d true %s\n" , 4, us->name); |
| 233 | // ps_end_context(); |
| 234 | } |
| 235 | gvprintf(job, "[ " ); |
| 236 | for (i = 0; i < 4; i++) |
| 237 | gvprintf(job, "%g %g " , AF[i].x, AF[i].y); |
| 238 | gvprintf(job, "%g %g " , AF[0].x, AF[0].y); |
| 239 | gvprintf(job, "] %d false %s\n" , 4, us->name); |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | static void core_loadimage_vml(GVJ_t * job, usershape_t *us, boxf b, boolean filled) |
| 244 | { |
| 245 | unsigned int graphHeight; |
| 246 | graphHeight =(int)(job->bb.UR.y - job->bb.LL.y); |
| 247 | gvprintf (job, "<v:image src=\"%s\" style=\" position:absolute; width:%.2f; height:%.2f; left:%.2f ; top:%.2f\"" , |
| 248 | us->name, b.UR.x - b.LL.x, b.UR.y - b.LL.y, b.LL.x, graphHeight-b.UR.y); |
| 249 | gvputs(job, " />\n" ); |
| 250 | } |
| 251 | |
| 252 | static void core_loadimage_tk(GVJ_t * job, usershape_t *us, boxf b, boolean filled) |
| 253 | { |
| 254 | gvprintf (job, "image create photo \"photo_%s\" -file \"%s\"\n" , |
| 255 | us->name, us->name); |
| 256 | gvprintf (job, "$c create image %.2f %.2f -image \"photo_%s\"\n" , |
| 257 | us->name, (b.UR.x + b.LL.x) / 2, (b.UR.y + b.LL.y) / 2); |
| 258 | } |
| 259 | |
| 260 | void core_loadimage_null(GVJ_t *gvc, usershape_t *us, boxf b, boolean filled) |
| 261 | { |
| 262 | /* null function - basically suppress the missing loader message */ |
| 263 | } |
| 264 | |
| 265 | static gvloadimage_engine_t engine_svg = { |
| 266 | core_loadimage_svg |
| 267 | }; |
| 268 | |
| 269 | static gvloadimage_engine_t engine_fig = { |
| 270 | core_loadimage_fig |
| 271 | }; |
| 272 | |
| 273 | static gvloadimage_engine_t engine_vrml = { |
| 274 | core_loadimage_vrml |
| 275 | }; |
| 276 | |
| 277 | static gvloadimage_engine_t engine_ps = { |
| 278 | core_loadimage_ps |
| 279 | }; |
| 280 | |
| 281 | static gvloadimage_engine_t engine_pslib = { |
| 282 | core_loadimage_pslib |
| 283 | }; |
| 284 | |
| 285 | static gvloadimage_engine_t engine_null = { |
| 286 | core_loadimage_null |
| 287 | }; |
| 288 | |
| 289 | static gvloadimage_engine_t engine_xdot = { |
| 290 | core_loadimage_xdot |
| 291 | }; |
| 292 | |
| 293 | static gvloadimage_engine_t engine_vml = { |
| 294 | core_loadimage_vml |
| 295 | }; |
| 296 | |
| 297 | static gvloadimage_engine_t engine_tk = { |
| 298 | core_loadimage_tk |
| 299 | }; |
| 300 | |
| 301 | gvplugin_installed_t gvloadimage_core_types[] = { |
| 302 | {FORMAT_PNG_SVG, "png:svg" , 1, &engine_svg, NULL}, |
| 303 | {FORMAT_GIF_SVG, "gif:svg" , 1, &engine_svg, NULL}, |
| 304 | {FORMAT_JPEG_SVG, "jpeg:svg" , 1, &engine_svg, NULL}, |
| 305 | {FORMAT_JPEG_SVG, "jpe:svg" , 1, &engine_svg, NULL}, |
| 306 | {FORMAT_JPEG_SVG, "jpg:svg" , 1, &engine_svg, NULL}, |
| 307 | |
| 308 | {FORMAT_PNG_FIG, "png:fig" , 1, &engine_fig, NULL}, |
| 309 | {FORMAT_GIF_FIG, "gif:fig" , 1, &engine_fig, NULL}, |
| 310 | {FORMAT_JPEG_FIG, "jpeg:fig" , 1, &engine_fig, NULL}, |
| 311 | {FORMAT_JPEG_FIG, "jpe:fig" , 1, &engine_fig, NULL}, |
| 312 | {FORMAT_JPEG_FIG, "jpg:fig" , 1, &engine_fig, NULL}, |
| 313 | |
| 314 | {FORMAT_PNG_VRML, "png:vrml" , 1, &engine_vrml, NULL}, |
| 315 | {FORMAT_GIF_VRML, "gif:vrml" , 1, &engine_vrml, NULL}, |
| 316 | {FORMAT_JPEG_VRML, "jpeg:vrml" , 1, &engine_vrml, NULL}, |
| 317 | {FORMAT_JPEG_VRML, "jpe:vrml" , 1, &engine_vrml, NULL}, |
| 318 | {FORMAT_JPEG_VRML, "jpg:vrml" , 1, &engine_vrml, NULL}, |
| 319 | |
| 320 | {FORMAT_PS_PS, "eps:ps" , 1, &engine_ps, NULL}, |
| 321 | {FORMAT_PS_PS, "ps:ps" , 1, &engine_ps, NULL}, |
| 322 | {FORMAT_PSLIB_PS, "(lib):ps" , 1, &engine_pslib, NULL}, /* for pslib */ |
| 323 | |
| 324 | {FORMAT_PNG_MAP, "png:map" , 1, &engine_null, NULL}, |
| 325 | {FORMAT_GIF_MAP, "gif:map" , 1, &engine_null, NULL}, |
| 326 | {FORMAT_JPEG_MAP, "jpeg:map" , 1, &engine_null, NULL}, |
| 327 | {FORMAT_JPEG_MAP, "jpe:map" , 1, &engine_null, NULL}, |
| 328 | {FORMAT_JPEG_MAP, "jpg:map" , 1, &engine_null, NULL}, |
| 329 | {FORMAT_PS_MAP, "ps:map" , 1, &engine_null, NULL}, |
| 330 | {FORMAT_PS_MAP, "eps:map" , 1, &engine_null, NULL}, |
| 331 | {FORMAT_SVG_MAP, "svg:map" , 1, &engine_null, NULL}, |
| 332 | |
| 333 | {FORMAT_PNG_DOT, "png:dot" , 1, &engine_null, NULL}, |
| 334 | {FORMAT_GIF_DOT, "gif:dot" , 1, &engine_null, NULL}, |
| 335 | {FORMAT_JPEG_DOT, "jpeg:dot" , 1, &engine_null, NULL}, |
| 336 | {FORMAT_JPEG_DOT, "jpe:dot" , 1, &engine_null, NULL}, |
| 337 | {FORMAT_JPEG_DOT, "jpg:dot" , 1, &engine_null, NULL}, |
| 338 | {FORMAT_PS_DOT, "ps:dot" , 1, &engine_null, NULL}, |
| 339 | {FORMAT_PS_DOT, "eps:dot" , 1, &engine_null, NULL}, |
| 340 | {FORMAT_SVG_DOT, "svg:dot" , 1, &engine_null, NULL}, |
| 341 | |
| 342 | {FORMAT_PNG_XDOT, "png:xdot" , 1, &engine_xdot, NULL}, |
| 343 | {FORMAT_GIF_XDOT, "gif:xdot" , 1, &engine_xdot, NULL}, |
| 344 | {FORMAT_JPEG_XDOT, "jpeg:xdot" , 1, &engine_xdot, NULL}, |
| 345 | {FORMAT_JPEG_XDOT, "jpe:xdot" , 1, &engine_xdot, NULL}, |
| 346 | {FORMAT_JPEG_XDOT, "jpg:xdot" , 1, &engine_xdot, NULL}, |
| 347 | {FORMAT_PS_XDOT, "ps:xdot" , 1, &engine_xdot, NULL}, |
| 348 | {FORMAT_PS_XDOT, "eps:xdot" , 1, &engine_xdot, NULL}, |
| 349 | {FORMAT_SVG_XDOT, "svg:xdot" , 1, &engine_xdot, NULL}, |
| 350 | |
| 351 | {FORMAT_SVG_SVG, "svg:svg" , 1, &engine_svg, NULL}, |
| 352 | |
| 353 | {FORMAT_PNG_VML, "png:vml" , 1, &engine_vml, NULL}, |
| 354 | {FORMAT_GIF_VML, "gif:vml" , 1, &engine_vml, NULL}, |
| 355 | {FORMAT_JPEG_VML, "jpeg:vml" , 1, &engine_vml, NULL}, |
| 356 | {FORMAT_JPEG_VML, "jpe:vml" , 1, &engine_vml, NULL}, |
| 357 | {FORMAT_JPEG_VML, "jpg:vml" , 1, &engine_vml, NULL}, |
| 358 | |
| 359 | {FORMAT_GIF_TK, "gif:tk" , 1, &engine_tk, NULL}, |
| 360 | |
| 361 | {0, NULL, 0, NULL, NULL} |
| 362 | }; |
| 363 | |