Coverage Report

Created: 2025-06-13 06:18

/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); }