/* * TransFig: Facility for Translating Fig code * Copyright (c) 1999 by T. Sato * Parts Copyright (c) 1989-2002 by Brian V. Smith * * Any party obtaining a copy of these files is granted, free of charge, a * full and unrestricted irrevocable, world-wide, paid up, royalty-free, * nonexclusive right and license to deal in this software and * documentation files (the "Software"), including without limitation the * rights to use, copy, modify, merge, publish and/or distribute copies of * the Software, and to permit persons who receive copies from any such * party to do so, with the only requirement being that this copyright * notice remain intact. * */ /* * genmap.c: HTML imagemap driver for fig2dev * * T.Sato * * * Description: * Generate HTML imagemap from Fig file. * If an object has comment like ``HREF="url" ALT="string"'', * the object will becomes link to the URL. * Object with smaller depth will be listed before deeper ones. * Figure comment will be used as the default link. */ #include "fig2dev.h" #include "object.h" #define TEXT_LENGTH 300 static int border_margin = 0; static char url[TEXT_LENGTH], alt[TEXT_LENGTH]; static char buf[2000]; #define MAX_LINKS 100 static int n_links = 0; static struct { char *url; char *alt; char *area; } links[MAX_LINKS]; #define fscale 15 #define XZOOM(x) round(mag * ((x) - llx) / fscale + border_margin) #define YZOOM(y) round(mag * ((y) - lly) / fscale + border_margin) #define MIN_DIST 5 /* ignore closer points when processing polyline */ #define ARC_STEP (M_PI / 9.0) #define ARC_EXPAND 1.02 /* make polygon slightly larger */ void genmap_option(opt, optarg) char opt; char *optarg; { switch (opt) { case 'b': /* border margin */ sscanf(optarg,"%d",&border_margin); break; case 'L': /* ignore language and magnif. */ case 'm': break; default: put_msg(Err_badarg, opt, "map"); exit(1); } } static char * is_link(comment) F_comment *comment; { char *cp1, *cp2; Boolean have_alt = False; int i; url[0] = '\0'; alt[0] = '\0'; while (comment != NULL) { cp1 = comment->comment; while (isspace(*cp1)) cp1++; /* ignore leading spaces */ if (strncasecmp(cp1, "HREF=", 5) == 0) { /* comment like "HREF=url ALT=string" */ cp2 = cp1 + 5; while (isspace(*cp2)) cp2++; /* spaces */ i = 0; while (isgraph(*cp2)) url[i++] = *(cp2++); /* URL */ url[i] = '\0'; while (isspace(*cp2)) cp2++; /* spaces */ if (*cp2 != '\0') { if (strncasecmp(cp2, "ALT=", 4) == 0) { have_alt = True; cp2 = cp2 + 4; while (isspace(*cp2)) cp2++; /* spaces */ i = 0; if (*cp2 == '"') { cp2++; while (*cp2 != '\0' && *cp2 != '"') alt[i++] = *(cp2++); /* text */ } else { while (isgraph(*cp2)) alt[i++] = *(cp2++); /* text */ } alt[i] = '\0'; } else { fprintf(stderr, "fig2dev(map): unknown attribute: %s\n", cp2); } } if (!have_alt) fprintf(stderr, "fig2dev(map): ALT is required in HTML 3.2: %s\n", cp1); return cp1; } comment = comment->next; } return NULL; } void add_link(char *area) { if (n_links < MAX_LINKS) { links[n_links].url = (char *)malloc(strlen(url) + 1); strcpy(links[n_links].url, url); links[n_links].alt = (char *)malloc(strlen(alt) + 1); strcpy(links[n_links].alt, alt); links[n_links].area = (char *)malloc(strlen(area) + 1); strcpy(links[n_links].area, area); n_links++; } else { fprintf(stderr, "fig2dev(map): more than %d links in a figure\n", MAX_LINKS); } } void genmap_start(objects) F_compound *objects; { char *basename; char *ref; int i; if (to != NULL) { basename = (char *)malloc(strlen(to) + 1); strcpy(basename, to); for (i = strlen(basename) - 1; 0 < i; i--) { if (basename[i] == '.') { basename[i] = '\0'; break; } } } else { basename = "imagemap"; } fprintf(tfp, "\n"); fprintf(tfp, "\n"); fprintf(tfp, "HTML imagemap generated by fig2dev\n"); fprintf(tfp, "\n\n"); fprintf(tfp, "

HTML imagemap generated by fig2dev

\n"); fprintf(tfp, "

This file is generated by fig2dev.

\n"); fprintf(tfp, "

You can copy the following lines into your HTML document.\n"); fprintf(tfp, "You may need to edit the name of the image file in the first line.

\n"); fprintf(tfp, "\n"); fprintf(tfp, "\n", basename, basename); fprintf(tfp, "\n", basename); ref = is_link(objects->comments); if (ref != NULL) { sprintf(buf, "\n", XZOOM(llx), YZOOM(lly), XZOOM(urx), YZOOM(ury), ref); add_link(buf); } } int genmap_end() { int i; int len; char label[TEXT_LENGTH]; for (i = n_links - 1; 0 <= i; i--) { fprintf(tfp, "%s", links[i].area); } fprintf(tfp, "\n"); fprintf(tfp, "\n"); fprintf(tfp, "

Alternative Text Links

\n"); fprintf(tfp, "

Because not all people can use imagemaps,\n"); fprintf(tfp, "it is recommended to prepare an alternative way for the people\n"); fprintf(tfp, "who can't use or don't want to use them.

\n"); fprintf(tfp, "

Here are text the links extracted from the above imagemap.\n"); fprintf(tfp, "If the ALT attribute (it is required in HTML 3.2) was not specified\n"); fprintf(tfp, "in the imagemap, those URLs will be displayed\n"); fprintf(tfp, "instead of labels specified by the ALT attributes.

\n"); fprintf(tfp, "\n"); fprintf(tfp, "

\n"); len = 0; for (i = n_links - 1; 0 <= i; i--) { if (links[i].alt[0] != '\0') strcpy(label, links[i].alt); else sprintf(label, "%s", links[i].url); fprintf(tfp, "%s%s\n", (len == 0) ? "" : " | ", links[i].url, label); len = len + strlen(label) + 3; if (50 < len) { fprintf(tfp, "
\n"); len = 0; } } fprintf(tfp, "

\n"); fprintf(tfp, "\n"); fprintf(tfp, "\n"); fprintf(tfp, "\n"); /* all ok */ return 0; } void genmap_arc(a) F_arc *a; { char *ref; int cx, cy, sx, sy, ex, ey; double r; double sa, ea; double alpha; ref = is_link(a->comments); if (ref != NULL) { cx = XZOOM(a->center.x); cy = YZOOM(a->center.y); sx = XZOOM(a->point[0].x); sy = YZOOM(a->point[0].y); ex = XZOOM(a->point[2].x); ey = YZOOM(a->point[2].y); if (a->direction == 0) { sa = atan2((double)(sy - cy), (double)(sx - cx)); ea = atan2((double)(ey - cy), (double)(ex - cx)); } else { ea = atan2((double)(sy - cy), (double)(sx - cx)); sa = atan2((double)(ey - cy), (double)(ex - cx)); } if (ea < sa) ea = ea + 2 * M_PI; r = sqrt((double)((sx - cx) * (sx - cx) + (sy - cy) * (sy - cy))) * ARC_EXPAND + 1.0; sprintf(buf, "type == T_PIE_WEDGE_ARC) sprintf(&buf[strlen(buf)], "%d,%d,", cx, cy); for (alpha = sa; alpha < (ea - ARC_STEP / 4); alpha += ARC_STEP) { if (alpha != sa) sprintf(&buf[strlen(buf)], ","); sprintf(&buf[strlen(buf)], "%d,%d", round(cx + r * cos(alpha)), round(cy + r * sin(alpha))); } sprintf(&buf[strlen(buf)], ",%d,%d", round(cx + r * cos(ea)), round(cy + r * sin(ea))); sprintf(&buf[strlen(buf)], "\" %s>\n", ref); add_link(buf); } } void genmap_ellipse(e) F_ellipse *e; { char *ref; int x0, y0; double rx, ry; double angle, theta; ref = is_link(e->comments); if (ref != NULL) { x0 = XZOOM(e->center.x); y0 = YZOOM(e->center.y); rx = mag * e->radiuses.x / fscale; ry = mag * e->radiuses.y / fscale; angle = - e->angle; if (e->radiuses.x == e->radiuses.y) { sprintf(buf, "\n", x0, y0, round(rx) + 1, ref); add_link(buf); } else { rx = rx * ARC_EXPAND + 1.0; ry = ry * ARC_EXPAND + 1.0; sprintf(buf, "\n", ref); add_link(buf); } } } void genmap_line(l) F_line *l; { char *ref; int xmin, xmax, ymin, ymax; int x, y, last_x, last_y; F_point *p; ref = is_link(l->comments); if (ref != NULL) { switch (l->type) { case T_BOX: case T_ARC_BOX: case T_PIC_BOX: xmin = xmax = l->points->x; ymin = ymax = l->points->y; for (p = l->points->next; p != NULL; p = p->next) { if (p->x < xmin) xmin = p->x; if (xmax < p->x) xmax = p->x; if (p->y < ymin) ymin = p->y; if (ymax < p->y) ymax = p->y; } sprintf(buf, "\n", XZOOM(xmin), YZOOM(ymin), XZOOM(xmax), YZOOM(ymax), ref); add_link(buf); break; case T_POLYLINE: case T_POLYGON: sprintf(buf, "points; (l->type==T_POLYLINE? p: p->next) != NULL; p = p->next) { x = XZOOM(p->x); y = YZOOM(p->y); if (p == l->points || MIN_DIST < abs(last_x - x) || MIN_DIST < abs(last_y - y)) { if (sizeof(buf) < strlen(buf) + 100) { fprintf(stderr, "fig2dev(map): too complex POLYLINE... ignored\n"); return; } else { if (p != l->points) sprintf(&buf[strlen(buf)], ","); sprintf(&buf[strlen(buf)], "%d,%d", x, y); last_x = x; last_y = y; } } } sprintf(&buf[strlen(buf)], "\" %s>\n", ref); add_link(buf); break; } } } void genmap_text(t) F_text *t; { char *ref; ref = is_link(t->comments); if (ref != NULL) { fprintf(stderr, "fig2dev(map): TEXT can't be used as link region\n"); } } struct driver dev_map = { genmap_option, genmap_start, gendev_null, genmap_arc, genmap_ellipse, genmap_line, gendev_null, genmap_text, genmap_end, INCLUDE_TEXT };