Coverage Report

Created: 2025-06-13 06:18

/src/MapServer/src/mapdrawgdal.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Code for drawing GDAL raster layers.  Called from
6
 *           msDrawRasterLayerLow() in mapraster.c.
7
 * Author:   Frank Warmerdam, warmerdam@pobox.com
8
 *
9
 ******************************************************************************
10
 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a
13
 * copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in
20
 * all copies of this Software or works derived from this Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28
 * DEALINGS IN THE SOFTWARE.
29
 *****************************************************************************/
30
31
#include <assert.h>
32
#include <stdbool.h>
33
#include "mapserver.h"
34
#include "mapresample.h"
35
#include "mapthread.h"
36
#include "maptime.h"
37
38
extern int InvGeoTransform(double *gt_in, double *gt_out);
39
40
0
#define MAXCOLORS 256
41
0
#define GEO_TRANS(tr, x, y) ((tr)[0] + (tr)[1] * (x) + (tr)[2] * (y))
42
#define SKIP_MASK(x, y)                                                        \
43
0
  (mask_rb && !*(mask_rb->data.rgba.a + (y)*mask_rb->data.rgba.row_step +      \
44
0
                 (x)*mask_rb->data.rgba.pixel_step))
45
46
#include "gdal.h"
47
#include "cpl_string.h"
48
49
#include "gdal_alg.h"
50
51
static bool IsNoData(double dfValue, double dfNoDataValue);
52
53
static int LoadGDALImages(GDALDatasetH hDS, int band_numbers[4], int band_count,
54
                          layerObj *layer, int src_xoff, int src_yoff,
55
                          int src_xsize, int src_ysize, GByte *pabyBuffer,
56
                          int dst_xsize, int dst_ysize, int *pbHaveRGBNoData,
57
                          int *pnNoData1, int *pnNoData2, int *pnNoData3,
58
                          bool *pbScaled, double *pdfScaleMin,
59
                          double *pdfScaleRatio, bool **ppbIsNoDataBuffer);
60
static int msDrawRasterLayerGDAL_RawMode(mapObj *map, layerObj *layer,
61
                                         imageObj *image, GDALDatasetH hDS,
62
                                         int src_xoff, int src_yoff,
63
                                         int src_xsize, int src_ysize,
64
                                         int dst_xoff, int dst_yoff,
65
                                         int dst_xsize, int dst_ysize);
66
67
static int msDrawRasterLayerGDAL_16BitClassification(
68
    mapObj *map, layerObj *layer, rasterBufferObj *rb, GDALRasterBandH hBand,
69
    int src_xoff, int src_yoff, int src_xsize, int src_ysize, int dst_xoff,
70
    int dst_yoff, int dst_xsize, int dst_ysize);
71
72
/*
73
 * rasterBufferObj setting macros.
74
 */
75
76
#define GAMMA_CORRECT(color, gamma)                                            \
77
0
  (int)(0.5 + 255 * pow((color) / 255.0, (gamma)))
78
79
/************************************************************************/
80
/*                       msDrawRasterLayerGDAL()                        */
81
/************************************************************************/
82
83
int msDrawRasterLayerGDAL(mapObj *map, layerObj *layer, imageObj *image,
84
                          rasterBufferObj *rb, void *hDSVoid)
85
86
0
{
87
0
  int i; /* loop counters */
88
0
  int cmap[MAXCOLORS];
89
0
#ifndef NDEBUG
90
0
  int cmap_set = FALSE;
91
0
#endif
92
0
  unsigned char rb_cmap[4][MAXCOLORS];
93
0
  double adfGeoTransform[6], adfInvGeoTransform[6];
94
0
  int dst_xoff, dst_yoff, dst_xsize, dst_ysize;
95
0
  int src_xoff, src_yoff, src_xsize, src_ysize;
96
0
  double llx, lly, urx, ury;
97
0
  rectObj copyRect, mapRect;
98
0
  unsigned char *pabyRaw1 = NULL, *pabyRaw2 = NULL, *pabyRaw3 = NULL,
99
0
                *pabyRawAlpha = NULL;
100
0
  int classified = FALSE;
101
0
  int red_band = 0, green_band = 0, blue_band = 0, alpha_band = 0;
102
0
  int band_count, band_numbers[4];
103
0
  GDALDatasetH hDS = hDSVoid;
104
0
  GDALColorTableH hColorMap = NULL;
105
0
  GDALRasterBandH hBand1 = NULL, hBand2 = NULL, hBand3 = NULL,
106
0
                  hBandAlpha = NULL;
107
0
  int bHaveRGBNoData = FALSE;
108
0
  int nNoData1 = -1, nNoData2 = -1, nNoData3 = -1;
109
0
  rasterBufferObj *mask_rb = NULL;
110
0
  rasterBufferObj s_mask_rb;
111
112
0
  if (layer->mask) {
113
0
    int ret;
114
0
    layerObj *maskLayer = GET_LAYER(map, msGetLayerIndex(map, layer->mask));
115
0
    mask_rb = &s_mask_rb;
116
0
    memset(mask_rb, 0, sizeof(s_mask_rb));
117
0
    ret = MS_IMAGE_RENDERER(maskLayer->maskimage)
118
0
              ->getRasterBufferHandle(maskLayer->maskimage, mask_rb);
119
0
    if (ret != MS_SUCCESS)
120
0
      return -1;
121
0
  }
122
123
  /*only support rawdata and pluggable renderers*/
124
0
  assert(MS_RENDERER_RAWDATA(image->format) ||
125
0
         (MS_RENDERER_PLUGIN(image->format) && rb));
126
127
0
  memset(cmap, 0xff, MAXCOLORS * sizeof(int));
128
0
  memset(rb_cmap, 0, sizeof(rb_cmap));
129
130
  /* -------------------------------------------------------------------- */
131
  /*      Test the image format instead of the map format.                */
132
  /*      Normally the map format and the image format should be the      */
133
  /*      same but In some cases like swf and pdf support, a temporary   */
134
  /*      GD image object is created and used to render raster layers     */
135
  /*      and then dumped into the SWF or the PDF file.                   */
136
  /* -------------------------------------------------------------------- */
137
138
0
  src_xsize = GDALGetRasterXSize(hDS);
139
0
  src_ysize = GDALGetRasterYSize(hDS);
140
141
  /*
142
   * If the RAW_WINDOW attribute is set, use that to establish what to
143
   * load.  This is normally just set by the mapresample.c module to avoid
144
   * problems with rotated maps.
145
   */
146
147
0
  if (CSLFetchNameValue(layer->processing, "RAW_WINDOW") != NULL) {
148
0
    char **papszTokens =
149
0
        CSLTokenizeString(CSLFetchNameValue(layer->processing, "RAW_WINDOW"));
150
151
0
    if (layer->debug)
152
0
      msDebug("msDrawGDAL(%s): using RAW_WINDOW=%s, dst=0,0,%d,%d\n",
153
0
              layer->name, CSLFetchNameValue(layer->processing, "RAW_WINDOW"),
154
0
              image->width, image->height);
155
156
0
    if (CSLCount(papszTokens) != 4) {
157
0
      CSLDestroy(papszTokens);
158
0
      msSetError(MS_IMGERR, "RAW_WINDOW PROCESSING directive corrupt.",
159
0
                 "msDrawGDAL()");
160
0
      return -1;
161
0
    }
162
163
0
    src_xoff = atoi(papszTokens[0]);
164
0
    src_yoff = atoi(papszTokens[1]);
165
0
    src_xsize = atoi(papszTokens[2]);
166
0
    src_ysize = atoi(papszTokens[3]);
167
168
0
    dst_xoff = 0;
169
0
    dst_yoff = 0;
170
0
    dst_xsize = image->width;
171
0
    dst_ysize = image->height;
172
173
0
    CSLDestroy(papszTokens);
174
0
  }
175
176
  /*
177
   * Compute the georeferenced window of overlap, and do nothing if there
178
   * is no overlap between the map extents, and the file we are operating on.
179
   */
180
0
  else if (layer->transform) {
181
0
    int dst_lrx, dst_lry;
182
183
0
    if (layer->debug)
184
0
      msDebug("msDrawRasterLayerGDAL(): Entering transform.\n");
185
186
0
    msGetGDALGeoTransform(hDS, map, layer, adfGeoTransform);
187
0
    InvGeoTransform(adfGeoTransform, adfInvGeoTransform);
188
189
0
    mapRect = map->extent;
190
191
0
    mapRect.minx -= map->cellsize * 0.5;
192
0
    mapRect.maxx += map->cellsize * 0.5;
193
0
    mapRect.miny -= map->cellsize * 0.5;
194
0
    mapRect.maxy += map->cellsize * 0.5;
195
196
0
    copyRect = mapRect;
197
198
0
    if (copyRect.minx < GEO_TRANS(adfGeoTransform, 0, src_ysize))
199
0
      copyRect.minx = GEO_TRANS(adfGeoTransform, 0, src_ysize);
200
0
    if (copyRect.maxx > GEO_TRANS(adfGeoTransform, src_xsize, 0))
201
0
      copyRect.maxx = GEO_TRANS(adfGeoTransform, src_xsize, 0);
202
203
0
    if (copyRect.miny < GEO_TRANS(adfGeoTransform + 3, 0, src_ysize))
204
0
      copyRect.miny = GEO_TRANS(adfGeoTransform + 3, 0, src_ysize);
205
0
    if (copyRect.maxy > GEO_TRANS(adfGeoTransform + 3, src_xsize, 0))
206
0
      copyRect.maxy = GEO_TRANS(adfGeoTransform + 3, src_xsize, 0);
207
208
0
    if (copyRect.minx >= copyRect.maxx || copyRect.miny >= copyRect.maxy) {
209
0
      if (layer->debug)
210
0
        msDebug("msDrawRasterLayerGDAL(): Error in overlap calculation.\n");
211
0
      return 0;
212
0
    }
213
214
    /*
215
     * Copy the source and destination raster coordinates.
216
     */
217
0
    llx = GEO_TRANS(adfInvGeoTransform + 0, copyRect.minx, copyRect.miny);
218
0
    lly = GEO_TRANS(adfInvGeoTransform + 3, copyRect.minx, copyRect.miny);
219
0
    urx = GEO_TRANS(adfInvGeoTransform + 0, copyRect.maxx, copyRect.maxy);
220
0
    ury = GEO_TRANS(adfInvGeoTransform + 3, copyRect.maxx, copyRect.maxy);
221
222
0
    src_xoff = MS_MAX(0, (int)floor(llx + 0.5));
223
0
    src_yoff = MS_MAX(0, (int)floor(ury + 0.5));
224
0
    src_xsize = MS_MIN(MS_MAX(0, (int)(urx - llx + 0.5)),
225
0
                       GDALGetRasterXSize(hDS) - src_xoff);
226
0
    src_ysize = MS_MIN(MS_MAX(0, (int)(lly - ury + 0.5)),
227
0
                       GDALGetRasterYSize(hDS) - src_yoff);
228
229
    /* We want very small windows to use at least one source pixel (#4172) */
230
0
    if (src_xsize == 0 && (urx - llx) > 0.0) {
231
0
      src_xsize = 1;
232
0
      src_xoff = MS_MIN(src_xoff, GDALGetRasterXSize(hDS) - 1);
233
0
    }
234
0
    if (src_ysize == 0 && (lly - ury) > 0.0) {
235
0
      src_ysize = 1;
236
0
      src_yoff = MS_MIN(src_yoff, GDALGetRasterYSize(hDS) - 1);
237
0
    }
238
239
0
    if (src_xsize == 0 || src_ysize == 0) {
240
0
      if (layer->debug)
241
0
        msDebug("msDrawRasterLayerGDAL(): no apparent overlap between map view "
242
0
                "and this window(1).\n");
243
0
      return 0;
244
0
    }
245
246
0
    if (map->cellsize == 0) {
247
0
      if (layer->debug)
248
0
        msDebug("msDrawRasterLayerGDAL(): Cellsize can't be 0.\n");
249
0
      return 0;
250
0
    }
251
252
0
    dst_xoff = (int)((copyRect.minx - mapRect.minx) / map->cellsize);
253
0
    dst_yoff = (int)((mapRect.maxy - copyRect.maxy) / map->cellsize);
254
255
0
    dst_lrx = (int)((copyRect.maxx - mapRect.minx) / map->cellsize + 0.5);
256
0
    dst_lry = (int)((mapRect.maxy - copyRect.miny) / map->cellsize + 0.5);
257
0
    dst_lrx = MS_MAX(0, MS_MIN(image->width, dst_lrx));
258
0
    dst_lry = MS_MAX(0, MS_MIN(image->height, dst_lry));
259
260
0
    dst_xsize = MS_MAX(0, MS_MIN(image->width, dst_lrx - dst_xoff));
261
0
    dst_ysize = MS_MAX(0, MS_MIN(image->height, dst_lry - dst_yoff));
262
263
0
    if (dst_xsize == 0 || dst_ysize == 0) {
264
0
      if (layer->debug)
265
0
        msDebug("msDrawRasterLayerGDAL(): no apparent overlap between map view "
266
0
                "and this window(2).\n");
267
0
      return 0;
268
0
    }
269
270
0
    if (layer->debug)
271
0
      msDebug("msDrawRasterLayerGDAL(): src=%d,%d,%d,%d, dst=%d,%d,%d,%d\n",
272
0
              src_xoff, src_yoff, src_xsize, src_ysize, dst_xoff, dst_yoff,
273
0
              dst_xsize, dst_ysize);
274
0
#ifndef notdef
275
0
    if (layer->debug) {
276
0
      double d_src_xoff, d_src_yoff, geo_x, geo_y;
277
278
0
      geo_x = mapRect.minx + dst_xoff * map->cellsize;
279
0
      geo_y = mapRect.maxy - dst_yoff * map->cellsize;
280
281
0
      d_src_xoff = (geo_x - adfGeoTransform[0]) / adfGeoTransform[1];
282
0
      d_src_yoff = (geo_y - adfGeoTransform[3]) / adfGeoTransform[5];
283
284
0
      msDebug("msDrawRasterLayerGDAL(): source raster PL (%.3f,%.3f) for dst "
285
0
              "PL (%d,%d).\n",
286
0
              d_src_xoff, d_src_yoff, dst_xoff, dst_yoff);
287
0
    }
288
0
#endif
289
0
  }
290
291
  /*
292
   * If layer transforms are turned off, just map 1:1.
293
   */
294
0
  else {
295
0
    dst_xoff = src_xoff = 0;
296
0
    dst_yoff = src_yoff = 0;
297
0
    dst_xsize = src_xsize = MS_MIN(image->width, src_xsize);
298
0
    dst_ysize = src_ysize = MS_MIN(image->height, src_ysize);
299
0
  }
300
301
  /*
302
   * In RAWDATA mode we don't fool with colors.  Do the raw processing,
303
   * and return from the function early.
304
   */
305
0
  if (MS_RENDERER_RAWDATA(image->format)) {
306
0
    return msDrawRasterLayerGDAL_RawMode(
307
0
        map, layer, image, hDS, src_xoff, src_yoff, src_xsize, src_ysize,
308
0
        dst_xoff, dst_yoff, dst_xsize, dst_ysize);
309
0
  }
310
311
  /*
312
   * Is this image classified?  We consider it classified if there are
313
   * classes with an expression string *or* a color range.  We don't want
314
   * to treat the raster as classified if there is just a bogus class here
315
   * to force inclusion in the legend.
316
   */
317
0
  for (i = 0; i < layer->numclasses; i++) {
318
0
    int s;
319
320
    /* change colour based on colour range? */
321
0
    for (s = 0; s < layer->class[i] -> numstyles; s++) {
322
0
      if (MS_VALID_COLOR(layer->class[i] -> styles[s] -> mincolor) &&
323
0
          MS_VALID_COLOR(layer->class[i] -> styles[s] -> maxcolor)) {
324
0
        classified = TRUE;
325
0
        break;
326
0
      }
327
0
    }
328
329
0
    if (layer->class[i] -> expression.string != NULL) {
330
0
      classified = TRUE;
331
0
      break;
332
0
    }
333
0
  }
334
335
  /*
336
   * Set up the band selection.  We look for a BANDS directive in the
337
   * the PROCESSING options.  If not found we default to grey=1, grey=1,alpha=2,
338
   * red=1,green=2,blue=3 or red=1,green=2,blue=3,alpha>=4.
339
   */
340
341
0
  if (CSLFetchNameValue(layer->processing, "BANDS") == NULL) {
342
0
    const int gdal_band_count = GDALGetRasterCount(hDS);
343
0
    red_band = 1;
344
345
0
    if (gdal_band_count >= 4) {
346
      /* The alpha band is not necessarily the 4th one */
347
0
      for (i = 4; i <= gdal_band_count; i++) {
348
0
        if (GDALGetRasterColorInterpretation(GDALGetRasterBand(hDS, i)) ==
349
0
            GCI_AlphaBand) {
350
0
          alpha_band = i;
351
0
          break;
352
0
        }
353
0
      }
354
0
    }
355
356
0
    if (gdal_band_count >= 3) {
357
0
      green_band = 2;
358
0
      blue_band = 3;
359
0
    }
360
361
0
    if (gdal_band_count == 2 && GDALGetRasterColorInterpretation(
362
0
                                    GDALGetRasterBand(hDS, 2)) == GCI_AlphaBand)
363
0
      alpha_band = 2;
364
365
0
    hBand1 = GDALGetRasterBand(hDS, red_band);
366
0
    if (classified || GDALGetRasterColorTable(hBand1) != NULL) {
367
0
      alpha_band = 0;
368
0
      green_band = 0;
369
0
      blue_band = 0;
370
0
    }
371
0
  } else {
372
0
    int *band_list;
373
374
0
    band_list = msGetGDALBandList(layer, hDS, 4, &band_count);
375
0
    if (band_list == NULL)
376
0
      return -1;
377
378
0
    if (band_count > 0)
379
0
      red_band = band_list[0];
380
0
    else
381
0
      red_band = 0;
382
0
    if (band_count > 2) {
383
0
      green_band = band_list[1];
384
0
      blue_band = band_list[2];
385
0
    } else {
386
0
      green_band = 0;
387
0
      blue_band = 0;
388
0
    }
389
390
0
    if (band_count > 3)
391
0
      alpha_band = band_list[3];
392
0
    else
393
0
      alpha_band = 0;
394
395
0
    free(band_list);
396
0
  }
397
398
0
  band_numbers[0] = red_band;
399
0
  band_numbers[1] = green_band;
400
0
  band_numbers[2] = blue_band;
401
0
  band_numbers[3] = 0;
402
403
0
  if (blue_band != 0 && alpha_band != 0) {
404
0
    band_numbers[3] = alpha_band;
405
0
    band_count = 4;
406
0
  } else if (blue_band != 0 && alpha_band == 0)
407
0
    band_count = 3;
408
0
  else if (alpha_band != 0) {
409
0
    band_numbers[1] = alpha_band;
410
0
    band_count = 2;
411
0
  } else
412
0
    band_count = 1;
413
414
0
  if (layer->debug > 1 || (layer->debug > 0 && green_band != 0)) {
415
0
    msDebug(
416
0
        "msDrawRasterLayerGDAL(): red,green,blue,alpha bands = %d,%d,%d,%d\n",
417
0
        red_band, green_band, blue_band, alpha_band);
418
0
  }
419
420
  /*
421
   * Get band handles for PC256, RGB or RGBA cases.
422
   */
423
0
  hBand1 = GDALGetRasterBand(hDS, red_band);
424
0
  if (hBand1 == NULL)
425
0
    return -1;
426
427
0
  hBand2 = hBand3 = hBandAlpha = NULL;
428
429
0
  if (green_band != 0) {
430
0
    hBand1 = GDALGetRasterBand(hDS, red_band);
431
0
    hBand2 = GDALGetRasterBand(hDS, green_band);
432
0
    hBand3 = GDALGetRasterBand(hDS, blue_band);
433
0
    if (hBand1 == NULL || hBand2 == NULL || hBand3 == NULL)
434
0
      return -1;
435
0
  }
436
437
0
  if (alpha_band != 0)
438
0
    hBandAlpha = GDALGetRasterBand(hDS, alpha_band);
439
440
  /*
441
   * The logic for a classification rendering of non-8bit raster bands
442
   * is sufficiently different than the normal mechanism of loading
443
   * into an 8bit buffer, that we isolate it into it's own subfunction.
444
   */
445
0
  if (classified && hBand1 != NULL &&
446
0
      GDALGetRasterDataType(hBand1) != GDT_Byte) {
447
0
    return msDrawRasterLayerGDAL_16BitClassification(
448
0
        map, layer, rb, hBand1, src_xoff, src_yoff, src_xsize, src_ysize,
449
0
        dst_xoff, dst_yoff, dst_xsize, dst_ysize);
450
0
  }
451
452
  /*
453
   * Get colormap for this image.  If there isn't one, and we have only
454
   * one band create a greyscale colormap.
455
   */
456
0
  bool isDefaultGreyscale = false;
457
458
0
  if (hBand2 != NULL)
459
0
    hColorMap = NULL;
460
0
  else {
461
0
    hColorMap = GDALGetRasterColorTable(hBand1);
462
0
    if (hColorMap != NULL)
463
0
      hColorMap = GDALCloneColorTable(hColorMap);
464
0
    else {
465
0
      hColorMap = GDALCreateColorTable(GPI_RGB);
466
0
      isDefaultGreyscale = true;
467
468
0
      for (i = 0; i < 256; i++) {
469
0
        colorObj pixel = {i, i, i, 0};
470
0
        GDALColorEntry sEntry;
471
472
0
        if (MS_COMPARE_COLORS(pixel, layer->offsite)) {
473
0
          sEntry.c1 = 0;
474
0
          sEntry.c2 = 0;
475
0
          sEntry.c3 = 0;
476
0
          sEntry.c4 = 0; /* alpha set to zero */
477
0
        } else {
478
0
          sEntry.c1 = i;
479
0
          sEntry.c2 = i;
480
0
          sEntry.c3 = i;
481
0
          sEntry.c4 = 255;
482
0
        }
483
484
0
        GDALSetColorEntry(hColorMap, i, &sEntry);
485
0
      }
486
0
    }
487
488
    /*
489
    ** If we have a known NODATA value, mark it now as transparent.
490
    */
491
0
    {
492
0
      int bGotNoData;
493
0
      double dfNoDataValue = msGetGDALNoDataValue(layer, hBand1, &bGotNoData);
494
495
0
      if (bGotNoData && dfNoDataValue >= 0 &&
496
0
          dfNoDataValue < GDALGetColorEntryCount(hColorMap)) {
497
0
        GDALColorEntry sEntry;
498
499
0
        memcpy(&sEntry, GDALGetColorEntry(hColorMap, (int)dfNoDataValue),
500
0
               sizeof(GDALColorEntry));
501
502
0
        sEntry.c4 = 0;
503
0
        GDALSetColorEntry(hColorMap, (int)dfNoDataValue, &sEntry);
504
0
      }
505
0
    }
506
0
  }
507
508
  /*
509
   * Allocate imagery buffers.
510
   */
511
0
  pabyRaw1 =
512
0
      (unsigned char *)malloc(((size_t)dst_xsize) * dst_ysize * band_count);
513
0
  if (pabyRaw1 == NULL) {
514
0
    msSetError(MS_MEMERR, "Allocating work image of size %dx%dx%d failed.",
515
0
               "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count);
516
0
    return -1;
517
0
  }
518
519
0
  if (hBand2 != NULL && hBand3 != NULL) {
520
0
    pabyRaw2 = pabyRaw1 + dst_xsize * dst_ysize * 1;
521
0
    pabyRaw3 = pabyRaw1 + dst_xsize * dst_ysize * 2;
522
0
  }
523
524
0
  if (hBandAlpha != NULL) {
525
0
    if (hBand2 != NULL)
526
0
      pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 3;
527
0
    else
528
0
      pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 1;
529
0
  }
530
531
  /*
532
   * Load image data into buffers with scaling, etc.
533
   */
534
0
  bool bScaled = false;
535
0
  double dfScaleMin = 0;
536
0
  double dfScaleRatio = 0;
537
0
  bool *pbIsNoDataBuffer = NULL;
538
0
  if (LoadGDALImages(hDS, band_numbers, band_count, layer, src_xoff, src_yoff,
539
0
                     src_xsize, src_ysize, pabyRaw1, dst_xsize, dst_ysize,
540
0
                     &bHaveRGBNoData, &nNoData1, &nNoData2, &nNoData3, &bScaled,
541
0
                     &dfScaleMin, &dfScaleRatio, &pbIsNoDataBuffer) == -1) {
542
0
    free(pabyRaw1);
543
0
    free(pbIsNoDataBuffer);
544
0
    return -1;
545
0
  }
546
547
0
  const char *sgamma = msLayerGetProcessingKey(layer, "GAMMA");
548
0
  const double gamma = sgamma ? CPLAtof(sgamma) : 1.0;
549
550
  /*
551
   * Setup the mapping between source eight bit pixel values, and the
552
   * output images color table.  There are two general cases, where the
553
   * class colors are provided by the MAP file, or where we use the native
554
   * color table.
555
   */
556
0
  if (classified) {
557
0
    int c;
558
0
    const char *pszRangeColorspace =
559
0
        msLayerGetProcessingKey(layer, "RANGE_COLORSPACE");
560
0
    colorspace iRangeColorspace;
561
562
0
#ifndef NDEBUG
563
0
    cmap_set = TRUE;
564
0
#endif
565
566
0
    if (hColorMap == NULL) {
567
0
      msSetError(MS_IOERR,
568
0
                 "Attempt to classify 24bit image, this is unsupported.",
569
0
                 "drawGDAL()");
570
0
      free(pabyRaw1);
571
0
      free(pbIsNoDataBuffer);
572
0
      return -1;
573
0
    }
574
575
0
    if (!pszRangeColorspace || !strcasecmp(pszRangeColorspace, "RGB")) {
576
0
      iRangeColorspace = MS_COLORSPACE_RGB;
577
0
    } else if (!strcasecmp(pszRangeColorspace, "HSL")) {
578
0
      iRangeColorspace = MS_COLORSPACE_HSL;
579
0
    } else {
580
0
      msSetError(MS_MISCERR,
581
0
                 "Unknown RANGE_COLORSPACE \"%s\", expecting RGB or HSL",
582
0
                 "drawGDAL()", pszRangeColorspace);
583
0
      GDALDestroyColorTable(hColorMap);
584
0
      free(pabyRaw1);
585
0
      free(pbIsNoDataBuffer);
586
0
      return -1;
587
0
    }
588
589
0
    int color_count = GDALGetColorEntryCount(hColorMap);
590
0
    const bool bScaleColors = bScaled && !isDefaultGreyscale;
591
592
0
    if (!bScaleColors && color_count > 256)
593
0
      color_count = 256;
594
595
0
    for (i = 0; i < color_count; i++) {
596
0
      colorObj pixel;
597
0
      int colormap_index;
598
0
      GDALColorEntry sEntry;
599
600
0
      GDALGetColorEntryAsRGB(hColorMap, i, &sEntry);
601
602
0
      const int j =
603
0
          bScaleColors
604
0
              ? MAX(0, MIN(255, (int)((i - dfScaleMin) * dfScaleRatio)))
605
0
              : i;
606
607
0
      pixel.red = sEntry.c1;
608
0
      pixel.green = sEntry.c2;
609
0
      pixel.blue = sEntry.c3;
610
0
      colormap_index = i;
611
612
0
      if (!MS_COMPARE_COLORS(pixel, layer->offsite)) {
613
0
        c = msGetClass(layer, &pixel, colormap_index);
614
615
0
        if (c != -1) { /* belongs to any class */
616
0
          int s;
617
618
          /* change colour based on colour range?  Currently we
619
             only address the greyscale case properly. */
620
621
0
          if (MS_VALID_COLOR(layer->class[c] -> styles[0] -> mincolor)) {
622
0
            for (s = 0; s < layer->class[c] -> numstyles; s++) {
623
0
              if (MS_VALID_COLOR(layer->class[c] -> styles[s] -> mincolor) &&
624
0
                  MS_VALID_COLOR(layer->class[c] -> styles[s] -> maxcolor)) {
625
0
                if (sEntry.c1 >= layer->class[c] -> styles[s]
626
0
                    -> minvalue &&
627
0
                           sEntry.c1 <=
628
0
                               layer->class[c] -> styles[s] -> maxvalue) {
629
0
                  msValueToRange(layer->class[c] -> styles[s], sEntry.c1,
630
0
                                 iRangeColorspace);
631
0
                  if (MS_VALID_COLOR(layer->class[c] -> styles[s] -> color)) {
632
0
                    rb_cmap[0][j] = layer->class[c]->styles[s]->color.red;
633
0
                    rb_cmap[1][j] = layer->class[c]->styles[s]->color.green;
634
0
                    rb_cmap[2][j] = layer->class[c]->styles[s]->color.blue;
635
0
                    rb_cmap[3][j] =
636
0
                        (layer->class[c] -> styles[s] -> color.alpha != 255)
637
0
                            ? (layer->class[c] -> styles[s] -> color.alpha)
638
0
                            : (255 * layer->class[c] -> styles[0] -> opacity /
639
0
                                                                         100);
640
0
                    break;
641
0
                  }
642
0
                }
643
0
              }
644
0
            }
645
0
          } else if (MS_TRANSPARENT_COLOR(
646
0
                         layer->class[c] -> styles[0] -> color))
647
0
            /* leave it transparent */;
648
649
0
          else if (MS_VALID_COLOR(layer->class[c] -> styles[0] -> color)) {
650
0
            rb_cmap[0][j] = layer->class[c]->styles[0]->color.red;
651
0
            rb_cmap[1][j] = layer->class[c]->styles[0]->color.green;
652
0
            rb_cmap[2][j] = layer->class[c]->styles[0]->color.blue;
653
0
            rb_cmap[3][j] =
654
0
                (255 * layer->class[c] -> styles[0] -> opacity / 100);
655
0
          }
656
657
0
          else { /* Use raster color */
658
0
            rb_cmap[0][j] = pixel.red;
659
0
            rb_cmap[1][j] = pixel.green;
660
0
            rb_cmap[2][j] = pixel.blue;
661
0
            rb_cmap[3][j] = 255;
662
0
          }
663
664
0
          if (gamma != 1.0) {
665
0
            rb_cmap[0][j] = GAMMA_CORRECT(rb_cmap[0][j], gamma);
666
0
            rb_cmap[1][j] = GAMMA_CORRECT(rb_cmap[1][j], gamma);
667
0
            rb_cmap[2][j] = GAMMA_CORRECT(rb_cmap[2][j], gamma);
668
0
          }
669
0
        }
670
0
      }
671
0
    }
672
0
  } else if (hBand2 == NULL && hColorMap != NULL &&
673
0
             rb->type == MS_BUFFER_BYTE_RGBA) {
674
0
    int color_count;
675
0
#ifndef NDEBUG
676
0
    cmap_set = TRUE;
677
0
#endif
678
679
0
    color_count = MS_MIN(256, GDALGetColorEntryCount(hColorMap));
680
0
    const bool bScaleColors = bScaled && !isDefaultGreyscale;
681
682
0
    for (i = 0; i < color_count; i++) {
683
0
      GDALColorEntry sEntry;
684
685
0
      GDALGetColorEntryAsRGB(hColorMap, i, &sEntry);
686
0
      const int j =
687
0
          bScaleColors
688
0
              ? MAX(0, MIN(255, (int)((i - dfScaleMin) * dfScaleRatio)))
689
0
              : i;
690
691
0
      if (sEntry.c4 != 0 &&
692
0
          (!MS_VALID_COLOR(layer->offsite) || layer->offsite.red != sEntry.c1 ||
693
0
           layer->offsite.green != sEntry.c2 ||
694
0
           layer->offsite.blue != sEntry.c3)) {
695
0
        rb_cmap[0][j] = sEntry.c1;
696
0
        rb_cmap[1][j] = sEntry.c2;
697
0
        rb_cmap[2][j] = sEntry.c3;
698
0
        rb_cmap[3][j] = sEntry.c4;
699
0
        if (gamma != 1.0) {
700
0
          rb_cmap[0][j] = GAMMA_CORRECT(rb_cmap[0][j], gamma);
701
0
          rb_cmap[1][j] = GAMMA_CORRECT(rb_cmap[1][j], gamma);
702
0
          rb_cmap[2][j] = GAMMA_CORRECT(rb_cmap[2][j], gamma);
703
0
        }
704
0
      }
705
0
    }
706
0
  }
707
708
0
  if (bHaveRGBNoData && layer->debug)
709
0
    msDebug("msDrawGDAL(): using RGB nodata values from GDAL dataset.\n");
710
711
  /* -------------------------------------------------------------------- */
712
  /*      If there was no alpha band, but we have a dataset level mask    */
713
  /*      load it as massage it so it will function as our alpha for      */
714
  /*      transparency purposes.                                          */
715
  /* -------------------------------------------------------------------- */
716
0
  if (hBandAlpha == NULL) {
717
0
    int nMaskFlags = GDALGetMaskFlags(hBand1);
718
719
0
    if (CSLTestBoolean(
720
0
            CSLFetchNameValueDef(layer->processing, "USE_MASK_BAND", "YES")) &&
721
0
        (nMaskFlags & GMF_PER_DATASET) != 0 &&
722
0
        (nMaskFlags & (GMF_NODATA | GMF_ALL_VALID)) == 0) {
723
0
      CPLErr eErr;
724
0
      unsigned char *pabyOrig = pabyRaw1;
725
726
0
      if (layer->debug)
727
0
        msDebug("msDrawGDAL(): using GDAL mask band for alpha.\n");
728
729
0
      band_count++;
730
731
0
      pabyRaw1 = (unsigned char *)realloc(pabyOrig, ((size_t)dst_xsize) *
732
0
                                                        dst_ysize * band_count);
733
734
0
      if (pabyRaw1 == NULL) {
735
0
        msSetError(MS_MEMERR, "Allocating work image of size %dx%dx%d failed.",
736
0
                   "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count);
737
0
        free(pabyOrig);
738
0
        if (hColorMap != NULL)
739
0
          GDALDestroyColorTable(hColorMap);
740
0
        free(pbIsNoDataBuffer);
741
0
        return -1;
742
0
      }
743
744
0
      if (hBand2 != NULL) {
745
0
        pabyRaw2 = pabyRaw1 + dst_xsize * dst_ysize * 1;
746
0
        pabyRaw3 = pabyRaw1 + dst_xsize * dst_ysize * 2;
747
0
        pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 3;
748
0
      } else {
749
0
        pabyRawAlpha = pabyRaw1 + dst_xsize * dst_ysize * 1;
750
0
      }
751
752
0
      hBandAlpha = GDALGetMaskBand(hBand1);
753
754
0
      eErr = GDALRasterIO(hBandAlpha, GF_Read, src_xoff, src_yoff, src_xsize,
755
0
                          src_ysize, pabyRawAlpha, dst_xsize, dst_ysize,
756
0
                          GDT_Byte, 0, 0);
757
758
0
      if (eErr != CE_None) {
759
0
        msSetError(MS_IOERR, "GDALRasterIO() failed: %s", "drawGDAL()",
760
0
                   CPLGetLastErrorMsg());
761
0
        if (hColorMap != NULL)
762
0
          GDALDestroyColorTable(hColorMap);
763
0
        free(pabyRaw1);
764
0
        free(pbIsNoDataBuffer);
765
0
        return -1;
766
0
      }
767
768
      /* In case the mask is not an alpha channel, expand values of 1 to 255, */
769
      /* so we can deal as it was an alpha band afterwards */
770
0
      if ((nMaskFlags & GMF_ALPHA) == 0) {
771
0
        for (i = 0; i < dst_xsize * dst_ysize; i++)
772
0
          if (pabyRawAlpha[i])
773
0
            pabyRawAlpha[i] = 255;
774
0
      }
775
0
    }
776
0
  }
777
778
  /* -------------------------------------------------------------------- */
779
  /*      Single band plus colormap and alpha to truecolor. (RB)          */
780
  /* -------------------------------------------------------------------- */
781
0
  if (hBand2 == NULL && rb->type == MS_BUFFER_BYTE_RGBA && hBandAlpha != NULL) {
782
0
    assert(cmap_set);
783
784
0
    int k = 0;
785
0
    for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) {
786
0
      for (int j = dst_xoff; j < dst_xoff + dst_xsize; j++, k++) {
787
0
        int src_pixel, src_alpha, cmap_alpha, merged_alpha;
788
0
        if (SKIP_MASK(j, i) || (pbIsNoDataBuffer && pbIsNoDataBuffer[k]))
789
0
          continue;
790
791
0
        src_pixel = pabyRaw1[k];
792
0
        src_alpha = pabyRawAlpha[k];
793
0
        cmap_alpha = rb_cmap[3][src_pixel];
794
795
0
        merged_alpha = (src_alpha * cmap_alpha) / 255;
796
797
0
        if (merged_alpha < 2)
798
0
          /* do nothing - transparent */;
799
0
        else if (merged_alpha > 253) {
800
0
          RB_SET_PIXEL(rb, j, i, rb_cmap[0][src_pixel], rb_cmap[1][src_pixel],
801
0
                       rb_cmap[2][src_pixel], cmap_alpha);
802
0
        } else {
803
0
          RB_MIX_PIXEL(rb, j, i, rb_cmap[0][src_pixel], rb_cmap[1][src_pixel],
804
0
                       rb_cmap[2][src_pixel], merged_alpha);
805
0
        }
806
0
      }
807
0
    }
808
0
  }
809
810
  /* -------------------------------------------------------------------- */
811
  /*      Single band plus colormap (no alpha) to truecolor (RB)          */
812
  /* -------------------------------------------------------------------- */
813
0
  else if (hBand2 == NULL && rb->type == MS_BUFFER_BYTE_RGBA) {
814
0
    assert(cmap_set);
815
816
0
    int k = 0;
817
0
    for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) {
818
0
      for (int j = dst_xoff; j < dst_xoff + dst_xsize; j++, k++) {
819
0
        int src_pixel = pabyRaw1[k];
820
0
        if (SKIP_MASK(j, i) || (pbIsNoDataBuffer && pbIsNoDataBuffer[k]))
821
0
          continue;
822
823
0
        if (rb_cmap[3][src_pixel] > 253) {
824
0
          RB_SET_PIXEL(rb, j, i, rb_cmap[0][src_pixel], rb_cmap[1][src_pixel],
825
0
                       rb_cmap[2][src_pixel], rb_cmap[3][src_pixel]);
826
0
        } else if (rb_cmap[3][src_pixel] > 1) {
827
0
          RB_MIX_PIXEL(rb, j, i, rb_cmap[0][src_pixel], rb_cmap[1][src_pixel],
828
0
                       rb_cmap[2][src_pixel], rb_cmap[3][src_pixel]);
829
0
        }
830
0
      }
831
0
    }
832
0
  }
833
834
  /* -------------------------------------------------------------------- */
835
  /*      Input is 3 band RGB.  Alpha blending is mixed into the loop     */
836
  /*      since this case is less commonly used and has lots of other     */
837
  /*      overhead. (RB)                                                  */
838
  /* -------------------------------------------------------------------- */
839
0
  else if (hBand3 != NULL && rb->type == MS_BUFFER_BYTE_RGBA) {
840
0
    int k = 0;
841
0
    for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) {
842
0
      for (int j = dst_xoff; j < dst_xoff + dst_xsize; j++, k++) {
843
0
        if (SKIP_MASK(j, i) || (pbIsNoDataBuffer && pbIsNoDataBuffer[k]))
844
0
          continue;
845
0
        int red = pabyRaw1[k];
846
0
        int green = pabyRaw2[k];
847
0
        int blue = pabyRaw3[k];
848
0
        if (MS_VALID_COLOR(layer->offsite) && red == layer->offsite.red &&
849
0
            green == layer->offsite.green && blue == layer->offsite.blue)
850
0
          continue;
851
852
0
        if (bHaveRGBNoData && red == nNoData1 && green == nNoData2 &&
853
0
            blue == nNoData3)
854
0
          continue;
855
856
0
        if (pabyRawAlpha == NULL || pabyRawAlpha[k] == 255) {
857
0
          if (gamma != 1.0) {
858
0
            red = GAMMA_CORRECT(red, gamma);
859
0
            green = GAMMA_CORRECT(green, gamma);
860
0
            blue = GAMMA_CORRECT(blue, gamma);
861
0
          }
862
863
0
          RB_SET_PIXEL(rb, j, i, red, green, blue, 255);
864
0
        } else if (pabyRawAlpha[k] != 0) {
865
0
          if (gamma != 1.0) {
866
0
            red = GAMMA_CORRECT(red, gamma);
867
0
            green = GAMMA_CORRECT(green, gamma);
868
0
            blue = GAMMA_CORRECT(blue, gamma);
869
0
          }
870
871
0
          RB_MIX_PIXEL(rb, j, i, red, green, blue, pabyRawAlpha[k]);
872
0
        }
873
0
      }
874
0
    }
875
0
  }
876
877
  /*
878
  ** Cleanup
879
  */
880
0
  free(pabyRaw1);
881
0
  free(pbIsNoDataBuffer);
882
883
0
  if (hColorMap != NULL)
884
0
    GDALDestroyColorTable(hColorMap);
885
886
0
  return 0;
887
0
}
888
889
/************************************************************************/
890
/*                          ParseDefaultLUT()                           */
891
/************************************************************************/
892
893
static int ParseDefaultLUT(const char *lut_def, GByte *lut, int nMaxValIn)
894
895
0
{
896
0
  const char *lut_read;
897
0
  int last_in = 0, last_out = 0, all_done = FALSE;
898
899
  /* -------------------------------------------------------------------- */
900
  /*      Parse definition, applying to lut on the fly.                   */
901
  /* -------------------------------------------------------------------- */
902
0
  lut_read = lut_def;
903
0
  while (!all_done) {
904
0
    int this_in = 0, this_out = 0;
905
0
    int lut_i;
906
907
0
    while (isspace(*lut_read))
908
0
      lut_read++;
909
910
    /* if we are at end, assume nMaxValIn:255 */
911
0
    if (*lut_read == '\0') {
912
0
      all_done = TRUE;
913
0
      if (last_in != nMaxValIn) {
914
0
        this_in = nMaxValIn;
915
0
        this_out = 255;
916
0
      }
917
0
    }
918
919
    /* otherwise read "in:out", and skip past */
920
0
    else {
921
0
      this_in = atoi(lut_read);
922
0
      while (*lut_read != ':' && *lut_read)
923
0
        lut_read++;
924
0
      if (*lut_read == ':')
925
0
        lut_read++;
926
0
      while (isspace(*lut_read))
927
0
        lut_read++;
928
0
      this_out = atoi(lut_read);
929
0
      while (*lut_read && *lut_read != ',' && *lut_read != '\n')
930
0
        lut_read++;
931
0
      if (*lut_read == ',' || *lut_read == '\n')
932
0
        lut_read++;
933
0
      while (isspace(*lut_read))
934
0
        lut_read++;
935
0
    }
936
937
0
    this_in = MS_MAX(0, MS_MIN(nMaxValIn, this_in));
938
0
    this_out = MS_MAX(0, MS_MIN(255, this_out));
939
940
    /* apply linear values from last in:out to this in:out */
941
0
    for (lut_i = last_in; lut_i <= this_in; lut_i++) {
942
0
      double ratio;
943
944
0
      if (last_in == this_in)
945
0
        ratio = 1.0;
946
0
      else
947
0
        ratio = (lut_i - last_in) / (double)(this_in - last_in);
948
949
0
      lut[lut_i] =
950
0
          (int)floor(((1.0 - ratio) * last_out + ratio * this_out) + 0.5);
951
0
    }
952
953
0
    last_in = this_in;
954
0
    last_out = this_out;
955
0
  }
956
957
0
  return 0;
958
0
}
959
960
/************************************************************************/
961
/*                          LutFromGimpLine()                           */
962
/************************************************************************/
963
964
static int LutFromGimpLine(char *lut_line, GByte *lut)
965
966
0
{
967
0
  char wrkLUTDef[1000];
968
0
  int i, count = 0;
969
0
  char **tokens;
970
971
  /* cleanup white space at end of line (DOS LF, etc) */
972
0
  i = strlen(lut_line) - 1;
973
0
  while (i > 0 && isspace(lut_line[i]))
974
0
    lut_line[i--] = '\0';
975
976
0
  while (*lut_line == 10 || *lut_line == 13)
977
0
    lut_line++;
978
979
  /* tokenize line */
980
0
  tokens = CSLTokenizeString(lut_line);
981
0
  if (CSLCount(tokens) != 17 * 2) {
982
0
    CSLDestroy(tokens);
983
0
    msSetError(MS_MISCERR, "GIMP curve file appears corrupt.",
984
0
               "LutFromGimpLine()");
985
0
    return -1;
986
0
  }
987
988
  /* Convert to our own format */
989
0
  wrkLUTDef[0] = '\0';
990
0
  for (i = 0; i < 17; i++) {
991
0
    if (atoi(tokens[i * 2]) >= 0) {
992
0
      if (count++ > 0)
993
0
        strlcat(wrkLUTDef, ",", sizeof(wrkLUTDef));
994
995
0
      snprintf(wrkLUTDef + strlen(wrkLUTDef),
996
0
               sizeof(wrkLUTDef) - strlen(wrkLUTDef), "%s:%s", tokens[i * 2],
997
0
               tokens[i * 2 + 1]);
998
0
    }
999
0
  }
1000
1001
0
  CSLDestroy(tokens);
1002
1003
0
  return ParseDefaultLUT(wrkLUTDef, lut, 255);
1004
0
}
1005
1006
/************************************************************************/
1007
/*                            ParseGimpLUT()                            */
1008
/*                                                                      */
1009
/*      Parse a Gimp style LUT.                                         */
1010
/************************************************************************/
1011
1012
static int ParseGimpLUT(const char *lut_def, GByte *lut, int iColorIndex)
1013
1014
0
{
1015
0
  int i;
1016
0
  GByte lutValue[256];
1017
0
  GByte lutColorBand[256];
1018
0
  char **lines = CSLTokenizeStringComplex(lut_def, "\n", FALSE, FALSE);
1019
1020
0
  if (!EQUALN(lines[0], "# GIMP Curves File", 18) || CSLCount(lines) < 6) {
1021
0
    msSetError(MS_MISCERR, "GIMP curve file appears corrupt.",
1022
0
               "ParseGimpLUT()");
1023
0
    CSLDestroy(lines);
1024
0
    return -1;
1025
0
  }
1026
1027
  /*
1028
   * Convert the overall curve, and the color band specific curve into LUTs.
1029
   */
1030
0
  if (LutFromGimpLine(lines[1], lutValue) != 0 ||
1031
0
      LutFromGimpLine(lines[iColorIndex + 1], lutColorBand) != 0) {
1032
0
    CSLDestroy(lines);
1033
0
    return -1;
1034
0
  }
1035
0
  CSLDestroy(lines);
1036
1037
  /*
1038
   * Compose the two luts as if the raw value passed through the color band
1039
   * specific lut, and then the general value lut.  Usually one or the
1040
   * other will be the identity mapping, but not always.
1041
   */
1042
1043
0
  for (i = 0; i < 256; i++) {
1044
0
    lut[i] = lutValue[lutColorBand[i]];
1045
0
  }
1046
1047
0
  return 0;
1048
0
}
1049
1050
/************************************************************************/
1051
/*                              LoadLUT()                               */
1052
/*                                                                      */
1053
/*      Load a LUT according to RFC 21.                                 */
1054
/************************************************************************/
1055
1056
static int LoadLUT(layerObj *layer, int iColorIndex, char **ppszLutDef)
1057
1058
0
{
1059
0
  const char *lut_def;
1060
0
  char key[20], lut_def_fromfile[2500];
1061
1062
0
  *ppszLutDef = NULL;
1063
1064
  /* -------------------------------------------------------------------- */
1065
  /*      Get lut specifier from processing directives.  Do nothing if    */
1066
  /*      none are found.                                                 */
1067
  /* -------------------------------------------------------------------- */
1068
0
  sprintf(key, "LUT_%d", iColorIndex);
1069
0
  lut_def = msLayerGetProcessingKey(layer, key);
1070
0
  if (lut_def == NULL)
1071
0
    lut_def = msLayerGetProcessingKey(layer, "LUT");
1072
0
  if (lut_def == NULL)
1073
0
    return 0;
1074
1075
  /* -------------------------------------------------------------------- */
1076
  /*      Does this look like a file?  If so, read it into memory.        */
1077
  /* -------------------------------------------------------------------- */
1078
0
  if (strspn(lut_def, "0123456789:, ") != strlen(lut_def)) {
1079
0
    FILE *fp;
1080
0
    char path[MS_MAXPATHLEN];
1081
0
    int len;
1082
0
    msBuildPath(path, layer->map->mappath, lut_def);
1083
0
    fp = fopen(path, "rb");
1084
0
    if (fp == NULL) {
1085
0
      msSetError(MS_IOERR, "Failed to open LUT file '%s'.", "drawGDAL()", path);
1086
0
      return -1;
1087
0
    }
1088
1089
0
    len = fread(lut_def_fromfile, 1, sizeof(lut_def_fromfile), fp);
1090
0
    fclose(fp);
1091
1092
0
    if (len == sizeof(lut_def_fromfile)) {
1093
0
      msSetError(MS_IOERR,
1094
0
                 "LUT definition from file %s longer than maximum buffer size "
1095
0
                 "(%d bytes).",
1096
0
                 "drawGDAL()", path, (int)sizeof(lut_def_fromfile));
1097
0
      return -1;
1098
0
    }
1099
1100
0
    lut_def_fromfile[len] = '\0';
1101
1102
0
    lut_def = lut_def_fromfile;
1103
0
  }
1104
1105
0
  *ppszLutDef = msStrdup(lut_def);
1106
1107
0
  return 0;
1108
0
}
1109
1110
/************************************************************************/
1111
/*                              FreeLUTs()                              */
1112
/************************************************************************/
1113
1114
0
static void FreeLUTs(char **apszLUTs) {
1115
0
  int i;
1116
0
  for (i = 0; i < 4; i++)
1117
0
    msFree(apszLUTs[i]);
1118
0
  msFree(apszLUTs);
1119
0
}
1120
1121
/************************************************************************/
1122
/*                            LoadLUTs()                                */
1123
/*                                                                      */
1124
/* Return an array of 4 strings (some possibly NULL) with loaded LUTs   */
1125
/* or NULL in case of failure.                                          */
1126
/************************************************************************/
1127
1128
0
static char **LoadLUTs(layerObj *layer, int band_count) {
1129
0
  int i;
1130
0
  char **apszLUTs;
1131
1132
0
  assert(band_count <= 4);
1133
1134
0
  apszLUTs = (char **)msSmallCalloc(4, sizeof(char *));
1135
0
  for (i = 0; i < band_count; i++) {
1136
0
    if (LoadLUT(layer, i + 1, &apszLUTs[i]) != 0) {
1137
0
      FreeLUTs(apszLUTs);
1138
0
      return NULL;
1139
0
    }
1140
0
  }
1141
1142
0
  return apszLUTs;
1143
0
}
1144
1145
/************************************************************************/
1146
/*                  GetDataTypeAppropriateForLUTS()                     */
1147
/*                                                                      */
1148
/*      This does a quick examination of the LUT strings to determine   */
1149
/*      if they have input values > 255, in which case the raster data  */
1150
/*      must be queries on 16-bits.                                     */
1151
/************************************************************************/
1152
1153
0
static GDALDataType GetDataTypeAppropriateForLUTS(char **apszLUTs) {
1154
0
  GDALDataType eDT = GDT_Byte;
1155
0
  int i;
1156
0
  for (i = 0; i < 4; i++) {
1157
0
    const char *pszLastTuple;
1158
0
    int nLastInValue;
1159
0
    if (apszLUTs[i] == NULL)
1160
0
      continue;
1161
0
    if (EQUALN(apszLUTs[i], "# GIMP", 6))
1162
0
      continue;
1163
    /* Find last in:out tuple in string */
1164
0
    pszLastTuple = strrchr(apszLUTs[i], ',');
1165
0
    if (pszLastTuple == NULL)
1166
0
      pszLastTuple = apszLUTs[i];
1167
0
    else
1168
0
      pszLastTuple++;
1169
0
    while (*pszLastTuple == ' ')
1170
0
      pszLastTuple++;
1171
0
    nLastInValue = atoi(pszLastTuple);
1172
0
    if (nLastInValue > 255) {
1173
0
      eDT = GDT_UInt16;
1174
0
      break;
1175
0
    }
1176
0
  }
1177
0
  return eDT;
1178
0
}
1179
1180
/************************************************************************/
1181
/*                              ApplyLUT()                              */
1182
/************************************************************************/
1183
1184
static int ApplyLUT(int iColorIndex, const char *lut_def, const void *pInBuffer,
1185
0
                    GDALDataType eDT, GByte *pabyOutBuffer, int nPixelCount) {
1186
0
  int i, err;
1187
0
  GByte byteLut[256];
1188
0
  GByte *uint16Lut = NULL;
1189
1190
0
  assert(eDT == GDT_Byte || eDT == GDT_UInt16);
1191
1192
0
  if (lut_def == NULL) {
1193
0
    if (pInBuffer != pabyOutBuffer) {
1194
0
      GDALCopyWords((void *)pInBuffer, eDT, GDALGetDataTypeSize(eDT) / 8,
1195
0
                    pabyOutBuffer, GDT_Byte, 1, nPixelCount);
1196
0
    }
1197
0
    return 0;
1198
0
  }
1199
1200
  /* -------------------------------------------------------------------- */
1201
  /*      Parse the LUT description.                                      */
1202
  /* -------------------------------------------------------------------- */
1203
0
  if (EQUALN(lut_def, "# GIMP", 6)) {
1204
0
    if (eDT != GDT_Byte) {
1205
0
      msSetError(MS_MISCERR, "Cannot apply a GIMP LUT on a 16-bit buffer",
1206
0
                 "ApplyLUT()");
1207
0
      return -1;
1208
0
    }
1209
0
    err = ParseGimpLUT(lut_def, byteLut, iColorIndex);
1210
0
  } else {
1211
0
    if (eDT == GDT_Byte)
1212
0
      err = ParseDefaultLUT(lut_def, byteLut, 255);
1213
0
    else {
1214
0
      uint16Lut = (GByte *)malloc(65536);
1215
0
      if (uint16Lut == NULL) {
1216
0
        msSetError(MS_MEMERR, "Cannot allocate 16-bit LUT", "ApplyLUT()");
1217
0
        return -1;
1218
0
      }
1219
0
      err = ParseDefaultLUT(lut_def, uint16Lut, 65535);
1220
0
    }
1221
0
  }
1222
1223
  /* -------------------------------------------------------------------- */
1224
  /*      Apply LUT.                                                      */
1225
  /* -------------------------------------------------------------------- */
1226
0
  if (eDT == GDT_Byte) {
1227
0
    for (i = 0; i < nPixelCount; i++)
1228
0
      pabyOutBuffer[i] = byteLut[((GByte *)pInBuffer)[i]];
1229
0
  } else {
1230
0
    for (i = 0; i < nPixelCount; i++)
1231
0
      pabyOutBuffer[i] = uint16Lut[((GUInt16 *)pInBuffer)[i]];
1232
0
    free(uint16Lut);
1233
0
  }
1234
1235
0
  return err;
1236
0
}
1237
1238
/************************************************************************/
1239
/*                           LoadGDALImages()                           */
1240
/*                                                                      */
1241
/*      This call will load and process 1-4 bands of input for the      */
1242
/*      selected rectangle, loading the result into the passed 8bit     */
1243
/*      buffer.  The processing options include scaling.                */
1244
/************************************************************************/
1245
1246
static int LoadGDALImages(GDALDatasetH hDS, int band_numbers[4], int band_count,
1247
                          layerObj *layer, int src_xoff, int src_yoff,
1248
                          int src_xsize, int src_ysize, GByte *pabyWholeBuffer,
1249
                          int dst_xsize, int dst_ysize, int *pbHaveRGBNoData,
1250
                          int *pnNoData1, int *pnNoData2, int *pnNoData3,
1251
                          bool *pbScaled, double *pdfScaleMin,
1252
                          double *pdfScaleRatio, bool **ppbIsNoDataBuffer)
1253
1254
0
{
1255
0
  int iColorIndex, result_code = 0;
1256
0
  CPLErr eErr;
1257
0
  float *pafWholeRawData;
1258
0
  char **papszLUTs;
1259
1260
0
  *pbScaled = false;
1261
0
  *pdfScaleMin = 0;
1262
0
  *pdfScaleRatio = 0;
1263
0
  *ppbIsNoDataBuffer = NULL;
1264
1265
  /* -------------------------------------------------------------------- */
1266
  /*      If we have no alpha band, but we do have three input            */
1267
  /*      bands, then check for nodata values.  If we only have one       */
1268
  /*      input band, then nodata will already have been adderssed as     */
1269
  /*      part of the real or manufactured color table.                   */
1270
  /* -------------------------------------------------------------------- */
1271
0
  if (band_count == 3) {
1272
0
    *pnNoData1 = (int)msGetGDALNoDataValue(
1273
0
        layer, GDALGetRasterBand(hDS, band_numbers[0]), pbHaveRGBNoData);
1274
1275
0
    if (*pbHaveRGBNoData)
1276
0
      *pnNoData2 = (int)msGetGDALNoDataValue(
1277
0
          layer, GDALGetRasterBand(hDS, band_numbers[1]), pbHaveRGBNoData);
1278
0
    if (*pbHaveRGBNoData)
1279
0
      *pnNoData3 = (int)msGetGDALNoDataValue(
1280
0
          layer, GDALGetRasterBand(hDS, band_numbers[2]), pbHaveRGBNoData);
1281
0
  }
1282
1283
  /* -------------------------------------------------------------------- */
1284
  /*      Are we doing a simple, non-scaling case?  If so, read directly  */
1285
  /*      and return.                                                     */
1286
  /* -------------------------------------------------------------------- */
1287
0
  if (CSLFetchNameValue(layer->processing, "SCALE") == NULL &&
1288
0
      CSLFetchNameValue(layer->processing, "SCALE_1") == NULL &&
1289
0
      CSLFetchNameValue(layer->processing, "SCALE_2") == NULL &&
1290
0
      CSLFetchNameValue(layer->processing, "SCALE_3") == NULL &&
1291
0
      CSLFetchNameValue(layer->processing, "SCALE_4") == NULL) {
1292
1293
0
    GDALDataType eDT;
1294
0
    GUInt16 *panBuffer = NULL;
1295
0
    void *pBuffer;
1296
1297
0
    papszLUTs = LoadLUTs(layer, band_count);
1298
0
    if (papszLUTs == NULL) {
1299
0
      return -1;
1300
0
    }
1301
1302
0
    eDT = GetDataTypeAppropriateForLUTS(papszLUTs);
1303
0
    if (eDT == GDT_UInt16) {
1304
0
      panBuffer = (GUInt16 *)malloc(sizeof(GUInt16) * dst_xsize * dst_ysize *
1305
0
                                    band_count);
1306
1307
0
      if (panBuffer == NULL) {
1308
0
        msSetError(MS_MEMERR,
1309
0
                   "Allocating work uint16 image of size %dx%dx%d failed.",
1310
0
                   "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count);
1311
0
        FreeLUTs(papszLUTs);
1312
0
        return -1;
1313
0
      }
1314
0
      pBuffer = panBuffer;
1315
0
    } else
1316
0
      pBuffer = pabyWholeBuffer;
1317
1318
0
    eErr = GDALDatasetRasterIO(hDS, GF_Read, src_xoff, src_yoff, src_xsize,
1319
0
                               src_ysize, pBuffer, dst_xsize, dst_ysize, eDT,
1320
0
                               band_count, band_numbers, 0, 0, 0);
1321
1322
0
    if (eErr != CE_None) {
1323
0
      msSetError(MS_IOERR, "GDALDatasetRasterIO() failed: %s", "drawGDAL()",
1324
0
                 CPLGetLastErrorMsg());
1325
0
      FreeLUTs(papszLUTs);
1326
0
      msFree(panBuffer);
1327
0
      return -1;
1328
0
    }
1329
1330
0
    for (iColorIndex = 0; iColorIndex < band_count && result_code == 0;
1331
0
         iColorIndex++) {
1332
0
      result_code =
1333
0
          ApplyLUT(iColorIndex + 1, papszLUTs[iColorIndex],
1334
0
                   (GByte *)pBuffer + dst_xsize * dst_ysize * iColorIndex *
1335
0
                                          (GDALGetDataTypeSize(eDT) / 8),
1336
0
                   eDT, pabyWholeBuffer + dst_xsize * dst_ysize * iColorIndex,
1337
0
                   dst_xsize * dst_ysize);
1338
0
    }
1339
1340
0
    FreeLUTs(papszLUTs);
1341
0
    msFree(panBuffer);
1342
0
    return result_code;
1343
0
  }
1344
1345
  /* -------------------------------------------------------------------- */
1346
  /*      Disable use of nodata if we are doing scaling.                  */
1347
  /* -------------------------------------------------------------------- */
1348
0
  *pbHaveRGBNoData = FALSE;
1349
1350
  /* -------------------------------------------------------------------- */
1351
  /*      We need to do some scaling.  Will load into either a 16bit      */
1352
  /*      unsigned or a floating point buffer depending on the source     */
1353
  /*      data.  We offer a special case for 16U data because it is       */
1354
  /*      common and it is a substantial win to avoid a lot of floating    */
1355
  /*      point operations on it.                                         */
1356
  /* -------------------------------------------------------------------- */
1357
  /* TODO */
1358
1359
  /* -------------------------------------------------------------------- */
1360
  /*      Allocate the raw imagery buffer, and load into it (band         */
1361
  /*      interleaved).                                                   */
1362
  /* -------------------------------------------------------------------- */
1363
0
  pafWholeRawData =
1364
0
      (float *)malloc(sizeof(float) * dst_xsize * dst_ysize * band_count);
1365
1366
0
  if (pafWholeRawData == NULL) {
1367
0
    msSetError(MS_MEMERR,
1368
0
               "Allocating work float image of size %dx%dx%d failed.",
1369
0
               "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize, band_count);
1370
0
    return -1;
1371
0
  }
1372
1373
0
  eErr = GDALDatasetRasterIO(hDS, GF_Read, src_xoff, src_yoff, src_xsize,
1374
0
                             src_ysize, pafWholeRawData, dst_xsize, dst_ysize,
1375
0
                             GDT_Float32, band_count, band_numbers, 0, 0, 0);
1376
1377
0
  if (eErr != CE_None) {
1378
0
    msSetError(MS_IOERR, "GDALDatasetRasterIO() failed: %s", "drawGDAL()",
1379
0
               CPLGetLastErrorMsg());
1380
1381
0
    free(pafWholeRawData);
1382
0
    return -1;
1383
0
  }
1384
1385
0
  papszLUTs = LoadLUTs(layer, band_count);
1386
0
  if (papszLUTs == NULL) {
1387
0
    free(pafWholeRawData);
1388
0
    return -1;
1389
0
  }
1390
1391
0
  if (GetDataTypeAppropriateForLUTS(papszLUTs) != GDT_Byte) {
1392
0
    msDebug("LoadGDALImage(%s): One of the LUT contains a input value > 255.\n"
1393
0
            "This is not properly supported in combination with SCALE\n",
1394
0
            layer->name);
1395
0
  }
1396
1397
  /* -------------------------------------------------------------------- */
1398
  /*      Fetch the scale processing option.                              */
1399
  /* -------------------------------------------------------------------- */
1400
0
  for (iColorIndex = 0; iColorIndex < band_count; iColorIndex++) {
1401
0
    unsigned char *pabyBuffer;
1402
0
    double dfScaleMin = 0.0, dfScaleMax = 255.0, dfScaleRatio = 0,
1403
0
           dfNoDataValue;
1404
0
    const char *pszScaleInfo;
1405
0
    float *pafRawData;
1406
0
    int nPixelCount = dst_xsize * dst_ysize, i, bGotNoData = FALSE;
1407
0
    GDALRasterBandH hBand = GDALGetRasterBand(hDS, band_numbers[iColorIndex]);
1408
0
    pszScaleInfo = CSLFetchNameValue(layer->processing, "SCALE");
1409
0
    const bool bIsAllBandScale = pszScaleInfo != NULL;
1410
0
    if (pszScaleInfo == NULL) {
1411
0
      char szBandScalingName[20];
1412
1413
0
      sprintf(szBandScalingName, "SCALE_%d", iColorIndex + 1);
1414
0
      pszScaleInfo = CSLFetchNameValue(layer->processing, szBandScalingName);
1415
0
    }
1416
1417
0
    if (pszScaleInfo != NULL) {
1418
0
      char **papszTokens;
1419
1420
0
      papszTokens = CSLTokenizeStringComplex(pszScaleInfo, " ,", FALSE, FALSE);
1421
0
      if (CSLCount(papszTokens) == 1 && EQUAL(papszTokens[0], "AUTO")) {
1422
0
        if (bIsAllBandScale &&
1423
0
            GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand &&
1424
0
            GDALGetRasterDataType(hBand) == GDT_Byte) {
1425
          // Do not try to scale the alpha band, as it is going to produce
1426
          // wrong results
1427
0
          dfScaleMin = 0.0;
1428
0
          dfScaleMax = 255.0;
1429
0
          dfScaleRatio = 1.0;
1430
0
        } else {
1431
0
          dfScaleMin = dfScaleMax = 0.0;
1432
0
        }
1433
0
      } else if (CSLCount(papszTokens) != 2) {
1434
0
        free(pafWholeRawData);
1435
0
        CSLDestroy(papszTokens);
1436
0
        FreeLUTs(papszLUTs);
1437
0
        msSetError(MS_MISCERR,
1438
0
                   "SCALE PROCESSING option unparsable for layer %s.",
1439
0
                   "msDrawGDAL()", layer->name);
1440
0
        return -1;
1441
0
      } else {
1442
0
        dfScaleMin = atof(papszTokens[0]);
1443
0
        dfScaleMax = atof(papszTokens[1]);
1444
0
      }
1445
0
      CSLDestroy(papszTokens);
1446
0
    }
1447
1448
    /* -------------------------------------------------------------------- */
1449
    /*      If we are using autoscaling, then compute the max and min       */
1450
    /*      now.  Perhaps we should eventually honour the offsite value     */
1451
    /*      as a nodata value, or get it from GDAL.                         */
1452
    /* -------------------------------------------------------------------- */
1453
0
    pafRawData = pafWholeRawData + iColorIndex * dst_xsize * dst_ysize;
1454
1455
0
    dfNoDataValue = msGetGDALNoDataValue(layer, hBand, &bGotNoData);
1456
1457
    /* we force assignment to a float rather than letting pafRawData[i]
1458
       get promoted to double later to avoid float precision issues. */
1459
0
    float fNoDataValue = (float)dfNoDataValue;
1460
1461
0
    if (dfScaleMin == dfScaleMax) {
1462
0
      int bMinMaxSet = 0;
1463
1464
      /* we force assignment to a float rather than letting pafRawData[i]
1465
         get promoted to double later to avoid float precision issues. */
1466
0
      float fNoDataValue = (float)dfNoDataValue;
1467
1468
0
      for (i = 0; i < nPixelCount; i++) {
1469
0
        if (bGotNoData && IsNoData(pafRawData[i], fNoDataValue))
1470
0
          continue;
1471
1472
0
        if (CPLIsNan(pafRawData[i]))
1473
0
          continue;
1474
1475
0
        if (!bMinMaxSet) {
1476
0
          dfScaleMin = dfScaleMax = pafRawData[i];
1477
0
          bMinMaxSet = TRUE;
1478
0
        }
1479
1480
0
        dfScaleMin = MS_MIN(dfScaleMin, pafRawData[i]);
1481
0
        dfScaleMax = MS_MAX(dfScaleMax, pafRawData[i]);
1482
0
      }
1483
1484
0
      if (dfScaleMin == dfScaleMax)
1485
0
        dfScaleMax = dfScaleMin + 1.0;
1486
0
    }
1487
1488
0
    if (layer->debug > 0)
1489
0
      msDebug("msDrawGDAL(%s): scaling to 8bit, src range=%g,%g\n", layer->name,
1490
0
              dfScaleMin, dfScaleMax);
1491
1492
    /* -------------------------------------------------------------------- */
1493
    /*      Now process the data.                                           */
1494
    /* -------------------------------------------------------------------- */
1495
0
    if (dfScaleRatio == 0.0)
1496
0
      dfScaleRatio = 256.0 / (dfScaleMax - dfScaleMin);
1497
0
    pabyBuffer = pabyWholeBuffer + iColorIndex * nPixelCount;
1498
1499
0
    if (iColorIndex == 0 && bGotNoData)
1500
0
      *ppbIsNoDataBuffer = (bool *)calloc(nPixelCount, 1);
1501
1502
0
    for (i = 0; i < nPixelCount; i++) {
1503
0
      float fScaledValue;
1504
1505
0
      if (bGotNoData && IsNoData(pafRawData[i], fNoDataValue)) {
1506
0
        if (iColorIndex == 0)
1507
0
          (*ppbIsNoDataBuffer)[i] = true;
1508
0
        continue;
1509
0
      }
1510
1511
0
      fScaledValue = (float)((pafRawData[i] - dfScaleMin) * dfScaleRatio);
1512
1513
0
      if (fScaledValue < 0.0)
1514
0
        pabyBuffer[i] = 0;
1515
0
      else if (fScaledValue > 255.0)
1516
0
        pabyBuffer[i] = 255;
1517
0
      else
1518
0
        pabyBuffer[i] = (int)fScaledValue;
1519
0
    }
1520
1521
0
    if (iColorIndex == 0) {
1522
0
      *pbScaled = true;
1523
0
      *pdfScaleMin = dfScaleMin;
1524
0
      *pdfScaleRatio = dfScaleRatio;
1525
0
    }
1526
1527
    /* -------------------------------------------------------------------- */
1528
    /*      Report a warning if NODATA keyword was applied.  We are         */
1529
    /*      unable to utilize it since we can't return any pixels marked    */
1530
    /*      as nodata from this function.  Need to fix someday.             */
1531
    /* -------------------------------------------------------------------- */
1532
0
    if (bGotNoData)
1533
0
      msDebug("LoadGDALImage(%s): NODATA value %g in GDAL\n"
1534
0
              "file or PROCESSING directive largely ignored.  Not yet fully "
1535
0
              "supported for\n"
1536
0
              "unclassified scaled data.  The NODATA value is excluded from "
1537
0
              "auto-scaling\n"
1538
0
              "min/max computation, but will not be transparent.\n",
1539
0
              layer->name, dfNoDataValue);
1540
1541
    /* -------------------------------------------------------------------- */
1542
    /*      Apply LUT if there is one.                                      */
1543
    /* -------------------------------------------------------------------- */
1544
0
    result_code = ApplyLUT(iColorIndex + 1, papszLUTs[iColorIndex], pabyBuffer,
1545
0
                           GDT_Byte, pabyBuffer, dst_xsize * dst_ysize);
1546
0
    if (result_code == -1) {
1547
0
      free(pafWholeRawData);
1548
0
      FreeLUTs(papszLUTs);
1549
0
      return result_code;
1550
0
    }
1551
0
  }
1552
1553
0
  free(pafWholeRawData);
1554
0
  FreeLUTs(papszLUTs);
1555
1556
0
  return result_code;
1557
0
}
1558
1559
/************************************************************************/
1560
/*                       msGetGDALGeoTransform()                        */
1561
/*                                                                      */
1562
/*      Cover function that tries GDALGetGeoTransform(), a world        */
1563
/*      file or OWS extents.  It is assumed that TLOCK_GDAL is held     */
1564
/*      before this function is called.                                 */
1565
/************************************************************************/
1566
1567
int msGetGDALGeoTransform(GDALDatasetH hDS, mapObj *map, layerObj *layer,
1568
                          double *padfGeoTransform)
1569
1570
0
{
1571
0
  const char *extent_priority = NULL;
1572
0
  const char *value;
1573
0
  const char *gdalDesc;
1574
0
  const char *fullPath;
1575
0
  char *fileExtension = NULL;
1576
0
  char szPath[MS_MAXPATHLEN];
1577
0
  int fullPathLen;
1578
0
  int success = 0;
1579
0
  rectObj rect;
1580
1581
  /* -------------------------------------------------------------------- */
1582
  /*      some GDAL drivers (ie. GIF) don't set geotransform on failure.  */
1583
  /* -------------------------------------------------------------------- */
1584
0
  padfGeoTransform[0] = 0.0;
1585
0
  padfGeoTransform[1] = 1.0;
1586
0
  padfGeoTransform[2] = 0.0;
1587
0
  padfGeoTransform[3] = GDALGetRasterYSize(hDS);
1588
0
  padfGeoTransform[4] = 0.0;
1589
0
  padfGeoTransform[5] = -1.0;
1590
1591
  /* -------------------------------------------------------------------- */
1592
  /*      Do we want to override GDAL with a worldfile if one is present? */
1593
  /* -------------------------------------------------------------------- */
1594
0
  extent_priority = CSLFetchNameValue(layer->processing, "EXTENT_PRIORITY");
1595
1596
0
  if (extent_priority != NULL && EQUALN(extent_priority, "WORLD", 5)) {
1597
    /* is there a user configured worldfile? */
1598
0
    value = CSLFetchNameValue(layer->processing, "WORLDFILE");
1599
1600
0
    if (value != NULL) {
1601
      /* at this point, fullPath may be a filePath or path only */
1602
0
      fullPath = msBuildPath(szPath, map->mappath, value);
1603
1604
      /* fullPath is a path only, so let's append the dataset filename */
1605
0
      if (strrchr(szPath, '.') == NULL) {
1606
0
        fullPathLen = strlen(fullPath);
1607
0
        gdalDesc = msStripPath((char *)GDALGetDescription(hDS));
1608
1609
0
        if ((fullPathLen + strlen(gdalDesc)) < MS_MAXPATHLEN) {
1610
0
          strcpy((char *)(fullPath + fullPathLen), gdalDesc);
1611
0
        } else {
1612
0
          msDebug(
1613
0
              "Path length to alternative worldfile exceeds MS_MAXPATHLEN.\n");
1614
0
          fullPath = NULL;
1615
0
        }
1616
0
      }
1617
      /* fullPath has a filename included, so get the extension */
1618
0
      else {
1619
0
        fileExtension = msStrdup(strrchr(szPath, '.') + 1);
1620
0
      }
1621
0
    }
1622
    /* common behavior with worldfile generated from basename + .wld */
1623
0
    else {
1624
0
      fullPath = GDALGetDescription(hDS);
1625
0
      fileExtension = msStrdup("wld");
1626
0
    }
1627
1628
0
    if (fullPath)
1629
0
      success = GDALReadWorldFile(fullPath, fileExtension, padfGeoTransform);
1630
1631
0
    if (success && layer->debug >= MS_DEBUGLEVEL_VVV) {
1632
0
      msDebug("Worldfile location: %s.\n", fullPath);
1633
0
    } else if (layer->debug >= MS_DEBUGLEVEL_VVV) {
1634
0
      msDebug("Failed using worldfile location: %s.\n",
1635
0
              fullPath ? fullPath : "(null)");
1636
0
    }
1637
1638
0
    msFree(fileExtension);
1639
1640
0
    if (success)
1641
0
      return MS_SUCCESS;
1642
0
  }
1643
1644
  /* -------------------------------------------------------------------- */
1645
  /*      Try GDAL.                                                       */
1646
  /*                                                                      */
1647
  /*      Make sure that ymax is always at the top, and ymin at the       */
1648
  /*      bottom ... that is flip any files without the usual             */
1649
  /*      orientation.  This is intended to enable display of "raw"       */
1650
  /*      files with no coordinate system otherwise they break down in    */
1651
  /*      many ways.                                                      */
1652
  /* -------------------------------------------------------------------- */
1653
0
  if (GDALGetGeoTransform(hDS, padfGeoTransform) == CE_None) {
1654
0
    if (padfGeoTransform[5] == 1.0 && padfGeoTransform[3] == 0.0) {
1655
0
      padfGeoTransform[5] = -1.0;
1656
0
      padfGeoTransform[3] = GDALGetRasterYSize(hDS);
1657
0
    }
1658
1659
0
    return MS_SUCCESS;
1660
0
  }
1661
1662
  /* -------------------------------------------------------------------- */
1663
  /*      Try worldfile.                                                  */
1664
  /* -------------------------------------------------------------------- */
1665
0
  if (GDALGetDescription(hDS) != NULL &&
1666
0
      GDALReadWorldFile(GDALGetDescription(hDS), "wld", padfGeoTransform)) {
1667
0
    return MS_SUCCESS;
1668
0
  }
1669
1670
  /* -------------------------------------------------------------------- */
1671
  /*      Do we have the extent keyword on the layer?  We only use        */
1672
  /*      this if we have a single raster associated with the layer as    */
1673
  /*      opposed to a tile index.                                        */
1674
  /*                                                                      */
1675
  /*      Arguably this ought to take priority over all the other         */
1676
  /*      stuff.                                                          */
1677
  /* -------------------------------------------------------------------- */
1678
0
  if (MS_VALID_EXTENT(layer->extent) && layer->data != NULL) {
1679
0
    rect = layer->extent;
1680
1681
0
    padfGeoTransform[0] = rect.minx;
1682
0
    padfGeoTransform[1] =
1683
0
        (rect.maxx - rect.minx) / (double)GDALGetRasterXSize(hDS);
1684
0
    padfGeoTransform[2] = 0;
1685
0
    padfGeoTransform[3] = rect.maxy;
1686
0
    padfGeoTransform[4] = 0;
1687
0
    padfGeoTransform[5] =
1688
0
        (rect.miny - rect.maxy) / (double)GDALGetRasterYSize(hDS);
1689
1690
0
    return MS_SUCCESS;
1691
0
  }
1692
1693
  /* -------------------------------------------------------------------- */
1694
  /*      We didn't find any info ... use the default.                    */
1695
  /*      Reset our default geotransform.  GDALGetGeoTransform() may      */
1696
  /*      have altered it even if GDALGetGeoTransform() failed.           */
1697
  /* -------------------------------------------------------------------- */
1698
0
  padfGeoTransform[0] = 0.0;
1699
0
  padfGeoTransform[1] = 1.0;
1700
0
  padfGeoTransform[2] = 0.0;
1701
0
  padfGeoTransform[3] = GDALGetRasterYSize(hDS);
1702
0
  padfGeoTransform[4] = 0.0;
1703
0
  padfGeoTransform[5] = -1.0;
1704
1705
0
  return MS_FAILURE;
1706
0
}
1707
1708
/************************************************************************/
1709
/*                   msDrawRasterLayerGDAL_RawMode()                    */
1710
/*                                                                      */
1711
/*      Handle the loading and application of data in rawmode.          */
1712
/************************************************************************/
1713
1714
static int
1715
msDrawRasterLayerGDAL_RawMode(mapObj *map, layerObj *layer, imageObj *image,
1716
                              GDALDatasetH hDS, int src_xoff, int src_yoff,
1717
                              int src_xsize, int src_ysize, int dst_xoff,
1718
                              int dst_yoff, int dst_xsize, int dst_ysize)
1719
1720
0
{
1721
0
  void *pBuffer;
1722
0
  GDALDataType eDataType;
1723
0
  int *band_list, band_count;
1724
0
  int i, j, k, band;
1725
0
  CPLErr eErr;
1726
0
  float *f_nodatas = NULL;
1727
0
  unsigned char *b_nodatas = NULL;
1728
0
  GInt16 *i_nodatas = NULL;
1729
0
  int got_nodata = FALSE;
1730
0
  rasterBufferObj *mask_rb = NULL;
1731
0
  rasterBufferObj s_mask_rb;
1732
0
  if (layer->mask) {
1733
0
    int ret;
1734
0
    layerObj *maskLayer = GET_LAYER(map, msGetLayerIndex(map, layer->mask));
1735
0
    mask_rb = &s_mask_rb;
1736
0
    memset(mask_rb, 0, sizeof(s_mask_rb));
1737
0
    ret = MS_IMAGE_RENDERER(maskLayer->maskimage)
1738
0
              ->getRasterBufferHandle(maskLayer->maskimage, mask_rb);
1739
0
    if (ret != MS_SUCCESS)
1740
0
      return -1;
1741
0
  }
1742
1743
0
  if (image->format->bands > 256) {
1744
0
    msSetError(MS_IMGERR, "Too many bands (more than 256).",
1745
0
               "msDrawRasterLayerGDAL_RawMode()");
1746
0
    return -1;
1747
0
  }
1748
1749
  /* -------------------------------------------------------------------- */
1750
  /*      What data type do we need?                                      */
1751
  /* -------------------------------------------------------------------- */
1752
0
  if (image->format->imagemode == MS_IMAGEMODE_INT16)
1753
0
    eDataType = GDT_Int16;
1754
0
  else if (image->format->imagemode == MS_IMAGEMODE_FLOAT32)
1755
0
    eDataType = GDT_Float32;
1756
0
  else if (image->format->imagemode == MS_IMAGEMODE_BYTE)
1757
0
    eDataType = GDT_Byte;
1758
0
  else
1759
0
    return -1;
1760
1761
  /* -------------------------------------------------------------------- */
1762
  /*      Work out the band list.                                         */
1763
  /* -------------------------------------------------------------------- */
1764
0
  band_list = msGetGDALBandList(layer, hDS, image->format->bands, &band_count);
1765
0
  if (band_list == NULL)
1766
0
    return -1;
1767
1768
0
  if (band_count != image->format->bands) {
1769
0
    free(band_list);
1770
0
    msSetError(MS_IMGERR,
1771
0
               "BANDS PROCESSING directive has wrong number of bands, expected "
1772
0
               "%d, got %d.",
1773
0
               "msDrawRasterLayerGDAL_RawMode()", image->format->bands,
1774
0
               band_count);
1775
0
    return -1;
1776
0
  }
1777
1778
  /* -------------------------------------------------------------------- */
1779
  /*      Do we have nodata values?                                       */
1780
  /* -------------------------------------------------------------------- */
1781
0
  f_nodatas = (float *)calloc(band_count, sizeof(float));
1782
0
  if (f_nodatas == NULL) {
1783
0
    msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n",
1784
0
               "msDrawRasterLayerGDAL_RawMode()", __FILE__, __LINE__,
1785
0
               (unsigned int)(sizeof(float) * band_count));
1786
0
    free(band_list);
1787
0
    return -1;
1788
0
  }
1789
1790
0
  if (band_count <= 3 &&
1791
0
      (layer->offsite.red != -1 || layer->offsite.green != -1 ||
1792
0
       layer->offsite.blue != -1)) {
1793
0
    if (band_count > 0)
1794
0
      f_nodatas[0] = layer->offsite.red;
1795
0
    if (band_count > 1)
1796
0
      f_nodatas[1] = layer->offsite.green;
1797
0
    if (band_count > 2)
1798
0
      f_nodatas[2] = layer->offsite.blue;
1799
0
    got_nodata = TRUE;
1800
0
  }
1801
1802
0
  if (!got_nodata) {
1803
0
    got_nodata = TRUE;
1804
0
    for (band = 0; band < band_count && got_nodata; band++) {
1805
0
      f_nodatas[band] = msGetGDALNoDataValue(
1806
0
          layer, GDALGetRasterBand(hDS, band_list[band]), &got_nodata);
1807
0
    }
1808
0
  }
1809
1810
0
  if (!got_nodata) {
1811
0
    free(f_nodatas);
1812
0
    f_nodatas = NULL;
1813
0
  } else if (eDataType == GDT_Byte) {
1814
0
    b_nodatas = (unsigned char *)f_nodatas;
1815
0
    for (band = 0; band < band_count; band++)
1816
0
      b_nodatas[band] = (unsigned char)f_nodatas[band];
1817
0
  } else if (eDataType == GDT_Int16) {
1818
0
    i_nodatas = (GInt16 *)f_nodatas;
1819
0
    for (band = 0; band < band_count; band++)
1820
0
      i_nodatas[band] = (GInt16)f_nodatas[band];
1821
0
  }
1822
1823
  /* -------------------------------------------------------------------- */
1824
  /*      Allocate buffer, and read data into it.                         */
1825
  /* -------------------------------------------------------------------- */
1826
0
  pBuffer = malloc(((size_t)dst_xsize) * dst_ysize * image->format->bands *
1827
0
                   (GDALGetDataTypeSize(eDataType) / 8));
1828
0
  if (pBuffer == NULL) {
1829
0
    msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
1830
0
               "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize);
1831
0
    free(band_list);
1832
0
    free(f_nodatas);
1833
0
    return -1;
1834
0
  }
1835
1836
0
  eErr =
1837
0
      GDALDatasetRasterIO(hDS, GF_Read, src_xoff, src_yoff, src_xsize,
1838
0
                          src_ysize, pBuffer, dst_xsize, dst_ysize, eDataType,
1839
0
                          image->format->bands, band_list, 0, 0, 0);
1840
0
  free(band_list);
1841
1842
0
  if (eErr != CE_None) {
1843
0
    msSetError(MS_IOERR, "GDALRasterIO() failed: %s",
1844
0
               "msDrawRasterLayerGDAL_RawMode()", CPLGetLastErrorMsg());
1845
0
    free(pBuffer);
1846
0
    free(f_nodatas);
1847
0
    return -1;
1848
0
  }
1849
1850
  /* -------------------------------------------------------------------- */
1851
  /*      Transfer the data to the imageObj.                              */
1852
  /* -------------------------------------------------------------------- */
1853
0
  k = 0;
1854
0
  for (band = 0; band < image->format->bands; band++) {
1855
0
    for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) {
1856
0
      if (image->format->imagemode == MS_IMAGEMODE_INT16) {
1857
0
        for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) {
1858
0
          int off = j + i * image->width + band * image->width * image->height;
1859
0
          int off_mask = j + i * image->width;
1860
1861
0
          if ((i_nodatas && ((GInt16 *)pBuffer)[k] == i_nodatas[band]) ||
1862
0
              SKIP_MASK(j, i)) {
1863
0
            k++;
1864
0
            continue;
1865
0
          }
1866
1867
0
          image->img.raw_16bit[off] = ((GInt16 *)pBuffer)[k++];
1868
0
          MS_SET_BIT(image->img_mask, off_mask);
1869
0
        }
1870
0
      } else if (image->format->imagemode == MS_IMAGEMODE_FLOAT32) {
1871
0
        for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) {
1872
0
          int off = j + i * image->width + band * image->width * image->height;
1873
0
          int off_mask = j + i * image->width;
1874
1875
0
          if ((f_nodatas && ((float *)pBuffer)[k] == f_nodatas[band]) ||
1876
0
              SKIP_MASK(j, i)) {
1877
0
            k++;
1878
0
            continue;
1879
0
          }
1880
1881
0
          image->img.raw_float[off] = ((float *)pBuffer)[k++];
1882
0
          MS_SET_BIT(image->img_mask, off_mask);
1883
0
        }
1884
0
      } else if (image->format->imagemode == MS_IMAGEMODE_BYTE) {
1885
0
        for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) {
1886
0
          int off = j + i * image->width + band * image->width * image->height;
1887
0
          int off_mask = j + i * image->width;
1888
1889
0
          if ((b_nodatas && ((unsigned char *)pBuffer)[k] == b_nodatas[band]) ||
1890
0
              SKIP_MASK(j, i)) {
1891
0
            k++;
1892
0
            continue;
1893
0
          }
1894
1895
0
          image->img.raw_byte[off] = ((unsigned char *)pBuffer)[k++];
1896
0
          MS_SET_BIT(image->img_mask, off_mask);
1897
0
        }
1898
0
      }
1899
0
    }
1900
0
  }
1901
1902
0
  free(pBuffer);
1903
0
  free(f_nodatas);
1904
1905
0
  return 0;
1906
0
}
1907
1908
/************************************************************************/
1909
/*              msDrawRasterLayerGDAL_16BitClassifcation()              */
1910
/*                                                                      */
1911
/*      Handle the rendering of rasters going through a 16bit           */
1912
/*      classification lookup instead of the more common 8bit one.      */
1913
/*                                                                      */
1914
/*      Currently we are using one data path where we load the          */
1915
/*      raster into a floating point buffer, and then scale to          */
1916
/*      16bit.  Eventually we could add optimizations for some of       */
1917
/*      the 16bit cases at the cost of some complication.               */
1918
/************************************************************************/
1919
1920
static int msDrawRasterLayerGDAL_16BitClassification(
1921
    mapObj *map, layerObj *layer, rasterBufferObj *rb, GDALRasterBandH hBand,
1922
    int src_xoff, int src_yoff, int src_xsize, int src_ysize, int dst_xoff,
1923
    int dst_yoff, int dst_xsize, int dst_ysize)
1924
1925
0
{
1926
0
  float *pafRawData;
1927
0
  double dfScaleMin = 0.0, dfScaleMax = 0.0, dfScaleRatio;
1928
0
  int nPixelCount = dst_xsize * dst_ysize, i, nBucketCount = 0;
1929
0
  GDALDataType eDataType;
1930
0
  float fDataMin = 0.0, fDataMax = 255.0, fNoDataValue;
1931
0
  const char *pszScaleInfo;
1932
0
  const char *pszBuckets;
1933
0
  int *cmap, c, j, k, bGotNoData = FALSE, bGotFirstValue;
1934
0
  unsigned char *rb_cmap[4];
1935
0
  CPLErr eErr;
1936
0
  rasterBufferObj *mask_rb = NULL;
1937
0
  rasterBufferObj s_mask_rb;
1938
0
  int lastC;
1939
0
  struct mstimeval starttime = {0}, endtime = {0};
1940
1941
0
  const char *pszClassifyScaled;
1942
0
  int bClassifyScaled = FALSE;
1943
1944
0
  if (layer->mask) {
1945
0
    int ret;
1946
0
    layerObj *maskLayer = GET_LAYER(map, msGetLayerIndex(map, layer->mask));
1947
0
    mask_rb = &s_mask_rb;
1948
0
    memset(mask_rb, 0, sizeof(s_mask_rb));
1949
0
    ret = MS_IMAGE_RENDERER(maskLayer->maskimage)
1950
0
              ->getRasterBufferHandle(maskLayer->maskimage, mask_rb);
1951
0
    if (ret != MS_SUCCESS)
1952
0
      return -1;
1953
0
  }
1954
1955
0
  assert(rb->type == MS_BUFFER_BYTE_RGBA);
1956
1957
  /* ==================================================================== */
1958
  /*      Read the requested data in one gulp into a floating point       */
1959
  /*      buffer.                                                         */
1960
  /* ==================================================================== */
1961
0
  pafRawData = (float *)malloc(sizeof(float) * dst_xsize * dst_ysize);
1962
0
  if (pafRawData == NULL) {
1963
0
    msSetError(MS_MEMERR, "Out of memory allocating working buffer.",
1964
0
               "msDrawRasterLayerGDAL_16BitClassification()");
1965
0
    return -1;
1966
0
  }
1967
1968
0
  eErr = GDALRasterIO(hBand, GF_Read, src_xoff, src_yoff, src_xsize, src_ysize,
1969
0
                      pafRawData, dst_xsize, dst_ysize, GDT_Float32, 0, 0);
1970
1971
0
  if (eErr != CE_None) {
1972
0
    free(pafRawData);
1973
0
    msSetError(MS_IOERR, "GDALRasterIO() failed: %s",
1974
0
               "msDrawRasterLayerGDAL_16BitClassification()",
1975
0
               CPLGetLastErrorMsg());
1976
0
    return -1;
1977
0
  }
1978
1979
0
  fNoDataValue = (float)msGetGDALNoDataValue(layer, hBand, &bGotNoData);
1980
1981
  /* ==================================================================== */
1982
  /*      Determine scaling.                                              */
1983
  /* ==================================================================== */
1984
0
  eDataType = GDALGetRasterDataType(hBand);
1985
1986
  /* -------------------------------------------------------------------- */
1987
  /*      Scan for absolute min/max of this block.                        */
1988
  /* -------------------------------------------------------------------- */
1989
0
  bGotFirstValue = FALSE;
1990
1991
0
  for (i = 1; i < nPixelCount; i++) {
1992
0
    if (bGotNoData && IsNoData(pafRawData[i], fNoDataValue))
1993
0
      continue;
1994
1995
0
    if (CPLIsNan(pafRawData[i]))
1996
0
      continue;
1997
1998
0
    if (!bGotFirstValue) {
1999
0
      fDataMin = fDataMax = pafRawData[i];
2000
0
      bGotFirstValue = TRUE;
2001
0
    } else {
2002
0
      fDataMin = MS_MIN(fDataMin, pafRawData[i]);
2003
0
      fDataMax = MS_MAX(fDataMax, pafRawData[i]);
2004
0
    }
2005
0
  }
2006
2007
  /* -------------------------------------------------------------------- */
2008
  /*      Fetch the scale classification option.                          */
2009
  /* -------------------------------------------------------------------- */
2010
0
  pszClassifyScaled = CSLFetchNameValue(layer->processing, "CLASSIFY_SCALED");
2011
0
  if (pszClassifyScaled != NULL)
2012
0
    bClassifyScaled = CSLTestBoolean(pszClassifyScaled);
2013
2014
  /* -------------------------------------------------------------------- */
2015
  /*      Fetch the scale processing option.                              */
2016
  /* -------------------------------------------------------------------- */
2017
0
  pszBuckets = CSLFetchNameValue(layer->processing, "SCALE_BUCKETS");
2018
0
  pszScaleInfo = CSLFetchNameValue(layer->processing, "SCALE");
2019
2020
0
  if (pszScaleInfo != NULL) {
2021
0
    char **papszTokens;
2022
2023
0
    papszTokens = CSLTokenizeStringComplex(pszScaleInfo, " ,", FALSE, FALSE);
2024
0
    if (CSLCount(papszTokens) == 1 && EQUAL(papszTokens[0], "AUTO")) {
2025
0
      dfScaleMin = dfScaleMax = 0.0;
2026
0
    } else if (CSLCount(papszTokens) != 2) {
2027
0
      free(pafRawData);
2028
0
      CSLDestroy(papszTokens);
2029
0
      msSetError(MS_MISCERR, "SCALE PROCESSING option unparsable for layer %s.",
2030
0
                 "msDrawGDAL()", layer->name);
2031
0
      return -1;
2032
0
    } else {
2033
0
      dfScaleMin = atof(papszTokens[0]);
2034
0
      dfScaleMax = atof(papszTokens[1]);
2035
0
    }
2036
0
    CSLDestroy(papszTokens);
2037
0
  }
2038
2039
  /* -------------------------------------------------------------------- */
2040
  /*      Special integer cases for scaling.                              */
2041
  /*                                                                      */
2042
  /*      TODO: Treat Int32 and UInt32 case the same way *if* the min     */
2043
  /*      and max are less than 65536 apart.                              */
2044
  /* -------------------------------------------------------------------- */
2045
0
  if (eDataType == GDT_Byte || eDataType == GDT_Int16 ||
2046
0
      eDataType == GDT_UInt16) {
2047
0
    if (pszScaleInfo == NULL) {
2048
0
      dfScaleMin = fDataMin - 0.5;
2049
0
      dfScaleMax = fDataMax + 0.5;
2050
0
    }
2051
2052
0
    if (pszBuckets == NULL) {
2053
0
      nBucketCount = (int)floor(fDataMax - fDataMin + 1.1);
2054
0
    }
2055
0
  }
2056
2057
  /* -------------------------------------------------------------------- */
2058
  /*      General case if no scaling values provided in mapfile.          */
2059
  /* -------------------------------------------------------------------- */
2060
0
  else if (dfScaleMin == 0.0 && dfScaleMax == 0.0) {
2061
0
    double dfEpsilon = (fDataMax - fDataMin) / (65536 * 2);
2062
0
    dfScaleMin = fDataMin - dfEpsilon;
2063
0
    dfScaleMax = fDataMax + dfEpsilon;
2064
0
  }
2065
2066
  /* -------------------------------------------------------------------- */
2067
  /*      How many buckets?  Only set if we don't already have a value.   */
2068
  /* -------------------------------------------------------------------- */
2069
0
  if (pszBuckets == NULL) {
2070
0
    if (nBucketCount == 0)
2071
0
      nBucketCount = 65536;
2072
0
  } else {
2073
0
    nBucketCount = atoi(pszBuckets);
2074
0
    if (nBucketCount < 2) {
2075
0
      free(pafRawData);
2076
0
      msSetError(
2077
0
          MS_MISCERR,
2078
0
          "SCALE_BUCKETS PROCESSING option is not a value of 2 or more: %s.",
2079
0
          "msDrawRasterLayerGDAL_16BitClassification()", pszBuckets);
2080
0
      return -1;
2081
0
    }
2082
0
  }
2083
2084
  /* -------------------------------------------------------------------- */
2085
  /*      Compute scaling ratio.                                          */
2086
  /* -------------------------------------------------------------------- */
2087
0
  if (dfScaleMax == dfScaleMin)
2088
0
    dfScaleMax = dfScaleMin + 1.0;
2089
2090
0
  dfScaleRatio = nBucketCount / (dfScaleMax - dfScaleMin);
2091
2092
0
  if (layer->debug > 0)
2093
0
    msDebug("msDrawRasterGDAL_16BitClassification(%s):\n"
2094
0
            "  scaling to %d buckets from range=%g,%g.\n",
2095
0
            layer->name, nBucketCount, dfScaleMin, dfScaleMax);
2096
2097
  /* ==================================================================== */
2098
  /*      Compute classification lookup table.                            */
2099
  /* ==================================================================== */
2100
2101
0
  cmap = (int *)msSmallCalloc(sizeof(int), nBucketCount);
2102
0
  rb_cmap[0] = (unsigned char *)msSmallCalloc(1, nBucketCount);
2103
0
  rb_cmap[1] = (unsigned char *)msSmallCalloc(1, nBucketCount);
2104
0
  rb_cmap[2] = (unsigned char *)msSmallCalloc(1, nBucketCount);
2105
0
  rb_cmap[3] = (unsigned char *)msSmallCalloc(1, nBucketCount);
2106
2107
0
  if (layer->debug >= MS_DEBUGLEVEL_TUNING) {
2108
0
    msGettimeofday(&starttime, NULL);
2109
0
  }
2110
2111
0
  const char *sgamma = msLayerGetProcessingKey(layer, "GAMMA");
2112
0
  const double gamma = sgamma ? CPLAtof(sgamma) : 1.0;
2113
2114
0
  lastC = -1;
2115
0
  for (i = 0; i < nBucketCount; i++) {
2116
0
    double dfOriginalValue;
2117
2118
0
    cmap[i] = -1;
2119
2120
    // i = (int) ((dfOriginalValue - dfScaleMin) * dfScaleRatio+1)-1;
2121
0
    dfOriginalValue = (i + 0.5) / dfScaleRatio + dfScaleMin;
2122
2123
    /* The creation of buckets takes a significant time when they are many, and
2124
       many classes as well. When iterating over buckets, a faster strategy is
2125
       to reuse first the last used class index. */
2126
0
    if (bClassifyScaled == TRUE)
2127
0
      c = msGetClass_FloatRGB_WithFirstClassToTry(layer, (float)i, -1, -1, -1,
2128
0
                                                  lastC);
2129
0
    else
2130
0
      c = msGetClass_FloatRGB_WithFirstClassToTry(layer, (float)dfOriginalValue,
2131
0
                                                  -1, -1, -1, lastC);
2132
2133
0
    lastC = c;
2134
0
    if (c != -1) {
2135
0
      int s;
2136
0
      int styleindex = 0;
2137
2138
      /* change colour based on colour range? */
2139
0
      if (MS_VALID_COLOR(layer->class[c] -> styles[0] -> mincolor)) {
2140
0
        styleindex = -1;
2141
0
        for (s = 0; s < layer->class[c] -> numstyles; s++) {
2142
0
          if (MS_VALID_COLOR(layer->class[c] -> styles[s] -> mincolor) &&
2143
0
                  MS_VALID_COLOR(layer->class[c] -> styles[s] -> maxcolor) &&
2144
0
                  dfOriginalValue + 0.5 / dfScaleRatio >=
2145
0
                      layer->class[c] -> styles[s]
2146
0
              -> minvalue && dfOriginalValue - 0.5 / dfScaleRatio <=
2147
0
                                 layer -> class[c] -> styles[s] -> maxvalue) {
2148
0
            msValueToRange(layer->class[c] -> styles[s], dfOriginalValue,
2149
0
                           MS_COLORSPACE_RGB);
2150
0
            styleindex = s;
2151
0
            break;
2152
0
          }
2153
0
        }
2154
0
      }
2155
0
      if (styleindex >= 0) {
2156
0
        if (MS_TRANSPARENT_COLOR(
2157
0
                layer->class[c] -> styles[styleindex] -> color)) {
2158
          /* leave it transparent */
2159
0
        } else if (MS_VALID_COLOR(
2160
0
                       layer->class[c] -> styles[styleindex] -> color)) {
2161
          /* use class color */
2162
0
          rb_cmap[0][i] = layer->class[c]->styles[styleindex]->color.red;
2163
0
          rb_cmap[1][i] = layer->class[c]->styles[styleindex]->color.green;
2164
0
          rb_cmap[2][i] = layer->class[c]->styles[styleindex]->color.blue;
2165
0
          rb_cmap[3][i] =
2166
0
              (255 * layer->class[c] -> styles[styleindex] -> opacity / 100);
2167
2168
0
          if (gamma != 1.0) {
2169
0
            rb_cmap[0][i] = GAMMA_CORRECT(rb_cmap[0][i], gamma);
2170
0
            rb_cmap[1][i] = GAMMA_CORRECT(rb_cmap[1][i], gamma);
2171
0
            rb_cmap[2][i] = GAMMA_CORRECT(rb_cmap[2][i], gamma);
2172
0
          }
2173
0
        }
2174
0
      }
2175
0
    }
2176
0
  }
2177
2178
0
  if (layer->debug >= MS_DEBUGLEVEL_TUNING) {
2179
0
    msGettimeofday(&endtime, NULL);
2180
0
    msDebug(
2181
0
        "msDrawRasterGDAL_16BitClassification() bucket creation time: %.3fs\n",
2182
0
        (endtime.tv_sec + endtime.tv_usec / 1.0e6) -
2183
0
            (starttime.tv_sec + starttime.tv_usec / 1.0e6));
2184
0
  }
2185
2186
  /* ==================================================================== */
2187
  /*      Now process the data, applying to the working imageObj.         */
2188
  /* ==================================================================== */
2189
0
  k = 0;
2190
2191
0
  for (i = dst_yoff; i < dst_yoff + dst_ysize; i++) {
2192
0
    for (j = dst_xoff; j < dst_xoff + dst_xsize; j++) {
2193
0
      float fRawValue = pafRawData[k++];
2194
0
      int iMapIndex;
2195
2196
      /*
2197
       * Skip nodata pixels ... no processing.
2198
       */
2199
0
      if (bGotNoData && IsNoData(fRawValue, fNoDataValue))
2200
0
        continue;
2201
2202
0
      if (CPLIsNan(fRawValue))
2203
0
        continue;
2204
2205
0
      if (SKIP_MASK(j, i))
2206
0
        continue;
2207
2208
      /*
2209
       * The funny +1/-1 is to avoid odd rounding around zero.
2210
       * We could use floor() but sometimes it is expensive.
2211
       */
2212
0
      iMapIndex = (int)((fRawValue - dfScaleMin) * dfScaleRatio + 1) - 1;
2213
2214
0
      if (iMapIndex >= nBucketCount || iMapIndex < 0) {
2215
0
        continue;
2216
0
      }
2217
      /* currently we never have partial alpha so keep simple */
2218
0
      if (rb_cmap[3][iMapIndex] > 0)
2219
0
        RB_SET_PIXEL(rb, j, i, rb_cmap[0][iMapIndex], rb_cmap[1][iMapIndex],
2220
0
                     rb_cmap[2][iMapIndex], rb_cmap[3][iMapIndex]);
2221
0
    }
2222
0
  }
2223
2224
  /* -------------------------------------------------------------------- */
2225
  /*      Cleanup                                                         */
2226
  /* -------------------------------------------------------------------- */
2227
0
  free(pafRawData);
2228
0
  free(cmap);
2229
0
  free(rb_cmap[0]);
2230
0
  free(rb_cmap[1]);
2231
0
  free(rb_cmap[2]);
2232
0
  free(rb_cmap[3]);
2233
2234
0
  assert(k == dst_xsize * dst_ysize);
2235
2236
0
  return 0;
2237
0
}
2238
2239
/************************************************************************/
2240
/*                          IsNoData()                                  */
2241
/************************************************************************/
2242
0
static bool IsNoData(double dfValue, double dfNoDataValue) {
2243
0
  return isnan(dfValue) || dfValue == dfNoDataValue;
2244
0
}
2245
2246
/************************************************************************/
2247
/*                          msGetGDALNoDataValue()                      */
2248
/************************************************************************/
2249
double msGetGDALNoDataValue(layerObj *layer, void *hBand, int *pbGotNoData)
2250
2251
0
{
2252
0
  const char *pszNODATAOpt;
2253
2254
0
  *pbGotNoData = FALSE;
2255
2256
  /* -------------------------------------------------------------------- */
2257
  /*      Check for a NODATA setting in the .map file.                    */
2258
  /* -------------------------------------------------------------------- */
2259
0
  pszNODATAOpt = CSLFetchNameValue(layer->processing, "NODATA");
2260
0
  if (pszNODATAOpt != NULL) {
2261
0
    if (EQUAL(pszNODATAOpt, "OFF") || strlen(pszNODATAOpt) == 0)
2262
0
      return -1234567.0;
2263
0
    if (!EQUAL(pszNODATAOpt, "AUTO")) {
2264
0
      *pbGotNoData = TRUE;
2265
0
      return atof(pszNODATAOpt);
2266
0
    }
2267
0
  }
2268
2269
  /* -------------------------------------------------------------------- */
2270
  /*      Check for a NODATA setting on the raw file.                     */
2271
  /* -------------------------------------------------------------------- */
2272
0
  if (hBand == NULL)
2273
0
    return -1234567.0;
2274
0
  else
2275
0
    return GDALGetRasterNoDataValue(hBand, pbGotNoData);
2276
0
}
2277
2278
/************************************************************************/
2279
/*                         msGetGDALBandList()                          */
2280
/*                                                                      */
2281
/*      max_bands - pass zero for no limit.                             */
2282
/*      band_count - location in which length of the return band        */
2283
/*      list is placed.                                                 */
2284
/*                                                                      */
2285
/*      returns malloc() list of band numbers (*band_count long).       */
2286
/************************************************************************/
2287
2288
int *msGetGDALBandList(layerObj *layer, void *hDS, int max_bands,
2289
                       int *band_count)
2290
2291
0
{
2292
0
  int i, file_bands;
2293
0
  int *band_list = NULL;
2294
2295
0
  file_bands = GDALGetRasterCount(hDS);
2296
0
  if (file_bands == 0) {
2297
0
    msSetError(MS_IMGERR,
2298
0
               "Attempt to operate on GDAL file with no bands, layer=%s.",
2299
0
               "msGetGDALBandList()", layer->name);
2300
2301
0
    return NULL;
2302
0
  }
2303
2304
  /* -------------------------------------------------------------------- */
2305
  /*      Use all (or first) bands.                                       */
2306
  /* -------------------------------------------------------------------- */
2307
0
  if (CSLFetchNameValue(layer->processing, "BANDS") == NULL) {
2308
0
    if (max_bands > 0)
2309
0
      *band_count = MS_MIN(file_bands, max_bands);
2310
0
    else
2311
0
      *band_count = file_bands;
2312
2313
0
    band_list = (int *)malloc(sizeof(int) * *band_count);
2314
2315
    /* FIXME MS_CHECK_ALLOC leaks papszItems */
2316
0
    MS_CHECK_ALLOC(band_list, sizeof(int) * *band_count, NULL);
2317
2318
0
    for (i = 0; i < *band_count; i++)
2319
0
      band_list[i] = i + 1;
2320
0
    return band_list;
2321
0
  }
2322
2323
  /* -------------------------------------------------------------------- */
2324
  /*      get bands from BANDS processing directive.                      */
2325
  /* -------------------------------------------------------------------- */
2326
0
  else {
2327
0
    char **papszItems = CSLTokenizeStringComplex(
2328
0
        CSLFetchNameValue(layer->processing, "BANDS"), " ,", FALSE, FALSE);
2329
2330
0
    if (CSLCount(papszItems) == 0) {
2331
0
      CSLDestroy(papszItems);
2332
0
      msSetError(MS_IMGERR, "BANDS PROCESSING directive has no items.",
2333
0
                 "msGetGDALBandList()");
2334
0
      return NULL;
2335
0
    } else if (max_bands != 0 && CSLCount(papszItems) > max_bands) {
2336
0
      msSetError(MS_IMGERR,
2337
0
                 "BANDS PROCESSING directive has wrong number of bands, "
2338
0
                 "expected at most %d, got %d.",
2339
0
                 "msGetGDALBandList()", max_bands, CSLCount(papszItems));
2340
0
      CSLDestroy(papszItems);
2341
0
      return NULL;
2342
0
    }
2343
2344
0
    *band_count = CSLCount(papszItems);
2345
0
    band_list = (int *)malloc(sizeof(int) * *band_count);
2346
0
    MS_CHECK_ALLOC(band_list, sizeof(int) * *band_count, NULL);
2347
2348
0
    for (i = 0; i < *band_count; i++) {
2349
0
      band_list[i] = atoi(papszItems[i]);
2350
0
      if (band_list[i] < 1 || band_list[i] > GDALGetRasterCount(hDS)) {
2351
0
        msSetError(MS_IMGERR,
2352
0
                   "BANDS PROCESSING directive includes illegal band '%s', "
2353
0
                   "should be from 1 to %d.",
2354
0
                   "msGetGDALBandList()", papszItems[i],
2355
0
                   GDALGetRasterCount(hDS));
2356
0
        CSLDestroy(papszItems);
2357
0
        free(band_list);
2358
0
        return NULL;
2359
0
      }
2360
0
    }
2361
0
    CSLDestroy(papszItems);
2362
2363
0
    return band_list;
2364
0
  }
2365
0
}