GDALOpen 代码分析
来源:互联网 发布:矩阵行列式计算公式 编辑:程序博客网 时间:2024/05/18 22:46
先来一句话,看了这么多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 代码分析
- GDAL GDALOpen 打开中文路径的问题
- 分析代码
- 代码分析
- 分析代码
- 代码分析
- 分析代码
- 代码分析
- 代码分析
- 代码分析
- butterknife源码分析:代码分析
- Bittorrent 精彩代码分析
- Duwamish代码分析篇
- 井字棋游戏 代码分析
- VC6启动代码分析
- Duwamish代码分析篇
- 定时器代码分析
- Duwamish -- 代码分析篇
- 如何做到 jQuery-free?
- 【PHP小错误整理】在类面调用自定义方法需要注意的问题
- Android 中自定义控件和属性(attr.xml,declare-styleable,TypedArray)的方法和使用
- hdu 4667(几何)
- 在连接点中设置传入参数时出错,怎么办?【ATL事件】
- GDALOpen 代码分析
- Shiro(4)默认鉴权与自定义鉴权
- 黑马程序员_7K月薪面试题之_交通灯管理系统
- 读串口总结
- 手机导航程序搜索不到GPS信号怎么办?
- 以自动化测试撬动遗留系统
- 手把手教你在Windows端搭建Redmine项目管理软件
- 移动应用中的流设计
- php案例01—在页面中打印服务器的时间