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

为便于在自己的程序中使用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) ;

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

  1. 继续复制GDALTranslateOptionsForBinaryNew和GDALTranslateOptionsForBinaryFree
  2. Gdal驱动的注册改为在CGdalTools类的构建函数中进行,而销毁则放在析构函数中。
  3. 删除EarlySetConfigOptions函数调用。
  4. exit函数全部改为return null;
  5. 认为不必要的地方,可以直接删除。比如输出使用说明、帮助信息、版本信息等地方。
  6. 有些输出Usage函数的地方,改为return NULL;
  7. 函数最后删除GDALClose(hOutDS); return nRetCode;改为return hOutDS;
  8. 找不到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");

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

这里写图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
即使你已经在Python解释器下成功导入了GDAL库,但是在运行`gdal_translate`命令时仍然会报错,这是因为`gdal_translate`是一个独立的命令行工具,它并不是GDAL库的一部分,而是GDAL提供的一个工具。这个工具通常是在GDAL的安装目录下的/bin目录内,也就是GDAL的可执行文件路径。 在Python中调用`gdal_translate`命令时,Python解释器会尝试在系统路径中查找该命令,而不是在GDAL的可执行文件路径中查找。因此,如果系统路径中没有包含GDAL的可执行文件路径,Python解释器就无法找到`gdal_translate`命令,从而报错。 解决这个问题的方法有两种: 1. 在系统路径中添加GDAL的可执行文件路径 可以将GDAL的可执行文件路径添加到系统路径中,这样Python解释器就可以找到`gdal_translate`命令了。在Windows系统中,可以按以下步骤操作: - 打开“控制面板” -> “系统和安全” -> “系统” -> “高级系统设置” -> “环境变量”。 - 在“系统变量”中找到“Path”变量,点击“编辑”。 - 在变量值的最后添加GDAL的可执行文件路径,例如:“C:\Program Files\GDAL\bin”。 - 确认保存并关闭所有窗口。重新启动Python解释器,再次尝试运行`gdal_translate`命令。 2. 在Python程序中指定GDAL的可执行文件路径 可以在Python程序中手动指定`gdal_translate`命令的路径,例如: ```python import subprocess gdal_translate_path = r'C:\Program Files\GDAL\bin\gdal_translate.exe' subprocess.call([gdal_translate_path, 'input_file.tif', 'output_file.tif']) ``` 这样就可以保证Python程序能够正确地调用`gdal_translate`命令。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值