WIN10 VS2019下编译GDAL3.0+PROJ6+SQLite
准备
- GDAL3.0编译要求PROJ6投影库,而PROJ6又要求SQLite3环境,所以在编译GDAL之前我们需要先编译好SQLite和PROJ6.
下载
- 下载库
GDAL官方下载地址为https://gdal.org/download.html,我下载的版本是gdal-3.0.0
;PROJ6的官方下载地址为https://proj.org/download.html,我现在的版本为6.1.0
版本;SQLite3的官方下载地址为https://www.sqlite.org/download.html,下载Source Code下的sqlite-amalgamation-3280000.zip
,和Precompiled Binaries for Windows下的sqlite-dll-win32-x86-3280000.zip
sqlite-tools-win32-x86-3280000.zip
为了方便编译,我将下载的三个文件分别解压在F盘的根目录GDAL、PROJ、SQLite文件夹内,以备后用。 - 工具下载
cmake官方下载地址为https://cmake.org/download/,下载cmake-3.15.0-rc3-win64-x64.msi
文件直接载windows上安装,之后添加环境变量,以便在cmd命令行中使用。详细方法 - 懒人包
我编译好的版本静态库debug版、静态库release版、动态库debug版、动态库release版。
编译和安装
1. 静态编译SQLite库
可以按照文章的步骤进行编译。我在此重复一遍。
- 解压
将下载好的两个文件sqlite-amalgamation-3280000.zip
、和sqlite-dll-win32-x86-3280000.zip
解压到SQLite文件夹内,如下所示:
F:.
├─sqlite-amalgamation-3280000
│ shell.c
│ sqlite3.c
│ sqlite3.h
│ sqlite3ext.h
│
└─sqlite-dll-win64-x64-3280000
sqlite3.def
sqlite3.dll
- 创建静态库工程
- 在SQLite目录下创建一个新工程
- 选好工程创建位置之后,将
sqlite3.c
、sqlite3.h
、sqlite3ext.h
、sqlite3.def
四个文件添加到工程中,如下图所示: - C/C++ --> 预处理器 --> 预处理器定义:设置预定义处理
_USRDLL
SQLITE_ENABLE_RTREE
SQLITE_ENABLE_COLUMN_METADATA
SQLITE_ENABLE_FTS5
SQLITE_ENABLE_UNLOCK_NOTIFY
- 设置模块定义文件,链接器 --> 输入 --> 模块定义文件:
sqlite3.def
- 修改模块定义文件:在最后追加sqlite3_unlock_notify
- 配置类型改为静态库lib
- 最后生成解决方案(需要生成debug版时,选择debug,这里一release版为例),在
F:\SQLite\SQLite3\x64\Release
文件夹可以看到SQLite3.lib静态库和SQLite3.exe(debug版在F:\SQLite\SQLite3\x64\Release
文件夹中)。
在SQLite目录中分别创建include
和lib
和bin
文件夹,将刚才生成的.lib文件放入lib
文件夹中,将sqlite3.h
、sqlite3ext.h
放入include
中,将sqlite-tools-win32-x86-3280000.zip
中的sqlite3.exe放在bin
文件夹中以备后用。
2. 编译PROJ6
- 解压
将下载好的proj-6.1.0
解压到PROJ文件夹内。 - 编译PROJ6
- 进入库文件夹中,在源码目录中创建
build
文件夹,打开cmake - 点击Configure,编译64位,vs2019
- 会出现一些错误,如图
- 这时找到
Name
为EXE_SQLITE3
、SQLITE3_INCLUDE_DIR
和SQLITE3_LIBRARY
三个属性,可以看到现在它们的Value
值都为NOTFOUND的状态,我们将SQLite3.exe
、include
和SQLite3.lib
的路径分别赋给它们。
并设置文件生成目录,我设置的是c:/OSGeo4W。
- 重新点击Configure,提示Configuring done。点击Generate,这时可以看到
build
文件夹里有PROJ4.sln。打开x64 Native Tools Command Prompt for VS 2019
(一般在开始菜单安装VS2019的文件夹里就能看到),进入build文件夹, - 然后输入命令
msbuild ALL_BUILD.vcxproj /p:Configuration="Release"
msbuild INSTALL.vcxproj /p:Configuration="Release"
- 开启编译(编译debug版是将引号里面的Release改为Debug)。
- 这时可以在设置的文件生成目录中找到生成的文件
bin
中有各种*.exe
文件、include
中放有头文件、lib
中是静态库文件、share
放有一些数据文件。到此PROJ编译完成。
3. 编译GDAL
- 解压
将下载好的GDAL3.0.0
解压到GDAL
文件夹内。 - 编译GDAL
首先简单了解一下nmake.opt
文件中变量的意义(链接):
项目 | Value |
---|---|
MSVC_VER | 编译器版本 |
WIN64 | 是否编译64位版本 |
GDAL_HOME | 生成文件的目录 |
DLLBUILD | 是否动态编译 |
进入库文件夹中,找到nmake.opt
文件,用VS2019打开。
- 第41行左右,找到
MSVC_VER=
设置为1921
(VS2019版本应该为1920及以上,视自己编译器而定)。 - 第57行左右找到
GDAL_HOME =
将生成文件的路径设置成你想要的位置,我这里设置成"F:\warmerda_release"
。 - 第194行左右找到
WIN64=YES
,如果生成64位版本取消注释本行。 - 第218行左右找到
DLLBUILD=
设置为1
启动动态编译、0
为静态编译。我这里进行静态编译设置DLLBUILD=0
。 - 第238行左右,找到
PROJ_INCLUDE
PROJ_LIBRARY
,分别设置成你刚才生成PROJ时的include
和lib
文件夹(其中PROJ_INCLUDE
的-I
后为地址),并将.lib的名称改对。 - 第509行左右,找到
SQLITE_INC
SQLITE_LIB
,路径设置同上。
至此设置完成,保存文件。
打开x64 Native Tools Command Prompt for VS 2019
进入库文件夹,输入命令:
nmake /f makefile.vc
nmake /f makefile.vc devinstall
debug版输入
nmake /f makefile.vc DEBUG=1
nmake /f makefile.vc devinstall
进行编译和安装,完毕后可以在生成文件夹找到5个文件夹
完成!
测试程序
下面几个程序来源于网络,可以作为测试程序验证库是否可用。
库的引用设置可以参考博客
#include "gdal_priv.h"
#include<iostream>
using namespace std;
int main()
{
const char* pszFile;
GDALAllRegister();
pszFile = "F://2.jpg";
GDALDataset *poDataset = (GDALDataset*)GDALOpen(pszFile, GA_ReadOnly);
GDALRasterBand *poBand = poDataset->GetRasterBand(1);
int xsize = poBand->GetXSize();
int ysize = poBand->GetYSize();
cout << xsize << endl;
cout << ysize << endl;
return 0;
}
上述程序输出加载图片的行列数,具体数值由你加载的图片决定:
#include <iostream>
#include <iomanip>
#include "gdal_priv.h"
using std::cout;
/*
@brief 计算图像行列号在给定坐标系下对应的地理坐标
@param x 行号
@param y 列号
@param coords 返回的地理坐标
@param transform 变换的六参数
*/
void toGeoCoord(int x, int y, double* coords, double* transform)
{
coords[0] = transform[0] + x * transform[1] + y * transform[2];
coords[1] = transform[3] + x * transform[4] + y * transform[5];
}
/*
@brief 读取数据并输出元数据信息
@param fileName 数据文件路径
@return 数据读取失败返回1,读取成功返回0
*/
int readGeoRaster(const char* fileName)
{
GDALAllRegister(); // 注册所有支持的数据格式驱动
GDALDataset* dataset = static_cast<GDALDataset*>(GDALOpen(fileName, GA_ReadOnly)); // 以只读模式打开给定的数据文件
if (!dataset)
{
cout << "影像读取失败:(" << fileName << ")!" << '\n';
return EXIT_FAILURE;
}
int nSizeX = dataset->GetRasterXSize(); // 影像的宽度(像元数目)
int nSizeY = dataset->GetRasterYSize(); // 影像的高度(像元数目)
int nBandCount = dataset->GetRasterCount(); // 影像波段数
cout << "图像大小:(" << nSizeX << ", " << nSizeY << ")\n";
cout << "波段数:" << nBandCount << "\n";
double adfGeoTransform[6]; // 存储图像的六参数信息
dataset->GetGeoTransform(adfGeoTransform); // 获取数据的六参数信息
double adfULCoord[2]; // 图像左上角坐标
double adfLRCoord[2]; // 图像右下角坐标
// 获取左上角和右下角的地理坐标
toGeoCoord(0, 0, adfULCoord, adfGeoTransform);
toGeoCoord(nSizeX - 1, nSizeY - 1, adfLRCoord, adfGeoTransform);
cout << std::fixed; // 对于double类型的数据可以使其正常输入,阻止默认的科学计数法输出,
cout << "左上角坐标:(" << adfULCoord[0] << ", " << adfULCoord[1] << ")\n";
cout << "右下角坐标:(" << adfLRCoord[0] << ", " << adfLRCoord[1] << ")\n";
const char* pszProj = dataset->GetProjectionRef(); // 获得WKT形式的投影信息
cout << "投影信息:" << pszProj << '\n';
GDALClose(dataset); // 关闭数据集
return EXIT_SUCCESS;
}
int main()
{
const char* pszFileName = R"(E:\1_MASK.tif)";
return readGeoRaster(pszFileName);
}
上述程序的结果为:
有可能提示ERROR:找不到pro.db。解决方法是设置一个环境变量PROJ_LIB,将其路径设定到你share文件夹下proj文件夹中,因为在那里面有pro.db文件。
#include "gdal_priv.h"
#include "cpl_conv.h" //for CPLMalloc()
// int main()
int main(int argc, char* argv[])
{
//注册文件格式
GDALAllRegister();
const char* pszFile = "F:\\2.jpg";//"C:\\Test.img"; //1.jpg
// const char* pszFile = argv[1];
GDALDataset *poDataset;
//使用只读方式打开图像
poDataset = (GDALDataset*) GDALOpen( pszFile,GA_ReadOnly );
if( poDataset == NULL )
{
printf( "File: %s不能打开!\n",pszFile);
return 0;
}
//输出图像的格式信息
printf( "Driver:%s/%s\n",
poDataset->GetDriver()->GetDescription(),
poDataset->GetDriver()->GetMetadataItem( GDAL_DMD_LONGNAME) );
//输出图像的大小和波段个数
printf( "Size is%dx%dx%d\n",
poDataset->GetRasterXSize(),poDataset->GetRasterYSize(),
poDataset->GetRasterCount());
//输出图像的投影信息
if( poDataset->GetProjectionRef() != NULL )
printf( "Projectionis `%s'\n", poDataset->GetProjectionRef() );
//输出图像的坐标和分辨率信息
double adfGeoTransform[6];
if( poDataset->GetGeoTransform( adfGeoTransform) == CE_None )
{
printf( "Origin =(%.6f,%.6f)\n",
adfGeoTransform[0], adfGeoTransform[3]);
printf( "PixelSize = (%.6f,%.6f)\n",
adfGeoTransform[1], adfGeoTransform[5]);
}
GDALRasterBand *poBand;
int nBlockXSize, nBlockYSize;
int bGotMin, bGotMax;
double adfMinMax[2];
//读取第一个波段
poBand = poDataset->GetRasterBand( 1 );
//获取图像的块大小并输出
poBand->GetBlockSize(&nBlockXSize, &nBlockYSize );
printf( "Block=%dx%dType=%s, ColorInterp=%s\n",
nBlockXSize, nBlockYSize,
GDALGetDataTypeName(poBand->GetRasterDataType()),
GDALGetColorInterpretationName(
poBand->GetColorInterpretation()));
//获取该波段的最大值最小值,如果获取失败,则进行统计
adfMinMax[0] = poBand->GetMinimum( &bGotMin);
adfMinMax[1] = poBand->GetMaximum( &bGotMax);
if( ! (bGotMin&& bGotMax) )
GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);
printf( "Min=%.3fd,Max=%.3f\n", adfMinMax[0], adfMinMax[1] );
//输出图像的金字塔信息
if( poBand->GetOverviewCount() > 0 )
printf( "Band has%d overviews.\n", poBand->GetOverviewCount() );
//输出图像的颜色表信息
if( poBand->GetColorTable() != NULL)
printf( "Band hasa color table with %d entries.\n",
poBand->GetColorTable()->GetColorEntryCount() );
float *pafScanline;
int nXSize = poBand->GetXSize();
//读取图像的第一行数据
pafScanline = (float*) CPLMalloc(sizeof(float)*nXSize);
poBand->RasterIO(GF_Read, 0, 0, nXSize,1,
pafScanline, nXSize,1, GDT_Float32, 0, 0 );
CPLFree(pafScanline);
//关闭文件
GDALClose((GDALDatasetH)poDataset);
}
上述程序的输出结果为(具体信息由加载图片决定)
#include "ogrsf_frmts.h"
int main()
{
GDALAllRegister();
GDALDataset* poDS;
poDS = (GDALDataset*)GDALOpenEx("F:\\point.shp", GDAL_OF_VECTOR, NULL, NULL, NULL);
if (poDS == NULL)
{
printf("Open failed.\n");
exit(1);
}
OGRLayer* poLayer;
poLayer = poDS->GetLayerByName("point");
//中间读取Feature、FeatureDefn和Geometry等接口没有任何变化
//关闭数据
GDALClose(poDS);
}
上述程序不报Open failed
,基本就为成功。
06f79bde-8c58-42b5-add6-d089aca9c3a2