Example #1
0
int main( int argc, char ** argv )

{
    const char *pszSrcFilename = NULL;
    int anReqOverviews[1000];
    int nReqOverviewCount = 0;
    bool bMasks = false;

    GDALAllRegister();

    argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
    if( argc < 1 )
        exit( -argc );

/* -------------------------------------------------------------------- */
/*      Process arguments.                                              */
/* -------------------------------------------------------------------- */
    for( int iArg = 1; iArg < argc; iArg++ )
    {
        if( EQUAL(argv[iArg],"-masks") )
        {
            bMasks = true;
        }
        else if( pszSrcFilename == NULL )
        {
            pszSrcFilename = argv[iArg];
        }
        else if( atoi(argv[iArg]) > 0 || EQUAL(argv[iArg],"0") )
        {
            anReqOverviews[nReqOverviewCount++] = atoi(argv[iArg]);
        }
        else
        {
            Usage();
        }
    }

    if( pszSrcFilename == NULL )
        Usage();

/* -------------------------------------------------------------------- */
/*      Open the input file.                                            */
/* -------------------------------------------------------------------- */
    GDALDatasetH hSrcDS = GDALOpen( pszSrcFilename, GA_ReadOnly );

    if( hSrcDS == NULL )
        exit( 1 );

/* ==================================================================== */
/*      Process all bands.                                              */
/* ==================================================================== */
    int iBand;
    int nBandCount = GDALGetRasterCount( hSrcDS );

    for( iBand = 0; iBand < nBandCount; iBand++ )
    {
        GDALRasterBandH hBaseBand = GDALGetRasterBand( hSrcDS, iBand+1 );

/* -------------------------------------------------------------------- */
/*      Process all overviews.                                          */
/* -------------------------------------------------------------------- */
        int iOverview;
        int nOverviewCount = GDALGetOverviewCount( hBaseBand );

        for( iOverview = 0; iOverview < nOverviewCount; iOverview++ )
        {
            GDALRasterBandH hSrcOver = GDALGetOverview( hBaseBand, iOverview );

            if (hSrcOver == NULL)
            {
                fprintf(stderr, "skipping overview %d as being null\n", iOverview);
                continue;
            }

/* -------------------------------------------------------------------- */
/*      Is this a requested overview?                                   */
/* -------------------------------------------------------------------- */
            if( nReqOverviewCount > 0 )
            {
                int i;

                for( i = 0; i < nReqOverviewCount; i++ )
                {
                    if( anReqOverviews[i] == iOverview )
                        break;
                }

                if( i == nReqOverviewCount )
                    continue;
            }

/* -------------------------------------------------------------------- */
/*      Create matching output file.                                    */
/* -------------------------------------------------------------------- */
            CPLString osFilename;
            osFilename.Printf( "%s_%d_%d.tif",
                               CPLGetBasename(pszSrcFilename),
                               iBand+1, iOverview );
            DumpBand( hSrcDS, hSrcOver, osFilename );

            if( bMasks )
            {
                CPLString osFilename;
                osFilename.Printf( "%s_%d_%d_mask.tif",
                                CPLGetBasename(pszSrcFilename),
                                iBand+1, iOverview );
                DumpBand( hSrcDS, GDALGetMaskBand(hSrcOver), osFilename );
            }
        }

/* -------------------------------------------------------------------- */
/*      Do we dump the mask?                                            */
/* -------------------------------------------------------------------- */
        if( bMasks )
        {
            CPLString osFilename;
            osFilename.Printf( "%s_%d_mask.tif",
                               CPLGetBasename(pszSrcFilename),
                               iBand+1 );
            DumpBand( hSrcDS, GDALGetMaskBand(hBaseBand), osFilename );
        }
    }

    GDALClose( hSrcDS );

    CSLDestroy( argv );
    GDALDestroyDriverManager();

    return 0;
}
Example #2
0
CPLErr CPL_STDCALL
GDALFillNodata( GDALRasterBandH hTargetBand,
                GDALRasterBandH hMaskBand,
                double dfMaxSearchDist,
                CPL_UNUSED int bDeprecatedOption,
                int nSmoothingIterations,
                char **papszOptions,
                GDALProgressFunc pfnProgress,
                void * pProgressArg )

{
    VALIDATE_POINTER1( hTargetBand, "GDALFillNodata", CE_Failure );

    const int nXSize = GDALGetRasterBandXSize(hTargetBand);
    const int nYSize = GDALGetRasterBandYSize(hTargetBand);

    if( dfMaxSearchDist == 0.0 )
        dfMaxSearchDist = std::max(nXSize, nYSize) + 1;

    const int nMaxSearchDist = static_cast<int>(floor(dfMaxSearchDist));

    // Special "x" pixel values identifying pixels as special.
    GDALDataType eType = GDT_UInt16;
    GUInt32 nNoDataVal = 65535;

    if( nXSize > 65533 || nYSize > 65533 )
    {
        eType = GDT_UInt32;
        nNoDataVal = 4000002;
    }

    if( hMaskBand == nullptr )
        hMaskBand = GDALGetMaskBand( hTargetBand );

    // If there are smoothing iterations, reserve 10% of the progress for them.
    const double dfProgressRatio = nSmoothingIterations > 0 ? 0.9 : 1.0;

    const char* pszNoData = CSLFetchNameValue(papszOptions, "NODATA");
    bool bHasNoData = false;
    float fNoData = 0.0f;
    if( pszNoData )
    {
        bHasNoData = true;
        fNoData = static_cast<float>(CPLAtof(pszNoData));
    }

/* -------------------------------------------------------------------- */
/*      Initialize progress counter.                                    */
/* -------------------------------------------------------------------- */
    if( pfnProgress == nullptr )
        pfnProgress = GDALDummyProgress;

    if( !pfnProgress( 0.0, "Filling...", pProgressArg ) )
    {
        CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
        return CE_Failure;
    }

/* -------------------------------------------------------------------- */
/*      Determine format driver for temp work files.                    */
/* -------------------------------------------------------------------- */
    CPLString osTmpFileDriver = CSLFetchNameValueDef(
            papszOptions, "TEMP_FILE_DRIVER", "GTiff");
    GDALDriverH hDriver = GDALGetDriverByName(osTmpFileDriver.c_str());

    if( hDriver == nullptr )
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Given driver is not registered");
        return CE_Failure;
    }

    if( GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) == nullptr )
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Given driver is incapable of creating temp work files");
        return CE_Failure;
    }

    char **papszWorkFileOptions = nullptr;
    if( osTmpFileDriver == "GTiff" )
    {
        papszWorkFileOptions = CSLSetNameValue(
                papszWorkFileOptions, "COMPRESS", "LZW");
        papszWorkFileOptions = CSLSetNameValue(
                papszWorkFileOptions, "BIGTIFF", "IF_SAFER");
    }

/* -------------------------------------------------------------------- */
/*      Create a work file to hold the Y "last value" indices.          */
/* -------------------------------------------------------------------- */
    const CPLString osTmpFile = CPLGenerateTempFilename("");
    const CPLString osYTmpFile = osTmpFile + "fill_y_work.tif";

    GDALDatasetH hYDS =
        GDALCreate( hDriver, osYTmpFile, nXSize, nYSize, 1,
                    eType, papszWorkFileOptions );

    if( hYDS == nullptr )
    {
        CPLError(
            CE_Failure, CPLE_AppDefined,
            "Could not create Y index work file. Check driver capabilities.");
        return CE_Failure;
    }

    GDALRasterBandH hYBand = GDALGetRasterBand( hYDS, 1 );

/* -------------------------------------------------------------------- */
/*      Create a work file to hold the pixel value associated with      */
/*      the "last xy value" pixel.                                      */
/* -------------------------------------------------------------------- */
    const CPLString osValTmpFile = osTmpFile + "fill_val_work.tif";

    GDALDatasetH hValDS =
        GDALCreate( hDriver, osValTmpFile, nXSize, nYSize, 1,
                    GDALGetRasterDataType( hTargetBand ),
                    papszWorkFileOptions );

    if( hValDS == nullptr )
    {
        CPLError(CE_Failure, CPLE_AppDefined,
            "Could not create XY value work file. Check driver capabilities.");
        return CE_Failure;
    }

    GDALRasterBandH hValBand = GDALGetRasterBand( hValDS, 1 );

/* -------------------------------------------------------------------- */
/*      Create a mask file to make it clear what pixels can be filtered */
/*      on the filtering pass.                                          */
/* -------------------------------------------------------------------- */
    const CPLString osFiltMaskTmpFile = osTmpFile + "fill_filtmask_work.tif";

    GDALDatasetH hFiltMaskDS =
        GDALCreate( hDriver, osFiltMaskTmpFile, nXSize, nYSize, 1,
                    GDT_Byte, papszWorkFileOptions );

    if( hFiltMaskDS == nullptr )
    {
        CPLError(CE_Failure, CPLE_AppDefined,
            "Could not create mask work file. Check driver capabilities.");
        return CE_Failure;
    }

    GDALRasterBandH hFiltMaskBand = GDALGetRasterBand( hFiltMaskDS, 1 );

/* -------------------------------------------------------------------- */
/*      Allocate buffers for last scanline and this scanline.           */
/* -------------------------------------------------------------------- */

    GUInt32 *panLastY =
        static_cast<GUInt32 *>(VSI_CALLOC_VERBOSE(nXSize, sizeof(GUInt32)));
    GUInt32 *panThisY =
        static_cast<GUInt32 *>(VSI_CALLOC_VERBOSE(nXSize, sizeof(GUInt32)));
    GUInt32 *panTopDownY =
        static_cast<GUInt32 *>(VSI_CALLOC_VERBOSE(nXSize, sizeof(GUInt32)));
    float *pafLastValue =
        static_cast<float *>(VSI_CALLOC_VERBOSE(nXSize, sizeof(float)));
    float *pafThisValue =
        static_cast<float *>(VSI_CALLOC_VERBOSE(nXSize, sizeof(float)));
    float *pafTopDownValue =
        static_cast<float *>(VSI_CALLOC_VERBOSE(nXSize, sizeof(float)));
    float *pafScanline =
        static_cast<float *>(VSI_CALLOC_VERBOSE(nXSize, sizeof(float)));
    GByte *pabyMask = static_cast<GByte *>(VSI_CALLOC_VERBOSE(nXSize, 1));
    GByte *pabyFiltMask = static_cast<GByte *>(VSI_CALLOC_VERBOSE(nXSize, 1));

    CPLErr eErr = CE_None;

    if( panLastY == nullptr || panThisY == nullptr || panTopDownY == nullptr ||
        pafLastValue == nullptr || pafThisValue == nullptr ||
        pafTopDownValue == nullptr ||
        pafScanline == nullptr || pabyMask == nullptr || pabyFiltMask == nullptr )
    {
        eErr = CE_Failure;
        goto end;
    }

    for( int iX = 0; iX < nXSize; iX++ )
    {
        panLastY[iX] = nNoDataVal;
    }

/* ==================================================================== */
/*      Make first pass from top to bottom collecting the "last         */
/*      known value" for each column and writing it out to the work     */
/*      files.                                                          */
/* ==================================================================== */

    for( int iY = 0; iY < nYSize && eErr == CE_None; iY++ )
    {
/* -------------------------------------------------------------------- */
/*      Read data and mask for this line.                               */
/* -------------------------------------------------------------------- */
        eErr =
            GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1,
                          pabyMask, nXSize, 1, GDT_Byte, 0, 0 );

        if( eErr != CE_None )
            break;

        eErr =
            GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1,
                          pafScanline, nXSize, 1, GDT_Float32, 0, 0 );

        if( eErr != CE_None )
            break;

/* -------------------------------------------------------------------- */
/*      Figure out the most recent pixel for each column.               */
/* -------------------------------------------------------------------- */

        for( int iX = 0; iX < nXSize; iX++ )
        {
            if( pabyMask[iX] )
            {
                pafThisValue[iX] = pafScanline[iX];
                panThisY[iX] = iY;
            }
            else if( iY <= dfMaxSearchDist + panLastY[iX] )
            {
                pafThisValue[iX] = pafLastValue[iX];
                panThisY[iX] = panLastY[iX];
            }
            else
            {
                panThisY[iX] = nNoDataVal;
            }
        }

/* -------------------------------------------------------------------- */
/*      Write out best index/value to working files.                    */
/* -------------------------------------------------------------------- */
        eErr = GDALRasterIO( hYBand, GF_Write, 0, iY, nXSize, 1,
                             panThisY, nXSize, 1, GDT_UInt32, 0, 0 );
        if( eErr != CE_None )
            break;

        eErr = GDALRasterIO( hValBand, GF_Write, 0, iY, nXSize, 1,
                             pafThisValue, nXSize, 1, GDT_Float32, 0, 0 );
        if( eErr != CE_None )
            break;

/* -------------------------------------------------------------------- */
/*      Flip this/last buffers.                                         */
/* -------------------------------------------------------------------- */
        std::swap(pafThisValue, pafLastValue);
        std::swap(panThisY, panLastY);

/* -------------------------------------------------------------------- */
/*      report progress.                                                */
/* -------------------------------------------------------------------- */
        if( eErr == CE_None &&
            !pfnProgress(
                dfProgressRatio * (0.5*(iY+1) /
                                   static_cast<double>(nYSize)),
                "Filling...", pProgressArg ) )
        {
            CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
            eErr = CE_Failure;
        }
    }

    for( int iX = 0; iX < nXSize; iX++ )
    {
        panLastY[iX] = nNoDataVal;
    }

/* ==================================================================== */
/*      Now we will do collect similar this/last information from       */
/*      bottom to top and use it in combination with the top to         */
/*      bottom search info to interpolate.                              */
/* ==================================================================== */
    for( int iY = nYSize-1; iY >= 0 && eErr == CE_None; iY-- )
    {
        eErr =
            GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1,
                          pabyMask, nXSize, 1, GDT_Byte, 0, 0 );

        if( eErr != CE_None )
            break;

        eErr =
            GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1,
                          pafScanline, nXSize, 1, GDT_Float32, 0, 0 );

        if( eErr != CE_None )
            break;

/* -------------------------------------------------------------------- */
/*      Figure out the most recent pixel for each column.               */
/* -------------------------------------------------------------------- */

        for( int iX = 0; iX < nXSize; iX++ )
        {
            if( pabyMask[iX] )
            {
                pafThisValue[iX] = pafScanline[iX];
                panThisY[iX] = iY;
            }
            else if( panLastY[iX] - iY <= dfMaxSearchDist )
            {
                pafThisValue[iX] = pafLastValue[iX];
                panThisY[iX] = panLastY[iX];
            }
            else
            {
                panThisY[iX] = nNoDataVal;
            }
        }

/* -------------------------------------------------------------------- */
/*      Load the last y and corresponding value from the top down pass. */
/* -------------------------------------------------------------------- */
        eErr =
            GDALRasterIO( hYBand, GF_Read, 0, iY, nXSize, 1,
                          panTopDownY, nXSize, 1, GDT_UInt32, 0, 0 );

        if( eErr != CE_None )
            break;

        eErr =
            GDALRasterIO( hValBand, GF_Read, 0, iY, nXSize, 1,
                          pafTopDownValue, nXSize, 1, GDT_Float32, 0, 0 );

        if( eErr != CE_None )
            break;

/* -------------------------------------------------------------------- */
/*      Attempt to interpolate any pixels that are nodata.              */
/* -------------------------------------------------------------------- */
        memset( pabyFiltMask, 0, nXSize );
        for( int iX = 0; iX < nXSize; iX++ )
        {
            int nThisMaxSearchDist = nMaxSearchDist;

            // If this was a valid target - no change.
            if( pabyMask[iX] )
                continue;

            // Quadrants 0:topleft, 1:bottomleft, 2:topright, 3:bottomright
            double adfQuadDist[4] = {};
            float fQuadValue[4] = {};

            for( int iQuad = 0; iQuad < 4; iQuad++ )
            {
                adfQuadDist[iQuad] = dfMaxSearchDist + 1.0;
                fQuadValue[iQuad] = 0.0;
            }

            // Step left and right by one pixel searching for the closest
            // target value for each quadrant.
            for( int iStep = 0; iStep <= nThisMaxSearchDist; iStep++ )
            {
                const int iLeftX = std::max(0, iX - iStep);
                const int iRightX = std::min(nXSize - 1, iX + iStep);

                // Top left includes current line.
                QUAD_CHECK(adfQuadDist[0], fQuadValue[0],
                           iLeftX, panTopDownY[iLeftX], iX, iY,
                           pafTopDownValue[iLeftX], nNoDataVal );

                // Bottom left.
                QUAD_CHECK(adfQuadDist[1], fQuadValue[1],
                           iLeftX, panLastY[iLeftX], iX, iY,
                           pafLastValue[iLeftX], nNoDataVal );

                // Top right and bottom right do no include center pixel.
                if( iStep == 0 )
                     continue;

                // Top right includes current line.
                QUAD_CHECK(adfQuadDist[2], fQuadValue[2],
                           iRightX, panTopDownY[iRightX], iX, iY,
                           pafTopDownValue[iRightX], nNoDataVal );

                // Bottom right.
                QUAD_CHECK(adfQuadDist[3], fQuadValue[3],
                           iRightX, panLastY[iRightX], iX, iY,
                           pafLastValue[iRightX], nNoDataVal );

                // Every four steps, recompute maximum distance.
                if( (iStep & 0x3) == 0 )
                    nThisMaxSearchDist = static_cast<int>(floor(
                        std::max(std::max(adfQuadDist[0], adfQuadDist[1]),
                                 std::max(adfQuadDist[2], adfQuadDist[3]))));
            }

            double dfWeightSum = 0.0;
            double dfValueSum = 0.0;
            bool bHasSrcValues = false;

            for( int iQuad = 0; iQuad < 4; iQuad++ )
            {
                if( adfQuadDist[iQuad] <= dfMaxSearchDist )
                {
                    const double dfWeight = 1.0 / adfQuadDist[iQuad];

                    bHasSrcValues = dfWeight != 0;
                    if( !bHasNoData || fQuadValue[iQuad] != fNoData )
                    {
                        dfWeightSum += dfWeight;
                        dfValueSum += fQuadValue[iQuad] * dfWeight;
                    }
                }
            }

            if( bHasSrcValues )
            {
                pabyMask[iX] = 255;
                pabyFiltMask[iX] = 255;
                if( dfWeightSum > 0.0 )
                    pafScanline[iX] = static_cast<float>(dfValueSum / dfWeightSum);
                else
                    pafScanline[iX] = fNoData;
            }
        }

/* -------------------------------------------------------------------- */
/*      Write out the updated data and mask information.                */
/* -------------------------------------------------------------------- */
        eErr =
            GDALRasterIO( hTargetBand, GF_Write, 0, iY, nXSize, 1,
                          pafScanline, nXSize, 1, GDT_Float32, 0, 0 );

        if( eErr != CE_None )
            break;

        eErr =
            GDALRasterIO( hFiltMaskBand, GF_Write, 0, iY, nXSize, 1,
                          pabyFiltMask, nXSize, 1, GDT_Byte, 0, 0 );

        if( eErr != CE_None )
            break;

/* -------------------------------------------------------------------- */
/*      Flip this/last buffers.                                         */
/* -------------------------------------------------------------------- */
        std::swap(pafThisValue, pafLastValue);
        std::swap(panThisY, panLastY);

/* -------------------------------------------------------------------- */
/*      report progress.                                                */
/* -------------------------------------------------------------------- */
        if( eErr == CE_None &&
            !pfnProgress(
                dfProgressRatio*(0.5+0.5*(nYSize-iY) /
                                 static_cast<double>(nYSize)),
                "Filling...", pProgressArg) )
        {
            CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
            eErr = CE_Failure;
        }
    }

/* ==================================================================== */
/*      Now we will do iterative average filters over the               */
/*      interpolated values to smooth things out and make linear        */
/*      artifacts less obvious.                                         */
/* ==================================================================== */
    if( eErr == CE_None && nSmoothingIterations > 0 )
    {
        // Force masks to be to flushed and recomputed.
        GDALFlushRasterCache( hMaskBand );

        void *pScaledProgress =
            GDALCreateScaledProgress( dfProgressRatio, 1.0, pfnProgress, nullptr );

        eErr = GDALMultiFilter( hTargetBand, hMaskBand, hFiltMaskBand,
                                nSmoothingIterations,
                                GDALScaledProgress, pScaledProgress );

        GDALDestroyScaledProgress( pScaledProgress );
    }

/* -------------------------------------------------------------------- */
/*      Close and clean up temporary files. Free working buffers        */
/* -------------------------------------------------------------------- */
end:
    CPLFree(panLastY);
    CPLFree(panThisY);
    CPLFree(panTopDownY);
    CPLFree(pafLastValue);
    CPLFree(pafThisValue);
    CPLFree(pafTopDownValue);
    CPLFree(pafScanline);
    CPLFree(pabyMask);
    CPLFree(pabyFiltMask);

    GDALClose( hYDS );
    GDALClose( hValDS );
    GDALClose( hFiltMaskDS );

    CSLDestroy(papszWorkFileOptions);

    GDALDeleteDataset( hDriver, osYTmpFile );
    GDALDeleteDataset( hDriver, osValTmpFile );
    GDALDeleteDataset( hDriver, osFiltMaskTmpFile );

    return eErr;
}
Example #3
0
int main( int argc, char ** argv )

{
    GDALDatasetH	hDataset;
    GDALRasterBandH	hBand;
    int			i, iBand;
    double		adfGeoTransform[6];
    GDALDriverH		hDriver;
    char		**papszMetadata;
    int                 bComputeMinMax = FALSE, bSample = FALSE;
    int                 bShowGCPs = TRUE, bShowMetadata = TRUE, bShowRAT=TRUE;
    int                 bStats = FALSE, bApproxStats = TRUE, iMDD;
    int                 bShowColorTable = TRUE, bComputeChecksum = FALSE;
    int                 bReportHistograms = FALSE;
    const char          *pszFilename = NULL;
    char              **papszExtraMDDomains = NULL, **papszFileList;
    const char  *pszProjection = NULL;
    OGRCoordinateTransformationH hTransform = NULL;

    /* Check that we are running against at least GDAL 1.5 */
    /* Note to developers : if we use newer API, please change the requirement */
    if (atoi(GDALVersionInfo("VERSION_NUM")) < 1500)
    {
        fprintf(stderr, "At least, GDAL >= 1.5.0 is required for this version of %s, "
                "which was compiled against GDAL %s\n", argv[0], GDAL_RELEASE_NAME);
        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;
        }
    }

    GDALAllRegister();

    argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
    if( argc < 1 )
        exit( -argc );

/* -------------------------------------------------------------------- */
/*      Parse 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], "-mm") )
            bComputeMinMax = TRUE;
        else if( EQUAL(argv[i], "-hist") )
            bReportHistograms = TRUE;
        else if( EQUAL(argv[i], "-stats") )
        {
            bStats = TRUE;
            bApproxStats = FALSE;
        }
        else if( EQUAL(argv[i], "-approx_stats") )
        {
            bStats = TRUE;
            bApproxStats = TRUE;
        }
        else if( EQUAL(argv[i], "-sample") )
            bSample = TRUE;
        else if( EQUAL(argv[i], "-checksum") )
            bComputeChecksum = TRUE;
        else if( EQUAL(argv[i], "-nogcp") )
            bShowGCPs = FALSE;
        else if( EQUAL(argv[i], "-nomd") )
            bShowMetadata = FALSE;
        else if( EQUAL(argv[i], "-norat") )
            bShowRAT = FALSE;
        else if( EQUAL(argv[i], "-noct") )
            bShowColorTable = FALSE;
        else if( EQUAL(argv[i], "-mdd") && i < argc-1 )
            papszExtraMDDomains = CSLAddString( papszExtraMDDomains,
                                                argv[++i] );
        else if( argv[i][0] == '-' )
            Usage();
        else if( pszFilename == NULL )
            pszFilename = argv[i];
        else
            Usage();
    }

    if( pszFilename == NULL )
        Usage();

/* -------------------------------------------------------------------- */
/*      Open dataset.                                                   */
/* -------------------------------------------------------------------- */
    hDataset = GDALOpen( pszFilename, GA_ReadOnly );
    
    if( hDataset == NULL )
    {
        fprintf( stderr,
                 "gdalinfo failed - unable to open '%s'.\n",
                 pszFilename );

        CSLDestroy( argv );
    
        GDALDumpOpenDatasets( stderr );

        GDALDestroyDriverManager();

        CPLDumpSharedList( NULL );

        exit( 1 );
    }
    
/* -------------------------------------------------------------------- */
/*      Report general info.                                            */
/* -------------------------------------------------------------------- */
    hDriver = GDALGetDatasetDriver( hDataset );
    printf( "Driver: %s/%s\n",
            GDALGetDriverShortName( hDriver ),
            GDALGetDriverLongName( hDriver ) );

    papszFileList = GDALGetFileList( hDataset );
    if( CSLCount(papszFileList) == 0 )
    {
        printf( "Files: none associated\n" );
    }
    else
    {
        printf( "Files: %s\n", papszFileList[0] );
        for( i = 1; papszFileList[i] != NULL; i++ )
            printf( "       %s\n", papszFileList[i] );
    }
    CSLDestroy( papszFileList );

    printf( "Size is %d, %d\n",
            GDALGetRasterXSize( hDataset ), 
            GDALGetRasterYSize( hDataset ) );

/* -------------------------------------------------------------------- */
/*      Report projection.                                              */
/* -------------------------------------------------------------------- */
    if( GDALGetProjectionRef( hDataset ) != NULL )
    {
        OGRSpatialReferenceH  hSRS;
        char		      *pszProjection;

        pszProjection = (char *) GDALGetProjectionRef( hDataset );

        hSRS = OSRNewSpatialReference(NULL);
        if( OSRImportFromWkt( hSRS, &pszProjection ) == CE_None )
        {
            char	*pszPrettyWkt = NULL;

            OSRExportToPrettyWkt( hSRS, &pszPrettyWkt, FALSE );
            printf( "Coordinate System is:\n%s\n", pszPrettyWkt );
            CPLFree( pszPrettyWkt );
        }
        else
            printf( "Coordinate System is `%s'\n",
                    GDALGetProjectionRef( hDataset ) );

        OSRDestroySpatialReference( hSRS );
    }

/* -------------------------------------------------------------------- */
/*      Report Geotransform.                                            */
/* -------------------------------------------------------------------- */
    if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None )
    {
        if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0 )
        {
            printf( "Origin = (%.15f,%.15f)\n",
                    adfGeoTransform[0], adfGeoTransform[3] );

            printf( "Pixel Size = (%.15f,%.15f)\n",
                    adfGeoTransform[1], adfGeoTransform[5] );
        }
        else
            printf( "GeoTransform =\n"
                    "  %.16g, %.16g, %.16g\n"
                    "  %.16g, %.16g, %.16g\n", 
                    adfGeoTransform[0],
                    adfGeoTransform[1],
                    adfGeoTransform[2],
                    adfGeoTransform[3],
                    adfGeoTransform[4],
                    adfGeoTransform[5] );
    }

/* -------------------------------------------------------------------- */
/*      Report GCPs.                                                    */
/* -------------------------------------------------------------------- */
    if( bShowGCPs && GDALGetGCPCount( hDataset ) > 0 )
    {
        if (GDALGetGCPProjection(hDataset) != NULL)
        {
            OGRSpatialReferenceH  hSRS;
            char		      *pszProjection;

            pszProjection = (char *) GDALGetGCPProjection( hDataset );

            hSRS = OSRNewSpatialReference(NULL);
            if( OSRImportFromWkt( hSRS, &pszProjection ) == CE_None )
            {
                char	*pszPrettyWkt = NULL;

                OSRExportToPrettyWkt( hSRS, &pszPrettyWkt, FALSE );
                printf( "GCP Projection = \n%s\n", pszPrettyWkt );
                CPLFree( pszPrettyWkt );
            }
            else
                printf( "GCP Projection = %s\n",
                        GDALGetGCPProjection( hDataset ) );

            OSRDestroySpatialReference( hSRS );
        }

        for( i = 0; i < GDALGetGCPCount(hDataset); i++ )
        {
            const GDAL_GCP	*psGCP;
            
            psGCP = GDALGetGCPs( hDataset ) + i;

            printf( "GCP[%3d]: Id=%s, Info=%s\n"
                    "          (%.15g,%.15g) -> (%.15g,%.15g,%.15g)\n", 
                    i, psGCP->pszId, psGCP->pszInfo, 
                    psGCP->dfGCPPixel, psGCP->dfGCPLine, 
                    psGCP->dfGCPX, psGCP->dfGCPY, psGCP->dfGCPZ );
        }
    }

/* -------------------------------------------------------------------- */
/*      Report metadata.                                                */
/* -------------------------------------------------------------------- */
    papszMetadata = (bShowMetadata) ? GDALGetMetadata( hDataset, NULL ) : NULL;
    if( bShowMetadata && CSLCount(papszMetadata) > 0 )
    {
        printf( "Metadata:\n" );
        for( i = 0; papszMetadata[i] != NULL; i++ )
        {
            printf( "  %s\n", papszMetadata[i] );
        }
    }

    for( iMDD = 0; bShowMetadata && iMDD < CSLCount(papszExtraMDDomains); iMDD++ )
    {
        papszMetadata = GDALGetMetadata( hDataset, papszExtraMDDomains[iMDD] );
        if( CSLCount(papszMetadata) > 0 )
        {
            printf( "Metadata (%s):\n", papszExtraMDDomains[iMDD]);
            for( i = 0; papszMetadata[i] != NULL; i++ )
            {
                printf( "  %s\n", papszMetadata[i] );
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Report "IMAGE_STRUCTURE" metadata.                              */
/* -------------------------------------------------------------------- */
    papszMetadata = (bShowMetadata) ? GDALGetMetadata( hDataset, "IMAGE_STRUCTURE" ) : NULL;
    if( bShowMetadata && CSLCount(papszMetadata) > 0 )
    {
        printf( "Image Structure Metadata:\n" );
        for( i = 0; papszMetadata[i] != NULL; i++ )
        {
            printf( "  %s\n", papszMetadata[i] );
        }
    }

/* -------------------------------------------------------------------- */
/*      Report subdatasets.                                             */
/* -------------------------------------------------------------------- */
    papszMetadata = GDALGetMetadata( hDataset, "SUBDATASETS" );
    if( CSLCount(papszMetadata) > 0 )
    {
        printf( "Subdatasets:\n" );
        for( i = 0; papszMetadata[i] != NULL; i++ )
        {
            printf( "  %s\n", papszMetadata[i] );
        }
    }

/* -------------------------------------------------------------------- */
/*      Report geolocation.                                             */
/* -------------------------------------------------------------------- */
    papszMetadata = (bShowMetadata) ? GDALGetMetadata( hDataset, "GEOLOCATION" ) : NULL;
    if( bShowMetadata && CSLCount(papszMetadata) > 0 )
    {
        printf( "Geolocation:\n" );
        for( i = 0; papszMetadata[i] != NULL; i++ )
        {
            printf( "  %s\n", papszMetadata[i] );
        }
    }

/* -------------------------------------------------------------------- */
/*      Report RPCs                                                     */
/* -------------------------------------------------------------------- */
    papszMetadata = (bShowMetadata) ? GDALGetMetadata( hDataset, "RPC" ) : NULL;
    if( bShowMetadata && CSLCount(papszMetadata) > 0 )
    {
        printf( "RPC Metadata:\n" );
        for( i = 0; papszMetadata[i] != NULL; i++ )
        {
            printf( "  %s\n", papszMetadata[i] );
        }
    }

/* -------------------------------------------------------------------- */
/*      Setup projected to lat/long transform if appropriate.           */
/* -------------------------------------------------------------------- */
    if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None )
        pszProjection = GDALGetProjectionRef(hDataset);

    if( pszProjection != NULL && strlen(pszProjection) > 0 )
    {
        OGRSpatialReferenceH hProj, hLatLong = NULL;

        hProj = OSRNewSpatialReference( pszProjection );
        if( hProj != NULL )
            hLatLong = OSRCloneGeogCS( hProj );

        if( hLatLong != NULL )
        {
            CPLPushErrorHandler( CPLQuietErrorHandler );
            hTransform = OCTNewCoordinateTransformation( hProj, hLatLong );
            CPLPopErrorHandler();
            
            OSRDestroySpatialReference( hLatLong );
        }

        if( hProj != NULL )
            OSRDestroySpatialReference( hProj );
    }

/* -------------------------------------------------------------------- */
/*      Report corners.                                                 */
/* -------------------------------------------------------------------- */
    printf( "Corner Coordinates:\n" );
    GDALInfoReportCorner( hDataset, hTransform, "Upper Left", 
                          0.0, 0.0 );
    GDALInfoReportCorner( hDataset, hTransform, "Lower Left", 
                          0.0, GDALGetRasterYSize(hDataset));
    GDALInfoReportCorner( hDataset, hTransform, "Upper Right", 
                          GDALGetRasterXSize(hDataset), 0.0 );
    GDALInfoReportCorner( hDataset, hTransform, "Lower Right", 
                          GDALGetRasterXSize(hDataset), 
                          GDALGetRasterYSize(hDataset) );
    GDALInfoReportCorner( hDataset, hTransform, "Center", 
                          GDALGetRasterXSize(hDataset)/2.0, 
                          GDALGetRasterYSize(hDataset)/2.0 );

    if( hTransform != NULL )
    {
        OCTDestroyCoordinateTransformation( hTransform );
        hTransform = NULL;
    }
    
/* ==================================================================== */
/*      Loop over bands.                                                */
/* ==================================================================== */
    for( iBand = 0; iBand < GDALGetRasterCount( hDataset ); iBand++ )
    {
        double      dfMin, dfMax, adfCMinMax[2], dfNoData;
        int         bGotMin, bGotMax, bGotNodata, bSuccess;
        int         nBlockXSize, nBlockYSize, nMaskFlags;
        double      dfMean, dfStdDev;
        GDALColorTableH	hTable;
        CPLErr      eErr;

        hBand = GDALGetRasterBand( hDataset, iBand+1 );

        if( bSample )
        {
            float afSample[10000];
            int   nCount;

            nCount = GDALGetRandomRasterSample( hBand, 10000, afSample );
            printf( "Got %d samples.\n", nCount );
        }
        
        GDALGetBlockSize( hBand, &nBlockXSize, &nBlockYSize );
        printf( "Band %d Block=%dx%d Type=%s, ColorInterp=%s\n", iBand+1,
                nBlockXSize, nBlockYSize,
                GDALGetDataTypeName(
                    GDALGetRasterDataType(hBand)),
                GDALGetColorInterpretationName(
                    GDALGetRasterColorInterpretation(hBand)) );

        if( GDALGetDescription( hBand ) != NULL 
            && strlen(GDALGetDescription( hBand )) > 0 )
            printf( "  Description = %s\n", GDALGetDescription(hBand) );

        dfMin = GDALGetRasterMinimum( hBand, &bGotMin );
        dfMax = GDALGetRasterMaximum( hBand, &bGotMax );
        if( bGotMin || bGotMax || bComputeMinMax )
        {
            printf( "  " );
            if( bGotMin )
                printf( "Min=%.3f ", dfMin );
            if( bGotMax )
                printf( "Max=%.3f ", dfMax );
        
            if( bComputeMinMax )
            {
                CPLErrorReset();
                GDALComputeRasterMinMax( hBand, FALSE, adfCMinMax );
                if (CPLGetLastErrorType() == CE_None)
                {
                  printf( "  Computed Min/Max=%.3f,%.3f", 
                          adfCMinMax[0], adfCMinMax[1] );
                }
            }

            printf( "\n" );
        }

        eErr = GDALGetRasterStatistics( hBand, bApproxStats, bStats, 
                                        &dfMin, &dfMax, &dfMean, &dfStdDev );
        if( eErr == CE_None )
        {
            printf( "  Minimum=%.3f, Maximum=%.3f, Mean=%.3f, StdDev=%.3f\n",
                    dfMin, dfMax, dfMean, dfStdDev );
        }

        if( bReportHistograms )
        {
            int nBucketCount, *panHistogram = NULL;

            eErr = GDALGetDefaultHistogram( hBand, &dfMin, &dfMax, 
                                            &nBucketCount, &panHistogram, 
                                            TRUE, GDALTermProgress, NULL );
            if( eErr == CE_None )
            {
                int iBucket;

                printf( "  %d buckets from %g to %g:\n  ",
                        nBucketCount, dfMin, dfMax );
                for( iBucket = 0; iBucket < nBucketCount; iBucket++ )
                    printf( "%d ", panHistogram[iBucket] );
                printf( "\n" );
                CPLFree( panHistogram );
            }
        }

        if ( bComputeChecksum)
        {
            printf( "  Checksum=%d\n",
                    GDALChecksumImage(hBand, 0, 0,
                                      GDALGetRasterXSize(hDataset),
                                      GDALGetRasterYSize(hDataset)));
        }

        dfNoData = GDALGetRasterNoDataValue( hBand, &bGotNodata );
        if( bGotNodata )
        {
            printf( "  NoData Value=%.18g\n", dfNoData );
        }

        if( GDALGetOverviewCount(hBand) > 0 )
        {
            int		iOverview;

            printf( "  Overviews: " );
            for( iOverview = 0; 
                 iOverview < GDALGetOverviewCount(hBand);
                 iOverview++ )
            {
                GDALRasterBandH	hOverview;
                const char *pszResampling = NULL;

                if( iOverview != 0 )
                    printf( ", " );

                hOverview = GDALGetOverview( hBand, iOverview );
                printf( "%dx%d", 
                        GDALGetRasterBandXSize( hOverview ),
                        GDALGetRasterBandYSize( hOverview ) );

                pszResampling = 
                    GDALGetMetadataItem( hOverview, "RESAMPLING", "" );

                if( pszResampling != NULL 
                    && EQUALN(pszResampling,"AVERAGE_BIT2",12) )
                    printf( "*" );
            }
            printf( "\n" );

            if ( bComputeChecksum)
            {
                printf( "  Overviews checksum: " );
                for( iOverview = 0; 
                    iOverview < GDALGetOverviewCount(hBand);
                    iOverview++ )
                {
                    GDALRasterBandH	hOverview;

                    if( iOverview != 0 )
                        printf( ", " );

                    hOverview = GDALGetOverview( hBand, iOverview );
                    printf( "%d",
                            GDALChecksumImage(hOverview, 0, 0,
                                      GDALGetRasterBandXSize(hOverview),
                                      GDALGetRasterBandYSize(hOverview)));
                }
                printf( "\n" );
            }
        }

        if( GDALHasArbitraryOverviews( hBand ) )
        {
            printf( "  Overviews: arbitrary\n" );
        }
        
        nMaskFlags = GDALGetMaskFlags( hBand );
        if( (nMaskFlags & (GMF_NODATA|GMF_ALL_VALID)) == 0 )
        {
            GDALRasterBandH hMaskBand = GDALGetMaskBand(hBand) ;

            printf( "  Mask Flags: " );
            if( nMaskFlags & GMF_PER_DATASET )
                printf( "PER_DATASET " );
            if( nMaskFlags & GMF_ALPHA )
                printf( "ALPHA " );
            if( nMaskFlags & GMF_NODATA )
                printf( "NODATA " );
            if( nMaskFlags & GMF_ALL_VALID )
                printf( "ALL_VALID " );
            printf( "\n" );

            if( hMaskBand != NULL &&
                GDALGetOverviewCount(hMaskBand) > 0 )
            {
                int		iOverview;

                printf( "  Overviews of mask band: " );
                for( iOverview = 0; 
                     iOverview < GDALGetOverviewCount(hMaskBand);
                     iOverview++ )
                {
                    GDALRasterBandH	hOverview;

                    if( iOverview != 0 )
                        printf( ", " );

                    hOverview = GDALGetOverview( hMaskBand, iOverview );
                    printf( "%dx%d", 
                            GDALGetRasterBandXSize( hOverview ),
                            GDALGetRasterBandYSize( hOverview ) );
                }
                printf( "\n" );
            }
        }

        if( strlen(GDALGetRasterUnitType(hBand)) > 0 )
        {
            printf( "  Unit Type: %s\n", GDALGetRasterUnitType(hBand) );
        }

        if( GDALGetRasterCategoryNames(hBand) != NULL )
        {
            char **papszCategories = GDALGetRasterCategoryNames(hBand);
            int i;

            printf( "  Categories:\n" );
            for( i = 0; papszCategories[i] != NULL; i++ )
                printf( "    %3d: %s\n", i, papszCategories[i] );
        }

        if( GDALGetRasterScale( hBand, &bSuccess ) != 1.0 
            || GDALGetRasterOffset( hBand, &bSuccess ) != 0.0 )
            printf( "  Offset: %.15g,   Scale:%.15g\n",
                    GDALGetRasterOffset( hBand, &bSuccess ),
                    GDALGetRasterScale( hBand, &bSuccess ) );

        papszMetadata = (bShowMetadata) ? GDALGetMetadata( hBand, NULL ) : NULL;
        if( bShowMetadata && CSLCount(papszMetadata) > 0 )
        {
            printf( "  Metadata:\n" );
            for( i = 0; papszMetadata[i] != NULL; i++ )
            {
                printf( "    %s\n", papszMetadata[i] );
            }
        }

        papszMetadata = (bShowMetadata) ? GDALGetMetadata( hBand, "IMAGE_STRUCTURE" ) : NULL;
        if( bShowMetadata && CSLCount(papszMetadata) > 0 )
        {
            printf( "  Image Structure Metadata:\n" );
            for( i = 0; papszMetadata[i] != NULL; i++ )
            {
                printf( "    %s\n", papszMetadata[i] );
            }
        }

        if( GDALGetRasterColorInterpretation(hBand) == GCI_PaletteIndex 
            && (hTable = GDALGetRasterColorTable( hBand )) != NULL )
        {
            int			i;

            printf( "  Color Table (%s with %d entries)\n", 
                    GDALGetPaletteInterpretationName(
                        GDALGetPaletteInterpretation( hTable )), 
                    GDALGetColorEntryCount( hTable ) );

            if (bShowColorTable)
            {
                for( i = 0; i < GDALGetColorEntryCount( hTable ); i++ )
                {
                    GDALColorEntry	sEntry;
    
                    GDALGetColorEntryAsRGB( hTable, i, &sEntry );
                    printf( "  %3d: %d,%d,%d,%d\n", 
                            i, 
                            sEntry.c1,
                            sEntry.c2,
                            sEntry.c3,
                            sEntry.c4 );
                }
            }
        }

        if( bShowRAT && GDALGetDefaultRAT( hBand ) != NULL )
        {
            GDALRasterAttributeTableH hRAT = GDALGetDefaultRAT( hBand );
            
            GDALRATDumpReadable( hRAT, NULL );
        }
    }

    GDALClose( hDataset );
    
    CSLDestroy( papszExtraMDDomains );
    CSLDestroy( argv );
    
    GDALDumpOpenDatasets( stderr );

    GDALDestroyDriverManager();

    CPLDumpSharedList( NULL );
    CPLCleanupTLS();

    exit( 0 );
}
Example #4
0
int main( int argc, char ** argv )

{
    /* Check that we are running against at least GDAL 1.4 (probably older in fact !) */
    /* Note to developers : if we use newer API, please change the requirement */
    if (atoi(GDALVersionInfo("VERSION_NUM")) < 1400)
    {
        fprintf(stderr, "At least, GDAL >= 1.4.0 is required for this version of %s, "
                "which was compiled against GDAL %s\n", argv[0], GDAL_RELEASE_NAME);
        exit(1);
    }

/* -------------------------------------------------------------------- */
/*      Generic arg processing.                                         */
/* -------------------------------------------------------------------- */
    GDALAllRegister();
    GDALSetCacheMax( 100000000 );
    argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
    if( argc < 1 )
        exit( -argc );
    
/* -------------------------------------------------------------------- */
/*      Parse arguments.                                                */
/* -------------------------------------------------------------------- */
    int i;
    const char *pszOutFile = NULL;
    const char *pszInFile = NULL;
    int nMaxNonBlack = 2;
    int nNearDist = 15;
    int bNearWhite = FALSE;
    int bSetAlpha = FALSE;
    int bSetMask = FALSE;
    const char* pszDriverName = "HFA";
    int bFormatExplicitelySet = FALSE;
    char** papszCreationOptions = NULL;
    int bQuiet = FALSE;

    Colors oColors;
    
    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], "-o") && i < argc-1 )
            pszOutFile = argv[++i];
        else if( EQUAL(argv[i], "-of") && i < argc-1 )
        {
            pszDriverName = argv[++i];
            bFormatExplicitelySet = TRUE;
        }
        else if( EQUAL(argv[i], "-white") ) {
            bNearWhite = TRUE;
        }

        /***** -color c1,c2,c3...cn *****/
        
        else if( EQUAL(argv[i], "-color") && i < argc-1 ) {
            Color oColor;
            
            /***** tokenize the arg on , *****/
            
            char **papszTokens;
            papszTokens = CSLTokenizeString2( argv[++i], ",", 0 );

            /***** loop over the tokens *****/
            
            int iToken;
            for( iToken = 0; papszTokens && papszTokens[iToken]; iToken++ )
            {

                /***** ensure the token is an int and add it to the color *****/
                
                if ( IsInt( papszTokens[iToken] ) )
                    oColor.push_back( atoi( papszTokens[iToken] ) );
                else {
                    CPLError(CE_Failure, CPLE_AppDefined,
                             "Colors must be valid integers." );
                    CSLDestroy( papszTokens );
                    exit(1);
                }
            }
            
            CSLDestroy( papszTokens );

            /***** check if the number of bands is consistant *****/

            if ( oColors.size() > 0 &&
                 oColors.front().size() != oColor.size() )
            {
                CPLError(CE_Failure, CPLE_AppDefined,
                         "ERROR: all -color args must have the same number of values.\n" );
                exit(1);
            }

            /***** add the color to the colors *****/
            
            oColors.push_back( oColor );
            
        }
        
        else if( EQUAL(argv[i], "-nb") && i < argc-1 )
            nMaxNonBlack = atoi(argv[++i]);
        else if( EQUAL(argv[i], "-near") && i < argc-1 )
            nNearDist = atoi(argv[++i]);
        else if( EQUAL(argv[i], "-setalpha") )
            bSetAlpha = TRUE;
        else if( EQUAL(argv[i], "-setmask") )
            bSetMask = TRUE;
        else if( EQUAL(argv[i], "-q") || EQUAL(argv[i], "-quiet") )
            bQuiet = TRUE;
        else if( EQUAL(argv[i], "-co") && i < argc-1 )
            papszCreationOptions = CSLAddString(papszCreationOptions, argv[++i]);
        else if( argv[i][0] == '-' )
            Usage();
        else if( pszInFile == NULL )
            pszInFile = argv[i];
        else
            Usage();
    }

    if( pszInFile == NULL )
        Usage();

    if( pszOutFile == NULL )
        pszOutFile = pszInFile;

/* -------------------------------------------------------------------- */
/*      Open input file.                                                */
/* -------------------------------------------------------------------- */
    GDALDatasetH hInDS, hOutDS = NULL;
    int nXSize, nYSize, nBands;

    if( pszOutFile == pszInFile )
        hInDS = hOutDS = GDALOpen( pszInFile, GA_Update );
    else
        hInDS = GDALOpen( pszInFile, GA_ReadOnly );

    if( hInDS == NULL )
        exit( 1 );

    nXSize = GDALGetRasterXSize( hInDS );
    nYSize = GDALGetRasterYSize( hInDS );
    nBands = GDALGetRasterCount( hInDS );
    int nDstBands = nBands;

    if( hOutDS != NULL && papszCreationOptions != NULL)
    {
        CPLError(CE_Warning, CPLE_AppDefined,
                  "Warning: creation options are ignored when writing to an existing file.");
    }

/* -------------------------------------------------------------------- */
/*      Do we need to create output file?                               */
/* -------------------------------------------------------------------- */
    if( hOutDS == NULL )
    {
        GDALDriverH hDriver = GDALGetDriverByName( pszDriverName );
        if (hDriver == NULL)
            exit(1);

        if (!bQuiet && !bFormatExplicitelySet)
            CheckExtensionConsistency(pszOutFile, pszDriverName);

        if (bSetAlpha)
        {
            /***** fixme there should be a way to preserve alpha band data not in the collar *****/
            if (nBands == 4)
                nBands --;
            else
                nDstBands ++;
        }

        if (bSetMask)
        {
            if (nBands == 4)
                nDstBands = nBands = 3;
        }

        hOutDS = GDALCreate( hDriver, pszOutFile, 
                             nXSize, nYSize, nDstBands, GDT_Byte, 
                             papszCreationOptions );
        if( hOutDS == NULL )
            exit( 1 );

        double adfGeoTransform[6];

        if( GDALGetGeoTransform( hInDS, adfGeoTransform ) == CE_None )
        {
            GDALSetGeoTransform( hOutDS, adfGeoTransform );
            GDALSetProjection( hOutDS, GDALGetProjectionRef( hInDS ) );
        }
    }
    else
    {
        if (bSetAlpha)
        {
            if (nBands != 4 &&
                (nBands < 2 ||
                 GDALGetRasterColorInterpretation(GDALGetRasterBand(hOutDS, nBands)) != GCI_AlphaBand))
            {
                CPLError(CE_Failure, CPLE_AppDefined,
                        "Last band is not an alpha band.");
                exit(1);
            }

            nBands --;
        }

        if (bSetMask)
        {
            if (nBands == 4)
                nDstBands = nBands = 3;
        }
    }

    /***** set a color if there are no colors set? *****/

    if ( oColors.size() == 0) {
        Color oColor;

        /***** loop over the bands to get the right number of values *****/

        int iBand;
        for (iBand = 0; iBand < nBands ; iBand++) {

            /***** black or white? *****/

            if (bNearWhite) 
                oColor.push_back(255);
            else
                oColor.push_back(0);
        }

        /***** add the color to the colors *****/

        oColors.push_back(oColor);
            
    }

    /***** does the number of bands match the number of color values? *****/

    if ( (int)oColors.front().size() != nBands ) {
        CPLError( CE_Failure, CPLE_AppDefined,
                  "-color args must have the same number of values as the non alpha input band count.\n" );
        exit(1); 
    }

    /***** check the input and output datasets are the same size *****/
    
    if (GDALGetRasterXSize(hOutDS) != nXSize ||
        GDALGetRasterYSize(hOutDS) != nYSize)
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "The dimensions of the output dataset don't match "
                 "the dimensions of the input dataset.");
        exit(1);
    }


    int iBand;
    for( iBand = 0; iBand < nBands; iBand++ )
    {
        GDALRasterBandH hBand = GDALGetRasterBand(hInDS, iBand+1);
        if (GDALGetRasterDataType(hBand) != GDT_Byte)
        {
            CPLError(CE_Warning, CPLE_AppDefined,
                     "Band %d is not of type GDT_Byte. It can lead to unexpected results.", iBand+1);
        }
        if (GDALGetRasterColorTable(hBand) != NULL)
        {
            CPLError(CE_Warning, CPLE_AppDefined,
                     "Band %d has a color table, which is ignored by nearblack. "
                     "It can lead to unexpected results.", iBand+1);
        }
    }

    GDALRasterBandH hMaskBand = NULL;
    
    if (bSetMask) {

        /***** if there isn't already a mask band on the output file create one *****/
        
        if ( GMF_PER_DATASET != GDALGetMaskFlags( GDALGetRasterBand(hOutDS, 1) ) )
        {

            if ( CE_None != GDALCreateDatasetMaskBand(hOutDS, GMF_PER_DATASET) ) {
                CPLError(CE_Failure, CPLE_AppDefined,
                         "Failed to create mask band on output DS");
                bSetMask = FALSE;
            }
        }

        if (bSetMask) {
            hMaskBand = GDALGetMaskBand(GDALGetRasterBand(hOutDS, 1));
        }
    }

/* -------------------------------------------------------------------- */
/*      Allocate a line buffer.                                         */
/* -------------------------------------------------------------------- */
    GByte *pabyLine;
    GByte *pabyMask=NULL;
    
    int   *panLastLineCounts;

    pabyLine = (GByte *) CPLMalloc(nXSize * nDstBands);
    
    if (bSetMask)
        pabyMask = (GByte *) CPLMalloc(nXSize);
    
    panLastLineCounts = (int *) CPLCalloc(sizeof(int),nXSize);

/* -------------------------------------------------------------------- */
/*      Processing data one line at a time.                             */
/* -------------------------------------------------------------------- */
    int iLine;

    for( iLine = 0; iLine < nYSize; iLine++ )
    {
        CPLErr eErr;

        eErr = GDALDatasetRasterIO( hInDS, GF_Read, 0, iLine, nXSize, 1, 
                                    pabyLine, nXSize, 1, GDT_Byte, 
                                    nBands, NULL, nDstBands, nXSize * nDstBands, 1 );
        if( eErr != CE_None )
            break;
        
        if (bSetAlpha)
        {
            int iCol;
            for(iCol = 0; iCol < nXSize; iCol ++)
            {
                pabyLine[iCol * nDstBands + nDstBands - 1] = 255;
            }
        }
        
        if (bSetMask)
        {
            int iCol;
            for(iCol = 0; iCol < nXSize; iCol ++)
            {
                pabyMask[iCol] = 255;
            }
        }
        
        ProcessLine( pabyLine, pabyMask, 0, nXSize-1, nBands, nDstBands,
                     nNearDist, nMaxNonBlack, bNearWhite, &oColors,
                     panLastLineCounts,
                     TRUE, // bDoHorizontalCheck
                     TRUE, // bDoVerticalCheck
                     FALSE // bBottomUp
                    );
        ProcessLine( pabyLine, pabyMask, nXSize-1, 0, nBands, nDstBands,
                     nNearDist, nMaxNonBlack, bNearWhite, &oColors,
                     panLastLineCounts,
                     TRUE,  // bDoHorizontalCheck
                     FALSE, // bDoVerticalCheck
                     FALSE  // bBottomUp
                    );
        
        eErr = GDALDatasetRasterIO( hOutDS, GF_Write, 0, iLine, nXSize, 1, 
                                    pabyLine, nXSize, 1, GDT_Byte, 
                                    nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );

        if( eErr != CE_None )
            break;
    
        /***** write out the mask band line *****/

        if (bSetMask) {

            eErr = GDALRasterIO ( hMaskBand, GF_Write, 0, iLine, nXSize, 1,
                                  pabyMask, nXSize, 1, GDT_Byte,
                                  0, 0 );
                             
            if( eErr != CE_None ) {
                CPLError(CE_Warning, CPLE_AppDefined,
                         "ERROR writeing out line to mask band.");
               break;
            }
        }
        
        if (!bQuiet)
            GDALTermProgress( 0.5 * ((iLine+1) / (double) nYSize), NULL, NULL );
    }

/* -------------------------------------------------------------------- */
/*      Now process from the bottom back up                            .*/
/* -------------------------------------------------------------------- */
    memset( panLastLineCounts, 0, sizeof(int) * nXSize);
    
    for( iLine = nYSize-1; iLine >= 0; iLine-- )
    {
        CPLErr eErr;

        eErr = GDALDatasetRasterIO( hOutDS, GF_Read, 0, iLine, nXSize, 1, 
                                    pabyLine, nXSize, 1, GDT_Byte, 
                                    nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );
        if( eErr != CE_None )
            break;

        /***** read the mask band line back in *****/

        if (bSetMask) {

            eErr = GDALRasterIO ( hMaskBand, GF_Read, 0, iLine, nXSize, 1,
                                  pabyMask, nXSize, 1, GDT_Byte,
                                  0, 0 );
                             
                                
            if( eErr != CE_None )
                break;
        }

        
        ProcessLine( pabyLine, pabyMask, 0, nXSize-1, nBands, nDstBands,
                     nNearDist, nMaxNonBlack, bNearWhite, &oColors,
                     panLastLineCounts,
                     TRUE, // bDoHorizontalCheck
                     TRUE, // bDoVerticalCheck
                     TRUE  // bBottomUp
                   );
        ProcessLine( pabyLine, pabyMask, nXSize-1, 0, nBands, nDstBands,
                     nNearDist, nMaxNonBlack, bNearWhite, &oColors,
                     panLastLineCounts,
                     TRUE,  // bDoHorizontalCheck
                     FALSE, // bDoVerticalCheck
                     TRUE   // bBottomUp
                    );
        
        eErr = GDALDatasetRasterIO( hOutDS, GF_Write, 0, iLine, nXSize, 1, 
                                    pabyLine, nXSize, 1, GDT_Byte, 
                                    nDstBands, NULL, nDstBands, nXSize * nDstBands, 1 );
        if( eErr != CE_None )
            break;

        /***** write out the mask band line *****/

        if (bSetMask) {

            eErr = GDALRasterIO ( hMaskBand, GF_Write, 0, iLine, nXSize, 1,
                                  pabyMask, nXSize, 1, GDT_Byte,
                                  0, 0 );
                             
                                
            if( eErr != CE_None )
                break;
        }

        
        if (!bQuiet)
            GDALTermProgress( 0.5 + 0.5 * (nYSize-iLine) / (double) nYSize, 
                            NULL, NULL );
    }

    CPLFree(pabyLine);
    if (bSetMask)
        CPLFree(pabyMask);
    
    CPLFree( panLastLineCounts );

    GDALClose( hOutDS );
    if( hInDS != hOutDS )
        GDALClose( hInDS );
    GDALDumpOpenDatasets( stderr );
    CSLDestroy( argv );
    CSLDestroy( papszCreationOptions );
    GDALDestroyDriverManager();
    
    return 0;
}
Example #5
0
CPLErr CPL_STDCALL
GDALFillNodata( GDALRasterBandH hTargetBand, 
                GDALRasterBandH hMaskBand,
                double dfMaxSearchDist, 
                CPL_UNUSED int bDeprecatedOption,
                int nSmoothingIterations,
                CPL_UNUSED char **papszOptions,
                GDALProgressFunc pfnProgress, 
                void * pProgressArg )

{
    VALIDATE_POINTER1( hTargetBand, "GDALFillNodata", CE_Failure );

    int nXSize = GDALGetRasterBandXSize( hTargetBand );
    int nYSize = GDALGetRasterBandYSize( hTargetBand );
    CPLErr eErr = CE_None;

    // Special "x" pixel values identifying pixels as special.
    GUInt32 nNoDataVal;
    GDALDataType eType;

    if( dfMaxSearchDist == 0.0 )
        dfMaxSearchDist = MAX(nXSize,nYSize) + 1;

    int nMaxSearchDist = (int) floor(dfMaxSearchDist);

    if( nXSize > 65533 || nYSize > 65533 )
    {
        eType = GDT_UInt32;
        nNoDataVal = 4000002;
    }
    else
    {
        eType = GDT_UInt16;
        nNoDataVal = 65535;
    }

    if( hMaskBand == NULL )
        hMaskBand = GDALGetMaskBand( hTargetBand );

    /* If there are smoothing iterations, reserve 10% of the progress for them */
    double dfProgressRatio = (nSmoothingIterations > 0) ? 0.9 : 1.0;

/* -------------------------------------------------------------------- */
/*      Initialize progress counter.                                    */
/* -------------------------------------------------------------------- */
    if( pfnProgress == NULL )
        pfnProgress = GDALDummyProgress;

    if( !pfnProgress( 0.0, "Filling...", pProgressArg ) )
    {
        CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
        return CE_Failure;
    }

/* -------------------------------------------------------------------- */
/*      Create a work file to hold the Y "last value" indices.          */
/* -------------------------------------------------------------------- */
    GDALDriverH  hDriver = GDALGetDriverByName( "GTiff" );
    if (hDriver == NULL)
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "GDALFillNodata needs GTiff driver");
        return CE_Failure;
    }
    
    GDALDatasetH hYDS;
    GDALRasterBandH hYBand;
    static const char *apszOptions[] = { "COMPRESS=LZW", "BIGTIFF=IF_SAFER", 
                                         NULL };
    CPLString osTmpFile = CPLGenerateTempFilename("");
    CPLString osYTmpFile = osTmpFile + "fill_y_work.tif";
    
    hYDS = GDALCreate( hDriver, osYTmpFile, nXSize, nYSize, 1, 
                       eType, (char **) apszOptions );
    
    if( hYDS == NULL )
        return CE_Failure;

    hYBand = GDALGetRasterBand( hYDS, 1 );

/* -------------------------------------------------------------------- */
/*      Create a work file to hold the pixel value associated with      */
/*      the "last xy value" pixel.                                      */
/* -------------------------------------------------------------------- */
    GDALDatasetH hValDS;
    GDALRasterBandH hValBand;
    CPLString osValTmpFile = osTmpFile + "fill_val_work.tif";

    hValDS = GDALCreate( hDriver, osValTmpFile, nXSize, nYSize, 1,
                         GDALGetRasterDataType( hTargetBand ), 
                         (char **) apszOptions );
    
    if( hValDS == NULL )
        return CE_Failure;

    hValBand = GDALGetRasterBand( hValDS, 1 );

/* -------------------------------------------------------------------- */
/*      Create a mask file to make it clear what pixels can be filtered */
/*      on the filtering pass.                                          */
/* -------------------------------------------------------------------- */
    GDALDatasetH hFiltMaskDS;
    GDALRasterBandH hFiltMaskBand;
    CPLString osFiltMaskTmpFile = osTmpFile + "fill_filtmask_work.tif";
    
    hFiltMaskDS = 
        GDALCreate( hDriver, osFiltMaskTmpFile, nXSize, nYSize, 1,
                    GDT_Byte, (char **) apszOptions );
    
    if( hFiltMaskDS == NULL )
        return CE_Failure;

    hFiltMaskBand = GDALGetRasterBand( hFiltMaskDS, 1 );

/* -------------------------------------------------------------------- */
/*      Allocate buffers for last scanline and this scanline.           */
/* -------------------------------------------------------------------- */
    GUInt32 *panLastY, *panThisY, *panTopDownY;
    float   *pafLastValue, *pafThisValue, *pafScanline, *pafTopDownValue;
    GByte   *pabyMask, *pabyFiltMask;
    int     iX;
    int     iY;

    panLastY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
    panThisY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
    panTopDownY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
    pafLastValue = (float *) VSICalloc(nXSize,sizeof(float));
    pafThisValue = (float *) VSICalloc(nXSize,sizeof(float));
    pafTopDownValue = (float *) VSICalloc(nXSize,sizeof(float));
    pafScanline = (float *) VSICalloc(nXSize,sizeof(float));
    pabyMask = (GByte *) VSICalloc(nXSize,1);
    pabyFiltMask = (GByte *) VSICalloc(nXSize,1);
    if (panLastY == NULL || panThisY == NULL || panTopDownY == NULL ||
        pafLastValue == NULL || pafThisValue == NULL || pafTopDownValue == NULL ||
        pafScanline == NULL || pabyMask == NULL || pabyFiltMask == NULL)
    {
        CPLError(CE_Failure, CPLE_OutOfMemory,
                 "Could not allocate enough memory for temporary buffers");

        eErr = CE_Failure;
        goto end;
    }

    for( iX = 0; iX < nXSize; iX++ )
    {
        panLastY[iX] = nNoDataVal;
    }

/* ==================================================================== */
/*      Make first pass from top to bottom collecting the "last         */
/*      known value" for each column and writing it out to the work     */
/*      files.                                                          */
/* ==================================================================== */
    
    for( iY = 0; iY < nYSize && eErr == CE_None; iY++ )
    {
/* -------------------------------------------------------------------- */
/*      Read data and mask for this line.                               */
/* -------------------------------------------------------------------- */
        eErr = 
            GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1, 
                          pabyMask, nXSize, 1, GDT_Byte, 0, 0 );

        if( eErr != CE_None )
            break;

        eErr = 
            GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1, 
                          pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
        
        if( eErr != CE_None )
            break;
        
/* -------------------------------------------------------------------- */
/*      Figure out the most recent pixel for each column.               */
/* -------------------------------------------------------------------- */
        
        for( iX = 0; iX < nXSize; iX++ )
        {
            if( pabyMask[iX] )
            {
                pafThisValue[iX] = pafScanline[iX];
                panThisY[iX] = iY;
            }
            else if( iY <= dfMaxSearchDist + panLastY[iX] )
            {
                pafThisValue[iX] = pafLastValue[iX];
                panThisY[iX] = panLastY[iX];
            }
            else
            {
                panThisY[iX] = nNoDataVal;
            }
        }
        
/* -------------------------------------------------------------------- */
/*      Write out best index/value to working files.                    */
/* -------------------------------------------------------------------- */
        eErr = GDALRasterIO( hYBand, GF_Write, 0, iY, nXSize, 1, 
                             panThisY, nXSize, 1, GDT_UInt32, 0, 0 );
        if( eErr != CE_None )
            break;

        eErr = GDALRasterIO( hValBand, GF_Write, 0, iY, nXSize, 1, 
                             pafThisValue, nXSize, 1, GDT_Float32, 0, 0 );
        if( eErr != CE_None )
            break;

/* -------------------------------------------------------------------- */
/*      Flip this/last buffers.                                         */
/* -------------------------------------------------------------------- */
        {
            float *pafTmp = pafThisValue;
            pafThisValue = pafLastValue;
            pafLastValue = pafTmp;

            GUInt32 *panTmp = panThisY;
            panThisY = panLastY;
            panLastY = panTmp;
        }

/* -------------------------------------------------------------------- */
/*      report progress.                                                */
/* -------------------------------------------------------------------- */
        if( eErr == CE_None
            && !pfnProgress( dfProgressRatio * (0.5*(iY+1) / (double)nYSize), 
                             "Filling...", pProgressArg ) )
        {
            CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
            eErr = CE_Failure;
        }
    }

/* ==================================================================== */
/*      Now we will do collect similar this/last information from       */
/*      bottom to top and use it in combination with the top to         */
/*      bottom search info to interpolate.                              */
/* ==================================================================== */
    for( iY = nYSize-1; iY >= 0 && eErr == CE_None; iY-- )
    {
        eErr = 
            GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1, 
                          pabyMask, nXSize, 1, GDT_Byte, 0, 0 );

        if( eErr != CE_None )
            break;

        eErr = 
            GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1, 
                          pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
        
        if( eErr != CE_None )
            break;
        
/* -------------------------------------------------------------------- */
/*      Figure out the most recent pixel for each column.               */
/* -------------------------------------------------------------------- */
        
        for( iX = 0; iX < nXSize; iX++ )
        {
            if( pabyMask[iX] )
            {
                pafThisValue[iX] = pafScanline[iX];
                panThisY[iX] = iY;
            }
            else if( panLastY[iX] - iY <= dfMaxSearchDist )
            {
                pafThisValue[iX] = pafLastValue[iX];
                panThisY[iX] = panLastY[iX];
            }
            else
            {
                panThisY[iX] = nNoDataVal;
            }
        }
        
/* -------------------------------------------------------------------- */
/*      Load the last y and corresponding value from the top down pass. */
/* -------------------------------------------------------------------- */
        eErr = 
            GDALRasterIO( hYBand, GF_Read, 0, iY, nXSize, 1, 
                          panTopDownY, nXSize, 1, GDT_UInt32, 0, 0 );

        if( eErr != CE_None )
            break;

        eErr = 
            GDALRasterIO( hValBand, GF_Read, 0, iY, nXSize, 1, 
                          pafTopDownValue, nXSize, 1, GDT_Float32, 0, 0 );

        if( eErr != CE_None )
            break;

/* -------------------------------------------------------------------- */
/*      Attempt to interpolate any pixels that are nodata.              */
/* -------------------------------------------------------------------- */
        memset( pabyFiltMask, 0, nXSize );
        for( iX = 0; iX < nXSize; iX++ )
        {
            int iStep, iQuad;
            int nThisMaxSearchDist = nMaxSearchDist;

            // If this was a valid target - no change.
            if( pabyMask[iX] )
                continue;

            // Quadrants 0:topleft, 1:bottomleft, 2:topright, 3:bottomright
            double adfQuadDist[4];
            double adfQuadValue[4];

            for( iQuad = 0; iQuad < 4; iQuad++ )
            {
                adfQuadDist[iQuad] = dfMaxSearchDist + 1.0;
                adfQuadValue[iQuad] = 0.0;
            }
            
            // Step left and right by one pixel searching for the closest 
            // target value for each quadrant. 
            for( iStep = 0; iStep < nThisMaxSearchDist; iStep++ )
            {
                int iLeftX = MAX(0,iX - iStep);
                int iRightX = MIN(nXSize-1,iX + iStep);
                
                // top left includes current line 
                QUAD_CHECK(adfQuadDist[0],adfQuadValue[0], 
                           iLeftX, panTopDownY[iLeftX], iX, iY,
                           pafTopDownValue[iLeftX] );

                // bottom left 
                QUAD_CHECK(adfQuadDist[1],adfQuadValue[1], 
                           iLeftX, panLastY[iLeftX], iX, iY, 
                           pafLastValue[iLeftX] );

                // top right and bottom right do no include center pixel.
                if( iStep == 0 )
                     continue;
                    
                // top right includes current line 
                QUAD_CHECK(adfQuadDist[2],adfQuadValue[2], 
                           iRightX, panTopDownY[iRightX], iX, iY,
                           pafTopDownValue[iRightX] );

                // bottom right
                QUAD_CHECK(adfQuadDist[3],adfQuadValue[3], 
                           iRightX, panLastY[iRightX], iX, iY,
                           pafLastValue[iRightX] );

                // every four steps, recompute maximum distance.
                if( (iStep & 0x3) == 0 )
                    nThisMaxSearchDist = (int) floor(
                        MAX(MAX(adfQuadDist[0],adfQuadDist[1]),
                            MAX(adfQuadDist[2],adfQuadDist[3])) );
            }

            double dfWeightSum = 0.0;
            double dfValueSum = 0.0;
            
            for( iQuad = 0; iQuad < 4; iQuad++ )
            {
                if( adfQuadDist[iQuad] <= dfMaxSearchDist )
                {
                    double dfWeight = 1.0 / adfQuadDist[iQuad];

                    dfWeightSum += dfWeight;
                    dfValueSum += adfQuadValue[iQuad] * dfWeight;
                }
            }

            if( dfWeightSum > 0.0 )
            {
                pabyMask[iX] = 255;
                pabyFiltMask[iX] = 255;
                pafScanline[iX] = (float) (dfValueSum / dfWeightSum);
            }

        }

/* -------------------------------------------------------------------- */
/*      Write out the updated data and mask information.                */
/* -------------------------------------------------------------------- */
        eErr = 
            GDALRasterIO( hTargetBand, GF_Write, 0, iY, nXSize, 1, 
                          pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
        
        if( eErr != CE_None )
            break;

        eErr = 
            GDALRasterIO( hFiltMaskBand, GF_Write, 0, iY, nXSize, 1, 
                          pabyFiltMask, nXSize, 1, GDT_Byte, 0, 0 );
        
        if( eErr != CE_None )
            break;

/* -------------------------------------------------------------------- */
/*      Flip this/last buffers.                                         */
/* -------------------------------------------------------------------- */
        {
            float *pafTmp = pafThisValue;
            pafThisValue = pafLastValue;
            pafLastValue = pafTmp;
            
            GUInt32 *panTmp = panThisY;
            panThisY = panLastY;
            panLastY = panTmp;
        }

/* -------------------------------------------------------------------- */
/*      report progress.                                                */
/* -------------------------------------------------------------------- */
        if( eErr == CE_None
            && !pfnProgress( dfProgressRatio*(0.5+0.5*(nYSize-iY) / (double)nYSize), 
                             "Filling...", pProgressArg ) )
        {
            CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
            eErr = CE_Failure;
        }
    }        

/* ==================================================================== */
/*      Now we will do iterative average filters over the               */
/*      interpolated values to smooth things out and make linear        */
/*      artifacts less obvious.                                         */
/* ==================================================================== */
    if( eErr == CE_None && nSmoothingIterations > 0 )
    {
        // force masks to be to flushed and recomputed.
        GDALFlushRasterCache( hMaskBand );

        void *pScaledProgress;
        pScaledProgress =
            GDALCreateScaledProgress( dfProgressRatio, 1.0, pfnProgress, NULL );

        eErr = GDALMultiFilter( hTargetBand, hMaskBand, hFiltMaskBand, 
                                nSmoothingIterations,
                                GDALScaledProgress, pScaledProgress );

        GDALDestroyScaledProgress( pScaledProgress );
    }

/* -------------------------------------------------------------------- */
/*      Close and clean up temporary files. Free working buffers        */
/* -------------------------------------------------------------------- */
end:
    CPLFree(panLastY);
    CPLFree(panThisY);
    CPLFree(panTopDownY);
    CPLFree(pafLastValue);
    CPLFree(pafThisValue);
    CPLFree(pafTopDownValue);
    CPLFree(pafScanline);
    CPLFree(pabyMask);
    CPLFree(pabyFiltMask);

    GDALClose( hYDS );
    GDALClose( hValDS );
    GDALClose( hFiltMaskDS );

    GDALDeleteDataset( hDriver, osYTmpFile );
    GDALDeleteDataset( hDriver, osValTmpFile );
    GDALDeleteDataset( hDriver, osFiltMaskTmpFile );

    return eErr;
}
int main( int argc, const char* argv[] )
{
    GDALDriverH   hDriver;
    double        adfGeoTransform[6];
    GDALDatasetH  in_Dataset;
    GDALDatasetH  mask_Dataset;
    GDALDatasetH  out_Dataset;
    GDALRasterBandH mask_band;
    char            *mask_scan_line, *data_scan_line;
    int             nBlockXSize, nBlockYSize;
    int             bGotMin, bGotMax;
    int             bands;
    int             xsize;
    double          adfMinMax[2];
    
    GDALAllRegister();
    
    if ( argc != 2) {
        printf("Usage: %s <file to add mask to> \n", argv[0]);
        printf("This utility adds a nodata mask to a file, were the datadata value is \"0\"\n");
        printf("contact/blame [email protected] for questions/problems.\n");
        return 0;
    }
    
    /* open datasets..*/
    in_Dataset = GDAL_open( argv[1]);
    
    /* add mask.. */
    GDALCreateDatasetMaskBand( in_Dataset, 0);
    
    /* Basic info on source dataset..*/
    GDALGetBlockSize(GDALGetRasterBand( in_Dataset, 1 ) , &nBlockXSize, &nBlockYSize );
    printf( "Block=%dx%d Type=%s, ColorInterp=%s\n",
                nBlockXSize, nBlockYSize,
                GDALGetDataTypeName(GDALGetRasterDataType( GDALGetRasterBand( in_Dataset, 1 ))),
                GDALGetColorInterpretationName(
                    GDALGetRasterColorInterpretation(GDALGetRasterBand( in_Dataset, 1 ))));
    
    /* Loop though bands, wiping values with mask values of 0.. */
    xsize = GDALGetRasterXSize( in_Dataset );
    mask_scan_line = (char *) CPLMalloc(sizeof(char)*xsize);
    data_scan_line = (char *) CPLMalloc(sizeof(char)*xsize);
    for (bands=1; bands <= GDALGetRasterCount( in_Dataset ); bands ++ ) {
        int x;
        GDALRasterBandH data_band, out_band;
        int y_index = 0;
        
        printf("INFO: Doing band %d of %d\n", bands,GDALGetRasterCount( in_Dataset ) );
        data_band =  GDALGetRasterBand( in_Dataset, bands);
        mask_band = GDALGetMaskBand(data_band);
        for (y_index = 0; y_index <GDALGetRasterYSize( in_Dataset ); y_index ++ ) {
            /* Read data..*/
            GDALRasterIO( data_band, GF_Read, 0, y_index, xsize , 1, data_scan_line, xsize , 1, GDT_Byte, 0, 0 );
            
            for(x=0; x < xsize; x++) {
                /* if mask is set to 0, then mask off...*/
                /* lame nodata handleing, but such is life.. */
                if ( data_scan_line[x] == 0 )
                    mask_scan_line[x]=0;
                else
                    mask_scan_line[x]=255;
            }
            
            /* now write out band..*/
            GDALRasterIO( mask_band, GF_Write, 0, y_index, xsize , 1, mask_scan_line, xsize , 1, GDT_Byte, 0, 0 );
        }
        
    }
    
    GDALClose(in_Dataset);
}
Example #7
0
// build out_ds
static ERL_NIF_TERM gdal_nif_create_warped_vrtimg(ErlNifEnv* env, int argc,
                                          const ERL_NIF_TERM argv[])
{
    ErlNifBinary filenameBin;
    if (!enif_inspect_iolist_as_binary(env, argv[0], &filenameBin) || 
        (filenameBin.size >= FILENAME_LEN)) {
        return make_error_msg(env, "filename error, maybe too long");
    }

    char imgfilename[FILENAME_LEN] = "";
    size_t name_sz = filenameBin.size;
    memcpy(imgfilename, filenameBin.data, filenameBin.size);
    DEBUG("img filename: %s\r\n", imgfilename);

    int epsg_code;
    if (!enif_get_int(env, argv[1], &epsg_code)) {
        return enif_make_badarg(env);
    }

    GDALDatasetH in_ds = GDALOpenShared(imgfilename, GA_ReadOnly);
    if (in_ds == NULL) {
        const char* msg = "It is not possible to open the input file '%s'.";
        char errstr[name_sz + strlen(msg) + 1];
        sprintf(errstr, msg, imgfilename);
        return make_error_msg(env, errstr);
    }

    gdal_img_handle* handle = enif_alloc_resource(
                                            gdal_img_RESOURCE, 
                                            sizeof(gdal_img_handle));
    memset(handle, '\0', sizeof(*handle));
    handle->in_ds = in_ds;
    handle->options_resampling = "average";
    handle->querysize = 256 * 4;
    handle->tilesize = 256;

    int rasterCount = GDALGetRasterCount(in_ds);
    if (rasterCount == 0) {
        const char* msg = "Input file '%s' has no raster band";
        char errstr[name_sz + strlen(msg) + 1];
        sprintf(errstr, msg, imgfilename);

        destroy_img_handle(handle);
        return make_error_msg(env, errstr);
    }

    GDALRasterBandH hBand = GDALGetRasterBand(in_ds, 1);
    if (GDALGetRasterColorTable(hBand) != NULL) {
        const char* msg = 
            "Please convert this file to RGB/RGBA and run gdal2tiles on the result.\n" 
            "From paletted file you can create RGBA file (temp.vrt) by:\n"
            "gdal_translate -of vrt -expand rgba %s temp.vrt\n"
            "then run this program: gdal2tiles temp.vrt";
        char errstr[name_sz + strlen(msg) + 1];
        sprintf(errstr, msg, imgfilename);

        destroy_img_handle(handle);
        return make_error_msg(env, errstr);
    }

    double padfTransform[6];
    double errTransform[6] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
    GDALGetGeoTransform(in_ds, padfTransform);
    if (0 == memcmp(padfTransform, errTransform, sizeof(errTransform))
             && GDALGetGCPCount(in_ds) == 0) {
        destroy_img_handle(handle);
        return make_error_msg(env, 
                              "There is no georeference - "
                              "neither affine transformation (worldfile) nor GCPs");
    }

    const char* in_srs_wkt = GDALGetProjectionRef(in_ds);
    if (in_srs_wkt == NULL && GDALGetGCPCount(in_ds) != 0) {
        in_srs_wkt = GDALGetGCPProjection(in_ds);
    }
    char* out_srs_wkt = get_wkt_of(epsg_code);
    GDALDatasetH out_ds = GDALAutoCreateWarpedVRT(in_ds, 
                                                  in_srs_wkt, 
                                                  out_srs_wkt, 
                                                  GRA_NearestNeighbour, 
                                                  0.0, 
                                                  NULL);
    handle->out_ds = out_ds;
    OGRFree(out_srs_wkt);


    handle->alphaBand = GDALGetMaskBand(GDALGetRasterBand(handle->out_ds, 1));
    rasterCount = GDALGetRasterCount(handle->out_ds);
    unsigned int dataBandsCount;
    if (GDALGetMaskFlags(handle->alphaBand) & GMF_ALPHA || 
            rasterCount == 4 || rasterCount == 2) {
        dataBandsCount = rasterCount - 1;
    }
    else {
        dataBandsCount = rasterCount;
    }
    handle->dataBandsCount = dataBandsCount;
    handle->tilebands = dataBandsCount + 1;


    ERL_NIF_TERM imginfo = get_imginfo(env, out_ds);
    if (enif_compare(ATOM_ERROR, imginfo) == 0) {
        destroy_img_handle(handle);
        return make_error_msg(env,
                              "Georeference of the raster contains rotation or skew. "
                              "Such raster is not supported. "
                              "Please use gdalwarp first");
    }

    ERL_NIF_TERM imgref = enif_make_resource(env, handle);
    enif_release_resource(handle);

    return enif_make_tuple3(env, ATOM_OK, imgref, imginfo);
}
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;
}