上篇博文中的代码使用了函数wcstombs来进行处理,今天发现GDAL库里面提供了宽字节转单字节的函数,名字叫CPLRecodeFromWChar(这个函数需要libiconv库的支持,也就是在编译GDAL的时候需要把libiconv库一起编译)。本以为C#语言也可以使用,结果很悲剧的发现,C#的提供的接口中没有相关的函数,看来使用C#的同学有点悲剧了。
需要说明的是,需要先用函数CPLRecodeFromWChar将宽字节转为UTF8,然后再使用函数CPLRecode将UTF8转为汉字编码(CP936)。
程序依旧是昨天的那个,函数全部换成GDAL的函数,代码如下:
int ReadS57()
{
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
OGRRegisterAll();
//打开数据
const char* pszS57 = "D:\\C1100102.000";
OGRDataSource *poDS = OGRSFDriverRegistrar::Open(pszS57, FALSE );
if( poDS == NULL )
{
printf( "Open failed.\n" );
return 1;
}
// 获取有中文属性值的图层
OGRLayer *poLayer = poDS->GetLayerByName( "BUAARE" );
if( poLayer == NULL )
{
printf( "Get Layer failed.\n" );
OGRDataSource::DestroyDataSource( poDS );
return 1;
}
poLayer->ResetReading();
OGRFeature *poFeature = poLayer->GetNextFeature();
while (poFeature != NULL )
{
OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn(); //获取属性字段值
// 为了演示说明,就只输出乱码的属性值
const char* pszAttValue = poFeature->GetFieldAsString("NOBJNM");
size_t size = strlen(pszAttValue);
if (size != 0)
{
char* pszValue = new char[size];
memcpy(pszValue, pszAttValue, size);
pszValue[size-1] = '\0';
char *pszGetUTF8 = CPLRecodeFromWChar( (const wchar_t*)pszValue, CPL_ENC_UCS2, CPL_ENC_UTF8);
pszAttValue = CPLRecode( pszGetUTF8, CPL_ENC_UTF8, "");
delete []pszValue;
}
printf("%s\n", pszAttValue);
OGRFeature::DestroyFeature( poFeature );
poFeature = poLayer->GetNextFeature();
}
OGRDataSource::DestroyDataSource( poDS );
return 0;
}下图是执行输出的结果,和使用QGIS打开对比。
通过上面的方式是可以解决这个问题,不过稍微有点麻烦,需要在每次获取属性值的时候都要进行判断。我们可以直接修改GDAL库中的代码,这样在读取的时候直接就是汉字编码。找了一下午,在GDAL库的源码中文件gdal-1.9.2\ogr\ogrsf_frmts\s57\s57reader.cpp行883左右,修改为下面:
// Add By liml 2013-04-25 Convert UCS-2 to Utf-8
const char* pachBuffer = poRecord->GetStringSubfield("NATF",0,"ATVL",iAttr);
if( EQUAL(pszAcronym, "NOBJNM"))
{
size_t nLength = strlen(pachBuffer);
char* pszValue = new char[nLength];
memcpy(pszValue, pachBuffer, nLength);
pszValue[nLength-1] = '\0';
char *pszGetUTF8 = CPLRecodeFromWChar( (const wchar_t*)pszValue, CPL_ENC_UCS2, CPL_ENC_UTF8);
pachBuffer = CPLRecode( pszGetUTF8, CPL_ENC_UTF8, CPL_ENC_LOCALE);
delete []pszValue;
}
// Add By liml 2013-04-25
poFeature->SetField( pszAcronym, pachBuffer);下面是使用ogrinfo输出的对比情况,左边是没修改时输出的,右边是修改后输出的。
虽然这么修改是可以解决这个问题,但是不知道会不会引起其他的副作用。等发现了再修改吧。修改之后的GDAL库已经上传至我的资源中心,有需要的同学可以自行去下载。