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; }
int GDALComputeMedianCutPCTInternal( GDALRasterBandH hRed, GDALRasterBandH hGreen, GDALRasterBandH hBlue, GByte* pabyRedBand, GByte* pabyGreenBand, GByte* pabyBlueBand, int (*pfnIncludePixel)(int,int,void*), int nColors, int nBits, int* panHistogram, /* NULL, or at least of size (1<<nBits)^3 * sizeof(int) bytes */ GDALColorTableH hColorTable, GDALProgressFunc pfnProgress, void * pProgressArg ) { VALIDATE_POINTER1( hRed, "GDALComputeMedianCutPCT", CE_Failure ); VALIDATE_POINTER1( hGreen, "GDALComputeMedianCutPCT", CE_Failure ); VALIDATE_POINTER1( hBlue, "GDALComputeMedianCutPCT", CE_Failure ); int nXSize, nYSize; CPLErr err = CE_None; /* -------------------------------------------------------------------- */ /* Validate parameters. */ /* -------------------------------------------------------------------- */ nXSize = GDALGetRasterBandXSize( hRed ); nYSize = GDALGetRasterBandYSize( hRed ); if( GDALGetRasterBandXSize( hGreen ) != nXSize || GDALGetRasterBandYSize( hGreen ) != nYSize || GDALGetRasterBandXSize( hBlue ) != nXSize || GDALGetRasterBandYSize( hBlue ) != nYSize ) { CPLError( CE_Failure, CPLE_IllegalArg, "Green or blue band doesn't match size of red band.\n" ); return CE_Failure; } if( pfnIncludePixel != NULL ) { CPLError( CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT() doesn't currently support " " pfnIncludePixel function." ); return CE_Failure; } if ( nColors <= 0 ) { CPLError( CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT() : nColors must be strictly greater than 1." ); return CE_Failure; } if ( nColors > 256 ) { CPLError( CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT() : nColors must be lesser than or equal to 256." ); return CE_Failure; } if( pfnProgress == NULL ) pfnProgress = GDALDummyProgress; /* ==================================================================== */ /* STEP 1: create empty boxes. */ /* ==================================================================== */ int i; Colorbox *box_list, *ptr; int* histogram; Colorbox *freeboxes; Colorbox *usedboxes; int nCLevels = 1 << nBits; int nColorShift = 8 - nBits; int nColorCounter = 0; GByte anRed[256], anGreen[256], anBlue[256]; int nPixels = 0; HashHistogram* psHashHistogram = NULL; if( nBits == 8 && pabyRedBand != NULL && pabyGreenBand != NULL && pabyBlueBand != NULL && nXSize < INT_MAX / nYSize ) { nPixels = nXSize * nYSize; } if( panHistogram ) { if( nBits == 8 && (GIntBig)nXSize * nYSize <= 65536 ) { /* If the image is small enough, then the number of colors */ /* will be limited and using a hashmap, rather than a full table */ /* will be more efficient */ histogram = NULL; psHashHistogram = (HashHistogram*)panHistogram; memset(psHashHistogram, 0xFF, sizeof(HashHistogram) * PRIME_FOR_65536); } else { histogram = panHistogram; memset(histogram, 0, nCLevels*nCLevels*nCLevels * sizeof(int)); } } else { histogram = (int*) VSICalloc(nCLevels*nCLevels*nCLevels,sizeof(int)); if( histogram == NULL ) { CPLError( CE_Failure, CPLE_OutOfMemory, "VSICalloc(): Out of memory in GDALComputeMedianCutPCT" ); return CE_Failure; } } usedboxes = NULL; box_list = freeboxes = (Colorbox *)CPLMalloc(nColors*sizeof (Colorbox)); freeboxes[0].next = &freeboxes[1]; freeboxes[0].prev = NULL; for (i = 1; i < nColors-1; ++i) { freeboxes[i].next = &freeboxes[i+1]; freeboxes[i].prev = &freeboxes[i-1]; } freeboxes[nColors-1].next = NULL; freeboxes[nColors-1].prev = &freeboxes[nColors-2]; /* ==================================================================== */ /* Build histogram. */ /* ==================================================================== */ GByte *pabyRedLine, *pabyGreenLine, *pabyBlueLine; int iLine, iPixel; /* -------------------------------------------------------------------- */ /* Initialize the box datastructures. */ /* -------------------------------------------------------------------- */ ptr = freeboxes; freeboxes = ptr->next; if (freeboxes) freeboxes->prev = NULL; ptr->next = usedboxes; usedboxes = ptr; if (ptr->next) ptr->next->prev = ptr; ptr->rmin = ptr->gmin = ptr->bmin = 999; ptr->rmax = ptr->gmax = ptr->bmax = -1; ptr->total = nXSize * nYSize; /* -------------------------------------------------------------------- */ /* Collect histogram. */ /* -------------------------------------------------------------------- */ pabyRedLine = (GByte *) VSIMalloc(nXSize); pabyGreenLine = (GByte *) VSIMalloc(nXSize); pabyBlueLine = (GByte *) VSIMalloc(nXSize); if (pabyRedLine == NULL || pabyGreenLine == NULL || pabyBlueLine == NULL) { CPLError( CE_Failure, CPLE_OutOfMemory, "VSIMalloc(): Out of memory in GDALComputeMedianCutPCT" ); err = CE_Failure; goto end_and_cleanup; } for( iLine = 0; iLine < nYSize; iLine++ ) { if( !pfnProgress( iLine / (double) nYSize, "Generating Histogram", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" ); err = CE_Failure; goto end_and_cleanup; } GDALRasterIO( hRed, GF_Read, 0, iLine, nXSize, 1, pabyRedLine, nXSize, 1, GDT_Byte, 0, 0 ); GDALRasterIO( hGreen, GF_Read, 0, iLine, nXSize, 1, pabyGreenLine, nXSize, 1, GDT_Byte, 0, 0 ); GDALRasterIO( hBlue, GF_Read, 0, iLine, nXSize, 1, pabyBlueLine, nXSize, 1, GDT_Byte, 0, 0 ); for( iPixel = 0; iPixel < nXSize; iPixel++ ) { int nRed, nGreen, nBlue; nRed = pabyRedLine[iPixel] >> nColorShift; nGreen = pabyGreenLine[iPixel] >> nColorShift; nBlue = pabyBlueLine[iPixel] >> nColorShift; ptr->rmin = MIN(ptr->rmin, nRed); ptr->gmin = MIN(ptr->gmin, nGreen); ptr->bmin = MIN(ptr->bmin, nBlue); ptr->rmax = MAX(ptr->rmax, nRed); ptr->gmax = MAX(ptr->gmax, nGreen); ptr->bmax = MAX(ptr->bmax, nBlue); int* pnColor; if( psHashHistogram ) { pnColor = FindAndInsertColorCount(psHashHistogram, MAKE_COLOR_CODE(nRed, nGreen, nBlue)); } else { pnColor = &HISTOGRAM(histogram, nCLevels, nRed, nGreen, nBlue); } if( *pnColor == 0 ) { if( nColorShift == 0 && nColorCounter < nColors ) { anRed[nColorCounter] = nRed; anGreen[nColorCounter] = nGreen; anBlue[nColorCounter] = nBlue; } nColorCounter++; } (*pnColor) ++; } } if( !pfnProgress( 1.0, "Generating Histogram", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" ); err = CE_Failure; goto end_and_cleanup; } if( nColorShift == 0 && nColorCounter <= nColors ) { //CPLDebug("MEDIAN_CUT", "%d colors found <= %d", nColorCounter, nColors); for(int iColor = 0; iColor<nColorCounter; iColor++) { GDALColorEntry sEntry; sEntry.c1 = (GByte) anRed[iColor]; sEntry.c2 = (GByte) anGreen[iColor]; sEntry.c3 = (GByte) anBlue[iColor]; sEntry.c4 = 255; GDALSetColorEntry( hColorTable, iColor, &sEntry ); } goto end_and_cleanup; } /* ==================================================================== */ /* STEP 3: continually subdivide boxes until no more free */ /* boxes remain or until all colors assigned. */ /* ==================================================================== */ while (freeboxes != NULL) { ptr = largest_box(usedboxes); if (ptr != NULL) splitbox(ptr, histogram, psHashHistogram, nCLevels, &freeboxes, &usedboxes, pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels); else freeboxes = NULL; } /* ==================================================================== */ /* STEP 4: assign colors to all boxes */ /* ==================================================================== */ for (i = 0, ptr = usedboxes; ptr != NULL; ++i, ptr = ptr->next) { GDALColorEntry sEntry; sEntry.c1 = (GByte) (((ptr->rmin + ptr->rmax) << nColorShift) / 2); sEntry.c2 = (GByte) (((ptr->gmin + ptr->gmax) << nColorShift) / 2); sEntry.c3 = (GByte) (((ptr->bmin + ptr->bmax) << nColorShift) / 2); sEntry.c4 = 255; GDALSetColorEntry( hColorTable, i, &sEntry ); } end_and_cleanup: CPLFree( pabyRedLine ); CPLFree( pabyGreenLine ); CPLFree( pabyBlueLine ); /* We're done with the boxes now */ CPLFree(box_list); freeboxes = usedboxes = NULL; if( panHistogram == NULL ) CPLFree( histogram ); return err; }
template<class T> int GDALComputeMedianCutPCTInternal( GDALRasterBandH hRed, GDALRasterBandH hGreen, GDALRasterBandH hBlue, GByte* pabyRedBand, GByte* pabyGreenBand, GByte* pabyBlueBand, int (*pfnIncludePixel)(int, int, void*), int nColors, int nBits, T* panHistogram, // NULL, or >= size (1<<nBits)^3 * sizeof(T) bytes. GDALColorTableH hColorTable, GDALProgressFunc pfnProgress, void * pProgressArg ) { VALIDATE_POINTER1( hRed, "GDALComputeMedianCutPCT", CE_Failure ); VALIDATE_POINTER1( hGreen, "GDALComputeMedianCutPCT", CE_Failure ); VALIDATE_POINTER1( hBlue, "GDALComputeMedianCutPCT", CE_Failure ); CPLErr err = CE_None; /* -------------------------------------------------------------------- */ /* Validate parameters. */ /* -------------------------------------------------------------------- */ const int nXSize = GDALGetRasterBandXSize( hRed ); const int nYSize = GDALGetRasterBandYSize( hRed ); if( GDALGetRasterBandXSize( hGreen ) != nXSize || GDALGetRasterBandYSize( hGreen ) != nYSize || GDALGetRasterBandXSize( hBlue ) != nXSize || GDALGetRasterBandYSize( hBlue ) != nYSize ) { CPLError(CE_Failure, CPLE_IllegalArg, "Green or blue band doesn't match size of red band."); return CE_Failure; } if( pfnIncludePixel != NULL ) { CPLError(CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT() doesn't currently support " "pfnIncludePixel function."); return CE_Failure; } if( nColors <= 0 ) { CPLError(CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT(): " "nColors must be strictly greater than 1."); return CE_Failure; } if( nColors > 256 ) { CPLError(CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT(): " "nColors must be lesser than or equal to 256."); return CE_Failure; } if( pfnProgress == NULL ) pfnProgress = GDALDummyProgress; /* ==================================================================== */ /* STEP 1: create empty boxes. */ /* ==================================================================== */ if( static_cast<GUInt32>(nXSize) > std::numeric_limits<T>::max() / static_cast<GUInt32>(nYSize) ) { CPLError(CE_Warning, CPLE_AppDefined, "GDALComputeMedianCutPCTInternal() not called " "with large enough type"); } T nPixels = 0; if( nBits == 8 && pabyRedBand != NULL && pabyGreenBand != NULL && pabyBlueBand != NULL && static_cast<GUInt32>(nXSize) <= std::numeric_limits<T>::max() / static_cast<GUInt32>(nYSize) ) { nPixels = static_cast<T>(nXSize) * static_cast<T>(nYSize); } const int nCLevels = 1 << nBits; T* histogram = NULL; HashHistogram* psHashHistogram = NULL; if( panHistogram ) { if( nBits == 8 && static_cast<GUIntBig>(nXSize) * nYSize <= 65536 ) { // If the image is small enough, then the number of colors // will be limited and using a hashmap, rather than a full table // will be more efficient. histogram = NULL; psHashHistogram = (HashHistogram*)panHistogram; memset(psHashHistogram, 0xFF, sizeof(HashHistogram) * PRIME_FOR_65536); } else { histogram = panHistogram; memset(histogram, 0, nCLevels*nCLevels*nCLevels * sizeof(T)); } } else { histogram = static_cast<T*>( VSI_CALLOC_VERBOSE(nCLevels * nCLevels * nCLevels, sizeof(T))); if( histogram == NULL ) { return CE_Failure; } } Colorbox *box_list = static_cast<Colorbox *>(CPLMalloc(nColors*sizeof (Colorbox))); Colorbox *freeboxes = box_list; freeboxes[0].next = &freeboxes[1]; freeboxes[0].prev = NULL; for( int i = 1; i < nColors-1; ++i ) { freeboxes[i].next = &freeboxes[i+1]; freeboxes[i].prev = &freeboxes[i-1]; } freeboxes[nColors-1].next = NULL; freeboxes[nColors-1].prev = &freeboxes[nColors-2]; /* ==================================================================== */ /* Build histogram. */ /* ==================================================================== */ /* -------------------------------------------------------------------- */ /* Initialize the box datastructures. */ /* -------------------------------------------------------------------- */ Colorbox *ptr = freeboxes; freeboxes = ptr->next; if( freeboxes ) freeboxes->prev = NULL; Colorbox *usedboxes = NULL; // TODO(schwehr): What? ptr->next = usedboxes; usedboxes = ptr; if( ptr->next ) ptr->next->prev = ptr; ptr->rmin = 999; ptr->gmin = 999; ptr->bmin = 999; ptr->rmax = -1; ptr->gmax = -1; ptr->bmax = -1; ptr->total = static_cast<GUIntBig>(nXSize) * static_cast<GUIntBig>(nYSize); /* -------------------------------------------------------------------- */ /* Collect histogram. */ /* -------------------------------------------------------------------- */ // TODO(schwehr): Move these closer to usage after removing gotos. const int nColorShift = 8 - nBits; int nColorCounter = 0; GByte anRed[256] = {}; GByte anGreen[256] = {}; GByte anBlue[256] = {}; GByte *pabyRedLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize)); GByte *pabyGreenLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize)); GByte *pabyBlueLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize)); if( pabyRedLine == NULL || pabyGreenLine == NULL || pabyBlueLine == NULL ) { err = CE_Failure; goto end_and_cleanup; } for( int iLine = 0; iLine < nYSize; iLine++ ) { if( !pfnProgress( iLine / static_cast<double>(nYSize), "Generating Histogram", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" ); err = CE_Failure; goto end_and_cleanup; } err = GDALRasterIO( hRed, GF_Read, 0, iLine, nXSize, 1, pabyRedLine, nXSize, 1, GDT_Byte, 0, 0 ); if( err == CE_None ) err = GDALRasterIO( hGreen, GF_Read, 0, iLine, nXSize, 1, pabyGreenLine, nXSize, 1, GDT_Byte, 0, 0 ); if( err == CE_None ) err = GDALRasterIO( hBlue, GF_Read, 0, iLine, nXSize, 1, pabyBlueLine, nXSize, 1, GDT_Byte, 0, 0 ); if( err != CE_None ) goto end_and_cleanup; for( int iPixel = 0; iPixel < nXSize; iPixel++ ) { const int nRed = pabyRedLine[iPixel] >> nColorShift; const int nGreen = pabyGreenLine[iPixel] >> nColorShift; const int nBlue = pabyBlueLine[iPixel] >> nColorShift; ptr->rmin = std::min(ptr->rmin, nRed); ptr->gmin = std::min(ptr->gmin, nGreen); ptr->bmin = std::min(ptr->bmin, nBlue); ptr->rmax = std::max(ptr->rmax, nRed); ptr->gmax = std::max(ptr->gmax, nGreen); ptr->bmax = std::max(ptr->bmax, nBlue); bool bFirstOccurrence; if( psHashHistogram ) { int* pnColor = FindAndInsertColorCount(psHashHistogram, MAKE_COLOR_CODE(nRed, nGreen, nBlue)); bFirstOccurrence = ( *pnColor == 0 ); (*pnColor)++; } else { T* pnColor = HISTOGRAM(histogram, nCLevels, nRed, nGreen, nBlue); bFirstOccurrence = ( *pnColor == 0 ); (*pnColor)++; } if( bFirstOccurrence) { if( nColorShift == 0 && nColorCounter < nColors ) { anRed[nColorCounter] = static_cast<GByte>(nRed); anGreen[nColorCounter] = static_cast<GByte>(nGreen); anBlue[nColorCounter] = static_cast<GByte>(nBlue); } nColorCounter++; } } } if( !pfnProgress( 1.0, "Generating Histogram", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" ); err = CE_Failure; goto end_and_cleanup; } if( nColorShift == 0 && nColorCounter <= nColors ) { #if DEBUG_VERBOSE CPLDebug("MEDIAN_CUT", "%d colors found <= %d", nColorCounter, nColors); #endif for( int iColor = 0; iColor < nColorCounter; iColor++ ) { const GDALColorEntry sEntry = { static_cast<GByte>(anRed[iColor]), static_cast<GByte>(anGreen[iColor]), static_cast<GByte>(anBlue[iColor]), 255 }; GDALSetColorEntry( hColorTable, iColor, &sEntry ); } goto end_and_cleanup; } /* ==================================================================== */ /* STEP 3: continually subdivide boxes until no more free */ /* boxes remain or until all colors assigned. */ /* ==================================================================== */ while( freeboxes != NULL ) { ptr = largest_box(usedboxes); if( ptr != NULL ) splitbox(ptr, histogram, psHashHistogram, nCLevels, &freeboxes, &usedboxes, pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels); else freeboxes = NULL; } /* ==================================================================== */ /* STEP 4: assign colors to all boxes */ /* ==================================================================== */ ptr = usedboxes; for( int i = 0; ptr != NULL; ++i, ptr = ptr->next ) { const GDALColorEntry sEntry = { static_cast<GByte>(((ptr->rmin + ptr->rmax) << nColorShift) / 2), static_cast<GByte>(((ptr->gmin + ptr->gmax) << nColorShift) / 2), static_cast<GByte>(((ptr->bmin + ptr->bmax) << nColorShift) / 2), 255 }; GDALSetColorEntry( hColorTable, i, &sEntry ); } end_and_cleanup: CPLFree( pabyRedLine ); CPLFree( pabyGreenLine ); CPLFree( pabyBlueLine ); // We're done with the boxes now. CPLFree(box_list); freeboxes = NULL; usedboxes = NULL; if( panHistogram == NULL ) CPLFree( histogram ); return err; }
extern "C" int CPL_STDCALL GDALComputeMedianCutPCT( GDALRasterBandH hRed, GDALRasterBandH hGreen, GDALRasterBandH hBlue, int (*pfnIncludePixel)(int,int,void*), int nColors, GDALColorTableH hColorTable, GDALProgressFunc pfnProgress, void * pProgressArg ) { VALIDATE_POINTER1( hRed, "GDALComputeMedianCutPCT", CE_Failure ); VALIDATE_POINTER1( hGreen, "GDALComputeMedianCutPCT", CE_Failure ); VALIDATE_POINTER1( hBlue, "GDALComputeMedianCutPCT", CE_Failure ); int nXSize, nYSize; CPLErr err = CE_None; /* -------------------------------------------------------------------- */ /* Validate parameters. */ /* -------------------------------------------------------------------- */ nXSize = GDALGetRasterBandXSize( hRed ); nYSize = GDALGetRasterBandYSize( hRed ); if( GDALGetRasterBandXSize( hGreen ) != nXSize || GDALGetRasterBandYSize( hGreen ) != nYSize || GDALGetRasterBandXSize( hBlue ) != nXSize || GDALGetRasterBandYSize( hBlue ) != nYSize ) { CPLError( CE_Failure, CPLE_IllegalArg, "Green or blue band doesn't match size of red band.\n" ); return CE_Failure; } if( pfnIncludePixel != NULL ) { CPLError( CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT() doesn't currently support " " pfnIncludePixel function." ); return CE_Failure; } if ( nColors <= 0 ) { CPLError( CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT() : nColors must be strictly greater than 1." ); return CE_Failure; } if ( nColors > 256 ) { CPLError( CE_Failure, CPLE_IllegalArg, "GDALComputeMedianCutPCT() : nColors must be lesser than or equal to 256." ); return CE_Failure; } if( pfnProgress == NULL ) pfnProgress = GDALDummyProgress; /* ==================================================================== */ /* STEP 1: crate empty boxes. */ /* ==================================================================== */ int i; Colorbox *box_list, *ptr; int (*histogram)[GMC_B_LEN][GMC_B_LEN]; Colorbox *freeboxes; Colorbox *usedboxes; histogram = (int (*)[GMC_B_LEN][GMC_B_LEN]) CPLCalloc(GMC_B_LEN * GMC_B_LEN * GMC_B_LEN,sizeof(int)); usedboxes = NULL; box_list = freeboxes = (Colorbox *)CPLMalloc(nColors*sizeof (Colorbox)); freeboxes[0].next = &freeboxes[1]; freeboxes[0].prev = NULL; for (i = 1; i < nColors-1; ++i) { freeboxes[i].next = &freeboxes[i+1]; freeboxes[i].prev = &freeboxes[i-1]; } freeboxes[nColors-1].next = NULL; freeboxes[nColors-1].prev = &freeboxes[nColors-2]; /* ==================================================================== */ /* Build histogram. */ /* ==================================================================== */ GByte *pabyRedLine, *pabyGreenLine, *pabyBlueLine; int iLine, iPixel; /* -------------------------------------------------------------------- */ /* Initialize the box datastructures. */ /* -------------------------------------------------------------------- */ ptr = freeboxes; freeboxes = ptr->next; if (freeboxes) freeboxes->prev = NULL; ptr->next = usedboxes; usedboxes = ptr; if (ptr->next) ptr->next->prev = ptr; ptr->rmin = ptr->gmin = ptr->bmin = 999; ptr->rmax = ptr->gmax = ptr->bmax = -1; ptr->total = nXSize * nYSize; /* -------------------------------------------------------------------- */ /* Collect histogram. */ /* -------------------------------------------------------------------- */ pabyRedLine = (GByte *) VSIMalloc(nXSize); pabyGreenLine = (GByte *) VSIMalloc(nXSize); pabyBlueLine = (GByte *) VSIMalloc(nXSize); if (pabyRedLine == NULL || pabyGreenLine == NULL || pabyBlueLine == NULL) { CPLError( CE_Failure, CPLE_OutOfMemory, "VSIMalloc(): Out of memory in GDALComputeMedianCutPCT" ); err = CE_Failure; goto end_and_cleanup; } for( iLine = 0; iLine < nYSize; iLine++ ) { if( !pfnProgress( iLine / (double) nYSize, "Generating Histogram", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" ); err = CE_Failure; goto end_and_cleanup; } GDALRasterIO( hRed, GF_Read, 0, iLine, nXSize, 1, pabyRedLine, nXSize, 1, GDT_Byte, 0, 0 ); GDALRasterIO( hGreen, GF_Read, 0, iLine, nXSize, 1, pabyGreenLine, nXSize, 1, GDT_Byte, 0, 0 ); GDALRasterIO( hBlue, GF_Read, 0, iLine, nXSize, 1, pabyBlueLine, nXSize, 1, GDT_Byte, 0, 0 ); for( iPixel = 0; iPixel < nXSize; iPixel++ ) { int nRed, nGreen, nBlue; nRed = pabyRedLine[iPixel] >> COLOR_SHIFT; nGreen = pabyGreenLine[iPixel] >> COLOR_SHIFT; nBlue = pabyBlueLine[iPixel] >> COLOR_SHIFT; ptr->rmin = MIN(ptr->rmin, nRed); ptr->gmin = MIN(ptr->gmin, nGreen); ptr->bmin = MIN(ptr->bmin, nBlue); ptr->rmax = MAX(ptr->rmax, nRed); ptr->gmax = MAX(ptr->gmax, nGreen); ptr->bmax = MAX(ptr->bmax, nBlue); histogram[nRed][nGreen][nBlue]++; } } if( !pfnProgress( 1.0, "Generating Histogram", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" ); err = CE_Failure; goto end_and_cleanup; } /* ==================================================================== */ /* STEP 3: continually subdivide boxes until no more free */ /* boxes remain or until all colors assigned. */ /* ==================================================================== */ while (freeboxes != NULL) { ptr = largest_box(usedboxes); if (ptr != NULL) splitbox(ptr, histogram, &freeboxes, &usedboxes); else freeboxes = NULL; } /* ==================================================================== */ /* STEP 4: assign colors to all boxes */ /* ==================================================================== */ for (i = 0, ptr = usedboxes; ptr != NULL; ++i, ptr = ptr->next) { GDALColorEntry sEntry; sEntry.c1 = (GByte) (((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2); sEntry.c2 = (GByte) (((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2); sEntry.c3 = (GByte) (((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2); sEntry.c4 = 255; GDALSetColorEntry( hColorTable, i, &sEntry ); } end_and_cleanup: CPLFree( pabyRedLine ); CPLFree( pabyGreenLine ); CPLFree( pabyBlueLine ); /* We're done with the boxes now */ CPLFree(box_list); freeboxes = usedboxes = NULL; CPLFree( histogram ); return err; }