GDALOpen 代码分析
先来一句话,看了这么多GDAL的源代码,并不喜欢其C风格的烙印太重,还是更喜欢boost风格的简洁的现代C++风格。不过为了更好地应用GDAL,更深的定制它,还是需要将源代码看到底。因为GDAL毕竟是一个很好的图像处理的解决方案。复用它,可以省掉很多人年的工作。
GDALOpen函数代码:注释值得一看
/************************************************************************/
/* GDALOpen() */
/************************************************************************/ /**
* \brief Open a raster file as a GDALDataset.
*
* This function will try to open the passed file, or virtual dataset
* name by invoking the Open method of each registered GDALDriver in turn.
* The first successful open will result in a returned dataset. If all
* drivers fail then NULL is returned and an error is issued.
*
* Several recommandations :
* <ul>
* <li>If you open a dataset object with GA_Update access, it is not recommanded
* to open a new dataset on the same underlying file.</li>
* <li>The returned dataset should only be accessed by one thread at a time. If you
* want to use it from different threads, you must add all necessary code (mutexes, etc.)
* to avoid concurrent use of the object. (Some drivers, such as GeoTIFF, maintain internal
* state variables that are updated each time a new block is read, thus preventing concurrent
* use.) </li>
* </ul>
*
* \sa GDALOpenShared()
*
* @param pszFilename the name of the file to access. In the case of
* exotic drivers this may not refer to a physical file, but instead contain
* information for the driver on how to access a dataset. It should be in UTF8
* encoding.
*
* @param eAccess the desired access, either GA_Update or GA_ReadOnly. Many
* drivers support only read only access.
*
* @return A GDALDatasetH handle or NULL on failure. For C++ applications
* this handle can be cast to a GDALDataset *.
*/ GDALDatasetH CPL_STDCALL
GDALOpen( const char * pszFilename, GDALAccess eAccess ) {
return GDALOpenInternal(pszFilename, eAccess, NULL);
}
注释提示了几个地方:
1. 会依次调用每个已经注册的driver的open函数,第一个成功的会返回Dataset。这个依次应该是按照注册顺序,先注册的driver先被调用。
2. Dataset对象不是线程安全的,使用者自己注意维护多线程环境下的安全性。
3. 返回NULL代表打开失败
GDALDatasetH实际上是个void* , 又是C的玩法。逃过了编译器类型检查。
/** Opaque type used for the C bindings of the C++ GDALDataset class */
typedef void *GDALDatasetH;
实际上就是CDALDataset* 指针。
真正实现代码在下面的函数里面:
/* The drivers listed in papszAllowedDrivers can be in any order */
/* Only the order of registration will be taken into account */
GDALDatasetH GDALOpenInternal( const char * pszFilename, GDALAccess eAccess,
const char* const * papszAllowedDrivers)
{
VALIDATE_POINTER1( pszFilename, "GDALOpen", NULL ); int iDriver;
GDALDriverManager *poDM = GetGDALDriverManager();
GDALOpenInfo oOpenInfo( pszFilename, eAccess );
CPLLocaleC oLocaleForcer; CPLErrorReset();
CPLAssert( NULL != poDM ); for( iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++ )
{
GDALDriver *poDriver = poDM->GetDriver( iDriver );
GDALDataset *poDS; if (papszAllowedDrivers != NULL &&
CSLFindString((char**)papszAllowedDrivers, GDALGetDriverShortName(poDriver)) == -1)
continue; if ( poDriver->pfnOpen == NULL )
continue; poDS = poDriver->pfnOpen( &oOpenInfo );
if( poDS != NULL )
{
if( strlen(poDS->GetDescription()) == 0 )
poDS->SetDescription( oOpenInfo.pszFilename ); if( poDS->poDriver == NULL )
poDS->poDriver = poDriver; if( CPLGetPID() != GDALGetResponsiblePIDForCurrentThread() )
CPLDebug( "GDAL", "GDALOpen(%s, this=%p) succeeds as %s (pid=%d, responsiblePID=%d).",
pszFilename, poDS, poDriver->GetDescription(),
(int)CPLGetPID(), (int)GDALGetResponsiblePIDForCurrentThread() );
else
CPLDebug( "GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
pszFilename, poDS, poDriver->GetDescription() ); return (GDALDatasetH) poDS;
} if( CPLGetLastErrorNo() != 0 )
return NULL;
} if( oOpenInfo.bStatOK )
CPLError( CE_Failure, CPLE_OpenFailed,
"`%s' not recognised as a supported file format.\n",
pszFilename );
else
CPLError( CE_Failure, CPLE_OpenFailed,
"`%s' does not exist in the file system,\n"
"and is not recognised as a supported dataset name.\n",
pszFilename ); return NULL;
}
这段就和注释说的一样,遍历driver,依次尝试打开文件。在我的GeoTiff driver中,open方法会调用geotiff.cpp文件的Open方法:
/************************************************************************/
/* Open() */
/************************************************************************/ GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo ) {
TIFF *hTIFF;
int bAllowRGBAInterface = TRUE;
const char *pszFilename = poOpenInfo->pszFilename; /* -------------------------------------------------------------------- */
/* Check if it looks like a TIFF file. */
/* -------------------------------------------------------------------- */
if (!Identify(poOpenInfo))
return NULL; if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
{
bAllowRGBAInterface = FALSE;
pszFilename += strlen("GTIFF_RAW:");
} /* -------------------------------------------------------------------- */
/* We have a special hook for handling opening a specific */
/* directory of a TIFF file. */
/* -------------------------------------------------------------------- */
if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
return OpenDir( poOpenInfo ); if (!GTiffOneTimeInit())
return NULL; /* -------------------------------------------------------------------- */
/* Try opening the dataset. */
/* -------------------------------------------------------------------- */
if( poOpenInfo->eAccess == GA_ReadOnly )
hTIFF = VSI_TIFFOpen( pszFilename, "r" );
else
hTIFF = VSI_TIFFOpen( pszFilename, "r+" ); if( hTIFF == NULL )
return( NULL ); /* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
GTiffDataset *poDS; poDS = new GTiffDataset();
poDS->SetDescription( pszFilename );
poDS->osFilename = pszFilename;
poDS->poActiveDS = poDS; if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
TIFFCurrentDirOffset(hTIFF), TRUE,
poOpenInfo->eAccess,
bAllowRGBAInterface, TRUE,
poOpenInfo->papszSiblingFiles) != CE_None )
{
delete poDS;
return NULL;
} /* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->TryLoadXML();
poDS->ApplyPamInfo(); int i;
for(i=1;i<=poDS->nBands;i++)
{
GTiffRasterBand* poBand = (GTiffRasterBand*) poDS->GetRasterBand(i); /* Load scale, offset and unittype from PAM if available */
if (!poBand->bHaveOffsetScale)
{
poBand->dfScale = poBand->GDALPamRasterBand::GetScale(&poBand->bHaveOffsetScale);
poBand->dfOffset = poBand->GDALPamRasterBand::GetOffset();
}
if (poBand->osUnitType.size() == 0)
{
const char* pszUnitType = poBand->GDALPamRasterBand::GetUnitType();
if (pszUnitType)
poBand->osUnitType = pszUnitType;
}
} poDS->bMetadataChanged = FALSE;
poDS->bGeoTIFFInfoChanged = FALSE; /* -------------------------------------------------------------------- */
/* Check for external overviews. */
/* -------------------------------------------------------------------- */
poDS->oOvManager.Initialize( poDS, pszFilename ); return poDS;
}
这里主要看poDs->OpenOffset函数,它负责读取tiff文件的基本信息,以便后面快速读取。因为这么大的文件,显然不可能一次读进内存来。
/************************************************************************/
/* OpenOffset() */
/* */
/* Initialize the GTiffDataset based on a passed in file */
/* handle, and directory offset to utilize. This is called for */
/* full res, and overview pages. */
/************************************************************************/ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
GTiffDataset **ppoActiveDSRef,
toff_t nDirOffsetIn,
int bBaseIn, GDALAccess eAccess,
int bAllowRGBAInterface,
int bReadGeoTransform,
char** papszSiblingFiles )
该函数的定义在geotiff.cpp文件中,非常长,所以这里就不列代码了。
如果要完整的将GeoTiff整个加载过程分析透,需要更多的篇幅。我以后会不断的修改已经有的文章,使得其更准确,并增加新的文章,描述更多的细节。
欢迎讨论。
GDALOpen 代码分析的更多相关文章
- Android代码分析工具lint学习
1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...
- pmd静态代码分析
在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...
- [Asp.net 5] DependencyInjection项目代码分析-目录
微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)
Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...
- 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)
构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...
- STM32启动代码分析 IAR 比较好
stm32启动代码分析 (2012-06-12 09:43:31) 转载▼ 最近开始使用ST的stm32w108芯片(也是一款zigbee芯片).开始看他的启动代码看的晕晕呼呼呼的. 还好在c ...
- 常用 Java 静态代码分析工具的分析与比较
常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...
- SonarQube-5.6.3 代码分析平台搭建使用
python代码分析 官网主页: http://docs.sonarqube.org/display/PLUG/Python+Plugin Windows下安装使用: 快速使用: 1.下载jdk ht ...
- angular代码分析之异常日志设计
angular代码分析之异常日志设计 错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最 ...
随机推荐
- 【ASP.NET】:Ckeditor+Fckeditor的使用
首先这三个文件:下载ckeditor和ckeditor_aspnet_3.6.4和ckfinder 然后把这三个文件复制到项目根目录下 添加引用CKEditor.NET.dll CKFind ...
- 用三个线程循环输出ABC
前两天看Java吧有人求助这个问题.想了想并不是很难.今天就顺手实现了一下. 我自己想到的有两种方法,一个是使用synchronized,一个是使用lock. 一.synchronized packa ...
- zabbix安装配置(2.4.5)
这是第一次安装配置,直接遭遇配置文件不明晰的大坑,因在编译阶段未指明配置文件路径,导致zabbix_server启动时直接读取默认的 /usr/local/zabbix/etc/zabbix_serv ...
- Divisible by Seven CodeForces - 376C (数论)
You have number a, whose decimal representation quite luckily contains digits 1, 6, 8, 9. Rearrange ...
- 【BZOJ 2298】 2298: [HAOI2011]problem a (DP)
2298: [HAOI2011]problem a Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1326 Solved: 637 Descript ...
- BZOJ4554 HEOI2016游戏
网络流. 我一开始傻傻的将每条边与每一列连边,边权为联通块树,但是这样做是错的因为我们就在跑网络流中会忽略掉边和列的关系. 我们在做网络流题时一定要注意题目中给出的限制条件,一定要以限制条件建图!!! ...
- [BZOJ4032][HEOI2015]最短不公共子串(Trie+DP)
在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之——被它们虐. 操作一:对A,B分别建SAM,暴力BFS. 操作二:对B建序列自动机或SAM,A在上面暴力匹配. 操作三:对A,B建 ...
- Arab Collegiate Programming Contest 2012 J- Math Homework
思路:由于只有1-6这几个数,而这几个数的最小公倍数是60,所以只需要求出60以内有多少满足条件的数即可. 再就是求出对于给定的n,求出60的倍数.然后就是怎样求的问题了. 首先可以写成如下形式: ...
- SHELL异常处理(转载)
写SHELL好久了,经常被异常困扰,可竟然坚持了若干年没用过,回想以前服务过的公司,阿弥陀佛,罪过罪过.废话少说,希望此篇文章可以协助大家和我彻底结束SHELL脚本就是LINUX命令集合的初级阶段. ...
- Spring过滤器组件自动扫描
在这个Spring自动组件扫描的教程,您已经了解如何使Spring自动扫描您的组件.在这篇文章中,我们将展示如何使用组件过滤器自动扫描过程. 1.过滤组件 - 包含 参见下面的例子中使用Spring ...