GDAL工具箱详解之gdalinfo.exe
来源:互联网 发布:中山大学图书馆 知乎 编辑:程序博客网 时间:2024/05/01 01:28
GDAL工具箱详解之gdalinfo.exe
GDAL自带的工具包含了众多的功能,可以看做是利用该开源库进行的典型开发案例。本节主要介绍其中基本的一项工具——gdalinfo.exe。
- 该工具箱位于GDAL文件夹下的apps文件夹中,属于命令行可执行程序。
目录
- GDAL工具箱详解之gdalinfoexe
- 目录
- 使用方法
- 常规项目的内容
- 典例
- 源码分析
- 源码及分析
- 流程图
- 参数初始化
- 读取信息主函数
使用方法
GDAL帮助文件中栅格工具箱里关于gdalinfo.exe的描述如下:
gdalinfo [--help-general] [-json] [-mm] [-stats] [-hist] [-nogcp] [-nomd] [-norat] [-noct] [-nofl] [-checksum] [-proj4] [-listmdd] [-mdd domain|`all`]* [-sd subdataset] [-oo NAME=VALUE]* datasetname
常规项目的内容
在命令行界面转到可执行程序目录,输入如下命令:
(Path of gdalinfo.exe)gdalinfo --help-general
得到输出
Generic GDAL utility command options: --version: report version of GDAL in use. --license: report GDAL license info. --formats: report all configured format drivers. --format [format]: details of one format. --optfile filename: expand an option file into the argument list. --config key value: set system configuration option. --debug [on/off/value]: set debug level. --pause: wait for user input, time to attach debugger --locale [locale]: install locale for debugging (i.e. en_US.UTF-8) --help-general: report detailed help on general options.
典例
下面是使用该程序的一个典型例子:
(Path of gdalinfo.exe)>gdalinfo -proj4 -stats ~\exmaple.tif
得到输出为:
Driver: GTiff/GeoTIFFFiles: E:\exmaple.tifSize is 200, 400Coordinate System is:GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84",6378137,298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich",0], UNIT["degree",0.0174532925199433], AUTHORITY["EPSG","4326"]]PROJ.4 string is:'+proj=longlat +datum=WGS84 +no_defs 'Origin = (116.438654182485010,40.154364985586007)Pixel Size = (0.000018000000000,-0.000018000000000)Metadata: AREA_OR_POINT=AreaImage Structure Metadata: INTERLEAVE=PIXELCorner Coordinates:Upper Left ( 116.4386542, 40.1543650)Lower Left ( 116.4386542, 40.1471650)Upper Right ( 116.4422542, 40.1543650)Lower Right ( 116.4422542, 40.1471650)Center ( 116.4404542, 40.1507650)Band 1 Block=200x5 Type=UInt16, ColorInterp=Gray Minimum=0.000, Maximum=0.000, Mean=0.000, StdDev=0.000 Metadata: STATISTICS_MAXIMUM=0 STATISTICS_MEAN=0 STATISTICS_MINIMUM=0 STATISTICS_STDDEV=0Band 2 Block=200x5 Type=UInt16, ColorInterp=Undefined Minimum=0.000, Maximum=0.000, Mean=0.000, StdDev=0.000 Metadata: STATISTICS_MAXIMUM=0 STATISTICS_MEAN=0 STATISTICS_MINIMUM=0 STATISTICS_STDDEV=0Band 3 Block=200x5 Type=UInt16, ColorInterp=Undefined Minimum=0.000, Maximum=0.000, Mean=0.000, StdDev=0.000 Metadata: STATISTICS_MAXIMUM=0 STATISTICS_MEAN=0 STATISTICS_MINIMUM=0 STATISTICS_STDDEV=0Band 4 Block=200x5 Type=UInt16, ColorInterp=Undefined Minimum=0.000, Maximum=0.000, Mean=0.000, StdDev=0.000 Metadata: STATISTICS_MAXIMUM=0 STATISTICS_MEAN=0 STATISTICS_MINIMUM=0 STATISTICS_STDDEV=0
这里使用的例子数据是一份实验数据,实际上带有信息的图像的统计信息不会全为0。
源码分析
那么gdalinfo是如何工作的呢,虽然有帮助的提示,我们还有很多选项不知道如何设定,比如:–oo中的NAME=VALUE存在哪些项目和可选项呢?这些选项的默认参数又是什么呢?下面我们就从源码角度来分析该应用程序是如何工作的。
源码及分析
int main( int argc, char ** argv ){ EarlySetConfigOptions(argc, argv);//预设置 GDALAllRegister();//注册所有驱动 argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );//命令行参数处理 if( argc < 1 )//如果参数小于1,程序退出 exit( -argc ); for( int i = 0; argv != NULL && argv[i] != NULL; i++ )//参数匹配 { if( EQUAL(argv[i], "--utility_version") ) {//打印工具版本 printf("%s was compiled against GDAL %s and is running against GDAL %s\n", argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME")); CSLDestroy( argv ); return 0; } else if( EQUAL(argv[i],"--help") ) {//打印帮助,并退出 Usage(); } } argv = CSLAddString(argv, "-stdout");//设置标准输出 GDALInfoOptionsForBinary* psOptionsForBinary = GDALInfoOptionsForBinaryNew();//初始化二值化选项 GDALInfoOptions *psOptions = GDALInfoOptionsNew(argv + 1, psOptionsForBinary);//**根据字符串数组初始化要显示的信息选项** if( psOptions == NULL )//如果选项初始化失败,退出 Usage(); if( psOptionsForBinary->pszFilename == NULL )//如果没有指定资源文件,退出 Usage("No datasource specified.");/* -------------------------------------------------------------------- *//* 打开数据集. *//* -------------------------------------------------------------------- */#ifdef __AFL_HAVE_MANUAL_CONTROL//**配合下面** int iIter = 0; while (__AFL_LOOP(1000)) { iIter ++;#endif GDALDatasetH hDataset = GDALOpenEx( psOptionsForBinary->pszFilename, GDAL_OF_READONLY | GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, NULL, (const char* const* )psOptionsForBinary->papszOpenOptions, NULL );//打开数据集 if( hDataset == NULL ) {#ifdef __AFL_HAVE_MANUAL_CONTROL continue;#else fprintf( stderr, "gdalinfo failed - unable to open '%s'.\n", psOptionsForBinary->pszFilename );/* -------------------------------------------------------------------- *//* 如果参数是一个VSI文件, 就打印其内容。 *//* -------------------------------------------------------------------- */ if ( STARTS_WITH(psOptionsForBinary->pszFilename, "/vsizip/") || STARTS_WITH(psOptionsForBinary->pszFilename, "/vsitar/") ) { char** papszFileList = VSIReadDirRecursive( psOptionsForBinary->pszFilename ); if ( papszFileList ) { int nCount = CSLCount( papszFileList ); fprintf( stdout, "Unable to open source `%s' directly.\n" "The archive contains %d files:\n", psOptionsForBinary->pszFilename, nCount ); for ( int i = 0; i < nCount; i++ ) {//打印内部文件列表 fprintf( stdout, " %s/%s\n", psOptionsForBinary->pszFilename, papszFileList[i] ); } CSLDestroy( papszFileList ); } } CSLDestroy( argv );//释放参数 GDALInfoOptionsForBinaryFree(psOptionsForBinary);//释放二值化选项 GDALInfoOptionsFree( psOptions );//释放选项占用的内存 GDALDumpOpenDatasets( stderr );//释放打开的数据集 GDALDestroyDriverManager();//释放驱动管理 CPLDumpSharedList( NULL ); exit( 1 );#endif }/* -------------------------------------------------------------------- *//* 读取特定的文件子数据集. *//* -------------------------------------------------------------------- */ if ( psOptionsForBinary->nSubdataset > 0 ) { char **papszSubdatasets = GDALGetMetadata( hDataset, "SUBDATASETS" ); int nSubdatasets = CSLCount( papszSubdatasets ); if ( nSubdatasets > 0 && psOptionsForBinary->nSubdataset <= nSubdatasets ) { char szKeyName[1024]; char *pszSubdatasetName; snprintf( szKeyName, sizeof(szKeyName), "SUBDATASET_%d_NAME", psOptionsForBinary->nSubdataset ); szKeyName[sizeof(szKeyName) - 1] = '\0'; pszSubdatasetName = CPLStrdup( CSLFetchNameValue( papszSubdatasets, szKeyName ) ); GDALClose( hDataset );//关闭原数据集 hDataset = GDALOpen( pszSubdatasetName, GA_ReadOnly );//打开子数据集 CPLFree( pszSubdatasetName ); } else { fprintf( stderr, "gdalinfo warning: subdataset %d of %d requested. " "Reading the main dataset.\n", psOptionsForBinary->nSubdataset, nSubdatasets ); } } char* pszGDALInfoOutput = GDALInfo( hDataset, psOptions );//**核心函数,读取数据集信息** if( pszGDALInfoOutput )//读取成功则输出 printf( "%s", pszGDALInfoOutput ); CPLFree( pszGDALInfoOutput );//释放输出字符串 GDALClose( hDataset );//关闭数据集#ifdef __AFL_HAVE_MANUAL_CONTROL }//**配合上面,组成循环**#endif GDALInfoOptionsForBinaryFree(psOptionsForBinary);//释放二值化选项 GDALInfoOptionsFree( psOptions );//释放选项 CSLDestroy( argv );//释放输入参数 GDALDumpOpenDatasets( stderr );//释放打开数据集 GDALDestroyDriverManager();//释放驱动管理 CPLDumpSharedList( NULL ); CPLCleanupTLS(); exit( 0 );}
流程图
从以上流程图可以看出,本程序的核心函数为GDALInfo(GDALDatasetH hDataset,
const GDALInfoOptions * psOptions )
前面大量的工作用来增强程序对多种输入的适应性和构筑信息选项。
参数初始化
参数初始化函数GDALInfoOptionsForBinaryNew()以及GDALInfoOptionsNew()是如何设置默认选项的呢,我们定位到函数体:
static GDALInfoOptionsForBinary *GDALInfoOptionsForBinaryNew(void){ return (GDALInfoOptionsForBinary*) CPLCalloc( 1, sizeof(GDALInfoOptionsForBinary) );}
很显然,二值化信息选项只是申请了内存并且返回指针。
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;//默认不以PROJ4字符报告 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;//默认显示文件列表/* -------------------------------------------------------------------- *//* 传参. *//* -------------------------------------------------------------------- */ for( int i = 0; papszArgv != NULL && papszArgv[i] != NULL; 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] != NULL ) {//设定要获取的属于该文件的元数据 psOptions->papszExtraMDDomains = CSLAddString( psOptions->papszExtraMDDomains, papszArgv[++i] ); } else if( EQUAL(papszArgv[i], "-oo") && papszArgv[i+1] != NULL ) {//设定属性 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] != NULL ) {//子数据集 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 NULL; } 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 NULL; } } return psOptions;}
从上面的源码我们可以得到一些处理命令行程序参数输入的小技巧,如-oo和文件名的指定,也清楚了默认文件打开参数和信息显示选项值。但必须注意的是,这里对于-oo的处理仅是将NMAE=VALUE加入OpenOptions字符串数组中,那么问题就转变成了如何根据这个字符串数组进行有效性判断!
没错,再次将视线转向GDALOpenEx(const char* pszFilename,unsigned int nOpenFlags, const char* const* papszAllowedDrivers, const char* const* papszOpenOptions,const char* const* papszSiblingFiles)函数。注意到帮助里的描述:
* @param papszOpenOptions NULL, or a NULL terminated list of strings with open * options passed to candidate drivers. An option exists for all drivers, * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset. * The level index starts at 0. The level number can be suffixed by "only" to specify that * only this overview level must be visible, and not sub-levels. * Open options are validated by default, and a warning is emitted in case the * option is not recognized. In some scenarios, it might be not desirable (e.g. * when not knowing which driver will open the file), so the special open option * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively, * since GDAL 2.1, an option name can be preceded by the @ character to indicate * that it may not cause a warning if the driver doesn't declare this option.
经过几步,最后定义到有效性检验函数体:
int GDALValidateOpenOptions( GDALDriverH hDriver, const char* const* papszOpenOptions){ VALIDATE_POINTER1( hDriver, "GDALValidateOpenOptions", FALSE ); const char *pszOptionList = ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_OPENOPTIONLIST ); CPLString osDriver; osDriver.Printf("driver %s", ((GDALDriver *) hDriver)->GetDescription()); return GDALValidateOptions( pszOptionList, papszOpenOptions, "open option", osDriver);}
可以看出该打开选项依赖于图像驱动的不同而变化,通过该驱动的GetMetadataItem()方法可以得到驱动所支持的打开选项列表。
这里还存在一个问题,GDAL_DMD_OPENOPTIONLIST
是一个定义项,其值为"DMD_OPENOPTIONLIST"
,然而在内部进行跟踪时别没有发现它是如何获得选项列表的。不过对帮助进行查看我们发现存在 char ** VRTDriver::GetMetadata ( const char * pszDomain = "" )
可以获得驱动的元数据列表,但同样是虚方法,根据具体驱动实现不同。
读取信息主函数
先上源码:
char *GDALInfo( GDALDatasetH hDataset, const GDALInfoOptions *psOptions ){ if( hDataset == NULL ) return NULL; GDALInfoOptions* psOptionsToFree = NULL; if( psOptions == NULL ) {//初始化信息选项 psOptionsToFree = GDALInfoOptionsNew(NULL, NULL); psOptions = psOptionsToFree; } CPLString osStr; json_object *poJsonObject = NULL, *poBands = NULL, *poMetadata = NULL; const bool bJson = psOptions->eFormat == GDALINFO_FORMAT_JSON;//先判断后赋值/* -------------------------------------------------------------------- *//* 报告通常信息. *//* -------------------------------------------------------------------- */ 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 == NULL || *papszFileList == NULL ) { if(bJson) { json_object *poFiles = json_object_new_array(); json_object_object_add(poJsonObject, "files", poFiles);//文件列表json } 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] != NULL; 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] != NULL; 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 ) );//栅格图像大小/* -------------------------------------------------------------------- *//* 报告投影信息. *//* -------------------------------------------------------------------- */ if( GDALGetProjectionRef( hDataset ) != NULL ) { json_object *poCoordinateSystem = NULL; if(bJson) poCoordinateSystem = json_object_new_object(); char *pszProjection = const_cast<char *>( GDALGetProjectionRef( hDataset ) ); OGRSpatialReferenceH hSRS = OSRNewSpatialReference(NULL); if( OSRImportFromWkt( hSRS, &pszProjection ) == CE_None )//尝试转化OGR参考系 { char *pszPrettyWkt = NULL; 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 = NULL; OSRExportToProj4( hSRS, &pszProj4 );//转换为PROJ4格式 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 ); }/* -------------------------------------------------------------------- *//* 报告地理转换参数. *//* -------------------------------------------------------------------- */ 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] );//顺序输出 } }/* -------------------------------------------------------------------- *//* 报告地面控制点. *//* -------------------------------------------------------------------- */ if( psOptions->bShowGCPs && GDALGetGCPCount( hDataset ) > 0 ) { json_object * const poGCPs = bJson ? json_object_new_object() : NULL; if (GDALGetGCPProjection(hDataset) != NULL)//获取地面控制点投影 { json_object *poGCPCoordinateSystem = NULL; char *pszProjection = const_cast<char *>( GDALGetGCPProjection( hDataset ) ); OGRSpatialReferenceH hSRS = OSRNewSpatialReference(NULL); if( OSRImportFromWkt( hSRS, &pszProjection ) == CE_None ) { char *pszPrettyWkt = NULL; 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() : NULL; 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); } }/* -------------------------------------------------------------------- *//* 报告数据集元数据. *//* -------------------------------------------------------------------- */ GDALInfoReportMetadata( psOptions, hDataset, false, bJson, poMetadata, osStr );//元数据信息获取函数(数据集) if(bJson) { if( psOptions->bShowMetadata ) json_object_object_add( poJsonObject, "metadata", poMetadata ); else json_object_put(poMetadata); }/* -------------------------------------------------------------------- *//* 如果合适,设置经纬度投影转换. *//* -------------------------------------------------------------------- */ const char *pszProjection = NULL; if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None ) pszProjection = GDALGetProjectionRef(hDataset); OGRCoordinateTransformationH hTransform = NULL; OGRCoordinateTransformationH hTransformWGS84 = NULL; if( pszProjection != NULL && strlen(pszProjection) > 0 ) { OGRSpatialReferenceH hProj, hLatLong = NULL, hLatLongWGS84 = NULL; hProj = OSRNewSpatialReference( pszProjection ); if( hProj != NULL ) { hLatLong = OSRCloneGeogCS( hProj ); if(bJson) { hLatLongWGS84 = OSRNewSpatialReference( NULL ); OSRSetWellKnownGeogCS( hLatLongWGS84, "WGS84" ); } } if( hLatLong != NULL ) { CPLPushErrorHandler( CPLQuietErrorHandler ); hTransform = OCTNewCoordinateTransformation( hProj, hLatLong );//坐标转换信息 CPLPopErrorHandler(); OSRDestroySpatialReference( hLatLong ); } if( hLatLongWGS84 != NULL ) { CPLPushErrorHandler( CPLQuietErrorHandler ); hTransformWGS84 = OCTNewCoordinateTransformation( hProj, hLatLongWGS84 ); CPLPopErrorHandler(); OSRDestroySpatialReference( hLatLongWGS84 ); } if( hProj != NULL ) OSRDestroySpatialReference( hProj ); }/* -------------------------------------------------------------------- *//* 报告边角信息. *//* -------------------------------------------------------------------- */ if(bJson) { json_object *poLinearRing = json_object_new_array(); json_object *poCornerCoordinates = json_object_new_object(); json_object *poWGS84Extent = json_object_new_object(); json_object *poWGS84ExtentType = json_object_new_string("Polygon"); json_object *poWGS84ExtentCoordinates = json_object_new_array(); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "upperLeft", 0.0, 0.0, bJson, poCornerCoordinates, poWGS84ExtentCoordinates, osStr );//边角报告函数 GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "lowerLeft", 0.0, GDALGetRasterYSize(hDataset), bJson, poCornerCoordinates, poWGS84ExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "upperRight", GDALGetRasterXSize(hDataset), 0.0, bJson, poCornerCoordinates, poWGS84ExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "lowerRight", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset), bJson, poCornerCoordinates, poWGS84ExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "center", GDALGetRasterXSize(hDataset)/2.0, GDALGetRasterYSize(hDataset)/2.0, bJson, poCornerCoordinates, poWGS84ExtentCoordinates, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "upperLeft", 0.0, 0.0, bJson, poCornerCoordinates, poWGS84ExtentCoordinates, osStr ); json_object_object_add( poJsonObject, "cornerCoordinates", poCornerCoordinates ); json_object_object_add( poWGS84Extent, "type", poWGS84ExtentType ); json_object_array_add( poLinearRing, poWGS84ExtentCoordinates ); json_object_object_add( poWGS84Extent, "coordinates", poLinearRing ); json_object_object_add( poJsonObject, "wgs84Extent", poWGS84Extent ); } else { Concat(osStr, psOptions->bStdoutOutput, "Corner Coordinates:\n" ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "Upper Left", 0.0, 0.0, bJson, NULL, NULL, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "Lower Left", 0.0, GDALGetRasterYSize(hDataset), bJson, NULL, NULL, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "Upper Right", GDALGetRasterXSize(hDataset), 0.0, bJson, NULL, NULL, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "Lower Right", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset), bJson, NULL, NULL, osStr ); GDALInfoReportCorner( psOptions, hDataset, hTransform, hTransformWGS84, "Center", GDALGetRasterXSize(hDataset)/2.0, GDALGetRasterYSize(hDataset)/2.0, bJson, NULL, NULL, osStr ); } if( hTransform != NULL ) { OCTDestroyCoordinateTransformation( hTransform ); hTransform = NULL; } if( hTransformWGS84 != NULL ) { OCTDestroyCoordinateTransformation( hTransformWGS84 ); hTransformWGS84 = NULL; }/* ==================================================================== *//* 循环处理波段. *//* ==================================================================== */ for( int iBand = 0; iBand < GDALGetRasterCount( hDataset ); iBand++ ) { json_object *poBand = NULL; json_object *poBandMetadata = NULL; 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 ) != NULL && 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; GUIntBig *panHistogram = NULL; if(bJson) eErr = GDALGetDefaultHistogramEx( hBand, &dfMinStat, &dfMaxStat, &nBucketCount, &panHistogram, TRUE, GDALDummyProgress, NULL );//获得默认直方图 else eErr = GDALGetDefaultHistogramEx( hBand, &dfMinStat, &dfMaxStat, &nBucketCount, &panHistogram, TRUE, GDALTermProgress, NULL ); if( eErr == CE_None ) { json_object *poHistogram = NULL, *poBuckets = NULL; 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) { 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 = NULL; 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 != NULL) { 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) { 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 != NULL && !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 ) { GDALRasterBandH hMaskBand = GDALGetMaskBand(hBand) ;//获取掩膜 json_object *poMask = NULL, *poFlags = NULL, *poMaskOverviews = NULL; 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( nMaskFlags & GMF_ALL_VALID ) { if(bJson) { json_object *poFlag = json_object_new_string( "ALL_VALID" ); json_object_array_add( poFlags, poFlag ); } else Concat(osStr, psOptions->bStdoutOutput, "ALL_VALID " ); } if(bJson) json_object_object_add( poMask, "flags", poFlags ); else Concat(osStr, psOptions->bStdoutOutput, "\n" ); if(bJson) poMaskOverviews = json_object_new_array(); if( hMaskBand != NULL && GDALGetOverviewCount(hMaskBand) > 0 ) {//获取掩膜预览 if(!bJson) Concat(osStr, psOptions->bStdoutOutput, " Overviews of mask band: " ); for( int iOverview = 0; iOverview < GDALGetOverviewCount(hMaskBand); iOverview++ ) { GDALRasterBandH hOverview; json_object *poMaskOverview = NULL; json_object *poMaskOverviewSize = NULL; if(bJson) { poMaskOverview = json_object_new_object(); poMaskOverviewSize = json_object_new_array(); } else { if( iOverview != 0 ) Concat(osStr, psOptions->bStdoutOutput, ", " ); } hOverview = GDALGetOverview( hMaskBand, iOverview ); 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) != NULL ) {//获取栅格种类名 char **papszCategories = GDALGetRasterCategoryNames(hBand); json_object *poCategories = NULL; if(bJson) poCategories = json_object_new_array(); else Concat(osStr, psOptions->bStdoutOutput, " Categories:\n" ); for( int i = 0; papszCategories[i] != NULL; 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 )) != NULL )//获得颜色索引及色彩表 { if(!bJson) Concat( osStr, psOptions->bStdoutOutput, " Color Table (%s with %d entries)\n", GDALGetPaletteInterpretationName( GDALGetPaletteInterpretation( hTable )), GDALGetColorEntryCount( hTable ) ); if (psOptions->bShowColorTable) { json_object *poEntries = NULL; 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 ) != NULL ) { GDALRasterAttributeTableH hRAT = GDALGetDefaultRAT( hBand );//获取栅格属性表 if(bJson) { json_object *poRAT = (json_object*) GDALRATSerializeJSON( hRAT ); json_object_object_add( poJsonObject, "rat", poRAT ); } else {//获取属性表并转化为xml树状信息 CPLXMLNode *psTree = ((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 != NULL ) GDALInfoOptionsFree(psOptionsToFree); return VSI_STRDUP_VERBOSE(osStr);}
根据函数名称,我们基本能够推断出函数的作用,从获取关联文件到栅格属性表等等。研究本源码文件更多地是向我们展示了GDAL库设计者们对于库函数的使用范本。
- GDAL工具箱详解之gdalinfo.exe
- GDAL工具箱详解之gdalwarp.exe
- GDAL实用工具之gdalinfo
- gdal之OGR入门
- Python之GDAL配置
- GDAL之OGR入门
- 我的小工具箱Oakutils.exe
- 【GIS】GDAL之OGR入门
- GDAL之栅格重投影
- gdalinfo 工具读取图像信息
- 【Matlab】优化工具箱使用详解
- GDAL源码剖析(六)之GDAL开发及其调试
- GDAL源码剖析(七)之GDAL RasterIO使用说明
- GDAL源码剖析(六)之GDAL开发及其调试
- GDAL源码剖析(七)之GDAL RasterIO使用说明
- GDAL源码剖析(九)之GDAL体系架构
- GDAL源码剖析(十二)之GDAL Warp API使用说明
- GDAL源码剖析(七)之GDAL RasterIO使用说明
- javascript-spilce()和slice()
- my学习OC--变量 数据类型
- Ubuntu Apache搭建modSecurity,创建自己的WAF
- 单元介绍二
- 脏读,不可重复读,幻读
- GDAL工具箱详解之gdalinfo.exe
- Python形参打包与解包小技巧
- 单例模式简要学习
- java实现单个或多个文件的压缩、解压缩 支持zip、rar等格式
- LightOJ 1104 Birthday Paradox (离散概率)
- 204.[LeetCode]count primes
- Maven指令跳过单元测试
- 某教育平台项目开发之--使用SSM框架开发过程遇到的问题总结
- 二叉查找树与平衡树简介