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