mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 14:15:21 -06:00
850 lines
28 KiB
C++
850 lines
28 KiB
C++
/******************************************************************************
|
|
* $Id: argdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
|
|
*
|
|
* Project: Azavea Raster Grid format driver.
|
|
* Purpose: Implements support for reading and writing Azavea Raster Grid
|
|
* format.
|
|
* Author: David Zwarg <dzwarg@azavea.com>
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2012, David Zwarg <dzwarg@azavea.com>
|
|
* Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "rawdataset.h"
|
|
#include "cpl_string.h"
|
|
#include <json.h>
|
|
#include <ogr_spatialref.h>
|
|
|
|
CPL_CVSID("$Id: argdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
|
|
|
|
#define MAX_FILENAME_LEN 4096
|
|
|
|
#ifndef NAN
|
|
# ifdef HUGE_VAL
|
|
# define NAN (HUGE_VAL * 0.0)
|
|
# else
|
|
|
|
static float CPLNaN(void)
|
|
{
|
|
float fNan;
|
|
int nNan = 0x7FC00000;
|
|
memcpy(&fNan, &nNan, 4);
|
|
return fNan;
|
|
}
|
|
|
|
# define NAN CPLNaN()
|
|
# endif
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* ARGDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class ARGDataset : public RawDataset
|
|
{
|
|
VSILFILE *fpImage; // image data file.
|
|
|
|
double adfGeoTransform[6];
|
|
char * pszFilename;
|
|
|
|
public:
|
|
ARGDataset();
|
|
~ARGDataset();
|
|
|
|
CPLErr GetGeoTransform( double * padfTransform );
|
|
|
|
static int Identify( GDALOpenInfo * );
|
|
static GDALDataset *Open( GDALOpenInfo * );
|
|
static GDALDataset *CreateCopy( const char *, GDALDataset *, int,
|
|
char **, GDALProgressFunc, void *);
|
|
virtual char ** GetFileList(void);
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* ARGDataset() */
|
|
/************************************************************************/
|
|
|
|
ARGDataset::ARGDataset()
|
|
{
|
|
adfGeoTransform[0] = 0.0;
|
|
adfGeoTransform[1] = 1.0;
|
|
adfGeoTransform[2] = 0.0;
|
|
adfGeoTransform[3] = 0.0;
|
|
adfGeoTransform[4] = 0.0;
|
|
adfGeoTransform[5] = 1.0;
|
|
fpImage = NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~ARGDataset() */
|
|
/************************************************************************/
|
|
|
|
ARGDataset::~ARGDataset()
|
|
|
|
{
|
|
CPLFree(pszFilename);
|
|
|
|
FlushCache();
|
|
if( fpImage != NULL )
|
|
VSIFCloseL( fpImage );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr ARGDataset::GetGeoTransform( double * padfTransform )
|
|
|
|
{
|
|
memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetJsonFilename() */
|
|
/************************************************************************/
|
|
CPLString GetJsonFilename(CPLString pszFilename)
|
|
{
|
|
return CPLSPrintf( "%s/%s.json", CPLGetDirname(pszFilename), CPLGetBasename(pszFilename) );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetJsonObject() */
|
|
/************************************************************************/
|
|
json_object * GetJsonObject(CPLString pszFilename)
|
|
{
|
|
json_object * pJSONObject = NULL;
|
|
CPLString osJSONFilename = GetJsonFilename(pszFilename);
|
|
|
|
pJSONObject = json_object_from_file((char *)osJSONFilename.c_str());
|
|
if (pJSONObject == NULL) {
|
|
CPLDebug("ARGDataset", "GetJsonObject(): "
|
|
"Could not parse JSON file.");
|
|
return NULL;
|
|
}
|
|
|
|
return pJSONObject;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetJsonValueStr() */
|
|
/************************************************************************/
|
|
const char * GetJsonValueStr(json_object * pJSONObject, CPLString pszKey)
|
|
{
|
|
json_object * pJSONItem = json_object_object_get(pJSONObject, pszKey.c_str());
|
|
if (pJSONItem == NULL) {
|
|
CPLDebug("ARGDataset", "GetJsonValueStr(): "
|
|
"Could not find '%s' in JSON.", pszKey.c_str());
|
|
return NULL;
|
|
}
|
|
|
|
return json_object_get_string(pJSONItem);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetJsonValueDbl() */
|
|
/************************************************************************/
|
|
double GetJsonValueDbl(json_object * pJSONObject, CPLString pszKey)
|
|
{
|
|
const char *pszJSONStr = GetJsonValueStr(pJSONObject, pszKey.c_str());
|
|
char *pszTmp;
|
|
double fTmp;
|
|
if (pszJSONStr == NULL) {
|
|
return NAN;
|
|
}
|
|
pszTmp = (char *)pszJSONStr;
|
|
fTmp = CPLStrtod(pszJSONStr, &pszTmp);
|
|
if (pszTmp == pszJSONStr) {
|
|
CPLDebug("ARGDataset", "GetJsonValueDbl(): "
|
|
"Key value is not a numeric value: %s:%s", pszKey.c_str(), pszTmp);
|
|
return NAN;
|
|
}
|
|
|
|
return fTmp;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetJsonValueInt() */
|
|
/************************************************************************/
|
|
int GetJsonValueInt(json_object * pJSONObject, CPLString pszKey)
|
|
{
|
|
double fTmp = GetJsonValueDbl(pJSONObject, pszKey.c_str());
|
|
if (CPLIsNan(fTmp)) {
|
|
return -1;
|
|
}
|
|
|
|
return (int)fTmp;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFileList() */
|
|
/************************************************************************/
|
|
char ** ARGDataset::GetFileList()
|
|
{
|
|
char **papszFileList = GDALPamDataset::GetFileList();
|
|
CPLString osJSONFilename = GetJsonFilename(pszFilename);
|
|
|
|
papszFileList = CSLAddString( papszFileList, osJSONFilename );
|
|
|
|
return papszFileList;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Identify() */
|
|
/************************************************************************/
|
|
|
|
int ARGDataset::Identify( GDALOpenInfo *poOpenInfo )
|
|
{
|
|
json_object * pJSONObject;
|
|
if (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "arg")) {
|
|
return FALSE;
|
|
}
|
|
|
|
pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
|
|
if (pJSONObject == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
GDALDataset *ARGDataset::Open( GDALOpenInfo * poOpenInfo )
|
|
{
|
|
json_object * pJSONObject;
|
|
const char * pszJSONStr;
|
|
char * pszLayer;
|
|
/***** items from the json metadata *****/
|
|
GDALDataType eType = GDT_Unknown;
|
|
double fXmin = 0.0;
|
|
double fYmin = 0.0;
|
|
double fXmax = 0.0;
|
|
double fYmax = 0.0;
|
|
double fCellwidth = 1.0;
|
|
double fCellheight = 1.0;
|
|
double fXSkew = 0.0;
|
|
double fYSkew = 0.0;
|
|
int nRows = 0;
|
|
int nCols = 0;
|
|
int nSrs = 3857;
|
|
/***** items from the json metadata *****/
|
|
int nPixelOffset = 0;
|
|
double fNoDataValue = NAN;
|
|
|
|
char * pszWKT = NULL;
|
|
OGRSpatialReference oSRS;
|
|
OGRErr nErr = OGRERR_NONE;
|
|
|
|
if ( !Identify( poOpenInfo ) )
|
|
return NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check metadata settings in JSON. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
|
|
|
|
if (pJSONObject == NULL) {
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Error parsing JSON.");
|
|
return NULL;
|
|
}
|
|
|
|
// get the type (always 'arg')
|
|
pszJSONStr = GetJsonValueStr(pJSONObject, "type");
|
|
if (pszJSONStr == NULL ) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'type' is missing from the JSON file.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
else if (!EQUAL(pszJSONStr, "arg")) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'type' is not recognized: '%s'.", pszJSONStr);
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
// get the datatype
|
|
pszJSONStr = GetJsonValueStr(pJSONObject, "datatype");
|
|
if (pszJSONStr == NULL) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'datatype' is missing from the JSON file.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
else if (EQUAL(pszJSONStr, "int8")) {
|
|
CPLDebug("ARGDataset", "Open(): "
|
|
"int8 data is not supported in GDAL -- mapped to uint8");
|
|
eType = GDT_Byte;
|
|
nPixelOffset = 1;
|
|
fNoDataValue = 128;
|
|
}
|
|
else if (EQUAL(pszJSONStr, "int16")) {
|
|
eType = GDT_Int16;
|
|
nPixelOffset = 2;
|
|
fNoDataValue = -32767;
|
|
}
|
|
else if (EQUAL(pszJSONStr, "int32")) {
|
|
eType = GDT_Int32;
|
|
nPixelOffset = 4;
|
|
fNoDataValue = -2e31;
|
|
}
|
|
else if (EQUAL(pszJSONStr, "uint8")) {
|
|
eType = GDT_Byte;
|
|
nPixelOffset = 1;
|
|
fNoDataValue = 255;
|
|
}
|
|
else if (EQUAL(pszJSONStr, "uint16")) {
|
|
eType = GDT_UInt16;
|
|
nPixelOffset = 2;
|
|
fNoDataValue = 65535;
|
|
}
|
|
else if (EQUAL(pszJSONStr, "uint32")) {
|
|
eType = GDT_UInt32;
|
|
nPixelOffset = 4;
|
|
fNoDataValue = -2e31;
|
|
}
|
|
else if (EQUAL(pszJSONStr, "float32")) {
|
|
eType = GDT_Float32;
|
|
nPixelOffset = 4;
|
|
fNoDataValue = NAN;
|
|
}
|
|
else if (EQUAL(pszJSONStr, "float64")) {
|
|
eType = GDT_Float64;
|
|
nPixelOffset = 8;
|
|
fNoDataValue = NAN;
|
|
}
|
|
else {
|
|
if (EQUAL(pszJSONStr, "int64") ||
|
|
EQUAL(pszJSONStr, "uint64")) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'datatype' is unsupported in GDAL: '%s'.", pszJSONStr);
|
|
}
|
|
else {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'datatype' is unknown: '%s'.", pszJSONStr);
|
|
}
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
// get the xmin of the bounding box
|
|
fXmin = GetJsonValueDbl(pJSONObject, "xmin");
|
|
if (CPLIsNan(fXmin)) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'xmin' is missing or invalid.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
// get the ymin of the bounding box
|
|
fYmin = GetJsonValueDbl(pJSONObject, "ymin");
|
|
if (CPLIsNan(fYmin)) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'ymin' is missing or invalid.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
// get the xmax of the bounding box
|
|
fXmax = GetJsonValueDbl(pJSONObject, "xmax");
|
|
if (CPLIsNan(fXmax)) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'xmax' is missing or invalid.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
// get the ymax of the bounding box
|
|
fYmax = GetJsonValueDbl(pJSONObject, "ymax");
|
|
if (CPLIsNan(fYmax)) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'ymax' is missing or invalid.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
// get the cell width
|
|
fCellwidth = GetJsonValueDbl(pJSONObject, "cellwidth");
|
|
if (CPLIsNan(fCellwidth)) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'cellwidth' is missing or invalid.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
// get the cell height
|
|
fCellheight = GetJsonValueDbl(pJSONObject, "cellheight");
|
|
if (CPLIsNan(fCellheight)) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'cellheight' is missing or invalid.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
fXSkew = GetJsonValueDbl(pJSONObject, "xskew");
|
|
if (CPLIsNan(fXSkew)) {
|
|
// not an error -- default to 0.0
|
|
fXSkew = 0.0f;
|
|
}
|
|
|
|
fYSkew = GetJsonValueDbl(pJSONObject, "yskew");
|
|
if (CPLIsNan(fYSkew)) {
|
|
// not an error -- default to 0.0
|
|
fYSkew = 0.0f;
|
|
}
|
|
|
|
// get the rows
|
|
nRows = GetJsonValueInt(pJSONObject, "rows");
|
|
if (nRows < 0) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'rows' is missing or invalid.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
// get the columns
|
|
nCols = GetJsonValueInt(pJSONObject, "cols");
|
|
if (nCols < 0) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'cols' is missing or invalid.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
nSrs = GetJsonValueInt(pJSONObject, "epsg");
|
|
if (nSrs < 0) {
|
|
// not an error -- default to web mercator
|
|
nSrs = 3857;
|
|
}
|
|
|
|
nErr = oSRS.importFromEPSG(nSrs);
|
|
if (nErr != OGRERR_NONE) {
|
|
nErr = oSRS.importFromEPSG(3857);
|
|
|
|
if (nErr == OGRERR_NONE) {
|
|
CPLDebug("ARGDataset", "Open(): "
|
|
"The EPSG provided did not import cleanly. Defaulting to EPSG:3857");
|
|
}
|
|
else {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The 'epsg' value did not transate to a known spatial reference."
|
|
" Please check the 'epsg' value and try again.");
|
|
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
nErr = oSRS.exportToWkt(&pszWKT);
|
|
if (nErr != OGRERR_NONE) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The spatial reference is known, but could not be set on the "
|
|
"dataset. Please check the 'epsg' value and try again.");
|
|
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// get the layer (always the file basename)
|
|
pszJSONStr = GetJsonValueStr(pJSONObject, "layer");
|
|
if (pszJSONStr == NULL) {
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"The ARG 'layer' is missing from the JSON file.");
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
pszLayer = CPLStrdup(pszJSONStr);
|
|
|
|
// done with the json object now
|
|
json_object_put(pJSONObject);
|
|
pJSONObject = NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create a corresponding GDALDataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
ARGDataset *poDS;
|
|
|
|
poDS = new ARGDataset();
|
|
|
|
poDS->pszFilename = CPLStrdup(poOpenInfo->pszFilename);
|
|
poDS->SetMetadataItem("LAYER",pszLayer,NULL);
|
|
poDS->nRasterXSize = nCols;
|
|
poDS->nRasterYSize = nRows;
|
|
poDS->SetProjection( pszWKT );
|
|
|
|
// done with the projection string
|
|
CPLFree(pszWKT);
|
|
CPLFree(pszLayer);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Assume ownership of the file handled from the GDALOpenInfo. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->fpImage = VSIFOpenL(poOpenInfo->pszFilename, "rb");
|
|
if (poDS->fpImage == NULL)
|
|
{
|
|
delete poDS;
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"Could not open dataset '%s'", poOpenInfo->pszFilename);
|
|
return NULL;
|
|
}
|
|
|
|
poDS->adfGeoTransform[0] = fXmin;
|
|
poDS->adfGeoTransform[1] = fCellwidth;
|
|
poDS->adfGeoTransform[2] = fXSkew;
|
|
poDS->adfGeoTransform[3] = fYmax;
|
|
poDS->adfGeoTransform[4] = fYSkew;
|
|
poDS->adfGeoTransform[5] = -fCellheight;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information objects. */
|
|
/* -------------------------------------------------------------------- */
|
|
RawRasterBand *poBand;
|
|
|
|
#ifdef CPL_LSB
|
|
int bNative = FALSE;
|
|
#else
|
|
int bNative = TRUE;
|
|
#endif
|
|
|
|
poBand = new RawRasterBand( poDS, 1, poDS->fpImage,
|
|
0, nPixelOffset, nPixelOffset * nCols,
|
|
eType, bNative, TRUE );
|
|
poDS->SetBand( 1, poBand );
|
|
|
|
poBand->SetNoDataValue( fNoDataValue );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize any PAM information. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->SetDescription( poOpenInfo->pszFilename );
|
|
poDS->TryLoadXML();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check for overviews. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
|
|
|
|
return( poDS );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreateCopy() */
|
|
/************************************************************************/
|
|
GDALDataset * ARGDataset::CreateCopy( const char * pszFilename,
|
|
GDALDataset * poSrcDS,
|
|
CPL_UNUSED int bStrict,
|
|
CPL_UNUSED char ** papszOptions,
|
|
CPL_UNUSED GDALProgressFunc pfnProgress,
|
|
CPL_UNUSED void * pProgressData )
|
|
{
|
|
int nBands = poSrcDS->GetRasterCount();
|
|
int nXSize = poSrcDS->GetRasterXSize();
|
|
int nYSize = poSrcDS->GetRasterYSize();
|
|
int nXBlockSize, nYBlockSize, nPixelOffset = 0;
|
|
GDALDataType eType;
|
|
CPLString osJSONFilename;
|
|
CPLString pszDataType;
|
|
json_object * poJSONObject = NULL;
|
|
double adfTransform[6];
|
|
GDALRasterBand * poSrcBand = NULL;
|
|
RawRasterBand * poDstBand = NULL;
|
|
VSILFILE * fpImage = NULL;
|
|
void * pabyData;
|
|
OGRSpatialReference oSRS;
|
|
char * pszWKT = NULL;
|
|
char ** pszTokens = NULL;
|
|
const char * pszLayer = NULL;
|
|
int nSrs = 0;
|
|
OGRErr nErr = OGRERR_NONE;
|
|
CPLErr eErr;
|
|
|
|
if( nBands != 1 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"ARG driver doesn't support %d bands. Must be 1 band.", nBands );
|
|
return NULL;
|
|
}
|
|
|
|
eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
|
|
if( eType == GDT_Unknown ||
|
|
eType == GDT_CInt16 ||
|
|
eType == GDT_CInt32 ||
|
|
eType == GDT_CFloat32 ||
|
|
eType == GDT_CFloat64 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"ARG driver doesn't support data type %s.",
|
|
GDALGetDataTypeName(eType) );
|
|
return NULL;
|
|
}
|
|
else if (eType == GDT_Int16) {
|
|
pszDataType = "int16";
|
|
nPixelOffset = 2;
|
|
}
|
|
else if (eType == GDT_Int32) {
|
|
pszDataType = "int32";
|
|
nPixelOffset = 4;
|
|
}
|
|
else if (eType == GDT_Byte) {
|
|
pszDataType = "uint8";
|
|
nPixelOffset = 1;
|
|
}
|
|
else if (eType == GDT_UInt16) {
|
|
pszDataType = "uint16";
|
|
nPixelOffset = 2;
|
|
}
|
|
else if (eType == GDT_UInt32) {
|
|
pszDataType = "uint32";
|
|
nPixelOffset = 4;
|
|
}
|
|
else if (eType == GDT_Float32) {
|
|
pszDataType = "float32";
|
|
nPixelOffset = 4;
|
|
}
|
|
else if (eType == GDT_Float64) {
|
|
pszDataType = "float64";
|
|
nPixelOffset = 8;
|
|
}
|
|
|
|
poSrcDS->GetGeoTransform( adfTransform );
|
|
|
|
pszWKT = (char *)poSrcDS->GetProjectionRef();
|
|
nErr = oSRS.importFromWkt(&pszWKT);
|
|
if (nErr != OGRERR_NONE) {
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"Cannot import spatial reference WKT from source dataset.");
|
|
return NULL;
|
|
}
|
|
|
|
if (oSRS.GetAuthorityCode("PROJCS") != NULL) {
|
|
nSrs = atoi(oSRS.GetAuthorityCode("PROJCS"));
|
|
}
|
|
else if (oSRS.GetAuthorityCode("GEOGCS") != NULL) {
|
|
nSrs = atoi(oSRS.GetAuthorityCode("GEOGCS"));
|
|
}
|
|
else {
|
|
// could not determine projected or geographic code
|
|
// default to EPSG:3857 if no code could be found
|
|
nSrs = 3857;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* Create JSON companion file. */
|
|
/********************************************************************/
|
|
osJSONFilename = GetJsonFilename(pszFilename);
|
|
|
|
poJSONObject = json_object_new_object();
|
|
|
|
pszTokens = poSrcDS->GetMetadata();
|
|
pszLayer = CSLFetchNameValue(pszTokens, "LAYER");
|
|
|
|
if ( pszLayer == NULL) {
|
|
// Set the layer
|
|
json_object_object_add(poJSONObject, "layer", json_object_new_string(
|
|
CPLGetBasename(osJSONFilename)
|
|
));
|
|
}
|
|
else {
|
|
// Set the layer
|
|
json_object_object_add(poJSONObject, "layer", json_object_new_string(
|
|
pszLayer
|
|
));
|
|
}
|
|
|
|
// Set the type
|
|
json_object_object_add(poJSONObject, "type", json_object_new_string("arg"));
|
|
// Set the datatype
|
|
json_object_object_add(poJSONObject, "datatype", json_object_new_string(pszDataType));
|
|
// Set the number of rows
|
|
json_object_object_add(poJSONObject, "rows", json_object_new_int(nYSize));
|
|
// Set the number of columns
|
|
json_object_object_add(poJSONObject, "cols", json_object_new_int(nXSize));
|
|
// Set the xmin
|
|
json_object_object_add(poJSONObject, "xmin", json_object_new_double(adfTransform[0]));
|
|
// Set the ymax
|
|
json_object_object_add(poJSONObject, "ymax", json_object_new_double(adfTransform[3]));
|
|
// Set the cellwidth
|
|
json_object_object_add(poJSONObject, "cellwidth", json_object_new_double(adfTransform[1]));
|
|
// Set the cellheight
|
|
json_object_object_add(poJSONObject, "cellheight", json_object_new_double(-adfTransform[5]));
|
|
// Set the xmax
|
|
json_object_object_add(poJSONObject, "xmax", json_object_new_double(adfTransform[0] + nXSize * adfTransform[1]));
|
|
// Set the ymin
|
|
json_object_object_add(poJSONObject, "ymin", json_object_new_double(adfTransform[3] + nYSize * adfTransform[5]));
|
|
// Set the xskew
|
|
json_object_object_add(poJSONObject, "xskew", json_object_new_double(adfTransform[2]));
|
|
// Set the yskew
|
|
json_object_object_add(poJSONObject, "yskew", json_object_new_double(adfTransform[4]));
|
|
if (nSrs > 0) {
|
|
// Set the epsg
|
|
json_object_object_add(poJSONObject, "epsg", json_object_new_int(nSrs));
|
|
}
|
|
|
|
if (json_object_to_file((char *)osJSONFilename.c_str(), poJSONObject) < 0) {
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"ARG driver can't write companion file.");
|
|
|
|
json_object_put(poJSONObject);
|
|
poJSONObject = NULL;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
json_object_put(poJSONObject);
|
|
poJSONObject = NULL;
|
|
|
|
fpImage = VSIFOpenL(pszFilename, "wb");
|
|
if (fpImage == NULL)
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"ARG driver can't create data file %s.", pszFilename);
|
|
|
|
// remove JSON file
|
|
VSIUnlink( osJSONFilename.c_str() );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// only 1 raster band
|
|
poSrcBand = poSrcDS->GetRasterBand( 1 );
|
|
|
|
#ifdef CPL_LSB
|
|
int bNative = FALSE;
|
|
#else
|
|
int bNative = TRUE;
|
|
#endif
|
|
|
|
poDstBand = new RawRasterBand( fpImage, 0, nPixelOffset,
|
|
nPixelOffset * nXSize, eType, bNative,
|
|
nXSize, nYSize, TRUE, FALSE);
|
|
|
|
poSrcBand->GetBlockSize(&nXBlockSize, &nYBlockSize);
|
|
|
|
pabyData = CPLMalloc(nXBlockSize * nPixelOffset);
|
|
|
|
// convert any blocks into scanlines
|
|
for (int nYBlock = 0; nYBlock * nYBlockSize < nYSize; nYBlock++) {
|
|
for (int nYScanline = 0; nYScanline < nYBlockSize; nYScanline++) {
|
|
if ((nYScanline+1) + nYBlock * nYBlockSize > poSrcBand->GetYSize() ) {
|
|
continue;
|
|
}
|
|
|
|
for (int nXBlock = 0; nXBlock * nXBlockSize < nXSize; nXBlock++) {
|
|
int nXValid;
|
|
|
|
if( (nXBlock+1) * nXBlockSize > poSrcBand->GetXSize() )
|
|
nXValid = poSrcBand->GetXSize() - nXBlock * nXBlockSize;
|
|
else
|
|
nXValid = nXBlockSize;
|
|
|
|
eErr = poSrcBand->RasterIO(GF_Read, nXBlock * nXBlockSize,
|
|
nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize,
|
|
1, eType, 0, 0, NULL);
|
|
|
|
if (eErr != CE_None) {
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Error reading.");
|
|
|
|
CPLFree( pabyData );
|
|
delete poDstBand;
|
|
VSIFCloseL( fpImage );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
eErr = poDstBand->RasterIO(GF_Write, nXBlock * nXBlockSize,
|
|
nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize,
|
|
1, eType, 0, 0, NULL);
|
|
|
|
if (eErr != CE_None) {
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Error writing.");
|
|
|
|
CPLFree( pabyData );
|
|
delete poDstBand;
|
|
VSIFCloseL( fpImage );
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CPLFree( pabyData );
|
|
delete poDstBand;
|
|
VSIFCloseL( fpImage );
|
|
|
|
return (GDALDataset *)GDALOpen( pszFilename, GA_ReadOnly );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALRegister_ARG() */
|
|
/************************************************************************/
|
|
|
|
void GDALRegister_ARG()
|
|
{
|
|
GDALDriver *poDriver;
|
|
|
|
if( GDALGetDriverByName( "ARG" ) == NULL )
|
|
{
|
|
poDriver = new GDALDriver();
|
|
|
|
poDriver->SetDescription( "ARG" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
|
|
"Azavea Raster Grid format" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
|
|
"frmt_various.html#ARG" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
|
|
|
|
poDriver->pfnIdentify = ARGDataset::Identify;
|
|
poDriver->pfnOpen = ARGDataset::Open;
|
|
poDriver->pfnCreateCopy = ARGDataset::CreateCopy;
|
|
|
|
GetGDALDriverManager()->RegisterDriver( poDriver );
|
|
}
|
|
}
|