SEXP RGDAL_SetRasterColorTable(SEXP raster, SEXP icT, SEXP ricT, SEXP cicT) { int i, nr=INTEGER_POINTER(ricT)[0], nc=INTEGER_POINTER(cicT)[0]; GDALRasterBand* target = getGDALRasterPtr(raster); installErrorHandler(); GDALColorTableH ctab = GDALCreateColorTable(GPI_RGB); uninstallErrorHandlerAndTriggerError(); for (i=0; i<nr; i++) { GDALColorEntry ce; ce.c1 = (GByte) INTEGER_POINTER(icT)[i]; ce.c2 = (GByte) INTEGER_POINTER(icT)[i+nr]; ce.c3 = (GByte) INTEGER_POINTER(icT)[i+(nr*2)]; if (nc == 3) ce.c4 = 255; else ce.c4 = (GByte) INTEGER_POINTER(icT)[i+(nr*3)]; installErrorHandler(); GDALSetColorEntry (ctab, i, &ce); uninstallErrorHandlerAndTriggerError(); } installErrorHandler(); int err = GDALSetRasterColorTable(target, ctab); if (err == CE_Failure) { uninstallErrorHandlerAndTriggerError(); warning("Unable to set color table"); } uninstallErrorHandlerAndTriggerError(); return(raster); }
/* actual raster band export * returns 0 on success * -1 on raster data read/write error * */ int export_band(GDALDatasetH hMEMDS, int band, const char *name, const char *mapset, struct Cell_head *cellhead, RASTER_MAP_TYPE maptype, double nodataval, int suppress_main_colortable) { struct Colors sGrassColors; GDALColorTableH hCT; int iColor; int bHaveMinMax; double dfCellMin; double dfCellMax; struct FPRange sRange; int fd; int cols = cellhead->cols; int rows = cellhead->rows; int ret = 0; char value[200]; /* Open GRASS raster */ fd = Rast_open_old(name, mapset); /* Get raster band */ GDALRasterBandH hBand = GDALGetRasterBand(hMEMDS, band); if (hBand == NULL) { G_warning(_("Unable to get raster band")); return -1; } /* Get min/max values. */ if (Rast_read_fp_range(name, mapset, &sRange) == -1) { bHaveMinMax = FALSE; } else { bHaveMinMax = TRUE; Rast_get_fp_range_min_max(&sRange, &dfCellMin, &dfCellMax); } sprintf(value, "GRASS GIS %s", GRASS_VERSION_NUMBER); GDALSetMetadataItem(hBand, "Generated_with", value, NULL); /* use default color rules if no color rules are given */ if (Rast_read_colors(name, mapset, &sGrassColors) >= 0) { int maxcolor, i; CELL min, max; char key[200]; int rcount; Rast_get_c_color_range(&min, &max, &sGrassColors); if (bHaveMinMax) { if (max < dfCellMax) { maxcolor = max; } else { maxcolor = (int)ceil(dfCellMax); } if (maxcolor > GRASS_MAX_COLORS) { maxcolor = GRASS_MAX_COLORS; G_warning("Too many values, color table cut to %d entries", maxcolor); } } else { if (max < GRASS_MAX_COLORS) { maxcolor = max; } else { maxcolor = GRASS_MAX_COLORS; G_warning("Too many values, color table set to %d entries", maxcolor); } } rcount = Rast_colors_count(&sGrassColors); G_debug(3, "dfCellMin: %f, dfCellMax: %f, maxcolor: %d", dfCellMin, dfCellMax, maxcolor); if (!suppress_main_colortable) { hCT = GDALCreateColorTable(GPI_RGB); for (iColor = 0; iColor <= maxcolor; iColor++) { int nRed, nGreen, nBlue; GDALColorEntry sColor; if (Rast_get_c_color(&iColor, &nRed, &nGreen, &nBlue, &sGrassColors)) { sColor.c1 = nRed; sColor.c2 = nGreen; sColor.c3 = nBlue; sColor.c4 = 255; G_debug(3, "Rast_get_c_color: Y, rcount %d, nRed %d, nGreen %d, nBlue %d", rcount, nRed, nGreen, nBlue); GDALSetColorEntry(hCT, iColor, &sColor); } else { sColor.c1 = 0; sColor.c2 = 0; sColor.c3 = 0; sColor.c4 = 0; G_debug(3, "Rast_get_c_color: N, rcount %d, nRed %d, nGreen %d, nBlue %d", rcount, nRed, nGreen, nBlue); GDALSetColorEntry(hCT, iColor, &sColor); } } GDALSetRasterColorTable(hBand, hCT); } if (rcount > 0) { /* Create metadata entries for color table rules */ sprintf(value, "%d", rcount); GDALSetMetadataItem(hBand, "COLOR_TABLE_RULES_COUNT", value, NULL); } /* Add the rules in reverse order */ /* This can cause a GDAL warning with many rules, something like * Warning 1: Lost metadata writing to GeoTIFF ... too large to fit in tag. */ for (i = rcount - 1; i >= 0; i--) { DCELL val1, val2; unsigned char r1, g1, b1, r2, g2, b2; Rast_get_fp_color_rule(&val1, &r1, &g1, &b1, &val2, &r2, &g2, &b2, &sGrassColors, i); sprintf(key, "COLOR_TABLE_RULE_RGB_%d", rcount - i - 1); sprintf(value, "%e %e %d %d %d %d %d %d", val1, val2, r1, g1, b1, r2, g2, b2); GDALSetMetadataItem(hBand, key, value, NULL); } } /* Create GRASS raster buffer */ void *bufer = Rast_allocate_buf(maptype); if (bufer == NULL) { G_warning(_("Unable to allocate buffer for reading raster map")); return -1; } /* the following routine must be kept identical to exact_checks */ /* Copy data form GRASS raster to GDAL raster */ int row, col; int n_nulls = 0; /* Better use selected GDAL datatype instead of * the best match with GRASS raster map types ? */ if (maptype == FCELL_TYPE) { /* Source datatype understandable by GDAL */ GDALDataType datatype = GDT_Float32; FCELL fnullval = (FCELL) nodataval; G_debug(1, "FCELL nodata val: %f", fnullval); for (row = 0; row < rows; row++) { Rast_get_row(fd, bufer, row, maptype); for (col = 0; col < cols; col++) { if (Rast_is_f_null_value(&((FCELL *) bufer)[col])) { ((FCELL *) bufer)[col] = fnullval; if (n_nulls == 0) { GDALSetRasterNoDataValue(hBand, nodataval); } n_nulls++; } } if (GDALRasterIO (hBand, GF_Write, 0, row, cols, 1, bufer, cols, 1, datatype, 0, 0) >= CE_Failure) { G_warning(_("Unable to write GDAL raster file")); return -1; } G_percent(row + 1, rows, 2); } } else if (maptype == DCELL_TYPE) { GDALDataType datatype = GDT_Float64; DCELL dnullval = (DCELL) nodataval; G_debug(1, "DCELL nodata val: %f", dnullval); for (row = 0; row < rows; row++) { Rast_get_row(fd, bufer, row, maptype); for (col = 0; col < cols; col++) { if (Rast_is_d_null_value(&((DCELL *) bufer)[col])) { ((DCELL *) bufer)[col] = dnullval; if (n_nulls == 0) { GDALSetRasterNoDataValue(hBand, nodataval); } n_nulls++; } } if (GDALRasterIO (hBand, GF_Write, 0, row, cols, 1, bufer, cols, 1, datatype, 0, 0) >= CE_Failure) { G_warning(_("Unable to write GDAL raster file")); return -1; } G_percent(row + 1, rows, 2); } } else { GDALDataType datatype = GDT_Int32; CELL inullval = (CELL) nodataval; G_debug(1, "CELL nodata val: %d", inullval); for (row = 0; row < rows; row++) { Rast_get_row(fd, bufer, row, maptype); for (col = 0; col < cols; col++) { if (Rast_is_c_null_value(&((CELL *) bufer)[col])) { ((CELL *) bufer)[col] = inullval; if (n_nulls == 0) { GDALSetRasterNoDataValue(hBand, nodataval); } n_nulls++; } } if (GDALRasterIO (hBand, GF_Write, 0, row, cols, 1, bufer, cols, 1, datatype, 0, 0) >= CE_Failure) { G_warning(_("Unable to write GDAL raster file")); return -1; } G_percent(row + 1, rows, 2); } } Rast_close(fd); G_free(bufer); return ret; }
int msSaveImageGDAL( mapObj *map, imageObj *image, char *filename ) { int bFileIsTemporary = MS_FALSE; GDALDatasetH hMemDS, hOutputDS; GDALDriverH hMemDriver, hOutputDriver; int nBands = 1; int iLine; GByte *pabyAlphaLine = NULL; char **papszOptions = NULL; outputFormatObj *format = image->format; rasterBufferObj rb; GDALDataType eDataType = GDT_Byte; int bUseXmp = MS_FALSE; msGDALInitialize(); memset(&rb,0,sizeof(rasterBufferObj)); #ifdef USE_EXEMPI if( map != NULL ) { bUseXmp = msXmpPresent(map); } #endif /* -------------------------------------------------------------------- */ /* Identify the proposed output driver. */ /* -------------------------------------------------------------------- */ msAcquireLock( TLOCK_GDAL ); hOutputDriver = GDALGetDriverByName( format->driver+5 ); if( hOutputDriver == NULL ) { msReleaseLock( TLOCK_GDAL ); msSetError( MS_MISCERR, "Failed to find %s driver.", "msSaveImageGDAL()", format->driver+5 ); return MS_FAILURE; } /* -------------------------------------------------------------------- */ /* We will need to write the output to a temporary file and */ /* then stream to stdout if no filename is passed. If the */ /* driver supports virtualio then we hold the temporary file in */ /* memory, otherwise we try to put it in a reasonable temporary */ /* file location. */ /* -------------------------------------------------------------------- */ if( filename == NULL ) { const char *pszExtension = format->extension; if( pszExtension == NULL ) pszExtension = "img.tmp"; if( bUseXmp == MS_FALSE && GDALGetMetadataItem( hOutputDriver, GDAL_DCAP_VIRTUALIO, NULL ) != NULL ) { CleanVSIDir( "/vsimem/msout" ); filename = msTmpFile(map, NULL, "/vsimem/msout/", pszExtension ); } if( filename == NULL && map != NULL) filename = msTmpFile(map, map->mappath,NULL,pszExtension); else if( filename == NULL ) { filename = msTmpFile(map, NULL, NULL, pszExtension ); } bFileIsTemporary = MS_TRUE; } /* -------------------------------------------------------------------- */ /* Establish the characteristics of our memory, and final */ /* dataset. */ /* -------------------------------------------------------------------- */ if( format->imagemode == MS_IMAGEMODE_RGB ) { nBands = 3; assert( MS_RENDERER_PLUGIN(format) && format->vtable->supports_pixel_buffer ); format->vtable->getRasterBufferHandle(image,&rb); } else if( format->imagemode == MS_IMAGEMODE_RGBA ) { pabyAlphaLine = (GByte *) calloc(image->width,1); if (pabyAlphaLine == NULL) { msReleaseLock( TLOCK_GDAL ); msSetError( MS_MEMERR, "Out of memory allocating %u bytes.\n", "msSaveImageGDAL()", image->width); return MS_FAILURE; } nBands = 4; assert( MS_RENDERER_PLUGIN(format) && format->vtable->supports_pixel_buffer ); format->vtable->getRasterBufferHandle(image,&rb); } else if( format->imagemode == MS_IMAGEMODE_INT16 ) { nBands = format->bands; eDataType = GDT_Int16; } else if( format->imagemode == MS_IMAGEMODE_FLOAT32 ) { nBands = format->bands; eDataType = GDT_Float32; } else if( format->imagemode == MS_IMAGEMODE_BYTE ) { nBands = format->bands; eDataType = GDT_Byte; } else { #ifdef USE_GD assert( format->imagemode == MS_IMAGEMODE_PC256 && format->renderer == MS_RENDER_WITH_GD ); #else { msReleaseLock( TLOCK_GDAL ); msSetError( MS_MEMERR, "GD not compiled in. This is a bug.", "msSaveImageGDAL()"); return MS_FAILURE; } #endif } /* -------------------------------------------------------------------- */ /* Create a memory dataset which we can use as a source for a */ /* CreateCopy(). */ /* -------------------------------------------------------------------- */ hMemDriver = GDALGetDriverByName( "MEM" ); if( hMemDriver == NULL ) { msReleaseLock( TLOCK_GDAL ); msSetError( MS_MISCERR, "Failed to find MEM driver.", "msSaveImageGDAL()" ); return MS_FAILURE; } hMemDS = GDALCreate( hMemDriver, "msSaveImageGDAL_temp", image->width, image->height, nBands, eDataType, NULL ); if( hMemDS == NULL ) { msReleaseLock( TLOCK_GDAL ); msSetError( MS_MISCERR, "Failed to create MEM dataset.", "msSaveImageGDAL()" ); return MS_FAILURE; } /* -------------------------------------------------------------------- */ /* Copy the gd image into the memory dataset. */ /* -------------------------------------------------------------------- */ for( iLine = 0; iLine < image->height; iLine++ ) { int iBand; for( iBand = 0; iBand < nBands; iBand++ ) { GDALRasterBandH hBand = GDALGetRasterBand( hMemDS, iBand+1 ); if( format->imagemode == MS_IMAGEMODE_INT16 ) { GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1, image->img.raw_16bit + iLine * image->width + iBand * image->width * image->height, image->width, 1, GDT_Int16, 2, 0 ); } else if( format->imagemode == MS_IMAGEMODE_FLOAT32 ) { GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1, image->img.raw_float + iLine * image->width + iBand * image->width * image->height, image->width, 1, GDT_Float32, 4, 0 ); } else if( format->imagemode == MS_IMAGEMODE_BYTE ) { GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1, image->img.raw_byte + iLine * image->width + iBand * image->width * image->height, image->width, 1, GDT_Byte, 1, 0 ); } #ifdef USE_GD else if(format->renderer == MS_RENDER_WITH_GD) { gdImagePtr img = (gdImagePtr)image->img.plugin; GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1, img->pixels[iLine], image->width, 1, GDT_Byte, 0, 0 ); } #endif else { GByte *pabyData; unsigned char *pixptr = NULL; assert( rb.type == MS_BUFFER_BYTE_RGBA ); switch(iBand) { case 0: pixptr = rb.data.rgba.r; break; case 1: pixptr = rb.data.rgba.g; break; case 2: pixptr = rb.data.rgba.b; break; case 3: pixptr = rb.data.rgba.a; break; } assert(pixptr); if( pixptr == NULL ) { msReleaseLock( TLOCK_GDAL ); msSetError( MS_MISCERR, "Missing RGB or A buffer.\n", "msSaveImageGDAL()" ); return MS_FAILURE; } pabyData = (GByte *)(pixptr + iLine*rb.data.rgba.row_step); if( rb.data.rgba.a == NULL || iBand == 3 ) { GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1, pabyData, image->width, 1, GDT_Byte, rb.data.rgba.pixel_step, 0 ); } else { /* We need to un-pre-multiple RGB by alpha. */ GByte *pabyUPM = (GByte*) malloc(image->width); GByte *pabyAlpha= (GByte *)(rb.data.rgba.a + iLine*rb.data.rgba.row_step); int i; for( i = 0; i < image->width; i++ ) { int alpha = pabyAlpha[i*rb.data.rgba.pixel_step]; if( alpha == 0 ) pabyUPM[i] = 0; else { int result = (pabyData[i*rb.data.rgba.pixel_step] * 255) / alpha; if( result > 255 ) result = 255; pabyUPM[i] = result; } } GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1, pabyUPM, image->width, 1, GDT_Byte, 1, 0 ); free( pabyUPM ); } } } } if( pabyAlphaLine != NULL ) free( pabyAlphaLine ); /* -------------------------------------------------------------------- */ /* Attach the palette if appropriate. */ /* -------------------------------------------------------------------- */ #ifdef USE_GD if( format->renderer == MS_RENDER_WITH_GD ) { GDALColorEntry sEntry; int iColor; GDALColorTableH hCT; gdImagePtr img = (gdImagePtr)image->img.plugin; hCT = GDALCreateColorTable( GPI_RGB ); for( iColor = 0; iColor < img->colorsTotal; iColor++ ) { sEntry.c1 = img->red[iColor]; sEntry.c2 = img->green[iColor]; sEntry.c3 = img->blue[iColor]; if( iColor == gdImageGetTransparent( img ) ) sEntry.c4 = 0; else if( iColor == 0 && gdImageGetTransparent( img ) == -1 && format->transparent ) sEntry.c4 = 0; else sEntry.c4 = 255; GDALSetColorEntry( hCT, iColor, &sEntry ); } GDALSetRasterColorTable( GDALGetRasterBand( hMemDS, 1 ), hCT ); GDALDestroyColorTable( hCT ); } else #endif if( format->imagemode == MS_IMAGEMODE_RGB ) { GDALSetRasterColorInterpretation( GDALGetRasterBand( hMemDS, 1 ), GCI_RedBand ); GDALSetRasterColorInterpretation( GDALGetRasterBand( hMemDS, 2 ), GCI_GreenBand ); GDALSetRasterColorInterpretation( GDALGetRasterBand( hMemDS, 3 ), GCI_BlueBand ); } else if( format->imagemode == MS_IMAGEMODE_RGBA ) { GDALSetRasterColorInterpretation( GDALGetRasterBand( hMemDS, 1 ), GCI_RedBand ); GDALSetRasterColorInterpretation( GDALGetRasterBand( hMemDS, 2 ), GCI_GreenBand ); GDALSetRasterColorInterpretation( GDALGetRasterBand( hMemDS, 3 ), GCI_BlueBand ); GDALSetRasterColorInterpretation( GDALGetRasterBand( hMemDS, 4 ), GCI_AlphaBand ); } /* -------------------------------------------------------------------- */ /* Assign the projection and coordinate system to the memory */ /* dataset. */ /* -------------------------------------------------------------------- */ if( map != NULL ) { char *pszWKT; GDALSetGeoTransform( hMemDS, map->gt.geotransform ); pszWKT = msProjectionObj2OGCWKT( &(map->projection) ); if( pszWKT != NULL ) { GDALSetProjection( hMemDS, pszWKT ); msFree( pszWKT ); } } /* -------------------------------------------------------------------- */ /* Possibly assign a nodata value. */ /* -------------------------------------------------------------------- */ if( msGetOutputFormatOption(format,"NULLVALUE",NULL) != NULL ) { int iBand; const char *nullvalue = msGetOutputFormatOption(format, "NULLVALUE",NULL); for( iBand = 0; iBand < nBands; iBand++ ) { GDALRasterBandH hBand = GDALGetRasterBand( hMemDS, iBand+1 ); GDALSetRasterNoDataValue( hBand, atof(nullvalue) ); } } /* -------------------------------------------------------------------- */ /* Try to save resolution in the output file. */ /* -------------------------------------------------------------------- */ if( image->resolution > 0 ) { char res[30]; sprintf( res, "%lf", image->resolution ); GDALSetMetadataItem( hMemDS, "TIFFTAG_XRESOLUTION", res, NULL ); GDALSetMetadataItem( hMemDS, "TIFFTAG_YRESOLUTION", res, NULL ); GDALSetMetadataItem( hMemDS, "TIFFTAG_RESOLUTIONUNIT", "2", NULL ); } /* -------------------------------------------------------------------- */ /* Create a disk image in the selected output format from the */ /* memory image. */ /* -------------------------------------------------------------------- */ papszOptions = (char**)calloc(sizeof(char *),(format->numformatoptions+1)); if (papszOptions == NULL) { msReleaseLock( TLOCK_GDAL ); msSetError( MS_MEMERR, "Out of memory allocating %u bytes.\n", "msSaveImageGDAL()", (unsigned int)(sizeof(char *)*(format->numformatoptions+1))); return MS_FAILURE; } memcpy( papszOptions, format->formatoptions, sizeof(char *) * format->numformatoptions ); hOutputDS = GDALCreateCopy( hOutputDriver, filename, hMemDS, FALSE, papszOptions, NULL, NULL ); free( papszOptions ); if( hOutputDS == NULL ) { GDALClose( hMemDS ); msReleaseLock( TLOCK_GDAL ); msSetError( MS_MISCERR, "Failed to create output %s file.\n%s", "msSaveImageGDAL()", format->driver+5, CPLGetLastErrorMsg() ); return MS_FAILURE; } /* closing the memory DS also frees all associated resources. */ GDALClose( hMemDS ); GDALClose( hOutputDS ); msReleaseLock( TLOCK_GDAL ); /* -------------------------------------------------------------------- */ /* Are we writing license info into the image? */ /* If so, add it to the temp file on disk now. */ /* -------------------------------------------------------------------- */ #ifdef USE_EXEMPI if ( bUseXmp == MS_TRUE ) { if( msXmpWrite(map, filename) == MS_FAILURE ) { /* Something bad happened. */ msSetError( MS_MISCERR, "XMP write to %s failed.\n", "msSaveImageGDAL()", filename); return MS_FAILURE; } } #endif /* -------------------------------------------------------------------- */ /* Is this supposed to be a temporary file? If so, stream to */ /* stdout and delete the file. */ /* -------------------------------------------------------------------- */ if( bFileIsTemporary ) { FILE *fp; unsigned char block[4000]; int bytes_read; if( msIO_needBinaryStdout() == MS_FAILURE ) return MS_FAILURE; /* We aren't sure how far back GDAL exports the VSI*L API, so we only use it if we suspect we need it. But we do need it if holding temporary file in memory. */ fp = VSIFOpenL( filename, "rb" ); if( fp == NULL ) { msSetError( MS_MISCERR, "Failed to open %s for streaming to stdout.", "msSaveImageGDAL()", filename ); return MS_FAILURE; } while( (bytes_read = VSIFReadL(block, 1, sizeof(block), fp)) > 0 ) msIO_fwrite( block, 1, bytes_read, stdout ); VSIFCloseL( fp ); VSIUnlink( filename ); CleanVSIDir( "/vsimem/msout" ); free( filename ); } return MS_SUCCESS; }