扩展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. JS中的DOM— —节点以及操作

    DOM操作在JS中可以说是非常常见了吧,很多网页的小功能的实现,比如一些元素的增删操作等都可以用JS来实现.那么在DOM中我们需要知道些什么才能完成一些功能的实现呢?今天这篇文章就先简单的带大家入一下 ...

  2. PHP 5 Array 函数

    PHP Array 简介 PHP Array 函数允许您访问并操作数组. 支持简单的数组和多维数组. 安装 PHP Array 函数是 PHP 核心的组成部分.无需安装即可使用这些函数. PHP 5 ...

  3. JavaScript 代码规范

    所有的 JavaScript 项目适用同一种规范. JavaScript 代码规范 代码规范通常包括以下几个方面: 变量和函数的命名规则 空格,缩进,注释的使用规则. 其他常用规范-- 规范的代码可以 ...

  4. 准备在CSDN知识库建立一个Ext JS的知识库

    CSDN近期正在建立一个知识库,目标是打造身边的技术百科全书 ,我觉得这创意挺好,就像stackoverflow一样,常见的问题在里面基本都有了,只要通过搜索就能找到所需的答案. 现在,大家对于Ext ...

  5. 预处理指令--C语言

    ANSI标准C还定义了如下几个宏: __LINE__ 表示正在编译的文件的行号 __FILE__ 表示正在编译的文件的名字 __DATE__ 表示编译时刻的日期字符串,例如:"25 Dec ...

  6. OBJ文件格式分析工具: objdump, nm,ar

    首先简要阐述关于gcc.glibc和 binutils模块之间的关系 一.关于gcc.glibc和binutils模块之间的关系 1.gcc(gnu collect compiler)是一组编译工具的 ...

  7. Scheme call/cc 研究

    目前尚不清楚实质,但已经能够从形式上理解它的某些好处,有个很简单的连乘函数可以说明: 为了展示究竟发生了什么,我包装了下乘法函数,将其变为mul. 我们将比较product和xproduct的区别. ...

  8. JAVA对象及属性的内存堆栈管理(通过小程序简单说明)

    JAVA在执行过程中会划分4个内存区域(heap.stack.data segment.code segment)代码区(codesegment):java开始执行会把代码加载到code segmen ...

  9. EBS开发常用编译命令

    一.编译FORM 1.将脚本写成shell脚本 cd $AU_TOP/forms/ZHS export FORMS_PATH=.:$FORMS_PATH:$AU_TOP/forms/ZHS frmcm ...

  10. 02_c3p0之c3p0-config.xml配置案例,操作c3p0的jdbcUtil工具类的编写

     c3p0也是一个开源jdbc连接池,我们熟悉的Hibernate和Spring框架使用的都是该数据源. 这里获得数据源使用的方法是:ComboPooledDataSource 它提供的构造方法有 ...