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