扩展GDAL,支持CNSDTF格式(一)

一、        简介

本文主要根据《中华人民共和国国家标准GB/T17798-2007——地理空间数据交换格式(Geospatialdata transfer format)》(http://www.bzxz.net/bzxz/129804.html)中定义的格网数据和矢量数据格式内容,对GDAL库进行扩充,使之可以直接打开这两种格式。

此外GDAL格式扩展就参考GDAL官方文档中的扩展方式。网址为:www.gdal.org/gdal_drivertut.html

二、        软件和数据

编写代码的软件使用Visual Studio2008 SP1,使用其他的记事本软件应该都可以,此外还需要一个编译器,来编译GDAL,用来检验写的代码的正确性。

数据是按照国标GB/T17798-2007中的示例数据自己写的一个测试数据。栅格数据内容如下,矢量数据比较复杂,后面单独再说,下面先介绍栅格数据。

DataMark:CNSDTF-DEM
Version:1.0
Alpha:0.0
Compress:0
X0:458312.500
Y0:3458762.500
DX:12.500
DY:12.500
Row:10
Col:30
ValueType:Integer
Hzoom:100
XYUnit:M
ZUnit:M
CoordinateSystemType:P
Spheroid:西安(1980),6378.140,298.257
Projection:高斯-克吕格
Parameters:117,0,,,,1,500000,0,3, 2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
2387987 1564 1574 785 854 587 747 454 7844
2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
2387987 1564 1574 785 854 587 747 454 7844
2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
2387987 1564 1574 785 854 587 747 454 7844
2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
2387987 1564 1574 785 854 587 747 454 7844
2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
2387987 1564 1574 785 854 587 747 454 7844
2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
100200 355 45 124 4548 147 145 1454 354
2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
100200 355 45 124 4548 147 145 1454 354
100200 355 45 124 4548 147 145 1454 354
2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
100200 355 45 124 4548 147 145 1454 354
100200 355 45 124 4548 147 145 1454 354
2387987 1564 1574 785 854 587 747 454 7844
100200 355 45 124 4548 147 145 1454 354
100200 355 45 124 4548 147 145 1454 354
100200 355 45 124 4548 147 145 1454 354

三、        编写源码

首先按照GDAL官网中的说明,我们要实现一个从GDALDataset类派生的一个子类CNSDTFDataset,该类的定义如下:

/************************************************************************/
/*==================================================================== */
/* CNSDTFDataset */
/*==================================================================== */
/************************************************************************/ classCNSDTFRasterBand; classCPL_DLL CNSDTFDataset : public GDALPamDataset
{
friend class CNSDTFRasterBand; VSILFILE *fp; char **papszPrj;
CPLString osPrjFilename;
char *pszProjection; // DataMark Version Compress Alpha
CPLString osDataMark;
CPLString osDataVersion;
GBool bIsCompress;
double adfAlphaValue;
CPLString osValueType;
int nHZoom;
CPLString osUnitType; unsigned char achReadBuf[256];
GUIntBig nBufferOffset;
int nOffsetInBuffer; char Getc();
GUIntBig Tell();
int Seek( GUIntBig nOffset ); protected:
GDALDataType eDataType;
double adfGeoTransform[6];
int bNoDataSet;
double dfNoDataValue;
double dfMin;
double dfMax; int ParseHeader(const char* pszHeader); public:
CNSDTFDataset();
~CNSDTFDataset(); virtual char **GetFileList(void); static GDALDataset *Open( GDALOpenInfo *poOpenInfo);
static int Identify( GDALOpenInfo * poOpenInfo);
static GDALDataset *CreateCopy( const char* pszFilename,
GDALDataset *poSrcDS, int bStrict,char ** papszOptions,
GDALProgressFunc pfnProgress, void *pProgressData ); virtual CPLErr GetGeoTransform( double *padfTransform);
virtual const char*GetProjectionRef(void);
};

下面是该类的实现,没有实现Create方法,只实现了CreateCopy方式,以后有时间把Create方法加上。

/************************************************************************/
/* CNSDTFDataset() */
/************************************************************************/ CNSDTFDataset::CNSDTFDataset()
{
papszPrj = NULL;
pszProjection = CPLStrdup("");
fp = NULL;
eDataType = GDT_Int32;
bNoDataSet = FALSE;
dfNoDataValue = -99999.0; adfGeoTransform[0] = 0.0;
adfGeoTransform[1] = 1.0;
adfGeoTransform[2] = 0.0;
adfGeoTransform[3] = 0.0;
adfGeoTransform[4] = 0.0;
adfGeoTransform[5] = 1.0; nOffsetInBuffer = 256;
nBufferOffset = 0; osDataMark = "CNSDTF-RAS";
osDataVersion = "GB/T17798-2007";
bIsCompress = FALSE;
adfAlphaValue = 0.0;
osValueType = "Integer";
nHZoom = 1;
dfMin = 0.0;
dfMax = 0.0;
} /************************************************************************/
/* ~CNSDTFDataset() */
/************************************************************************/ CNSDTFDataset::~CNSDTFDataset() {
FlushCache(); if( fp != NULL )
VSIFCloseL( fp ); CPLFree( pszProjection );
CSLDestroy( papszPrj );
} /************************************************************************/
/* Tell() */
/************************************************************************/ GUIntBigCNSDTFDataset::Tell() {
return nBufferOffset + nOffsetInBuffer;
} /************************************************************************/
/* Seek() */
/************************************************************************/ intCNSDTFDataset::Seek( GUIntBig nNewOffset ) {
nOffsetInBuffer = sizeof(achReadBuf);
return VSIFSeekL( fp, nNewOffset, SEEK_SET);
} /************************************************************************/
/* Getc() */
/* */
/* Read a single character from the inputfile (efficiently we */
/* hope). */
/************************************************************************/ charCNSDTFDataset::Getc() {
if( nOffsetInBuffer < (int)sizeof(achReadBuf) )
return achReadBuf[nOffsetInBuffer++]; nBufferOffset = VSIFTellL( fp );
int nRead = VSIFReadL( achReadBuf, 1,sizeof(achReadBuf), fp );
unsigned int i;
for(i=nRead;i<sizeof(achReadBuf);i++)
achReadBuf[i] = '\0'; nOffsetInBuffer = 0; return achReadBuf[nOffsetInBuffer++];
} /************************************************************************/
/* GetFileList() */
/************************************************************************/ char**CNSDTFDataset::GetFileList() {
char **papszFileList =GDALPamDataset::GetFileList(); if( papszPrj != NULL )
papszFileList = CSLAddString(papszFileList, osPrjFilename ); return papszFileList;
} /************************************************************************/
/* Identify() */
/************************************************************************/ intCNSDTFDataset::Identify( GDALOpenInfo * poOpenInfo ) {
/*-------------------------------------------------------------------- */
/* Does this look like an CNSDTF grid file? */
/*-------------------------------------------------------------------- */
if( poOpenInfo->nHeaderBytes < 40
|| !( EQUALN((const char *) poOpenInfo->pabyHeader,"DataMark",8)||
EQUALN((const char *)poOpenInfo->pabyHeader,"Version",7) ||
EQUALN((const char *)poOpenInfo->pabyHeader,"Alpha",5)||
EQUALN((const char *)poOpenInfo->pabyHeader,"Compress",7)||
EQUALN((const char *)poOpenInfo->pabyHeader,"X0",2)||
EQUALN((const char *)poOpenInfo->pabyHeader,"Y0",2)||
EQUALN((const char *)poOpenInfo->pabyHeader,"DX",2)||
EQUALN((const char *)poOpenInfo->pabyHeader,"DY",2)||
EQUALN((const char *) poOpenInfo->pabyHeader,"Row",3)||
EQUALN((const char *)poOpenInfo->pabyHeader,"Col",3)||
EQUALN((const char *)poOpenInfo->pabyHeader,"ValueType",9)||
EQUALN((const char *)poOpenInfo->pabyHeader,"HZoom",5)) )
return FALSE; char** papszTokens = CSLTokenizeString2((const char *) poOpenInfo->pabyHeader, " \n\r\t" , 0 );
int nTokens = CSLCount(papszTokens);
if (nTokens <11) //the header at (the) least 11 lines
{
CSLDestroy( papszTokens );
return FALSE;
} if( poOpenInfo->nHeaderBytes < 40 ||
!( EQUALN(papszTokens[0],"DataMark:CNSDTF-DEM", 19) ||
EQUALN(papszTokens[0],"DataMark:CNSDTF-RAS", 19) ||
EQUALN(papszTokens[0],"DataMark:CSDTF-DEM", 18) ||
EQUALN(papszTokens[0],"DataMark:CSDTF-RAS", 18))
)
{
CSLDestroy( papszTokens );
return FALSE;
} CSLDestroy( papszTokens );
return TRUE;
} /************************************************************************/
/* Open() */
/************************************************************************/ GDALDataset*CNSDTFDataset::Open( GDALOpenInfo * poOpenInfo )
{
if (!Identify(poOpenInfo))
return NULL; int i = 0; /*-------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/*-------------------------------------------------------------------- */
CNSDTFDataset *poDS;
poDS = new CNSDTFDataset(); /* --------------------------------------------------------------------*/
/* Parse the header. */
/*-------------------------------------------------------------------- */
if (!poDS->ParseHeader((const char *)poOpenInfo->pabyHeader))
{
delete poDS;
return NULL;
} /*-------------------------------------------------------------------- */
/* Open file with large file API. */
/*-------------------------------------------------------------------- */ poDS->fp = VSIFOpenL(poOpenInfo->pszFilename, "r" );
if( poDS->fp == NULL )
{
CPLError( CE_Failure,CPLE_OpenFailed,
"VSIFOpenL(%s) failedunexpectedly.",
poOpenInfo->pszFilename );
delete poDS;
return NULL;
} /*-------------------------------------------------------------------- */
/* Find the start of real data. */
/*-------------------------------------------------------------------- */
int nStartOfData; for (i=0; TRUE; i++)
{
char cChar =poOpenInfo->pabyHeader[i];
if( cChar == '\0' )
{
CPLError( CE_Failure,CPLE_AppDefined,
"Couldn't find datavalues in CNSDTF Grid file.\n" );
delete poDS;
return NULL;
} if (cChar == '\r' || cChar == '\n')
{
char cNext =poOpenInfo->pabyHeader[i+1];
if(isalpha(cNext) ||isalpha(poOpenInfo->pabyHeader[i+2]))
continue; if ((cNext >= '0' &&cNext <='9')
|| cNext=='-'
|| cNext=='.' )
{
nStartOfData = i+1;
/* Beginning of real datafound. */
break;
}
}
} /*-------------------------------------------------------------------- */
/* Recognize the type of data. */
/* --------------------------------------------------------------------*/
CPLAssert( NULL != poDS->fp ); /*-------------------------------------------------------------------- */
/* Create band information objects. */
/* --------------------------------------------------------------------*/
CNSDTFRasterBand* band = newCNSDTFRasterBand( poDS, nStartOfData );
poDS->SetBand( 1, band );
if (band->panLineOffset == NULL)
{
delete poDS;
return NULL;
} /*-------------------------------------------------------------------- */
/* Parse the SRS. */
/*-------------------------------------------------------------------- */
CPLString strProjection = ParseSpatialReference((constchar *) poOpenInfo->pabyHeader);
if (strProjection != "")
{
CPLFree( poDS->pszProjection );
poDS->pszProjection =CPLStrdup(strProjection.c_str());
} if (EQUAL(poDS->pszProjection,""))
{
/* --------------------------------------------------------------------*/
/* Try to read projection file. */
/*-------------------------------------------------------------------- */
char *pszDirname, *pszBasename;
VSIStatBufL sStatBuf; pszDirname =CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
pszBasename =CPLStrdup(CPLGetBasename(poOpenInfo->pszFilename)); poDS->osPrjFilename =CPLFormFilename( pszDirname, pszBasename, "prj" );
int nRet = VSIStatL(poDS->osPrjFilename, &sStatBuf ); if( nRet != 0 &&VSIIsCaseSensitiveFS(poDS->osPrjFilename) )
{
poDS->osPrjFilename =CPLFormFilename( pszDirname, pszBasename, "PRJ" );
nRet = VSIStatL(poDS->osPrjFilename, &sStatBuf );
} if( nRet == 0 )
{
OGRSpatialReference oSRS; poDS->papszPrj = CSLLoad(poDS->osPrjFilename ); CPLDebug( "CNSDTFGrid", "Loaded SRS from %s",
poDS->osPrjFilename.c_str()); if( oSRS.importFromESRI(poDS->papszPrj ) == OGRERR_NONE )
{
// If geographic valuesare in seconds, we must transform.
// Is there a code forminutes too?
if( oSRS.IsGeographic()
&&EQUAL(OSR_GDS( poDS->papszPrj, "Units", ""),"DS") )
{
poDS->adfGeoTransform[0]/= 3600.0;
poDS->adfGeoTransform[1] /= 3600.0;
poDS->adfGeoTransform[2]/= 3600.0;
poDS->adfGeoTransform[3]/= 3600.0;
poDS->adfGeoTransform[4]/= 3600.0;
poDS->adfGeoTransform[5]/= 3600.0;
} CPLFree(poDS->pszProjection );
oSRS.exportToWkt(&(poDS->pszProjection) );
}
} CPLFree( pszDirname );
CPLFree( pszBasename );
} /*-------------------------------------------------------------------- */
/* Initialize any PAM information. */
/*-------------------------------------------------------------------- */
poDS->SetDescription(poOpenInfo->pszFilename );
poDS->TryLoadXML(); /*-------------------------------------------------------------------- */
/* Check for external overviews. */
/*-------------------------------------------------------------------- */
poDS->oOvManager.Initialize( poDS,poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles ); return( poDS );
} /************************************************************************/
/* ParseHeader() */
/************************************************************************/ intCNSDTFDataset::ParseHeader(const char* pszHeader)
{
int i, j;
char** papszTokens = CSLTokenizeString2(pszHeader, " \n\r\t::" , 0 );
int nTokens = CSLCount(papszTokens); if ( (i = CSLFindString( papszTokens,"DataMark" )) < 0 || i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
}
osDataMark = papszTokens[i + 1]; if ( (i = CSLFindString( papszTokens,"Version" )) < 0 || i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
}
osDataVersion = papszTokens[i + 1]; if ( (i = CSLFindString( papszTokens,"Alpha" )) < 0 || i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
}
adfAlphaValue = CPLAtofM(papszTokens[i +1]); if ( (i = CSLFindString( papszTokens,"Compress" )) < 0 || i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
}
bIsCompress = atoi(papszTokens[i + 1]); if ( (i = CSLFindString( papszTokens,"Hzoom" )) < 0 ||
i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
}
nHZoom = atoi(papszTokens[i + 1]); if ( (i = CSLFindString( papszTokens,"Col" )) < 0 || i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
} nRasterXSize = atoi(papszTokens[i + 1]); if ( (i = CSLFindString( papszTokens,"Row" )) < 0 || i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
} nRasterYSize = atoi(papszTokens[i + 1]); if(!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize))
{
CSLDestroy( papszTokens );
return FALSE;
} double dfCellDX = 0;
double dfCellDY = 0;
if ( (i = CSLFindString( papszTokens,"CELLSIZE" )) < 0 )
{
int iDX, iDY;
if( (iDX =CSLFindString(papszTokens,"DX")) < 0
|| (iDY =CSLFindString(papszTokens,"DY")) < 0
|| iDX+1 >= nTokens
|| iDY+1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
} dfCellDX = CPLAtofM(papszTokens[iDX+1] );
dfCellDY = CPLAtofM(papszTokens[iDY+1] );
}
else
{
if (i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
}
dfCellDX = dfCellDY = CPLAtofM(papszTokens[i + 1] );
} if ((i = CSLFindString( papszTokens,"X0" )) >= 0 &&
(j = CSLFindString( papszTokens,"Y0" )) >= 0 &&
i + 1 < nTokens && j + 1< nTokens)
{
adfGeoTransform[0] = CPLAtofM(papszTokens[i + 1] );
adfGeoTransform[1] = dfCellDX;
adfGeoTransform[2] = 0.0;
adfGeoTransform[3] = CPLAtofM(papszTokens[j + 1] );
adfGeoTransform[4] = 0.0;
adfGeoTransform[5] = - dfCellDY;
}
else
{
adfGeoTransform[0] = 0.0;
adfGeoTransform[1] = dfCellDX;
adfGeoTransform[2] = 0.0;
adfGeoTransform[3] = 0.0;
adfGeoTransform[4] = 0.0;
adfGeoTransform[5] = - dfCellDY;
} if ( (i = CSLFindString( papszTokens,"ValueType" )) < 0 || i + 1 >= nTokens)
{
CSLDestroy( papszTokens );
return FALSE;
} osValueType = papszTokens[i + 1];
if (EQUAL(osValueType,"Integer"))
{
eDataType = GDT_Int32;
bNoDataSet = TRUE;
dfNoDataValue = -99999;
}
else if (EQUAL(osValueType,"Char"))
{
eDataType = GDT_Byte;
}
else
{
CSLDestroy( papszTokens );
returnFALSE;
} if( (i = CSLFindString( papszTokens,"NODATA_value" )) >= 0 && i + 1 < nTokens)
{
const char* pszNoData = papszTokens[i+ 1]; bNoDataSet = TRUE;
dfNoDataValue = CPLAtofM(pszNoData);
if((strchr( pszNoData, '.' ) != NULL||
strchr( pszNoData, ',' ) !=NULL ||
INT_MIN > dfNoDataValue ||dfNoDataValue > INT_MAX) )
{
eDataType = GDT_Float32;
} if( eDataType == GDT_Float32 )
{
dfNoDataValue = (double)(float) dfNoDataValue;
}
} if ( (i = CSLFindString( papszTokens,"MinV" )) >= 0 && i + 1 < nTokens)
dfMin = CPLAtofM(papszTokens[i + 1]); if ( (i = CSLFindString( papszTokens,"MaxV" )) >= 0 && i + 1 < nTokens)
dfMax = CPLAtofM(papszTokens[i + 1]); if ( (i = CSLFindString( papszTokens,"Unit" )) >= 0 && i + 1 < nTokens)
osUnitType = papszTokens[i + 1]; if ( (i = CSLFindString( papszTokens,"ZUnit" )) >= 0 && i + 1 < nTokens)
osUnitType = papszTokens[i + 1]; CSLDestroy( papszTokens );
return TRUE;
} /************************************************************************/
/* GetGeoTransform() */
/************************************************************************/ CPLErrCNSDTFDataset::GetGeoTransform( double * padfTransform ) {
memcpy( padfTransform, adfGeoTransform,sizeof(double) * 6 );
return( CE_None );
} /************************************************************************/
/* GetProjectionRef() */
/************************************************************************/ constchar *CNSDTFDataset::GetProjectionRef() {
return pszProjection;
} /************************************************************************/
/* CreateCopy() */
/************************************************************************/ GDALDataset* CNSDTFDataset::CreateCopy(
constchar * pszFilename, GDALDataset *poSrcDS,
intbStrict, char ** papszOptions,
GDALProgressFuncpfnProgress, void * pProgressData ) {
int nBands = poSrcDS->GetRasterCount();
int nXSize = poSrcDS->GetRasterXSize();
int nYSize = poSrcDS->GetRasterYSize(); /*-------------------------------------------------------------------- */
/* Some rudimentary checks */
/*-------------------------------------------------------------------- */
if( nBands != 1 )
{
CPLError( CE_Failure,CPLE_NotSupported,
"CNSDTF Grid driverdoesn't support %d bands. Must be 1band.\n",
nBands ); return NULL;
} if( !pfnProgress( 0.0, NULL, pProgressData) )
return NULL; /*-------------------------------------------------------------------- */
/* Create the dataset. */
/*-------------------------------------------------------------------- */
VSILFILE *fpImage; fpImage = VSIFOpenL( pszFilename,"wt" );
if( fpImage == NULL )
{
CPLError( CE_Failure,CPLE_OpenFailed,
"Unable to create file%s.\n", pszFilename );
return NULL;
} /*-------------------------------------------------------------------- */
/* Write CNSDTF Grid file header */
/*-------------------------------------------------------------------- */
char szHeader[2000];
const char *pszForceRaster =CSLFetchNameValue( papszOptions, "FORCE_RASTER" );
char* pszHeaderMark ="DataMark:CNSDTF-DEM";
if(pszForceRaster != NULL &&CSLTestBoolean(pszForceRaster))
pszHeaderMark ="DataMark:CNSDTF-RAS"; double adfGeoTransform[6];
poSrcDS->GetGeoTransform(adfGeoTransform ); sprintf( szHeader,
"%s\n"
"Version:GB/T17798-2007\n"
"Alpha:0.0\n"
"Compress:0\n"
"X0:%.12f\n"
"Y0:%.12f\n"
"DX:%.12f\n"
"DY:%.12f\n"
"Row:%d\n"
"Col:%d\n"
"ValueType:Integer\n", //Integer
pszHeaderMark,
adfGeoTransform[0],
adfGeoTransform[3],
ABS(adfGeoTransform[1]),
ABS(adfGeoTransform[5]),
nYSize, nXSize); /*-------------------------------------------------------------------- */
/* Try to write projection file. */
/* --------------------------------------------------------------------*/
const char *pszOriginalProjection = poSrcDS->GetProjectionRef();
if( !EQUAL( pszOriginalProjection,"" ) )
{
char *pszDirname, *pszBasename;
char *pszPrjFilename;
char *pszESRIProjection = NULL;
VSILFILE *fp;
OGRSpatialReference oSRS; pszDirname = CPLStrdup(CPLGetPath(pszFilename) );
pszBasename = CPLStrdup(CPLGetBasename(pszFilename) ); pszPrjFilename = CPLStrdup(CPLFormFilename( pszDirname, pszBasename, "prj" ) );
fp = VSIFOpenL( pszPrjFilename,"wt" );
if (fp != NULL)
{
oSRS.importFromWkt( (char **)&pszOriginalProjection );
oSRS.morphToESRI();
oSRS.exportToWkt(&pszESRIProjection );
VSIFWriteL( pszESRIProjection,1, strlen(pszESRIProjection), fp ); VSIFCloseL( fp );
CPLFree( pszESRIProjection );
}
else
{
CPLError( CE_Failure,CPLE_FileIO,
"Unable to createfile %s.\n", pszPrjFilename );
}
CPLFree( pszDirname );
CPLFree( pszBasename );
CPLFree( pszPrjFilename );
} GDALRasterBand * poBand =poSrcDS->GetRasterBand( 1 );
double dfNoData, dfScale, dfMin, dfMax;
int bSuccess; const char* pszUnitType =poBand->GetUnitType();
if(pszUnitType != NULL)
sprintf( szHeader+strlen(szHeader),"ZUnit:%s\n", pszUnitType ); // Write `nodata' value to header if it isexists in source dataset
dfNoData = poBand->GetNoDataValue(&bSuccess );
if ( bSuccess )
sprintf( szHeader+strlen(szHeader),"NODATA_value:%6.20g\n", dfNoData ); // Write `HZoom' value to header if it isexists in source dataset
dfScale = poBand->GetScale(&bSuccess );
if ( !bSuccess )
dfScale = 1.0;
sprintf( szHeader+strlen(szHeader),"HZoom:%.20g\n", dfScale ); // Write `minmax' value to header if it isexists in source dataset
dfMin = poBand->GetMinimum(&bSuccess );
if ( bSuccess )
sprintf( szHeader+strlen(szHeader),"MinV:%.20g\n", dfMin ); dfMax = poBand->GetMaximum(&bSuccess );
if ( bSuccess )
sprintf( szHeader+strlen(szHeader),"MaxV:%.20g\n", dfMax ); VSIFWriteL( szHeader, 1, strlen(szHeader),fpImage ); /*-------------------------------------------------------------------- */
/* Builds the format string used for printing float values. */
/*-------------------------------------------------------------------- */
char szFormatFloat[32];
strcpy(szFormatFloat, " %.20g");
const char *pszDecimalPrecision =CSLFetchNameValue( papszOptions, "DECIMAL_PRECISION" );
if (pszDecimalPrecision)
{
int nDecimal =atoi(pszDecimalPrecision);
if (nDecimal >= 0)
sprintf(szFormatFloat, "%%.%dg", nDecimal);
} /*-------------------------------------------------------------------- */
/* Loop over image, copying image data. */
/*-------------------------------------------------------------------- */
int *panScanline = NULL;
double *padfScanline = NULL;
int bReadAsInt;
int iLine, iPixel;
CPLErr eErr = CE_None; bReadAsInt = (poBand->GetRasterDataType() == GDT_Byte
|| poBand->GetRasterDataType() ==GDT_Int16
|| poBand->GetRasterDataType() ==GDT_UInt16
|| poBand->GetRasterDataType() ==GDT_Int32 ); // Write scanlines to output file
if (bReadAsInt)
panScanline = (int *) CPLMalloc(nXSize * GDALGetDataTypeSize(GDT_Int32) / 8 );
else
padfScanline = (double *) CPLMalloc(nXSize * GDALGetDataTypeSize(GDT_Float64) / 8 ); for( iLine = 0; eErr == CE_None &&iLine < nYSize; iLine++ )
{
CPLString osBuf;
eErr = poBand->RasterIO( GF_Read,0, iLine, nXSize, 1,
(bReadAsInt) ?(void*)panScanline : (void*)padfScanline,
nXSize, 1, (bReadAsInt) ?GDT_Int32 : GDT_Float64, 0, 0 ); if( bReadAsInt )
{
for ( iPixel = 0; iPixel <nXSize; iPixel++ )
{
sprintf( szHeader,"%d ", panScanline[iPixel] );
if(iPixel % 10 == 9)
sprintf(szHeader+strlen(szHeader), "\n" ); osBuf += szHeader;
if( (iPixel & 1023) ==0 || iPixel == nXSize - 1 )
{
if ( VSIFWriteL(osBuf, (int)osBuf.size(), 1, fpImage ) != 1 )
{
eErr =CE_Failure;
CPLError(CE_Failure, CPLE_AppDefined, "Write failed, disk full?\n" );
break;
}
osBuf ="";
}
}
}
else
{
for ( iPixel = 0; iPixel <nXSize; iPixel++ )
{
sprintf( szHeader,szFormatFloat, padfScanline[iPixel] );
if(iPixel % 10 == 9)
sprintf(szHeader+strlen(szHeader), "\n" ); osBuf += szHeader;
if( (iPixel & 1023) ==0 || iPixel == nXSize - 1 )
{
if ( VSIFWriteL(osBuf, (int)osBuf.size(), 1, fpImage ) != 1 )
{
eErr =CE_Failure;
CPLError(CE_Failure, CPLE_AppDefined, "Write failed, disk full?\n" );
break;
}
osBuf ="";
}
}
}
VSIFWriteL( (void *) "\n",1, 1, fpImage ); if( eErr == CE_None &&
!pfnProgress((iLine + 1) /((double) nYSize), NULL, pProgressData) )
{
eErr = CE_Failure;
CPLError( CE_Failure,CPLE_UserInterrupt, "User terminated CreateCopy()" );
}
} CPLFree( panScanline );
CPLFree( padfScanline );
VSIFCloseL( fpImage ); if( eErr != CE_None )
return NULL; /*-------------------------------------------------------------------- */
/* Re-open dataset, and copy any auxilary pam information. */
/*-------------------------------------------------------------------- */ /* If outputing to stdout, we can't reopenit, so we'll return */
/* a fake dataset to make the caller happy*/
CPLPushErrorHandler(CPLQuietErrorHandler);
GDALPamDataset* poDS = (GDALPamDataset*)GDALOpen(pszFilename, GA_ReadOnly);
CPLPopErrorHandler();
if (poDS)
{
poDS->CloneInfo( poSrcDS,GCIF_PAM_DEFAULT );
return poDS;
} CPLErrorReset(); CNSDTFDataset* poCnsdtfDS = newCNSDTFDataset();
poCnsdtfDS->nRasterXSize = nXSize;
poCnsdtfDS->nRasterYSize = nYSize;
poCnsdtfDS->nBands = 1;
poCnsdtfDS->SetBand( 1, newCNSDTFRasterBand( poCnsdtfDS, 1 ) );
return poCnsdtfDS;
}

上面的代码中关于CNSDTF中的空间参考部分,由于定义的比较复杂,所以保留了直接读取同名的prj文件投影。在这里需要用到一个函数OSR_GDS,该函数的实现以及定义如下:

/************************************************************************/
/* OSR_GDS() */
/************************************************************************/ staticCPLString OSR_GDS( char **papszNV, const char * pszField,
const char *pszDefaultValue ) {
int iLine; if( papszNV == NULL || papszNV[0] == NULL)
return pszDefaultValue; for( iLine = 0;
papszNV[iLine] != NULL &&
!EQUALN(papszNV[iLine],pszField,strlen(pszField));
iLine++ ) {} if( papszNV[iLine] == NULL )
return pszDefaultValue;
else
{
CPLString osResult;
char **papszTokens; papszTokens =CSLTokenizeString(papszNV[iLine]); if( CSLCount(papszTokens) > 1 )
osResult = papszTokens[1];
else
osResult = pszDefaultValue; CSLDestroy( papszTokens );
return osResult;
}
}

此外还写了从文件头中解析投影信息并组成WKT格式,目前还有国标中定义的两个投影(彭纳等积伪圆锥和等积斜轴切方位)没有找到与OSR中对应的,所以暂时没有处理。具体的代码如下:

staticchar *papszProjectionName[18] = {
"地理坐标系",
"高斯-克吕格",
"兰勃特正形割圆锥",
"兰勃特正形切圆锥",
"兰勃特等积方位",
"亚尔勃斯等积割圆锥",
"亚尔勃斯等积切圆锥",
"通用横轴墨卡托",
"墨卡托正轴等角切圆柱",
"墨卡托正轴等角割圆柱",
"波斯托等距切方位",
"彭纳等积伪圆锥",
"等积正轴切圆柱",
"等积正轴割圆柱",
"等距正轴切圆锥",
"等距正轴割圆锥",
"等积斜轴切方位",
NULL
}; staticconst int nProjectionParametersIndex[18] = {
0, //0000000000 "地理坐标系"
543, //1000011111 "高斯-克吕格"
972, //1111001100 "兰勃特正形割圆锥"
780, //1100001100 "兰勃特正形切圆锥"
796, //1100011100 "兰勃特等积方位"
543, //1111001100 "亚尔勃斯等积割圆锥"
972, //1111001100 "亚尔勃斯等积切圆锥"
525, //1000001101 "通用横轴墨卡托"
540, //1000011100 "墨卡托正轴等角切圆柱"
796, //1100011100 "墨卡托正轴等角割圆柱"
780, //1100001100 "波斯托等距切方位"
780, //1100001100 "彭纳等积伪圆锥"
524, //1000001100 "等积正轴切圆柱"
780, //1100001100 "等积正轴割圆柱"
780, //1100001100 "等距正轴切圆锥"
972, //1111001100 "等距正轴割圆锥"
796, //1100011100 "等积斜轴切方位"
0
}; /************************************************************************/
/* ParseSpatialReference() */
/************************************************************************/ CPLStringParseSpatialReference(const char* pszHeader)
{
char** papszTokens = CSLTokenizeString2(pszHeader, " \n\r\t::", 0 );
int nTokens = CSLCount(papszTokens); int iCST = CSLFindString( papszTokens,"CoordinateSystemType" );
if ( iCST<0 || iCST+1 >= nTokens)
{
CSLDestroy( papszTokens );
CPLDebug( "CNSDTF Grid","Can't find SRS");
return "";
} char *pszCoordinateSystemType =papszTokens[iCST + 1];
if (EQUAL(pszCoordinateSystemType,"C"))
{
CSLDestroy( papszTokens );
CPLDebug( "CNSDTF Grid","Can't find SRS");
return "";
} if ( (!EQUAL(pszCoordinateSystemType,"D")) && (!EQUAL(pszCoordinateSystemType, "P")))
{
CSLDestroy( papszTokens );
CPLDebug( "CNSDTF Grid","Can't find SRS");
return "";
} int iSpheroid = CSLFindString(papszTokens, "Spheroid" );
if ( iSpheroid<0 || iSpheroid+1 >=nTokens)
{
CSLDestroy( papszTokens );
CPLDebug( "CNSDTF Grid","Can't find Spheroid, but the CoordinateSystemType is %s, this file headermaybe is wrong.", pszCoordinateSystemType);
return "";
} char* pszSpheroid = papszTokens[iSpheroid+ 1];
char** papszSpheroidTokens =CSLTokenizeString2( pszSpheroid, ",,", 0 );
int nSpheroidTokens =CSLCount(papszSpheroidTokens);
if(nSpheroidTokens != 3)
{
CSLDestroy( papszSpheroidTokens );
CSLDestroy( papszTokens );
CPLDebug( "CNSDTF Grid","The Spheroid value is %s, maybe is wrong.", pszSpheroid);
return "";
} char *pszPrimeMeridian ="Greenwich";
double dPrimeMeridian = 0.0;
int iPrimeMeridian = CSLFindString(papszTokens, "PrimeMeridian" );
if ( iPrimeMeridian>=0 &&iPrimeMeridian+1 < nTokens)
{
char* pszPrimeMeridianValue =papszTokens[iPrimeMeridian + 1];
if (!EQUAL(pszPrimeMeridian,pszPrimeMeridianValue))
{
char** papszPrimeMeridianTokens= CSLTokenizeString2( pszPrimeMeridianValue, ",,", 0 );
int nPrimeMeridianTokens =CSLCount(papszPrimeMeridianTokens);
if(nPrimeMeridianTokens == 2)
{
pszPrimeMeridian =papszPrimeMeridianTokens[0];
dPrimeMeridian =CPLAtofM(papszPrimeMeridianTokens[1]);
} CSLDestroy(papszPrimeMeridianTokens );
}
} double dSemiMajor =CPLAtofM(papszSpheroidTokens[1]);
double dInvFlattening = CPLAtofM(papszSpheroidTokens[2]);
if (dSemiMajor < 6400) //unit is km
dSemiMajor *= 1000; OGRSpatialReference oSRS;
oSRS.SetGeogCS(papszSpheroidTokens[0],
"unknown",
papszSpheroidTokens[0],
dSemiMajor, dInvFlattening,
pszPrimeMeridian, dPrimeMeridian,
"degree",0.0174532925199433 ); char* pszWkt = NULL; if (EQUAL(pszCoordinateSystemType,"D"))
{
oSRS.exportToWkt( &pszWkt );
CSLDestroy( papszTokens );
return CPLString(pszWkt);
} int iProjection = CSLFindString(papszTokens, "Projection" );
if ( iProjection<0 || iProjection+1>= nTokens)
{
CSLDestroy( papszTokens );
CPLDebug( "CNSDTF Grid","Can't find Projection");
return "";
} char* pszProjection =papszTokens[iProjection+1];
if(EQUAL(pszProjection, "地理坐标系"))
{
oSRS.exportToWkt( &pszWkt );
CSLDestroy( papszTokens );
return CPLString(pszWkt);
} int iProjectionType = CSLFindString(papszProjectionName, pszProjection );
if (iProjectionType<=0)
{
oSRS.exportToWkt( &pszWkt );
CSLDestroy( papszTokens );
return CPLString(pszWkt);
} int iParametersIndex =nProjectionParametersIndex[iProjectionType]; int iParameters = CSLFindString(papszTokens, "Parameters" );
if ( iParameters<0 || iParameters+1>= nTokens)
{
CSLDestroy( papszTokens );
CPLDebug( "CNSDTF Grid","Can't find Projection Parameters");
return "";
} char* pszParameters =papszTokens[iParameters+1];
char** papszParametersTokens =CSLTokenizeString2( pszParameters, ",,", CSLT_ALLOWEMPTYTOKENS);
int nParametersTokens =CSLCount(papszParametersTokens);
if(nParametersTokens != 10)
{
CSLDestroy( papszParametersTokens );
CSLDestroy( papszTokens );
CPLDebug( "CNSDTF Grid","Parse projection parameters error, the count should be 10, but now is%d", nParametersTokens);
return "";
} double dParmeters[10] = {0.0};
for (int i=0; i<10; i++)
dParmeters[i] =CPLAtofM(papszParametersTokens[i]); switch(iProjectionType)
{
case 1: //高斯-克吕格
oSRS.SetTM(0.0, dParmeters[0],dParmeters[5], dParmeters[6], dParmeters[7]);
break;
case 2: //兰勃特正形割圆锥
oSRS.SetLCC(dParmeters[2],dParmeters[3], dParmeters[1], dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 3: //兰勃特正形切圆锥
oSRS.SetLCC(dParmeters[1],dParmeters[1], dParmeters[1], dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 4: //兰勃特等积方位
oSRS.SetLAEA(dParmeters[1],dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 5: //亚尔勃斯等积割圆锥
oSRS.SetACEA(dParmeters[2], dParmeters[3],dParmeters[1], dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 6: //亚尔勃斯等积切圆锥
oSRS.SetACEA(dParmeters[1],dParmeters[1], dParmeters[1], dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 7: //通用横轴墨卡托
{
int dZone =((int)(dParmeters[0]) + 183) / 6;
int bIsNorth = TRUE;
if(dParmeters[7] >=10000000)
bIsNorth = FALSE; oSRS.SetUTM(dZone, bIsNorth);
}
break;
case 8: //墨卡托正轴等角切圆柱
oSRS.SetMercator(0.0, dParmeters[0],dParmeters[5], dParmeters[6], dParmeters[7]);
break;
case 9: //墨卡托正轴等角割圆柱
oSRS.SetMercator(dParmeters[1],dParmeters[0], dParmeters[5], dParmeters[6], dParmeters[7]);
break;
case 10: //波斯托等距切方位
oSRS.SetAE(dParmeters[1],dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 11: //彭纳等积伪圆锥
// dont know which one is match
break;
case 12: //等积正轴切圆柱
oSRS.SetCEA(0.0, dParmeters[0],dParmeters[6], dParmeters[7]);
break;
case 13: //等积正轴割圆柱
oSRS.SetCEA(dParmeters[1],dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 14: //等距正轴切圆锥
oSRS.SetMC(dParmeters[1],dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 15: //等距正轴割圆锥
oSRS.SetEC(dParmeters[2],dParmeters[3], dParmeters[1], dParmeters[0], dParmeters[6], dParmeters[7]);
break;
case 16: //等积斜轴切方位
// dont know which one is match
break;
default:
{
CSLDestroy(papszParametersTokens );
CSLDestroy( papszTokens );
CPLDebug( "CNSDTFGrid", "Can not support this projection %s",papszProjectionName);
return "";
}
} CSLDestroy( papszParametersTokens ); oSRS.exportToWkt( &pszWkt );
CSLDestroy( papszTokens );
return CPLString(pszWkt);
}

接下来关于Dataset相关的所有的都已经实现,剩下就是GDALRasterBand类了。同样,按照官方文档中的说明,首先从GDALRasterBand类中派生一个类CNSDTFRasterBand,下面是该类的定义。

/************************************************************************/
/*==================================================================== */
/* CNSDTFRasterBand */
/*==================================================================== */
/************************************************************************/ classCNSDTFRasterBand : public GDALPamRasterBand
{
friend class CNSDTFDataset; GUIntBig *panLineOffset;
char *pszUnitType;
double dfScale; public: CNSDTFRasterBand( CNSDTFDataset *poDS, intnDataStart);
virtual ~CNSDTFRasterBand(); virtual double GetMinimum( int *pbSuccess);
virtual double GetMaximum( int *pbSuccess);
virtual double GetNoDataValue( int *pbSuccess);
virtual CPLErr SetNoDataValue( doubledfNoData);
virtual const char *GetUnitType();
CPLErr SetUnitType( const char *pszNewValue);
virtual double GetScale( int *pbSuccess =NULL );
CPLErr SetScale( double dfNewScale); virtual CPLErr IReadBlock( int nBlockXOff,int nBlockYOff, void * pImage);
};

接下来就是CNSDTFRasterBand类的具体实现。

/************************************************************************/
/* CNSDTFRasterBand() */
/************************************************************************/ CNSDTFRasterBand::CNSDTFRasterBand(CNSDTFDataset *poDS, int nDataStart ) {
this->poDS = poDS; nBand = 1;
eDataType = poDS->eDataType; nBlockXSize = poDS->nRasterXSize;
nBlockYSize = 1; panLineOffset =
(GUIntBig *) VSICalloc(poDS->nRasterYSize, sizeof(GUIntBig) );
if (panLineOffset == NULL)
{
CPLError(CE_Failure,CPLE_OutOfMemory,
"CNSDTFRasterBand::CNSDTFRasterBand: Out of memory (nRasterYSize = %d)",
poDS->nRasterYSize);
return;
} panLineOffset[0] = nDataStart;
dfScale = poDS->nHZoom;
pszUnitType =CPLStrdup(poDS->osUnitType.c_str());
} /************************************************************************/
/* ~CNSDTFRasterBand() */
/************************************************************************/ CNSDTFRasterBand::~CNSDTFRasterBand() {
CPLFree( panLineOffset );
CPLFree( pszUnitType );
} /************************************************************************/
/* IReadBlock() */
/************************************************************************/ CPLErrCNSDTFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
void* pImage ) {
CNSDTFDataset *poODS = (CNSDTFDataset *)poDS;
int iPixel; if( nBlockYOff < 0 || nBlockYOff >poODS->nRasterYSize - 1
|| nBlockXOff != 0 || panLineOffset== NULL || poODS->fp == NULL )
return CE_Failure; if( panLineOffset[nBlockYOff] == 0 )
{
int iPrevLine; for( iPrevLine = 1; iPrevLine <=nBlockYOff; iPrevLine++ )
if( panLineOffset[iPrevLine] ==0 )
IReadBlock( nBlockXOff,iPrevLine-1, NULL );
} if( panLineOffset[nBlockYOff] == 0 )
return CE_Failure; if( poODS->Seek(panLineOffset[nBlockYOff] ) != 0 )
{
CPLError( CE_Failure, CPLE_FileIO,
"Can't seek to offset %luin input file to read data.",
(long unsignedint)panLineOffset[nBlockYOff] );
return CE_Failure;
} for( iPixel = 0; iPixel <poODS->nRasterXSize; )
{
char szToken[500];
char chNext;
int iTokenChar = 0; /* suck up any pre-white space. */
do {
chNext = poODS->Getc();
} while( isspace( (unsignedchar)chNext ) ); while( chNext != '\0' &&!isspace((unsigned char)chNext) )
{
if( iTokenChar ==sizeof(szToken)-2 )
{
CPLError( CE_Failure,CPLE_FileIO,
"Token too longat scanline %d.",
nBlockYOff );
return CE_Failure;
} szToken[iTokenChar++] = chNext;
chNext = poODS->Getc();
} if( chNext == '\0' &&
(iPixel !=poODS->nRasterXSize - 1 ||
nBlockYOff !=poODS->nRasterYSize - 1) )
{
CPLError( CE_Failure,CPLE_FileIO,
"File short, can'tread line %d.",
nBlockYOff );
return CE_Failure;
} szToken[iTokenChar] = '\0'; if( pImage != NULL )
{
if( eDataType == GDT_Float64 )
((double *)pImage)[iPixel] = CPLAtofM(szToken);
else if( eDataType ==GDT_Float32 )
((float *) pImage)[iPixel]= (float) CPLAtofM(szToken);
else
((GInt32 *)pImage)[iPixel] = (GInt32) atoi(szToken);
} iPixel++;
} if( nBlockYOff < poODS->nRasterYSize- 1 )
panLineOffset[nBlockYOff + 1] =poODS->Tell(); return CE_None;
} /************************************************************************/
/* GetMinimum() */
/************************************************************************/ doubleCNSDTFRasterBand::GetMinimum( int *pbSuccess ) {
CNSDTFDataset *poODS = (CNSDTFDataset *) poDS; if( pbSuccess != NULL )
*pbSuccess = TRUE; return poODS->dfMin;
} /************************************************************************/
/* GetMaximum() */
/************************************************************************/ doubleCNSDTFRasterBand::GetMaximum( int *pbSuccess ) {
CNSDTFDataset *poODS = (CNSDTFDataset *) poDS; if( pbSuccess != NULL )
*pbSuccess = TRUE; return poODS->dfMax;
} /************************************************************************/
/* GetNoDataValue() */
/************************************************************************/ doubleCNSDTFRasterBand::GetNoDataValue( int * pbSuccess ) {
CNSDTFDataset *poODS = (CNSDTFDataset *) poDS; if( pbSuccess )
*pbSuccess = poODS->bNoDataSet; return poODS->dfNoDataValue;
} /************************************************************************/
/* SetNoDataValue() */
/************************************************************************/ CPLErrCNSDTFRasterBand::SetNoDataValue( double dfNoData ) {
CNSDTFDataset *poODS = (CNSDTFDataset *)poDS; poODS->bNoDataSet = TRUE;
poODS->dfNoDataValue = dfNoData; return CE_None;
} /************************************************************************/
/* GetUnitType() */
/************************************************************************/ constchar *CNSDTFRasterBand::GetUnitType() {
if( pszUnitType == NULL )
return "";
else
return pszUnitType;
} /************************************************************************/
/* SetUnitType() */
/************************************************************************/ CPLErrCNSDTFRasterBand::SetUnitType( const char *pszNewValue ) {
CPLFree( pszUnitType ); if( pszNewValue == NULL )
pszUnitType = NULL;
else
pszUnitType = CPLStrdup(pszNewValue); return CE_None;
} /************************************************************************/
/* GetScale() */
/************************************************************************/ doubleCNSDTFRasterBand::GetScale( int *pbSuccess ) {
if( pbSuccess != NULL )
*pbSuccess = TRUE; return dfScale;
} /************************************************************************/
/* SetScale() */
/************************************************************************/ CPLErrCNSDTFRasterBand::SetScale( double dfNewScale ) {
dfScale = dfNewScale;
return CE_None;
}

至此,基本上所有的源码都已经编写完毕,接下来就是将源码加入到GDAL源码中进行编译。首先将上面的代码写成cpp和h文件,也可以写一个cpp。并且在cpp的末尾加上一个函数,用来注册使用,具体代码如下,主要就是对该格式的一些描述,以及是否可以创建,删除等,可以参考其他的驱动来进行修改就可以了。

/************************************************************************/
/* GDALRegister_CNSDTFGrid() */
/************************************************************************/ voidGDALRegister_CNSDTFGrid() {
GDALDriver *poDriver; if( GDALGetDriverByName("CNSDTF-GRD" ) == NULL )
{
poDriver = new GDALDriver(); poDriver->SetDescription("CNSDTF-GRD" );
poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
"China Geospatial DataTransfer Grid Format (.grd)" );
poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
"frmt_cnsdtf.html" );
poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd" );
poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
"Byte UInt16 Int16Int32" ); poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES" );
poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST,
"<CreationOptionList>\n"
" <Option name='FORCE_RASTER'type='boolean' description='Force use of RASTER, default isFALSE(DEM).'/>\n"
" <Option name='DECIMAL_PRECISION'type='int' description='Number of decimal when writing floating-pointnumbers.'/>\n"
"</CreationOptionList>\n"); poDriver->pfnOpen =CNSDTFDataset::Open;
poDriver->pfnIdentify =CNSDTFDataset::Identify;
poDriver->pfnCreateCopy =CNSDTFDataset::CreateCopy; GetGDALDriverManager()->RegisterDriver(poDriver );
}
}

四、        修改GDAL编译文件

上面基本上编写完了所有的代码,下面就需要修改GDAL库中的部分文件,然后编译来使GDAL支持新的文件格式。

1、在frmts文件夹中新建一个cnsdtf的文件夹,将上面的代码放到该文件夹中,并新建三个文件,分别是frmt_cnsdtf.html、makefile.vc 和GNUmakefile。frmt_cnsdtf.html这个文件主要就是对新的文件格式的一个说明,书写方式可以参考其他文件夹中的文件。makefile.vc和GNUmakefile分别对应于windows系统和Linux系统下的编译文件,这里只编译Window版本,所以只编写makefile.vc文件,编辑完的内容如下:

OBJ =   cnsdtfdataset.objcnsdtfsrs.obj

GDAL_ROOT =   ..\..

!INCLUDE$(GDAL_ROOT)\nmake.opt

default: $(OBJ)
xcopy /D /Y *.obj ..\o clean:
-del *.obj

2、修改frmts文件夹中的gdalallregister.cpp文件,在代码中的最后将新的文件驱动进行注册进去,如下(红色的为新增的):

#ifdefFRMT_iris
GDALRegister_IRIS();
#endif #ifdefFRMT_cnsdtf
GDALRegister_CNSDTFGrid(); //红色
#endif

3、修改frmts文件夹中的makefile.vc,在EXTRAFLAGS的最后没添加-DFRMT_cnsdtf,需要与步骤2中的一致。

4、修改gcore文件夹中的gdal_frmts.h文件,在最后添加新驱动注册声明。如下(红色的为新增的):

voidCPL_DLL GDALRegister_IRIS(void);
voidCPL_DLL GDALRegister_CNSDTFGrid(void); //红色

5、修改完上面的文件,然后将GDAL工程清理掉之后重新编译,如果提示有语法错误,请先修改代码中的语法错误,如果没有,正常编译完成的话,就是用gdalinfo工具(或者其他的工具)中的命令行参数—formats(下图1)或者—format CNSDTF-GRD(下图2)来进行查看是否新的驱动已经包含在内。如果输出有CNSDTF的字样,说明新的驱动添加成功。下面我们使用gdalinfo来对真实的数据进行测试。

图1 –formats命令

图2 —format CNSDTF-GRD命令

五、        测试

为了测试我们新添加的驱动是否能够正确读取数据,我们使用gdalinfo工具来进行检验。使用的命令行如下所示:

gdalinfo –checksum --configGDAL_FILENAME_IS_UTF8 NO F:\我的资料\cnsdtf\sample.grd

使用-checksum的原因是为了检验GDAL读取像素值是否正确,--config是为了支持中文路径,如果程序不报错,并且能够输出下面的信息,说明基本上读取是没有问题了。

接下来可以建议创建图像的功能,可以使用gdal_translate工具,将一个其他格式的单波段数据进行转换成CNSDTF格式,然后使用gdalinfo的-checksum命令,如果两个图像转换前后的checksum值计算的相同,那么就说明创建应该是没有问题的。

之后我会将CNSDTF格式的代码申请提交到GDAL的库中,如果GDAL接收的话,那么以后就可以直接支持了,如果没有接收,使用上面的方式自己扩展一下也问题不大。接下来有时间的话会将Create方法进行实现,同时也将矢量格式也扩展到OGR库中。

扩展GDAL,支持CNSDTF格式(一)的更多相关文章

  1. OpenMediaVault的OwnCloud扩展不支持NTFS格式硬盘

    来源https://forum.openmediavault.org/index.php/Thread/15510-OwnCloud-Operation-not-supported-setfacl/ ...

  2. GDAL添加ECW格式支持

    目录 GDAL添加ECW格式支持 ECW 下载ECW JPEG SDK 在Unix平台构建支持ECW的GDAL 二进制ECW SDK和GCC >= 5.1 在Linux上构建的教程 在Windo ...

  3. Call to undefined function imagecreatefromjpeg() 让GD支持JPEG格式的图片扩展

    安装扩展支持jpeg格式: 第一步:首先下载文件: 版本v8: wget http://www.ijg.org/files/jpegsrc.v8b.tar.gz 版本v9: wget http://w ...

  4. 字定义JSON序列化支持datetime格式序列化

    字定义JSON序列化支持datetime格式序列化 由于json.dumps无法处理datetime日期,所以可以通过自定义处理器来做扩展,如: import json from datetime i ...

  5. 配置iis支持.json格式的文件

    配置iis支持.json格式的文件发现要让IIS支持json文件并不是单纯的添加mime这么简单啊,以下是设置方法:一.IIS 6 1. MIME设置:在IIS的站点属性的HTTP头设置里,选MIME ...

  6. html5中audio支持音频格式

    HTML5 Audio标签能够支持wav, mp3, ogg, acc, webm等格式,但有个很重要的音乐文件格式midi(扩展名mid)却在各大浏览器中都没有内置的支持.不是所有的浏览器都支持MP ...

  7. Windows Vista如何让梦幻桌面支持更多格式

    Windows Vista 梦幻桌面(DreamScene)到底能不能支持除了Mpeg/mpg以外的格式? 很多人说梦幻桌面的视频格式有限,像AVI.RM.RMVB就不能做成梦幻桌面!也有很多朋友着急 ...

  8. 问题:iis配置json;结果:如何配置iis支持.json格式的文件

    如何配置iis支持.json格式的文件 | 浏览:1357 | 更新:2015-04-05 11:00 | 标签:软件 1 2 3 4 5 6 7 分步阅读 现在大家在制作HTM5的一些小场景,小游戏 ...

  9. Kindle支持哪些格式

    官方产品介绍页面有相关技术参数: Kindle Format 8 (AZW3), Kindle (AZW), TXT,PDF, MOBI, PRC原格式,HTML,DOC,DOCX,JPEG,GIF, ...

随机推荐

  1. Kafka生产者-向Kafka中写入数据

    (1)生产者概览 (1)不同的应用场景对消息有不同的需求,即是否允许消息丢失.重复.延迟以及吞吐量的要求.不同场景对Kafka生产者的API使用和配置会有直接的影响. 例子1:信用卡事务处理系统,不允 ...

  2. Java 零散笔记

    运算符: 整数被0除将会产生一个异常,而浮点数被0除会得到无穷大或NaN结果. 二元运算符: 如果运算符得到一个值,其类型与左侧操作数的类型不用,就会发生强制类型转换. int x = 0; x += ...

  3. Node.js 子进程

    稳定性: 3 - 稳定 Node 通过 child_process 模块提供了 popen(3) 数据流. 它能在非阻塞的方式中,通过 stdin, stdout, 和 stderr 传递数据. (请 ...

  4. Node.js NPM 使用介绍

    NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从NPM服务器下载并 ...

  5. Go 语言变量

    变量来源于数学,是计算机语言中能储存计算结果或能表示值抽象概念.变量可以通过变量名访问. Go 语言变量名由字母.数字.下划线组成,其中首个字母不能为数字. 声明变量的一般形式是使用 var 关键字: ...

  6. Docker的Fig 项目

    在你的应用里面添加一个 fig.yml 文件,并指定一些简单的内容,执行 fig up 它就能帮你快速建立起一个容器 快速搭建基于 Docker 的隔离开发环境 使用 Dockerfile 文件指定你 ...

  7. Swift基础之CoreData的使用

    以前使用过OC版本的CoreData应该很好理解Swift方式,所以这里简单的展示一下,增删改查的方法使用,同时给大家说一下创建步骤,方便大家的使用,转载请注明出处,谢谢~ 步骤一:创建一个Swift ...

  8. DB查询分析器7.01新增的周、月SQL执行计划功能

                DB查询分析器7.01新增的周.月SQL执行计划功能 马根峰              (广东联合电子服务股份有限公司, 广州 510300) 1      引言   中国本土 ...

  9. Android开发基础规范(二)

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52614696 前言:Androi ...

  10. Android控制软键盘的弹出和隐藏

    弹出软键盘 前提:必须要有一个可以编辑的控件(EditText),并且当前已经获取焦点 /** * 弹出软键盘 */ public void openKeyboard(View view) { // ...