/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/gvc/gvusershape.c

Go to the documentation of this file.
00001 /* $Id: gvusershape.c,v 1.34 2007/12/27 22:09:22 ellson Exp $ $Revision: 1.34 $ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /**********************************************************
00005 *      This software is part of the graphviz package      *
00006 *                http://www.graphviz.org/                 *
00007 *                                                         *
00008 *            Copyright (c) 1994-2004 AT&T Corp.           *
00009 *                and is licensed under the                *
00010 *            Common Public License, Version 1.0           *
00011 *                      by AT&T Corp.                      *
00012 *                                                         *
00013 *        Information and Software Systems Research        *
00014 *              AT&T Research, Florham Park NJ             *
00015 **********************************************************/
00016 
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020 
00021 #include <stddef.h>
00022 #include <string.h>
00023 
00024 #include "types.h"
00025 #include "logic.h"
00026 #include "memory.h"
00027 #include "graph.h"
00028 #include "agxbuf.h"
00029 #include "utils.h"
00030 
00031 extern shape_desc *find_user_shape(char *);
00032 
00033 static Dict_t *ImageDict;
00034 
00035 typedef struct {
00036     char *template;
00037     int size;
00038     int type;
00039     char *stringtype;
00040 } knowntype_t;
00041 
00042 #define HDRLEN 20
00043 
00044 #define PNG_MAGIC  "\x89PNG\x0D\x0A\x1A\x0A"
00045 #define PS_MAGIC   "%!PS-Adobe-"
00046 #define BMP_MAGIC  "BM"
00047 #define GIF_MAGIC  "GIF8"
00048 #define JPEG_MAGIC "\xFF\xD8\xFF\xE0"
00049 #define PDF_MAGIC  "%PDF-"
00050 #define EPS_MAGIC  "\xC5\xD0\xD3\xC6"
00051 #define XML_MAGIC  "<?xml"
00052 #define SVG_MAGIC  "<svg"
00053 
00054 static knowntype_t knowntypes[] = {
00055     { PNG_MAGIC,  sizeof(PNG_MAGIC)-1,  FT_PNG,  "png",  },
00056     { PS_MAGIC,   sizeof(PS_MAGIC)-1,   FT_PS,   "ps",   },
00057     { BMP_MAGIC,  sizeof(BMP_MAGIC)-1,  FT_BMP,  "bmp",  },
00058     { GIF_MAGIC,  sizeof(GIF_MAGIC)-1,  FT_GIF,  "gif",  },
00059     { JPEG_MAGIC, sizeof(JPEG_MAGIC)-1, FT_JPEG, "jpeg", },
00060     { PDF_MAGIC,  sizeof(PDF_MAGIC)-1,  FT_PDF,  "pdf",  },
00061     { EPS_MAGIC,  sizeof(EPS_MAGIC)-1,  FT_EPS,  "eps",  },
00062 /*    { SVG_MAGIC,  sizeof(SVG_MAGIC)-1,  FT_SVG,  "svg",  },  - viewers expect xml preamble */
00063     { XML_MAGIC,  sizeof(XML_MAGIC)-1,  FT_XML,  "xml",  },
00064 };
00065 
00066 static int imagetype (usershape_t *us)
00067 {
00068     char header[HDRLEN];
00069     char line[200];
00070     int i;
00071 
00072     if (us->f && fread(header, 1, HDRLEN, us->f) == HDRLEN) {
00073         for (i = 0; i < sizeof(knowntypes) / sizeof(knowntype_t); i++) {
00074             if (!memcmp (header, knowntypes[i].template, knowntypes[i].size)) {
00075                 us->stringtype = knowntypes[i].stringtype;
00076                 us->type = knowntypes[i].type;
00077                 if (us->type != FT_XML)
00078                     return us->type;
00079                 /* check for SVG in case of XML */
00080                 while (fgets(line, sizeof(line), us->f) != NULL) {
00081                     if (!memcmp(line, SVG_MAGIC, sizeof(SVG_MAGIC)-1)) {
00082                         us->stringtype = "svg";
00083                         return (us->type = FT_SVG);
00084                     }
00085                 }
00086             }
00087         }
00088     }
00089 
00090     us->stringtype = "(lib)";
00091     us->type = FT_NULL;
00092 
00093     return FT_NULL;
00094 }
00095     
00096 static boolean get_int_lsb_first (FILE *f, unsigned int sz, unsigned int *val)
00097 {
00098     int ch, i;
00099 
00100     *val = 0;
00101     for (i = 0; i < sz; i++) {
00102         ch = fgetc(f);
00103         if (feof(f))
00104             return FALSE;
00105         *val |= (ch << 8*i);
00106     }
00107     return TRUE;
00108 }
00109         
00110 static boolean get_int_msb_first (FILE *f, unsigned int sz, unsigned int *val)
00111 {
00112     int ch, i;
00113 
00114     *val = 0;
00115     for (i = 0; i < sz; i++) {
00116         ch = fgetc(f);
00117         if (feof(f))
00118             return FALSE;
00119         *val <<= 8;
00120         *val |= ch;
00121     }
00122     return TRUE;
00123 }
00124 
00125 static unsigned int svg_units_convert(double n, char *u)
00126 {
00127     if (strcmp(u, "in") == 0)
00128         return ROUND(n * POINTS_PER_INCH);
00129     if (strcmp(u, "px") == 0)
00130         return ROUND(n * POINTS_PER_INCH / 96);
00131     if (strcmp(u, "pc") == 0)
00132         return ROUND(n * POINTS_PER_INCH / 6); 
00133     if (strcmp(u, "pt") == 0 || strcmp(u, "\"") == 0)   /* ugly!!  - if there are no inits then the %2s get the trailing '"' */
00134         return ROUND(n);
00135     if (strcmp(u, "cm") == 0)
00136         return ROUND(n * POINTS_PER_CM);
00137     if (strcmp(u, "mm") == 0)
00138         return ROUND(n * POINTS_PER_MM);
00139     return 0;
00140 }
00141 
00142 static void svg_size (usershape_t *us)
00143 {
00144     unsigned int w = 0, h = 0;
00145     double n;
00146     char u[10];
00147     char *token;
00148     char line[200];
00149     bool wFlag = false, hFlag = false;
00150 
00151     fseek(us->f, -strlen(line), SEEK_CUR);
00152     while (fgets(line, sizeof(line), us->f) != NULL && (!wFlag || !hFlag)) {
00153         token = strtok(line, " ");
00154         while (token != NULL && token[strlen(token)-1] != '>') {
00155             if (sscanf(token, "width=\"%lf%2s\"", &n, u) == 2) {
00156                 w = svg_units_convert(n, u);
00157                 wFlag = true;
00158                 if (hFlag)
00159                     break;
00160             }
00161             if (sscanf(token, "height=\"%lf%2s\"", &n, u) == 2) {
00162                 h = svg_units_convert(n, u);
00163                 hFlag = true;
00164                 if (wFlag)
00165                     break;
00166             }
00167             token =  strtok(NULL, " ");
00168         }
00169     }
00170     us->dpi = 72;
00171     us->w = w;
00172     us->h = h;
00173 }
00174 
00175 static void png_size (usershape_t *us)
00176 {
00177     unsigned int w, h;
00178 
00179     us->dpi = 0;
00180     fseek(us->f, 16, SEEK_SET);
00181     if (get_int_msb_first(us->f, 4, &w) && get_int_msb_first(us->f, 4, &h)) {
00182         us->w = w;
00183         us->h = h;
00184     }
00185 }
00186 
00187 static void gif_size (usershape_t *us)
00188 {
00189     unsigned int w, h;
00190 
00191     us->dpi = 0;
00192     fseek(us->f, 6, SEEK_SET);
00193     if (get_int_lsb_first(us->f, 2, &w) && get_int_lsb_first(us->f, 2, &h)) {
00194         us->w = w;
00195         us->h = h;
00196     }
00197 }
00198 
00199 static void bmp_size (usershape_t *us) {
00200     unsigned int size_x_msw, size_x_lsw, size_y_msw, size_y_lsw;
00201 
00202     us->dpi = 0;
00203     fseek (us->f, 16, SEEK_SET);
00204     if ( get_int_lsb_first (us->f, 2, &size_x_msw) &&
00205          get_int_lsb_first (us->f, 2, &size_x_lsw) &&
00206          get_int_lsb_first (us->f, 2, &size_y_msw) &&
00207          get_int_lsb_first (us->f, 2, &size_y_lsw) ) {
00208         us->w = size_x_msw << 16 | size_x_lsw;
00209         us->h = size_y_msw << 16 | size_y_lsw;
00210     }
00211 }
00212 
00213 static void jpeg_size (usershape_t *us) {
00214     unsigned int marker, length, size_x, size_y, junk;
00215 
00216     /* These are the markers that follow 0xff in the file.
00217      * Other markers implicitly have a 2-byte length field that follows.
00218      */
00219     static unsigned char standalone_markers [] = {
00220         0x01,                       /* Temporary */
00221         0xd0, 0xd1, 0xd2, 0xd3,     /* Reset */
00222             0xd4, 0xd5, 0xd6,
00223             0xd7,
00224         0xd8,                       /* Start of image */
00225         0xd9,                       /* End of image */
00226         0
00227     };
00228 
00229     us->dpi = 0;
00230     while (TRUE) {
00231         /* Now we must be at a 0xff or at a series of 0xff's.
00232          * If that is not the case, or if we're at EOF, then there's
00233          * a parsing error.
00234          */
00235         if (! get_int_msb_first (us->f, 1, &marker))
00236             return;
00237 
00238         if (marker == 0xff)
00239             continue;
00240 
00241         /* Ok.. marker now read. If it is not a stand-alone marker,
00242          * then continue. If it's a Start Of Frame (0xc?), then we're there.
00243          * If it's another marker with a length field, then skip ahead
00244          * over that length field.
00245          */
00246 
00247         /* A stand-alone... */
00248         if (strchr ((char*)standalone_markers, marker))
00249             continue;
00250 
00251         /* Incase of a 0xc0 marker: */
00252         if (marker == 0xc0) {
00253             /* Skip length and 2 lengths. */
00254             if ( get_int_msb_first (us->f, 3, &junk)   &&
00255                  get_int_msb_first (us->f, 2, &size_x) &&
00256                  get_int_msb_first (us->f, 2, &size_y) ) {
00257 
00258             /* Store length. */
00259                 us->h = size_x;
00260                 us->w = size_y;
00261             }
00262             return;
00263         }
00264 
00265         /* Incase of a 0xc2 marker: */
00266         if (marker == 0xc2) {
00267             /* Skip length and one more byte */
00268             if (! get_int_msb_first (us->f, 3, &junk))
00269                 return;
00270 
00271             /* Get length and store. */
00272             if ( get_int_msb_first (us->f, 2, &size_x) &&
00273                  get_int_msb_first (us->f, 2, &size_y) ) {
00274                 us->h = size_x;
00275                 us->w = size_y;
00276             }
00277             return;
00278         }
00279 
00280         /* Any other marker is assumed to be followed by 2 bytes length. */
00281         if (! get_int_msb_first (us->f, 2, &length))
00282             return;
00283 
00284         fseek (us->f, length - 2, SEEK_CUR);
00285     }
00286 }
00287 
00288 static void ps_size (usershape_t *us)
00289 {
00290     char line[BUFSIZ];
00291     boolean saw_bb;
00292     int lx, ly, ux, uy;
00293 
00294     us->dpi = POINTS_PER_INCH;
00295     fseek(us->f, 0, SEEK_SET);
00296     saw_bb = FALSE;
00297     while (fgets(line, sizeof(line), us->f)) {
00298         if (sscanf (line, "%%%%BoundingBox: %d %d %d %d", &lx, &ly, &ux, &uy) == 4) {
00299             saw_bb = TRUE;
00300             break;
00301         }
00302     }
00303     if (saw_bb) {
00304         us->x = lx;
00305         us->y = ly;
00306         us->w = ux - lx;
00307         us->h = uy - ly;
00308     }
00309 }
00310 
00311 static void usershape_close (Dict_t * dict, Void_t * p, Dtdisc_t * disc)
00312 {
00313     usershape_t *us = (usershape_t *)p;
00314 
00315     if (us->f)
00316         fclose(us->f);
00317     if (us->data && us->datafree)
00318         us->datafree(us);
00319     free (us);
00320 }
00321 
00322 static Dtdisc_t ImageDictDisc = {
00323     offsetof(usershape_t, name), /* key */
00324     -1,                         /* size */
00325     0,                          /* link offset */
00326     NIL(Dtmake_f),
00327     usershape_close,
00328     NIL(Dtcompar_f),
00329     NIL(Dthash_f),
00330     NIL(Dtmemory_f),
00331     NIL(Dtevent_f)
00332 };
00333 
00334 usershape_t *gvusershape_find(char *name)
00335 {
00336     usershape_t probe;
00337 
00338     if (!ImageDict)
00339         return NULL;
00340 
00341     probe.name = name;
00342     return (dtsearch(ImageDict, &probe));
00343 }
00344 
00345 static usershape_t *gvusershape_open (char *name)
00346 {
00347     usershape_t *us;
00348     char *fn;
00349 
00350     if (!ImageDict)
00351         ImageDict = dtopen(&ImageDictDisc, Dttree);
00352 
00353     if (! (us = gvusershape_find(name))) {
00354         if (! (us = zmalloc(sizeof(usershape_t))))
00355             return NULL;
00356 
00357         us->name = name;
00358         if ((fn = safefile(name))) {
00359 #ifndef WIN32
00360             us->f = fopen(fn, "r");
00361 #else
00362             us->f = fopen(fn, "rb");
00363 #endif
00364         }
00365         switch(imagetype(us)) {
00366             case FT_NULL:
00367                 if (!(us->data = (void*)find_user_shape(us->name)))
00368                     agerr(AGWARN, "\"%s\" was not found as a file or as a shape library member\n", us->name);
00369                     free(us);
00370                     return NULL;
00371                 break;
00372             case FT_GIF:
00373                 gif_size(us);
00374                 break;
00375             case FT_PNG:
00376                 png_size(us);
00377                 break;
00378             case FT_BMP:
00379                 bmp_size(us);
00380                 break;
00381             case FT_JPEG:
00382                 jpeg_size(us);
00383                 break;
00384             case FT_PS:
00385                 ps_size(us);
00386                 break;
00387             case FT_SVG:
00388                 svg_size(us);
00389                 break;
00390             case FT_PDF:   /* no pdf_size code available */
00391             case FT_EPS:   /* no eps_size code available */
00392             default:
00393                 break;
00394         }
00395         dtinsert(ImageDict, us);
00396     }
00397 
00398     return us;
00399 }
00400 
00401 /* gvusershape_size_dpi:
00402  * Return image size in points.
00403  */
00404 point 
00405 gvusershape_size_dpi (usershape_t* us, pointf dpi)
00406 {
00407     point rv;
00408 
00409     if (!us) {
00410         rv.x = rv.y = -1;
00411     }
00412     else {
00413         if (us->dpi != 0) {
00414             dpi.x = dpi.y = us->dpi;
00415         }
00416         rv.x = us->w * POINTS_PER_INCH / dpi.x;
00417         rv.y = us->h * POINTS_PER_INCH / dpi.y;
00418     }
00419     return rv;
00420 }
00421 
00422 /* gvusershape_size:
00423  * Loads user image from file name if not already loaded.
00424  * Return image size in points.
00425  */
00426 point gvusershape_size(graph_t * g, char *name)
00427 {
00428     point rv;
00429     pointf dpi;
00430 
00431     /* no shape file, no shape size */
00432     if (!name || (*name == '\0')) {
00433         rv.x = rv.y = -1;
00434         return rv;
00435     }
00436 
00437     if ((dpi.y = GD_drawing(g)->dpi) >= 1.0)
00438         dpi.x = dpi.y;
00439     else
00440         dpi.x = dpi.y = (double)DEFAULT_DPI;
00441 
00442     return gvusershape_size_dpi (gvusershape_open (name), dpi);
00443 }

Generated on Mon Mar 31 19:03:27 2008 for Graphviz by  doxygen 1.5.1