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