您的位置:首页 > 其它

GDAL 2.1.0工具开发之gdal_translate(图像裁剪、缩放、拉伸、赋坐标投影、格式转换等)

2016-06-12 13:30 531 查看
为便于在自己的程序中使用GDAL的示例代码提供的那些强大功能,计划建立一个动态库,在动态库中模拟实现gdal的demo的功能。

初步想法是建立一个类CGdalTools,类的成员即是这些demo的名字。实现与demo一样的功能。

下面的例子是以gdal_translate为例。

找到gdal_translate_bin.cpp(该文件已经相当简单,加上各种注释仅300行出头),复制其中的main函数内容到一个单独的gdal_translate函数中,函数参数与main函数同,返回值与其核心函数GDALTranslate的返回值同,为GDALDatasetH,如下:

GDALDatasetH Gdal_Translate(int argc, char** argv) ;


复制过来的代码不同直接使用,需要做一些修改:

继续复制GDALTranslateOptionsForBinaryNew和GDALTranslateOptionsForBinaryFree

Gdal驱动的注册改为在CGdalTools类的构建函数中进行,而销毁则放在析构函数中。

删除EarlySetConfigOptions函数调用。

exit函数全部改为return null;

认为不必要的地方,可以直接删除。比如输出使用说明、帮助信息、版本信息等地方。

有些输出Usage函数的地方,改为return NULL;

函数最后删除GDALClose(hOutDS); return nRetCode;改为return hOutDS;

找不到GDALTranslateOptionsForBinary类,经检查,该类其实定义于gdal_utils_priv.h中,该定义主要是用来演示DEMO的使用而添加,并不是GDAL的核心功能,因此,GDAL的编译并没有将它导出。为便于开发,最简单的方法是将该文件复制到gdal开发版本的include目录下,然后在所有结构体的定义前加CPL_DLL即可。

修改后的代码已经可以运行了,其输入参数与在命令行中调用gdal_translate完全相同。代码示例如下,需要注意的是输出的GDALDatasetH须在外面关闭,也就是调用在上面的第7步中删除的GDALClose(hOutDS);

GDALDatasetH CGdalTools::Gdal_Translate(int argc, char** argv)
{
GDALDatasetH    hDataset, hOutDS;
int bUsageError;

argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
if (argc < 1)
return NULL;

if (CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", NULL) == NULL)
{
CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
}

GDALTranslateOptionsForBinary* psOptionsForBinary = GDALTranslateOptionsForBinaryNew();
GDALTranslateOptions *psOptions = GDALTranslateOptionsNew(argv + 1, psOptionsForBinary);
CSLDestroy(argv);

if (psOptions == NULL)
{
return NULL;
}

if (psOptionsForBinary->pszSource == NULL)
{
return NULL;
}

if (psOptionsForBinary->pszDest == NULL)
{
return NULL;
}

if (strcmp(psOptionsForBinary->pszDest, "/vsistdout/") == 0)
{
psOptionsForBinary->bQuiet = TRUE;
}

if (!(psOptionsForBinary->bQuiet))
{
GDALTranslateOptionsSetProgress(psOptions, GDALTermProgress, NULL);
}

if (!psOptionsForBinary->bQuiet && !psOptionsForBinary->bFormatExplicitlySet)
CheckExtensionConsistency(psOptionsForBinary->pszDest, psOptionsForBinary->pszFormat);

/* -------------------------------------------------------------------- */
/*      Attempt to open source file.                                    */
/* -------------------------------------------------------------------- */

hDataset = GDALOpenEx(psOptionsForBinary->pszSource, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, NULL,
(const char* const*)psOptionsForBinary->papszOpenOptions, NULL);

if (hDataset == NULL)
{
return NULL;
}

/* -------------------------------------------------------------------- */
/*      Handle subdatasets.                                             */
/* -------------------------------------------------------------------- */
if (!psOptionsForBinary->bCopySubDatasets
&& CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0
&& GDALGetRasterCount(hDataset) == 0)
{
fprintf(stderr,
"Input file contains subdatasets. Please, select one of them for reading.\n");
GDALClose(hDataset);
return NULL;
}

if (CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0
&& psOptionsForBinary->bCopySubDatasets)
{
char **papszSubdatasets = GDALGetMetadata(hDataset, "SUBDATASETS");
char *pszSubDest = (char *)CPLMalloc(strlen(psOptionsForBinary->pszDest) + 32);
int i;

CPLString osPath = CPLGetPath(psOptionsForBinary->pszDest);
CPLString osBasename = CPLGetBasename(psOptionsForBinary->pszDest);
CPLString osExtension = CPLGetExtension(psOptionsForBinary->pszDest);
CPLString osTemp;

const char* pszFormat = NULL;
if (CSLCount(papszSubdatasets) / 2 < 10)
{
pszFormat = "%s_%d";
}
else if (CSLCount(papszSubdatasets) / 2 < 100)
{
pszFormat = "%s_%002d";
}
else
{
pszFormat = "%s_%003d";
}

const char* pszDest = pszSubDest;

for (i = 0; papszSubdatasets[i] != NULL; i += 2)
{
char* pszSource = CPLStrdup(strstr(papszSubdatasets[i], "=") + 1);
osTemp = CPLSPrintf(pszFormat, osBasename.c_str(), i / 2 + 1);
osTemp = CPLFormFilename(osPath, osTemp, osExtension);
strcpy(pszSubDest, osTemp.c_str());
hDataset = GDALOpenEx(pszSource, GDAL_OF_RASTER, NULL,
(const char* const*)psOptionsForBinary->papszOpenOptions, NULL);
CPLFree(pszSource);
if (!psOptionsForBinary->bQuiet)
printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset));
hOutDS = GDALTranslate(pszDest, hDataset, psOptions, &bUsageError);
if (bUsageError == TRUE)
return NULL;
if (hOutDS == NULL)
break;
GDALClose(hOutDS);
}

GDALClose(hDataset);
GDALTranslateOptionsFree(psOptions);
GDALTranslateOptionsForBinaryFree(psOptionsForBinary);
CPLFree(pszSubDest);

GDALDestroyDriverManager();
return 0;

}

if (!psOptionsForBinary->bQuiet)
printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset));

hOutDS = GDALTranslate(psOptionsForBinary->pszDest, hDataset, psOptions, &bUsageError);
if (bUsageError == TRUE)
return NULL;
int nRetCode = (hOutDS) ? 0 : 1;

/* Close hOutDS before hDataset for the -f VRT case */
//GDALClose(hOutDS);
GDALClose(hDataset);
GDALTranslateOptionsFree(psOptions);
GDALTranslateOptionsForBinaryFree(psOptionsForBinary);

return hOutDS;
}


继续对该函数进行改造。上面的代码中,变化最大的当属第8步,需要变更GDAL的源文件,gdal_utils_priv.h文件。实际上,GDALTranslateOptionsForBinaryNew只是用作GDALTranslateOptionsNew的构建参数,也就是在GDALTranslateOptionsNew中将某些参数输出给GDALTranslateOptionsForBinaryNew,具体内容可以参看GDALTranslateOptionsForBinaryNew的定义,在gdal_utils_priv.h的第52行,具体内容不展开。需要注意的是在GDALTranslateOptionsNew是如何添加GDALTranslateOptionsForBinaryNew信息的。

在gdal_translate_lib.cpp中,第1674行,能看到GDALTranslateOptionsNew函数。里面与GDALTranslateOptionsForBinaryNew相关的内容如下:

if( EQUAL(papszArgv[i],"-of") && i < argc-1 )
{
++i;
CPLFree(psOptions->pszFormat);
psOptions->pszFormat = CPLStrdup(papszArgv[i]);
if( psOptionsForBinary )
{
psOptionsForBinary->bFormatExplicitlySet = TRUE;
}
}
else if( EQUAL(papszArgv[i],"-q") || EQUAL(papszArgv[i],"-quiet") )
{
if( psOptionsForBinary )
psOptionsForBinary->bQuiet = TRUE;
}
else if( EQUAL(papszArgv[i],"-sds")  )
{
if( psOptionsForBinary )
psOptionsForBinary->bCopySubDatasets = TRUE;
}
else if( EQUAL(papszArgv[i], "-oo") && i+1 < argc )
{
i++;
if( psOptionsForBinary )
{
psOptionsForBinary->papszOpenOptions =
CSLAddString( psOptionsForBinary->papszOpenOptions,
papszArgv[i] );
}
}
else if( !bGotSourceFilename )
{
bGotSourceFilename = true;
if( psOptionsForBinary )
psOptionsForBinary->pszSource = CPLStrdup(papszArgv[i]);
}
else if( !bGotDestFilename )
{
bGotDestFilename = true;
if( psOptionsForBinary )
psOptionsForBinary->pszDest = CPLStrdup(papszArgv[i]);
}
if( psOptionsForBinary )
{
psOptionsForBinary->pszFormat = CPLStrdup(psOptions->pszFormat);
}


回到上文,不进行第8步,也就是不变动gdal_utils_priv.h文件,也就是在函数外自行构建并管理GDALTranslateOptionsForBinaryNew里的信息。因此,上面的8步中,第1步也不需要。为保证输入文件与输出文件信息,变更函数声明如下:

GDALDatasetH Gdal_Translate(char ** argv, char* srcFile, char* dstFile);


为保证程序调用时传入GDALDatasetH也可以完成相关工作,这里加一个重载函数

GDALDatasetH Gdal_Translate(char ** argv, GDALDatasetH hDataset, char* dstFile);


前者详细如下:

GDALDatasetH CGdalTools::Gdal_Translate(char** argv, char* srcFile, char* dstFile)
{
if (srcFile == NULL)
{
return NULL;
}

char** papszOpenOptions=nullptr;

int argc = CSLCount(argv);
for (int i = 0; i < argc; i++)
{

if (EQUAL(argv[i], "-oo") && i + 1 < argc)
{
i++;
papszOpenOptions = CSLAddString(papszOpenOptions, argv[i]);
}
}

GDALDatasetH    hDataset;

hDataset = GDALOpenEx(srcFile, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, NULL,
(const char* const*)papszOpenOptions, NULL);

if (hDataset == NULL)
{
return NULL;
}

GDALDatasetH hOutDs = Gdal_Translate(argv, hDataset, dstFile);

GDALClose(hDataset);

return hOutDs;
}


后者详细如下:

GDALDatasetH CGdalTools::Gdal_Translate(char** argv, GDALDatasetH hDataset, char* dstFile)
{
if (hDataset == NULL)
{
return NULL;
}

if (dstFile == NULL)
{
return NULL;
}

bool bQuiet = false, bCopySubDatasets = false, bFormatExplicitlySet = false;
char* pszFormat = NULL;
char** papszOpenOptions=nullptr;

int argc = CSLCount(argv);
for (int i = 0; i < argc; i++)
{
if (EQUAL(argv[i], "-of") && i < argc - 1)
{
++i;
pszFormat = CPLStrdup(argv[i]);
bFormatExplicitlySet = TRUE;
}
else if (EQUAL(argv[i], "-q") || EQUAL(argv[i], "-quiet"))
{
bQuiet = TRUE;
}
else if (EQUAL(argv[i], "-sds"))
{
bCopySubDatasets = TRUE;
}
else if (EQUAL(argv[i], "-oo") && i + 1 < argc)
{
i++;
papszOpenOptions = CSLAddString(papszOpenOptions, argv[i]);
}
}

GDALDatasetH    hOutDS;
int bUsageError;

argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
if (argc < 1)
return NULL;

if (CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", NULL) == NULL)
{
CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
}

GDALTranslateOptions *psOptions = GDALTranslateOptionsNew(argv + 1, NULL);
CSLDestroy(argv);

if (strcmp(dstFile, "/vsistdout/") == 0)
{
bQuiet = TRUE;
}

if (!bQuiet)
{
GDALTranslateOptionsSetProgress(psOptions, GDALTermProgress, NULL);
}

if (!bQuiet && !bFormatExplicitlySet)
CheckExtensionConsistency(dstFile, pszFormat);

/* -------------------------------------------------------------------- */
/*      Handle subdatasets.                                             */
/* -------------------------------------------------------------------- */
if (!bCopySubDatasets
&& CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0
&& GDALGetRasterCount(hDataset) == 0)
{
fprintf(stderr,
"Input file contains subdatasets. Please, select one of them for reading.\n");
return NULL;
}

if (CSLCount(GDALGetMetadata(hDataset, "SUBDATASETS")) > 0
&& bCopySubDatasets)
{
char **papszSubdatasets = GDALGetMetadata(hDataset, "SUBDATASETS");
char *pszSubDest = (char *)CPLMalloc(strlen(dstFile) + 32);
int i;

CPLString osPath = CPLGetPath(dstFile);
CPLString osBasename = CPLGetBasename(dstFile);
CPLString osExtension = CPLGetExtension(dstFile);
CPLString osTemp;

const char* pszFormat = NULL;
if (CSLCount(papszSubdatasets) / 2 < 10)
{
pszFormat = "%s_%d";
}
else if (CSLCount(papszSubdatasets) / 2 < 100)
{
pszFormat = "%s_%002d";
}
else
{
pszFormat = "%s_%003d";
}

const char* pszDest = pszSubDest;

for (i = 0; papszSubdatasets[i] != NULL; i += 2)
{
char* pszSource = CPLStrdup(strstr(papszSubdatasets[i], "=") + 1);
osTemp = CPLSPrintf(pszFormat, osBasename.c_str(), i / 2 + 1);
osTemp = CPLFormFilename(osPath, osTemp, osExtension);
strcpy(pszSubDest, osTemp.c_str());
hDataset = GDALOpenEx(pszSource, GDAL_OF_RASTER, NULL,
(const char* const*)papszOpenOptions, NULL);
CPLFree(pszSource);
if (!bQuiet)
printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset));
hOutDS = GDALTranslate(pszDest, hDataset, psOptions, &bUsageError);
if (bUsageError == TRUE)
return NULL;
if (hOutDS == NULL)
break;
GDALClose(hOutDS);
}

GDALTranslateOptionsFree(psOptions);

CPLFree(pszSubDest);

return NULL;

}

if (!bQuiet)
printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset));

hOutDS = GDALTranslate(dstFile, hDataset, psOptions, &bUsageError);
if (bUsageError == TRUE)
{
GDALClose(hOutDS);
hOutDS = NULL;
}

GDALTranslateOptionsFree(psOptions);

return hOutDS;
}


现在编写一个主程序,对上述代码进行测试,

char** pszInfo = NULL;
pszInfo = CSLAddString(pszInfo, "change_format");
pszInfo = CSLAddString(pszInfo, "-of");
pszInfo = CSLAddString(pszInfo, "JPEG");
gt.Gdal_Translate( pszInfo, "G:\\sss.tif", "G:\\sss.jpg");


经测试,程序运行界面如下

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: