00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
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)
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
00217
00218
00219 static unsigned char standalone_markers [] = {
00220 0x01,
00221 0xd0, 0xd1, 0xd2, 0xd3,
00222 0xd4, 0xd5, 0xd6,
00223 0xd7,
00224 0xd8,
00225 0xd9,
00226 0
00227 };
00228
00229 us->dpi = 0;
00230 while (TRUE) {
00231
00232
00233
00234
00235 if (! get_int_msb_first (us->f, 1, &marker))
00236 return;
00237
00238 if (marker == 0xff)
00239 continue;
00240
00241
00242
00243
00244
00245
00246
00247
00248 if (strchr ((char*)standalone_markers, marker))
00249 continue;
00250
00251
00252 if (marker == 0xc0) {
00253
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
00259 us->h = size_x;
00260 us->w = size_y;
00261 }
00262 return;
00263 }
00264
00265
00266 if (marker == 0xc2) {
00267
00268 if (! get_int_msb_first (us->f, 3, &junk))
00269 return;
00270
00271
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
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),
00324 -1,
00325 0,
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:
00391 case FT_EPS:
00392 default:
00393 break;
00394 }
00395 dtinsert(ImageDict, us);
00396 }
00397
00398 return us;
00399 }
00400
00401
00402
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
00423
00424
00425
00426 point gvusershape_size(graph_t * g, char *name)
00427 {
00428 point rv;
00429 pointf dpi;
00430
00431
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 }