扩展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. AIX 命令

    1,[ctrl]+h 删除命令 2, set -o emacs后: [ctrl]+p 看上条命令 [ctrl]+n 看下条命令 两次[esc] 自动补全 3, set -o vi 后,可以按照vi编辑 ...

  2. Helm 架构 - 每天5分钟玩转 Docker 容器技术(161)

    在实践之前,我们先来看看 Helm 的架构. Helm 有两个重要的概念:chart 和 release. chart 是创建一个应用的信息集合,包括各种 Kubernetes 对象的配置模板.参数定 ...

  3. PHP MySQL Where 子句

    WHERE 子句 WHERE 子句用于提取满足指定标准的的记录. 语法 SELECT column_name(s) FROM table_name WHERE column_name operator ...

  4. MySQL系列教程(四)

    文件打开数(open_files) 我们现在处理MySQL故障时,发现当Open_files大于open_files_limit值时,MySQL数据库就会发生卡住的现象,导致Nginx服务器打不开相应 ...

  5. 项目分享:通过使用SSH框架的公司-学员关系管理系统(CRM)

    ----------------------------------------------------------------------------------------------[版权申明: ...

  6. 多线程(五) Fork/Join框架介绍及实例讲解

    什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过For ...

  7. 20160220.CCPP体系详解(0030天)

    程序片段(01):对称.c 内容概要:对称 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h ...

  8. 前端CSS技术全解(一)

    一.概述 1)用HTML完成样式工作 哪个标签有哪个属性难以记忆 需求变更影响较大(例如像修改成功法则以下的文字颜色需要修改4个地方) <h1 align="center"& ...

  9. Python动态展现之一

    首先: def f(): print('first') def g(): f() g() def f(): print('second') g() 结果: >>> first sec ...

  10. [Ubuntu] 14.04 关闭桌面

    一直在用Ubuntu的桌面来做调试环境,最近发现桌面会有崩溃的时候,占用资源也比较大,所以想把桌面关闭,只用command界面. 我的系统是Ubuntu14.04 Ctrl+Alt+F1 可以转到命令 ...