EVOLUTION-MANAGER
Edit File: gdalinfo_lib.cpp
/****************************************************************************** * * Project: GDAL Utilities * Purpose: Command line application to list info about a file. * Author: Frank Warmerdam, warmerdam@pobox.com * * **************************************************************************** * Copyright (c) 1998, Frank Warmerdam * Copyright (c) 2007-2015, Even Rouault <even.rouault at spatialys.com> * Copyright (c) 2015, Faza Mahamood * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "cpl_port.h" #include "gdal_utils.h" #include "gdal_utils_priv.h" #include <cmath> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <new> #include <string> #include <vector> #include "commonutils.h" #include "cpl_conv.h" #include "cpl_error.h" #include "cpl_json_header.h" #include "cpl_minixml.h" #include "cpl_progress.h" #include "cpl_string.h" #include "cpl_vsi.h" #include "gdal.h" #include "gdal_alg.h" #include "gdal_priv.h" #include "gdal_rat.h" #include "ogr_api.h" #include "ogr_srs_api.h" #include "ogr_spatialref.h" #include "ogrgeojsonreader.h" #include "ogrgeojsonwriter.h" using std::vector; CPL_CVSID("$Id: gdalinfo_lib.cpp 5da1c4d1b6c7e38f7f5917fff3ddbc8ad42af7aa 2018-03-30 21:59:13 +0200 Even Rouault $") /*! output format */ typedef enum { /*! output in text format */ GDALINFO_FORMAT_TEXT = 0, /*! output in json format */ GDALINFO_FORMAT_JSON = 1 } GDALInfoFormat; /************************************************************************/ /* GDALInfoOptions */ /************************************************************************/ /** Options for use with GDALInfo(). GDALInfoOptions* must be allocated and * freed with GDALInfoOptionsNew() and GDALInfoOptionsFree() respectively. */ struct GDALInfoOptions { /*! output format */ GDALInfoFormat eFormat; int bComputeMinMax; /*! report histogram information for all bands */ int bReportHistograms; /*! report a PROJ.4 string corresponding to the file's coordinate system */ int bReportProj4; /*! read and display image statistics. Force computation if no statistics are stored in an image */ int bStats; /*! read and display image statistics. Force computation if no statistics are stored in an image. However, they may be computed based on overviews or a subset of all tiles. Useful if you are in a hurry and don't want precise stats. */ int bApproxStats; int bSample; /*! force computation of the checksum for each band in the dataset */ int bComputeChecksum; /*! allow or suppress ground control points list printing. It may be useful for datasets with huge amount of GCPs, such as L1B AVHRR or HDF4 MODIS which contain thousands of them. */ int bShowGCPs; /*! allow or suppress metadata printing. Some datasets may contain a lot of metadata strings. */ int bShowMetadata; /*! allow or suppress printing of raster attribute table */ int bShowRAT; /*! allow or suppress printing of color table */ int bShowColorTable; /*! list all metadata domains available for the dataset */ int bListMDD; /*! display the file list or the first file of the file list */ int bShowFileList; /*! report metadata for the specified domains. "all" can be used to report metadata in all domains. */ char **papszExtraMDDomains; bool bStdoutOutput; }; static int GDALInfoReportCorner( const GDALInfoOptions* psOptions, GDALDatasetH hDataset, OGRCoordinateTransformationH hTransform, const char * corner_name, double x, double y, bool bJson, json_object *poCornerCoordinates, json_object *poLongLatExtentCoordinates, CPLString& osStr ); static void GDALInfoReportMetadata( const GDALInfoOptions* psOptions, GDALMajorObjectH hObject, bool bIsBand, bool bJson, json_object *poMetadata, CPLString& osStr ); static void Concat( CPLString& osRet, bool bStdoutOutput, const char* pszFormat, ... ) CPL_PRINT_FUNC_FORMAT (3, 4); static void Concat( CPLString& osRet, bool bStdoutOutput, const char* pszFormat, ... ) { va_list args; va_start( args, pszFormat ); if( bStdoutOutput ) { vfprintf(stdout, pszFormat, args ); } else { try { CPLString osTarget; osTarget.vPrintf( pszFormat, args ); osRet += osTarget; } catch( const std::bad_alloc& ) { CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory"); } } va_end( args ); } /************************************************************************/ /* GDALInfo() */ /************************************************************************/ /** * Lists various information about a GDAL supported raster dataset. * * This is the equivalent of the <a href="gdalinfo.html">gdalinfo</a> utility. * * GDALInfoOptions* must be allocated and freed with GDALInfoOptionsNew() * and GDALInfoOptionsFree() respectively. * * @param hDataset the dataset handle. * @param psOptions the options structure returned by GDALInfoOptionsNew() or NULL. * @return string corresponding to the information about the raster dataset (must be freed with CPLFree()), or NULL in case of error. * * @since GDAL 2.1 */ char *GDALInfo( GDALDatasetH hDataset, const GDALInfoOptions *psOptions ) { if( hDataset == nullptr ) return nullptr; GDALInfoOptions* psOptionsToFree = nullptr; if( psOptions == nullptr ) { psOptionsToFree = GDALInfoOptionsNew(nullptr, nullptr); psOptions = psOptionsToFree; } CPLString osStr; json_object *poJsonObject = nullptr; json_object *poBands = nullptr; json_object *poMetadata = nullptr; const bool bJson = psOptions->eFormat == GDALINFO_FORMAT_JSON; /* -------------------------------------------------------------------- */ /* Report general info. */ /* -------------------------------------------------------------------- */ GDALDriverH hDriver = GDALGetDatasetDriver( hDataset ); if( bJson ) { json_object *poDescription = json_object_new_string(GDALGetDescription(hDataset)); json_object *poDriverShortName = json_object_new_string(GDALGetDriverShortName(hDriver)); json_object *poDriverLongName = json_object_new_string(GDALGetDriverLongName(hDriver)); poJsonObject = json_object_new_object(); poBands = json_object_new_array(); poMetadata = json_object_new_object(); json_object_object_add(poJsonObject, "description", poDescription); json_object_object_add(poJsonObject, "driverShortName", poDriverShortName); json_object_object_add(poJsonObject, "driverLongName", poDriverLongName); } else { Concat( osStr, psOptions->bStdoutOutput, "Driver: %s/%s\n", GDALGetDriverShortName( hDriver ), GDALGetDriverLongName( hDriver ) ); } char **papszFileList = GDALGetFileList( hDataset ); if( papszFileList == nullptr || *papszFileList == nullptr ) { if( bJson ) { json_object *poFiles = json_object_new_array(); json_object_object_add(poJsonObject, "files", poFiles); } else { Concat( osStr, psOptions->bStdoutOutput, "Files: none associated\n" ); } } else { if( bJson ) { if( psOptions->bShowFileList ) { json_object *poFiles = json_object_new_array(); for( int i = 0; papszFileList[i] != nullptr; i++ ) { json_object *poFile = json_object_new_string(papszFileList[i]); json_object_array_add(poFiles, poFile); } json_object_object_add(poJsonObject, "files", poFiles); } } else { Concat(osStr, psOptions->bStdoutOutput, "Files: %s\n", papszFileList[0] ); if( psOptions->bShowFileList ) { for( int i = 1; papszFileList[i] != nullptr; i++ ) Concat(osStr, psOptions->bStdoutOutput, " %s\n", papszFileList[i] ); } } } CSLDestroy( papszFileList ); if( bJson ) { json_object *poSize = json_object_new_array(); json_object *poSizeX = json_object_new_int(GDALGetRasterXSize(hDataset)); json_object *poSizeY = json_object_new_int(GDALGetRasterYSize(hDataset)); json_object_array_add(poSize, poSizeX); json_object_array_add(poSize, poSizeY); json_object_object_add(poJsonObject, "size", poSize); } else { Concat(osStr, psOptions->bStdoutOutput, "Size is %d, %d\n", GDALGetRasterXSize( hDataset ), GDALGetRasterYSize( hDataset ) ); } /* -------------------------------------------------------------------- */ /* Report projection. */ /* -------------------------------------------------------------------- */ if( GDALGetProjectionRef( hDataset ) != nullptr ) { json_object *poCoordinateSystem = nullptr; if( bJson ) poCoordinateSystem = json_object_new_object(); char *pszProjection = const_cast<char *>( GDALGetProjectionRef( hDataset ) ); OGRSpatialReferenceH hSRS = OSRNewSpatialReference(nullptr); if( OSRImportFromWkt( hSRS, &pszProjection ) == CE_None ) { char *pszPrettyWkt = nullptr; OSRExportToPrettyWkt( hSRS, &pszPrettyWkt, FALSE ); if( bJson ) { json_object *poWkt = json_object_new_string(pszPrettyWkt); json_object_object_add(poCoordinateSystem, "wkt", poWkt); } else { Concat( osStr, psOptions->bStdoutOutput, "Coordinate System is:\n%s\n", pszPrettyWkt ); } CPLFree( pszPrettyWkt ); } else { if( bJson ) { json_object *poWkt = json_object_new_string(GDALGetProjectionRef(hDataset)); json_object_object_add(poCoordinateSystem, "wkt", poWkt); } else { Concat( osStr, psOptions->bStdoutOutput, "Coordinate System is `%s'\n", GDALGetProjectionRef( hDataset ) ); } } if ( psOptions->bReportProj4 ) { char *pszProj4 = nullptr; OSRExportToProj4( hSRS, &pszProj4 ); if( bJson ) { json_object *proj4 = json_object_new_string(pszProj4); json_object_object_add(poCoordinateSystem, "proj4", proj4); } else Concat(osStr, psOptions->bStdoutOutput, "PROJ.4 string is:\n\'%s\'\n",pszProj4); CPLFree( pszProj4 ); } if( bJson ) json_object_object_add(poJsonObject, "coordinateSystem", poCoordinateSystem); OSRDestroySpatialReference( hSRS ); } /* -------------------------------------------------------------------- */ /* Report Geotransform. */ /* -------------------------------------------------------------------- */ double adfGeoTransform[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None ) { if( bJson ) { json_object *poGeoTransform = json_object_new_array(); for( int i = 0; i < 6; i++ ) { json_object *poGeoTransformCoefficient = json_object_new_double_with_precision(adfGeoTransform[i], 16); json_object_array_add(poGeoTransform, poGeoTransformCoefficient); } json_object_object_add(poJsonObject, "geoTransform", poGeoTransform); } else { if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0 ) { Concat( osStr, psOptions->bStdoutOutput, "Origin = (%.15f,%.15f)\n", adfGeoTransform[0], adfGeoTransform[3] ); Concat( osStr, psOptions->bStdoutOutput, "Pixel Size = (%.15f,%.15f)\n", adfGeoTransform[1], adfGeoTransform[5] ); } else { Concat( osStr, psOptions->bStdoutOutput, "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( psOptions->bShowGCPs && GDALGetGCPCount( hDataset ) > 0 ) { json_object * const poGCPs = bJson ? json_object_new_object() : nullptr; if (GDALGetGCPProjection(hDataset) != nullptr) { json_object *poGCPCoordinateSystem = nullptr; char *pszProjection = const_cast<char *>( GDALGetGCPProjection( hDataset ) ); OGRSpatialReferenceH hSRS = OSRNewSpatialReference(nullptr); if( OSRImportFromWkt( hSRS, &pszProjection ) == CE_None ) { char *pszPrettyWkt = nullptr; OSRExportToPrettyWkt( hSRS, &pszPrettyWkt, FALSE ); if( bJson ) { json_object *poWkt = json_object_new_string(pszPrettyWkt); poGCPCoordinateSystem = json_object_new_object(); json_object_object_add(poGCPCoordinateSystem, "wkt", poWkt); } else { Concat(osStr, psOptions->bStdoutOutput, "GCP Projection = \n%s\n", pszPrettyWkt ); } CPLFree( pszPrettyWkt ); } else { if(bJson) { json_object *poWkt = json_object_new_string(GDALGetGCPProjection(hDataset)); poGCPCoordinateSystem = json_object_new_object(); json_object_object_add(poGCPCoordinateSystem, "wkt", poWkt); } else { Concat(osStr, psOptions->bStdoutOutput, "GCP Projection = %s\n", GDALGetGCPProjection( hDataset ) ); } } if(bJson) json_object_object_add(poGCPs, "coordinateSystem", poGCPCoordinateSystem); OSRDestroySpatialReference( hSRS ); } json_object * const poGCPList = bJson ? json_object_new_array() : nullptr; for( int i = 0; i < GDALGetGCPCount(hDataset); i++ ) { const GDAL_GCP *psGCP = GDALGetGCPs( hDataset ) + i; if( bJson ) { json_object *poGCP = json_object_new_object(); json_object *poId = json_object_new_string(psGCP->pszId); json_object *poInfo = json_object_new_string(psGCP->pszInfo); json_object *poPixel = json_object_new_double_with_precision(psGCP->dfGCPPixel, 15); json_object *poLine = json_object_new_double_with_precision(psGCP->dfGCPLine, 15); json_object *poX = json_object_new_double_with_precision(psGCP->dfGCPX, 15); json_object *poY = json_object_new_double_with_precision(psGCP->dfGCPY, 15); json_object *poZ = json_object_new_double_with_precision(psGCP->dfGCPZ, 15); json_object_object_add(poGCP, "id", poId); json_object_object_add(poGCP, "info", poInfo); json_object_object_add(poGCP, "pixel", poPixel); json_object_object_add(poGCP, "line", poLine); json_object_object_add(poGCP, "x", poX); json_object_object_add(poGCP, "y", poY); json_object_object_add(poGCP, "z", poZ); json_object_array_add(poGCPList, poGCP); } else { Concat(osStr, psOptions->bStdoutOutput, "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 ); } } if( bJson ) { json_object_object_add(poGCPs, "gcpList", poGCPList); json_object_object_add(poJsonObject, "gcps", poGCPs); } } /* -------------------------------------------------------------------- */ /* Report metadata. */ /* -------------------------------------------------------------------- */ GDALInfoReportMetadata( psOptions, hDataset, false, bJson, poMetadata, osStr ); if( bJson ) { if( psOptions->bShowMetadata ) json_object_object_add( poJsonObject, "metadata", poMetadata ); else json_object_put(poMetadata); } /* -------------------------------------------------------------------- */ /* Setup projected to lat/long transform if appropriate. */ /* -------------------------------------------------------------------- */ const char *pszProjection = nullptr; if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None ) pszProjection = GDALGetProjectionRef(hDataset); OGRCoordinateTransformationH hTransform = nullptr; bool bTransformToWGS84 = false; if( pszProjection != nullptr && strlen(pszProjection) > 0 ) { OGRSpatialReferenceH hLatLong = nullptr; OGRSpatialReferenceH hProj = OSRNewSpatialReference( pszProjection ); if( hProj != nullptr ) { OGRErr eErr = OGRERR_NONE; // Check that it looks like Earth before trying to reproject to wgs84... if(bJson && fabs( OSRGetSemiMajor(hProj, &eErr) - 6378137.0) < 10000.0 && eErr == OGRERR_NONE ) { bTransformToWGS84 = true; hLatLong = OSRNewSpatialReference( nullptr ); OSRSetWellKnownGeogCS( hLatLong, "WGS84" ); } else { hLatLong = OSRCloneGeogCS( hProj ); if( hLatLong ) { // Drop GEOGCS|UNIT child to be sure to output as degrees OGRSpatialReference* poLatLong = reinterpret_cast< OGRSpatialReference*>(hLatLong); OGR_SRSNode *poGEOGCS = poLatLong->GetRoot(); if( poGEOGCS ) { const int iUnitChild = poGEOGCS->FindChild("UNIT"); if( iUnitChild != -1 ) poGEOGCS->DestroyChild(iUnitChild); } } } } if( hLatLong != nullptr ) { CPLPushErrorHandler( CPLQuietErrorHandler ); hTransform = OCTNewCoordinateTransformation( hProj, hLatLong ); CPLPopErrorHandler(); OSRDestroySpatialReference( hLatLong ); } if( hProj != nullptr ) OSRDestroySpatialReference( hProj ); } /* -------------------------------------------------------------------- */ /* Report corners. */ /* -------------------------------------------------------------------- */ if( bJson ) { json_object *poLinearRing = json_object_new_array(); json_object *poCornerCoordinates = json_object_new_object(); json_object *poLongLatExtent = json_object_new_object(); json_object *poLongLatExtentType = json_object_new_string("Polygon"); json_object *poLongLatExtentCoordinates = json_object_new_array(); GDALInfoReportCorner( psOptions, hDataset, hTransform, "upperLeft", 0.0, 0.0, bJson, poCornerCoordinates, poLongLatExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "lowerLeft", 0.0, GDALGetRasterYSize(hDataset), bJson, poCornerCoordinates, poLongLatExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "lowerRight", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset), bJson, poCornerCoordinates, poLongLatExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "upperRight", GDALGetRasterXSize(hDataset), 0.0, bJson, poCornerCoordinates, poLongLatExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "center", GDALGetRasterXSize(hDataset) / 2.0, GDALGetRasterYSize(hDataset) / 2.0, bJson, poCornerCoordinates, poLongLatExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "upperLeft", 0.0, 0.0, bJson, poCornerCoordinates, poLongLatExtentCoordinates, osStr ); json_object_object_add( poJsonObject, "cornerCoordinates", poCornerCoordinates ); json_object_object_add( poLongLatExtent, "type", poLongLatExtentType ); json_object_array_add( poLinearRing, poLongLatExtentCoordinates ); json_object_object_add( poLongLatExtent, "coordinates", poLinearRing ); json_object_object_add( poJsonObject, bTransformToWGS84 ? "wgs84Extent": "extent", poLongLatExtent ); } else { Concat(osStr, psOptions->bStdoutOutput, "Corner Coordinates:\n" ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "Upper Left", 0.0, 0.0, bJson, nullptr, nullptr, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "Lower Left", 0.0, GDALGetRasterYSize(hDataset), bJson, nullptr, nullptr, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "Upper Right", GDALGetRasterXSize(hDataset), 0.0, bJson, nullptr, nullptr, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "Lower Right", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset), bJson, nullptr, nullptr, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, "Center", GDALGetRasterXSize(hDataset)/2.0, GDALGetRasterYSize(hDataset)/2.0, bJson, nullptr, nullptr, osStr ); } if( hTransform != nullptr ) { OCTDestroyCoordinateTransformation( hTransform ); hTransform = nullptr; } /* ==================================================================== */ /* Loop over bands. */ /* ==================================================================== */ for( int iBand = 0; iBand < GDALGetRasterCount( hDataset ); iBand++ ) { json_object *poBand = nullptr; json_object *poBandMetadata = nullptr; if( bJson ) { poBand = json_object_new_object(); poBandMetadata = json_object_new_object(); } GDALRasterBandH const hBand = GDALGetRasterBand( hDataset, iBand+1 ); if( psOptions->bSample ) { vector<float> ofSample(10000, 0); float * const pafSample = &ofSample[0]; const int nCount = GDALGetRandomRasterSample( hBand, 10000, pafSample ); if( !bJson ) Concat( osStr, psOptions->bStdoutOutput, "Got %d samples.\n", nCount ); } int nBlockXSize = 0; int nBlockYSize = 0; GDALGetBlockSize( hBand, &nBlockXSize, &nBlockYSize ); if( bJson ) { json_object *poBandNumber = json_object_new_int(iBand+1); json_object *poBlock = json_object_new_array(); json_object *poType = json_object_new_string( GDALGetDataTypeName(GDALGetRasterDataType(hBand))); json_object *poColorInterp = json_object_new_string( GDALGetColorInterpretationName( GDALGetRasterColorInterpretation(hBand))); json_object_array_add(poBlock, json_object_new_int(nBlockXSize)); json_object_array_add(poBlock, json_object_new_int(nBlockYSize)); json_object_object_add(poBand, "band", poBandNumber); json_object_object_add(poBand, "block", poBlock); json_object_object_add(poBand, "type", poType); json_object_object_add(poBand, "colorInterpretation", poColorInterp); } else { Concat( osStr, psOptions->bStdoutOutput, "Band %d Block=%dx%d Type=%s, ColorInterp=%s\n", iBand + 1, nBlockXSize, nBlockYSize, GDALGetDataTypeName( GDALGetRasterDataType(hBand)), GDALGetColorInterpretationName( GDALGetRasterColorInterpretation(hBand)) ); } if( GDALGetDescription( hBand ) != nullptr && strlen(GDALGetDescription( hBand )) > 0 ) { if(bJson) { json_object *poBandDescription = json_object_new_string(GDALGetDescription(hBand)); json_object_object_add(poBand, "description", poBandDescription); } else { Concat( osStr, psOptions->bStdoutOutput, " Description = %s\n", GDALGetDescription(hBand) ); } } { int bGotMin = FALSE; int bGotMax = FALSE; const double dfMin = GDALGetRasterMinimum( hBand, &bGotMin ); const double dfMax = GDALGetRasterMaximum( hBand, &bGotMax ); if( bGotMin || bGotMax || psOptions->bComputeMinMax ) { if( !bJson ) Concat(osStr, psOptions->bStdoutOutput, " " ); if( bGotMin ) { if( bJson ) { json_object *poMin = json_object_new_double_with_precision(dfMin, 3); json_object_object_add(poBand, "min", poMin); } else { Concat(osStr, psOptions->bStdoutOutput, "Min=%.3f ", dfMin ); } } if( bGotMax ) { if( bJson ) { json_object *poMax = json_object_new_double_with_precision(dfMax, 3); json_object_object_add(poBand, "max", poMax); } else { Concat(osStr, psOptions->bStdoutOutput, "Max=%.3f ", dfMax ); } } if( psOptions->bComputeMinMax ) { CPLErrorReset(); double adfCMinMax[2] = {0.0, 0.0}; GDALComputeRasterMinMax( hBand, FALSE, adfCMinMax ); if( CPLGetLastErrorType() == CE_None ) { if( bJson ) { json_object *poComputedMin = json_object_new_double_with_precision( adfCMinMax[0], 3); json_object *poComputedMax = json_object_new_double_with_precision( adfCMinMax[1], 3); json_object_object_add(poBand, "computedMin", poComputedMin); json_object_object_add(poBand, "computedMax", poComputedMax); } else { Concat(osStr, psOptions->bStdoutOutput, " Computed Min/Max=%.3f,%.3f", adfCMinMax[0], adfCMinMax[1] ); } } } if(!bJson) Concat(osStr, psOptions->bStdoutOutput, "\n" ); } } double dfMinStat = 0.0; double dfMaxStat = 0.0; double dfMean = 0.0; double dfStdDev = 0.0; CPLErr eErr = GDALGetRasterStatistics( hBand, psOptions->bApproxStats, psOptions->bStats, &dfMinStat, &dfMaxStat, &dfMean, &dfStdDev ); if( eErr == CE_None ) { if( bJson ) { json_object *poMinimum = json_object_new_double_with_precision(dfMinStat, 3); json_object *poMaximum = json_object_new_double_with_precision(dfMaxStat, 3); json_object *poMean = json_object_new_double_with_precision(dfMean, 3); json_object *poStdDev = json_object_new_double_with_precision(dfStdDev, 3); json_object_object_add(poBand, "minimum", poMinimum); json_object_object_add(poBand, "maximum", poMaximum); json_object_object_add(poBand, "mean", poMean); json_object_object_add(poBand, "stdDev", poStdDev); } else { Concat(osStr, psOptions->bStdoutOutput, " Minimum=%.3f, Maximum=%.3f, Mean=%.3f, StdDev=%.3f\n", dfMinStat, dfMaxStat, dfMean, dfStdDev ); } } if( psOptions->bReportHistograms ) { int nBucketCount = 0; GUIntBig *panHistogram = nullptr; if( bJson ) eErr = GDALGetDefaultHistogramEx( hBand, &dfMinStat, &dfMaxStat, &nBucketCount, &panHistogram, TRUE, GDALDummyProgress, nullptr ); else eErr = GDALGetDefaultHistogramEx( hBand, &dfMinStat, &dfMaxStat, &nBucketCount, &panHistogram, TRUE, GDALTermProgress, nullptr ); if( eErr == CE_None ) { json_object *poHistogram = nullptr; json_object *poBuckets = nullptr; if( bJson ) { json_object *poCount = json_object_new_int(nBucketCount); json_object *poMin = json_object_new_double(dfMinStat); json_object *poMax = json_object_new_double(dfMaxStat); poBuckets = json_object_new_array(); poHistogram = json_object_new_object(); json_object_object_add(poHistogram, "count", poCount); json_object_object_add(poHistogram, "min", poMin); json_object_object_add(poHistogram, "max", poMax); } else { Concat(osStr, psOptions->bStdoutOutput, " %d buckets from %g to %g:\n ", nBucketCount, dfMinStat, dfMaxStat ); } for( int iBucket = 0; iBucket < nBucketCount; iBucket++ ) { if(bJson) { json_object *poBucket = json_object_new_int64(panHistogram[iBucket]); json_object_array_add(poBuckets, poBucket); } else Concat(osStr, psOptions->bStdoutOutput, CPL_FRMT_GUIB " ", panHistogram[iBucket] ); } if( bJson ) { json_object_object_add(poHistogram, "buckets", poBuckets); json_object_object_add(poBand, "histogram", poHistogram); } else { Concat(osStr, psOptions->bStdoutOutput, "\n" ); } CPLFree( panHistogram ); } } if ( psOptions->bComputeChecksum) { const int nBandChecksum = GDALChecksumImage(hBand, 0, 0, GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset)); if( bJson ) { json_object *poChecksum = json_object_new_int(nBandChecksum); json_object_object_add(poBand, "checksum", poChecksum); } else { Concat(osStr, psOptions->bStdoutOutput, " Checksum=%d\n", nBandChecksum ); } } int bGotNodata = FALSE; const double dfNoData = GDALGetRasterNoDataValue( hBand, &bGotNodata ); if( bGotNodata ) { if( CPLIsNan(dfNoData) ) { if( bJson ) { json_object *poNoDataValue = json_object_new_string("nan"); json_object_object_add(poBand, "noDataValue", poNoDataValue); } else { Concat(osStr, psOptions->bStdoutOutput, " NoData Value=nan\n" ); } } else { if(bJson) { json_object *poNoDataValue = json_object_new_double_with_precision(dfNoData, 18); json_object_object_add(poBand, "noDataValue", poNoDataValue); } else { Concat(osStr, psOptions->bStdoutOutput, " NoData Value=%.18g\n", dfNoData ); } } } if( GDALGetOverviewCount(hBand) > 0 ) { json_object *poOverviews = nullptr; if( bJson ) poOverviews = json_object_new_array(); else Concat(osStr, psOptions->bStdoutOutput, " Overviews: " ); for( int iOverview = 0; iOverview < GDALGetOverviewCount(hBand); iOverview++ ) { if( !bJson ) if( iOverview != 0 ) Concat(osStr, psOptions->bStdoutOutput, ", " ); GDALRasterBandH hOverview = GDALGetOverview( hBand, iOverview ); if (hOverview != nullptr) { if(bJson) { json_object *poOverviewSize = json_object_new_array(); json_object *poOverviewSizeX = json_object_new_int( GDALGetRasterBandXSize( hOverview) ); json_object *poOverviewSizeY = json_object_new_int( GDALGetRasterBandYSize( hOverview) ); json_object *poOverview = json_object_new_object(); json_object_array_add( poOverviewSize, poOverviewSizeX ); json_object_array_add( poOverviewSize, poOverviewSizeY ); json_object_object_add( poOverview, "size", poOverviewSize ); if(psOptions->bComputeChecksum) { const int nOverviewChecksum = GDALChecksumImage( hOverview, 0, 0, GDALGetRasterBandXSize(hOverview), GDALGetRasterBandYSize(hOverview)); json_object *poOverviewChecksum = json_object_new_int(nOverviewChecksum); json_object_object_add(poOverview, "checksum", poOverviewChecksum); } json_object_array_add(poOverviews, poOverview); } else { Concat(osStr, psOptions->bStdoutOutput, "%dx%d", GDALGetRasterBandXSize( hOverview ), GDALGetRasterBandYSize( hOverview ) ); } const char *pszResampling = GDALGetMetadataItem( hOverview, "RESAMPLING", "" ); if( pszResampling != nullptr && !bJson && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") ) Concat(osStr, psOptions->bStdoutOutput, "*" ); } else { if(!bJson) Concat(osStr, psOptions->bStdoutOutput, "(null)" ); } } if(bJson) json_object_object_add(poBand, "overviews", poOverviews); else Concat(osStr, psOptions->bStdoutOutput, "\n" ); if ( psOptions->bComputeChecksum && !bJson ) { Concat(osStr, psOptions->bStdoutOutput, " Overviews checksum: " ); for( int iOverview = 0; iOverview < GDALGetOverviewCount(hBand); iOverview++ ) { GDALRasterBandH hOverview; if( iOverview != 0 ) Concat(osStr, psOptions->bStdoutOutput, ", " ); hOverview = GDALGetOverview( hBand, iOverview ); if (hOverview) { Concat(osStr, psOptions->bStdoutOutput, "%d", GDALChecksumImage(hOverview, 0, 0, GDALGetRasterBandXSize(hOverview), GDALGetRasterBandYSize(hOverview))); } else { Concat(osStr, psOptions->bStdoutOutput, "(null)" ); } } Concat(osStr, psOptions->bStdoutOutput, "\n" ); } } if( GDALHasArbitraryOverviews( hBand ) && !bJson ) { Concat(osStr, psOptions->bStdoutOutput, " Overviews: arbitrary\n" ); } const int nMaskFlags = GDALGetMaskFlags( hBand ); if( (nMaskFlags & (GMF_NODATA|GMF_ALL_VALID)) == 0 || nMaskFlags == (GMF_NODATA | GMF_PER_DATASET) ) { GDALRasterBandH hMaskBand = GDALGetMaskBand(hBand) ; json_object *poMask = nullptr; json_object *poFlags = nullptr; json_object *poMaskOverviews = nullptr; if(bJson) { poMask = json_object_new_object(); poFlags = json_object_new_array(); } else Concat(osStr, psOptions->bStdoutOutput, " Mask Flags: " ); if( nMaskFlags & GMF_PER_DATASET ) { if(bJson) { json_object *poFlag = json_object_new_string( "PER_DATASET" ); json_object_array_add( poFlags, poFlag ); } else Concat(osStr, psOptions->bStdoutOutput, "PER_DATASET " ); } if( nMaskFlags & GMF_ALPHA ) { if(bJson) { json_object *poFlag = json_object_new_string( "ALPHA" ); json_object_array_add( poFlags, poFlag ); } else Concat(osStr, psOptions->bStdoutOutput, "ALPHA " ); } if( nMaskFlags & GMF_NODATA ) { if(bJson) { json_object *poFlag = json_object_new_string( "NODATA" ); json_object_array_add( poFlags, poFlag ); } else { Concat(osStr, psOptions->bStdoutOutput, "NODATA " ); } } if(bJson) json_object_object_add( poMask, "flags", poFlags ); else Concat(osStr, psOptions->bStdoutOutput, "\n" ); if(bJson) poMaskOverviews = json_object_new_array(); if( hMaskBand != nullptr && GDALGetOverviewCount(hMaskBand) > 0 ) { if(!bJson) Concat(osStr, psOptions->bStdoutOutput, " Overviews of mask band: " ); for( int iOverview = 0; iOverview < GDALGetOverviewCount(hMaskBand); iOverview++ ) { GDALRasterBandH hOverview = GDALGetOverview( hMaskBand, iOverview ); if( !hOverview ) break; json_object *poMaskOverview = nullptr; json_object *poMaskOverviewSize = nullptr; if(bJson) { poMaskOverview = json_object_new_object(); poMaskOverviewSize = json_object_new_array(); } else { if( iOverview != 0 ) Concat(osStr, psOptions->bStdoutOutput, ", " ); } if(bJson) { json_object *poMaskOverviewSizeX = json_object_new_int( GDALGetRasterBandXSize(hOverview)); json_object *poMaskOverviewSizeY = json_object_new_int( GDALGetRasterBandYSize(hOverview)); json_object_array_add(poMaskOverviewSize, poMaskOverviewSizeX); json_object_array_add(poMaskOverviewSize, poMaskOverviewSizeY); json_object_object_add(poMaskOverview, "size", poMaskOverviewSize); json_object_array_add(poMaskOverviews, poMaskOverview); } else { Concat( osStr, psOptions->bStdoutOutput, "%dx%d", GDALGetRasterBandXSize( hOverview ), GDALGetRasterBandYSize( hOverview ) ); } } if( !bJson ) Concat(osStr, psOptions->bStdoutOutput, "\n" ); } if(bJson) { json_object_object_add(poMask, "overviews", poMaskOverviews); json_object_object_add(poBand, "mask", poMask); } } if( strlen(GDALGetRasterUnitType(hBand)) > 0 ) { if( bJson ) { json_object *poUnit = json_object_new_string(GDALGetRasterUnitType(hBand)); json_object_object_add(poBand, "unit", poUnit); } else { Concat(osStr, psOptions->bStdoutOutput, " Unit Type: %s\n", GDALGetRasterUnitType(hBand) ); } } if( GDALGetRasterCategoryNames(hBand) != nullptr ) { char **papszCategories = GDALGetRasterCategoryNames(hBand); json_object *poCategories = nullptr; if( bJson ) poCategories = json_object_new_array(); else Concat(osStr, psOptions->bStdoutOutput, " Categories:\n" ); for( int i = 0; papszCategories[i] != nullptr; i++ ) { if(bJson) { json_object *poCategoryName = json_object_new_string(papszCategories[i]); json_object_array_add(poCategories, poCategoryName); } else Concat(osStr, psOptions->bStdoutOutput, " %3d: %s\n", i, papszCategories[i] ); } if(bJson) json_object_object_add(poBand, "categories", poCategories); } int bSuccess = FALSE; if( GDALGetRasterScale( hBand, &bSuccess ) != 1.0 || GDALGetRasterOffset( hBand, &bSuccess ) != 0.0 ) { if( bJson ) { json_object *poOffset = json_object_new_double_with_precision( GDALGetRasterOffset(hBand, &bSuccess), 15); json_object *poScale = json_object_new_double_with_precision( GDALGetRasterScale(hBand, &bSuccess), 15); json_object_object_add(poBand, "offset", poOffset); json_object_object_add(poBand, "scale", poScale); } else { Concat(osStr, psOptions->bStdoutOutput, " Offset: %.15g, Scale:%.15g\n", GDALGetRasterOffset( hBand, &bSuccess ), GDALGetRasterScale( hBand, &bSuccess ) ); } } GDALInfoReportMetadata( psOptions, hBand, true, bJson, poBandMetadata, osStr ); if( bJson ) { if (psOptions->bShowMetadata) json_object_object_add( poBand, "metadata", poBandMetadata ); else json_object_put(poBandMetadata); } GDALColorTableH hTable; if( GDALGetRasterColorInterpretation(hBand) == GCI_PaletteIndex && (hTable = GDALGetRasterColorTable( hBand )) != nullptr ) { if( !bJson ) Concat( osStr, psOptions->bStdoutOutput, " Color Table (%s with %d entries)\n", GDALGetPaletteInterpretationName( GDALGetPaletteInterpretation( hTable )), GDALGetColorEntryCount( hTable ) ); if (psOptions->bShowColorTable) { json_object *poEntries = nullptr; if( bJson ) { json_object *poPalette = json_object_new_string(GDALGetPaletteInterpretationName( GDALGetPaletteInterpretation(hTable))); json_object *poCount = json_object_new_int(GDALGetColorEntryCount(hTable)); json_object *poColorTable = json_object_new_object(); json_object_object_add(poColorTable, "palette", poPalette); json_object_object_add(poColorTable, "count", poCount); poEntries = json_object_new_array(); json_object_object_add(poColorTable, "entries", poEntries); json_object_object_add(poBand, "colorTable", poColorTable); } for( int i = 0; i < GDALGetColorEntryCount( hTable ); i++ ) { GDALColorEntry sEntry; GDALGetColorEntryAsRGB( hTable, i, &sEntry ); if(bJson) { json_object *poEntry = json_object_new_array(); json_object *poC1 = json_object_new_int(sEntry.c1); json_object *poC2 = json_object_new_int(sEntry.c2); json_object *poC3 = json_object_new_int(sEntry.c3); json_object *poC4 = json_object_new_int(sEntry.c4); json_object_array_add(poEntry, poC1); json_object_array_add(poEntry, poC2); json_object_array_add(poEntry, poC3); json_object_array_add(poEntry, poC4); json_object_array_add(poEntries, poEntry); } else { Concat(osStr, psOptions->bStdoutOutput, " %3d: %d,%d,%d,%d\n", i, sEntry.c1, sEntry.c2, sEntry.c3, sEntry.c4 ); } } } } if( psOptions->bShowRAT && GDALGetDefaultRAT( hBand ) != nullptr ) { GDALRasterAttributeTableH hRAT = GDALGetDefaultRAT( hBand ); if( bJson ) { json_object *poRAT = static_cast<json_object*>(GDALRATSerializeJSON( hRAT )); json_object_object_add( poJsonObject, "rat", poRAT ); } else { CPLXMLNode *psTree = static_cast<GDALRasterAttributeTable *>(hRAT)->Serialize(); char *pszXMLText = CPLSerializeXMLTree( psTree ); CPLDestroyXMLNode( psTree ); Concat(osStr, psOptions->bStdoutOutput, "%s\n", pszXMLText ); CPLFree( pszXMLText ); } } if(bJson) json_object_array_add(poBands, poBand); } if(bJson) { json_object_object_add(poJsonObject, "bands", poBands); Concat(osStr, psOptions->bStdoutOutput, "%s", json_object_to_json_string_ext(poJsonObject, JSON_C_TO_STRING_PRETTY)); json_object_put(poJsonObject); } if( psOptionsToFree != nullptr ) GDALInfoOptionsFree(psOptionsToFree); return VSI_STRDUP_VERBOSE(osStr); } /************************************************************************/ /* GDALInfoReportCorner() */ /************************************************************************/ static int GDALInfoReportCorner( const GDALInfoOptions* psOptions, GDALDatasetH hDataset, OGRCoordinateTransformationH hTransform, const char * corner_name, double x, double y, bool bJson, json_object *poCornerCoordinates, json_object *poLongLatExtentCoordinates, CPLString& osStr ) { if(!bJson) Concat(osStr, psOptions->bStdoutOutput, "%-11s ", corner_name ); /* -------------------------------------------------------------------- */ /* Transform the point into georeferenced coordinates. */ /* -------------------------------------------------------------------- */ double adfGeoTransform[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; double dfGeoX = 0.0; double dfGeoY = 0.0; if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None ) { dfGeoX = adfGeoTransform[0] + adfGeoTransform[1] * x + adfGeoTransform[2] * y; dfGeoY = adfGeoTransform[3] + adfGeoTransform[4] * x + adfGeoTransform[5] * y; } else { if( bJson ) { json_object * const poCorner = json_object_new_array(); json_object * const poX = json_object_new_double_with_precision( x, 1 ); json_object * const poY = json_object_new_double_with_precision( y, 1 ); json_object_array_add( poCorner, poX ); json_object_array_add( poCorner, poY ); json_object_object_add( poCornerCoordinates, corner_name, poCorner ); } else { Concat(osStr, psOptions->bStdoutOutput, "(%7.1f,%7.1f)\n", x, y ); } return FALSE; } /* -------------------------------------------------------------------- */ /* Report the georeferenced coordinates. */ /* -------------------------------------------------------------------- */ if( std::abs(dfGeoX) < 181 && std::abs(dfGeoY) < 91 ) { if(bJson) { json_object * const poCorner = json_object_new_array(); json_object * const poX = json_object_new_double_with_precision( dfGeoX, 7 ); json_object * const poY = json_object_new_double_with_precision( dfGeoY, 7 ); json_object_array_add( poCorner, poX ); json_object_array_add( poCorner, poY ); json_object_object_add( poCornerCoordinates, corner_name, poCorner ); } else { Concat(osStr, psOptions->bStdoutOutput, "(%12.7f,%12.7f) ", dfGeoX, dfGeoY ); } } else { if(bJson) { json_object * const poCorner = json_object_new_array(); json_object * const poX = json_object_new_double_with_precision( dfGeoX, 3 ); json_object * const poY = json_object_new_double_with_precision( dfGeoY, 3 ); json_object_array_add( poCorner, poX ); json_object_array_add( poCorner, poY ); json_object_object_add( poCornerCoordinates, corner_name, poCorner ); } else { Concat(osStr, psOptions->bStdoutOutput, "(%12.3f,%12.3f) ", dfGeoX, dfGeoY ); } } /* -------------------------------------------------------------------- */ /* Transform to latlong and report. */ /* -------------------------------------------------------------------- */ if(bJson) { double dfZ = 0.0; if( hTransform != nullptr && !EQUAL( corner_name, "center" ) && OCTTransform(hTransform,1,&dfGeoX,&dfGeoY,&dfZ) ) { json_object * const poCorner = json_object_new_array(); json_object * const poX = json_object_new_double_with_precision( dfGeoX, 7 ); json_object * const poY = json_object_new_double_with_precision( dfGeoY, 7 ); json_object_array_add( poCorner, poX ); json_object_array_add( poCorner, poY ); json_object_array_add( poLongLatExtentCoordinates , poCorner ); } } else { double dfZ = 0.0; if( hTransform != nullptr && OCTTransform(hTransform,1,&dfGeoX,&dfGeoY,&dfZ) ) { Concat(osStr, psOptions->bStdoutOutput, "(%s,", GDALDecToDMS( dfGeoX, "Long", 2 ) ); Concat(osStr, psOptions->bStdoutOutput, "%s)", GDALDecToDMS( dfGeoY, "Lat", 2 ) ); } Concat(osStr, psOptions->bStdoutOutput, "\n" ); } return TRUE; } /************************************************************************/ /* GDALInfoPrintMetadata() */ /************************************************************************/ static void GDALInfoPrintMetadata( const GDALInfoOptions* psOptions, GDALMajorObjectH hObject, const char *pszDomain, const char *pszDisplayedname, const char *pszIndent, int bJsonOutput, json_object *poMetadata, CPLString& osStr ) { const bool bIsxml = pszDomain != nullptr && STARTS_WITH_CI(pszDomain, "xml:"); const bool bMDIsJson = pszDomain != nullptr && STARTS_WITH_CI(pszDomain, "json:"); char **papszMetadata = GDALGetMetadata( hObject, pszDomain ); if( papszMetadata != nullptr && *papszMetadata != nullptr ) { json_object *poDomain = (bJsonOutput && !bIsxml && !bMDIsJson) ? json_object_new_object() : nullptr; if( !bJsonOutput ) Concat( osStr, psOptions->bStdoutOutput, "%s%s:\n", pszIndent, pszDisplayedname ); json_object *poValue = nullptr; for( int i = 0; papszMetadata[i] != nullptr; i++ ) { if( bJsonOutput ) { if( bIsxml ) { poValue = json_object_new_string( papszMetadata[i] ); break; } else if( bMDIsJson ) { OGRJSonParse(papszMetadata[i], &poValue, true); break; } else { char *pszKey = nullptr; const char *pszValue = CPLParseNameValue( papszMetadata[i], &pszKey ); if( pszKey ) { poValue = json_object_new_string( pszValue ); json_object_object_add( poDomain, pszKey, poValue ); CPLFree( pszKey ); } } } else { if (bIsxml || bMDIsJson) Concat(osStr, psOptions->bStdoutOutput, "%s%s\n", pszIndent, papszMetadata[i] ); else Concat(osStr, psOptions->bStdoutOutput, "%s %s\n", pszIndent, papszMetadata[i] ); } } if(bJsonOutput) { if(bIsxml || bMDIsJson) { json_object_object_add( poMetadata, pszDomain, poValue ); } else { if(pszDomain == nullptr) json_object_object_add( poMetadata, "", poDomain ); else json_object_object_add( poMetadata, pszDomain, poDomain ); } } } } /************************************************************************/ /* GDALInfoReportMetadata() */ /************************************************************************/ static void GDALInfoReportMetadata( const GDALInfoOptions* psOptions, GDALMajorObjectH hObject, bool bIsBand, bool bJson, json_object *poMetadata, CPLString& osStr ) { const char* const pszIndent = bIsBand ? " " : ""; /* -------------------------------------------------------------------- */ /* Report list of Metadata domains */ /* -------------------------------------------------------------------- */ if( psOptions->bListMDD ) { char** papszMDDList = GDALGetMetadataDomainList( hObject ); char** papszIter = papszMDDList; json_object *poMDD = nullptr; json_object * const poListMDD = bJson ? json_object_new_array() : nullptr; if( papszMDDList != nullptr ) { if( !bJson ) Concat(osStr, psOptions->bStdoutOutput, "%sMetadata domains:\n", pszIndent ); } while( papszIter != nullptr && *papszIter != nullptr ) { if( EQUAL(*papszIter, "") ) { if( bJson ) poMDD = json_object_new_string( *papszIter ); else Concat(osStr, psOptions->bStdoutOutput, "%s (default)\n", pszIndent); } else { if( bJson ) poMDD = json_object_new_string( *papszIter ); else Concat(osStr, psOptions->bStdoutOutput, "%s %s\n", pszIndent, *papszIter ); } if( bJson ) json_object_array_add( poListMDD, poMDD ); papszIter ++; } if( bJson ) json_object_object_add( poMetadata, "metadataDomains", poListMDD ); CSLDestroy(papszMDDList); } if (!psOptions->bShowMetadata) return; /* -------------------------------------------------------------------- */ /* Report default Metadata domain. */ /* -------------------------------------------------------------------- */ GDALInfoPrintMetadata( psOptions, hObject, nullptr, "Metadata", pszIndent, bJson, poMetadata, osStr ); /* -------------------------------------------------------------------- */ /* Report extra Metadata domains */ /* -------------------------------------------------------------------- */ if( psOptions->papszExtraMDDomains != nullptr ) { char **papszExtraMDDomainsExpanded = nullptr; if( EQUAL(psOptions->papszExtraMDDomains[0], "all") && psOptions->papszExtraMDDomains[1] == nullptr ) { char ** papszMDDList = GDALGetMetadataDomainList( hObject ); char * const * papszIter = papszMDDList; while( papszIter != nullptr && *papszIter != nullptr ) { if( !EQUAL(*papszIter, "") && !EQUAL(*papszIter, "IMAGE_STRUCTURE") && !EQUAL(*papszIter, "SUBDATASETS") && !EQUAL(*papszIter, "GEOLOCATION") && !EQUAL(*papszIter, "RPC") ) { papszExtraMDDomainsExpanded = CSLAddString(papszExtraMDDomainsExpanded, *papszIter); } papszIter ++; } CSLDestroy(papszMDDList); } else { papszExtraMDDomainsExpanded = CSLDuplicate(psOptions->papszExtraMDDomains); } for( int iMDD = 0; papszExtraMDDomainsExpanded != nullptr && papszExtraMDDomainsExpanded[iMDD] != nullptr; iMDD++ ) { if(bJson) { GDALInfoPrintMetadata( psOptions, hObject, papszExtraMDDomainsExpanded[iMDD], papszExtraMDDomainsExpanded[iMDD], pszIndent, bJson, poMetadata, osStr ); } else { CPLString osDisplayedname = "Metadata (" + CPLString(papszExtraMDDomainsExpanded[iMDD]) + ")"; GDALInfoPrintMetadata( psOptions, hObject, papszExtraMDDomainsExpanded[iMDD], osDisplayedname.c_str(), pszIndent, bJson, poMetadata, osStr ); } } CSLDestroy(papszExtraMDDomainsExpanded); } /* -------------------------------------------------------------------- */ /* Report various named metadata domains. */ /* -------------------------------------------------------------------- */ GDALInfoPrintMetadata( psOptions, hObject, "IMAGE_STRUCTURE", "Image Structure Metadata", pszIndent, bJson, poMetadata, osStr ); if (!bIsBand) { GDALInfoPrintMetadata( psOptions, hObject, "SUBDATASETS", "Subdatasets", pszIndent, bJson, poMetadata, osStr ); GDALInfoPrintMetadata( psOptions, hObject, "GEOLOCATION", "Geolocation", pszIndent, bJson, poMetadata, osStr ); GDALInfoPrintMetadata( psOptions, hObject, "RPC", "RPC Metadata", pszIndent, bJson, poMetadata, osStr ); } } /************************************************************************/ /* GDALInfoOptionsNew() */ /************************************************************************/ /** * Allocates a GDALInfoOptions struct. * * @param papszArgv NULL terminated list of options (potentially including filename and open options too), or NULL. * The accepted options are the ones of the <a href="gdalinfo.html">gdalinfo</a> utility. * @param psOptionsForBinary (output) may be NULL (and should generally be NULL), * otherwise (gdalinfo_bin.cpp use case) must be allocated with * GDALInfoOptionsForBinaryNew() prior to this function. Will be * filled with potentially present filename, open options, subdataset number... * @return pointer to the allocated GDALInfoOptions struct. Must be freed with GDALInfoOptionsFree(). * * @since GDAL 2.1 */ GDALInfoOptions *GDALInfoOptionsNew( char** papszArgv, GDALInfoOptionsForBinary* psOptionsForBinary ) { bool bGotFilename = false; GDALInfoOptions *psOptions = static_cast<GDALInfoOptions *>( CPLCalloc( 1, sizeof(GDALInfoOptions) ) ); psOptions->eFormat = GDALINFO_FORMAT_TEXT; psOptions->bComputeMinMax = FALSE; psOptions->bReportHistograms = FALSE; psOptions->bReportProj4 = FALSE; psOptions->bStats = FALSE; psOptions->bApproxStats = TRUE; psOptions->bSample = FALSE; psOptions->bComputeChecksum = FALSE; psOptions->bShowGCPs = TRUE; psOptions->bShowMetadata = TRUE; psOptions->bShowRAT = TRUE; psOptions->bShowColorTable = TRUE; psOptions->bListMDD = FALSE; psOptions->bShowFileList = TRUE; /* -------------------------------------------------------------------- */ /* Parse arguments. */ /* -------------------------------------------------------------------- */ for( int i = 0; papszArgv != nullptr && papszArgv[i] != nullptr; i++ ) { if( EQUAL(papszArgv[i],"-json") ) psOptions->eFormat = GDALINFO_FORMAT_JSON; else if( EQUAL(papszArgv[i], "-mm") ) psOptions->bComputeMinMax = TRUE; else if( EQUAL(papszArgv[i], "-hist") ) psOptions->bReportHistograms = TRUE; else if( EQUAL(papszArgv[i], "-proj4") ) psOptions->bReportProj4 = TRUE; else if( EQUAL(papszArgv[i], "-stats") ) { psOptions->bStats = TRUE; psOptions->bApproxStats = FALSE; } else if( EQUAL(papszArgv[i], "-approx_stats") ) { psOptions->bStats = TRUE; psOptions->bApproxStats = TRUE; } else if( EQUAL(papszArgv[i], "-sample") ) psOptions->bSample = TRUE; else if( EQUAL(papszArgv[i], "-checksum") ) psOptions->bComputeChecksum = TRUE; else if( EQUAL(papszArgv[i], "-nogcp") ) psOptions->bShowGCPs = FALSE; else if( EQUAL(papszArgv[i], "-nomd") ) psOptions->bShowMetadata = FALSE; else if( EQUAL(papszArgv[i], "-norat") ) psOptions->bShowRAT = FALSE; else if( EQUAL(papszArgv[i], "-noct") ) psOptions->bShowColorTable = FALSE; else if( EQUAL(papszArgv[i], "-listmdd") ) psOptions->bListMDD = TRUE; /* Not documented: used by gdalinfo_bin.cpp only */ else if( EQUAL(papszArgv[i], "-stdout") ) psOptions->bStdoutOutput = true; else if( EQUAL(papszArgv[i], "-mdd") && papszArgv[i+1] != nullptr ) { psOptions->papszExtraMDDomains = CSLAddString( psOptions->papszExtraMDDomains, papszArgv[++i] ); } else if( EQUAL(papszArgv[i], "-oo") && papszArgv[i+1] != nullptr ) { i++; if( psOptionsForBinary ) { psOptionsForBinary->papszOpenOptions = CSLAddString( psOptionsForBinary->papszOpenOptions, papszArgv[i] ); } } else if( EQUAL(papszArgv[i], "-nofl") ) psOptions->bShowFileList = FALSE; else if( EQUAL(papszArgv[i], "-sd") && papszArgv[i+1] != nullptr ) { i++; if( psOptionsForBinary ) { psOptionsForBinary->nSubdataset = atoi(papszArgv[i]); } } else if( papszArgv[i][0] == '-' ) { CPLError(CE_Failure, CPLE_NotSupported, "Unknown option name '%s'", papszArgv[i]); GDALInfoOptionsFree(psOptions); return nullptr; } else if( !bGotFilename ) { bGotFilename = true; if( psOptionsForBinary ) psOptionsForBinary->pszFilename = CPLStrdup(papszArgv[i]); } else { CPLError(CE_Failure, CPLE_NotSupported, "Too many command options '%s'", papszArgv[i]); GDALInfoOptionsFree(psOptions); return nullptr; } } return psOptions; } /************************************************************************/ /* GDALInfoOptionsFree() */ /************************************************************************/ /** * Frees the GDALInfoOptions struct. * * @param psOptions the options struct for GDALInfo(). * * @since GDAL 2.1 */ void GDALInfoOptionsFree( GDALInfoOptions *psOptions ) { if( psOptions != nullptr ) { CSLDestroy( psOptions->papszExtraMDDomains ); CPLFree(psOptions); } }