root/tags/rel-5-0-2/mapserver/mapdrawgdal.c

Revision 6944, 75.9 kB (checked in by warmerdam, 10 months ago)

improve handling of out of memory conditions (#2351)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  *
3  * Project:  MapServer
4  * Purpose:  Code for drawing GDAL raster layers.  Called from
5  *           msDrawRasterLayerLow() in mapraster.c. 
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1996-2005 Regents of the University of Minnesota.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies of this Software or works derived from this Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  *****************************************************************************/
29
30 #include <assert.h>
31 #include "mapserver.h"
32 #include "mapresample.h"
33 #include "mapthread.h"
34
35 MS_CVSID("$Id$")
36
37 extern int InvGeoTransform( double *gt_in, double *gt_out );
38
39 #define MAXCOLORS 256
40 #define GEO_TRANS(tr,x,y)  ((tr)[0]+(tr)[1]*(x)+(tr)[2]*(y))
41
42 #if defined(USE_GDAL)
43
44 #include "gdal.h"
45 #include "cpl_string.h"
46
47 #if GDAL_VERSION_NUM > 1174
48 define ENABLE_DITHER
49 #endif
50
51 #ifdef ENABLE_DITHER
52 #include "gdal_alg.h"
53 #endif
54
55 static int
56 LoadGDALImage( GDALRasterBandH hBand, int iColorIndex,
57                layerObj *layer,
58                int src_xoff, int src_yoff, int src_xsize, int src_ysize,
59                GByte *pabyBuffer, int dst_xsize, int dst_ysize );
60 static int
61 msDrawRasterLayerGDAL_RawMode(
62     mapObj *map, layerObj *layer, imageObj *image, GDALDatasetH hDS,
63     int src_xoff, int src_yoff, int src_xsize, int src_ysize,
64     int dst_xoff, int dst_yoff, int dst_xsize, int dst_ysize );
65
66 static int
67 msDrawRasterLayerGDAL_16BitClassification(
68     mapObj *map, layerObj *layer, imageObj *image,
69     GDALDatasetH hDS, GDALRasterBandH hBand,
70     int src_xoff, int src_yoff, int src_xsize, int src_ysize,
71     int dst_xoff, int dst_yoff, int dst_xsize, int dst_ysize );
72
73
74 #ifdef ENABLE_DITHER
75 static void Dither24to8( GByte *pabyRed, GByte *pabyGreen, GByte *pabyBlue,
76                          GByte *pabyDithered, int xsize, int ysize,
77                          int bTransparent, colorObj transparentColor,
78                          gdImagePtr gdImg );
79 #endif
80
81 /*
82  * Stuff for allocating color cubes, and mapping between RGB values and
83  * the corresponding color cube index.
84  */
85
86 static int allocColorCube(mapObj *map, gdImagePtr img, int *panColorCube);
87
88 #define RED_LEVELS 5
89 #define RED_DIV 52
90 /* #define GREEN_LEVELS 7 */
91 #define GREEN_LEVELS 5
92 /* #define GREEN_DIV 37 */
93 #define GREEN_DIV 52
94 #define BLUE_LEVELS 5
95 #define BLUE_DIV 52
96
97 #define RGB_LEVEL_INDEX(r,g,b) ((r)*GREEN_LEVELS*BLUE_LEVELS + (g)*BLUE_LEVELS+(b))
98 #define RGB_INDEX(r,g,b) RGB_LEVEL_INDEX(((r)/RED_DIV),((g)/GREEN_DIV),((b)/BLUE_DIV))
99
100 /************************************************************************/
101 /*                       msDrawRasterLayerGDAL()                        */
102 /************************************************************************/
103
104 int msDrawRasterLayerGDAL(mapObj *map, layerObj *layer, imageObj *image,
105                           void *hDSVoid )
106
107 {
108   int i,j, k; /* loop counters */
109   int cmap[MAXCOLORS], cmap_set = FALSE;
110   double adfGeoTransform[6], adfInvGeoTransform[6];
111   int   dst_xoff, dst_yoff, dst_xsize, dst_ysize;
112   int   src_xoff, src_yoff, src_xsize, src_ysize;
113   int   anColorCube[256];
114   double llx, lly, urx, ury;
115   rectObj copyRect, mapRect;
116   unsigned char *pabyRaw1=NULL, *pabyRaw2=NULL, *pabyRaw3=NULL,
117                 *pabyRawAlpha = NULL;
118   int truecolor = FALSE, classified = FALSE;
119   int red_band=0, green_band=0, blue_band=0, alpha_band=0, cmt=0;
120   gdImagePtr gdImg = NULL;
121   GDALDatasetH hDS = hDSVoid;
122   GDALColorTableH hColorMap;
123   GDALRasterBandH hBand1, hBand2, hBand3, hBandAlpha;
124
125   memset( cmap, 0xff, MAXCOLORS * sizeof(int) );
126
127 /* -------------------------------------------------------------------- */
128 /*      Test the image format instead of the map format.                */
129 /*      Normally the map format and the image format should be the      */
130 /*      same but In somes cases like swf and pdf support, a temporary   */
131 /*      GD image object is created and used to render raster layers     */
132 /*      and then dumped into the SWF or the PDF file.                   */
133 /* -------------------------------------------------------------------- */
134  
135   /* if( MS_RENDERER_GD(map->outputformat) ) */
136   if( MS_RENDERER_GD(image->format) )
137   {
138       gdImg = image->img.gd;
139
140       truecolor = gdImageTrueColor( gdImg );
141       if( CSLFetchNameValue( layer->processing,
142                              "COLOR_MATCH_THRESHOLD" ) != NULL )
143       {
144           cmt = MAX(0,atoi(CSLFetchNameValue( layer->processing,
145                                               "COLOR_MATCH_THRESHOLD" )));
146       }
147   }
148 #ifdef USE_AGG
149   else if( MS_RENDERER_AGG(image->format) )
150   {
151       gdImg = image->img.gd;
152
153       truecolor = gdImageTrueColor( gdImg );
154       if( CSLFetchNameValue( layer->processing,
155                              "COLOR_MATCH_THRESHOLD" ) != NULL )
156       {
157           cmt = MAX(0,atoi(CSLFetchNameValue( layer->processing,
158                                               "COLOR_MATCH_THRESHOLD" )));
159       }
160   }
161 #endif
162   src_xsize = GDALGetRasterXSize( hDS );
163   src_ysize = GDALGetRasterYSize( hDS );
164
165   /*
166    * If the RAW_WINDOW attribute is set, use that to establish what to
167    * load.  This is normally just set by the mapresample.c module to avoid
168    * problems with rotated maps.
169    */
170
171   if( CSLFetchNameValue( layer->processing, "RAW_WINDOW" ) != NULL )
172   {
173       char **papszTokens =
174           CSLTokenizeString(
175               CSLFetchNameValue( layer->processing, "RAW_WINDOW" ) );
176      
177       if( layer->debug )
178           msDebug( "msDrawGDAL(%s): using RAW_WINDOW=%s\n",
179                    layer->name,
180                    CSLFetchNameValue( layer->processing, "RAW_WINDOW" ) );
181
182       if( CSLCount(papszTokens) != 4 )
183       {
184           CSLDestroy( papszTokens );
185           msSetError( MS_IMGERR, "RAW_WINDOW PROCESSING directive corrupt.",
186                       "msDrawGDAL()" );
187           return -1;
188       }
189
190       src_xoff = atoi(papszTokens[0]);
191       src_yoff = atoi(papszTokens[1]);
192       src_xsize = atoi(papszTokens[2]);
193       src_ysize = atoi(papszTokens[3]);
194
195       dst_xoff = 0;
196       dst_yoff = 0;
197       dst_xsize = image->width;
198       dst_ysize = image->height;
199
200       CSLDestroy( papszTokens );
201   }
202
203   /*
204    * Compute the georeferenced window of overlap, and do nothing if there
205    * is no overlap between the map extents, and the file we are operating on.
206    */
207   else if( layer->transform )
208   {
209       int dst_lrx, dst_lry;
210
211       msGetGDALGeoTransform( hDS, map, layer, adfGeoTransform );
212       InvGeoTransform( adfGeoTransform, adfInvGeoTransform );
213      
214       mapRect = map->extent;
215      
216       mapRect.minx -= map->cellsize*0.5;
217       mapRect.maxx += map->cellsize*0.5;
218       mapRect.miny -= map->cellsize*0.5;
219       mapRect.maxy += map->cellsize*0.5;
220      
221       copyRect = mapRect;
222      
223       if( copyRect.minx < GEO_TRANS(adfGeoTransform,0,src_ysize) )
224           copyRect.minx = GEO_TRANS(adfGeoTransform,0,src_ysize);
225       if( copyRect.maxx > GEO_TRANS(adfGeoTransform,src_xsize,0) )
226           copyRect.maxx = GEO_TRANS(adfGeoTransform,src_xsize,0);
227
228       if( copyRect.miny < GEO_TRANS(adfGeoTransform+3,0,src_ysize) )
229           copyRect.miny = GEO_TRANS(adfGeoTransform+3,0,src_ysize);
230       if( copyRect.maxy > GEO_TRANS(adfGeoTransform+3,src_xsize,0) )
231           copyRect.maxy = GEO_TRANS(adfGeoTransform+3,src_xsize,0);
232      
233       if( copyRect.minx >= copyRect.maxx || copyRect.miny >= copyRect.maxy )
234           return 0;
235
236       /*
237        * Copy the source and destination raster coordinates.
238        */
239       llx = GEO_TRANS(adfInvGeoTransform+0,copyRect.minx,copyRect.miny);
240       lly = GEO_TRANS(adfInvGeoTransform+3,copyRect.minx,copyRect.miny);
241       urx = GEO_TRANS(adfInvGeoTransform+0,copyRect.maxx,copyRect.maxy);
242       ury = GEO_TRANS(adfInvGeoTransform+3,copyRect.maxx,copyRect.maxy);
243      
244       src_xoff = MAX(0,(int) llx);
245       src_yoff = MAX(0,(int) ury);
246       src_xsize = MIN(MAX(0,(int) (urx - llx + 0.5)),
247                       GDALGetRasterXSize(hDS) - src_xoff);
248       src_ysize = MIN(MAX(0,(int) (lly - ury + 0.5)),
249                       GDALGetRasterYSize(hDS) - src_yoff);
250
251       if( src_xsize == 0 || src_ysize == 0 )
252       {
253           if( layer->debug )
254               msDebug( "msDrawGDAL(): no apparent overlap between map view and this window(1).\n" );
255           return 0;
256       }
257
258       dst_xoff = (int) ((copyRect.minx - mapRect.minx) / map->cellsize);
259       dst_yoff = (int) ((mapRect.maxy - copyRect.maxy) / map->cellsize);
260
261       dst_lrx = (int) ((copyRect.maxx - mapRect.minx) / map->cellsize + 0.5);
262       dst_lry = (int) ((mapRect.maxy - copyRect.miny) / map->cellsize + 0.5);
263       dst_lrx = MAX(0,MIN(image->width,dst_lrx));
264       dst_lry = MAX(0,MIN(image->height,dst_lry));
265      
266       dst_xsize = MAX(0,MIN(image->width,dst_lrx - dst_xoff));
267       dst_ysize = MAX(0,MIN(image->height,dst_lry - dst_yoff));
268
269       if( dst_xsize == 0 || dst_ysize == 0 )
270       {
271           if( layer->debug )
272               msDebug( "msDrawGDAL(): no apparent overlap between map view and this window(2).\n" );
273           return 0;
274       }
275
276 #ifndef notdef
277       if( layer->debug )
278           msDebug( "msDrawGDAL(): src=%d,%d,%d,%d, dst=%d,%d,%d,%d\n",
279                    src_xoff, src_yoff, src_xsize, src_ysize,
280                    dst_xoff, dst_yoff, dst_xsize, dst_ysize );
281 #endif
282   }
283
284   /*
285    * If layer transforms are turned off, just map 1:1.
286    */
287   else
288   {
289       dst_xoff = src_xoff = 0;
290       dst_yoff = src_yoff = 0;
291       dst_xsize = src_xsize = MIN(image->width,src_xsize);
292       dst_ysize = src_ysize = MIN(image->height,src_ysize);
293   }
294
295   /*
296    * In RAWDATA mode we don't fool with colors.  Do the raw processing,
297    * and return from the function early.
298    */
299   if( !gdImg )
300   {
301       assert( MS_RENDERER_RAWDATA( image->format ) );
302
303       return msDrawRasterLayerGDAL_RawMode(
304           map, layer, image, hDS,
305           src_xoff, src_yoff, src_xsize, src_ysize,
306           dst_xoff, dst_yoff, dst_xsize, dst_ysize );
307   }
308  
309   /*
310    * Is this image classified?  We consider it classified if there are
311    * classes with an expression string *or* a color range.  We don't want
312    * to treat the raster as classified if there is just a bogus class here
313    * to force inclusion in the legend.
314    */
315   for( i = 0; i < layer->numclasses; i++ )
316   {
317       int s;
318
319       /* change colour based on colour range? */
320       for(s=0; s<layer->class[i]->numstyles; s++)
321       {
322           if( MS_VALID_COLOR(layer->class[i]->styles[s]->mincolor)
323               && MS_VALID_COLOR(layer->class[i]->styles[s]->maxcolor) )
324           {
325               classified = TRUE;
326               break;
327           }
328       }
329      
330       if( layer->class[i]->expression.string != NULL )
331       {
332           classified = TRUE;
333           break;
334       }
335   }
336
337   /*
338    * Set up the band selection.  We look for a BANDS directive in the
339    * the PROCESSING options.  If not found we default to red=1 or
340    * red=1,green=2,blue=3 or red=1,green=2,blue=3,alpha=4.
341    */
342
343   if( CSLFetchNameValue( layer->processing, "BANDS" ) == NULL )
344   {
345       red_band = 1;
346
347       if( GDALGetRasterCount( hDS ) >= 4
348           && GDALGetRasterColorInterpretation(
349               GDALGetRasterBand( hDS, 4 ) ) == GCI_AlphaBand )
350           alpha_band = 4;
351      
352       if( GDALGetRasterCount( hDS ) >= 3 )
353       {
354           green_band = 2;
355           blue_band = 3;
356       }
357
358       if( GDALGetRasterCount( hDS ) == 2
359           && GDALGetRasterColorInterpretation(
360               GDALGetRasterBand( hDS, 2 ) ) == GCI_AlphaBand )
361           alpha_band = 2;
362      
363       hBand1 = GDALGetRasterBand( hDS, red_band );
364       if( classified
365           || GDALGetRasterColorTable( hBand1 ) != NULL )
366       {
367           alpha_band = 0;
368           green_band = 0;
369           blue_band = 0;
370       }
371   }
372   else
373   {
374       int band_count, *band_list;
375
376       band_list = msGetGDALBandList( layer, hDS, 4, &band_count );
377       if( band_list == NULL )
378           return -1;
379      
380       if( band_count > 0 )
381           red_band = band_list[0];
382       else
383           red_band = 0;
384       if( band_count > 2 )
385       {
386           green_band = band_list[1];
387           blue_band = band_list[2];
388       }
389       else     
390       {
391           green_band = 0;
392           blue_band = 0;
393       }
394
395       if( band_count > 3 )
396           alpha_band = band_list[3];
397       else
398           alpha_band = 0;
399
400       free( band_list );
401   }
402
403   if( layer->debug > 1 || (layer->debug > 0 && green_band != 0) )
404   {
405       msDebug( "msDrawGDAL(): red,green,blue,alpha bands = %d,%d,%d,%d\n",
406                red_band, green_band, blue_band, alpha_band );
407   }
408
409   /*
410    * Get band handles for PC256, RGB or RGBA cases.
411    */
412   hBand1 = GDALGetRasterBand( hDS, red_band );
413   if( hBand1 == NULL )
414       return -1;
415
416   hBand2 = hBand3 = hBandAlpha = NULL;
417
418   if( green_band != 0 )
419   {
420       hBand1 = GDALGetRasterBand( hDS, red_band );
421       hBand2 = GDALGetRasterBand( hDS, green_band );
422       hBand3 = GDALGetRasterBand( hDS, blue_band );
423       if( hBand1 == NULL || hBand2 == NULL || hBand3 == NULL )
424           return -1;
425   }
426
427   if( alpha_band != 0 )
428       hBandAlpha = GDALGetRasterBand( hDS, alpha_band );
429
430   /*
431    * Wipe pen indicators for all our layer class colors if they exist. 
432    * Sometimes temporary gdImg'es are used in which case previously allocated
433    * pens won't generally apply.  See Bug 504.
434    */
435   if( gdImg && !truecolor )
436   {
437       int iClass;
438       int iStyle;
439       for( iClass = 0; iClass < layer->numclasses; iClass++ )
440       {
441           for (iStyle=0; iStyle<layer->class[iClass]->numstyles; iStyle++)
442             layer->class[iClass]->styles[iStyle]->color.pen = MS_PEN_UNSET;
443       }
444   }
445
446   /*
447    * The logic for a classification rendering of non-8bit raster bands
448    * is sufficiently different than the normal mechanism of loading
449    * into an 8bit buffer, that we isolate it into it's own subfunction.
450    */
451   if( classified && gdImg
452      && hBand1 != NULL && GDALGetRasterDataType( hBand1 ) != GDT_Byte )
453   {
454       return msDrawRasterLayerGDAL_16BitClassification(
455           map, layer, image, hDS, hBand1,
456           src_xoff, src_yoff, src_xsize, src_ysize,
457           dst_xoff, dst_yoff, dst_xsize, dst_ysize );
458   }
459
460   /*
461    * Get colormap for this image.  If there isn't one, and we have only
462    * one band create a greyscale colormap.
463    */
464   if( hBand2 != NULL )
465       hColorMap = NULL;
466   else
467   {
468       hColorMap = GDALGetRasterColorTable( hBand1 );
469       if( hColorMap != NULL )
470           hColorMap = GDALCloneColorTable( hColorMap );
471       else if( hBand2 == NULL )
472       {
473           hColorMap = GDALCreateColorTable( GPI_RGB );
474          
475           for( i = 0; i < 256; i++ )
476           {
477               colorObj pixel;
478               GDALColorEntry sEntry;
479
480               pixel.red = i;
481               pixel.green = i;
482               pixel.blue = i;
483               pixel.pen = i;
484              
485               if(MS_COMPARE_COLORS(pixel, layer->offsite))
486               {
487                   sEntry.c1 = 0;
488                   sEntry.c2 = 0;
489                   sEntry.c3 = 0;
490                   sEntry.c4 = 0; /* alpha set to zero */
491               }
492               else if( truecolor )
493               {
494                   sEntry.c1 = i;
495                   sEntry.c2 = i;
496                   sEntry.c3 = i;
497                   sEntry.c4 = 255;
498               }
499               else
500               {
501                   /*
502                   ** This special calculation is intended to use only 128
503                   ** unique colors for greyscale in non-truecolor mode.
504                   */
505
506                   sEntry.c1 = i - i%2;
507                   sEntry.c2 = i - i%2;
508                   sEntry.c3 = i - i%2;
509                   sEntry.c4 = 255;
510               }
511                  
512               GDALSetColorEntry( hColorMap, i, &sEntry );
513           }
514       }
515
516       /*
517       ** If we have a known NODATA value, mark it now as transparent.
518       */
519       {
520           int    bGotNoData;
521           double dfNoDataValue = msGetGDALNoDataValue( layer, hBand1,
522                                                        &bGotNoData);
523
524           if( bGotNoData && dfNoDataValue >= 0
525               && dfNoDataValue < GDALGetColorEntryCount( hColorMap ) )
526           {
527               GDALColorEntry sEntry;
528              
529               memcpy( &sEntry,
530                       GDALGetColorEntry( hColorMap, (int) dfNoDataValue ),
531                       sizeof(GDALColorEntry) );
532
533               sEntry.c4 = 0;
534               GDALSetColorEntry( hColorMap, (int) dfNoDataValue, &sEntry );
535           }
536       }
537   }
538
539   /*
540    * Setup the mapping between source eightbit pixel values, and the
541    * output images color table.  There are two general cases, where the
542    * class colors are provided by the MAP file, or where we use the native
543    * color table.
544    */
545   if( classified && gdImg ) {
546     int c, color_count;
547
548     cmap_set = TRUE;
549
550     if( hColorMap == NULL )
551     {
552         msSetError(MS_IOERR,
553                    "Attempt to classify 24bit image, this is unsupported.",
554                    "drawGDAL()");
555         return -1;
556     }
557
558     color_count = MIN(256,GDALGetColorEntryCount(hColorMap));
559     for(i=0; i < color_count; i++) {
560         colorObj pixel;
561         GDALColorEntry sEntry;
562
563         GDALGetColorEntryAsRGB( hColorMap, i, &sEntry );
564            
565         pixel.red = sEntry.c1;
566         pixel.green = sEntry.c2;
567         pixel.blue = sEntry.c3;
568         pixel.pen = i;
569        
570         if(!MS_COMPARE_COLORS(pixel, layer->offsite))
571         {
572             c = msGetClass(layer, &pixel);
573            
574             if(c == -1)/* doesn't belong to any class, so handle like offsite*/
575                 cmap[i] = -1;
576             else
577             {
578                 int s;
579                
580                 /* change colour based on colour range?  Currently we
581                    only address the greyscale case properly. */
582
583                 for(s=0; s<layer->class[c]->numstyles; s++)
584                 {
585                     if( MS_VALID_COLOR(layer->class[c]->styles[s]->mincolor)
586                         && MS_VALID_COLOR(layer->class[c]->styles[s]->maxcolor) )
587                         msValueToRange(layer->class[c]->styles[s],
588                                        sEntry.c1 );
589                 }
590
591                 RESOLVE_PEN_GD(gdImg, layer->class[c]->styles[0]->color);
592                 if( MS_TRANSPARENT_COLOR(layer->class[c]->styles[0]->color) )
593                     cmap[i] = -1;
594                 else if( MS_VALID_COLOR(layer->class[c]->styles[0]->color))
595                 {
596                     /* use class color */
597                     cmap[i] = layer->class[c]->styles[0]->color.pen;
598                 }
599                 else /* Use raster color */
600                     cmap[i] = msAddColorGD(map, gdImg, cmt,
601                                            pixel.red, pixel.green, pixel.blue);
602             }
603         } else
604             cmap[i] = -1;
605     }
606   } else if( hColorMap != NULL && !truecolor && gdImg ) {
607     int color_count;
608     cmap_set = TRUE;
609
610     color_count = MIN(256,GDALGetColorEntryCount(hColorMap));
611
612     for(i=0; i < color_count; i++) {
613         GDALColorEntry sEntry;
614
615         GDALGetColorEntryAsRGB( hColorMap, i, &sEntry );
616
617         if( sEntry.c4 != 0
618             && (!MS_VALID_COLOR( layer->offsite )
619                 || layer->offsite.red != sEntry.c1
620                 || layer->offsite.green != sEntry.c2
621                 || layer->offsite.blue != sEntry.c3 ) )
622             cmap[i] = msAddColorGD(map, gdImg, cmt,
623                                    sEntry.c1, sEntry.c2, sEntry.c3);
624         else
625             cmap[i] = -1;
626     }
627   }
628   else if( hBand2 == NULL && hColorMap != NULL )
629   {
630       int color_count;
631       cmap_set = TRUE;
632
633       color_count = MIN(256,GDALGetColorEntryCount(hColorMap));
634
635       for(i=0; i < color_count; i++) {
636           GDALColorEntry sEntry;
637          
638           GDALGetColorEntryAsRGB( hColorMap, i, &sEntry );
639
640           if( sEntry.c4 != 0
641               && (!MS_VALID_COLOR( layer->offsite )
642                   || layer->offsite.red != sEntry.c1
643                   || layer->offsite.green != sEntry.c2
644                   || layer->offsite.blue != sEntry.c3 ) )
645               cmap[i] = gdTrueColorAlpha(sEntry.c1, sEntry.c2, sEntry.c3,
646                                          127 - (sEntry.c4 >> 1) );
647           else
648               cmap[i] = -1;
649       }
650   }
651   else if( !truecolor && gdImg )
652   {
653       allocColorCube( map, gdImg, anColorCube );
654   }
655   else if( !truecolor )
656   {
657       msSetError(MS_IOERR,
658                  "Unsupported configuration for raster layer read via GDAL.",
659                  "drawGDAL()");
660       return -1;
661   }
662
663   /*
664    * Read the entire region of interest in one gulp.  GDAL will take
665    * care of downsampling and window logic. 
666    */
667   pabyRaw1 = (unsigned char *) malloc(dst_xsize * dst_ysize);
668   if( pabyRaw1 == NULL )
669   {
670       msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
671                  "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
672       return -1;
673   }
674
675   if( LoadGDALImage( hBand1, 1, layer,
676                      src_xoff, src_yoff, src_xsize, src_ysize,
677                      pabyRaw1, dst_xsize, dst_ysize ) == -1 )
678   {
679       free( pabyRaw1 );
680       return -1;
681   }
682
683   if( hBand2 != NULL && hBand3 != NULL )
684   {
685       pabyRaw2 = (unsigned char *) malloc(dst_xsize * dst_ysize);
686       if( pabyRaw2 == NULL )
687       {
688           msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
689                      "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
690           return -1;
691       }
692      
693       if( LoadGDALImage( hBand2, 2, layer,
694                          src_xoff, src_yoff, src_xsize, src_ysize,
695                          pabyRaw2, dst_xsize, dst_ysize ) == -1 )
696       {
697           free( pabyRaw1 );
698           free( pabyRaw2 );
699           return -1;
700       }
701
702       pabyRaw3 = (unsigned char *) malloc(dst_xsize * dst_ysize);
703       if( pabyRaw3 == NULL )
704       {
705           msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
706                      "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
707           return -1;
708       }
709      
710       if( LoadGDALImage( hBand3, 3, layer,
711                          src_xoff, src_yoff, src_xsize, src_ysize,
712                          pabyRaw3, dst_xsize, dst_ysize ) == -1 )
713       {
714           free( pabyRaw1 );
715           free( pabyRaw2 );
716           free( pabyRaw3 );
717           return -1;
718       }
719   }
720
721   if( hBandAlpha != NULL )
722   {
723       pabyRawAlpha = (unsigned char *) malloc(dst_xsize * dst_ysize);
724       if( pabyRawAlpha == NULL )
725       {
726           msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
727                      "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
728           return -1;
729       }
730      
731       if( LoadGDALImage( hBandAlpha, 4, layer,
732                          src_xoff, src_yoff, src_xsize, src_ysize,
733                          pabyRawAlpha, dst_xsize, dst_ysize ) == -1 )
734       {
735           free( pabyRaw1 );
736           if( pabyRaw3 != NULL )
737           {
738               free( pabyRaw2 );
739               free( pabyRaw3 );
740           }
741
742           free( pabyRawAlpha );
743           return -1;
744       }
745   }
746   else
747       pabyRawAlpha = NULL;
748
749 /* -------------------------------------------------------------------- */
750 /*      Single band plus colormap with alpha blending to 8bit.          */
751 /* -------------------------------------------------------------------- */
752   if( hBand2 == NULL && !truecolor && gdImg && hBandAlpha != NULL )
753   {
754       assert( cmap_set );
755       k = 0;
756
757       for( i = dst_yoff; i < dst_yoff + dst_ysize; i++ )
758       {
759           int   result, alpha;
760          
761           for( j = dst_xoff; j < dst_xoff + dst_xsize; j++ )
762           {
763               alpha = pabyRawAlpha[k];
764
765               result = cmap[pabyRaw1[k++]];
766
767               /*
768               ** We don't do alpha blending in non-truecolor mode, just
769               ** threshold the point on/off at alpha=128.
770               */
771
772               if( result != -1 && alpha >= 128 )
773                   gdImg->pixels[i][j] = result;
774           }
775       }
776
777       assert( k == dst_xsize * dst_ysize );
778   }
779
780 /* -------------------------------------------------------------------- */
781 /*      Single band plus colormap (no alpha) to 8bit.                   */
782 /* -------------------------------------------------------------------- */
783   else if( hBand2 == NULL && !truecolor && gdImg )
784   {
785       assert( cmap_set );
786       k = 0;
787
788       for( i = dst_yoff; i < dst_yoff + dst_ysize; i++ )
789       {
790           int   result;
791          
792           for( j = dst_xoff; j < dst_xoff + dst_xsize; j++ )
793           {
794               result = cmap[pabyRaw1[k++]];
795               if( result != -1 )
796               {
797                   gdImg->pixels[i][j] = result;
798               }
799           }
800       }
801
802       assert( k == dst_xsize * dst_ysize );
803   }
804
805 /* -------------------------------------------------------------------- */
806 /*      Single band plus colormap and alpha to truecolor.               */
807 /* -------------------------------------------------------------------- */
808   else if( hBand2 == NULL && truecolor && gdImg && hBandAlpha != NULL )
809   {
810       assert( cmap_set );
811
812       k = 0;
813       for( i = dst_yoff; i < dst_yoff + dst_ysize; i++ )
814       {
815           int   result, alpha;
816          
817           for( j = dst_xoff; j < dst_xoff + dst_xsize; j++ )
818           {
819               alpha = pabyRawAlpha[k];
820               result = cmap[pabyRaw1[k++]];
821
822               if( result == -1 || alpha < 2 )
823                   /* do nothing - transparent */;
824               else if( alpha > 253 )
825                   gdImg->tpixels[i][j] = result;
826               else
827               {
828                   /* mix alpha into "result" */
829                   result += (127 - (alpha >> 1)) << 24;
830                   gdImg->tpixels[i][j] =
831                       msAlphaBlend( gdImg->tpixels[i][j], result );
832               }
833           }
834       }
835   }
836
837 /* -------------------------------------------------------------------- */
838 /*      Single band plus colormap (no alpha) to truecolor               */
839 /* -------------------------------------------------------------------- */
840   else if( hBand2 == NULL && truecolor && gdImg )
841   {
842       assert( cmap_set );
843
844       k = 0;
845       for( i = dst_yoff; i < dst_yoff + dst_ysize; i++ )
846       {
847           int   result;
848          
849           for( j = dst_xoff; j < dst_xoff + dst_xsize; j++ )
850           {
851               result = cmap[pabyRaw1[k++]];
852               if( result != -1 )
853                   gdImg->tpixels[i][j] = result;
854           }
855       }
856   }
857
858 /* -------------------------------------------------------------------- */
859 /*      Input is 3 band RGB.  Alpha blending is mixed into the loop     */
860 /*      since this case is less commonly used and has lots of other     */
861 /*      overhead.                                                       */
862 /* -------------------------------------------------------------------- */
863   else if( hBand3 != NULL && gdImg )
864   {
865       /* Dithered 24bit to 8bit conversion */
866       if( !truecolor && CSLFetchBoolean( layer->processing, "DITHER", FALSE ) )
867       {
868 #ifdef ENABLE_DITHER
869           unsigned char *pabyDithered;
870
871           pabyDithered = (unsigned char *) malloc(dst_xsize * dst_ysize);
872           if( pabyDithered == NULL )
873           {
874               msSetError(MS_MEMERR, "Allocating work image of size %dx%d failed.",
875                          "msDrawRasterLayerGDAL()", dst_xsize, dst_ysize );
876               return -1;
877           }
878          
879           Dither24to8( pabyRaw1, pabyRaw2, pabyRaw3, pabyDithered,
880                        dst_xsize, dst_ysize, image->format->transparent,
881                        map->imagecolor, gdImg );
882
883           k = 0;
884           for( i = dst_yoff; i < dst_yoff + dst_ysize; i++ )
885           {
886               for( j = dst_xoff; j < dst_xoff + dst_xsize; j++, k++ )
887               {
888                   if( MS_VALID_COLOR( layer->offsite )
889                       && pabyRaw1[k] == layer->offsite.red
890                       && pabyRaw2[k] == layer->offsite.green
891                       && pabyRaw3[k] == layer->offsite.blue )
892                       continue;
893
894                   if( pabyRawAlpha != NULL && pabyRawAlpha[k] == 0 )
895                       continue;
896
897                   gdImg->pixels[i][j] = pabyDithered[k];
898               }
899           }
900          
901           free( pabyDithered );
902 #else
903           msSetError( MS_IMGERR,
904                       "DITHER not supported in this build.  Update to latest GDAL, and define the ENABLE_DITHER macro.", "drawGDAL()" );
905           return -1;
906 #endif
907       }
908
909       /* Color cubed 24bit to 8bit conversion. */
910       else if( !truecolor )
911       {
912           k = 0;
913           for( i = dst_yoff; i < dst_yoff + dst_ysize; i++ )
914           {
915               for( j = dst_xoff; j < dst_xoff + dst_xsize; j++, k++ )
916               {
917                   int   cc_index;
918                  
919                   if( MS_VALID_COLOR( layer->offsite )
920                       && pabyRaw1[k] == layer->offsite.red
921                       && pabyRaw2[k] == layer->offsite.green
922                       && pabyRaw3[k] == layer->offsite.blue )
923                       continue;
924                  
925                   if( pabyRawAlpha != NULL && pabyRawAlpha[k] == 0 )
926                       continue;
927
928                   cc_index= RGB_INDEX(pabyRaw1[k],pabyRaw2[k],pabyRaw3[k]);
929                   gdImg->pixels[i][j] = anColorCube[cc_index];
930               }
931           }
932       }
933       else if( truecolor )
934       {
935           k = 0;
936           for( i = dst_yoff; i < dst_yoff + dst_ysize; i++ )
937           {
938