int main( int argc, char ** argv ) { const char *pszSrcFilename = NULL; const char *pszDstFilename = NULL; int nOrder = 0; void *hTransformArg; GDALTransformerFunc pfnTransformer = NULL; int nGCPCount = 0; GDAL_GCP *pasGCPs = NULL; int bInverse = FALSE; char **papszTO = 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); } GDALAllRegister(); argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 ); if( argc < 1 ) exit( -argc ); /* -------------------------------------------------------------------- */ /* Parse arguments. */ /* -------------------------------------------------------------------- */ int i; 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],"-t_srs") && i < argc-1 ) { char *pszSRS = SanitizeSRS(argv[++i]); papszTO = CSLSetNameValue( papszTO, "DST_SRS", pszSRS ); CPLFree( pszSRS ); } else if( EQUAL(argv[i],"-s_srs") && i < argc-1 ) { char *pszSRS = SanitizeSRS(argv[++i]); papszTO = CSLSetNameValue( papszTO, "SRC_SRS", pszSRS ); CPLFree( pszSRS ); } else if( EQUAL(argv[i],"-order") && i < argc-1 ) { nOrder = atoi(argv[++i]); papszTO = CSLSetNameValue( papszTO, "MAX_GCP_ORDER", argv[i] ); } else if( EQUAL(argv[i],"-tps") ) { papszTO = CSLSetNameValue( papszTO, "METHOD", "GCP_TPS" ); nOrder = -1; } else if( EQUAL(argv[i],"-rpc") ) { papszTO = CSLSetNameValue( papszTO, "METHOD", "RPC" ); } else if( EQUAL(argv[i],"-geoloc") ) { papszTO = CSLSetNameValue( papszTO, "METHOD", "GEOLOC_ARRAY" ); } else if( EQUAL(argv[i],"-i") ) { bInverse = TRUE; } else if( EQUAL(argv[i],"-to") && i < argc-1 ) { papszTO = CSLAddString( papszTO, argv[++i] ); } 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 = atof(argv[++i]); pasGCPs[nGCPCount-1].dfGCPLine = atof(argv[++i]); pasGCPs[nGCPCount-1].dfGCPX = atof(argv[++i]); pasGCPs[nGCPCount-1].dfGCPY = atof(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 = atof(argv[++i]); } /* should set id and info? */ } else if( argv[i][0] == '-' ) Usage(); else if( pszSrcFilename == NULL ) pszSrcFilename = argv[i]; else if( pszDstFilename == NULL ) pszDstFilename = argv[i]; else Usage(); } /* -------------------------------------------------------------------- */ /* Open src and destination file, if appropriate. */ /* -------------------------------------------------------------------- */ GDALDatasetH hSrcDS = NULL, hDstDS = NULL; if( pszSrcFilename != NULL ) { hSrcDS = GDALOpen( pszSrcFilename, GA_ReadOnly ); if( hSrcDS == NULL ) exit( 1 ); } if( pszDstFilename != NULL ) { hDstDS = GDALOpen( pszDstFilename, GA_ReadOnly ); if( hDstDS == NULL ) exit( 1 ); } if( hSrcDS != NULL && nGCPCount > 0 ) { fprintf( stderr, "Commandline GCPs and input file specified, specify one or the other.\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Create a transformation object from the source to */ /* destination coordinate system. */ /* -------------------------------------------------------------------- */ if( nGCPCount != 0 && nOrder == -1 ) { pfnTransformer = GDALTPSTransform; hTransformArg = GDALCreateTPSTransformer( nGCPCount, pasGCPs, FALSE ); } else if( nGCPCount != 0 ) { pfnTransformer = GDALGCPTransform; hTransformArg = GDALCreateGCPTransformer( nGCPCount, pasGCPs, nOrder, FALSE ); } else { pfnTransformer = GDALGenImgProjTransform; hTransformArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszTO ); } CSLDestroy( papszTO ); if( hTransformArg == NULL ) { exit( 1 ); } /* -------------------------------------------------------------------- */ /* Read points from stdin, transform and write to stdout. */ /* -------------------------------------------------------------------- */ while( !feof(stdin) ) { char szLine[1024]; if( fgets( szLine, sizeof(szLine)-1, stdin ) == NULL ) break; char **papszTokens = CSLTokenizeString(szLine); double dfX, dfY, dfZ = 0.0; int bSuccess = TRUE; if( CSLCount(papszTokens) < 2 ) { CSLDestroy(papszTokens); continue; } dfX = atof(papszTokens[0]); dfY = atof(papszTokens[1]); if( CSLCount(papszTokens) >= 3 ) dfZ = atof(papszTokens[2]); if( pfnTransformer( hTransformArg, bInverse, 1, &dfX, &dfY, &dfZ, &bSuccess ) && bSuccess ) { printf( "%.15g %.15g %.15g\n", dfX, dfY, dfZ ); } else { printf( "transformation failed.\n" ); } CSLDestroy(papszTokens); } if( nGCPCount != 0 && nOrder == -1 ) { GDALDestroyTPSTransformer(hTransformArg); } else if( nGCPCount != 0 ) { GDALDestroyGCPTransformer(hTransformArg); } else { GDALDestroyGenImgProjTransformer(hTransformArg); } if (nGCPCount) { GDALDeinitGCPs( nGCPCount, pasGCPs ); CPLFree( pasGCPs ); } if (hSrcDS) GDALClose(hSrcDS); if (hDstDS) GDALClose(hDstDS); GDALDumpOpenDatasets( stderr ); GDALDestroyDriverManager(); CSLDestroy( argv ); return 0; }
int main( int nArgc, char ** papszArgv ) { // register drivers GDALAllRegister(); if( nArgc < 2 ) return EXIT_FAILURE; double dfaCornersX[5] = {0}; double dfaCornersY[5] = {0}; CPLString sFileName; // parse input values for( int iArg = 1; iArg < nArgc; iArg++ ) { if( EQUAL(papszArgv[iArg],"-nw")) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2); const char* pszCoord = papszArgv[++iArg]; dfaCornersY[1] = CPLAtofM(pszCoord); pszCoord = papszArgv[++iArg]; dfaCornersX[1] = CPLAtofM(pszCoord); } else if( EQUAL(papszArgv[iArg],"-ne")) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2); const char* pszCoord = papszArgv[++iArg]; dfaCornersY[2] = CPLAtofM(pszCoord); pszCoord = papszArgv[++iArg]; dfaCornersX[2] = CPLAtofM(pszCoord); } else if( EQUAL(papszArgv[iArg],"-se")) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2); const char* pszCoord = papszArgv[++iArg]; dfaCornersY[3] = CPLAtofM(pszCoord); pszCoord = papszArgv[++iArg]; dfaCornersX[3] = CPLAtofM(pszCoord); } else if( EQUAL(papszArgv[iArg],"-sw")) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2); const char* pszCoord = papszArgv[++iArg]; dfaCornersY[4] = CPLAtofM(pszCoord); pszCoord = papszArgv[++iArg]; dfaCornersX[4] = CPLAtofM(pszCoord); } else if( EQUAL(papszArgv[iArg],"-c")) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2); const char* pszCoord = papszArgv[++iArg]; dfaCornersY[0] = CPLAtofM(pszCoord); pszCoord = papszArgv[++iArg]; dfaCornersX[0] = CPLAtofM(pszCoord); } else if(sFileName.empty()) sFileName = papszArgv[iArg]; } OGRSpatialReference oOGRSpatialReference(SRS_WKT_WGS84); int nZoneNo = ceil( (180.0 + dfaCornersX[0]) / 6.0 ); OGRSpatialReference oDstSpatialReference(SRS_WKT_WGS84); oDstSpatialReference.SetUTM(nZoneNo, dfaCornersY[0] > 0); // transform coordinates from WGS84 to UTM OGRCoordinateTransformation *poCT = OGRCreateCoordinateTransformation( &oOGRSpatialReference, &oDstSpatialReference); if(!poCT) { Usage("get coordinate transformation failed"); return EXIT_FAILURE; } int nResult = poCT->Transform(5, dfaCornersX, dfaCornersY, NULL); if(!nResult) { Usage("transformation failed"); return EXIT_FAILURE; } // open input dataset GDALDataset *poSrcDataset = (GDALDataset *) GDALOpen( sFileName, GA_ReadOnly ); // GA_Update char* pszSpaRefDef = NULL; if( oDstSpatialReference.exportToWkt(&pszSpaRefDef) != OGRERR_NONE) { CPLFree( pszSpaRefDef ); GDALClose( (GDALDatasetH) poSrcDataset ); return EXIT_FAILURE; } // search point along image // add GCP to opened raster OGRPoint ptCenter(dfaCornersX[0], dfaCornersY[0]); OGRPoint pt1(dfaCornersX[1], dfaCornersY[1]); // NW Cormer OGRPoint pt2(dfaCornersX[2], dfaCornersY[2]); // NE Corner OGRPoint pt3(dfaCornersX[3], dfaCornersY[3]); // SE Corner OGRPoint pt4(dfaCornersX[4], dfaCornersY[4]); // SW Corner int nGCPCount = 0; OGREnvelope DstEnv; GDAL_GCP *paGSPs = PrepareGCP(sFileName, &pt1, &pt2, &pt3, &pt4, &ptCenter, oDstSpatialReference, poSrcDataset->GetRasterXSize(), poSrcDataset->GetRasterYSize(), nGCPCount, DstEnv); if(poSrcDataset->SetGCPs(nGCPCount, paGSPs, pszSpaRefDef) != CE_None) { Usage( "Set GCPs failed" ); return EXIT_FAILURE; } // create warper char **papszTO = NULL; papszTO = CSLSetNameValue( papszTO, "METHOD", "GCP_TPS" ); papszTO = CSLSetNameValue( papszTO, "NUM_THREADS", "4" ); papszTO = CSLSetNameValue( papszTO, "DST_SRS", pszSpaRefDef ); papszTO = CSLSetNameValue( papszTO, "SRC_SRS", pszSpaRefDef ); papszTO = CSLSetNameValue( papszTO, "INSERT_CENTER_LONG", "FALSE" ); GDALDriver *poOutputDriver = (GDALDriver *) GDALGetDriverByName( "GTiff" ); CPLSetConfigOption( "CHECK_WITH_INVERT_PROJ", "TRUE" ); void* hTransformArg = GDALCreateGenImgProjTransformer2( poSrcDataset, NULL, papszTO ); GDALTransformerInfo* psInfo = (GDALTransformerInfo*)hTransformArg; double adfThisGeoTransform[6]; double adfExtent[4]; int nThisPixels, nThisLines; // suggest the raster output size if( GDALSuggestedWarpOutput2( poSrcDataset, psInfo->pfnTransform, hTransformArg, adfThisGeoTransform, &nThisPixels, &nThisLines, adfExtent, 0 ) != CE_None ) { Usage( "Suggest Output failed" ); return EXIT_FAILURE; } adfThisGeoTransform[0] = DstEnv.MinX; adfThisGeoTransform[3] = DstEnv.MaxY; int nPixels = (int) ((DstEnv.MaxX - DstEnv.MinX) / adfThisGeoTransform[1] + 0.5); int nLines = (int) ((DstEnv.MaxY - DstEnv.MinY) / -adfThisGeoTransform[5] + 0.5); GDALSetGenImgProjTransformerDstGeoTransform( hTransformArg, adfThisGeoTransform); // create new raster CPLString sOutputRasterPath = CPLResetExtension(sFileName, "tif"); GDALDataset *poDstDataset = poOutputDriver->Create(sOutputRasterPath, nPixels, nLines, poSrcDataset->GetRasterCount(), GDT_Byte, NULL ); if( NULL == poDstDataset ) { Usage( "Create Output failed" ); return EXIT_FAILURE; } poDstDataset->SetProjection( pszSpaRefDef ); poDstDataset->SetGeoTransform( adfThisGeoTransform ); #ifdef APRROX_MAXERROR hTransformArg = GDALCreateApproxTransformer( GDALGenImgProjTransform, hTransformArg, APRROX_MAXERROR); GDALTransformerFunc pfnTransformer = GDALApproxTransform; GDALApproxTransformerOwnsSubtransformer(hTransformArg, TRUE); #else GDALTransformerFunc pfnTransformer = GDALGenImgProjTransform; #endif // APRROX_MAXERROR // warp GDALWarpOptions *psWO = GDALCreateWarpOptions(); psWO->eWorkingDataType = GDT_Byte; psWO->eResampleAlg = GRA_NearestNeighbour; psWO->hSrcDS = poSrcDataset; psWO->hDstDS = poDstDataset; psWO->pfnTransformer = pfnTransformer; psWO->pTransformerArg = hTransformArg; psWO->pfnProgress = GDALTermProgress; psWO->nBandCount = poSrcDataset->GetRasterCount(); psWO->panSrcBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int)); psWO->panDstBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int)); for(int i = 0; i < psWO->nBandCount; ++i ) { psWO->panSrcBands[i] = i+1; psWO->panDstBands[i] = i+1; } GDALWarpOperation oWO; if( oWO.Initialize( psWO ) == CE_None ) { #ifdef MULTI if( oWO.ChunkAndWarpMulti( 0, 0, poDstDataset->GetRasterXSize(), poDstDataset->GetRasterYSize() ) != CE_None) #else //MULTI if( oWO.ChunkAndWarpImage( 0, 0, poDstDataset->GetRasterXSize(), poDstDataset->GetRasterYSize() ) != CE_None) #endif //MULTI { const char* err = CPLGetLastErrorMsg(); Usage( CPLSPrintf("Warp failed.%s", err) ); return EXIT_FAILURE; } } // cleanup GDALDestroyWarpOptions( psWO ); CSLDestroy( papszTO ); CPLFree( pszSpaRefDef ); GDALClose( (GDALDatasetH) poSrcDataset ); GDALClose( (GDALDatasetH) poDstDataset ); GDALDestroyDriverManager(); return EXIT_SUCCESS; }
MAIN_START(argc, argv) { // 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); } GDALAllRegister(); argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 ); if( argc < 1 ) exit( -argc ); const char *pszSrcFilename = nullptr; const char *pszDstFilename = nullptr; int nOrder = 0; void *hTransformArg; GDALTransformerFunc pfnTransformer = nullptr; int nGCPCount = 0; GDAL_GCP *pasGCPs = nullptr; int bInverse = FALSE; CPLStringList aosTO; int bOutputXY = FALSE; double dfX = 0.0; double dfY = 0.0; double dfZ = 0.0; double dfT = 0.0; bool bCoordOnCommandLine = false; /* -------------------------------------------------------------------- */ /* Parse arguments. */ /* -------------------------------------------------------------------- */ for( int i = 1; i < argc && argv[i] != nullptr; 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")); CSLDestroy(argv); return 0; } else if( EQUAL(argv[i],"--help") ) { Usage(); } else if( EQUAL(argv[i],"-t_srs") ) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); const char *pszSRS = argv[++i]; if( !IsValidSRS(pszSRS) ) exit(1); aosTO.SetNameValue("DST_SRS", pszSRS ); } else if( EQUAL(argv[i],"-s_srs") ) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); const char *pszSRS = argv[++i]; if( !IsValidSRS(pszSRS) ) exit(1); aosTO.SetNameValue("SRC_SRS", pszSRS ); } else if( EQUAL(argv[i],"-ct") ) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); const char *pszCT = argv[++i]; aosTO.SetNameValue("COORDINATE_OPERATION", pszCT ); } else if( EQUAL(argv[i],"-order") ) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); nOrder = atoi(argv[++i]); aosTO.SetNameValue("MAX_GCP_ORDER", argv[i] ); } else if( EQUAL(argv[i],"-tps") ) { aosTO.SetNameValue("METHOD", "GCP_TPS" ); nOrder = -1; } else if( EQUAL(argv[i],"-rpc") ) { aosTO.SetNameValue("METHOD", "RPC" ); } else if( EQUAL(argv[i],"-geoloc") ) { aosTO.SetNameValue("METHOD", "GEOLOC_ARRAY" ); } else if( EQUAL(argv[i],"-i") ) { bInverse = TRUE; } else if( EQUAL(argv[i],"-to") ) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); aosTO.AddString( argv[++i] ); } else if( EQUAL(argv[i],"-gcp") ) { CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4); char* endptr = nullptr; /* -gcp pixel line easting northing [elev] */ nGCPCount++; pasGCPs = static_cast<GDAL_GCP *>( CPLRealloc(pasGCPs, sizeof(GDAL_GCP) * nGCPCount)); GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 ); pasGCPs[nGCPCount-1].dfGCPPixel = CPLAtof(argv[++i]); pasGCPs[nGCPCount-1].dfGCPLine = CPLAtof(argv[++i]); pasGCPs[nGCPCount-1].dfGCPX = CPLAtof(argv[++i]); pasGCPs[nGCPCount-1].dfGCPY = CPLAtof(argv[++i]); if( argv[i+1] != nullptr && (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 = CPLAtof(argv[++i]); } /* should set id and info? */ } else if( EQUAL(argv[i],"-output_xy") ) { bOutputXY = TRUE; } else if( EQUAL(argv[i],"-coord") && i + 2 < argc) { bCoordOnCommandLine = true; dfX = CPLAtof(argv[++i]); dfY = CPLAtof(argv[++i]); if( i + 1 < argc && CPLGetValueType(argv[i+1]) != CPL_VALUE_STRING ) dfZ = CPLAtof(argv[++i]); if( i + 1 < argc && CPLGetValueType(argv[i+1]) != CPL_VALUE_STRING ) dfT = CPLAtof(argv[++i]); } else if( argv[i][0] == '-' ) { Usage(CPLSPrintf("Unknown option name '%s'", argv[i])); } else if( pszSrcFilename == nullptr ) { pszSrcFilename = argv[i]; } else if( pszDstFilename == nullptr ) { pszDstFilename = argv[i]; } else { Usage("Too many command options."); } } /* -------------------------------------------------------------------- */ /* Open src and destination file, if appropriate. */ /* -------------------------------------------------------------------- */ GDALDatasetH hSrcDS = nullptr; if( pszSrcFilename != nullptr ) { hSrcDS = GDALOpen( pszSrcFilename, GA_ReadOnly ); if( hSrcDS == nullptr ) exit( 1 ); } GDALDatasetH hDstDS = nullptr; if( pszDstFilename != nullptr ) { hDstDS = GDALOpen( pszDstFilename, GA_ReadOnly ); if( hDstDS == nullptr ) exit( 1 ); } if( hSrcDS != nullptr && nGCPCount > 0 ) { fprintf(stderr, "Command line GCPs and input file specified, " "specify one or the other.\n"); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Create a transformation object from the source to */ /* destination coordinate system. */ /* -------------------------------------------------------------------- */ if( nGCPCount != 0 && nOrder == -1 ) { pfnTransformer = GDALTPSTransform; hTransformArg = GDALCreateTPSTransformer( nGCPCount, pasGCPs, FALSE ); } else if( nGCPCount != 0 ) { pfnTransformer = GDALGCPTransform; hTransformArg = GDALCreateGCPTransformer( nGCPCount, pasGCPs, nOrder, FALSE ); } else { pfnTransformer = GDALGenImgProjTransform; hTransformArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, aosTO.List() ); } if( hTransformArg == nullptr ) { exit( 1 ); } /* -------------------------------------------------------------------- */ /* Read points from stdin, transform and write to stdout. */ /* -------------------------------------------------------------------- */ double dfLastT = 0.0; while( bCoordOnCommandLine || !feof(stdin) ) { if( !bCoordOnCommandLine ) { char szLine[1024]; if( fgets( szLine, sizeof(szLine)-1, stdin ) == nullptr ) break; char **papszTokens = CSLTokenizeString(szLine); const int nCount = CSLCount(papszTokens); if( nCount < 2 ) { CSLDestroy(papszTokens); continue; } dfX = CPLAtof(papszTokens[0]); dfY = CPLAtof(papszTokens[1]); if( nCount >= 3 ) dfZ = CPLAtof(papszTokens[2]); else dfZ = 0.0; if( nCount == 4 ) dfT = CPLAtof(papszTokens[3]); else dfT = 0.0; CSLDestroy(papszTokens); } if( dfT != dfLastT && nGCPCount == 0 ) { if( dfT != 0.0 ) { aosTO.SetNameValue("COORDINATE_EPOCH", CPLSPrintf("%g", dfT)); } else { aosTO.SetNameValue("COORDINATE_EPOCH", nullptr); } GDALDestroyGenImgProjTransformer(hTransformArg); hTransformArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, aosTO.List() ); } int bSuccess = TRUE; if( pfnTransformer( hTransformArg, bInverse, 1, &dfX, &dfY, &dfZ, &bSuccess ) && bSuccess ) { if( bOutputXY ) CPLprintf( "%.15g %.15g\n", dfX, dfY ); else CPLprintf( "%.15g %.15g %.15g\n", dfX, dfY, dfZ ); } else { printf( "transformation failed.\n" ); } if( bCoordOnCommandLine ) break; dfLastT = dfT; } if( nGCPCount != 0 && nOrder == -1 ) { GDALDestroyTPSTransformer(hTransformArg); } else if( nGCPCount != 0 ) { GDALDestroyGCPTransformer(hTransformArg); } else { GDALDestroyGenImgProjTransformer(hTransformArg); } if (nGCPCount) { GDALDeinitGCPs( nGCPCount, pasGCPs ); CPLFree( pasGCPs ); } if (hSrcDS) GDALClose(hSrcDS); if (hDstDS) GDALClose(hDstDS); GDALDumpOpenDatasets( stderr ); GDALDestroyDriverManager(); CSLDestroy( argv ); return 0; }