/src/MapServer/src/mapimagemap.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * $Id$ |
3 | | * |
4 | | * Project: MapServer |
5 | | * Purpose: Implements imagemap outputformat support. |
6 | | * Author: Attila Csipa |
7 | | * |
8 | | ****************************************************************************** |
9 | | * Copyright (c) 1996-2005 Regents of the University of Minnesota. |
10 | | * |
11 | | * Permission is hereby granted, free of charge, to any person obtaining a |
12 | | * copy of this software and associated documentation files (the "Software"), |
13 | | * to deal in the Software without restriction, including without limitation |
14 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
15 | | * and/or sell copies of the Software, and to permit persons to whom the |
16 | | * Software is furnished to do so, subject to the following conditions: |
17 | | * |
18 | | * The above copyright notice and this permission notice shall be included in |
19 | | * all copies of this Software or works derived from this Software. |
20 | | * |
21 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
22 | | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
23 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
24 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
25 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
26 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
27 | | * DEALINGS IN THE SOFTWARE. |
28 | | ****************************************************************************/ |
29 | | |
30 | | #include "mapserver.h" |
31 | | #include "dxfcolor.h" |
32 | | |
33 | | #include <stdarg.h> |
34 | | #include <time.h> |
35 | | |
36 | | #ifdef _WIN32 |
37 | | #include <fcntl.h> |
38 | | #include <io.h> |
39 | | #endif |
40 | | |
41 | 0 | #define MYDEBUG 0 |
42 | 0 | #define DEBUG_IF if (MYDEBUG > 2) |
43 | | |
44 | | /* |
45 | | * Client-side imagemap support was originally written by |
46 | | * Attila Csipa (http://prometheus.org.yu/me.php). C. Scott Ananian |
47 | | * (http://cscott.net) cleaned up the code somewhat and made it more flexible: |
48 | | * you can now customize the generated HREFs and create mouseover and |
49 | | * mouseout attributes. |
50 | | * |
51 | | * Use |
52 | | * IMAGETYPE imagemap |
53 | | * to select this driver. |
54 | | * |
55 | | * The following FORMATOPTIONs are available. If any are set to the empty |
56 | | * string the associated attribute will be suppressed. |
57 | | * POLYHREF the href string to use for the <area> elements. |
58 | | * use a %s to interpolate the area title. |
59 | | * default: "javascript:Clicked('%s');" |
60 | | * POLYMOUSEOVER the onMouseOver string to use for the <area> elements. |
61 | | * use a %s to interpolate the area title. |
62 | | * default: "" (ie the attribute is suppressed) |
63 | | * POLYMOUSEOUT the onMouseOut string to use for the <area> elements. |
64 | | * use a %s to interpolate the area title. |
65 | | * default: "" (ie the attribute is suppressed) |
66 | | * SYMBOLMOUSEOVER and SYMBOLMOUSEOUT are equivalent properties for |
67 | | * <area> tags representing symbols, with the same defaults. |
68 | | * MAPNAME the string which will be used in the name attribute |
69 | | * of the <map> tag. There is no %s interpolation. |
70 | | * default: "map1" |
71 | | * SUPPRESS if "yes", then we will suppress area declarations with |
72 | | * no title. |
73 | | * default: "NO" |
74 | | * |
75 | | * For example, http://vevo.verifiedvoting.org/verifier contains this |
76 | | * .map file fragment: |
77 | | * OUTPUTFORMAT |
78 | | * NAME imagemap |
79 | | * DRIVER imagemap |
80 | | * FORMATOPTION "POLYHREF=/verifier/map.php?state=%s" |
81 | | * FORMATOPTION "SYMBOLHREF=#" |
82 | | * FORMATOPTION "SUPPRESS=YES" |
83 | | * FORMATOPTION "MAPNAME=map-48" |
84 | | * FORMATOPTION "POLYMOUSEOUT=return nd();" |
85 | | * FORMATOPTION "POLYMOUSEOVER=return overlib('%s');" |
86 | | * END |
87 | | */ |
88 | | |
89 | | /*-------------------------------------------------------------------------*/ |
90 | | |
91 | | /* A pString is a variable-length (appendable) string, stored as a triple: |
92 | | * character pointer, allocated length, and used length. The one wrinkle |
93 | | * is that we use pointers to the allocated size and character pointer, |
94 | | * in order to support referring to fields declared elsewhere (ie in the |
95 | | * 'image' data structure) for these. The 'iprintf' function appends |
96 | | * to a pString. */ |
97 | | typedef struct pString { |
98 | | /* these two fields are somewhere else */ |
99 | | char **string; |
100 | | int *alloc_size; |
101 | | /* this field is stored locally. */ |
102 | | int string_len; |
103 | | } pString; |
104 | | /* These are the pStrings we declare statically. One is the 'output' |
105 | | * imagemap/dxf file; parts of this live in another data structure and |
106 | | * are only referenced indirectly here. The other contains layer-specific |
107 | | * information for the dxf output. */ |
108 | | static char *layerlist = NULL; |
109 | | static int layersize = 0; |
110 | | static pString imgStr, layerStr = {&layerlist, &layersize, 0}; |
111 | | |
112 | | /* Format strings for the various bits of a client-side imagemap. */ |
113 | | static const char *polyHrefFmt, *polyMOverFmt, *polyMOutFmt; |
114 | | static const char *symbolHrefFmt, *symbolMOverFmt, *symbolMOutFmt; |
115 | | static const char *mapName; |
116 | | /* Should we suppress AREA declarations in imagemaps with no title? */ |
117 | | static int suppressEmpty = 0; |
118 | | |
119 | | /* Prevent buffer-overrun and format-string attacks by "sanitizing" any |
120 | | * provided format string to fit the number of expected string arguments |
121 | | * (MAX) exactly. */ |
122 | 0 | static const char *makeFmtSafe(const char *fmt, int MAX) { |
123 | | /* format string should have exactly 'MAX' %s */ |
124 | |
|
125 | 0 | char *result = msSmallMalloc(strlen(fmt) + 1 + 3 * MAX), *cp; |
126 | 0 | int numstr = 0, saw_percent = 0; |
127 | |
|
128 | 0 | strcpy(result, fmt); |
129 | 0 | for (cp = result; *cp; cp++) { |
130 | 0 | if (saw_percent) { |
131 | 0 | if (*cp == '%') { |
132 | | /* safe */ |
133 | 0 | } else if (*cp == 's' && numstr < MAX) { |
134 | 0 | numstr++; /* still safe */ |
135 | 0 | } else { |
136 | | /* disable this unsafe format string! */ |
137 | 0 | *(cp - 1) = ' '; |
138 | 0 | } |
139 | 0 | saw_percent = 0; |
140 | 0 | } else if (*cp == '%') |
141 | 0 | saw_percent = 1; |
142 | 0 | } |
143 | | /* fixup format strings without enough %s in them */ |
144 | 0 | while (numstr < MAX) { |
145 | 0 | strcpy(cp, "%.s"); /* print using zero-length precision */ |
146 | 0 | cp += 3; |
147 | 0 | numstr++; |
148 | 0 | } |
149 | 0 | return result; |
150 | 0 | } |
151 | | |
152 | | /* Append the given printf-style formatted string to the pString 'ps'. |
153 | | * This is much cleaner (and faster) than the technique this file |
154 | | * used to use! */ |
155 | 0 | static void im_iprintf(pString *ps, const char *fmt, ...) { |
156 | 0 | int n, remaining; |
157 | 0 | va_list ap; |
158 | 0 | do { |
159 | 0 | remaining = *(ps->alloc_size) - ps->string_len; |
160 | 0 | va_start(ap, fmt); |
161 | 0 | #if defined(HAVE_VSNPRINTF) |
162 | 0 | n = vsnprintf((*(ps->string)) + ps->string_len, remaining, fmt, ap); |
163 | | #else |
164 | | /* If vsnprintf() is not available then require a minimum |
165 | | * of 512 bytes of free space to prevent a buffer overflow |
166 | | * This is not fully bulletproof but should help, see bug 1613 |
167 | | */ |
168 | | if (remaining < 512) |
169 | | n = -1; |
170 | | else |
171 | | n = vsprintf((*(ps->string)) + ps->string_len, fmt, ap); |
172 | | #endif |
173 | 0 | va_end(ap); |
174 | | /* if that worked, we're done! */ |
175 | 0 | if (-1 < n && n < remaining) { |
176 | 0 | ps->string_len += n; |
177 | 0 | return; |
178 | 0 | } else { /* double allocated string size */ |
179 | 0 | *(ps->alloc_size) *= 2; /* these keeps realloc linear.*/ |
180 | 0 | if (*(ps->alloc_size) < 1024) |
181 | | /* careful: initial size can be 0 */ |
182 | 0 | *(ps->alloc_size) = 1024; |
183 | 0 | if (n > -1 && *(ps->alloc_size) <= (n + ps->string_len)) |
184 | | /* ensure at least as much as what is needed */ |
185 | 0 | *(ps->alloc_size) = n + ps->string_len + 1; |
186 | 0 | *(ps->string) = (char *)msSmallRealloc(*(ps->string), *(ps->alloc_size)); |
187 | | /* if realloc doesn't work, we're screwed! */ |
188 | 0 | } |
189 | 0 | } while (1); /* go back and try again. */ |
190 | 0 | } |
191 | | |
192 | | static int lastcolor = -1; |
193 | 0 | static int matchdxfcolor(colorObj col) { |
194 | 0 | int best = 7; |
195 | 0 | int delta = 128 * 255; |
196 | 0 | int tcolor = 0; |
197 | 0 | if (lastcolor != -1) |
198 | 0 | return lastcolor; |
199 | 0 | while (tcolor < 256 && |
200 | 0 | (ctable[tcolor].r != col.red || ctable[tcolor].g != col.green || |
201 | 0 | ctable[tcolor].b != col.blue)) { |
202 | 0 | const int dr = ctable[tcolor].r - col.red; |
203 | 0 | const int dg = ctable[tcolor].g - col.green; |
204 | 0 | const int db = ctable[tcolor].b - col.blue; |
205 | 0 | const int newdelta = dr * dr + dg * dg + db * db; |
206 | 0 | if (newdelta < delta) { |
207 | 0 | best = tcolor; |
208 | 0 | delta = newdelta; |
209 | 0 | } |
210 | 0 | tcolor++; |
211 | 0 | } |
212 | 0 | if (tcolor >= 256) |
213 | 0 | tcolor = best; |
214 | | /* DEBUG_IF printf("%d/%d/%d (%d/%d - %d), %d : %d/%d/%d<BR>\n", |
215 | | * ctable[tcolor].r, ctable[tcolor].g, ctable[tcolor].b, tcolor, best, delta, |
216 | | * lastcolor, col.red, col.green, col.blue); */ |
217 | 0 | lastcolor = tcolor; |
218 | 0 | return tcolor; |
219 | 0 | } |
220 | | |
221 | | static char *lname; |
222 | | static int dxf; |
223 | | |
224 | 0 | void msImageStartLayerIM(mapObj *map, layerObj *layer, imageObj *image) { |
225 | 0 | (void)map; |
226 | 0 | (void)image; |
227 | 0 | DEBUG_IF printf("ImageStartLayerIM\n<BR>"); |
228 | 0 | free(lname); |
229 | 0 | if (layer->name) |
230 | 0 | lname = msStrdup(layer->name); |
231 | 0 | else |
232 | 0 | lname = msStrdup("NONE"); |
233 | 0 | if (dxf == 2) { |
234 | 0 | im_iprintf(&layerStr, "LAYER\n%s\n", lname); |
235 | 0 | } else if (dxf) { |
236 | 0 | im_iprintf(&layerStr, |
237 | 0 | " 0\nLAYER\n 2\n%s\n" |
238 | 0 | " 70\n 64\n 6\nCONTINUOUS\n", |
239 | 0 | lname); |
240 | 0 | } |
241 | 0 | lastcolor = -1; |
242 | 0 | } |
243 | | |
244 | | /* |
245 | | * Utility function to create a IM image. Returns |
246 | | * a pointer to an imageObj structure. |
247 | | */ |
248 | | imageObj *msImageCreateIM(int width, int height, outputFormatObj *format, |
249 | | char *imagepath, char *imageurl, double resolution, |
250 | 0 | double defresolution) { |
251 | 0 | imageObj *image = NULL; |
252 | 0 | if (setvbuf(stdout, NULL, _IONBF, 0)) { |
253 | 0 | printf("Whoops..."); |
254 | 0 | }; |
255 | 0 | DEBUG_IF printf("msImageCreateIM<BR>\n"); |
256 | 0 | if (width > 0 && height > 0) { |
257 | 0 | image = (imageObj *)msSmallCalloc(1, sizeof(imageObj)); |
258 | 0 | imgStr.string = &(image->img.imagemap); |
259 | 0 | imgStr.alloc_size = &(image->size); |
260 | |
|
261 | 0 | image->format = format; |
262 | 0 | format->refcount++; |
263 | |
|
264 | 0 | image->width = width; |
265 | 0 | image->height = height; |
266 | 0 | image->imagepath = NULL; |
267 | 0 | image->imageurl = NULL; |
268 | 0 | image->resolution = resolution; |
269 | 0 | image->resolutionfactor = resolution / defresolution; |
270 | |
|
271 | 0 | if (strcasecmp("ON", msGetOutputFormatOption(format, "DXF", "OFF")) == 0) { |
272 | 0 | dxf = 1; |
273 | 0 | im_iprintf(&layerStr, " 2\nLAYER\n 70\n 10\n"); |
274 | 0 | } else |
275 | 0 | dxf = 0; |
276 | |
|
277 | 0 | if (strcasecmp("ON", msGetOutputFormatOption(format, "SCRIPT", "OFF")) == |
278 | 0 | 0) { |
279 | 0 | dxf = 2; |
280 | 0 | im_iprintf(&layerStr, ""); |
281 | 0 | } |
282 | | |
283 | | /* get href formation string options */ |
284 | 0 | polyHrefFmt = |
285 | 0 | makeFmtSafe(msGetOutputFormatOption(format, "POLYHREF", |
286 | 0 | "javascript:Clicked('%s');"), |
287 | 0 | 1); |
288 | 0 | polyMOverFmt = |
289 | 0 | makeFmtSafe(msGetOutputFormatOption(format, "POLYMOUSEOVER", ""), 1); |
290 | 0 | polyMOutFmt = |
291 | 0 | makeFmtSafe(msGetOutputFormatOption(format, "POLYMOUSEOUT", ""), 1); |
292 | 0 | symbolHrefFmt = |
293 | 0 | makeFmtSafe(msGetOutputFormatOption(format, "SYMBOLHREF", |
294 | 0 | "javascript:SymbolClicked();"), |
295 | 0 | 1); |
296 | 0 | symbolMOverFmt = |
297 | 0 | makeFmtSafe(msGetOutputFormatOption(format, "SYMBOLMOUSEOVER", ""), 1); |
298 | 0 | symbolMOutFmt = |
299 | 0 | makeFmtSafe(msGetOutputFormatOption(format, "SYMBOLMOUSEOUT", ""), 1); |
300 | | /* get name of client-side image map */ |
301 | 0 | mapName = msGetOutputFormatOption(format, "MAPNAME", "map1"); |
302 | | /* should we suppress area declarations with no title? */ |
303 | 0 | if (strcasecmp("YES", msGetOutputFormatOption(format, "SUPPRESS", "NO")) == |
304 | 0 | 0) { |
305 | 0 | suppressEmpty = 1; |
306 | 0 | } |
307 | |
|
308 | 0 | lname = msStrdup("NONE"); |
309 | 0 | *(imgStr.string) = msStrdup(""); |
310 | 0 | if (*(imgStr.string)) { |
311 | 0 | *(imgStr.alloc_size) = imgStr.string_len = strlen(*(imgStr.string)); |
312 | 0 | } else { |
313 | 0 | *(imgStr.alloc_size) = imgStr.string_len = 0; |
314 | 0 | } |
315 | 0 | if (imagepath) { |
316 | 0 | image->imagepath = msStrdup(imagepath); |
317 | 0 | } |
318 | 0 | if (imageurl) { |
319 | 0 | image->imageurl = msStrdup(imageurl); |
320 | 0 | } |
321 | |
|
322 | 0 | return image; |
323 | 0 | } else { |
324 | 0 | msSetError(MS_IMGERR, "Cannot create IM image of size %d x %d.", |
325 | 0 | "msImageCreateIM()", width, height); |
326 | 0 | } |
327 | 0 | return image; |
328 | 0 | } |
329 | | |
330 | | /* ------------------------------------------------------------------------- */ |
331 | | /* Draw a single marker symbol of the specified size and color */ |
332 | | /* ------------------------------------------------------------------------- */ |
333 | | void msDrawMarkerSymbolIM(mapObj *map, imageObj *img, pointObj *p, |
334 | 0 | styleObj *style, double scalefactor) { |
335 | 0 | symbolObj *symbol; |
336 | 0 | int ox, oy; |
337 | 0 | double size; |
338 | |
|
339 | 0 | DEBUG_IF printf("msDrawMarkerSymbolIM\n<BR>"); |
340 | | |
341 | | /* skip this, we don't do text */ |
342 | |
|
343 | 0 | if (!p) |
344 | 0 | return; |
345 | | |
346 | 0 | if (style->symbol > map->symbolset.numsymbols || style->symbol < 0) |
347 | 0 | return; /* no such symbol, 0 is OK */ |
348 | 0 | symbol = map->symbolset.symbol[style->symbol]; |
349 | 0 | ox = style->offsetx * scalefactor; |
350 | 0 | oy = style->offsety * scalefactor; |
351 | 0 | if (style->size == -1) { |
352 | 0 | size = msSymbolGetDefaultSize(symbol); |
353 | 0 | size = MS_NINT(size * scalefactor); |
354 | 0 | } else |
355 | 0 | size = MS_NINT(style->size * scalefactor); |
356 | 0 | size = MS_MAX(size, style->minsize * img->resolutionfactor); |
357 | 0 | size = MS_MIN(size, style->maxsize * img->resolutionfactor); |
358 | |
|
359 | 0 | if (size < 1) |
360 | 0 | return; /* size too small */ |
361 | | |
362 | | /* DEBUG_IF printf(".%d.%d.%d.", symbol->type, style->symbol, fc); */ |
363 | 0 | if (style->symbol == |
364 | 0 | 0) { /* simply draw a single pixel of the specified color */ |
365 | |
|
366 | 0 | if (dxf) { |
367 | 0 | if (dxf == 2) |
368 | 0 | im_iprintf(&imgStr, "POINT\n%.0f %.0f\n%d\n", p->x + ox, p->y + oy, |
369 | 0 | matchdxfcolor(style->color)); |
370 | 0 | else |
371 | 0 | im_iprintf(&imgStr, |
372 | 0 | " 0\nPOINT\n 10\n%f\n 20\n%f\n 30\n0.0\n" |
373 | 0 | " 62\n%6d\n 8\n%s\n", |
374 | 0 | p->x + ox, p->y + oy, matchdxfcolor(style->color), lname); |
375 | 0 | } else { |
376 | 0 | im_iprintf(&imgStr, "<area "); |
377 | 0 | if (strcmp(symbolHrefFmt, "%.s") != 0) { |
378 | 0 | im_iprintf(&imgStr, "href=\""); |
379 | 0 | im_iprintf(&imgStr, symbolHrefFmt, lname); |
380 | 0 | im_iprintf(&imgStr, "\" "); |
381 | 0 | } |
382 | 0 | if (strcmp(symbolMOverFmt, "%.s") != 0) { |
383 | 0 | im_iprintf(&imgStr, "onMouseOver=\""); |
384 | 0 | im_iprintf(&imgStr, symbolMOverFmt, lname); |
385 | 0 | im_iprintf(&imgStr, "\" "); |
386 | 0 | } |
387 | 0 | if (strcmp(symbolMOutFmt, "%.s") != 0) { |
388 | 0 | im_iprintf(&imgStr, "onMouseOut=\""); |
389 | 0 | im_iprintf(&imgStr, symbolMOutFmt, lname); |
390 | 0 | im_iprintf(&imgStr, "\" "); |
391 | 0 | } |
392 | 0 | im_iprintf(&imgStr, "shape=\"circle\" coords=\"%.0f,%.0f, 3\" />\n", |
393 | 0 | p->x + ox, p->y + oy); |
394 | 0 | } |
395 | | |
396 | | /* point2 = &( p->line[j].point[i] ); */ |
397 | | /* if(point1->y == point2->y) {} */ |
398 | 0 | return; |
399 | 0 | } |
400 | 0 | DEBUG_IF printf("A"); |
401 | 0 | switch (symbol->type) { |
402 | 0 | case (MS_SYMBOL_TRUETYPE): |
403 | 0 | DEBUG_IF printf("T"); |
404 | 0 | break; |
405 | 0 | case (MS_SYMBOL_PIXMAP): |
406 | 0 | DEBUG_IF printf("P"); |
407 | 0 | break; |
408 | 0 | case (MS_SYMBOL_VECTOR): |
409 | 0 | DEBUG_IF printf("V"); |
410 | 0 | { |
411 | 0 | double d, offset_x, offset_y; |
412 | |
|
413 | 0 | d = size / symbol->sizey; |
414 | 0 | offset_x = MS_NINT(p->x - d * .5 * symbol->sizex + ox); |
415 | 0 | offset_y = MS_NINT(p->y - d * .5 * symbol->sizey + oy); |
416 | | |
417 | | /* For now I only render filled vector symbols in imagemap, and no */ |
418 | | /* dxf support available yet. */ |
419 | 0 | if (symbol->filled && !dxf /* && fc >= 0 */) { |
420 | | /* char *title=(p->numvalues) ? p->values[0] : ""; */ |
421 | 0 | char *title = ""; |
422 | 0 | int j; |
423 | |
|
424 | 0 | im_iprintf(&imgStr, "<area "); |
425 | 0 | if (strcmp(symbolHrefFmt, "%.s") != 0) { |
426 | 0 | im_iprintf(&imgStr, "href=\""); |
427 | 0 | im_iprintf(&imgStr, symbolHrefFmt, lname); |
428 | 0 | im_iprintf(&imgStr, "\" "); |
429 | 0 | } |
430 | 0 | if (strcmp(symbolMOverFmt, "%.s") != 0) { |
431 | 0 | im_iprintf(&imgStr, "onMouseOver=\""); |
432 | 0 | im_iprintf(&imgStr, symbolMOverFmt, lname); |
433 | 0 | im_iprintf(&imgStr, "\" "); |
434 | 0 | } |
435 | 0 | if (strcmp(symbolMOutFmt, "%.s") != 0) { |
436 | 0 | im_iprintf(&imgStr, "onMouseOut=\""); |
437 | 0 | im_iprintf(&imgStr, symbolMOutFmt, lname); |
438 | 0 | im_iprintf(&imgStr, "\" "); |
439 | 0 | } |
440 | |
|
441 | 0 | im_iprintf(&imgStr, "title=\"%s\" shape=\"poly\" coords=\"", title); |
442 | |
|
443 | 0 | for (j = 0; j < symbol->numpoints; j++) { |
444 | 0 | im_iprintf(&imgStr, "%s %d,%d", j == 0 ? "" : ",", |
445 | 0 | (int)MS_NINT(d * symbol->points[j].x + offset_x), |
446 | 0 | (int)MS_NINT(d * symbol->points[j].y + offset_y)); |
447 | 0 | } |
448 | 0 | im_iprintf(&imgStr, "\" />\n"); |
449 | 0 | } /* end of imagemap, filled case. */ |
450 | 0 | } |
451 | 0 | break; |
452 | | |
453 | 0 | default: |
454 | 0 | DEBUG_IF printf("DEF"); |
455 | 0 | break; |
456 | 0 | } /* end switch statement */ |
457 | | |
458 | 0 | return; |
459 | 0 | } |
460 | | |
461 | | /* ------------------------------------------------------------------------- */ |
462 | | /* Draw a line symbol of the specified size and color */ |
463 | | /* ------------------------------------------------------------------------- */ |
464 | | void msDrawLineSymbolIM(mapObj *map, imageObj *img, shapeObj *p, |
465 | 0 | styleObj *style, double scalefactor_ignored) { |
466 | 0 | (void)img; |
467 | 0 | (void)scalefactor_ignored; |
468 | 0 | symbolObj *symbol; |
469 | 0 | int i, j, l; |
470 | 0 | char first = 1; |
471 | 0 | DEBUG_IF printf("msDrawLineSymbolIM<BR>\n"); |
472 | |
|
473 | 0 | if (!p) |
474 | 0 | return; |
475 | 0 | if (p->numlines <= 0) |
476 | 0 | return; |
477 | | |
478 | 0 | if (style->symbol > map->symbolset.numsymbols || style->symbol < 0) |
479 | 0 | return; /* no such symbol, 0 is OK */ |
480 | 0 | symbol = map->symbolset.symbol[style->symbol]; |
481 | |
|
482 | 0 | if (suppressEmpty && p->numvalues == 0) |
483 | 0 | return; /* suppress area with empty title */ |
484 | 0 | if (style->symbol == 0) { /* just draw a single width line */ |
485 | 0 | for (l = 0, j = 0; j < p->numlines; j++) { |
486 | 0 | if (dxf == 2) { |
487 | 0 | im_iprintf(&imgStr, "LINE\n%d\n", matchdxfcolor(style->color)); |
488 | 0 | } else if (dxf) { |
489 | 0 | im_iprintf(&imgStr, " 0\nPOLYLINE\n 70\n 0\n 62\n%6d\n 8\n%s\n", |
490 | 0 | matchdxfcolor(style->color), lname); |
491 | 0 | } else { |
492 | 0 | char *title; |
493 | |
|
494 | 0 | first = 1; |
495 | 0 | title = (p->numvalues) ? p->values[0] : ""; |
496 | 0 | im_iprintf(&imgStr, "<area "); |
497 | 0 | if (strcmp(polyHrefFmt, "%.s") != 0) { |
498 | 0 | im_iprintf(&imgStr, "href=\""); |
499 | 0 | im_iprintf(&imgStr, polyHrefFmt, title); |
500 | 0 | im_iprintf(&imgStr, "\" "); |
501 | 0 | } |
502 | 0 | if (strcmp(polyMOverFmt, "%.s") != 0) { |
503 | 0 | im_iprintf(&imgStr, "onMouseOver=\""); |
504 | 0 | im_iprintf(&imgStr, polyMOverFmt, title); |
505 | 0 | im_iprintf(&imgStr, "\" "); |
506 | 0 | } |
507 | 0 | if (strcmp(polyMOutFmt, "%.s") != 0) { |
508 | 0 | im_iprintf(&imgStr, "onMouseOut=\""); |
509 | 0 | im_iprintf(&imgStr, polyMOutFmt, title); |
510 | 0 | im_iprintf(&imgStr, "\" "); |
511 | 0 | } |
512 | 0 | im_iprintf(&imgStr, "title=\"%s\" shape=\"poly\" coords=\"", title); |
513 | 0 | } |
514 | | /* point1 = &( p->line[j].point[p->line[j].numpoints-1] ); */ |
515 | 0 | for (i = 0; i < p->line[j].numpoints; i++, l++) { |
516 | 0 | if (dxf == 2) { |
517 | 0 | im_iprintf(&imgStr, "%.0f %.0f\n", p->line[j].point[i].x, |
518 | 0 | p->line[j].point[i].y); |
519 | 0 | } else if (dxf) { |
520 | 0 | im_iprintf(&imgStr, " 0\nVERTEX\n 10\n%f\n 20\n%f\n 30\n%f\n", |
521 | 0 | p->line[j].point[i].x, p->line[j].point[i].y, 0.0); |
522 | 0 | } else { |
523 | 0 | im_iprintf(&imgStr, "%s %.0f,%.0f", first ? "" : ",", |
524 | 0 | p->line[j].point[i].x, p->line[j].point[i].y); |
525 | 0 | } |
526 | 0 | first = 0; |
527 | | |
528 | | /* point2 = &( p->line[j].point[i] ); */ |
529 | | /* if(point1->y == point2->y) {} */ |
530 | 0 | } |
531 | 0 | im_iprintf(&imgStr, dxf ? (dxf == 2 ? "" : " 0\nSEQEND\n") : "\" />\n"); |
532 | 0 | } |
533 | | |
534 | | /* DEBUG_IF printf ("%d, ",strlen(img->img.imagemap) ); */ |
535 | 0 | return; |
536 | 0 | } |
537 | | |
538 | 0 | DEBUG_IF printf("-%d-", symbol->type); |
539 | |
|
540 | 0 | return; |
541 | 0 | } |
542 | | |
543 | | /* ------------------------------------------------------------------------- */ |
544 | | /* Draw a shade symbol of the specified size and color */ |
545 | | /* ------------------------------------------------------------------------- */ |
546 | | void msDrawShadeSymbolIM(mapObj *map, imageObj *img, shapeObj *p, |
547 | 0 | styleObj *style, double scalefactor_ignored) { |
548 | 0 | (void)img; |
549 | 0 | (void)scalefactor_ignored; |
550 | 0 | symbolObj *symbol; |
551 | 0 | int i, j, l; |
552 | 0 | char first = 1; |
553 | |
|
554 | 0 | DEBUG_IF printf("msDrawShadeSymbolIM\n<BR>"); |
555 | 0 | if (!p) |
556 | 0 | return; |
557 | 0 | if (p->numlines <= 0) |
558 | 0 | return; |
559 | | |
560 | 0 | symbol = map->symbolset.symbol[style->symbol]; |
561 | |
|
562 | 0 | if (suppressEmpty && p->numvalues == 0) |
563 | 0 | return; /* suppress area with empty title */ |
564 | 0 | if (style->symbol == |
565 | 0 | 0) { /* simply draw a single pixel of the specified color // */ |
566 | 0 | for (l = 0, j = 0; j < p->numlines; j++) { |
567 | 0 | if (dxf == 2) { |
568 | 0 | im_iprintf(&imgStr, "POLY\n%d\n", matchdxfcolor(style->color)); |
569 | 0 | } else if (dxf) { |
570 | 0 | im_iprintf(&imgStr, " 0\nPOLYLINE\n 73\n 1\n 62\n%6d\n 8\n%s\n", |
571 | 0 | matchdxfcolor(style->color), lname); |
572 | 0 | } else { |
573 | 0 | char *title = (p->numvalues) ? p->values[0] : ""; |
574 | 0 | first = 1; |
575 | 0 | im_iprintf(&imgStr, "<area "); |
576 | 0 | if (strcmp(polyHrefFmt, "%.s") != 0) { |
577 | 0 | im_iprintf(&imgStr, "href=\""); |
578 | 0 | im_iprintf(&imgStr, polyHrefFmt, title); |
579 | 0 | im_iprintf(&imgStr, "\" "); |
580 | 0 | } |
581 | 0 | if (strcmp(polyMOverFmt, "%.s") != 0) { |
582 | 0 | im_iprintf(&imgStr, "onMouseOver=\""); |
583 | 0 | im_iprintf(&imgStr, polyMOverFmt, title); |
584 | 0 | im_iprintf(&imgStr, "\" "); |
585 | 0 | } |
586 | 0 | if (strcmp(polyMOutFmt, "%.s") != 0) { |
587 | 0 | im_iprintf(&imgStr, "onMouseOut=\""); |
588 | 0 | im_iprintf(&imgStr, polyMOutFmt, title); |
589 | 0 | im_iprintf(&imgStr, "\" "); |
590 | 0 | } |
591 | 0 | im_iprintf(&imgStr, "title=\"%s\" shape=\"poly\" coords=\"", title); |
592 | 0 | } |
593 | | |
594 | | /* point1 = &( p->line[j].point[p->line[j].numpoints-1] ); */ |
595 | 0 | for (i = 0; i < p->line[j].numpoints; i++, l++) { |
596 | 0 | if (dxf == 2) { |
597 | 0 | im_iprintf(&imgStr, "%.0f %.0f\n", p->line[j].point[i].x, |
598 | 0 | p->line[j].point[i].y); |
599 | 0 | } else if (dxf) { |
600 | 0 | im_iprintf(&imgStr, " 0\nVERTEX\n 10\n%f\n 20\n%f\n 30\n%f\n", |
601 | 0 | p->line[j].point[i].x, p->line[j].point[i].y, 0.0); |
602 | 0 | } else { |
603 | 0 | im_iprintf(&imgStr, "%s %.0f,%.0f", first ? "" : ",", |
604 | 0 | p->line[j].point[i].x, p->line[j].point[i].y); |
605 | 0 | } |
606 | 0 | first = 0; |
607 | | |
608 | | /* point2 = &( p->line[j].point[i] ); */ |
609 | | /* if(point1->y == point2->y) {} */ |
610 | 0 | } |
611 | 0 | im_iprintf(&imgStr, dxf ? (dxf == 2 ? "" : " 0\nSEQEND\n") : "\" />\n"); |
612 | 0 | } |
613 | |
|
614 | 0 | return; |
615 | 0 | } |
616 | | /* DEBUG_IF printf ("d"); */ |
617 | 0 | DEBUG_IF printf("-%d-", symbol->type); |
618 | 0 | return; |
619 | 0 | } |
620 | | |
621 | | /* |
622 | | * Simply draws a label based on the label point and the supplied label object. |
623 | | */ |
624 | | int msDrawTextIM(mapObj *map, imageObj *img, pointObj labelPnt, char *string, |
625 | 0 | labelObj *label, double scalefactor) { |
626 | 0 | (void)map; |
627 | 0 | (void)img; |
628 | 0 | DEBUG_IF printf("msDrawText<BR>\n"); |
629 | 0 | if (!string) |
630 | 0 | return (0); /* not errors, just don't want to do anything */ |
631 | 0 | if (strlen(string) == 0) |
632 | 0 | return (0); |
633 | 0 | if (!dxf) |
634 | 0 | return (0); |
635 | | |
636 | 0 | if (dxf == 2) { |
637 | 0 | im_iprintf(&imgStr, "TEXT\n%d\n%s\n%.0f\n%.0f\n%.0f\n", |
638 | 0 | matchdxfcolor(label->color), string, labelPnt.x, labelPnt.y, |
639 | 0 | -label->angle); |
640 | 0 | } else { |
641 | 0 | im_iprintf(&imgStr, |
642 | 0 | " 0\nTEXT\n 1\n%s\n 10\n%f\n 20\n%f\n 30\n0.0\n 40\n%f\n " |
643 | 0 | "50\n%f\n 62\n%6d\n 8\n%s\n 73\n 2\n 72\n 1\n", |
644 | 0 | string, labelPnt.x, labelPnt.y, label->size * scalefactor * 100, |
645 | 0 | -label->angle, matchdxfcolor(label->color), lname); |
646 | 0 | } |
647 | 0 | return (0); |
648 | 0 | } |
649 | | |
650 | | /* |
651 | | * Save an image to a file named filename, if filename is NULL it goes to stdout |
652 | | */ |
653 | | |
654 | | int msSaveImageIM(imageObj *img, const char *filename, outputFormatObj *format) |
655 | | |
656 | 0 | { |
657 | 0 | FILE *stream_to_free = NULL; |
658 | 0 | FILE *stream; |
659 | 0 | char workbuffer[5000]; |
660 | |
|
661 | 0 | DEBUG_IF printf("msSaveImageIM\n<BR>"); |
662 | |
|
663 | 0 | if (filename != NULL && strlen(filename) > 0) { |
664 | 0 | stream_to_free = fopen(filename, "wb"); |
665 | 0 | if (!stream_to_free) { |
666 | 0 | msSetError(MS_IOERR, "(%s)", "msSaveImage()", filename); |
667 | 0 | return (MS_FAILURE); |
668 | 0 | } |
669 | 0 | stream = stream_to_free; |
670 | 0 | } else { /* use stdout */ |
671 | |
|
672 | | #ifdef _WIN32 |
673 | | /* |
674 | | * Change stdout mode to binary on win32 platforms |
675 | | */ |
676 | | if (_setmode(_fileno(stdout), _O_BINARY) == -1) { |
677 | | msSetError(MS_IOERR, "Unable to change stdout to binary mode.", |
678 | | "msSaveImage()"); |
679 | | return (MS_FAILURE); |
680 | | } |
681 | | #endif |
682 | 0 | stream = stdout; |
683 | 0 | } |
684 | | |
685 | 0 | if (strcasecmp(format->driver, "imagemap") == 0) { |
686 | 0 | DEBUG_IF printf("ALLOCD %d<BR>\n", img->size); |
687 | | /* DEBUG_IF printf("F %s<BR>\n", img->img.imagemap); */ |
688 | 0 | DEBUG_IF printf("FLEN %d<BR>\n", (int)strlen(img->img.imagemap)); |
689 | 0 | if (dxf == 2) { |
690 | 0 | msIO_fprintf(stream, "%s", layerlist); |
691 | 0 | } else if (dxf) { |
692 | 0 | msIO_fprintf( |
693 | 0 | stream, |
694 | 0 | " 0\nSECTION\n 2\nHEADER\n 9\n$ACADVER\n 1\nAC1009\n0\nENDSEC\n " |
695 | 0 | "0\nSECTION\n 2\nTABLES\n 0\nTABLE\n%s0\nENDTAB\n0\nENDSEC\n " |
696 | 0 | "0\nSECTION\n 2\nBLOCKS\n0\nENDSEC\n 0\nSECTION\n 2\nENTITIES\n", |
697 | 0 | layerlist); |
698 | 0 | } else { |
699 | 0 | msIO_fprintf(stream, "<map name=\"%s\" width=\"%d\" height=\"%d\">\n", |
700 | 0 | mapName, img->width, img->height); |
701 | 0 | } |
702 | 0 | const int nSize = sizeof(workbuffer); |
703 | |
|
704 | 0 | const int size = strlen(img->img.imagemap); |
705 | 0 | if (size > nSize) { |
706 | 0 | int iIndice = 0; |
707 | 0 | while ((iIndice + nSize) <= size) { |
708 | 0 | snprintf(workbuffer, sizeof(workbuffer), "%s", |
709 | 0 | img->img.imagemap + iIndice); |
710 | 0 | workbuffer[nSize - 1] = '\0'; |
711 | 0 | msIO_fwrite(workbuffer, strlen(workbuffer), 1, stream); |
712 | 0 | iIndice += nSize - 1; |
713 | 0 | } |
714 | 0 | if (iIndice < size) { |
715 | 0 | sprintf(workbuffer, "%s", img->img.imagemap + iIndice); |
716 | 0 | msIO_fprintf(stream, "%s", workbuffer); |
717 | 0 | } |
718 | 0 | } else |
719 | 0 | msIO_fwrite(img->img.imagemap, size, 1, stream); |
720 | 0 | if (strcasecmp("OFF", |
721 | 0 | msGetOutputFormatOption(format, "SKIPENDTAG", "OFF")) == 0) { |
722 | 0 | if (dxf == 2) |
723 | 0 | msIO_fprintf(stream, "END"); |
724 | 0 | else if (dxf) |
725 | 0 | msIO_fprintf(stream, "0\nENDSEC\n0\nEOF\n"); |
726 | 0 | else |
727 | 0 | msIO_fprintf(stream, "</map>"); |
728 | 0 | } |
729 | 0 | } else { |
730 | 0 | msSetError(MS_MISCERR, "Unknown output image type driver: %s.", |
731 | 0 | "msSaveImage()", format->driver); |
732 | 0 | if (stream_to_free != NULL) |
733 | 0 | fclose(stream_to_free); |
734 | 0 | return (MS_FAILURE); |
735 | 0 | } |
736 | | |
737 | 0 | if (stream_to_free != NULL) |
738 | 0 | fclose(stream_to_free); |
739 | 0 | return (MS_SUCCESS); |
740 | 0 | } |
741 | | |
742 | | /* |
743 | | * Free gdImagePtr |
744 | | */ |
745 | 0 | void msFreeImageIM(imageObj *img) { free(img->img.imagemap); } |