예제 #1
0
파일: metadata.cpp 프로젝트: zlazow/GeoC
int main()
{
    GDALDataset  *poDataset;
    GDALAllRegister();
    poDataset = (GDALDataset *) GDALOpen( "GE01.tif", GA_ReadOnly );
    printf("Working! \n");

    if( poDataset != NULL ){
    	//Get Dataset Information
        double adfGeoTransform[6];

		printf( "Driver: %s/%s\n", poDataset->GetDriver()->GetDescription(), poDataset->GetDriver()->GetMetadataItem( GDAL_DMD_LONGNAME ) );

		printf( "Size is %dx%dx%d\n", poDataset->GetRasterXSize(), poDataset->GetRasterYSize(), poDataset->GetRasterCount() );

		if( poDataset->GetProjectionRef()  != NULL )
    		printf( "Projection is `%s'\n", poDataset->GetProjectionRef() );

		if( poDataset->GetGeoTransform( adfGeoTransform ) == CE_None ){
    		printf( "Origin = (%.6f,%.6f)\n",
            adfGeoTransform[0], adfGeoTransform[3] );
    		printf( "Pixel Size = (%.6f,%.6f)\n",
            adfGeoTransform[1], adfGeoTransform[5] );
		}

		//Fetch Raster Band
		GDALRasterBand  *poBand;
		int             nBlockXSize, nBlockYSize;
		int             bGotMin, bGotMax;
		double          adfMinMax[2];
		poBand = poDataset->GetRasterBand( 1 );
		poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
		printf( "Block=%dx%d Type=%s, ColorInterp=%s\n",
		        nBlockXSize, nBlockYSize,
		        GDALGetDataTypeName(poBand->GetRasterDataType()),
		        GDALGetColorInterpretationName(
		            poBand->GetColorInterpretation()) );
		adfMinMax[0] = poBand->GetMinimum( &bGotMin );
		adfMinMax[1] = poBand->GetMaximum( &bGotMax );
		if( ! (bGotMin && bGotMax) )
		    GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);
		printf( "Min=%.3fd, Max=%.3f\n", adfMinMax[0], adfMinMax[1] );
		if( poBand->GetOverviewCount() > 0 )
		    printf( "Band has %d overviews.\n", poBand->GetOverviewCount() );
		if( poBand->GetColorTable() != NULL )
		    printf( "Band has a color table with %d entries.\n", 
		             poBand->GetColorTable()->GetColorEntryCount() );

		//Close Dataset
		GDALClose(poDataset);
		//Exit      
		return 0;
	}


}
예제 #2
0
SEXP
RGDAL_GetPaletteInterp(SEXP sxpRasterBand) {

  GDALRasterBand *pRasterBand = getGDALRasterPtr(sxpRasterBand);

  GDALPaletteInterp ePI = 
    pRasterBand->GetColorTable()->GetPaletteInterpretation();

  return(mkString_safe(GDALGetPaletteInterpretationName(ePI)));

}
예제 #3
0
SEXP
RGDAL_GetPaletteInterp(SEXP sxpRasterBand) {

  GDALRasterBand *pRasterBand = getGDALRasterPtr(sxpRasterBand);

  installErrorHandler();
  GDALPaletteInterp ePI = 
    pRasterBand->GetColorTable()->GetPaletteInterpretation();
  uninstallErrorHandlerAndTriggerError();
  
  installErrorHandler();
  const char *desc = GDALGetPaletteInterpretationName(ePI);
  uninstallErrorHandlerAndTriggerError();
  return(mkString_safe(desc));

}
예제 #4
0
GDALColorTable *GDALProxyPoolRasterBand::GetColorTable()
{
    GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
    if (poUnderlyingRasterBand == NULL)
        return NULL;

    if (poColorTable)
        delete poColorTable;
    poColorTable = NULL;

    GDALColorTable* poUnderlyingColorTable = poUnderlyingRasterBand->GetColorTable();
    if (poUnderlyingColorTable)
        poColorTable = poUnderlyingColorTable->Clone();

    UnrefUnderlyingRasterBand(poUnderlyingRasterBand);

    return poColorTable;
}
예제 #5
0
static GDALDataset *
BSBCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
               int bStrict, char ** papszOptions, 
               GDALProgressFunc pfnProgress, void * pProgressData )

{
    int  nBands = poSrcDS->GetRasterCount();
    int  nXSize = poSrcDS->GetRasterXSize();
    int  nYSize = poSrcDS->GetRasterYSize();

/* -------------------------------------------------------------------- */
/*      Some some rudimentary checks                                    */
/* -------------------------------------------------------------------- */
    if( nBands != 1 )
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "BSB driver only supports one band images.\n" );

        return NULL;
    }

    if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte 
        && bStrict )
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "BSB driver doesn't support data type %s. "
                  "Only eight bit bands supported.\n", 
                  GDALGetDataTypeName( 
                      poSrcDS->GetRasterBand(1)->GetRasterDataType()) );

        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Open the output file.                                           */
/* -------------------------------------------------------------------- */
    BSBInfo *psBSB;

    psBSB = BSBCreate( pszFilename, 0, 200, nXSize, nYSize );
    if( psBSB == NULL )
        return NULL;

/* -------------------------------------------------------------------- */
/*      Prepare initial color table.colortable.                         */
/* -------------------------------------------------------------------- */
    GDALRasterBand	*poBand = poSrcDS->GetRasterBand(1);
    int			iColor;
    unsigned char       abyPCT[771];
    int                 nPCTSize;
    int                 anRemap[256];

    abyPCT[0] = 0;
    abyPCT[1] = 0;
    abyPCT[2] = 0;

    if( poBand->GetColorTable() == NULL )
    {
        /* map greyscale down to 63 grey levels. */
        for( iColor = 0; iColor < 256; iColor++ )
        {
            int nOutValue = (int) (iColor / 4.1) + 1;

            anRemap[iColor] = nOutValue;
            abyPCT[nOutValue*3 + 0] = (unsigned char) iColor;
            abyPCT[nOutValue*3 + 1] = (unsigned char) iColor;
            abyPCT[nOutValue*3 + 2] = (unsigned char) iColor;
        }
        nPCTSize = 64;
    }
    else
    {
        GDALColorTable	*poCT = poBand->GetColorTable();
        int nColorTableSize = poCT->GetColorEntryCount();
        if (nColorTableSize > 255)
            nColorTableSize = 255;

        for( iColor = 0; iColor < nColorTableSize; iColor++ )
        {
            GDALColorEntry	sEntry;

            poCT->GetColorEntryAsRGB( iColor, &sEntry );

            anRemap[iColor] = iColor + 1;
            abyPCT[(iColor+1)*3 + 0] = (unsigned char) sEntry.c1;
            abyPCT[(iColor+1)*3 + 1] = (unsigned char) sEntry.c2;
            abyPCT[(iColor+1)*3 + 2] = (unsigned char) sEntry.c3;
        }

        nPCTSize = nColorTableSize + 1;

        // Add entries for pixel values which apparently will not occur.
        for( iColor = nPCTSize; iColor < 256; iColor++ )
            anRemap[iColor] = 1;
    }

/* -------------------------------------------------------------------- */
/*      Boil out all duplicate entries.                                 */
/* -------------------------------------------------------------------- */
    int  i;

    for( i = 1; i < nPCTSize-1; i++ )
    {
        int  j;

        for( j = i+1; j < nPCTSize; j++ )
        {
            if( abyPCT[i*3+0] == abyPCT[j*3+0] 
                && abyPCT[i*3+1] == abyPCT[j*3+1] 
                && abyPCT[i*3+2] == abyPCT[j*3+2] )
            {
                int   k;

                nPCTSize--;
                abyPCT[j*3+0] = abyPCT[nPCTSize*3+0];
                abyPCT[j*3+1] = abyPCT[nPCTSize*3+1];
                abyPCT[j*3+2] = abyPCT[nPCTSize*3+2];

                for( k = 0; k < 256; k++ )
                {
                    // merge matching entries.
                    if( anRemap[k] == j )
                        anRemap[k] = i;

                    // shift the last PCT entry into the new hole.
                    if( anRemap[k] == nPCTSize )
                        anRemap[k] = j;
                }
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Boil out all duplicate entries.                                 */
/* -------------------------------------------------------------------- */
    if( nPCTSize > 128 )
    {
        CPLError( CE_Warning, CPLE_AppDefined,
                  "Having to merge color table entries to reduce %d real\n"
                  "color table entries down to 127 values.", 
                  nPCTSize );
    }

    while( nPCTSize > 128 )
    {
        int nBestRange = 768;
        int iBestMatch1=-1, iBestMatch2=-1;

        // Find the closest pair of color table entries.

        for( i = 1; i < nPCTSize-1; i++ )
        {
            int  j;
            
            for( j = i+1; j < nPCTSize; j++ )
            {
                int nRange = ABS(abyPCT[i*3+0] - abyPCT[j*3+0])
                    + ABS(abyPCT[i*3+1] - abyPCT[j*3+1])
                    + ABS(abyPCT[i*3+2] - abyPCT[j*3+2]);

                if( nRange < nBestRange )
                {
                    iBestMatch1 = i;
                    iBestMatch2 = j;
                    nBestRange = nRange;
                }
            }
        }

        // Merge the second entry into the first. 
        nPCTSize--;
        abyPCT[iBestMatch2*3+0] = abyPCT[nPCTSize*3+0];
        abyPCT[iBestMatch2*3+1] = abyPCT[nPCTSize*3+1];
        abyPCT[iBestMatch2*3+2] = abyPCT[nPCTSize*3+2];

        for( i = 0; i < 256; i++ )
        {
            // merge matching entries.
            if( anRemap[i] == iBestMatch2 )
                anRemap[i] = iBestMatch1;
            
            // shift the last PCT entry into the new hole.
            if( anRemap[i] == nPCTSize )
                anRemap[i] = iBestMatch2;
        }
    }

/* -------------------------------------------------------------------- */
/*      Write the PCT.                                                  */
/* -------------------------------------------------------------------- */
    if( !BSBWritePCT( psBSB, nPCTSize, abyPCT ) )
    {
        BSBClose( psBSB );
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Write the GCPs.                                                 */
/* -------------------------------------------------------------------- */
    double adfGeoTransform[6];
    int nGCPCount = poSrcDS->GetGCPCount();
    if (nGCPCount)
    {
        const char* pszGCPProjection = poSrcDS->GetGCPProjection();
        if ( BSBIsSRSOK(pszGCPProjection) )
        {
            const GDAL_GCP * pasGCPList = poSrcDS->GetGCPs();
            for( i = 0; i < nGCPCount; i++ )
            {
                VSIFPrintfL( psBSB->fp, 
                            "REF/%d,%f,%f,%f,%f\n", 
                            i+1,
                            pasGCPList[i].dfGCPPixel, pasGCPList[i].dfGCPLine,
                            pasGCPList[i].dfGCPY, pasGCPList[i].dfGCPX);
            }
        }
    }
    else if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None)
    {
        const char* pszProjection = poSrcDS->GetProjectionRef();
        if ( BSBIsSRSOK(pszProjection) )
        {
            VSIFPrintfL( psBSB->fp, 
                        "REF/%d,%d,%d,%f,%f\n",
                        1,
                        0, 0,
                        adfGeoTransform[3] + 0 * adfGeoTransform[4] + 0 * adfGeoTransform[5],
                        adfGeoTransform[0] + 0 * adfGeoTransform[1] + 0 * adfGeoTransform[2]);
            VSIFPrintfL( psBSB->fp, 
                        "REF/%d,%d,%d,%f,%f\n",
                        2,
                        nXSize, 0,
                        adfGeoTransform[3] + nXSize * adfGeoTransform[4] + 0 * adfGeoTransform[5],
                        adfGeoTransform[0] + nXSize * adfGeoTransform[1] + 0 * adfGeoTransform[2]);
            VSIFPrintfL( psBSB->fp, 
                        "REF/%d,%d,%d,%f,%f\n",
                        3,
                        nXSize, nYSize,
                        adfGeoTransform[3] + nXSize * adfGeoTransform[4] + nYSize * adfGeoTransform[5],
                        adfGeoTransform[0] + nXSize * adfGeoTransform[1] + nYSize * adfGeoTransform[2]);
            VSIFPrintfL( psBSB->fp, 
                        "REF/%d,%d,%d,%f,%f\n",
                        4,
                        0, nYSize,
                        adfGeoTransform[3] + 0 * adfGeoTransform[4] + nYSize * adfGeoTransform[5],
                        adfGeoTransform[0] + 0 * adfGeoTransform[1] + nYSize * adfGeoTransform[2]);
        }
    }

/* -------------------------------------------------------------------- */
/*      Loop over image, copying image data.                            */
/* -------------------------------------------------------------------- */
    GByte 	*pabyScanline;
    CPLErr      eErr = CE_None;

    pabyScanline = (GByte *) CPLMalloc( nXSize );

    for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )
    {
        eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                                 pabyScanline, nXSize, 1, GDT_Byte,
                                 nBands, nBands * nXSize );
        if( eErr == CE_None )
        {
            for( i = 0; i < nXSize; i++ )
                pabyScanline[i] = (GByte) anRemap[pabyScanline[i]];

            if( !BSBWriteScanline( psBSB, pabyScanline ) )
                eErr = CE_Failure;
        }
    }

    CPLFree( pabyScanline );

/* -------------------------------------------------------------------- */
/*      cleanup                                                         */
/* -------------------------------------------------------------------- */
    BSBClose( psBSB );

    if( eErr != CE_None )
    {
        VSIUnlink( pszFilename );
        return NULL;
    }
    else
        return (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly );
}
예제 #6
0
CC_FILE_ERROR RasterGridFilter::loadFile(QString filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, CCVector3d* coordinatesShift/*=0*/)
{
	GDALAllRegister();
	ccLog::PrintDebug("(GDAL drivers: %i)", GetGDALDriverManager()->GetDriverCount());

	GDALDataset* poDataset = static_cast<GDALDataset*>(GDALOpen( qPrintable(filename), GA_ReadOnly ));

	if( poDataset != NULL )
	{
		ccLog::Print(QString("Raster file: '%1'").arg(filename));
		ccLog::Print( "Driver: %s/%s",
			poDataset->GetDriver()->GetDescription(), 
			poDataset->GetDriver()->GetMetadataItem( GDAL_DMD_LONGNAME ) );

		int rasterCount = poDataset->GetRasterCount();
		int rasterX = poDataset->GetRasterXSize();
		int rasterY = poDataset->GetRasterYSize();
		ccLog::Print( "Size is %dx%dx%d", rasterX, rasterY, rasterCount );

		ccPointCloud* pc = new ccPointCloud();
		if (!pc->reserve(static_cast<unsigned>(rasterX * rasterY)))
		{
			delete pc;
			return CC_FERR_NOT_ENOUGH_MEMORY;
		}

		if( poDataset->GetProjectionRef() != NULL )
			ccLog::Print( "Projection is `%s'", poDataset->GetProjectionRef() );

		double adfGeoTransform[6] = {	 0, //top left x
										 1, //w-e pixel resolution (can be negative)
										 0, //0
										 0, //top left y
										 0, //0
										 1  //n-s pixel resolution (can be negative)
		};

		if( poDataset->GetGeoTransform( adfGeoTransform ) == CE_None )
		{
			ccLog::Print( "Origin = (%.6f,%.6f)", adfGeoTransform[0], adfGeoTransform[3] );
			ccLog::Print( "Pixel Size = (%.6f,%.6f)", adfGeoTransform[1], adfGeoTransform[5] );
		}

		if (adfGeoTransform[1] == 0 || adfGeoTransform[5] == 0)
		{
			ccLog::Warning("Invalid pixel size! Forcing it to (1,1)");
			adfGeoTransform[1] = adfGeoTransform[5] = 1;
		}

		CCVector3d origin( adfGeoTransform[0], adfGeoTransform[3], 0.0 );
		CCVector3d Pshift(0,0,0);
		//check for 'big' coordinates
		{
			bool shiftAlreadyEnabled = (coordinatesShiftEnabled && *coordinatesShiftEnabled && coordinatesShift);
			if (shiftAlreadyEnabled)
				Pshift = *coordinatesShift;
			bool applyAll = false;
			if (	sizeof(PointCoordinateType) < 8
				&&	ccCoordinatesShiftManager::Handle(origin,0,alwaysDisplayLoadDialog,shiftAlreadyEnabled,Pshift,0,&applyAll))
			{
				pc->setGlobalShift(Pshift);
				ccLog::Warning("[RasterFilter::loadFile] Raster has been recentered! Translation: (%.2f,%.2f,%.2f)",Pshift.x,Pshift.y,Pshift.z);

				//we save coordinates shift information
				if (applyAll && coordinatesShiftEnabled && coordinatesShift)
				{
					*coordinatesShiftEnabled = true;
					*coordinatesShift = Pshift;
				}
			}
		}

		//create blank raster 'grid'
		{
			double z = 0.0 /*+ Pshift.z*/;
			for (int j=0; j<rasterY; ++j)
			{
				double y = adfGeoTransform[3] + static_cast<double>(j) * adfGeoTransform[5] + Pshift.y;
				CCVector3 P(	0,
								static_cast<PointCoordinateType>(y),
								static_cast<PointCoordinateType>(z));
				for (int i=0; i<rasterX; ++i)
				{
					double x = adfGeoTransform[0] + static_cast<double>(i) * adfGeoTransform[1] + Pshift.x;

					P.x = static_cast<PointCoordinateType>(x);
					pc->addPoint(P);
				}
			}

			QVariant xVar = QVariant::fromValue<int>(rasterX);
			QVariant yVar = QVariant::fromValue<int>(rasterY);
			pc->setMetaData("raster_width",xVar);
			pc->setMetaData("raster_height",yVar);
		}

		//fetch raster bands
		bool zRasterProcessed = false;
		unsigned zInvalid = 0;
		double zMinMax[2] = {0, 0};

		for (int i=1; i<=rasterCount; ++i)
		{
			ccLog::Print( "Reading band #%i", i);
			GDALRasterBand* poBand = poDataset->GetRasterBand(i);

			GDALColorInterp colorInterp = poBand->GetColorInterpretation();
			GDALDataType bandType = poBand->GetRasterDataType();

			int nBlockXSize, nBlockYSize;
			poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
			ccLog::Print( "Block=%dx%d Type=%s, ColorInterp=%s", nBlockXSize, nBlockYSize, GDALGetDataTypeName(poBand->GetRasterDataType()), GDALGetColorInterpretationName(colorInterp) );

			//fetching raster scan-line
			int nXSize = poBand->GetXSize();
			int nYSize = poBand->GetYSize();
			assert(nXSize == rasterX);
			assert(nYSize == rasterY);
			
			int bGotMin, bGotMax;
			double adfMinMax[2] = {0, 0};
			adfMinMax[0] = poBand->GetMinimum( &bGotMin );
			adfMinMax[1] = poBand->GetMaximum( &bGotMax );
			if (!bGotMin || !bGotMax )
				//DGM FIXME: if the file is corrupted (e.g. ASCII ArcGrid with missing rows) this method will enter in a infinite loop!
				GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);
			ccLog::Print( "Min=%.3fd, Max=%.3f", adfMinMax[0], adfMinMax[1] );

			GDALColorTable* colTable = poBand->GetColorTable();
			if( colTable != NULL )
				printf( "Band has a color table with %d entries", colTable->GetColorEntryCount() );

			if( poBand->GetOverviewCount() > 0 )
				printf( "Band has %d overviews", poBand->GetOverviewCount() );

			if (colorInterp == GCI_Undefined && !zRasterProcessed/*&& !colTable*/) //probably heights?
			{
				zRasterProcessed = true;
				zMinMax[0] = adfMinMax[0];
				zMinMax[1] = adfMinMax[1];

				double* scanline = (double*) CPLMalloc(sizeof(double)*nXSize);
				//double* scanline = new double[nXSize];
				memset(scanline,0,sizeof(double)*nXSize);

				for (int j=0; j<nYSize; ++j)
				{
					if (poBand->RasterIO( GF_Read, /*xOffset=*/0, /*yOffset=*/j, /*xSize=*/nXSize, /*ySize=*/1, /*buffer=*/scanline, /*bufferSizeX=*/nXSize, /*bufferSizeY=*/1, /*bufferType=*/GDT_Float64, /*x_offset=*/0, /*y_offset=*/0 ) != CE_None)
					{
						delete pc;
						CPLFree(scanline);
						GDALClose(poDataset);
						return CC_FERR_READING;
					}

					for (int k=0; k<nXSize; ++k)
					{
						double z = static_cast<double>(scanline[k]) + Pshift[2];
						unsigned pointIndex = static_cast<unsigned>(k + j * rasterX);
						if (pointIndex <= pc->size())
						{
							if (z < zMinMax[0] || z > zMinMax[1])
							{
								z = zMinMax[0] - 1.0;
								++zInvalid;
							}
							const_cast<CCVector3*>(pc->getPoint(pointIndex))->z = static_cast<PointCoordinateType>(z);
						}
					}
				}

				//update bounding-box
				pc->invalidateBoundingBox();

				if (scanline)
					CPLFree(scanline);
				scanline = 0;
			}
			else //colors
			{
				bool isRGB = false;
				bool isScalar = false;
				bool isPalette = false;
				
				switch(colorInterp)
				{
				case GCI_Undefined:
					isScalar = true;
					break;
				case GCI_PaletteIndex:
					isPalette = true;
					break;
				case GCI_RedBand:
				case GCI_GreenBand:
				case GCI_BlueBand:
					isRGB = true;
					break;
				case GCI_AlphaBand:
					if (adfMinMax[0] != adfMinMax[1])
						isScalar = true;
					else
						ccLog::Warning(QString("Alpha band ignored as it has a unique value (%1)").arg(adfMinMax[0]));
					break;
				default:
					isScalar = true;
					break;
				}


				if (isRGB || isPalette)
				{
					//first check that a palette exists if the band is a palette index
					if (isPalette && !colTable)
					{
						ccLog::Warning(QString("Band is declared as a '%1' but no palette is associated!").arg(GDALGetColorInterpretationName(colorInterp)));
						isPalette = false;
					}
					else
					{
						//instantiate memory for RBG colors if necessary
						if (!pc->hasColors() && !pc->setRGBColor(MAX_COLOR_COMP,MAX_COLOR_COMP,MAX_COLOR_COMP))
						{
							ccLog::Warning(QString("Failed to instantiate memory for storing color band '%1'!").arg(GDALGetColorInterpretationName(colorInterp)));
						}
						else
						{
							assert(bandType <= GDT_Int32);

							int* colIndexes = (int*) CPLMalloc(sizeof(int)*nXSize);
							//double* scanline = new double[nXSize];
							memset(colIndexes,0,sizeof(int)*nXSize);

							for (int j=0; j<nYSize; ++j)
							{
								if (poBand->RasterIO( GF_Read, /*xOffset=*/0, /*yOffset=*/j, /*xSize=*/nXSize, /*ySize=*/1, /*buffer=*/colIndexes, /*bufferSizeX=*/nXSize, /*bufferSizeY=*/1, /*bufferType=*/GDT_Int32, /*x_offset=*/0, /*y_offset=*/0 ) != CE_None)
								{
									CPLFree(colIndexes);
									delete pc;
									return CC_FERR_READING;
								}

								for (int k=0; k<nXSize; ++k)
								{
									unsigned pointIndex = static_cast<unsigned>(k + j * rasterX);
									if (pointIndex <= pc->size())
									{
										colorType* C = const_cast<colorType*>(pc->getPointColor(pointIndex));

										switch(colorInterp)
										{
										case GCI_PaletteIndex:
											assert(colTable);
											{
												GDALColorEntry col;
												colTable->GetColorEntryAsRGB(colIndexes[k],&col);
												C[0] = static_cast<colorType>(col.c1 & MAX_COLOR_COMP);
												C[1] = static_cast<colorType>(col.c2 & MAX_COLOR_COMP);
												C[2] = static_cast<colorType>(col.c3 & MAX_COLOR_COMP);
											}
											break;

										case GCI_RedBand:
											C[0] = static_cast<colorType>(colIndexes[k] & MAX_COLOR_COMP);
											break;
										case GCI_GreenBand:
											C[1] = static_cast<colorType>(colIndexes[k] & MAX_COLOR_COMP);
											break;
										case GCI_BlueBand:
											C[2] = static_cast<colorType>(colIndexes[k] & MAX_COLOR_COMP);
											break;

										default:
											assert(false);
											break;
										}
									}
								}
							}

							if (colIndexes)
								CPLFree(colIndexes);
							colIndexes = 0;

							pc->showColors(true);
						}
					}
				}
				else if (isScalar)
				{
					ccScalarField* sf = new ccScalarField(GDALGetColorInterpretationName(colorInterp));
					if (!sf->resize(pc->size(),true,NAN_VALUE))
					{
						ccLog::Warning(QString("Failed to instantiate memory for storing '%1' as a scalar field!").arg(sf->getName()));
						sf->release();
						sf = 0;
					}
					else
					{
						double* colValues = (double*) CPLMalloc(sizeof(double)*nXSize);
						//double* scanline = new double[nXSize];
						memset(colValues,0,sizeof(double)*nXSize);

						for (int j=0; j<nYSize; ++j)
						{
							if (poBand->RasterIO( GF_Read, /*xOffset=*/0, /*yOffset=*/j, /*xSize=*/nXSize, /*ySize=*/1, /*buffer=*/colValues, /*bufferSizeX=*/nXSize, /*bufferSizeY=*/1, /*bufferType=*/GDT_Float64, /*x_offset=*/0, /*y_offset=*/0 ) != CE_None)
							{
								CPLFree(colValues);
								delete pc;
								return CC_FERR_READING;
							}

							for (int k=0; k<nXSize; ++k)
							{
								unsigned pointIndex = static_cast<unsigned>(k + j * rasterX);
								if (pointIndex <= pc->size())
								{
									ScalarType s = static_cast<ScalarType>(colValues[k]);
									sf->setValue(pointIndex,s);
								}
							}
						}

						if (colValues)
							CPLFree(colValues);
						colValues = 0;

						sf->computeMinAndMax();
						pc->addScalarField(sf);
						if (pc->getNumberOfScalarFields() == 1)
							pc->setCurrentDisplayedScalarField(0);
						pc->showSF(true);
					}
				}
			}
		}

		if (pc)
		{
			if (!zRasterProcessed)
			{
				ccLog::Warning("Raster has no height (Z) information: you can convert one of its scalar fields to Z with 'Edit > Scalar Fields > Set SF as coordinate(s)'");
			}
			else if (zInvalid != 0 && zInvalid < pc->size())
			{
				//shall we remove the points with invalid heights?
				if (QMessageBox::question(0,"Remove NaN points?","This raster has pixels with invalid heights. Shall we remove them?",QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
				{
					CCLib::ReferenceCloud validPoints(pc);
					unsigned count = pc->size();
					bool error = true;
					if (validPoints.reserve(count-zInvalid))
					{
						for (unsigned i=0; i<count; ++i)
						{
							if (pc->getPoint(i)->z >= zMinMax[0])
								validPoints.addPointIndex(i);
						}

						if (validPoints.size() > 0)
						{
							validPoints.resize(validPoints.size());
							ccPointCloud* newPC = pc->partialClone(&validPoints);
							if (newPC)
							{
								delete pc;
								pc = newPC;
								error = false;
							}
						}
						else
						{
							assert(false);
						}
					}

					if (error)
					{
						ccLog::Error("Not enough memory to remove the points with invalid heights!");
					}
				}
			}
			container.addChild(pc);
		}

		GDALClose(poDataset);
	}
	else
	{
		return CC_FERR_UNKNOWN_FILE;
	}

	return CC_FERR_NO_ERROR;
}
예제 #7
0
feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
{
    feature_ptr feature = feature_factory::create(ctx_,1);
    int raster_has_nodata = 0;
    double raster_nodata = 0;
    GDALRasterBand * red = 0;
    GDALRasterBand * green = 0;
    GDALRasterBand * blue = 0;
    GDALRasterBand * alpha = 0;
    GDALRasterBand * grey = 0;
    CPLErr raster_io_error = CE_None;

    /*
#ifdef MAPNIK_LOG
      double tr[6];
      dataset_.GetGeoTransform(tr);

      const double dx = tr[1];
      const double dy = tr[5];
      MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: dx_=" << dx_ << " dx=" << dx << " dy_=" << dy_ << "dy=" << dy;
#endif
    */

    view_transform t(raster_width_, raster_height_, raster_extent_, 0, 0);
    box2d<double> intersect = raster_extent_.intersect(q.get_bbox());
    box2d<double> box = t.forward(intersect);

    //size of resized output pixel in source image domain
    double margin_x = 1.0 / (std::fabs(dx_) * std::get<0>(q.resolution()));
    double margin_y = 1.0 / (std::fabs(dy_) * std::get<1>(q.resolution()));
    if (margin_x < 1)
    {
        margin_x = 1.0;
    }
    if (margin_y < 1)
    {
        margin_y = 1.0;
    }

    //select minimum raster containing whole box
    int x_off = rint(box.minx() - margin_x);
    int y_off = rint(box.miny() - margin_y);
    int end_x = rint(box.maxx() + margin_x);
    int end_y = rint(box.maxy() + margin_y);

    //clip to available data
    if (x_off < 0)
    {
        x_off = 0;
    }
    if (y_off < 0)
    {
        y_off = 0;
    }
    if (end_x > (int)raster_width_)
    {
        end_x = raster_width_;
    }
    if (end_y > (int)raster_height_)
    {
        end_y = raster_height_;
    }
    int width = end_x - x_off;
    int height = end_y - y_off;

    // don't process almost invisible data
    if (box.width() < 0.5)
    {
        width = 0;
    }
    if (box.height() < 0.5)
    {
        height = 0;
    }

    //calculate actual box2d of returned raster
    box2d<double> feature_raster_extent(x_off, y_off, x_off + width, y_off + height);
    intersect = t.backward(feature_raster_extent);

    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Raster extent=" << raster_extent_;
    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: View extent=" << intersect;
    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Query resolution=" << std::get<0>(q.resolution()) << "," << std::get<1>(q.resolution());
    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: StartX=" << x_off << " StartY=" << y_off << " Width=" << width << " Height=" << height;

    if (width > 0 && height > 0)
    {
        double width_res = std::get<0>(q.resolution());
        double height_res = std::get<1>(q.resolution());
        int im_width = int(width_res * intersect.width() + 0.5);
        int im_height = int(height_res * intersect.height() + 0.5);

        double filter_factor = q.get_filter_factor();
        im_width = int(im_width * filter_factor + 0.5);
        im_height = int(im_height * filter_factor + 0.5);

        // case where we need to avoid upsampling so that the
        // image can be later scaled within raster_symbolizer
        if (im_width >= width || im_height >= height)
        {
            im_width = width;
            im_height = height;
        }

        if (im_width > 0 && im_height > 0)
        {
            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Image Size=(" << im_width << "," << im_height << ")";
            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_;
            if (band_ > 0) // we are querying a single band
            {
                GDALRasterBand * band = dataset_.GetRasterBand(band_);
                if (band_ > nbands_)
                {
                    std::ostringstream s;
                    s << "GDAL Plugin: " << band_ << " is an invalid band, dataset only has " << nbands_ << "bands";
                    throw datasource_exception(s.str());
                }
                GDALDataType band_type = band->GetRasterDataType();
                switch (band_type)
                {
                case GDT_Byte:
                {
                    mapnik::image_gray8 image(im_width, im_height);
                    image.set(std::numeric_limits<std::uint8_t>::max());
                    raster_nodata = band->GetNoDataValue(&raster_has_nodata);
                    raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
                                                     image.data(), image.width(), image.height(),
                                                     GDT_Byte, 0, 0);
                    if (raster_io_error == CE_Failure)
                    {
                        throw datasource_exception(CPLGetLastErrorMsg());
                    }
                    mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
                    // set nodata value to be used in raster colorizer
                    if (nodata_value_) raster->set_nodata(*nodata_value_);
                    else raster->set_nodata(raster_nodata);
                    feature->set_raster(raster);
                    break;
                }
                case GDT_Float64:
                case GDT_Float32:
                {
                    mapnik::image_gray32f image(im_width, im_height);
                    image.set(std::numeric_limits<float>::max());
                    raster_nodata = band->GetNoDataValue(&raster_has_nodata);
                    raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
                                                     image.data(), image.width(), image.height(),
                                                     GDT_Float32, 0, 0);
                    if (raster_io_error == CE_Failure)
                    {
                        throw datasource_exception(CPLGetLastErrorMsg());
                    }
                    mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
                    // set nodata value to be used in raster colorizer
                    if (nodata_value_) raster->set_nodata(*nodata_value_);
                    else raster->set_nodata(raster_nodata);
                    feature->set_raster(raster);
                    break;
                }
                case GDT_UInt16:
                {
                    mapnik::image_gray16 image(im_width, im_height);
                    image.set(std::numeric_limits<std::uint16_t>::max());
                    raster_nodata = band->GetNoDataValue(&raster_has_nodata);
                    raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
                                                     image.data(), image.width(), image.height(),
                                                     GDT_UInt16, 0, 0);
                    if (raster_io_error == CE_Failure)
                    {
                        throw datasource_exception(CPLGetLastErrorMsg());
                    }
                    mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
                    // set nodata value to be used in raster colorizer
                    if (nodata_value_) raster->set_nodata(*nodata_value_);
                    else raster->set_nodata(raster_nodata);
                    feature->set_raster(raster);
                    break;
                }
                default:
                case GDT_Int16:
                {
                    mapnik::image_gray16s image(im_width, im_height);
                    image.set(std::numeric_limits<std::int16_t>::max());
                    raster_nodata = band->GetNoDataValue(&raster_has_nodata);
                    raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height,
                                                     image.data(), image.width(), image.height(),
                                                     GDT_Int16, 0, 0);
                    if (raster_io_error == CE_Failure)
                    {
                        throw datasource_exception(CPLGetLastErrorMsg());
                    }
                    mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
                    // set nodata value to be used in raster colorizer
                    if (nodata_value_) raster->set_nodata(*nodata_value_);
                    else raster->set_nodata(raster_nodata);
                    feature->set_raster(raster);
                    break;
                }
                }
            }
            else // working with all bands
            {
                mapnik::image_rgba8 image(im_width, im_height);
                image.set(std::numeric_limits<std::uint32_t>::max());
                for (int i = 0; i < nbands_; ++i)
                {
                    GDALRasterBand * band = dataset_.GetRasterBand(i + 1);
#ifdef MAPNIK_LOG
                    get_overview_meta(band);
#endif
                    GDALColorInterp color_interp = band->GetColorInterpretation();
                    switch (color_interp)
                    {
                    case GCI_RedBand:
                        red = band;
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found red band";
                        break;
                    case GCI_GreenBand:
                        green = band;
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found green band";
                        break;
                    case GCI_BlueBand:
                        blue = band;
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found blue band";
                        break;
                    case GCI_AlphaBand:
                        alpha = band;
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found alpha band";
                        break;
                    case GCI_GrayIndex:
                        grey = band;
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found gray band";
                        break;
                    case GCI_PaletteIndex:
                    {
                        grey = band;
#ifdef MAPNIK_LOG
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found gray band, and colortable...";
                        GDALColorTable *color_table = band->GetColorTable();

                        if (color_table)
                        {
                            int count = color_table->GetColorEntryCount();
                            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Color Table count=" << count;

                            for (int j = 0; j < count; j++)
                            {
                                const GDALColorEntry *ce = color_table->GetColorEntry (j);
                                if (! ce) continue;
                                MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Color entry RGB=" << ce->c1 << "," <<ce->c2 << "," << ce->c3;
                            }
                        }
#endif
                        break;
                    }
                    case GCI_Undefined:
#if GDAL_VERSION_NUM <= 1730
                        if (nbands_ == 4)
                        {
                            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found undefined band (assumming alpha band)";
                            alpha = band;
                        }
                        else
                        {
                            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found undefined band (assumming gray band)";
                            grey = band;
                        }
#else
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found undefined band (assumming gray band)";
                        grey = band;
#endif
                        break;
                    default:
                        MAPNIK_LOG_WARN(gdal) << "gdal_featureset: Band type unknown!";
                        break;
                    }
                }
                if (red && green && blue)
                {
                    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing rgb bands...";
                    raster_nodata = red->GetNoDataValue(&raster_has_nodata);
                    GDALColorTable *color_table = red->GetColorTable();
                    bool has_nodata = nodata_value_ || raster_has_nodata;

                    // we can deduce the alpha channel from nodata in the Byte case
                    // by reusing the reading of R,G,B bands directly
                    if (has_nodata && !color_table && red->GetRasterDataType() == GDT_Byte)
                    {
                        double apply_nodata = nodata_value_ ? *nodata_value_ : raster_nodata;
                        // read the data in and create an alpha channel from the nodata values
                        // TODO - we assume here the nodata value for the red band applies to all bands
                        // more details about this at http://trac.osgeo.org/gdal/ticket/2734
                        float* imageData = (float*)image.bytes();
                        raster_io_error = red->RasterIO(GF_Read, x_off, y_off, width, height,
                                                        imageData, image.width(), image.height(),
                                                        GDT_Float32, 0, 0);
                        if (raster_io_error == CE_Failure) {
                            throw datasource_exception(CPLGetLastErrorMsg());
                        }
                        int len = image.width() * image.height();
                        for (int i = 0; i < len; ++i)
                        {
                            if (std::fabs(apply_nodata - imageData[i]) < nodata_tolerance_)
                            {
                                *reinterpret_cast<unsigned *>(&imageData[i]) = 0;
                            }
                            else
                            {
                                *reinterpret_cast<unsigned *>(&imageData[i]) = 0xFFFFFFFF;
                            }
                        }
                    }

                    /* Use dataset RasterIO in priority in 99.9% of the cases */
                    if( red->GetBand() == 1 && green->GetBand() == 2 && blue->GetBand() == 3 )
                    {
                        int nBandsToRead = 3;
                        if( alpha != NULL && alpha->GetBand() == 4 && !raster_has_nodata )
                        {
                            nBandsToRead = 4;
                            alpha = NULL; // to avoid reading it again afterwards
                        }
                        raster_io_error = dataset_.RasterIO(GF_Read, x_off, y_off, width, height,
                                                            image.bytes(),
                                                            image.width(), image.height(), GDT_Byte,
                                                            nBandsToRead, NULL,
                                                            4, 4 * image.width(), 1);
                        if (raster_io_error == CE_Failure) {
                            throw datasource_exception(CPLGetLastErrorMsg());
                        }
                    }
                    else
                    {
                        raster_io_error = red->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 0,
                                                        image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                        if (raster_io_error == CE_Failure) {
                            throw datasource_exception(CPLGetLastErrorMsg());
                        }
                        raster_io_error = green->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 1,
                                                        image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                        if (raster_io_error == CE_Failure) {
                            throw datasource_exception(CPLGetLastErrorMsg());
                        }
                        raster_io_error = blue->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 2,
                                                        image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                        if (raster_io_error == CE_Failure) {
                            throw datasource_exception(CPLGetLastErrorMsg());
                        }
                    }

                    // In the case we skipped initializing the alpha channel
                    if (has_nodata && !color_table && red->GetRasterDataType() == GDT_Byte)
                    {
                        double apply_nodata = nodata_value_ ? *nodata_value_ : raster_nodata;
                        if( apply_nodata >= 0 && apply_nodata <= 255 )
                        {
                            int len = image.width() * image.height();
                            GByte* pabyBytes = (GByte*) image.bytes();
                            for (int i = 0; i < len; ++i)
                            {
                                // TODO - we assume here the nodata value for the red band applies to all bands
                                // more details about this at http://trac.osgeo.org/gdal/ticket/2734
                                if (std::fabs(apply_nodata - pabyBytes[4*i]) < nodata_tolerance_)
                                    pabyBytes[4*i + 3] = 0;
                                else
                                    pabyBytes[4*i + 3] = 255;
                            }
                        }
                    }
                }
                else if (grey)
                {
                    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing gray band...";
                    raster_nodata = grey->GetNoDataValue(&raster_has_nodata);
                    GDALColorTable* color_table = grey->GetColorTable();
                    bool has_nodata = nodata_value_ || raster_has_nodata;
                    if (!color_table && has_nodata)
                    {
                        double apply_nodata = nodata_value_ ? *nodata_value_ : raster_nodata;
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: applying nodata value for layer=" << apply_nodata;
                        // first read the data in and create an alpha channel from the nodata values
                        float* imageData = (float*)image.bytes();
                        raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height,
                                                         imageData, image.width(), image.height(),
                                                         GDT_Float32, 0, 0);
                        if (raster_io_error == CE_Failure)
                        {
                            throw datasource_exception(CPLGetLastErrorMsg());
                        }
                        int len = image.width() * image.height();
                        for (int i = 0; i < len; ++i)
                        {
                            if (std::fabs(apply_nodata - imageData[i]) < nodata_tolerance_)
                            {
                                *reinterpret_cast<unsigned *>(&imageData[i]) = 0;
                            }
                            else
                            {
                                *reinterpret_cast<unsigned *>(&imageData[i]) = 0xFFFFFFFF;
                            }
                        }
                    }

                    raster_io_error = grey->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 0,
                                                     image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                    if (raster_io_error == CE_Failure)
                    {
                        throw datasource_exception(CPLGetLastErrorMsg());
                    }

                    raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.bytes() + 1,
                                                     image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                    if (raster_io_error == CE_Failure)
                    {
                        throw datasource_exception(CPLGetLastErrorMsg());
                    }

                    raster_io_error = grey->RasterIO(GF_Read,x_off, y_off, width, height, image.bytes() + 2,
                                                     image.width(), image.height(), GDT_Byte, 4, 4 * image.width());

                    if (raster_io_error == CE_Failure)
                    {
                        throw datasource_exception(CPLGetLastErrorMsg());
                    }

                    if (color_table)
                    {
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Loading color table...";
                        for (unsigned y = 0; y < image.height(); ++y)
                        {
                            unsigned int* row = image.get_row(y);
                            for (unsigned x = 0; x < image.width(); ++x)
                            {
                                unsigned value = row[x] & 0xff;
                                const GDALColorEntry *ce = color_table->GetColorEntry(value);
                                if (ce)
                                {
                                    row[x] = (ce->c4 << 24)| (ce->c3 << 16) |  (ce->c2 << 8) | (ce->c1) ;
                                }
                                else
                                {
                                    // make lacking color entry fully alpha
                                    // note - gdal_translate makes black
                                    row[x] = 0;
                                }
                            }
                        }
                    }
                }
                if (alpha)
                {
                    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: processing alpha band...";
                    if (!raster_has_nodata)
                    {
                        raster_io_error = alpha->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 3,
                                                          image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                        if (raster_io_error == CE_Failure) {
                            throw datasource_exception(CPLGetLastErrorMsg());
                        }
                    }
                    else
                    {
                        MAPNIK_LOG_WARN(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of alpha band";
                    }
                }
                mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
                // set nodata value to be used in raster colorizer
                if (nodata_value_) raster->set_nodata(*nodata_value_);
                else raster->set_nodata(raster_nodata);
                feature->set_raster(raster);
            }
            // report actual/original source nodata in feature attributes
            if (raster_has_nodata)
            {
                feature->put("nodata",raster_nodata);
            }
            return feature;
        }
    }
    return feature_ptr();
}
예제 #8
0
GDALDataset *IntergraphDataset::CreateCopy( const char *pszFilename,
        GDALDataset *poSrcDS,
        int bStrict,
        char **papszOptions,
        GDALProgressFunc pfnProgress,
        void *pProgressData )
{
    (void) bStrict;

    int nBands = poSrcDS->GetRasterCount();
    if (nBands == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Intergraph driver does not support source dataset with zero band.\n");
        return NULL;
    }

    if( !pfnProgress( 0.0, NULL, pProgressData ) )
    {
        return NULL;
    }

    // --------------------------------------------------------------------
    // Query GDAL Data Type
    // --------------------------------------------------------------------

    GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();

    // --------------------------------------------------------------------
    // Copy metadata
    // --------------------------------------------------------------------

    char **papszCreateOptions = CSLDuplicate( papszOptions );
    const char  *pszValue;

    pszValue = CSLFetchNameValue(papszCreateOptions, "RESOLUTION");
    if( pszValue == NULL )
    {
        const char *value = poSrcDS->GetMetadataItem("RESOLUTION");
        if (value)
        {
            papszCreateOptions = CSLSetNameValue( papszCreateOptions, "RESOLUTION",
                                                  value );
        }
    }

    // --------------------------------------------------------------------
    // Create IntergraphDataset
    // --------------------------------------------------------------------

    IntergraphDataset *poDstDS;

    poDstDS = (IntergraphDataset*) IntergraphDataset::Create( pszFilename,
              poSrcDS->GetRasterXSize(),
              poSrcDS->GetRasterYSize(),
              poSrcDS->GetRasterCount(),
              eType,
              papszCreateOptions );

    CSLDestroy( papszCreateOptions );

    if( poDstDS == NULL )
    {
        return NULL;
    }

    // --------------------------------------------------------------------
    // Copy Transformation Matrix to the dataset
    // --------------------------------------------------------------------

    double adfGeoTransform[6];

    poDstDS->SetProjection( poSrcDS->GetProjectionRef() );
    poSrcDS->GetGeoTransform( adfGeoTransform );
    poDstDS->SetGeoTransform( adfGeoTransform );

    // --------------------------------------------------------------------
    // Copy information to the raster band
    // --------------------------------------------------------------------

    GDALRasterBand *poSrcBand;
    GDALRasterBand *poDstBand;
    double dfMin;
    double dfMax;
    double dfMean;
    double dfStdDev = -1;

    for( int i = 1; i <= poDstDS->nBands; i++)
    {
        delete poDstDS->GetRasterBand(i);
    }
    poDstDS->nBands = 0;

    if( poDstDS->hHeaderOne.DataTypeCode == Uncompressed24bit )
    {
        poDstDS->SetBand( 1, new IntergraphRGBBand( poDstDS, 1, 0, 3 ) );
        poDstDS->SetBand( 2, new IntergraphRGBBand( poDstDS, 2, 0, 2 ) );
        poDstDS->SetBand( 3, new IntergraphRGBBand( poDstDS, 3, 0, 1 ) );
        poDstDS->nBands = 3;
    }
    else
    {
        for( int i = 1; i <= poSrcDS->GetRasterCount(); i++ )
        {
            poSrcBand = poSrcDS->GetRasterBand(i);
            eType = poSrcDS->GetRasterBand(i)->GetRasterDataType();

            poDstBand = new IntergraphRasterBand( poDstDS, i, 0, eType );
            poDstDS->SetBand( i, poDstBand );

            poDstBand->SetCategoryNames( poSrcBand->GetCategoryNames() );
            poDstBand->SetColorTable( poSrcBand->GetColorTable() );
            poSrcBand->GetStatistics( false, true, &dfMin, &dfMax, &dfMean, &dfStdDev );
            poDstBand->SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
        }
    }

    // --------------------------------------------------------------------
    // Copy image data
    // --------------------------------------------------------------------

    int nXSize = poDstDS->GetRasterXSize();
    int nYSize = poDstDS->GetRasterYSize();

    int nBlockXSize;
    int nBlockYSize;

    CPLErr eErr = CE_None;

    for( int iBand = 1; iBand <= poSrcDS->GetRasterCount(); iBand++ )
    {
        GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand );
        GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand );

        // ------------------------------------------------------------
        // Copy Untiled / Uncompressed
        // ------------------------------------------------------------

        int   iYOffset, iXOffset;
        void *pData;

        poSrcBand->GetBlockSize( &nBlockXSize, &nBlockYSize );

        nBlockXSize = nXSize;
        nBlockYSize = 1;

        pData = CPLMalloc( nBlockXSize * nBlockYSize * GDALGetDataTypeSize( eType ) / 8 );

        for( iYOffset = 0; iYOffset < nYSize; iYOffset += nBlockYSize )
        {
            for( iXOffset = 0; iXOffset < nXSize; iXOffset += nBlockXSize )
            {
                eErr = poSrcBand->RasterIO( GF_Read,
                                            iXOffset, iYOffset,
                                            nBlockXSize, nBlockYSize,
                                            pData, nBlockXSize, nBlockYSize,
                                            eType, 0, 0, NULL );
                if( eErr != CE_None )
                {
                    return NULL;
                }
                eErr = poDstBand->RasterIO( GF_Write,
                                            iXOffset, iYOffset,
                                            nBlockXSize, nBlockYSize,
                                            pData, nBlockXSize, nBlockYSize,
                                            eType, 0, 0, NULL );
                if( eErr != CE_None )
                {
                    return NULL;
                }
            }
            if( ( eErr == CE_None ) && ( ! pfnProgress(
                                             ( iYOffset + 1 ) / ( double ) nYSize, NULL, pProgressData ) ) )
            {
                eErr = CE_Failure;
                CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated CreateCopy()" );
            }
        }
        CPLFree( pData );
    }

    // --------------------------------------------------------------------
    // Finalize
    // --------------------------------------------------------------------

    poDstDS->FlushCache();

    return poDstDS;
}
예제 #9
0
CPLErr GDALPamDataset::TryLoadAux()

{
/* -------------------------------------------------------------------- */
/*      Initialize PAM.                                                 */
/* -------------------------------------------------------------------- */
    PamInitialize();
    if( psPam == NULL )
        return CE_None;

/* -------------------------------------------------------------------- */
/*      What is the name of the physical file we are referencing?       */
/*      We allow an override via the psPam->pszPhysicalFile item.       */
/* -------------------------------------------------------------------- */
    const char *pszPhysicalFile = psPam->osPhysicalFilename;

    if( strlen(pszPhysicalFile) == 0 && GetDescription() != NULL )
        pszPhysicalFile = GetDescription();

    if( strlen(pszPhysicalFile) == 0 )
        return CE_None;

/* -------------------------------------------------------------------- */
/*      Try to open .aux file.                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *poAuxDS = GDALFindAssociatedAuxFile( pszPhysicalFile, 
                                                      GA_ReadOnly, this );

    if( poAuxDS == NULL )
        return CE_None;

/* -------------------------------------------------------------------- */
/*      Do we have an SRS on the aux file?                              */
/* -------------------------------------------------------------------- */
    if( strlen(poAuxDS->GetProjectionRef()) > 0 )
        GDALPamDataset::SetProjection( poAuxDS->GetProjectionRef() );

/* -------------------------------------------------------------------- */
/*      Geotransform.                                                   */
/* -------------------------------------------------------------------- */
    if( poAuxDS->GetGeoTransform( psPam->adfGeoTransform ) == CE_None )
        psPam->bHaveGeoTransform = TRUE;

/* -------------------------------------------------------------------- */
/*      GCPs                                                            */
/* -------------------------------------------------------------------- */
    if( poAuxDS->GetGCPCount() > 0 )
    {
        psPam->nGCPCount = poAuxDS->GetGCPCount();
        psPam->pasGCPList = GDALDuplicateGCPs( psPam->nGCPCount, 
                                               poAuxDS->GetGCPs() );
    }

/* -------------------------------------------------------------------- */
/*      Apply metadata. We likely ought to be merging this in rather    */
/*      than overwriting everything that was there.                     */
/* -------------------------------------------------------------------- */
    char **papszMD = poAuxDS->GetMetadata();
    if( CSLCount(papszMD) > 0 )
    {
        char **papszMerged = 
            CSLMerge( CSLDuplicate(GetMetadata()), papszMD );
        GDALPamDataset::SetMetadata( papszMerged );
        CSLDestroy( papszMerged );
    }

    papszMD = poAuxDS->GetMetadata("XFORMS");
    if( CSLCount(papszMD) > 0 )
    {
        char **papszMerged = 
            CSLMerge( CSLDuplicate(GetMetadata("XFORMS")), papszMD );
        GDALPamDataset::SetMetadata( papszMerged, "XFORMS" );
        CSLDestroy( papszMerged );
    }

/* ==================================================================== */
/*      Process bands.                                                  */
/* ==================================================================== */
    int iBand;

    for( iBand = 0; iBand < poAuxDS->GetRasterCount(); iBand++ )
    {
        if( iBand >= GetRasterCount() )
            break;

        GDALRasterBand *poAuxBand = poAuxDS->GetRasterBand( iBand+1 );
        GDALRasterBand *poBand = GetRasterBand( iBand+1 );

        papszMD = poAuxBand->GetMetadata();
        if( CSLCount(papszMD) > 0 )
        {
            char **papszMerged = 
                CSLMerge( CSLDuplicate(poBand->GetMetadata()), papszMD );
            poBand->SetMetadata( papszMerged );
            CSLDestroy( papszMerged );
        }

        if( poAuxBand->GetCategoryNames() != NULL )
            poBand->SetCategoryNames( poAuxBand->GetCategoryNames() );

        if( poAuxBand->GetColorTable() != NULL 
            && poBand->GetColorTable() == NULL )
            poBand->SetColorTable( poAuxBand->GetColorTable() );

        // histograms?
        double dfMin, dfMax;
        int nBuckets, *panHistogram=NULL;

        if( poAuxBand->GetDefaultHistogram( &dfMin, &dfMax, 
                                            &nBuckets, &panHistogram,
                                            FALSE, NULL, NULL ) == CE_None )
        {
            poBand->SetDefaultHistogram( dfMin, dfMax, nBuckets, 
                                         panHistogram );
            CPLFree( panHistogram );
        }

        // RAT 
        if( poAuxBand->GetDefaultRAT() != NULL )
            poBand->SetDefaultRAT( poAuxBand->GetDefaultRAT() );

        // NoData
        int bSuccess = FALSE;
        double dfNoDataValue = poAuxBand->GetNoDataValue( &bSuccess );
        if( bSuccess )
            poBand->SetNoDataValue( dfNoDataValue );
    }

    GDALClose( poAuxDS );
    
/* -------------------------------------------------------------------- */
/*      Mark PAM info as clean.                                         */
/* -------------------------------------------------------------------- */
    nPamFlags &= ~GPF_DIRTY;

    return CE_Failure;
}
예제 #10
0
CMapRaster::CMapRaster(const QString& fn, CCanvas * parent)
: IMap(eRaster, "",parent)
, x(0)
, y(0)
, zoomlevel(1)
, zoomfactor(1.0)
, rasterBandCount(0)
{
    filename = fn;
#ifdef WIN32
    dataset = (GDALDataset*)GDALOpen(filename.toLocal8Bit(),GA_ReadOnly);
#else
    dataset = (GDALDataset*)GDALOpen(filename.toUtf8(),GA_ReadOnly);
#endif
    if(dataset == 0)
    {
        QMessageBox::warning(0, tr("Error..."), tr("Failed to load file: %1").arg(filename));
        return;
    }

    rasterBandCount = dataset->GetRasterCount();
    if(rasterBandCount == 1)
    {
        GDALRasterBand * pBand;
        pBand = dataset->GetRasterBand(1);
        if(pBand == 0)
        {
            delete dataset; dataset = 0;
            QMessageBox::warning(0, tr("Error..."), tr("Failed to load file: %1").arg(filename));
            return;
        }

        if(pBand->GetColorInterpretation() !=  GCI_PaletteIndex && pBand->GetColorInterpretation() !=  GCI_GrayIndex)
        {
            delete dataset; dataset = 0;
            QMessageBox::warning(0, tr("Error..."), tr("File must be 8 bit palette or gray indexed."));
            return;
        }

        if(pBand->GetColorInterpretation() ==  GCI_PaletteIndex )
        {
            GDALColorTable * pct = pBand->GetColorTable();
            for(int i=0; i < pct->GetColorEntryCount(); ++i)
            {
                const GDALColorEntry& e = *pct->GetColorEntry(i);
                colortable << qRgba(e.c1, e.c2, e.c3, e.c4);
            }
        }
        else if(pBand->GetColorInterpretation() ==  GCI_GrayIndex )
        {
            for(int i=0; i < 256; ++i)
            {
                colortable << qRgba(i, i, i, 255);
            }
        }
        else
        {
            delete dataset; dataset = 0;
            QMessageBox::warning(0, tr("Error..."), tr("File must be 8 bit palette or gray indexed."));
            return;
        }

        int success = 0;
        double idx = pBand->GetNoDataValue(&success);

        if(success)
        {
            QColor tmp(colortable[idx]);
            tmp.setAlpha(0);
            colortable[idx] = tmp.rgba();
        }
    }
    maparea.setWidth(dataset->GetRasterXSize());
    maparea.setHeight(dataset->GetRasterYSize());

}
예제 #11
0
GDALDataset *GSBGDataset::CreateCopy( const char *pszFilename,
				      GDALDataset *poSrcDS,
				      int bStrict, char **papszOptions,
				      GDALProgressFunc pfnProgress,
				      void *pProgressData )
{
    if( pfnProgress == NULL )
	pfnProgress = GDALDummyProgress;

    int nBands = poSrcDS->GetRasterCount();
    if (nBands == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "GSBG driver does not support source dataset with zero band.\n");
        return NULL;
    }
    else if (nBands > 1)
    {
	if( bStrict )
	{
	    CPLError( CE_Failure, CPLE_NotSupported,
		      "Unable to create copy, Golden Software Binary Grid "
		      "format only supports one raster band.\n" );
	    return NULL;
	}
	else
	    CPLError( CE_Warning, CPLE_NotSupported,
		      "Golden Software Binary Grid format only supports one "
		      "raster band, first band will be copied.\n" );
    }

    GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( 1 );
    if( poSrcBand->GetXSize() > SHRT_MAX
	|| poSrcBand->GetYSize() > SHRT_MAX )
    {
	CPLError( CE_Failure, CPLE_IllegalArg,
		  "Unable to create grid, Golden Software Binary Grid format "
		  "only supports sizes up to %dx%d.  %dx%d not supported.\n",
		  SHRT_MAX, SHRT_MAX,
		  poSrcBand->GetXSize(), poSrcBand->GetYSize() );

	return NULL;
    }

    if( !pfnProgress( 0.0, NULL, pProgressData ) )
    {
        CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated\n" );
        return NULL;
    }

    VSILFILE    *fp = VSIFOpenL( pszFilename, "w+b" );

    if( fp == NULL )
    {
        CPLError( CE_Failure, CPLE_OpenFailed,
                  "Attempt to create file '%s' failed.\n",
                  pszFilename );
        return NULL;
    }

    GInt16  nXSize = poSrcBand->GetXSize();
    GInt16  nYSize = poSrcBand->GetYSize();
    double  adfGeoTransform[6];

    poSrcDS->GetGeoTransform( adfGeoTransform );

    double dfMinX = adfGeoTransform[0] + adfGeoTransform[1] / 2;
    double dfMaxX = adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0];
    double dfMinY = adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3];
    double dfMaxY = adfGeoTransform[3] + adfGeoTransform[5] / 2;
    CPLErr eErr = WriteHeader( fp, nXSize, nYSize,
			       dfMinX, dfMaxX, dfMinY, dfMaxY, 0.0, 0.0 );

    if( eErr != CE_None )
    {
	VSIFCloseL( fp );
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Copy band data.							*/
/* -------------------------------------------------------------------- */
    float *pfData = (float *)VSIMalloc2( nXSize, sizeof( float ) );
    if( pfData == NULL )
    {
	VSIFCloseL( fp );
	CPLError( CE_Failure, CPLE_OutOfMemory,
		  "Unable to create copy, unable to allocate line buffer.\n" );
	return NULL;
    }

    int     bSrcHasNDValue;
    float   fSrcNoDataValue = poSrcBand->GetNoDataValue( &bSrcHasNDValue );
    double  dfMinZ = DBL_MAX;
    double  dfMaxZ = -DBL_MAX;
    for( GInt16 iRow = nYSize - 1; iRow >= 0; iRow-- )
    {
	eErr = poSrcBand->RasterIO( GF_Read, 0, iRow,
				    nXSize, 1, pfData,
				    nXSize, 1, GDT_Float32, 0, 0 );

	if( eErr != CE_None )
	{
	    VSIFCloseL( fp );
	    VSIFree( pfData );
	    return NULL;
	}

	for( int iCol=0; iCol<nXSize; iCol++ )
	{
	    if( bSrcHasNDValue && pfData[iCol] == fSrcNoDataValue )
	    {
		pfData[iCol] = fNODATA_VALUE;
	    }
	    else
	    {
		if( pfData[iCol] > dfMaxZ )
		    dfMaxZ = pfData[iCol];

		if( pfData[iCol] < dfMinZ )
		    dfMinZ = pfData[iCol];
	    }

	    CPL_LSBPTR32( pfData+iCol );
	}

	if( VSIFWriteL( (void *)pfData, 4, nXSize,
			fp ) != static_cast<unsigned>(nXSize) )
	{
	    VSIFCloseL( fp );
	    VSIFree( pfData );
	    CPLError( CE_Failure, CPLE_FileIO,
		      "Unable to write grid row. Disk full?\n" );
	    return NULL;
	}

	if( !pfnProgress( static_cast<double>(iRow)/nYSize,
			  NULL, pProgressData ) )
	{
	    VSIFCloseL( fp );
	    VSIFree( pfData );
	    CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
	    return NULL;
	}
    }

    VSIFree( pfData );

    /* write out the min and max values */
    eErr = WriteHeader( fp, nXSize, nYSize,
			dfMinX, dfMaxX, dfMinY, dfMaxY, dfMinZ, dfMaxZ );

    if( eErr != CE_None )
    {
	VSIFCloseL( fp );
        return NULL;
    }

    VSIFCloseL( fp );

    GDALPamDataset *poDstDS = (GDALPamDataset *)GDALOpen( pszFilename,
							  GA_Update );
    if( poDstDS == NULL )
    {
	VSIUnlink( pszFilename );
	CPLError( CE_Failure, CPLE_FileIO,
		  "Unable to open copy of dataset.\n" );
	return NULL;
    }
    else if( dynamic_cast<GSBGDataset *>(poDstDS) == NULL )
    {
	VSIUnlink( pszFilename );
	delete poDstDS;
	CPLError( CE_Failure, CPLE_FileIO,
		  "Copy dataset not opened as Golden Surfer Binary Grid!?\n" );
	return NULL;
    }

    GDALRasterBand *poDstBand = poSrcDS->GetRasterBand(1);
    if( poDstBand == NULL )
    {
	VSIUnlink( pszFilename );
	delete poDstDS;
	CPLError( CE_Failure, CPLE_FileIO,
		  "Unable to open copy of raster band?\n" );
	return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Attempt to copy metadata.					*/
/* -------------------------------------------------------------------- */
    if( !bStrict )
	CPLPushErrorHandler( CPLQuietErrorHandler );

    /* non-zero transform 2 or 4 or negative 1 or 5  not supported natively */
    /*if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0
	|| adfGeoTransform[1] < 0.0 || adfGeoTransform[5] < 0.0 )
	poDstDS->GDALPamDataset::SetGeoTransform( adfGeoTransform );*/

    const char *szProjectionRef = poSrcDS->GetProjectionRef();
    if( *szProjectionRef != '\0' )
	poDstDS->SetProjection( szProjectionRef );

    char **pszMetadata = poSrcDS->GetMetadata();
    if( pszMetadata != NULL )
	poDstDS->SetMetadata( pszMetadata );

    /* FIXME:  Should the dataset description be copied as well, or is it
     *         always the file name? */
    poDstBand->SetDescription( poSrcBand->GetDescription() );

    int bSuccess;
    double dfOffset = poSrcBand->GetOffset( &bSuccess );
    if( bSuccess && dfOffset != 0.0 )
	poDstBand->SetOffset( dfOffset );

    double dfScale = poSrcBand->GetScale( &bSuccess );
    if( bSuccess && dfScale != 1.0 )
	poDstBand->SetScale( dfScale );

    GDALColorInterp oColorInterp = poSrcBand->GetColorInterpretation();
    if( oColorInterp != GCI_Undefined )
        poDstBand->SetColorInterpretation( oColorInterp );

    char **pszCatNames = poSrcBand->GetCategoryNames();
    if( pszCatNames != NULL)
	poDstBand->SetCategoryNames( pszCatNames );

    GDALColorTable *poColorTable = poSrcBand->GetColorTable();
    if( poColorTable != NULL )
	poDstBand->SetColorTable( poColorTable );

    if( !bStrict )
	CPLPopErrorHandler();

    return poDstDS;
}
예제 #12
0
static GDALDataset *
XPMCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
               int bStrict, char ** papszOptions, 
               GDALProgressFunc pfnProgress, void * pProgressData )

{
    int  nBands = poSrcDS->GetRasterCount();
    int  nXSize = poSrcDS->GetRasterXSize();
    int  nYSize = poSrcDS->GetRasterYSize();
    GDALColorTable *poCT;

/* -------------------------------------------------------------------- */
/*      Some some rudimentary checks                                    */
/* -------------------------------------------------------------------- */
    if( nBands != 1 )
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "XPM driver only supports one band images.\n" );

        return NULL;
    }

    if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte 
        && bStrict )
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "XPM driver doesn't support data type %s. "
                  "Only eight bit bands supported.\n", 
                  GDALGetDataTypeName( 
                      poSrcDS->GetRasterBand(1)->GetRasterDataType()) );

        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      If there is no colortable on the source image, create a         */
/*      greyscale one with 64 levels of grey.                           */
/* -------------------------------------------------------------------- */
    GDALRasterBand	*poBand = poSrcDS->GetRasterBand(1);
    int                 i;
    GDALColorTable      oGreyTable;

    poCT = poBand->GetColorTable();
    if( poCT == NULL )
    {
        poCT = &oGreyTable;

        for( i = 0; i < 256; i++ )
        {
            GDALColorEntry sColor;

            sColor.c1 = (short) i;
            sColor.c2 = (short) i;
            sColor.c3 = (short) i;
            sColor.c4 = 255;

            poCT->SetColorEntry( i, &sColor );
        }
    }

/* -------------------------------------------------------------------- */
/*      Build list of active colors, and the mapping from pixels to     */
/*      our active colormap.                                            */
/* -------------------------------------------------------------------- */
    const char *pszColorCodes = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-+=[]|:;,.<>?/";

    int  anPixelMapping[256];
    GDALColorEntry asPixelColor[256];
    int  nActiveColors = MIN(poCT->GetColorEntryCount(),256);

    // Setup initial colortable and pixel value mapping. 
    memset( anPixelMapping+0, 0, sizeof(int) * 256 );
    for( i = 0; i < nActiveColors; i++ )
    {
        poCT->GetColorEntryAsRGB( i, asPixelColor + i );
        anPixelMapping[i] = i;
    }

/* ==================================================================== */
/*      Iterate merging colors until we are under our limit (about 85). */
/* ==================================================================== */
    while( nActiveColors > (int) strlen(pszColorCodes) )
    {
        int nClosestDistance = 768;
        int iClose1 = -1, iClose2 = -1;
        int iColor1, iColor2;

        // Find the closest pair of colors. 
        for( iColor1 = 0; iColor1 < nActiveColors; iColor1++ )
        {
            for( iColor2 = iColor1+1; iColor2 < nActiveColors; iColor2++ )
            {
                int	nDistance;

                if( asPixelColor[iColor1].c4 < 128 
                    && asPixelColor[iColor2].c4 < 128 )
                    nDistance = 0;
                else
                    nDistance = 
                        ABS(asPixelColor[iColor1].c1-asPixelColor[iColor2].c1)
                      + ABS(asPixelColor[iColor1].c2-asPixelColor[iColor2].c2)
                      + ABS(asPixelColor[iColor1].c3-asPixelColor[iColor2].c3);

                if( nDistance < nClosestDistance )
                {
                    nClosestDistance = nDistance;
                    iClose1 = iColor1;
                    iClose2 = iColor2;
                }
            }

            if( nClosestDistance < 8 )
                break;
        }

        // This should never happen!
        if( iClose1 == -1 )
            break;

        // Merge two selected colors - shift icolor2 into icolor1 and
        // move the last active color into icolor2's slot. 
        for( i = 0; i < 256; i++ )
        {
            if( anPixelMapping[i] == iClose2 )
                anPixelMapping[i] = iClose1;
            else if( anPixelMapping[i] == nActiveColors-1 )
                anPixelMapping[i] = iClose2;
        }

        asPixelColor[iClose2] = asPixelColor[nActiveColors-1];
        nActiveColors--;
    }
        
/* ==================================================================== */
/*      Write the output image.                                         */
/* ==================================================================== */
    FILE	*fpPBM;

    fpPBM = VSIFOpen( pszFilename, "wt+" );
    if( fpPBM == NULL )
    {
        CPLError( CE_Failure, CPLE_OpenFailed, 
                  "Unable to create file `%s'.", 
                  pszFilename );

        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Write the header lines.                                         */
/* -------------------------------------------------------------------- */
    fprintf( fpPBM, "/* XPM */\n" );
    fprintf( fpPBM, "static char *%s[] = {\n", 
             CPLGetBasename( pszFilename ) );
    fprintf( fpPBM, "/* width height num_colors chars_per_pixel */\n" );
    fprintf( fpPBM, "\"  %3d   %3d     %3d             1\",\n",
             nXSize, nYSize, nActiveColors );
    fprintf( fpPBM, "/* colors */\n" );

/* -------------------------------------------------------------------- */
/*      Write the color table.                                          */
/* -------------------------------------------------------------------- */
    for( i = 0; i < nActiveColors; i++ )
    {
        if( asPixelColor[i].c4 < 128 )
            fprintf( fpPBM, "\"%c c None\",\n", pszColorCodes[i] );
        else
            fprintf( fpPBM, 
                     "\"%c c #%02x%02x%02x\",\n",
                     pszColorCodes[i],
                     asPixelColor[i].c1, 
                     asPixelColor[i].c2, 
                     asPixelColor[i].c3 );
    }

/* -------------------------------------------------------------------- */
/*	Dump image.							*/
/* -------------------------------------------------------------------- */
    int iLine;
    GByte 	*pabyScanline;

    pabyScanline = (GByte *) CPLMalloc( nXSize );
    for( iLine = 0; iLine < nYSize; iLine++ )
    {
        poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                          (void *) pabyScanline, nXSize, 1, GDT_Byte, 0, 0 );
        
        fputc( '"', fpPBM );
        for( int iPixel = 0; iPixel < nXSize; iPixel++ )
            fputc( pszColorCodes[anPixelMapping[pabyScanline[iPixel]]], 
                   fpPBM);
        fprintf( fpPBM, "\",\n" );
    }
    
    CPLFree( pabyScanline );

/* -------------------------------------------------------------------- */
/*      cleanup                                                         */
/* -------------------------------------------------------------------- */
    fprintf( fpPBM, "};\n" );
    VSIFClose( fpPBM );

/* -------------------------------------------------------------------- */
/*      Re-open dataset, and copy any auxilary pam information.         */
/* -------------------------------------------------------------------- */
    GDALPamDataset *poDS = (GDALPamDataset *) 
        GDALOpen( pszFilename, GA_ReadOnly );

    if( poDS )
        poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );

    return poDS;
}
예제 #13
0
CPLErr
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList,
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling,
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    if( !GTiffOneTimeInit() )
        return CE_Failure;

    TIFF *hOTIFF = nullptr;
    int nBitsPerPixel = 0;
    int nCompression = COMPRESSION_NONE;
    int nPhotometric = 0;
    int nSampleFormat = 0;
    int nPlanarConfig = 0;
    int iOverview = 0;
    int nXSize = 0;
    int nYSize = 0;

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( int iBand = 0; iBand < nBands; iBand++ )
    {
        int nBandBits = 0;
        int nBandFormat = 0;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CInt32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( false );
            return CE_Failure;
        }

        if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) )
        {
            nBandBits =
                atoi(hBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE"));

            if( nBandBits == 1
                && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") )
                nBandBits = 8;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != nullptr )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", nullptr );

    if( pszCompress != nullptr && pszCompress[0] != '\0' )
    {
        nCompression =
            GTIFFGetCompressionMethod(pszCompress, "COMPRESS_OVERVIEW");
        if( nCompression < 0 )
            return CE_Failure;
    }

    if( nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8 )
    {
        if( nBitsPerPixel > 16 )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " JPEG compressed overviews of nBitsPerPixel > 16." );
            return CE_Failure;
        }

        nBitsPerPixel = 12;
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    bool bSourceIsPixelInterleaved = false;
    bool bSourceIsJPEG2000 = false;
    if( nBands > 1 )
    {
        GDALDataset* poSrcDS = papoBandList[0]->GetDataset();
        if( poSrcDS )
        {
            const char* pszSrcInterleave = poSrcDS->GetMetadataItem("INTERLEAVE",
                                                                "IMAGE_STRUCTURE");
            if( pszSrcInterleave && EQUAL(pszSrcInterleave, "PIXEL") )
            {
                bSourceIsPixelInterleaved = true;
            }
        }

        const char* pszSrcCompression = papoBandList[0]->GetMetadataItem("COMPRESSION",
                                                                "IMAGE_STRUCTURE");
        if( pszSrcCompression )
        {
            bSourceIsJPEG2000 = EQUAL(pszSrcCompression, "JPEG2000");
        }
        if( bSourceIsPixelInterleaved && bSourceIsJPEG2000 )
        {
            nPlanarConfig = PLANARCONFIG_CONTIG;
        }
    }

    const char* pszInterleave =
        CPLGetConfigOption( "INTERLEAVE_OVERVIEW", nullptr );
    if( pszInterleave != nullptr && pszInterleave[0] != '\0' )
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError(
                CE_Failure, CPLE_AppDefined,
                "INTERLEAVE_OVERVIEW=%s unsupported, "
                "value must be PIXEL or BAND. ignoring",
                pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != nullptr
             && !STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        // Should set the colormap up at this point too!
    }
    else if( nBands >= 3 &&
             papoBandList[0]->GetColorInterpretation() == GCI_RedBand &&
             papoBandList[1]->GetColorInterpretation() == GCI_GreenBand &&
             papoBandList[2]->GetColorInterpretation() == GCI_BlueBand )
    {
        nPhotometric = PHOTOMETRIC_RGB;
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric =
        CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", nullptr );
    if( pszPhotometric != nullptr && pszPhotometric[0] != '\0' )
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;

            // Because of subsampling, setting YCBCR without JPEG compression
            // leads to a crash currently. Would need to make
            // GTiffRasterBand::IWriteBlock() aware of subsampling so that it
            // doesn't overrun buffer size returned by libtiff.
            if( nCompression != COMPRESSION_JPEG )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires "
                    "COMPRESS_OVERVIEW=JPEG" );
                return CE_Failure;
            }

            if( pszInterleave != nullptr &&
                pszInterleave[0] != '\0' &&
                nPlanarConfig == PLANARCONFIG_SEPARATE )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "PHOTOMETRIC_OVERVIEW=YCBCR requires "
                    "INTERLEAVE_OVERVIEW=PIXEL" );
                return CE_Failure;
            }
            else
            {
                nPlanarConfig = PLANARCONFIG_CONTIG;
            }

            // YCBCR strictly requires 3 bands. Not less, not more
            // Issue an explicit error message as libtiff one is a bit cryptic:
            // JPEGLib:Bogus input colorspace.
            if( nBands != 3 )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster "
                    "with only 3 bands (RGB)" );
                return CE_Failure;
            }
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError(
                CE_Warning, CPLE_IllegalArg,
                "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.",
                pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the predictor value to use.                          */
/* -------------------------------------------------------------------- */
    int nPredictor = PREDICTOR_NONE;
    if( nCompression == COMPRESSION_LZW ||
        nCompression == COMPRESSION_ADOBE_DEFLATE )
    {
        const char* pszPredictor =
            CPLGetConfigOption( "PREDICTOR_OVERVIEW", nullptr );
        if( pszPredictor != nullptr )
        {
            nPredictor = atoi( pszPredictor );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBufL sStatBuf;
    VSILFILE* fpL = nullptr;

    if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
    {
    /* -------------------------------------------------------------------- */
    /*      Compute the uncompressed size.                                  */
    /* -------------------------------------------------------------------- */
        double dfUncompressedOverviewSize = 0;
        int nDataTypeSize =
            GDALGetDataTypeSizeBytes(papoBandList[0]->GetRasterDataType());

        for( iOverview = 0; iOverview < nOverviews; iOverview++ )
        {
            const int nOXSize = (nXSize + panOverviewList[iOverview] - 1)
                / panOverviewList[iOverview];
            const int nOYSize = (nYSize + panOverviewList[iOverview] - 1)
                / panOverviewList[iOverview];

            dfUncompressedOverviewSize +=
                nOXSize * static_cast<double>(nOYSize) * nBands * nDataTypeSize;
        }

        if( nCompression == COMPRESSION_NONE
            && dfUncompressedOverviewSize > 4200000000.0 )
        {
    #ifndef BIGTIFF_SUPPORT
            CPLError(
                CE_Failure, CPLE_NotSupported,
                "The overview file would be larger than 4GB, "
                "but this is the largest size a TIFF can be, "
                "and BigTIFF is unavailable.  "
                "Creation failed." );
            return CE_Failure;
    #endif
        }
    /* -------------------------------------------------------------------- */
    /*      Should the file be created as a bigtiff file?                   */
    /* -------------------------------------------------------------------- */
        const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", nullptr );

        if( pszBIGTIFF == nullptr )
            pszBIGTIFF = "IF_SAFER";

        bool bCreateBigTIFF = false;
        if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
        {
            if( nCompression == COMPRESSION_NONE
                && dfUncompressedOverviewSize > 4200000000.0 )
                bCreateBigTIFF = true;
        }
        else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
        {
            // Look at the size of the base image and suppose that
            // the added overview levels won't be more than 1/2 of
            // the size of the base image. The theory says 1/3 of the
            // base image size if the overview levels are 2, 4, 8, 16.
            // Thus take 1/2 as the security margin for 1/3.
            const double dfUncompressedImageSize =
                nXSize * static_cast<double>(nYSize) * nBands * nDataTypeSize;
            if( dfUncompressedImageSize * 0.5 > 4200000000.0 )
                bCreateBigTIFF = true;
        }
        else
        {
            bCreateBigTIFF = CPLTestBool( pszBIGTIFF );
            if( !bCreateBigTIFF && nCompression == COMPRESSION_NONE
                && dfUncompressedOverviewSize > 4200000000.0 )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "The overview file will be larger than 4GB, "
                    "so BigTIFF is necessary.  "
                    "Creation failed.");
                return CE_Failure;
            }
        }

    #ifndef BIGTIFF_SUPPORT
        if( bCreateBigTIFF )
        {
            CPLError(
                CE_Warning, CPLE_NotSupported,
                "BigTIFF requested, but GDAL built without BigTIFF "
                "enabled libtiff, request ignored." );
            bCreateBigTIFF = false;
        }
    #endif

        if( bCreateBigTIFF )
            CPLDebug( "GTiff", "File being created as a BigTIFF." );

        fpL = VSIFOpenL( pszFilename, "w+" );
        if( fpL == nullptr )
            hOTIFF = nullptr;
        else
            hOTIFF =
               VSI_TIFFOpen( pszFilename, bCreateBigTIFF ? "w+8" : "w+", fpL );
        if( hOTIFF == nullptr )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s' "
                          "failed in VSI_TIFFOpen().",
                          pszFilename );
            if( fpL != nullptr )
                CPL_IGNORE_RET_VAL(VSIFCloseL(fpL));
            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else
    {
        fpL = VSIFOpenL( pszFilename, "r+" );
        if( fpL == nullptr )
            hOTIFF = nullptr;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL );
        if( hOTIFF == nullptr )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s' "
                          "failed in VSI_TIFFOpen().",
                          pszFilename );
            if( fpL != nullptr )
                CPL_IGNORE_RET_VAL(VSIFCloseL(fpL));
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short *panRed = nullptr;
    unsigned short *panGreen = nullptr;
    unsigned short *panBlue = nullptr;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount = 65536;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;

        panRed = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );
        panGreen = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );
        panBlue = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
          GDALColorEntry sRGB = { 0, 0, 0, 0 };

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                // TODO(schwehr): Check for underflow.
                // Going from signed short to unsigned short.
                panRed[iColor] = static_cast<unsigned short>(257 * sRGB.c1);
                panGreen[iColor] = static_cast<unsigned short>(257 * sRGB.c2);
                panBlue[iColor] = static_cast<unsigned short>(257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    int nOvrBlockXSize = 0;
    int nOvrBlockYSize = 0;
    GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);

    CPLString osNoData; // don't move this in inner scope
    const char* pszNoData = nullptr;
    int bNoDataSet = FALSE;
    const double dfNoDataValue = papoBandList[0]->GetNoDataValue(&bNoDataSet);
    if( bNoDataSet )
    {
        osNoData = GTiffFormatGDALNoDataTagValue(dfNoDataValue);
        pszNoData = osNoData.c_str();
    }

    std::vector<uint16> anExtraSamples;
    for( int i = GTIFFGetMaxColorChannels(nPhotometric)+1; i <= nBands; i++ )
    {
        if( papoBandList[i-1]->GetColorInterpretation() == GCI_AlphaBand )
        {
            anExtraSamples.push_back(
                GTiffGetAlphaValue(CPLGetConfigOption("GTIFF_ALPHA", nullptr),
                                   DEFAULT_ALPHA_TYPE));
        }
        else
        {
            anExtraSamples.push_back(EXTRASAMPLE_UNSPECIFIED);
        }
    }

    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        const int nOXSize = (nXSize + panOverviewList[iOverview] - 1)
            / panOverviewList[iOverview];
        const int nOYSize = (nYSize + panOverviewList[iOverview] - 1)
            / panOverviewList[iOverview];

        GTIFFWriteDirectory( hOTIFF, FILETYPE_REDUCEDIMAGE,
                             nOXSize, nOYSize, nBitsPerPixel,
                             nPlanarConfig, nBands,
                             nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression,
                             nPhotometric, nSampleFormat, nPredictor,
                             panRed, panGreen, panBlue,
                             static_cast<int>(anExtraSamples.size()),
                             anExtraSamples.empty() ? nullptr : anExtraSamples.data(),
                             osMetadata,
                             CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", nullptr ),
                             CPLGetConfigOption( "JPEG_TABLESMODE_OVERVIEW", nullptr ),
                             pszNoData,
                             nullptr
                           );
    }

    if( panRed )
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = nullptr;
        panGreen = nullptr;
        panBlue = nullptr;
    }

    XTIFFClose( hOTIFF );
    if( VSIFCloseL(fpL) != 0 )
        return CE_Failure;
    fpL = nullptr;

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS = GDALDataset::Open( pszFilename,
                                           GDAL_OF_RASTER | GDAL_OF_UPDATE );
    if( hODS == nullptr )
        return CE_Failure;

/* -------------------------------------------------------------------- */
/*      Do we need to set the jpeg quality?                             */
/* -------------------------------------------------------------------- */
    TIFF *hTIFF = static_cast<TIFF *>( hODS->GetInternalHandle(nullptr) );

    if( nCompression == COMPRESSION_JPEG
        && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", nullptr ) != nullptr )
    {
        const int nJpegQuality =
            atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75"));
        TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY,
                      nJpegQuality );
        GTIFFSetJpegQuality(GDALDataset::ToHandle(hODS), nJpegQuality);
    }

    if( nCompression == COMPRESSION_JPEG
        && CPLGetConfigOption( "JPEG_TABLESMODE_OVERVIEW", nullptr ) != nullptr )
    {
        const int nJpegTablesMode =
            atoi(CPLGetConfigOption("JPEG_TABLESMODE_OVERVIEW",
                            CPLSPrintf("%d", knGTIFFJpegTablesModeDefault)));
        TIFFSetField( hTIFF, TIFFTAG_JPEGTABLESMODE,
                      nJpegTablesMode );
        GTIFFSetJpegTablesMode(GDALDataset::ToHandle(hODS), nJpegTablesMode);
    }

/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    int *panOverviewListSorted =
        static_cast<int*>(CPLMalloc(sizeof(int) * nOverviews));
    memcpy( panOverviewListSorted, panOverviewList, sizeof(int) * nOverviews);
    std::sort(panOverviewListSorted, panOverviewListSorted + nOverviews);

    GTIFFSetInExternalOvr(true);

    CPLErr eErr = CE_None;

    if(  ((bSourceIsPixelInterleaved && bSourceIsJPEG2000) ||
          (nCompression != COMPRESSION_NONE)) &&
         nPlanarConfig == PLANARCONFIG_CONTIG &&
         !GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) &&
         papoBandList[0]->GetColorTable() == nullptr &&
         (STARTS_WITH_CI(pszResampling, "NEAR") ||
          EQUAL(pszResampling, "AVERAGE") ||
          EQUAL(pszResampling, "GAUSS") ||
          EQUAL(pszResampling, "CUBIC") ||
          EQUAL(pszResampling, "CUBICSPLINE") ||
          EQUAL(pszResampling, "LANCZOS") ||
          EQUAL(pszResampling, "BILINEAR")) )
    {
        // In the case of pixel interleaved compressed overviews, we want to
        // generate the overviews for all the bands block by block, and not
        // band after band, in order to write the block once and not loose
        // space in the TIFF file.
        GDALRasterBand ***papapoOverviewBands =
            static_cast<GDALRasterBand ***>(
                CPLCalloc(sizeof(void *), nBands) );
        for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand *poSrcBand = papoBandList[iBand];
            GDALRasterBand *poDstBand = hODS->GetRasterBand( iBand + 1 );
            papapoOverviewBands[iBand] =
                static_cast<GDALRasterBand **>(
                    CPLCalloc(sizeof(void *), nOverviews) );

            int bHasNoData = FALSE;
            const double noDataValue = poSrcBand->GetNoDataValue(&bHasNoData);
            if( bHasNoData )
                poDstBand->SetNoDataValue(noDataValue);

            for( int i = 0; i < nOverviews && eErr == CE_None; i++ )
            {
                for( int j = -1; j < poDstBand->GetOverviewCount() &&
                                 eErr == CE_None; j++ )
                {
                    GDALRasterBand * poOverview =
                            (j < 0 ) ? poDstBand : poDstBand->GetOverview( j );
                    if( poOverview == nullptr )
                    {
                        eErr = CE_Failure;
                        continue;
                    }

                    const int nOvFactor =
                        GDALComputeOvFactor(poOverview->GetXSize(),
                                            poSrcBand->GetXSize(),
                                            poOverview->GetYSize(),
                                            poSrcBand->GetYSize());

                    if( nOvFactor == panOverviewListSorted[i]
                        || nOvFactor == GDALOvLevelAdjust2(
                                            panOverviewListSorted[i],
                                            poSrcBand->GetXSize(),
                                            poSrcBand->GetYSize() ) )
                    {
                        papapoOverviewBands[iBand][i] = poOverview;
                        if( bHasNoData )
                            poOverview->SetNoDataValue(noDataValue);
                        break;
                    }
                }
                CPLAssert( papapoOverviewBands[iBand][i] != nullptr );
            }
        }

        if( eErr == CE_None )
            eErr =
                GDALRegenerateOverviewsMultiBand(
                    nBands, papoBandList,
                    nOverviews, papapoOverviewBands,
                    pszResampling, pfnProgress, pProgressData );

        for( int iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand **papoOverviews =
            static_cast<GDALRasterBand **>(
                CPLCalloc( sizeof(void*), knMaxOverviews ) );

        for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand *hSrcBand = papoBandList[iBand];
            GDALRasterBand *hDstBand = hODS->GetRasterBand( iBand + 1 );

            int bHasNoData = FALSE;
            const double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if( bHasNoData )
                hDstBand->SetNoDataValue(noDataValue);

            // FIXME: this logic regenerates all overview bands, not only the
            // ones requested.

            papoOverviews[0] = hDstBand;
            int nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < knMaxOverviews );
            nDstOverviews = std::min(knMaxOverviews, nDstOverviews);

            // TODO(schwehr): Convert to starting with i = 1 and remove +1.
            for( int i = 0; i < nDstOverviews - 1 && eErr == CE_None; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
                if( papoOverviews[i+1] == nullptr )
                {
                    eErr = CE_Failure;
                }
                else
                {
                    if( bHasNoData )
                        papoOverviews[i+1]->SetNoDataValue(noDataValue);
                }
            }

            void *pScaledProgressData =
                GDALCreateScaledProgress(
                    iBand / static_cast<double>( nBands ),
                    (iBand + 1) / static_cast<double>( nBands ),
                    pfnProgress, pProgressData );

            if( eErr == CE_None )
                eErr =
                    GDALRegenerateOverviews(
                        hSrcBand,
                        nDstOverviews,
                        reinterpret_cast<GDALRasterBandH *>( papoOverviews ),
                        pszResampling,
                        GDALScaledProgress,
                        pScaledProgressData );

            GDALDestroyScaledProgress( pScaledProgressData );
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    if( eErr == CE_None )
        hODS->FlushCache();
    delete hODS;

    GTIFFSetInExternalOvr(false);

    CPLFree(panOverviewListSorted);

    pfnProgress( 1.0, nullptr, pProgressData );

    return eErr;
}
예제 #14
0
bool vtImageGeo::ReadTIF(const char *filename, bool progress_callback(int))
{
	// Use GDAL to read a TIF file (or any other format that GDAL is
	//  configured to read) into this OSG image.
	bool bRet = true;
	vtString message;

	setFileName(filename);

	g_GDALWrapper.RequestGDALFormats();

	GDALDataset *pDataset = NULL;
	GDALRasterBand *pBand;
	GDALRasterBand *pRed = NULL;
	GDALRasterBand *pGreen = NULL;
	GDALRasterBand *pBlue = NULL;
	GDALRasterBand *pAlpha = NULL;
	GDALColorTable *pTable;
	uchar *pScanline = NULL;
	uchar *pRedline = NULL;
	uchar *pGreenline = NULL;
	uchar *pBlueline = NULL;
	uchar *pAlphaline = NULL;

	CPLErr Err;
	bool bColorPalette = false;
	int iXSize, iYSize;
	int nxBlocks, nyBlocks;
	int xBlockSize, yBlockSize;

	try
	{
		pDataset = (GDALDataset *) GDALOpen(filename, GA_ReadOnly);
		if(pDataset == NULL )
			throw "Couldn't open that file.";

		// Get size
		iXSize = pDataset->GetRasterXSize();
		iYSize = pDataset->GetRasterYSize();

		// Try getting CRS
		vtProjection temp;
		bool bHaveProj = false;
		const char *pProjectionString = pDataset->GetProjectionRef();
		if (pProjectionString)
		{
			OGRErr err = temp.importFromWkt((char**)&pProjectionString);
			if (err == OGRERR_NONE)
			{
				m_proj = temp;
				bHaveProj = true;
			}
		}
		if (!bHaveProj)
		{
			// check for existence of .prj file
			bool bSuccess = temp.ReadProjFile(filename);
			if (bSuccess)
			{
				m_proj = temp;
				bHaveProj = true;
			}
		}

		// Try getting extents
		double affineTransform[6];
		if (pDataset->GetGeoTransform(affineTransform) == CE_None)
		{
			m_extents.left = affineTransform[0];
			m_extents.right = m_extents.left + affineTransform[1] * iXSize;
			m_extents.top = affineTransform[3];
			m_extents.bottom = m_extents.top + affineTransform[5] * iYSize;
		}

		// Raster count should be 3 for colour images (assume RGB)
		int iRasterCount = pDataset->GetRasterCount();

		if (iRasterCount != 1 && iRasterCount != 3 && iRasterCount != 4)
		{
			message.Format("Image has %d bands (not 1, 3, or 4).", iRasterCount);
			throw (const char *)message;
		}

		if (iRasterCount == 1)
		{
			pBand = pDataset->GetRasterBand(1);

			// Check the band's data type
			GDALDataType dtype = pBand->GetRasterDataType();
			if (dtype != GDT_Byte)
			{
				message.Format("Band is of type %s, but we support type Byte.", GDALGetDataTypeName(dtype));
				throw (const char *)message;
			}
			GDALColorInterp ci = pBand->GetColorInterpretation();

			if (ci == GCI_PaletteIndex)
			{
				if (NULL == (pTable = pBand->GetColorTable()))
					throw "Couldn't get color table.";
				bColorPalette = true;
			}
			else if (ci == GCI_GrayIndex)
			{
				// we will assume 0-255 is black to white
			}
			else
				throw "Unsupported color interpretation.";

			pBand->GetBlockSize(&xBlockSize, &yBlockSize);
			nxBlocks = (iXSize + xBlockSize - 1) / xBlockSize;
			nyBlocks = (iYSize + yBlockSize - 1) / yBlockSize;
			if (NULL == (pScanline = new uchar[xBlockSize * yBlockSize]))
				throw "Couldnt allocate scan line.";
		}

		if (iRasterCount == 3)
		{
			for (int i = 1; i <= 3; i++)
			{
				pBand = pDataset->GetRasterBand(i);

				// Check the band's data type
				GDALDataType dtype = pBand->GetRasterDataType();
				if (dtype != GDT_Byte)
				{
					message.Format("Band is of type %s, but we support type Byte.", GDALGetDataTypeName(dtype));
					throw (const char *)message;
				}
				switch (pBand->GetColorInterpretation())
				{
				case GCI_RedBand:
					pRed = pBand;
					break;
				case GCI_GreenBand:
					pGreen = pBand;
					break;
				case GCI_BlueBand:
					pBlue = pBand;
					break;
				}
			}
			if ((NULL == pRed) || (NULL == pGreen) || (NULL == pBlue))
				throw "Couldn't find bands for Red, Green, Blue.";

			pRed->GetBlockSize(&xBlockSize, &yBlockSize);
			nxBlocks = (iXSize + xBlockSize - 1) / xBlockSize;
			nyBlocks = (iYSize + yBlockSize - 1) / yBlockSize;

			pRedline = new uchar[xBlockSize * yBlockSize];
			pGreenline = new uchar[xBlockSize * yBlockSize];
			pBlueline = new uchar[xBlockSize * yBlockSize];
		}

		if (iRasterCount == 4)
		{
#if VTDEBUG
			VTLOG1("Band interpretations:");
#endif
			for (int i = 1; i <= 4; i++)
			{
				pBand = pDataset->GetRasterBand(i);

				// Check the band's data type
				GDALDataType dtype = pBand->GetRasterDataType();
				if (dtype != GDT_Byte)
				{
					message.Format("Band is of type %s, but we support type Byte.", GDALGetDataTypeName(dtype));
					throw (const char *)message;
				}
				GDALColorInterp ci = pBand->GetColorInterpretation();
#if VTDEBUG
				VTLOG(" %d", ci);
#endif
				switch (ci)
				{
				case GCI_RedBand:
					pRed = pBand;
					break;
				case GCI_GreenBand:
					pGreen = pBand;
					break;
				case GCI_BlueBand:
					pBlue = pBand;
					break;
				case GCI_AlphaBand:
					pAlpha = pBand;
					break;
				case GCI_Undefined:
					// If we have four bands: R,G,B,undefined, then assume that
					//  the undefined one is actually alpha
					if (pRed && pGreen && pBlue && !pAlpha)
						pAlpha = pBand;
					break;
				}
			}
#if VTDEBUG
			VTLOG1("\n");
#endif
			if ((NULL == pRed) || (NULL == pGreen) || (NULL == pBlue) || (NULL == pAlpha))
				throw "Couldn't find bands for Red, Green, Blue, Alpha.";

			pRed->GetBlockSize(&xBlockSize, &yBlockSize);
			nxBlocks = (iXSize + xBlockSize - 1) / xBlockSize;
			nyBlocks = (iYSize + yBlockSize - 1) / yBlockSize;

			pRedline = new uchar[xBlockSize * yBlockSize];
			pGreenline = new uchar[xBlockSize * yBlockSize];
			pBlueline = new uchar[xBlockSize * yBlockSize];
			pAlphaline = new uchar[xBlockSize * yBlockSize];
		}

		// Allocate the image buffer
		if (iRasterCount == 4)
		{
			Create(iXSize, iYSize, 32);
		}
		else if (iRasterCount == 3 || bColorPalette)
		{
			Create(iXSize, iYSize, 24);
		}
		else if (iRasterCount == 1)
			Create(iXSize, iYSize, 8);

		// Read the data
#if LOG_IMAGE_LOAD
		VTLOG("Reading the image data (%d x %d pixels)\n", iXSize, iYSize);
#endif

		int x, y;
		int ixBlock, iyBlock;
		int nxValid, nyValid;
		int iY, iX;
		RGBi rgb;
		RGBAi rgba;
		if (iRasterCount == 1)
		{
			GDALColorEntry Ent;
			for (iyBlock = 0; iyBlock < nyBlocks; iyBlock++)
			{
				if (progress_callback != NULL)
					progress_callback(iyBlock * 100 / nyBlocks);

				y = iyBlock * yBlockSize;
				for (ixBlock = 0; ixBlock < nxBlocks; ixBlock++)
				{
					x = ixBlock * xBlockSize;
					Err = pBand->ReadBlock(ixBlock, iyBlock, pScanline);
					if (Err != CE_None)
						throw "Problem reading the image data.";

					// Compute the portion of the block that is valid
					// for partial edge blocks.
					if ((ixBlock+1) * xBlockSize > iXSize)
						nxValid = iXSize - ixBlock * xBlockSize;
					else
						nxValid = xBlockSize;

					if( (iyBlock+1) * yBlockSize > iYSize)
						nyValid = iYSize - iyBlock * yBlockSize;
					else
						nyValid = yBlockSize;

					for( iY = 0; iY < nyValid; iY++ )
					{
						for( iX = 0; iX < nxValid; iX++ )
						{
							if (bColorPalette)
							{
								pTable->GetColorEntryAsRGB(pScanline[iY * xBlockSize + iX], &Ent);
								rgb.r = (uchar) Ent.c1;
								rgb.g = (uchar) Ent.c2;
								rgb.b = (uchar) Ent.c3;
								SetPixel24(x + iX, y + iY, rgb);
							}
							else
								SetPixel8(x + iX, y + iY, pScanline[iY * xBlockSize + iX]);
						}
					}
				}
			}
		}
		if (iRasterCount >= 3)
		{
			for (iyBlock = 0; iyBlock < nyBlocks; iyBlock++)
			{
				if (progress_callback != NULL)
					progress_callback(iyBlock * 100 / nyBlocks);

				y = iyBlock * yBlockSize;
				for (ixBlock = 0; ixBlock < nxBlocks; ixBlock++)
				{
					x = ixBlock * xBlockSize;
					Err = pRed->ReadBlock(ixBlock, iyBlock, pRedline);
					if (Err != CE_None)
						throw "Cannot read data.";
					Err = pGreen->ReadBlock(ixBlock, iyBlock, pGreenline);
					if (Err != CE_None)
						throw "Cannot read data.";
					Err = pBlue->ReadBlock(ixBlock, iyBlock, pBlueline);
					if (Err != CE_None)
						throw "Cannot read data.";
					if (iRasterCount == 4)
					{
						Err = pAlpha->ReadBlock(ixBlock, iyBlock, pAlphaline);
						if (Err != CE_None)
							throw "Cannot read data.";
					}

					// Compute the portion of the block that is valid
					// for partial edge blocks.
					if ((ixBlock+1) * xBlockSize > iXSize)
						nxValid = iXSize - ixBlock * xBlockSize;
					else
						nxValid = xBlockSize;

					if( (iyBlock+1) * yBlockSize > iYSize)
						nyValid = iYSize - iyBlock * yBlockSize;
					else
						nyValid = yBlockSize;

					for (int iY = 0; iY < nyValid; iY++)
					{
						for (int iX = 0; iX < nxValid; iX++)
						{
							if (iRasterCount == 3)
							{
								rgb.r = pRedline[iY * xBlockSize + iX];
								rgb.g = pGreenline[iY * xBlockSize + iX];
								rgb.b = pBlueline[iY * xBlockSize + iX];
								SetPixel24(x + iX, y + iY, rgb);
							}
							else if (iRasterCount == 4)
							{
								rgba.r = pRedline[iY * xBlockSize + iX];
								rgba.g = pGreenline[iY * xBlockSize + iX];
								rgba.b = pBlueline[iY * xBlockSize + iX];
								rgba.a = pAlphaline[iY * xBlockSize + iX];
								SetPixel32(x + iX, y + iY, rgba);
							}
						}
					}
				}
			}
		}
	}
	catch (const char *msg)
	{
		VTLOG1("Problem: ");
		VTLOG1(msg);
		VTLOG1("\n");
		bRet = false;
	}

	if (NULL != pDataset)
		GDALClose(pDataset);
	if (NULL != pScanline)
		delete pScanline;
	if (NULL != pRedline)
		delete pRedline;
	if (NULL != pGreenline)
		delete pGreenline;
	if (NULL != pBlueline)
		delete pBlueline;
	if (NULL != pAlphaline)
		delete pAlphaline;

	return bRet;
}
예제 #15
0
파일: io.cpp 프로젝트: jlehtoma/geodrill
int readRaster(const char* pszFilename)
{
    // Set config options for GDAL (needs >= 2.0). Setting GTIFF_VIRTUAL_MEM_IO to "YES" can cause things bleed to
    // swap if enough RAM is not available. Use "IF_ENOUGH_RAM" for safer performance if unsure. NOTE that faster
    // mem io only works with *uncompressed* GeoTIFFs.
    // New in GDAL 2.0, from https://2015.foss4g-na.org/sites/default/files/slides/GDAL%202.0%20overview.pdf
    // GeoTIFF driver (with i7-4700 HQ (8 vCPUs)):with i7-4700 HQ (8 vCPUs)
    //   - Default: time ./testblockcache -ondisk: 7.5s
    //   - GTIFF_DIRECT_IO=YES: short circuit the block cache&libtiff for most RasterIO() operations (restricted to
    //     uncompressed stripped GeoTIFF). time ./testblockcache -ondisk: 2s
    //   - GTIFF_VIRTUAL_MEM_IO=YES: same as above, with tiled GeoTIFF as well. Uses memory-mapped file access. Linux
    //     only for now, 64bit recommended (could be extended to other platforms possible).
    //     time ./testblockcache -ondisk: 0.3s
    //
    CPLSetConfigOption("GTIFF_VIRTUAL_MEM_IO", "YES" );
    // Open the dataset
    GDALDataset *poDataset;
    GDALAllRegister();
    poDataset = (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly );

    if( poDataset == NULL )
    {
        std::cout << "Dataset " << pszFilename << " could not be opened." << std::endl;
        return -1;
    }
    else
    {
        GDALRasterBand  *poBand;
        int             nBlockXSize, nBlockYSize;
        int             bGotMin, bGotMax;
        double          adfMinMax[2];

        //  Get raster band and its size
        poBand = poDataset->GetRasterBand(1);
        poBand->GetBlockSize( &nBlockXSize, &nBlockYSize);

        std::cout << "Dataset: " << pszFilename << std::endl;

        std::cout << "Block=" << nBlockXSize << "x" << nBlockYSize << " Type=" <<
                GDALGetDataTypeName(poBand->GetRasterDataType()) << " ColorInterp=" <<
                GDALGetColorInterpretationName(poBand->GetColorInterpretation()) << std::endl;

        // Calculate some stats
        adfMinMax[0] = poBand->GetMinimum(&bGotMin);
        adfMinMax[1] = poBand->GetMaximum(&bGotMax);

        if(!(bGotMin && bGotMax)) {
            GDALComputeRasterMinMax((GDALRasterBandH) poBand, TRUE, adfMinMax);
        }
        std::cout << "Min=" << adfMinMax[0] << " Max=" << adfMinMax[1] << std::endl;

        if(poBand->GetOverviewCount() > 0) {
            std::cout << "Band has " << poBand->GetOverviewCount() << " overviews." << std::endl;
        }
        if( poBand->GetColorTable() != NULL ) {
            std::cout << "Band has a color table with " << poBand->GetColorTable()->GetColorEntryCount() <<
                    " entries." << std::endl;
        }

        // Get the actual data
        float *pafScanline;
        int   nXSize = poBand->GetXSize();
        pafScanline = (float *) CPLMalloc(sizeof(float) * nXSize);

        // RasterIO has a new argument psExtraArg in GDAL > 2.0. NOTE: that  GDALRasterBand::ReadBlock() probably has
        // better performance for reading the whole data at one go.
        #ifdef USE_GDAL_2
            GDALRasterIOExtraArg* arg = NULL;
            poBand->RasterIO(GF_Read, 0, 0, nXSize, 1, pafScanline, nXSize, 1, GDT_Float3GDALRasterBand::ReadBlock 2,
               0, 0, arg);
        #else
            poBand->RasterIO(GF_Read, 0, 0, nXSize, 1, pafScanline, nXSize, 1, GDT_Float32, 0, 0);
        #endif

        // ... do something with the data ...

        // Free resources
        CPLFree(pafScanline);
        GDALClose((GDALDatasetH) poDataset);
        std::cout << std::endl;
    }
    return 0;
}
예제 #16
0
 virtual GDALColorTable* GetColorTable()
 {
     return poUnderlyingBand->GetColorTable();
 }
bool gstIconManager::CopyIcon(const std::string& src_path,
                              const std::string& dst_path) {
  // file must not exist already
  if (khExists(dst_path)) {
    notify(NFY_WARN, "Icon \"%s\" already exists", dst_path.c_str());
    return false;
  }

  GDALDataset* srcDataset = static_cast<GDALDataset*>(
                        GDALOpen(src_path.c_str(), GA_ReadOnly));
  if (!srcDataset) {
    notify(NFY_WARN, "Unable to open icon %s", src_path.c_str());
    return false;
  }

  // determine the image type
  // is it rgb or palette_index type
  bool palette_type = false;
  if (srcDataset->GetRasterCount() == 1 &&
      srcDataset->GetRasterBand(1)->GetColorInterpretation() ==
      GCI_PaletteIndex) {
    palette_type = true;
  } else if (srcDataset->GetRasterCount() != 4) {
    notify(NFY_WARN, "%s: Image type not supported", src_path.c_str());
    return false;
  }

  GDALDataset* oldSrcDataset = 0;
  int target_size = 0;
  bool need_scaling = false;
  int srcXSize = srcDataset->GetRasterXSize();
  int srcYSize = srcDataset->GetRasterYSize();
  if ((srcXSize == 32) || (srcXSize == 64)) {
    target_size = srcXSize;
    if ((srcYSize != srcXSize) &&
        (srcYSize != srcXSize*2) &&
        (srcYSize != srcXSize*3)) {
      need_scaling = true;
    }
  } else if (srcXSize < 32) {
    target_size = 32;
    need_scaling = true;
  } else {
    target_size = 64;
    need_scaling = true;
  }

  if (need_scaling) {
    // create a temp output dataset to scale the src
    // icon to a square target_size*target_size. Later we'll make a stack.
    VRTDataset* tempDataset = new VRTDataset(target_size, target_size);
    int numBands = palette_type ? 1 : 4;
    for (int b = 1; b <= numBands; ++b) {
      tempDataset->AddBand(GDT_Byte, NULL);
      VRTSourcedRasterBand* tempBand =
        static_cast<VRTSourcedRasterBand*>(tempDataset->GetRasterBand(b));

      GDALRasterBand* srcBand = srcDataset->GetRasterBand(b);
      tempBand->AddSimpleSource(srcBand,
                                0, 0, srcXSize, srcYSize,
                                0, 0, target_size, target_size);
      if (palette_type) {
        tempBand->SetColorInterpretation(srcBand->GetColorInterpretation());
        tempBand->SetColorTable(srcBand->GetColorTable());
      }
    }
    oldSrcDataset = srcDataset;
    srcDataset = tempDataset;
    srcXSize = srcYSize = target_size;
  }
  assert(srcXSize == target_size);

  // From here on we assume that we have a square, a stack of 2, or a stack of
  // 3. It will be either 32 or 64 wide. The actual size is stored in srcXSize
  // and srcYSize
  bool simpleCopy = false;
  if (srcYSize == srcXSize * 3)
    simpleCopy = true;

  // create a virtual dataset to represent the desired output image
  VRTDataset* vds = new VRTDataset(target_size, target_size * 3);

  // copy all the bands from the source
  int numBands = palette_type ? 1 : 4;
  for (int b = 1; b <= numBands; ++b) {
    vds->AddBand(GDT_Byte, NULL);
    VRTSourcedRasterBand* vrtBand =
      static_cast<VRTSourcedRasterBand*>(vds->GetRasterBand(b));

    GDALRasterBand* srcBand = srcDataset->GetRasterBand(b);
    if (!simpleCopy) {
      // extract the normal icon (on bottom of input image)
      // and put it on the bottom of new image
      // NOTE: srcYSize calculation lets us hand single, square images
      // as well as two squares stacked on top of each other
      vrtBand->AddSimpleSource(
          srcBand,
          0, srcYSize-target_size, target_size, target_size,
          0, target_size*2, target_size, target_size);

      // extract the highlight icon (on top of input image)
      // and put it in the middle of new image
      vrtBand->AddSimpleSource(srcBand,
                               0, 0, target_size, target_size,
                               0, target_size, target_size, target_size);

      // extract the normal icon (on bottom of input image), scale it to 16x16
      // and put it on the top of the new image
      // NOTE: srcYSize calculation lets us hand single, square images
      // as well as two squares stacked on top of each other
      vrtBand->AddSimpleSource(
          srcBand,
          0, srcYSize-target_size, target_size, target_size,
          0, 0, 16, 16);
    } else {
      vrtBand->AddSimpleSource(srcBand,
                               0, 0, target_size, target_size * 3,
                               0, 0, target_size, target_size * 3);
    }
    if (palette_type) {
      vrtBand->SetColorInterpretation(srcBand->GetColorInterpretation());
      vrtBand->SetColorTable(srcBand->GetColorTable());
    }
  }

  // find output driver
  GDALDriver* pngDriver = GetGDALDriverManager()->GetDriverByName("PNG");
  if (pngDriver == NULL) {
    notify(NFY_FATAL, "Unable to find png driver!");
    return false;
  }

  // write out all bands at once
  GDALDataset* dest = pngDriver->CreateCopy(
                      dst_path.c_str(), vds, false, NULL, NULL, NULL);

  delete dest;
  delete vds;
  delete srcDataset;
  delete oldSrcDataset;

  // just in case the umask trimmed any permissions
  khChmod(dst_path, 0666);

  return true;
}
예제 #18
0
feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
{
    feature_ptr feature = feature_factory::create(ctx_,1);

    GDALRasterBand * red = 0;
    GDALRasterBand * green = 0;
    GDALRasterBand * blue = 0;
    GDALRasterBand * alpha = 0;
    GDALRasterBand * grey = 0;

    /*
#ifdef MAPNIK_LOG
      double tr[6];
      dataset_.GetGeoTransform(tr);

      const double dx = tr[1];
      const double dy = tr[5];
      MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: dx_=" << dx_ << " dx=" << dx << " dy_=" << dy_ << "dy=" << dy;
#endif
    */

    CoordTransform t(raster_width_, raster_height_, raster_extent_, 0, 0);
    box2d<double> intersect = raster_extent_.intersect(q.get_bbox());
    box2d<double> box = t.forward(intersect);

    //size of resized output pixel in source image domain
    double margin_x = 1.0 / (fabs(dx_) * boost::get<0>(q.resolution()));
    double margin_y = 1.0 / (fabs(dy_) * boost::get<1>(q.resolution()));
    if (margin_x < 1)
    {
        margin_x = 1.0;
    }
    if (margin_y < 1)
    {
        margin_y = 1.0;
    }

    //select minimum raster containing whole box
    int x_off = rint(box.minx() - margin_x);
    int y_off = rint(box.miny() - margin_y);
    int end_x = rint(box.maxx() + margin_x);
    int end_y = rint(box.maxy() + margin_y);

    //clip to available data
    if (x_off < 0)
    {
        x_off = 0;
    }
    if (y_off < 0)
    {
        y_off = 0;
    }
    if (end_x > (int)raster_width_)
    {
        end_x = raster_width_;
    }
    if (end_y > (int)raster_height_)
    {
        end_y = raster_height_;
    }
    int width = end_x - x_off;
    int height = end_y - y_off;

    // don't process almost invisible data
    if (box.width() < 0.5)
    {
        width = 0;
    }
    if (box.height() < 0.5)
    {
        height = 0;
    }

    //calculate actual box2d of returned raster
    box2d<double> feature_raster_extent(x_off, y_off, x_off + width, y_off + height);
    intersect = t.backward(feature_raster_extent);

    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Raster extent=" << raster_extent_;
    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: View extent=" << intersect;
    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Query resolution=" << boost::get<0>(q.resolution()) << "," << boost::get<1>(q.resolution());
    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: StartX=" << x_off << " StartY=" << y_off << " Width=" << width << " Height=" << height;

    if (width > 0 && height > 0)
    {
        double width_res = boost::get<0>(q.resolution());
        double height_res = boost::get<1>(q.resolution());
        int im_width = int(width_res * intersect.width() + 0.5);
        int im_height = int(height_res * intersect.height() + 0.5);

        // if layer-level filter_factor is set, apply it
        if (filter_factor_)
        {
            im_width *= filter_factor_;
            im_height *= filter_factor_;

            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Applying layer filter_factor=" << filter_factor_;
        }
        // otherwise respect symbolizer level factor applied to query, default of 1.0
        else
        {
            double sym_downsample_factor = q.get_filter_factor();
            im_width *= sym_downsample_factor;
            im_height *= sym_downsample_factor;
        }

        // case where we need to avoid upsampling so that the
        // image can be later scaled within raster_symbolizer
        if (im_width >= width || im_height >= height)
        {
            im_width = width;
            im_height = height;
        }

        if (im_width > 0 && im_height > 0)
        {
            mapnik::raster_ptr raster = boost::make_shared<mapnik::raster>(intersect, im_width, im_height);
            feature->set_raster(raster);
            mapnik::image_data_32 & image = raster->data_;
            image.set(0xffffffff);

            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Image Size=(" << im_width << "," << im_height << ")";
            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_;

            if (band_ > 0) // we are querying a single band
            {
                if (band_ > nbands_)
                {
                    throw datasource_exception((boost::format("GDAL Plugin: '%d' is an invalid band, dataset only has '%d' bands\n") % band_ % nbands_).str());
                }

                float* imageData = (float*)image.getBytes();
                GDALRasterBand * band = dataset_.GetRasterBand(band_);
                int hasNoData(0);
                double nodata(0);
                if (nodata_value_)
                {
                    hasNoData = 1;
                    nodata = *nodata_value_;
                }
                else
                {
                    nodata = band->GetNoDataValue(&hasNoData);
                }
                band->RasterIO(GF_Read, x_off, y_off, width, height,
                               imageData, image.width(), image.height(),
                               GDT_Float32, 0, 0);

                if (hasNoData)
                {
                    feature->put("NODATA",nodata);
                }
            }
            else // working with all bands
            {
                for (int i = 0; i < nbands_; ++i)
                {
                    GDALRasterBand * band = dataset_.GetRasterBand(i + 1);

#ifdef MAPNIK_LOG
                    get_overview_meta(band);
#endif

                    GDALColorInterp color_interp = band->GetColorInterpretation();
                    switch (color_interp)
                    {
                    case GCI_RedBand:
                        red = band;

                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found red band";

                        break;
                    case GCI_GreenBand:
                        green = band;

                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found green band";

                        break;
                    case GCI_BlueBand:
                        blue = band;

                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found blue band";

                        break;
                    case GCI_AlphaBand:
                        alpha = band;

                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found alpha band";

                        break;
                    case GCI_GrayIndex:
                        grey = band;

                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found gray band";

                        break;
                    case GCI_PaletteIndex:
                    {
                        grey = band;

                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found gray band, and colortable...";

                        GDALColorTable *color_table = band->GetColorTable();

                        if (color_table)
                        {
                            int count = color_table->GetColorEntryCount();

                            MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Color Table count=" << count;

                            for (int j = 0; j < count; j++)
                            {
                                const GDALColorEntry *ce = color_table->GetColorEntry (j);
                                if (! ce) continue;

                                MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Color entry RGB=" << ce->c1 << "," <<ce->c2 << "," << ce->c3;
                            }
                        }
                        break;
                    }
                    case GCI_Undefined:
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Found undefined band (assumming gray band)";

                        grey = band;
                        break;
                    default:
                        MAPNIK_LOG_WARN(gdal) << "gdal_featureset: Band type unknown!";

                        break;
                    }
                }

                if (red && green && blue)
                {
                    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing rgb bands...";

                    int hasNoData = 0;
                    double nodata = 0.0;
                    if (nodata_value_)
                    {
                        hasNoData = 1;
                        nodata = *nodata_value_;
                    }
                    else
                    {
                        nodata = red->GetNoDataValue(&hasNoData);
                    }
                    if (hasNoData)
                    {
                        feature->put("NODATA",nodata);
                    }
                    GDALColorTable *color_table = red->GetColorTable();

                    if (! alpha && hasNoData && ! color_table)
                    {
                        // first read the data in and create an alpha channel from the nodata values
                        float* imageData = (float*)image.getBytes();
                        red->RasterIO(GF_Read, x_off, y_off, width, height,
                                      imageData, image.width(), image.height(),
                                      GDT_Float32, 0, 0);

                        int len = image.width() * image.height();

                        for (int i = 0; i < len; ++i)
                        {
                            if (nodata == imageData[i])
                            {
                                *reinterpret_cast<unsigned *>(&imageData[i]) = 0;
                            }
                            else
                            {
                                *reinterpret_cast<unsigned *>(&imageData[i]) = 0xFFFFFFFF;
                            }
                        }

                    }

                    red->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 0,
                                  image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                    green->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 1,
                                    image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                    blue->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 2,
                                   image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                }
                else if (grey)
                {
                    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing gray band...";

                    int hasNoData(0);
                    double nodata(0);
                    if (nodata_value_)
                    {
                        hasNoData = 1;
                        nodata = *nodata_value_;
                    }
                    else
                    {
                        nodata = grey->GetNoDataValue(&hasNoData);
                    }
                    GDALColorTable* color_table = grey->GetColorTable();

                    if (hasNoData && ! color_table)
                    {
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: No data value for layer=" << nodata;

                        feature->put("NODATA",nodata);
                        // first read the data in and create an alpha channel from the nodata values
                        float* imageData = (float*)image.getBytes();
                        grey->RasterIO(GF_Read, x_off, y_off, width, height,
                                       imageData, image.width(), image.height(),
                                       GDT_Float32, 0, 0);

                        int len = image.width() * image.height();

                        for (int i = 0; i < len; ++i)
                        {
                            if (nodata == imageData[i])
                            {
                                *reinterpret_cast<unsigned *>(&imageData[i]) = 0;
                            }
                            else
                            {
                                *reinterpret_cast<unsigned *> (&imageData[i]) = 0xFFFFFFFF;
                            }
                        }
                    }

                    grey->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 0,
                                   image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                    grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 1,
                                   image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                    grey->RasterIO(GF_Read,x_off, y_off, width, height, image.getBytes() + 2,
                                   image.width(), image.height(), GDT_Byte, 4, 4 * image.width());

                    if (color_table)
                    {
                        MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Loading colour table...";

                        unsigned nodata_value = static_cast<unsigned>(nodata);
                        if (hasNoData)
                        {
                            feature->put("NODATA",static_cast<int>(nodata_value));
                        }
                        for (unsigned y = 0; y < image.height(); ++y)
                        {
                            unsigned int* row = image.getRow(y);
                            for (unsigned x = 0; x < image.width(); ++x)
                            {
                                unsigned value = row[x] & 0xff;
                                if (hasNoData && (value == nodata_value))
                                {
                                    // make no data fully alpha
                                    row[x] = 0;
                                }
                                else
                                {
                                    const GDALColorEntry *ce = color_table->GetColorEntry(value);
                                    if (ce)
                                    {
                                        // TODO - big endian support
                                        row[x] = (ce->c4 << 24)| (ce->c3 << 16) |  (ce->c2 << 8) | (ce->c1) ;
                                    }
                                    else
                                    {
                                        // make lacking color entry fully alpha
                                        // note - gdal_translate makes black
                                        row[x] = 0;
                                    }
                                }
                            }
                        }
                    }
                }
                if (alpha)
                {
                    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: processing alpha band...";

                    alpha->RasterIO(GF_Read, x_off, y_off, width, height, image.getBytes() + 3,
                                    image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
                }
            }
            return feature;
        }
    }
    return feature_ptr();
}
GDALDataset *
GIFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
               int bStrict, char ** papszOptions, 
               GDALProgressFunc pfnProgress, void * pProgressData )

{
    int  nBands = poSrcDS->GetRasterCount();
    int  nXSize = poSrcDS->GetRasterXSize();
    int  nYSize = poSrcDS->GetRasterYSize();
    int	 bInterlace = FALSE;

/* -------------------------------------------------------------------- */
/*      Check for interlaced option.                                    */
/* -------------------------------------------------------------------- */
    bInterlace = CSLFetchBoolean(papszOptions, "INTERLACING", FALSE);

/* -------------------------------------------------------------------- */
/*      Some some rudimentary checks                                    */
/* -------------------------------------------------------------------- */
    if( nBands != 1 )
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "GIF driver only supports one band images.\n" );

        return NULL;
    }

    if (nXSize > 65535 || nYSize > 65535)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "GIF driver only supports datasets up to 65535x65535 size.\n" );

        return NULL;
    }

    if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte 
        && bStrict )
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "GIF driver doesn't support data type %s. "
                  "Only eight bit bands supported.\n", 
                  GDALGetDataTypeName( 
                      poSrcDS->GetRasterBand(1)->GetRasterDataType()) );

        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Open the output file.                                           */
/* -------------------------------------------------------------------- */
    GifFileType *hGifFile;
    VSILFILE *fp;

    fp = VSIFOpenL( pszFilename, "wb" );
    if( fp == NULL )
    {
        CPLError( CE_Failure, CPLE_OpenFailed, 
                  "Failed to create %s:\n%s", 
                  pszFilename, VSIStrerror( errno ) );
        return NULL;
    }

#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
    int nError;
    hGifFile = EGifOpen( fp, VSIGIFWriteFunc, &nError );
#else
    hGifFile = EGifOpen( fp, VSIGIFWriteFunc );
#endif
    if( hGifFile == NULL )
    {
        VSIFCloseL( fp );
        CPLError( CE_Failure, CPLE_OpenFailed, 
                  "EGifOpenFilename(%s) failed.  Does file already exist?",
                  pszFilename );

        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Prepare colortable.                                             */
/* -------------------------------------------------------------------- */
    GDALRasterBand	*poBand = poSrcDS->GetRasterBand(1);
    ColorMapObject	*psGifCT;
    int			iColor;

    if( poBand->GetColorTable() == NULL )
    {
        psGifCT = GifMakeMapObject( 256, NULL );
        for( iColor = 0; iColor < 256; iColor++ )
        {
            psGifCT->Colors[iColor].Red = (GifByteType) iColor;
            psGifCT->Colors[iColor].Green = (GifByteType) iColor;
            psGifCT->Colors[iColor].Blue = (GifByteType) iColor;
        }
    }
    else
    {
        GDALColorTable	*poCT = poBand->GetColorTable();
        int nFullCount = 1;

        while( nFullCount < poCT->GetColorEntryCount() )
            nFullCount = nFullCount * 2;

        psGifCT = GifMakeMapObject( nFullCount, NULL );
        for( iColor = 0; iColor < poCT->GetColorEntryCount(); iColor++ )
        {
            GDALColorEntry	sEntry;

            poCT->GetColorEntryAsRGB( iColor, &sEntry );
            psGifCT->Colors[iColor].Red = (GifByteType) sEntry.c1;
            psGifCT->Colors[iColor].Green = (GifByteType) sEntry.c2;
            psGifCT->Colors[iColor].Blue = (GifByteType) sEntry.c3;
        }
        for( ; iColor < nFullCount; iColor++ )
        {
            psGifCT->Colors[iColor].Red = 0;
            psGifCT->Colors[iColor].Green = 0;
            psGifCT->Colors[iColor].Blue = 0;
        }
    }

/* -------------------------------------------------------------------- */
/*      Setup parameters.                                               */
/* -------------------------------------------------------------------- */
    if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, 
                          psGifCT->ColorCount, 255, psGifCT) == GIF_ERROR)
    {
        GifFreeMapObject(psGifCT);
        GDALPrintGifError(hGifFile, "Error writing gif file.");
        GIFAbstractDataset::myEGifCloseFile(hGifFile);
        VSIFCloseL( fp );
        return NULL;
    }
    
    GifFreeMapObject(psGifCT);
    psGifCT = NULL;

    /* Support for transparency */
    int bNoDataValue;
    double noDataValue = poBand->GetNoDataValue(&bNoDataValue);
    if (bNoDataValue && noDataValue >= 0 && noDataValue <= 255)
    {
        unsigned char extensionData[4];
        extensionData[0] = 1; /*  Transparent Color Flag */
        extensionData[1] = 0;
        extensionData[2] = 0;
        extensionData[3] = (unsigned char)noDataValue;
        EGifPutExtension(hGifFile, 0xf9, 4, extensionData);
    }

    if (EGifPutImageDesc(hGifFile, 0, 0, nXSize, nYSize, bInterlace, NULL) == GIF_ERROR )
    {
        GDALPrintGifError(hGifFile, "Error writing gif file.");
        GIFAbstractDataset::myEGifCloseFile(hGifFile);
        VSIFCloseL( fp );
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Loop over image, copying image data.                            */
/* -------------------------------------------------------------------- */
    CPLErr      eErr;
    GDALPamDataset *poDS;
    GByte      *pabyScanline;

    pabyScanline = (GByte *) CPLMalloc( nXSize );

    if( !pfnProgress( 0.0, NULL, pProgressData ) )
        eErr = CE_Failure;

    if( !bInterlace )
    {
        for( int iLine = 0; iLine < nYSize; iLine++ )
        {
            eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                                     pabyScanline, nXSize, 1, GDT_Byte,
                                     nBands, nBands * nXSize );

            if( eErr != CE_None || EGifPutLine( hGifFile, pabyScanline, nXSize ) == GIF_ERROR )
            {
                CPLError( CE_Failure, CPLE_AppDefined, 
                          "Error writing gif file." );
                goto error;
            }

            if( !pfnProgress( (iLine + 1) * 1.0 / nYSize, NULL, pProgressData ) )
            {
                goto error;
            }

        }
    }
    else
    {
        int 	i, j;
        int nLinesRead = 0;
        int nLinesToRead = 0;
        for ( i = 0; i < 4; i++)
        {
            for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) 
            {
                nLinesToRead ++;
            }
        }

        /* Need to perform 4 passes on the images: */
        for ( i = 0; i < 4; i++)
        {
            for (j = InterlacedOffset[i]; j < nYSize; j += InterlacedJumps[i]) 
            {
                eErr= poBand->RasterIO( GF_Read, 0, j, nXSize, 1, 
                                        pabyScanline, nXSize, 1, GDT_Byte,
                                        1, nXSize );

                if (eErr != CE_None || EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
                {
                    CPLError( CE_Failure, CPLE_AppDefined, 
                            "Error writing gif file." );
                    goto error;
                }

                nLinesRead ++;
                if( !pfnProgress( nLinesRead * 1.0 / nYSize, NULL, pProgressData ) )
                {
                    goto error;
                }
            }
        }
    }

    CPLFree( pabyScanline );
    pabyScanline = NULL;

/* -------------------------------------------------------------------- */
/*      cleanup                                                         */
/* -------------------------------------------------------------------- */
    if (GIFAbstractDataset::myEGifCloseFile(hGifFile) == GIF_ERROR)
    {
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "EGifCloseFile() failed.\n" );
        hGifFile = NULL;
        goto error;
    }
    hGifFile = NULL;

    VSIFCloseL( fp );
    fp = NULL;

/* -------------------------------------------------------------------- */
/*      Do we need a world file?                                          */
/* -------------------------------------------------------------------- */
    if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
    {
    	double      adfGeoTransform[6];
	
	if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
            GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform );
    }

/* -------------------------------------------------------------------- */
/*      Re-open dataset, and copy any auxilary pam information.         */
/* -------------------------------------------------------------------- */

    /* If outputing to stdout, we can't reopen it, so we'll return */
    /* a fake dataset to make the caller happy */
    CPLPushErrorHandler(CPLQuietErrorHandler);
    poDS = (GDALPamDataset*) GDALOpen(pszFilename, GA_ReadOnly);
    CPLPopErrorHandler();
    if (poDS)
    {
        poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
        return poDS;
    }
    else
    {
        CPLErrorReset();

        GIFDataset* poGIF_DS = new GIFDataset();
        poGIF_DS->nRasterXSize = nXSize;
        poGIF_DS->nRasterYSize = nYSize;
        for(int i=0;i<nBands;i++)
            poGIF_DS->SetBand( i+1, new GIFRasterBand( poGIF_DS, i+1, NULL, 0 ) );
        return poGIF_DS;
    }

error:
    if (hGifFile)
        GIFAbstractDataset::myEGifCloseFile(hGifFile);
    if (fp)
        VSIFCloseL( fp );
    if (pabyScanline)
        CPLFree( pabyScanline );
    return NULL;
}
static int ProxyMain(int argc, char **argv)

{
    GDALDatasetH     hDataset, hOutDS;
    int              i;
    int              nRasterXSize, nRasterYSize;
    const char       *pszSource = NULL, *pszDest = NULL, *pszFormat = "GTiff";
    GDALDriverH      hDriver;
    int              *panBandList = NULL;    /* negative value of panBandList[i] means mask band of ABS(panBandList[i]) */
    int              nBandCount   = 0, bDefBands = TRUE;
    double           adfGeoTransform[6];
    GDALDataType     eOutputType          = GDT_Unknown;
    int              nOXSize              = 0, nOYSize = 0;
    char             *pszOXSize           = NULL, *pszOYSize = NULL;
    char             **papszCreateOptions = NULL;
    int              anSrcWin[4], bStrict = FALSE;
    const char       *pszProjection;
    int              bScale        = FALSE, bHaveScaleSrc = FALSE, bUnscale = FALSE;
    double           dfScaleSrcMin = 0.0, dfScaleSrcMax = 255.0;
    double           dfScaleDstMin = 0.0, dfScaleDstMax = 255.0;
    double           dfULX, dfULY, dfLRX, dfLRY;
    char             **papszMetadataOptions = NULL;
    char             *pszOutputSRS          = NULL;
    int              bQuiet                 = FALSE, bGotBounds = FALSE;
    GDALProgressFunc pfnProgress            = GDALTermProgress;
    int              nGCPCount              = 0;
    GDAL_GCP         *pasGCPs               = NULL;
    int              iSrcFileArg            = -1, iDstFileArg = -1;
    int              bCopySubDatasets       = FALSE;
    double           adfULLR[4]             = { 0, 0, 0, 0 };
    int              bSetNoData             = FALSE;
    int              bUnsetNoData           = FALSE;
    double           dfNoDataReal           = 0.0;
    int              nRGBExpand             = 0;
    int              bParsedMaskArgument    = FALSE;
    int              eMaskMode              = MASK_AUTO;
    int              nMaskBand              = 0; /* negative value means mask band of ABS(nMaskBand) */
    int              bStats                 = FALSE, bApproxStats = FALSE;


    anSrcWin[0] = 0;
    anSrcWin[1] = 0;
    anSrcWin[2] = 0;
    anSrcWin[3] = 0;

    dfULX = dfULY = dfLRX = dfLRY = 0.0;

    /* Check strict compilation and runtime library version as we use C++ API */
    if (!GDAL_CHECK_VERSION(argv[0]))
        exit(1);

    /* Must process GDAL_SKIP before GDALAllRegister(), but we can't call */
    /* GDALGeneralCmdLineProcessor before it needs the drivers to be registered */
    /* for the --format or --formats options */
    for (i = 1; i < argc; i++)
    {
        if (EQUAL(argv[i], "--config") && i + 2 < argc && EQUAL(argv[i + 1], "GDAL_SKIP"))
        {
            CPLSetConfigOption(argv[i + 1], argv[i + 2]);

            i += 2;
        }
    }

/* -------------------------------------------------------------------- */
/*      Register standard GDAL drivers, and process generic GDAL        */
/*      command options.                                                */
/* -------------------------------------------------------------------- */
    GDALAllRegister();
    argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
    if (argc < 1)
        exit(-argc);

/* -------------------------------------------------------------------- */
/*      Handle command line arguments.                                  */
/* -------------------------------------------------------------------- */
    for (i = 1; i < argc; i++)
    {
        if (EQUAL(argv[i], "--utility_version"))
        {
            printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
                   argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
            return 0;
        }
        else if (EQUAL(argv[i], "-of") && i < argc - 1)
            pszFormat = argv[++i];

        else if (EQUAL(argv[i], "-q") || EQUAL(argv[i], "-quiet"))
        {
            bQuiet      = TRUE;
            pfnProgress = GDALDummyProgress;
        }

        else if (EQUAL(argv[i], "-ot") && i < argc - 1)
        {
            int iType;

            for (iType = 1; iType < GDT_TypeCount; iType++)
            {
                if (GDALGetDataTypeName((GDALDataType)iType) != NULL
                    && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
                             argv[i + 1]))
                {
                    eOutputType = (GDALDataType) iType;
                }
            }

            if (eOutputType == GDT_Unknown)
            {
                printf("Unknown output pixel type: %s\n", argv[i + 1]);
                Usage();
                GDALDestroyDriverManager();
                exit(2);
            }

            i++;
        }
        else if (EQUAL(argv[i], "-b") && i < argc - 1)
        {
            const char *pszBand = argv[i + 1];
            int        bMask    = FALSE;
            if (EQUAL(pszBand, "mask"))
                pszBand = "mask,1";

            if (EQUALN(pszBand, "mask,", 5))
            {
                bMask    = TRUE;
                pszBand += 5;
                /* If we use tha source mask band as a regular band */
                /* don't create a target mask band by default */
                if (!bParsedMaskArgument)
                    eMaskMode = MASK_DISABLED;
            }

            int nBand = atoi(pszBand);
            if (nBand < 1)
            {
                printf("Unrecognizable band number (%s).\n", argv[i + 1]);
                Usage();
                GDALDestroyDriverManager();
                exit(2);
            }

            i++;

            nBandCount++;
            panBandList = (int*)
                          CPLRealloc(panBandList, sizeof(int) * nBandCount);
            panBandList[nBandCount - 1] = nBand;
            if (bMask)
                panBandList[nBandCount - 1] *= -1;

            if (panBandList[nBandCount - 1] != nBandCount)
                bDefBands = FALSE;
        }
        else if (EQUAL(argv[i], "-mask") && i < argc - 1)
        {
            bParsedMaskArgument = TRUE;
            const char *pszBand = argv[i + 1];
            if (EQUAL(pszBand, "none"))
            {
                eMaskMode = MASK_DISABLED;
            }
            else if (EQUAL(pszBand, "auto"))
            {
                eMaskMode = MASK_AUTO;
            }
            else
            {
                int bMask = FALSE;
                if (EQUAL(pszBand, "mask"))
                    pszBand = "mask,1";

                if (EQUALN(pszBand, "mask,", 5))
                {
                    bMask    = TRUE;
                    pszBand += 5;
                }

                int nBand = atoi(pszBand);
                if (nBand < 1)
                {
                    printf("Unrecognizable band number (%s).\n", argv[i + 1]);
                    Usage();
                    GDALDestroyDriverManager();
                    exit(2);
                }

                eMaskMode = MASK_USER;
                nMaskBand = nBand;
                if (bMask)
                    nMaskBand *= -1;
            }

            i++;
        }
        else if (EQUAL(argv[i], "-not_strict"))
            bStrict = FALSE;

        else if (EQUAL(argv[i], "-strict"))
            bStrict = TRUE;

        else if (EQUAL(argv[i], "-sds"))
            bCopySubDatasets = TRUE;

        else if (EQUAL(argv[i], "-gcp") && i < argc - 4)
        {
            char *endptr = NULL;
            /* -gcp pixel line easting northing [elev] */

            nGCPCount++;
            pasGCPs = (GDAL_GCP*)
                      CPLRealloc(pasGCPs, sizeof(GDAL_GCP) * nGCPCount);
            GDALInitGCPs(1, pasGCPs + nGCPCount - 1);

            pasGCPs[nGCPCount - 1].dfGCPPixel = CPLAtofM(argv[++i]);
            pasGCPs[nGCPCount - 1].dfGCPLine  = CPLAtofM(argv[++i]);
            pasGCPs[nGCPCount - 1].dfGCPX     = CPLAtofM(argv[++i]);
            pasGCPs[nGCPCount - 1].dfGCPY     = CPLAtofM(argv[++i]);
            if (argv[i + 1] != NULL
                && (CPLStrtod(argv[i + 1], &endptr) != 0.0 || argv[i + 1][0] == '0'))
            {
                /* Check that last argument is really a number and not a filename */
                /* looking like a number (see ticket #863) */
                if (endptr && *endptr == 0)
                    pasGCPs[nGCPCount - 1].dfGCPZ = CPLAtofM(argv[++i]);
            }

            /* should set id and info? */
        }

        else if (EQUAL(argv[i], "-a_nodata") && i < argc - 1)
        {
            if (EQUAL(argv[i + 1], "none"))
            {
                bUnsetNoData = TRUE;
            }
            else
            {
                bSetNoData   = TRUE;
                dfNoDataReal = CPLAtofM(argv[i + 1]);
            }

            i += 1;
        }

        else if (EQUAL(argv[i], "-a_ullr") && i < argc - 4)
        {
            adfULLR[0] = CPLAtofM(argv[i + 1]);
            adfULLR[1] = CPLAtofM(argv[i + 2]);
            adfULLR[2] = CPLAtofM(argv[i + 3]);
            adfULLR[3] = CPLAtofM(argv[i + 4]);

            bGotBounds = TRUE;

            i += 4;
        }

        else if (EQUAL(argv[i], "-co") && i < argc - 1)
        {
            papszCreateOptions = CSLAddString(papszCreateOptions, argv[++i]);
        }

        else if (EQUAL(argv[i], "-scale"))
        {
            bScale = TRUE;
            if (i < argc - 2 && ArgIsNumeric(argv[i + 1]))
            {
                bHaveScaleSrc = TRUE;
                dfScaleSrcMin = CPLAtofM(argv[i + 1]);
                dfScaleSrcMax = CPLAtofM(argv[i + 2]);
                i            += 2;
            }

            if (i < argc - 2 && bHaveScaleSrc && ArgIsNumeric(argv[i + 1]))
            {
                dfScaleDstMin = CPLAtofM(argv[i + 1]);
                dfScaleDstMax = CPLAtofM(argv[i + 2]);
                i            += 2;
            }
            else
            {
                dfScaleDstMin = 0.0;
                dfScaleDstMax = 255.999;
            }
        }

        else if (EQUAL(argv[i], "-unscale"))
        {
            bUnscale = TRUE;
        }

        else if (EQUAL(argv[i], "-mo") && i < argc - 1)
        {
            papszMetadataOptions = CSLAddString(papszMetadataOptions,
                                                argv[++i]);
        }

        else if (EQUAL(argv[i], "-outsize") && i < argc - 2)
        {
            pszOXSize = argv[++i];
            pszOYSize = argv[++i];
        }

        else if (EQUAL(argv[i], "-srcwin") && i < argc - 4)
        {
            anSrcWin[0] = atoi(argv[++i]);
            anSrcWin[1] = atoi(argv[++i]);
            anSrcWin[2] = atoi(argv[++i]);
            anSrcWin[3] = atoi(argv[++i]);
        }

        else if (EQUAL(argv[i], "-projwin") && i < argc - 4)
        {
            dfULX = CPLAtofM(argv[++i]);
            dfULY = CPLAtofM(argv[++i]);
            dfLRX = CPLAtofM(argv[++i]);
            dfLRY = CPLAtofM(argv[++i]);
        }

        else if (EQUAL(argv[i], "-a_srs") && i < argc - 1)
        {
            OGRSpatialReference oOutputSRS;

            if (oOutputSRS.SetFromUserInput(argv[i + 1]) != OGRERR_NONE)
            {
                fprintf(stderr, "Failed to process SRS definition: %s\n",
                        argv[i + 1]);
                GDALDestroyDriverManager();
                exit(1);
            }

            oOutputSRS.exportToWkt(&pszOutputSRS);
            i++;
        }

        else if (EQUAL(argv[i], "-expand") && i < argc - 1)
        {
            if (EQUAL(argv[i + 1], "gray"))
                nRGBExpand = 1;
            else if (EQUAL(argv[i + 1], "rgb"))
                nRGBExpand = 3;
            else if (EQUAL(argv[i + 1], "rgba"))
                nRGBExpand = 4;
            else
            {
                printf("Value %s unsupported. Only gray, rgb or rgba are supported.\n\n",
                       argv[i]);
                Usage();
                GDALDestroyDriverManager();
                exit(2);
            }

            i++;
        }

        else if (EQUAL(argv[i], "-stats"))
        {
            bStats       = TRUE;
            bApproxStats = FALSE;
        }
        else if (EQUAL(argv[i], "-approx_stats"))
        {
            bStats       = TRUE;
            bApproxStats = TRUE;
        }

        else if (argv[i][0] == '-')
        {
            printf("Option %s incomplete, or not recognised.\n\n",
                   argv[i]);
            Usage();
            GDALDestroyDriverManager();
            exit(2);
        }
        else if (pszSource == NULL)
        {
            iSrcFileArg = i;
            pszSource   = argv[i];
        }
        else if (pszDest == NULL)
        {
            pszDest     = argv[i];
            iDstFileArg = i;
        }

        else
        {
            printf("Too many command options.\n\n");
            Usage();
            GDALDestroyDriverManager();
            exit(2);
        }
    }

    if (pszDest == NULL)
    {
        Usage();
        GDALDestroyDriverManager();
        exit(10);
    }

    if (strcmp(pszSource, pszDest) == 0)
    {
        fprintf(stderr, "Source and destination datasets must be different.\n");
        GDALDestroyDriverManager();
        exit(1);
    }

    if (strcmp(pszDest, "/vsistdout/") == 0)
    {
        bQuiet      = TRUE;
        pfnProgress = GDALDummyProgress;
    }

/* -------------------------------------------------------------------- */
/*      Attempt to open source file.                                    */
/* -------------------------------------------------------------------- */

    hDataset = GDALOpenShared(pszSource, GA_ReadOnly);

    if (hDataset == NULL)
    {
        fprintf(stderr,
                "GDALOpen failed - %d\n%s\n",
                CPLGetLastErrorNo(), CPLGetLastErrorMsg());
        GDALDestroyDriverManager();
        exit(1);
    }

/* -------------------------------------------------------------------- */
/*      Handle subdatasets.                                             */
/* -------------------------------------------------------------------- */
    if (!bCopySubDatasets
        && CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0
        && GDALGetRasterCount(hDataset) == 0)
    {
        fprintf(stderr,
                "Input file contains subdatasets. Please, select one of them for reading.\n");
        GDALClose(hDataset);
        GDALDestroyDriverManager();
        exit(1);
    }

    if (CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0
        && bCopySubDatasets)
    {
        char **papszSubdatasets = GDALGetMetadata(hDataset, "SUBDATASETS");
        char *pszSubDest        = (char*) CPLMalloc(strlen(pszDest) + 32);
        int  i;
        int  bOldSubCall    = bSubCall;
        char **papszDupArgv = CSLDuplicate(argv);
        int  nRet           = 0;

        CPLFree(papszDupArgv[iDstFileArg]);
        papszDupArgv[iDstFileArg] = pszSubDest;
        bSubCall                  = TRUE;

        for (i = 0; papszSubdatasets[i] != NULL; i += 2)
        {
            CPLFree(papszDupArgv[iSrcFileArg]);
            papszDupArgv[iSrcFileArg] = CPLStrdup(strstr(papszSubdatasets[i], "=") + 1);
            sprintf(pszSubDest, "%s%d", pszDest, i / 2 + 1);
            nRet = ProxyMain(argc, papszDupArgv);
            if (nRet != 0)
                break;
        }

        CSLDestroy(papszDupArgv);

        bSubCall = bOldSubCall;
        CSLDestroy(argv);

        GDALClose(hDataset);

        if (!bSubCall)
        {
            GDALDumpOpenDatasets(stderr);
            GDALDestroyDriverManager();
        }

        return nRet;
    }

/* -------------------------------------------------------------------- */
/*      Collect some information from the source file.                  */
/* -------------------------------------------------------------------- */
    nRasterXSize = GDALGetRasterXSize(hDataset);
    nRasterYSize = GDALGetRasterYSize(hDataset);

    if (!bQuiet)
        printf("Input file size is %d, %d\n", nRasterXSize, nRasterYSize);

    if (anSrcWin[2] == 0 && anSrcWin[3] == 0)
    {
        anSrcWin[2] = nRasterXSize;
        anSrcWin[3] = nRasterYSize;
    }

/* -------------------------------------------------------------------- */
/*      Build band list to translate                                    */
/* -------------------------------------------------------------------- */
    if (nBandCount == 0)
    {
        nBandCount = GDALGetRasterCount(hDataset);
        if (nBandCount == 0)
        {
            fprintf(stderr, "Input file has no bands, and so cannot be translated.\n");
            GDALDestroyDriverManager();
            exit(1);
        }

        panBandList = (int*) CPLMalloc(sizeof(int) * nBandCount);

        for (i = 0; i < nBandCount; i++)
            panBandList[i] = i + 1;
    }
    else
    {
        for (i = 0; i < nBandCount; i++)
        {
            if (ABS(panBandList[i]) > GDALGetRasterCount(hDataset))
            {
                fprintf(stderr,
                        "Band %d requested, but only bands 1 to %d available.\n",
                        ABS(panBandList[i]), GDALGetRasterCount(hDataset));
                GDALDestroyDriverManager();
                exit(2);
            }
        }

        if (nBandCount != GDALGetRasterCount(hDataset))
            bDefBands = FALSE;
    }

/* -------------------------------------------------------------------- */
/*      Compute the source window from the projected source window      */
/*      if the projected coordinates were provided.  Note that the      */
/*      projected coordinates are in ulx, uly, lrx, lry format,         */
/*      while the anSrcWin is xoff, yoff, xsize, ysize with the         */
/*      xoff,yoff being the ulx, uly in pixel/line.                     */
/* -------------------------------------------------------------------- */
    if (dfULX != 0.0 || dfULY != 0.0
        || dfLRX != 0.0 || dfLRY != 0.0)
    {
        double adfGeoTransform[6];

        GDALGetGeoTransform(hDataset, adfGeoTransform);

        if (adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0)
        {
            fprintf(stderr,
                    "The -projwin option was used, but the geotransform is\n"
                    "rotated.  This configuration is not supported.\n");
            GDALClose(hDataset);
            CPLFree(panBandList);
            GDALDestroyDriverManager();
            exit(1);
        }

        anSrcWin[0] = (int)
                      ((dfULX - adfGeoTransform[0]) / adfGeoTransform[1] + 0.001);
        anSrcWin[1] = (int)
                      ((dfULY - adfGeoTransform[3]) / adfGeoTransform[5] + 0.001);

        anSrcWin[2] = (int) ((dfLRX - dfULX) / adfGeoTransform[1] + 0.5);
        anSrcWin[3] = (int) ((dfLRY - dfULY) / adfGeoTransform[5] + 0.5);

        if (!bQuiet)
            fprintf(stdout,
                    "Computed -srcwin %d %d %d %d from projected window.\n",
                    anSrcWin[0],
                    anSrcWin[1],
                    anSrcWin[2],
                    anSrcWin[3]);

        if (anSrcWin[0] < 0 || anSrcWin[1] < 0
            || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset)
            || anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hDataset))
        {
            fprintf(stderr,
                    "Computed -srcwin falls outside raster size of %dx%d.\n",
                    GDALGetRasterXSize(hDataset),
                    GDALGetRasterYSize(hDataset));
            exit(1);
        }
    }

/* -------------------------------------------------------------------- */
/*      Verify source window.                                           */
/* -------------------------------------------------------------------- */
    if (anSrcWin[0] < 0 || anSrcWin[1] < 0
        || anSrcWin[2] <= 0 || anSrcWin[3] <= 0
        || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset)
        || anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hDataset))
    {
        fprintf(stderr,
                "-srcwin %d %d %d %d falls outside raster size of %dx%d\n"
                "or is otherwise illegal.\n",
                anSrcWin[0],
                anSrcWin[1],
                anSrcWin[2],
                anSrcWin[3],
                GDALGetRasterXSize(hDataset),
                GDALGetRasterYSize(hDataset));
        exit(1);
    }

/* -------------------------------------------------------------------- */
/*      Find the output driver.                                         */
/* -------------------------------------------------------------------- */
    hDriver = GDALGetDriverByName(pszFormat);
    if (hDriver == NULL)
    {
        int iDr;

        printf("Output driver `%s' not recognised.\n", pszFormat);
        printf("The following format drivers are configured and support output:\n");

        for (iDr = 0; iDr < GDALGetDriverCount(); iDr++)
        {
            GDALDriverH hDriver = GDALGetDriver(iDr);

            if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, NULL) != NULL
                || GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY,
                                       NULL) != NULL)
            {
                printf("  %s: %s\n",
                       GDALGetDriverShortName(hDriver),
                       GDALGetDriverLongName(hDriver));
            }
        }

        printf("\n");
        Usage();

        GDALClose(hDataset);
        CPLFree(panBandList);
        GDALDestroyDriverManager();
        CSLDestroy(argv);
        CSLDestroy(papszCreateOptions);
        exit(1);
    }

/* -------------------------------------------------------------------- */
/*      The short form is to CreateCopy().  We use this if the input    */
/*      matches the whole dataset.  Eventually we should rewrite        */
/*      this entire program to use virtual datasets to construct a      */
/*      virtual input source to copy from.                              */
/* -------------------------------------------------------------------- */


    int bSpatialArrangementPreserved = (
        anSrcWin[0] == 0 && anSrcWin[1] == 0
        && anSrcWin[2] == GDALGetRasterXSize(hDataset)
        && anSrcWin[3] == GDALGetRasterYSize(hDataset)
        && pszOXSize == NULL && pszOYSize == NULL);

    if (eOutputType == GDT_Unknown
        && !bScale && !bUnscale
        && CSLCount(papszMetadataOptions) == 0 && bDefBands
        && eMaskMode == MASK_AUTO
        && bSpatialArrangementPreserved
        && nGCPCount == 0 && !bGotBounds
        && pszOutputSRS == NULL && !bSetNoData && !bUnsetNoData
        && nRGBExpand == 0 && !bStats)
    {
        hOutDS = GDALCreateCopy(hDriver, pszDest, hDataset,
                                bStrict, papszCreateOptions,
                                pfnProgress, NULL);

        if (hOutDS != NULL)
            GDALClose(hOutDS);

        GDALClose(hDataset);

        CPLFree(panBandList);

        if (!bSubCall)
        {
            GDALDumpOpenDatasets(stderr);
            GDALDestroyDriverManager();
        }

        CSLDestroy(argv);
        CSLDestroy(papszCreateOptions);

        return hOutDS == NULL;
    }

/* -------------------------------------------------------------------- */
/*      Establish some parameters.                                      */
/* -------------------------------------------------------------------- */
    if (pszOXSize == NULL)
    {
        nOXSize = anSrcWin[2];
        nOYSize = anSrcWin[3];
    }
    else
    {
        nOXSize = (int) ((pszOXSize[strlen(pszOXSize) - 1] == '%'
                          ? CPLAtofM(pszOXSize) / 100 * anSrcWin[2] : atoi(pszOXSize)));
        nOYSize = (int) ((pszOYSize[strlen(pszOYSize) - 1] == '%'
                          ? CPLAtofM(pszOYSize) / 100 * anSrcWin[3] : atoi(pszOYSize)));
    }

/* ==================================================================== */
/*      Create a virtual dataset.                                       */
/* ==================================================================== */
    VRTDataset *poVDS;

/* -------------------------------------------------------------------- */
/*      Make a virtual clone.                                           */
/* -------------------------------------------------------------------- */
    poVDS = (VRTDataset*) VRTCreate(nOXSize, nOYSize);

    if (nGCPCount == 0)
    {
        if (pszOutputSRS != NULL)
        {
            poVDS->SetProjection(pszOutputSRS);
        }
        else
        {
            pszProjection = GDALGetProjectionRef(hDataset);
            if (pszProjection != NULL && strlen(pszProjection) > 0)
                poVDS->SetProjection(pszProjection);
        }
    }

    if (bGotBounds)
    {
        adfGeoTransform[0] = adfULLR[0];
        adfGeoTransform[1] = (adfULLR[2] - adfULLR[0]) / nOXSize;
        adfGeoTransform[2] = 0.0;
        adfGeoTransform[3] = adfULLR[1];
        adfGeoTransform[4] = 0.0;
        adfGeoTransform[5] = (adfULLR[3] - adfULLR[1]) / nOYSize;

        poVDS->SetGeoTransform(adfGeoTransform);
    }

    else if (GDALGetGeoTransform(hDataset, adfGeoTransform) == CE_None
             && nGCPCount == 0)
    {
        adfGeoTransform[0] += anSrcWin[0] * adfGeoTransform[1]
                              + anSrcWin[1] * adfGeoTransform[2];
        adfGeoTransform[3] += anSrcWin[0] * adfGeoTransform[4]
                              + anSrcWin[1] * adfGeoTransform[5];

        adfGeoTransform[1] *= anSrcWin[2] / (double) nOXSize;
        adfGeoTransform[2] *= anSrcWin[3] / (double) nOYSize;
        adfGeoTransform[4] *= anSrcWin[2] / (double) nOXSize;
        adfGeoTransform[5] *= anSrcWin[3] / (double) nOYSize;

        poVDS->SetGeoTransform(adfGeoTransform);
    }

    if (nGCPCount != 0)
    {
        const char *pszGCPProjection = pszOutputSRS;

        if (pszGCPProjection == NULL)
            pszGCPProjection = GDALGetGCPProjection(hDataset);

        if (pszGCPProjection == NULL)
            pszGCPProjection = "";

        poVDS->SetGCPs(nGCPCount, pasGCPs, pszGCPProjection);

        GDALDeinitGCPs(nGCPCount, pasGCPs);
        CPLFree(pasGCPs);
    }

    else if (GDALGetGCPCount(hDataset) > 0)
    {
        GDAL_GCP *pasGCPs;
        int      nGCPs = GDALGetGCPCount(hDataset);

        pasGCPs = GDALDuplicateGCPs(nGCPs, GDALGetGCPs(hDataset));

        for (i = 0; i < nGCPs; i++)
        {
            pasGCPs[i].dfGCPPixel -= anSrcWin[0];
            pasGCPs[i].dfGCPLine  -= anSrcWin[1];
            pasGCPs[i].dfGCPPixel *= (nOXSize / (double) anSrcWin[2]);
            pasGCPs[i].dfGCPLine  *= (nOYSize / (double) anSrcWin[3]);
        }

        poVDS->SetGCPs(nGCPs, pasGCPs,
                       GDALGetGCPProjection(hDataset));

        GDALDeinitGCPs(nGCPs, pasGCPs);
        CPLFree(pasGCPs);
    }

/* -------------------------------------------------------------------- */
/*      Transfer generally applicable metadata.                         */
/* -------------------------------------------------------------------- */
    poVDS->SetMetadata(((GDALDataset*)hDataset)->GetMetadata());
    AttachMetadata((GDALDatasetH) poVDS, papszMetadataOptions);

    const char *pszInterleave = GDALGetMetadataItem(hDataset, "INTERLEAVE", "IMAGE_STRUCTURE");
    if (pszInterleave)
        poVDS->SetMetadataItem("INTERLEAVE", pszInterleave, "IMAGE_STRUCTURE");

/* -------------------------------------------------------------------- */
/*      Transfer metadata that remains valid if the spatial             */
/*      arrangement of the data is unaltered.                           */
/* -------------------------------------------------------------------- */
    if (bSpatialArrangementPreserved)
    {
        char **papszMD;

        papszMD = ((GDALDataset*)hDataset)->GetMetadata("RPC");
        if (papszMD != NULL)
            poVDS->SetMetadata(papszMD, "RPC");

        papszMD = ((GDALDataset*)hDataset)->GetMetadata("GEOLOCATION");
        if (papszMD != NULL)
            poVDS->SetMetadata(papszMD, "GEOLOCATION");
    }

    int nSrcBandCount = nBandCount;

    if (nRGBExpand != 0)
    {
        GDALRasterBand *poSrcBand;
        poSrcBand = ((GDALDataset*)
                     hDataset)->GetRasterBand(ABS(panBandList[0]));
        if (panBandList[0] < 0)
            poSrcBand = poSrcBand->GetMaskBand();

        GDALColorTable *poColorTable = poSrcBand->GetColorTable();
        if (poColorTable == NULL)
        {
            fprintf(stderr, "Error : band %d has no color table\n", ABS(panBandList[0]));
            GDALClose(hDataset);
            CPLFree(panBandList);
            GDALDestroyDriverManager();
            CSLDestroy(argv);
            CSLDestroy(papszCreateOptions);
            exit(1);
        }

        /* Check that the color table only contains gray levels */
        /* when using -expand gray */
        if (nRGBExpand == 1)
        {
            int nColorCount = poColorTable->GetColorEntryCount();
            int nColor;

            for (nColor = 0; nColor < nColorCount; nColor++)
            {
                const GDALColorEntry *poEntry = poColorTable->GetColorEntry(nColor);
                if (poEntry->c1 != poEntry->c2 || poEntry->c1 != poEntry->c2)
                {
                    fprintf(stderr, "Warning : color table contains non gray levels colors\n");
                    break;
                }
            }
        }

        if (nBandCount == 1)
            nBandCount = nRGBExpand;
        else if (nBandCount == 2 && (nRGBExpand == 3 || nRGBExpand == 4))
            nBandCount = nRGBExpand;
        else
        {
            fprintf(stderr, "Error : invalid use of -expand option.\n");
            exit(1);
        }
    }

    int bFilterOutStatsMetadata =
        (bScale || bUnscale || !bSpatialArrangementPreserved || nRGBExpand != 0);

/* ==================================================================== */
/*      Process all bands.                                              */
/* ==================================================================== */
    for (i = 0; i < nBandCount; i++)
    {
        VRTSourcedRasterBand *poVRTBand;
        GDALRasterBand       *poSrcBand;
        GDALDataType         eBandType;
        int                  nComponent = 0;

        int nSrcBand;
        if (nRGBExpand != 0)
        {
            if (nSrcBandCount == 2 && nRGBExpand == 4 && i == 3)
                nSrcBand = panBandList[1];
            else
            {
                nSrcBand   = panBandList[0];
                nComponent = i + 1;
            }
        }
        else
            nSrcBand = panBandList[i];

        poSrcBand = ((GDALDataset*) hDataset)->GetRasterBand(ABS(nSrcBand));

/* -------------------------------------------------------------------- */
/*      Select output data type to match source.                        */
/* -------------------------------------------------------------------- */
        if (eOutputType == GDT_Unknown)
            eBandType = poSrcBand->GetRasterDataType();
        else
            eBandType = eOutputType;

/* -------------------------------------------------------------------- */
/*      Create this band.                                               */
/* -------------------------------------------------------------------- */
        poVDS->AddBand(eBandType, NULL);
        poVRTBand = (VRTSourcedRasterBand*) poVDS->GetRasterBand(i + 1);
        if (nSrcBand < 0)
        {
            poVRTBand->AddMaskBandSource(poSrcBand);
            continue;
        }

/* -------------------------------------------------------------------- */
/*      Do we need to collect scaling information?                      */
/* -------------------------------------------------------------------- */
        double dfScale = 1.0, dfOffset = 0.0;

        if (bScale && !bHaveScaleSrc)
        {
            double adfCMinMax[2];
            GDALComputeRasterMinMax(poSrcBand, TRUE, adfCMinMax);
            dfScaleSrcMin = adfCMinMax[0];
            dfScaleSrcMax = adfCMinMax[1];
        }

        if (bScale)
        {
            if (dfScaleSrcMax == dfScaleSrcMin)
                dfScaleSrcMax += 0.1;

            if (dfScaleDstMax == dfScaleDstMin)
                dfScaleDstMax += 0.1;

            dfScale = (dfScaleDstMax - dfScaleDstMin)
                      / (dfScaleSrcMax - dfScaleSrcMin);
            dfOffset = -1 * dfScaleSrcMin * dfScale + dfScaleDstMin;
        }

        if (bUnscale)
        {
            dfScale  = poSrcBand->GetScale();
            dfOffset = poSrcBand->GetOffset();
        }

/* -------------------------------------------------------------------- */
/*      Create a simple or complex data source depending on the         */
/*      translation type required.                                      */
/* -------------------------------------------------------------------- */
        if (bUnscale || bScale || (nRGBExpand != 0 && i < nRGBExpand))
        {
            poVRTBand->AddComplexSource(poSrcBand,
                                        anSrcWin[0], anSrcWin[1],
                                        anSrcWin[2], anSrcWin[3],
                                        0, 0, nOXSize, nOYSize,
                                        dfOffset, dfScale,
                                        VRT_NODATA_UNSET,
                                        nComponent);
        }
        else
            poVRTBand->AddSimpleSource(poSrcBand,
                                       anSrcWin[0], anSrcWin[1],
                                       anSrcWin[2], anSrcWin[3],
                                       0, 0, nOXSize, nOYSize);

/* -------------------------------------------------------------------- */
/*      In case of color table translate, we only set the color         */
/*      interpretation other info copied by CopyBandInfo are            */
/*      not relevant in RGB expansion.                                  */
/* -------------------------------------------------------------------- */
        if (nRGBExpand == 1)
        {
            poVRTBand->SetColorInterpretation(GCI_GrayIndex);
        }
        else if (nRGBExpand != 0 && i < nRGBExpand)
        {
            poVRTBand->SetColorInterpretation((GDALColorInterp) (GCI_RedBand + i));
        }

/* -------------------------------------------------------------------- */
/*      copy over some other information of interest.                   */
/* -------------------------------------------------------------------- */
        else
        {
            CopyBandInfo(poSrcBand, poVRTBand,
                         !bStats && !bFilterOutStatsMetadata,
                         !bUnscale,
                         !bSetNoData && !bUnsetNoData);
        }

/* -------------------------------------------------------------------- */
/*      Set a forcable nodata value?                                    */
/* -------------------------------------------------------------------- */
        if (bSetNoData)
        {
            double dfVal    = dfNoDataReal;
            int    bClamped = FALSE, bRounded = FALSE;

#define CLAMP(val, type, minval, maxval)                                          \
    do { if (val < minval) { bClamped = TRUE; val = minval;                       \
         }                                                                        \
         else if (val > maxval) { bClamped = TRUE; val = maxval; }                \
         else if (val != (type)val) { bRounded = TRUE; val = (type)(val + 0.5); } \
    }                                                                             \
    while (0)

            switch (eBandType)
            {
            case GDT_Byte:
                CLAMP(dfVal, GByte, 0.0, 255.0);
                break;

            case GDT_Int16:
                CLAMP(dfVal, GInt16, -32768.0, 32767.0);
                break;

            case GDT_UInt16:
                CLAMP(dfVal, GUInt16, 0.0, 65535.0);
                break;

            case GDT_Int32:
                CLAMP(dfVal, GInt32, -2147483648.0, 2147483647.0);
                break;

            case GDT_UInt32:
                CLAMP(dfVal, GUInt32, 0.0, 4294967295.0);
                break;

            default:
                break;
            }

            if (bClamped)
            {
                printf("for band %d, nodata value has been clamped "
                       "to %.0f, the original value being out of range.\n",
                       i + 1, dfVal);
            }
            else if (bRounded)
            {
                printf("for band %d, nodata value has been rounded "
                       "to %.0f, %s being an integer datatype.\n",
                       i + 1, dfVal,
                       GDALGetDataTypeName(eBandType));
            }

            poVRTBand->SetNoDataValue(dfVal);
        }

        if (eMaskMode == MASK_AUTO &&
            (GDALGetMaskFlags(GDALGetRasterBand(hDataset, 1)) & GMF_PER_DATASET) == 0 &&
            (poSrcBand->GetMaskFlags() & (GMF_ALL_VALID | GMF_NODATA)) == 0)
        {
            if (poVRTBand->CreateMaskBand(poSrcBand->GetMaskFlags()) == CE_None)
            {
                VRTSourcedRasterBand *hMaskVRTBand =
                    (VRTSourcedRasterBand*)poVRTBand->GetMaskBand();
                hMaskVRTBand->AddMaskBandSource(poSrcBand,
                                                anSrcWin[0], anSrcWin[1],
                                                anSrcWin[2], anSrcWin[3],
                                                0, 0, nOXSize, nOYSize);
            }
        }
    }

    if (eMaskMode == MASK_USER)
    {
        GDALRasterBand *poSrcBand =
            (GDALRasterBand*)GDALGetRasterBand(hDataset, ABS(nMaskBand));
        if (poSrcBand && poVDS->CreateMaskBand(GMF_PER_DATASET) == CE_None)
        {
            VRTSourcedRasterBand *hMaskVRTBand = (VRTSourcedRasterBand*)
                                                 GDALGetMaskBand(GDALGetRasterBand((GDALDatasetH)poVDS, 1));
            if (nMaskBand > 0)
                hMaskVRTBand->AddSimpleSource(poSrcBand,
                                              anSrcWin[0], anSrcWin[1],
                                              anSrcWin[2], anSrcWin[3],
                                              0, 0, nOXSize, nOYSize);
            else
                hMaskVRTBand->AddMaskBandSource(poSrcBand,
                                                anSrcWin[0], anSrcWin[1],
                                                anSrcWin[2], anSrcWin[3],
                                                0, 0, nOXSize, nOYSize);
        }
    }
    else if (eMaskMode == MASK_AUTO && nSrcBandCount > 0 &&
             GDALGetMaskFlags(GDALGetRasterBand(hDataset, 1)) == GMF_PER_DATASET)
    {
        if (poVDS->CreateMaskBand(GMF_PER_DATASET) == CE_None)
        {
            VRTSourcedRasterBand *hMaskVRTBand = (VRTSourcedRasterBand*)
                                                 GDALGetMaskBand(GDALGetRasterBand((GDALDatasetH)poVDS, 1));
            hMaskVRTBand->AddMaskBandSource((GDALRasterBand*)GDALGetRasterBand(hDataset, 1),
                                            anSrcWin[0], anSrcWin[1],
                                            anSrcWin[2], anSrcWin[3],
                                            0, 0, nOXSize, nOYSize);
        }
    }

/* -------------------------------------------------------------------- */
/*      Compute stats if required.                                      */
/* -------------------------------------------------------------------- */
    if (bStats)
    {
        for (i = 0; i < poVDS->GetRasterCount(); i++)
        {
            double dfMin, dfMax, dfMean, dfStdDev;
            poVDS->GetRasterBand(i + 1)->ComputeStatistics(bApproxStats,
                                                           &dfMin, &dfMax, &dfMean, &dfStdDev, GDALDummyProgress, NULL);
        }
    }

/* -------------------------------------------------------------------- */
/*      Write to the output file using CopyCreate().                    */
/* -------------------------------------------------------------------- */
    hOutDS = GDALCreateCopy(hDriver, pszDest, (GDALDatasetH) poVDS,
                            bStrict, papszCreateOptions,
                            pfnProgress, NULL);
    if (hOutDS != NULL)
    {
        int bHasGotErr = FALSE;
        CPLErrorReset();
        GDALFlushCache(hOutDS);
        if (CPLGetLastErrorType() != CE_None)
            bHasGotErr = TRUE;

        GDALClose(hOutDS);
        if (bHasGotErr)
            hOutDS = NULL;
    }

    GDALClose((GDALDatasetH) poVDS);

    GDALClose(hDataset);

    CPLFree(panBandList);

    CPLFree(pszOutputSRS);

    if (!bSubCall)
    {
        GDALDumpOpenDatasets(stderr);
        GDALDestroyDriverManager();
    }

    CSLDestroy(argv);
    CSLDestroy(papszCreateOptions);

    return hOutDS == NULL;
}
예제 #21
0
CPLErr 
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList, 
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling, 
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    TIFF    *hOTIFF;
    int     nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0;
    int     nSampleFormat=0, nPlanarConfig, iOverview, iBand;
    int     nXSize=0, nYSize=0;

    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    if (!GTiffOneTimeInit())
        return CE_Failure;

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( iBand = 0; iBand < nBands; iBand++ )
    {
        int     nBandBits, nBandFormat;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CInt32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( FALSE );
            return CE_Failure;
        }

        if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) )
        {
            nBandBits = 
                atoi(hBand->GetMetadataItem("NBITS","IMAGE_STRUCTURE"));

            if( nBandBits == 1 
                && EQUALN(pszResampling,"AVERAGE_BIT2",12) )
                nBandBits = 8;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != NULL )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize 
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL );

    if( pszCompress != NULL && pszCompress[0] != '\0' )
    {
        nCompression = GTIFFGetCompressionMethod(pszCompress, "COMPRESS_OVERVIEW");
        if (nCompression < 0)
            return CE_Failure;
    }
    
    if( nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8 )
    {  
        if( nBitsPerPixel > 16 )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " JPEG compressed overviews of nBitsPerPixel > 16." );
            return CE_Failure;
        }

        nBitsPerPixel = 12;
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL );
    if (pszInterleave != NULL && pszInterleave[0] != '\0')
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                      "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring",
                      pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != NULL 
             && !EQUALN(pszResampling,"AVERAGE_BIT2",12) )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        /* should set the colormap up at this point too! */
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL );
    if (pszPhotometric != NULL && pszPhotometric[0] != '\0')
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;

            /* Because of subsampling, setting YCBCR without JPEG compression leads */
            /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */
            /* aware of subsampling so that it doesn't overrun buffer size returned */
            /* by libtiff */
            if ( nCompression != COMPRESSION_JPEG )
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires COMPRESS_OVERVIEW=JPEG");
                return CE_Failure;
            }

            if (pszInterleave != NULL && pszInterleave[0] != '\0' && nPlanarConfig == PLANARCONFIG_SEPARATE)
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "PHOTOMETRIC_OVERVIEW=YCBCR requires INTERLEAVE_OVERVIEW=PIXEL");
                return CE_Failure;
            }
            else
            {
                nPlanarConfig = PLANARCONFIG_CONTIG;
            }

            /* YCBCR strictly requires 3 bands. Not less, not more */
            /* Issue an explicit error message as libtiff one is a bit cryptic : */
            /* JPEGLib:Bogus input colorspace */
            if ( nBands != 3 )
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)");
                return CE_Failure;
            }
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n",
                      pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the predictor value to use.                          */
/* -------------------------------------------------------------------- */
    int nPredictor = PREDICTOR_NONE;
    if ( nCompression == COMPRESSION_LZW ||
         nCompression == COMPRESSION_ADOBE_DEFLATE )
    {
        const char* pszPredictor = CPLGetConfigOption( "PREDICTOR_OVERVIEW", NULL );
        if( pszPredictor  != NULL )
        {
            nPredictor =  atoi( pszPredictor );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBufL  sStatBuf;
    VSILFILE* fpL = NULL;

    if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
    {
    /* -------------------------------------------------------------------- */
    /*      Compute the uncompressed size.                                  */
    /* -------------------------------------------------------------------- */
        double  dfUncompressedOverviewSize = 0;
        int nDataTypeSize = GDALGetDataTypeSize(papoBandList[0]->GetRasterDataType())/8;

        for( iOverview = 0; iOverview < nOverviews; iOverview++ )
        {
            int    nOXSize, nOYSize;

            nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
                / panOverviewList[iOverview];
            nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
                / panOverviewList[iOverview];

            dfUncompressedOverviewSize += 
                nOXSize * ((double)nOYSize) * nBands * nDataTypeSize;
        }

        if( nCompression == COMPRESSION_NONE 
            && dfUncompressedOverviewSize > 4200000000.0 )
        {
    #ifndef BIGTIFF_SUPPORT
            CPLError( CE_Failure, CPLE_NotSupported, 
                    "The overview file would be larger than 4GB\n"
                    "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n"
                    "Creation failed." );
            return CE_Failure;
    #endif
        }
    /* -------------------------------------------------------------------- */
    /*      Should the file be created as a bigtiff file?                   */
    /* -------------------------------------------------------------------- */
        const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", NULL );

        if( pszBIGTIFF == NULL )
            pszBIGTIFF = "IF_NEEDED";

        int bCreateBigTIFF = FALSE;
        if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
        {
            if( nCompression == COMPRESSION_NONE 
                && dfUncompressedOverviewSize > 4200000000.0 )
                bCreateBigTIFF = TRUE;
        }
        else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
        {
            /* Look at the size of the base image and suppose that */
            /* the added overview levels won't be more than 1/2 of */
            /* the size of the base image. The theory says 1/3 of the */
            /* base image size if the overview levels are 2, 4, 8, 16... */
            /* Thus take 1/2 as the security margin for 1/3 */
            double dfUncompressedImageSize =
                        nXSize * ((double)nYSize) * nBands * nDataTypeSize;
            if( dfUncompressedImageSize * .5 > 4200000000.0 )
                bCreateBigTIFF = TRUE;
        }
        else
        {
            bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF );
            if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE 
                && dfUncompressedOverviewSize > 4200000000.0 )
            {
                CPLError( CE_Failure, CPLE_NotSupported, 
                    "The overview file will be larger than 4GB, so BigTIFF is necessary.\n"
                    "Creation failed.");
                return CE_Failure;
            }
        }

    #ifndef BIGTIFF_SUPPORT
        if( bCreateBigTIFF )
        {
            CPLError( CE_Warning, CPLE_NotSupported,
                    "BigTIFF requested, but GDAL built without BigTIFF\n"
                    "enabled libtiff, request ignored." );
            bCreateBigTIFF = FALSE;
        }
    #endif

        if( bCreateBigTIFF )
            CPLDebug( "GTiff", "File being created as a BigTIFF." );

        fpL = VSIFOpenL( pszFilename, "w+" );
        if( fpL == NULL )
            hOTIFF = NULL;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, (bCreateBigTIFF) ? "w+8" : "w+", fpL );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in VSI_TIFFOpen().\n",
                          pszFilename );
            if( fpL != NULL )
                VSIFCloseL(fpL);
            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else 
    {
        fpL = VSIFOpenL( pszFilename, "r+" );
        if( fpL == NULL )
            hOTIFF = NULL;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in VSI_TIFFOpen().\n",
                          pszFilename );
            if( fpL != NULL )
                VSIFCloseL(fpL);
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short      *panRed=NULL, *panGreen=NULL, *panBlue=NULL;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;
        else
            nColorCount = 65536;

        panRed   = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panGreen = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panBlue  = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
            GDALColorEntry  sRGB;

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                panRed[iColor] = (unsigned short) (257 * sRGB.c1);
                panGreen[iColor] = (unsigned short) (257 * sRGB.c2);
                panBlue[iColor] = (unsigned short) (257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    int nOvrBlockXSize, nOvrBlockYSize;
    GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        int    nOXSize, nOYSize;

        nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];
        nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];

        GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE,
                            nOXSize, nOYSize, nBitsPerPixel, 
                            nPlanarConfig, nBands,
                            nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression,
                            nPhotometric, nSampleFormat, nPredictor,
                            panRed, panGreen, panBlue,
                            0, NULL, /* FIXME? how can we fetch extrasamples */
                            osMetadata );
    }

    if (panRed)
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = panGreen = panBlue = NULL;
    }

    XTIFFClose( hOTIFF );
    VSIFCloseL(fpL);
    fpL = NULL;

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS;
    CPLErr eErr = CE_None;

    hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update );
    if( hODS == NULL )
        return CE_Failure;
    
/* -------------------------------------------------------------------- */
/*      Do we need to set the jpeg quality?                             */
/* -------------------------------------------------------------------- */
    TIFF *hTIFF = (TIFF*) hODS->GetInternalHandle(NULL);

    if( nCompression == COMPRESSION_JPEG 
        && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", NULL ) != NULL )
    {
        int nJpegQuality = atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75"));
        TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, 
                      nJpegQuality );
        GTIFFSetJpegQuality((GDALDatasetH)hODS, nJpegQuality);
    }

/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    if (nCompression != COMPRESSION_NONE &&
        nPlanarConfig == PLANARCONFIG_CONTIG &&
        GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE &&
        papoBandList[0]->GetColorTable() == NULL &&
        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") ||
         EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") ||
         EQUAL(pszResampling, "CUBICSPLINE") || EQUAL(pszResampling, "LANCZOS") ||
         EQUAL(pszResampling, "BILINEAR")))
    {
        /* In the case of pixel interleaved compressed overviews, we want to generate */
        /* the overviews for all the bands block by block, and not band after band, */
        /* in order to write the block once and not loose space in the TIFF file */
        GDALRasterBand ***papapoOverviewBands;

        papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
        for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand = hODS->GetRasterBand( iBand+1 );
            papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews);
            papapoOverviewBands[iBand][0] = hDstBand;

            int bHasNoData;
            double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if (bHasNoData)
                hDstBand->SetNoDataValue(noDataValue);

            for( int i = 0; i < nOverviews-1 && eErr == CE_None; i++ )
            {
                papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i);
                if (papapoOverviewBands[iBand][i+1] == NULL)
                    eErr = CE_Failure;
                else
                {
                    if (bHasNoData)
                        papapoOverviewBands[iBand][i+1]->SetNoDataValue(noDataValue);
                }
            }
        }

        if (eErr == CE_None)
            eErr = GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
                                            nOverviews, papapoOverviewBands,
                                            pszResampling, pfnProgress, pProgressData );

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand   **papoOverviews;

        papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128);

        for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand;
            int               nDstOverviews;

            hDstBand = hODS->GetRasterBand( iBand+1 );

            int bHasNoData;
            double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if (bHasNoData)
                hDstBand->SetNoDataValue(noDataValue);

            papoOverviews[0] = hDstBand;
            nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < 128 );
            nDstOverviews = MIN(128,nDstOverviews);

            for( int i = 0; i < nDstOverviews-1 && eErr == CE_None; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
                if (papoOverviews[i+1] == NULL)
                    eErr = CE_Failure;
                else
                {
                    if (bHasNoData)
                        papoOverviews[i+1]->SetNoDataValue(noDataValue);
                }
            }

            void         *pScaledProgressData;

            pScaledProgressData = 
                GDALCreateScaledProgress( iBand / (double) nBands, 
                                        (iBand+1) / (double) nBands,
                                        pfnProgress, pProgressData );

            if (eErr == CE_None)
                eErr = 
                    GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand, 
                                        nDstOverviews, 
                                        (GDALRasterBandH *) papoOverviews, 
                                        pszResampling,
                                        GDALScaledProgress, 
                                        pScaledProgressData);

            GDALDestroyScaledProgress( pScaledProgressData );
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    if (eErr == CE_None)
        hODS->FlushCache();
    delete hODS;

    pfnProgress( 1.0, NULL, pProgressData );

    return eErr;
}
예제 #22
0
CPLErr 
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList, 
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling, 
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    TIFF    *hOTIFF;
    int     nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0;
    int     nSampleFormat=0, nPlanarConfig, iOverview, iBand;
    int     nXSize=0, nYSize=0;

    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    GTiffOneTimeInit();

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( iBand = 0; iBand < nBands; iBand++ )
    {
        int     nBandBits, nBandFormat;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( FALSE );
            return CE_Failure;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != NULL )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize 
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL );

    if( pszCompress != NULL && pszCompress[0] != '\0' )
    {
        if( EQUAL( pszCompress, "JPEG" ) )
            nCompression = COMPRESSION_JPEG;
        else if( EQUAL( pszCompress, "LZW" ) )
            nCompression = COMPRESSION_LZW;
        else if( EQUAL( pszCompress, "PACKBITS" ))
            nCompression = COMPRESSION_PACKBITS;
        else if( EQUAL( pszCompress, "DEFLATE" ) || EQUAL( pszCompress, "ZIP" ))
            nCompression = COMPRESSION_ADOBE_DEFLATE;
        else
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "COMPRESS_OVERVIEW=%s value not recognised, ignoring.",
                      pszCompress );
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL );
    if (pszInterleave != NULL && pszInterleave[0] != '\0')
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                      "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring",
                      pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != NULL 
             && !EQUALN(pszResampling,"AVERAGE_BIT2",12) )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        /* should set the colormap up at this point too! */
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL );
    if (pszPhotometric != NULL && pszPhotometric[0] != '\0')
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n",
                      pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBuf  sStatBuf;

    if( VSIStat( pszFilename, &sStatBuf ) != 0 )
    {
        hOTIFF = XTIFFOpen( pszFilename, "w+" );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in XTIFFOpen().\n",
                          pszFilename );

            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else 
    {
        hOTIFF = XTIFFOpen( pszFilename, "r+" );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in XTIFFOpen().\n",
                          pszFilename );

            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short      *panRed=NULL, *panGreen=NULL, *panBlue=NULL;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;
        else
            nColorCount = 65536;

        panRed   = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panGreen = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panBlue  = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
            GDALColorEntry  sRGB;

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                panRed[iColor] = (unsigned short) (257 * sRGB.c1);
                panGreen[iColor] = (unsigned short) (257 * sRGB.c2);
                panBlue[iColor] = (unsigned short) (257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        int    nOXSize, nOYSize;
        uint32 nDirOffset;

        nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];
        nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];

        nDirOffset = 
            GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE,
                                nOXSize, nOYSize, nBitsPerPixel, 
                                nPlanarConfig, nBands,
                                128, 128, TRUE, nCompression,
                                nPhotometric, nSampleFormat, 
                                panRed, panGreen, panBlue,
                                0, NULL, /* FIXME ? how can we fetch extrasamples from here */
                                osMetadata );
    }

    if (panRed)
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = panGreen = panBlue = NULL;
    }

    XTIFFClose( hOTIFF );

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS;

    hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update );
    if( hODS == NULL )
        return CE_Failure;
    
/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    if (nCompression != COMPRESSION_NONE &&
        nPlanarConfig == PLANARCONFIG_CONTIG &&
        GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE &&
        papoBandList[0]->GetColorTable() == NULL &&
        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
    {
        /* In the case of pixel interleaved compressed overviews, we want to generate */
        /* the overviews for all the bands block by block, and not band after band, */
        /* in order to write the block once and not loose space in the TIFF file */

        GDALRasterBand ***papapoOverviewBands;

        papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
        for( iBand = 0; iBand < nBands; iBand++ )
        {
            GDALRasterBand    *hDstBand = hODS->GetRasterBand( iBand+1 );
            papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews);
            papapoOverviewBands[iBand][0] = hDstBand;
            for( int i = 0; i < nOverviews-1; i++ )
            {
                papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i);
            }
        }

        GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
                                         nOverviews, papapoOverviewBands,
                                         pszResampling, pfnProgress, pProgressData );

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand   **papoOverviews;

        papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128);

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand;
            int               nDstOverviews;
            CPLErr            eErr;

            hDstBand = hODS->GetRasterBand( iBand+1 );

            papoOverviews[0] = hDstBand;
            nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < 128 );
            nDstOverviews = MIN(128,nDstOverviews);

            for( int i = 0; i < nDstOverviews-1; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
            }

            void         *pScaledProgressData;

            pScaledProgressData = 
                GDALCreateScaledProgress( iBand / (double) nBands, 
                                        (iBand+1) / (double) nBands,
                                        pfnProgress, pProgressData );

            eErr = 
                GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand, 
                                        nDstOverviews, 
                                        (GDALRasterBandH *) papoOverviews, 
                                        pszResampling,
                                        GDALScaledProgress, 
                                        pScaledProgressData);

            GDALDestroyScaledProgress( pScaledProgressData );

            if( eErr != CE_None )
            {
                delete hODS;
                return eErr;
            }
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    hODS->FlushCache();
    delete hODS;

    pfnProgress( 1.0, NULL, pProgressData );

    return CE_None;
}
예제 #23
0
bool GdalAdapter::loadImage(const QString& fn)
{
    if (alreadyLoaded(fn))
        return true;

    QFileInfo fi(fn);
    GdalImage img;
    QRectF bbox;

    poDataset = (GDALDataset *) GDALOpen( QDir::toNativeSeparators(fi.absoluteFilePath()).toUtf8().constData(), GA_ReadOnly );
    if( poDataset == NULL )
    {
        qDebug() <<  "GDAL Open failed: " << fn;
        return false;
    }

    bool hasGeo = false;
    QDir dir(fi.absoluteDir());
    QString f = fi.baseName();
    QStringList wldFilter;
    wldFilter <<  f+".tfw" << f+".tifw" << f+".tiffw" << f+".wld";
    QFileInfoList fil = dir.entryInfoList(wldFilter);
    if (fil.count()) {
        QFile wld(fil[0].absoluteFilePath());
        if (wld.open(QIODevice::ReadOnly)) {
            int i;
            for (i=0; i<6; ++i) {
                if (wld.atEnd())
                    break;
                QString l = wld.readLine();
                bool ok;
                double d = l.toDouble(&ok);
                if (!ok)
                    break;
                switch (i) {
                case 0:
                    img.adfGeoTransform[1] = d;
                    break;
                case 1:
                    img.adfGeoTransform[4] = d;
                    break;
                case 2:
                    img.adfGeoTransform[2] = d;
                    break;
                case 3:
                    img.adfGeoTransform[5] = d;
                    break;
                case 4:
                    img.adfGeoTransform[0] = d;
                    break;
                case 5:
                    img.adfGeoTransform[3] = d;
                    break;
                }

            }
            if (i == 6)
                hasGeo = true;
        }
    }
    if(!hasGeo)
        if ( poDataset->GetGeoTransform( img.adfGeoTransform ) != CE_None ) {
            GDALClose((GDALDatasetH)poDataset);
            return false;
        }

    qDebug( "Origin = (%.6f,%.6f)\n",
            img.adfGeoTransform[0], img.adfGeoTransform[3] );

    qDebug( "Pixel Size = (%.6f,%.6f)\n",
            img.adfGeoTransform[1], img.adfGeoTransform[5] );

    bbox.setTopLeft(QPointF(img.adfGeoTransform[0], img.adfGeoTransform[3]));
    bbox.setWidth(img.adfGeoTransform[1]*poDataset->GetRasterXSize());
    bbox.setHeight(img.adfGeoTransform[5]*poDataset->GetRasterYSize());

    isLatLon = false;
    if( strlen(poDataset->GetProjectionRef()) != 0 ) {
        qDebug( "Projection is `%s'\n", poDataset->GetProjectionRef() );
        OGRSpatialReference* theSrs = new OGRSpatialReference(poDataset->GetProjectionRef());
        if (theSrs && theSrs->Validate() == OGRERR_NONE) {
            theSrs->morphFromESRI();
            char* theProj4;
            if (theSrs->exportToProj4(&theProj4) == OGRERR_NONE) {
                qDebug() << "GDAL: to proj4 : " << theProj4;
            } else {
                qDebug() << "GDAL: to proj4 error: " << CPLGetLastErrorMsg();
                GDALClose((GDALDatasetH)poDataset);
                return false;
            }
            QString srsProj = QString(theProj4);
            if (!srsProj.isEmpty() && theProjection != srsProj) {
                cleanup();
                theProjection = srsProj;
            }
            isLatLon = (theSrs->IsGeographic() == TRUE);
        }
    }
    if (theProjection.isEmpty()) {
        theProjection = ProjectionChooser::getProjection(QCoreApplication::translate("ImportExportGdal", "Unable to set projection; please specify one"));
        if (theProjection.isEmpty()) {
            GDALClose((GDALDatasetH)poDataset);
            return false;
        }
    }

    qDebug( "Driver: %s/%s\n",
            poDataset->GetDriver()->GetDescription(),
            poDataset->GetDriver()->GetMetadataItem( GDAL_DMD_LONGNAME ) );

    qDebug( "Size is %dx%dx%d\n",
            poDataset->GetRasterXSize(), poDataset->GetRasterYSize(),
            poDataset->GetRasterCount() );

    GdalAdapter::ImgType theType = GdalAdapter::Unknown;
    int bandCount = poDataset->GetRasterCount();
    int ixA = -1;
    int ixR, ixG, ixB;
    int ixH, ixS, ixL;
    int ixC, ixM, ixY, ixK;
    int ixYuvY, ixYuvU, ixYuvV;
    double adfMinMax[2];
    double UnknownUnit;
    GDALColorTable* colTable = NULL;
    for (int i=0; i<bandCount; ++i) {
        GDALRasterBand  *poBand = poDataset->GetRasterBand( i+1 );
        GDALColorInterp bandtype = poBand->GetColorInterpretation();
        qDebug() << "Band " << i+1 << " Color: " <<  GDALGetColorInterpretationName(poBand->GetColorInterpretation());

        switch (bandtype)
        {
        case GCI_Undefined:
            theType = GdalAdapter::Unknown;
            int             bGotMin, bGotMax;
            adfMinMax[0] = poBand->GetMinimum( &bGotMin );
            adfMinMax[1] = poBand->GetMaximum( &bGotMax );
            if( ! (bGotMin && bGotMax) )
                GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);
            UnknownUnit = (adfMinMax[1] - adfMinMax[0]) / 256;
            break;
        case GCI_GrayIndex:
            theType = GdalAdapter::GrayScale;
            break;
        case GCI_RedBand:
            theType = GdalAdapter::Rgb;
            ixR = i;
            break;
        case GCI_GreenBand:
            theType = GdalAdapter::Rgb;
            ixG = i;
            break;
        case GCI_BlueBand :
            theType = GdalAdapter::Rgb;
            ixB = i;
            break;
        case GCI_HueBand:
            theType = GdalAdapter::Hsl;
            ixH = i;
            break;
        case GCI_SaturationBand:
            theType = GdalAdapter::Hsl;
            ixS = i;
            break;
        case GCI_LightnessBand:
            theType = GdalAdapter::Hsl;
            ixL = i;
            break;
        case GCI_CyanBand:
            theType = GdalAdapter::Cmyk;
            ixC = i;
            break;
        case GCI_MagentaBand:
            theType = GdalAdapter::Cmyk;
            ixM = i;
            break;
        case GCI_YellowBand:
            theType = GdalAdapter::Cmyk;
            ixY = i;
            break;
        case GCI_BlackBand:
            theType = GdalAdapter::Cmyk;
            ixK = i;
            break;
        case GCI_YCbCr_YBand:
            theType = GdalAdapter::YUV;
            ixYuvY = i;
            break;
        case GCI_YCbCr_CbBand:
            theType = GdalAdapter::YUV;
            ixYuvU = i;
            break;
        case GCI_YCbCr_CrBand:
            theType = GdalAdapter::YUV;
            ixYuvV = i;
            break;
        case GCI_AlphaBand:
            ixA = i;
            break;
        case GCI_PaletteIndex:
            colTable = poBand->GetColorTable();
            switch (colTable->GetPaletteInterpretation())
            {
            case GPI_Gray :
                theType = GdalAdapter::Palette_Gray;
                break;
            case GPI_RGB :
                theType = GdalAdapter::Palette_RGBA;
                break;
            case GPI_CMYK :
                theType = GdalAdapter::Palette_CMYK;
                break;
            case GPI_HLS :
                theType = GdalAdapter::Palette_HLS;
                break;
            }
            break;
        }
    }

    QSize theImgSize(poDataset->GetRasterXSize(), poDataset->GetRasterYSize());
    QImage theImg = QImage(theImgSize, QImage::Format_ARGB32);

    // Make sure that lineBuf holds one whole line of data.
    float *lineBuf;
    lineBuf = (float *) CPLMalloc(theImgSize.width() * bandCount * sizeof(float));

    int px, py;
    //every row loop
    for (int row = 0; row < theImgSize.height(); row++) {
        py = row;
        poDataset->RasterIO( GF_Read, 0, row, theImgSize.width(), 1, lineBuf, theImgSize.width(), 1, GDT_Float32,
                            bandCount, NULL, sizeof(float) * bandCount, 0, sizeof(float) );
        // every pixel in row.
        for (int col = 0; col < theImgSize.width(); col++){
            px = col;
            switch (theType)
            {
            case GdalAdapter::Unknown:
            {
                float* v = lineBuf + (col*bandCount);
                float val = (*v - adfMinMax[0]) / UnknownUnit;
                theImg.setPixel(px, py, qRgb(val, val, val));
                break;
            }
            case GdalAdapter::GrayScale:
            {
                float* v = lineBuf + (col*bandCount);
                theImg.setPixel(px, py, qRgb(*v, *v, *v));
                break;
            }
            case GdalAdapter::Rgb:
            {
                float* r = lineBuf + (col*bandCount) + ixR;
                float* g = lineBuf + (col*bandCount) + ixG;
                float* b = lineBuf + (col*bandCount) + ixB;
                int a = 255;
                if (ixA != -1) {
                    float* fa = lineBuf + (col*bandCount) + ixA;
                    a = *fa;
                }
                theImg.setPixel(px, py, qRgba(*r, *g, *b, a));
                break;
            }
#if QT_VERSION >= 0x040600
            case GdalAdapter::Hsl:
            {
                float* h = lineBuf + (col*bandCount) + ixH;
                float* s = lineBuf + (col*bandCount) + ixS;
                float* l = lineBuf + (col*bandCount) + ixL;
                int a = 255;
                if (ixA != -1) {
                    float* fa = lineBuf + (col*bandCount) + ixA;
                    a = *fa;
                }
                QColor C = QColor::fromHsl(*h, *s, *l, a);
                theImg.setPixel(px, py, C.rgba());
                break;
            }
#endif
            case GdalAdapter::Cmyk:
            {
                float* c = lineBuf + (col*bandCount) + ixC;
                float* m = lineBuf + (col*bandCount) + ixM;
                float* y = lineBuf + (col*bandCount) + ixY;
                float* k = lineBuf + (col*bandCount) + ixK;
                int a = 255;
                if (ixA != -1) {
                    float* fa = lineBuf + (col*bandCount) + ixA;
                    a = *fa;
                }
                QColor C = QColor::fromCmyk(*c, *m, *y, *k, a);
                theImg.setPixel(px, py, C.rgba());
                break;
            }
            case GdalAdapter::YUV:
            {
                // From http://www.fourcc.org/fccyvrgb.php
                float* y = lineBuf + (col*bandCount) + ixYuvY;
                float* u = lineBuf + (col*bandCount) + ixYuvU;
                float* v = lineBuf + (col*bandCount) + ixYuvV;
                int a = 255;
                if (ixA != -1) {
                    float* fa = lineBuf + (col*bandCount) + ixA;
                    a = *fa;
                }
                float R = 1.164*(*y - 16) + 1.596*(*v - 128);
                float G = 1.164*(*y - 16) - 0.813*(*v - 128) - 0.391*(*u - 128);
                float B = 1.164*(*y - 16) + 2.018*(*u - 128);

                theImg.setPixel(px, py, qRgba(R, G, B, a));
                break;
            }
            case GdalAdapter::Palette_Gray:
            {
                float* ix = (lineBuf + (col*bandCount));
                const GDALColorEntry* color = colTable->GetColorEntry(*ix);
                theImg.setPixel(px, py, qRgb(color->c1, color->c1, color->c1));
                break;
            }
            case GdalAdapter::Palette_RGBA:
            {
                float* ix = (lineBuf + (col*bandCount));
                const GDALColorEntry* color = colTable->GetColorEntry(*ix);
                theImg.setPixel(px, py, qRgba(color->c1, color->c2, color->c3, color->c4));
                break;
            }
#if QT_VERSION >= 0x040600
            case GdalAdapter::Palette_HLS:
            {
                float* ix = (lineBuf + (col*bandCount));
                const GDALColorEntry* color = colTable->GetColorEntry(*ix);
                QColor C = QColor::fromHsl(color->c1, color->c2, color->c3, color->c4);
                theImg.setPixel(px, py, C.rgba());
                break;
            }
#endif
            case GdalAdapter::Palette_CMYK:
            {
                float* ix = (lineBuf + (col*bandCount));
                const GDALColorEntry* color = colTable->GetColorEntry(*ix);
                QColor C = QColor::fromCmyk(color->c1, color->c2, color->c3, color->c4);
                theImg.setPixel(px, py, C.rgba());
                break;
            }
            }
        }
        QCoreApplication::processEvents();
    }

    img.theFilename = fn;
    img.theImg = QPixmap::fromImage(theImg);
    theImages.push_back(img);
    theBbox = theBbox.united(bbox);

    GDALClose((GDALDatasetH)poDataset);
    return true;
}
예제 #24
0
CPLErr GDALWMSRasterBand::ReadBlockFromFile(int x, int y, const char *file_name, int to_buffer_band, void *buffer, int advise_read) {
    CPLErr ret = CE_None;
    GDALDataset *ds = 0;
    GByte *color_table = NULL;
    int i;

    //CPLDebug("WMS", "ReadBlockFromFile: to_buffer_band=%d, (x,y)=(%d, %d)", to_buffer_band, x, y);

    /* expected size */
    const int esx = MIN(MAX(0, (x + 1) * nBlockXSize), nRasterXSize) - MIN(MAX(0, x * nBlockXSize), nRasterXSize);
    const int esy = MIN(MAX(0, (y + 1) * nBlockYSize), nRasterYSize) - MIN(MAX(0, y * nBlockYSize), nRasterYSize);
    ds = reinterpret_cast<GDALDataset*>(GDALOpen(file_name, GA_ReadOnly));
    if (ds != NULL) {
        int sx = ds->GetRasterXSize();
        int sy = ds->GetRasterYSize();
        bool accepted_as_no_alpha = false;  // if the request is for 4 bands but the wms returns 3  
        /* Allow bigger than expected so pre-tiled constant size images work on corners */
        if ((sx > nBlockXSize) || (sy > nBlockYSize) || (sx < esx) || (sy < esy)) {
            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect size %d x %d of downloaded block, expected %d x %d, max %d x %d.",
                sx, sy, esx, esy, nBlockXSize, nBlockYSize);
            ret = CE_Failure;
        }
        if (ret == CE_None) {
            int nDSRasterCount = ds->GetRasterCount();
            if (nDSRasterCount != m_parent_dataset->nBands) {
                /* Maybe its an image with color table */
                bool accepted_as_ct = false;
                if ((eDataType == GDT_Byte) && (ds->GetRasterCount() == 1)) {
                    GDALRasterBand *rb = ds->GetRasterBand(1);
                    if (rb->GetRasterDataType() == GDT_Byte) {
                        GDALColorTable *ct = rb->GetColorTable();
                        if (ct != NULL) {
                            accepted_as_ct = true;
                            if (!advise_read) {
                                color_table = new GByte[256 * 4];
                                const int count = MIN(256, ct->GetColorEntryCount());
                                for (i = 0; i < count; ++i) {
                                    GDALColorEntry ce;
                                    ct->GetColorEntryAsRGB(i, &ce);
                                    color_table[i] = static_cast<GByte>(ce.c1);
                                    color_table[i + 256] = static_cast<GByte>(ce.c2);
                                    color_table[i + 512] = static_cast<GByte>(ce.c3);
                                    color_table[i + 768] = static_cast<GByte>(ce.c4);
                                }
                                for (i = count; i < 256; ++i) {
                                    color_table[i] = 0;
                                    color_table[i + 256] = 0;
                                    color_table[i + 512] = 0;
                                    color_table[i + 768] = 0;
                                }
                            }
                        }
                    }
                }

                if (nDSRasterCount == 4 && m_parent_dataset->nBands == 3)
                {
                    /* metacarta TMS service sometimes return a 4 band PNG instead of the expected 3 band... */
                }
                else if (!accepted_as_ct) {
                   if (ds->GetRasterCount()==3 && m_parent_dataset->nBands == 4 && (eDataType == GDT_Byte))
                   { // WMS returned a file with no alpha so we will fill the alpha band with "opaque" 
                      accepted_as_no_alpha = true;
                   }
                   else
                   {
                      CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.",
                         nDSRasterCount, m_parent_dataset->nBands);
                      ret = CE_Failure;
                   }
                }
            }
        }
        if (!advise_read) {
            for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
                if (ret == CE_None) {
                    void *p = NULL;
                    GDALRasterBlock *b = NULL;
                    if ((buffer != NULL) && (ib == to_buffer_band)) {
                        p = buffer;
                    } else {
                        GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
                        if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
                        if (!band->IsBlockInCache(x, y)) {
                            b = band->GetLockedBlockRef(x, y, true);
                            if (b != NULL) {
                                p = b->GetDataRef();
                                if (p == NULL) {
                                  CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL.");
                                  ret = CE_Failure;
                                }
                            }
                        }
                        else
                        {
                            //CPLDebug("WMS", "Band %d, block (x,y)=(%d, %d) already in cache", band->GetBand(), x, y);
                        }
                    }
                    if (p != NULL) {
                        int pixel_space = GDALGetDataTypeSize(eDataType) / 8;
                        int line_space = pixel_space * nBlockXSize;
                        if (color_table == NULL) {
                            if( ib <= ds->GetRasterCount()) {
                               if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, &ib, pixel_space, line_space, 0) != CE_None) {
                                   CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
                                   ret = CE_Failure;
                               }
                            }
                            else
                            {  // parent expects 4 bands but file only has 3 so generate a all "opaque" 4th band
                               if (accepted_as_no_alpha)
                               {
                                  // the file had 3 bands and we are reading band 4 (Alpha) so fill with 255 (no alpha)
                                  GByte *byte_buffer = reinterpret_cast<GByte *>(p);
                                  for (int y = 0; y < sy; ++y) {
                                     for (int x = 0; x < sx; ++x) {
                                        const int offset = x + y * line_space;
                                        byte_buffer[offset] = 255;  // fill with opaque
                                     }
                                  }
                               }
                               else
                               {  // we should never get here because this case was caught above
                                  CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.",
                                     ds->GetRasterCount(), m_parent_dataset->nBands);
                                  ret = CE_Failure;
                               }     
                            }
                        } else if (ib <= 4) {
                            if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, NULL, pixel_space, line_space, 0) != CE_None) {
                                CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
                                ret = CE_Failure;
                            }
                            if (ret == CE_None) {
                                GByte *band_color_table = color_table + 256 * (ib - 1);
                                GByte *byte_buffer = reinterpret_cast<GByte *>(p);
                                for (int y = 0; y < sy; ++y) {
                                    for (int x = 0; x < sx; ++x) {
                                        const int offset = x + y * line_space;
                                        byte_buffer[offset] = band_color_table[byte_buffer[offset]];
                                    }
                                }
                            }
                        } else {
                            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Color table supports at most 4 components.");
                            ret = CE_Failure;
                        }
                    }
                    if (b != NULL) {
                        b->DropLock();
                    }
                }
            }
        }
        GDALClose(ds);
    } else {
        CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to open downloaded block.");
        ret = CE_Failure;
    }

    if (color_table != NULL) {
        delete[] color_table;
    }

    return ret;
}
예제 #25
0
std::tuple<boost::shared_ptr<Map_Matrix<DataFormat> >, std::string, GeoTransform>  read_in_map(fs::path file_path, GDALDataType data_type, const bool doCategorise) throw(std::runtime_error)
{

    std::string projection;
    GeoTransform transformation;
    GDALDriver driver;
    
	//Check that the file name is valid
	if (!(fs::is_regular_file(file_path)))
	{
		throw std::runtime_error("Input file is not a regular file");
	}	

	// Get GDAL to open the file - code is based on the tutorial at http://www.gdal.org/gdal_tutorial.html
	GDALDataset *poDataset;
	GDALAllRegister(); //This registers all availble raster file formats for use with this utility. How neat is that. We can input any GDAL supported rater file format.

	//Open the Raster by calling GDALOpen. http://www.gdal.org/gdal_8h.html#a6836f0f810396c5e45622c8ef94624d4
	//char pszfilename[] = file_path.c_str(); //Set this to the file name, as GDALOpen requires the standard C char pointer as function parameter.
	poDataset = (GDALDataset *) GDALOpen (file_path.string().c_str(), GA_ReadOnly);
	if (poDataset == NULL)
	{
		throw std::runtime_error("Unable to open file");
	}
	
//	Print some general information about the raster
	double        adfGeoTransform[6]; //An array of doubles that will be used to save information about the raster - where the origin is, what the raster pizel size is.
    
    
    printf( "Driver: %s/%s\n",
            poDataset->GetDriver()->GetDescription(),
            poDataset->GetDriver()->GetMetadataItem( GDAL_DMD_LONGNAME ) );

    printf( "Size is %dx%dx%d\n", 
            poDataset->GetRasterXSize(), poDataset->GetRasterYSize(),
            poDataset->GetRasterCount() );

    if( poDataset->GetProjectionRef()  != NULL )
    {
        printf( "Projection is `%s'\n", poDataset->GetProjectionRef() );
        projection = poDataset->GetProjectionRef();
    }

    if( poDataset->GetGeoTransform( adfGeoTransform ) == CE_None )
    {
        printf( "Origin = (%.6f,%.6f)\n",
                adfGeoTransform[0], adfGeoTransform[3] );

        printf( "Pixel Size = (%.6f,%.6f)\n",
                adfGeoTransform[1], adfGeoTransform[5] );
        
        transformation.x_origin = adfGeoTransform[0];
        transformation.pixel_width = adfGeoTransform[1];
        transformation.x_line_space = adfGeoTransform[2];
        transformation.y_origin = adfGeoTransform[3];
        transformation.pixel_height = adfGeoTransform[4];
        transformation.y_line_space = adfGeoTransform[5];
        
    }


	/// Some raster file formats allow many layers of data (called a 'band', with each having the same pixel size and origin location and spatial extent). We will get the data for the first layer into a Boost Array.
	//Get the data from the first band, 
	// TODO implement method with input to specify what band.
	    GDALRasterBand  *poBand;
        int             nBlockXSize, nBlockYSize;
        int             bGotMin, bGotMax;
        double          adfMinMax[2];
        
        poBand = poDataset->GetRasterBand( 1 );
        poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
        printf( "Block=%dx%d Type=%s, ColorInterp=%s\n",
                nBlockXSize, nBlockYSize,
                GDALGetDataTypeName(poBand->GetRasterDataType()),
                GDALGetColorInterpretationName(
                    poBand->GetColorInterpretation()) );

        adfMinMax[0] = poBand->GetMinimum( &bGotMin );
        adfMinMax[1] = poBand->GetMaximum( &bGotMax );
        if( ! (bGotMin && bGotMax) )
            GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);

        printf( "Min=%.3fd, Max=%.3f\n", adfMinMax[0], adfMinMax[1] );
        
        if( poBand->GetOverviewCount() > 0 )
            printf( "Band has %d overviews.\n", poBand->GetOverviewCount() );

        if( poBand->GetColorTable() != NULL )
            printf( "Band has a color table with %d entries.\n", 
                     poBand->GetColorTable()->GetColorEntryCount() );

		DataFormat * pafScanline;
        int   nXSize = poBand->GetXSize();
		int   nYSize = poBand->GetYSize();
		boost::shared_ptr<Map_Matrix<DataFormat> > in_map(new Map_Matrix<DataFormat>(nYSize, nXSize));
		//get a c array of this size and read into this.
		
		
		//pafScanline = new DataFormat[nXSize];
		//for (int i = 0; i < nYSize; i++) //rows
		//{
		//	poBand->RasterIO(GF_Read, 0, i, nXSize, 1,
		//		pafScanline, nXSize, 1, data_type,
		//		0, 0);
		//	for (int j = 0; j < nXSize; j++) //cols
		//	{
		//		in_map->Get(i, j) = pafScanline[j];
		//	}
		//}
    
        //get a c array of this size and read into this.
        pafScanline = new DataFormat[nXSize * nYSize];
        //pafScanline = (float *) CPLMalloc(sizeof(float)*nXSize);
        poBand->RasterIO( GF_Read, 0, 0, nXSize, nYSize, 
			pafScanline, nXSize, nYSize, data_type,
                          0, 0 );
    
        //Copy into Map_Matrix.
        int pafIterator = 0;
		// Note: Map Matrixes indexes are in opposite order to C arrays. e.g. map matrix is indexed by (row, Col) which is (y, x) and c matrices are done by (x, y) which is (Col, Row)
        
        //for (int i = 0; i < nXSize; i++)
        //{
        //    for(int j = 0; j < nYSize; j++)
        //    {
        //        in_map->Get(j, i) = pafScanline[pafIterator];
        //        pafIterator++;
        //    }
        //}		
		for (int i = 0; i < nYSize; i++) //rows
		{
			for (int j = 0; j < nXSize; j++) //cols
			{
				in_map->Get(i, j) = pafScanline[pafIterator];
				pafIterator++;
			}
		}


    
    //free the c array storage
    delete pafScanline;
    int pbsuccess; // can be used with get no data value
    in_map->SetNoDataValue(poBand->GetNoDataValue(&pbsuccess));
    //This creates a list (map?) listing all the unique values contained in the raster.
	if (doCategorise) in_map->updateCategories();

    
	//Close GDAL, freeing the memory GDAL is using
	GDALClose( (GDALDatasetH)poDataset);

    return (std::make_tuple(in_map, projection, transformation));
}
feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
{
    feature_ptr feature(new Feature(1));

    GDALRasterBand * red = 0;
    GDALRasterBand * green = 0;
    GDALRasterBand * blue = 0;
    GDALRasterBand * alpha = 0;
    GDALRasterBand * grey = 0; 
   
    /*
    double tr[6];
    dataset_.GetGeoTransform(tr);
    
    double dx = tr[1];
    double dy = tr[5];
    std::clog << "dx_: " << dx_ << " dx: " << dx << " dy_: " << dy_ << "dy: " << dy << "\n";
    */
          
    CoordTransform t(raster_width_,raster_height_,raster_extent_,0,0);
    box2d<double> intersect = raster_extent_.intersect(q.get_bbox());
    box2d<double> box = t.forward(intersect);

    //size of resized output pixel in source image domain
    double margin_x = 1.0/(fabs(dx_)*boost::get<0>(q.resolution()));
    double margin_y = 1.0/(fabs(dy_)*boost::get<1>(q.resolution()));
    if (margin_x < 1)
        margin_x = 1.0;
    if (margin_y < 1)
        margin_y = 1.0;
    //select minimum raster containing whole box
    int x_off = rint(box.minx() - margin_x);
    int y_off = rint(box.miny() - margin_y);
    int end_x = rint(box.maxx() + margin_x);
    int end_y = rint(box.maxy() + margin_y);
    //clip to available data
    if (x_off < 0)
        x_off = 0;
    if (y_off < 0)
        y_off = 0;
    if (end_x > (int)raster_width_)
        end_x = raster_width_;
    if (end_y > (int)raster_height_)
        end_y = raster_height_;
    int width = end_x - x_off;
    int height = end_y - y_off;
    // don't process almost invisible data
    if (box.width() < 0.5)
        width = 0;
    if (box.height() < 0.5)
        height = 0;
    //calculate actual box2d of returned raster
    box2d<double> feature_raster_extent(x_off, y_off, x_off+width, y_off+height); 
    intersect = t.backward(feature_raster_extent);
    
#ifdef MAPNIK_DEBUG         
    std::clog << "GDAL Plugin: Raster extent=" << raster_extent_ << std::endl;
    std::clog << "GDAL Plugin: View extent=" << intersect << std::endl;
    std::clog << "GDAL Plugin: Query resolution=" << boost::get<0>(q.resolution()) << "," << boost::get<1>(q.resolution()) << std::endl;
    std::clog << boost::format("GDAL Plugin: StartX=%d StartY=%d Width=%d Height=%d") % x_off % y_off % width % height << std::endl;
#endif
   
    if (width > 0 && height > 0)
    {
        double width_res = boost::get<0>(q.resolution());
        double height_res = boost::get<1>(q.resolution());
        int im_width = int(width_res * intersect.width() + 0.5);
        int im_height = int(height_res * intersect.height() + 0.5);
        
        // if layer-level filter_factor is set, apply it
        if (filter_factor_)
        {
            im_width *= filter_factor_;
            im_height *= filter_factor_;
        }
        // otherwise respect symbolizer level factor applied to query, default of 1.0
        else
        {
            double sym_downsample_factor = q.get_filter_factor();
            im_width *= sym_downsample_factor;
            im_height *= sym_downsample_factor;
        }

        // case where we need to avoid upsampling so that the
        // image can be later scaled within raster_symbolizer 
        if (im_width >= width || im_height >= height)
        {
            im_width = width;
            im_height = height;
        }

        if (im_width > 0 && im_height > 0)
        {
            mapnik::image_data_32 image(im_width, im_height);
            image.set(0xffffffff); 
             
#ifdef MAPNIK_DEBUG
            std::clog << "GDAL Plugin: Image Size=(" << im_width << "," << im_height << ")" << std::endl;
            std::clog << "GDAL Plugin: Reading band " << band_ << std::endl;
#endif
            typedef std::vector<int,int> pallete;
        
            if (band_ > 0) // we are querying a single band
            {
                if (band_ > nbands_)
                    throw datasource_exception((boost::format("GDAL Plugin: '%d' is an invalid band, dataset only has '%d' bands\n") % band_ % nbands_).str());
                float *imageData = (float*)image.getBytes();
                GDALRasterBand * band = dataset_.GetRasterBand(band_);
                band->RasterIO(GF_Read, x_off, y_off, width, height,
                               imageData, image.width(), image.height(),
                               GDT_Float32, 0, 0);
    
                feature->set_raster(mapnik::raster_ptr(new mapnik::raster(intersect,image)));
            }
          
            else // working with all bands
            {
                for (int i = 0; i < nbands_; ++i)
                {
                    GDALRasterBand * band = dataset_.GetRasterBand(i+1);
             
#ifdef MAPNIK_DEBUG
                    get_overview_meta(band);  
#endif
    
                    GDALColorInterp color_interp = band->GetColorInterpretation();
                    switch (color_interp)
                    {
                    case GCI_RedBand:
                        red = band;
#ifdef MAPNIK_DEBUG
                        std::clog << "GDAL Plugin: Found red band" << std::endl;
#endif
                        break;
                    case GCI_GreenBand:
                        green = band;
#ifdef MAPNIK_DEBUG
                        std::clog << "GDAL Plugin: Found green band" << std::endl;
#endif
                        break;
                    case GCI_BlueBand:
                        blue = band;
#ifdef MAPNIK_DEBUG
                        std::clog << "GDAL Plugin: Found blue band" << std::endl;
#endif
                        break;
                    case GCI_AlphaBand:
                        alpha = band;
#ifdef MAPNIK_DEBUG
                        std::clog << "GDAL Plugin: Found alpha band" << std::endl;
#endif
                        break;
                    case GCI_GrayIndex:
                        grey = band;
#ifdef MAPNIK_DEBUG
                        std::clog << "GDAL Plugin: Found gray band" << std::endl;
#endif
                        break;
                    case GCI_PaletteIndex:
                    {
                        grey = band;
#ifdef MAPNIK_DEBUG
                        std::clog << "GDAL Plugin: Found gray band, and colortable..." << std::endl;
#endif
                        GDALColorTable *color_table = band->GetColorTable();
                
                        if ( color_table)
                        {
                            int count = color_table->GetColorEntryCount();
#ifdef MAPNIK_DEBUG
                            std::clog << "GDAL Plugin: Color Table count = " << count << std::endl;
#endif 
                            for (int j = 0; j < count; j++)
                            {
                                const GDALColorEntry *ce = color_table->GetColorEntry (j);
                                if (! ce) continue;
#ifdef MAPNIK_DEBUG
                                std::clog << "GDAL Plugin: Color entry RGB (" << ce->c1 << "," <<ce->c2 << "," << ce->c3 << ")" << std::endl; 
#endif
                            }
                        }
                        break;
                    }
                    case GCI_Undefined:
#ifdef MAPNIK_DEBUG
                        std::clog << "GDAL Plugin: Found undefined band (assumming gray band)" << std::endl;
#endif
                        grey = band;
                        break;
                    default:
#ifdef MAPNIK_DEBUG
                        std::clog << "GDAL Plugin: band type unknown!" << std::endl;
#endif
                        break;
                    }
                }
    
                if (red && green && blue)
                {
#ifdef MAPNIK_DEBUG
                    std::clog << "GDAL Plugin: processing rgb bands..." << std::endl;
#endif
                    red->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 0,
                                  image.width(),image.height(),GDT_Byte,4,4*image.width());
                    green->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 1,
                                    image.width(),image.height(),GDT_Byte,4,4*image.width());
                    blue->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 2,
                                   image.width(),image.height(),GDT_Byte,4,4*image.width());
                }
                else if (grey)
                {
#ifdef MAPNIK_DEBUG
                    std::clog << "GDAL Plugin: processing gray band..." << std::endl;
#endif
                    // TODO : apply colormap if present
                
                    grey->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 0,
                                   image.width(),image.height(),GDT_Byte, 4, 4 * image.width());
                    grey->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 1,
                                   image.width(),image.height(),GDT_Byte, 4, 4 * image.width());
                    grey->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 2,
                                   image.width(),image.height(),GDT_Byte, 4, 4 * image.width());
                }
    
                if (alpha)
                {
#ifdef MAPNIK_DEBUG
                    std::clog << "GDAL Plugin: processing alpha band..." << std::endl;
#endif
                    alpha->RasterIO(GF_Read,x_off,y_off,width,height,image.getBytes() + 3,
                                    image.width(),image.height(),GDT_Byte,4,4*image.width());
                }
    
                feature->set_raster(mapnik::raster_ptr(new mapnik::raster(intersect,image)));
            }
            return feature;
        }
    }
    return feature_ptr();
}