mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-25 06:12:47 -06:00
1044 lines
34 KiB
C++
1044 lines
34 KiB
C++
/******************************************************************************
|
|
* $Id: landataset.cpp 28435 2015-02-07 14:35:34Z rouault $
|
|
*
|
|
* Project: eCognition
|
|
* Purpose: Implementation of Erdas .LAN / .GIS format.
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2004, Frank Warmerdam
|
|
* Copyright (c) 2008-2011, 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 "ogr_spatialref.h"
|
|
|
|
CPL_CVSID("$Id: landataset.cpp 28435 2015-02-07 14:35:34Z rouault $");
|
|
|
|
CPL_C_START
|
|
void GDALRegister_LAN(void);
|
|
CPL_C_END
|
|
|
|
/**
|
|
|
|
Erdas Header format: "HEAD74"
|
|
|
|
Offset Size Type Description
|
|
------ ---- ---- -----------
|
|
0 6 char magic cookie / version (ie. HEAD74).
|
|
6 2 Int16 Pixel type, 0=8bit, 1=4bit, 2=16bit
|
|
8 2 Int16 Number of Bands.
|
|
10 6 char Unknown.
|
|
16 4 Int32 Width
|
|
20 4 Int32 Height
|
|
24 4 Int32 X Start (offset in original file?)
|
|
28 4 Int32 Y Start (offset in original file?)
|
|
32 56 char Unknown.
|
|
88 2 Int16 0=LAT, 1=UTM, 2=StatePlane, 3- are projections?
|
|
90 2 Int16 Classes in coverage.
|
|
92 14 char Unknown.
|
|
106 2 Int16 Area Unit (0=none, 1=Acre, 2=Hectare, 3=Other)
|
|
108 4 Float32 Pixel area.
|
|
112 4 Float32 Upper Left corner X (center of pixel?)
|
|
116 4 Float32 Upper Left corner Y (center of pixel?)
|
|
120 4 Float32 Width of a pixel.
|
|
124 4 Float32 Height of a pixel.
|
|
|
|
Erdas Header format: "HEADER"
|
|
|
|
Offset Size Type Description
|
|
------ ---- ---- -----------
|
|
0 6 char magic cookie / version (ie. HEAD74).
|
|
6 2 Int16 Pixel type, 0=8bit, 1=4bit, 2=16bit
|
|
8 2 Int16 Number of Bands.
|
|
10 6 char Unknown.
|
|
16 4 Float32 Width
|
|
20 4 Float32 Height
|
|
24 4 Int32 X Start (offset in original file?)
|
|
28 4 Int32 Y Start (offset in original file?)
|
|
32 56 char Unknown.
|
|
88 2 Int16 0=LAT, 1=UTM, 2=StatePlane, 3- are projections?
|
|
90 2 Int16 Classes in coverage.
|
|
92 14 char Unknown.
|
|
106 2 Int16 Area Unit (0=none, 1=Acre, 2=Hectare, 3=Other)
|
|
108 4 Float32 Pixel area.
|
|
112 4 Float32 Upper Left corner X (center of pixel?)
|
|
116 4 Float32 Upper Left corner Y (center of pixel?)
|
|
120 4 Float32 Width of a pixel.
|
|
124 4 Float32 Height of a pixel.
|
|
|
|
All binary fields are in the same byte order but it may be big endian or
|
|
little endian depending on what platform the file was written on. Usually
|
|
this can be checked against the number of bands though this test won't work
|
|
if there are more than 255 bands.
|
|
|
|
There is also some information on .STA and .TRL files at:
|
|
|
|
http://www.pcigeomatics.com/cgi-bin/pcihlp/ERDASWR%7CTRAILER+FORMAT
|
|
|
|
**/
|
|
|
|
#define ERD_HEADER_SIZE 128
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* LAN4BitRasterBand */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class LANDataset;
|
|
|
|
class LAN4BitRasterBand : public GDALPamRasterBand
|
|
{
|
|
GDALColorTable *poCT;
|
|
GDALColorInterp eInterp;
|
|
|
|
public:
|
|
LAN4BitRasterBand( LANDataset *, int );
|
|
~LAN4BitRasterBand();
|
|
|
|
virtual GDALColorTable *GetColorTable();
|
|
virtual GDALColorInterp GetColorInterpretation();
|
|
virtual CPLErr SetColorTable( GDALColorTable * );
|
|
virtual CPLErr SetColorInterpretation( GDALColorInterp );
|
|
|
|
virtual CPLErr IReadBlock( int, int, void * );
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* LANDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class LANDataset : public RawDataset
|
|
{
|
|
public:
|
|
VSILFILE *fpImage; // image data file.
|
|
|
|
char pachHeader[ERD_HEADER_SIZE];
|
|
|
|
char *pszProjection;
|
|
|
|
double adfGeoTransform[6];
|
|
|
|
CPLString osSTAFilename;
|
|
void CheckForStatistics(void);
|
|
|
|
virtual char **GetFileList();
|
|
|
|
public:
|
|
LANDataset();
|
|
~LANDataset();
|
|
|
|
virtual CPLErr GetGeoTransform( double * padfTransform );
|
|
virtual CPLErr SetGeoTransform( double * padfTransform );
|
|
virtual const char *GetProjectionRef();
|
|
virtual CPLErr SetProjection( const char * );
|
|
|
|
static GDALDataset *Open( GDALOpenInfo * );
|
|
static GDALDataset *Create( const char * pszFilename,
|
|
int nXSize, int nYSize, int nBands,
|
|
GDALDataType eType, char ** papszOptions );
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* LAN4BitRasterBand */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* LAN4BitRasterBand() */
|
|
/************************************************************************/
|
|
|
|
LAN4BitRasterBand::LAN4BitRasterBand( LANDataset *poDS, int nBandIn )
|
|
|
|
{
|
|
this->poDS = poDS;
|
|
this->nBand = nBandIn;
|
|
this->eDataType = GDT_Byte;
|
|
|
|
nBlockXSize = poDS->GetRasterXSize();;
|
|
nBlockYSize = 1;
|
|
|
|
poCT = NULL;
|
|
eInterp = GCI_Undefined;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~LAN4BitRasterBand() */
|
|
/************************************************************************/
|
|
|
|
LAN4BitRasterBand::~LAN4BitRasterBand()
|
|
|
|
{
|
|
if( poCT )
|
|
delete poCT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr LAN4BitRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
|
|
int nBlockYOff,
|
|
void * pImage )
|
|
|
|
{
|
|
LANDataset *poLAN_DS = (LANDataset *) poDS;
|
|
CPLAssert( nBlockXOff == 0 );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Seek to profile. */
|
|
/* -------------------------------------------------------------------- */
|
|
int nOffset;
|
|
|
|
nOffset =
|
|
ERD_HEADER_SIZE
|
|
+ (nBlockYOff * nRasterXSize * poLAN_DS->GetRasterCount()) / 2
|
|
+ ((nBand - 1) * nRasterXSize) / 2;
|
|
|
|
if( VSIFSeekL( poLAN_DS->fpImage, nOffset, SEEK_SET ) != 0 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"LAN Seek failed:%s", VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read the profile. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( VSIFReadL( pImage, 1, nRasterXSize/2, poLAN_DS->fpImage ) !=
|
|
(size_t) nRasterXSize / 2 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"LAN Read failed:%s", VSIStrerror( errno ) );
|
|
return CE_Failure;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Convert 4bit to 8bit. */
|
|
/* -------------------------------------------------------------------- */
|
|
int i;
|
|
|
|
for( i = nRasterXSize-1; i >= 0; i-- )
|
|
{
|
|
if( (i & 0x01) != 0 )
|
|
((GByte *) pImage)[i] = ((GByte *) pImage)[i/2] & 0x0f;
|
|
else
|
|
((GByte *) pImage)[i] = (((GByte *) pImage)[i/2] & 0xf0)/16;
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetColorTable() */
|
|
/************************************************************************/
|
|
|
|
CPLErr LAN4BitRasterBand::SetColorTable( GDALColorTable *poNewCT )
|
|
|
|
{
|
|
if( poCT )
|
|
delete poCT;
|
|
if( poNewCT == NULL )
|
|
poCT = NULL;
|
|
else
|
|
poCT = poNewCT->Clone();
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorTable() */
|
|
/************************************************************************/
|
|
|
|
GDALColorTable *LAN4BitRasterBand::GetColorTable()
|
|
|
|
{
|
|
if( poCT != NULL )
|
|
return poCT;
|
|
else
|
|
return GDALPamRasterBand::GetColorTable();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetColorInterpretation() */
|
|
/************************************************************************/
|
|
|
|
CPLErr LAN4BitRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
|
|
|
|
{
|
|
eInterp = eNewInterp;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorInterpretation() */
|
|
/************************************************************************/
|
|
|
|
GDALColorInterp LAN4BitRasterBand::GetColorInterpretation()
|
|
|
|
{
|
|
return eInterp;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* LANDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* LANDataset() */
|
|
/************************************************************************/
|
|
|
|
LANDataset::LANDataset()
|
|
{
|
|
fpImage = NULL;
|
|
pszProjection = NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~LANDataset() */
|
|
/************************************************************************/
|
|
|
|
LANDataset::~LANDataset()
|
|
|
|
{
|
|
FlushCache();
|
|
|
|
if( fpImage != NULL )
|
|
VSIFCloseL( fpImage );
|
|
|
|
CPLFree( pszProjection );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *LANDataset::Open( GDALOpenInfo * poOpenInfo )
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* We assume the user is pointing to the header (.pcb) file. */
|
|
/* Does this appear to be a pcb file? */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poOpenInfo->nHeaderBytes < ERD_HEADER_SIZE )
|
|
return NULL;
|
|
|
|
if( !EQUALN((const char *)poOpenInfo->pabyHeader,"HEADER",6)
|
|
&& !EQUALN((const char *)poOpenInfo->pabyHeader,"HEAD74",6) )
|
|
return NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create a corresponding GDALDataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
LANDataset *poDS;
|
|
|
|
poDS = new LANDataset();
|
|
|
|
poDS->eAccess = poOpenInfo->eAccess;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Adopt the openinfo file pointer for use with this file. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poOpenInfo->eAccess == GA_ReadOnly )
|
|
poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
|
|
else
|
|
poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb+" );
|
|
|
|
if( poDS->fpImage == NULL )
|
|
return NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Do we need to byte swap the headers to local machine order? */
|
|
/* -------------------------------------------------------------------- */
|
|
int bBigEndian = poOpenInfo->pabyHeader[8] == 0;
|
|
int bNeedSwap;
|
|
|
|
memcpy( poDS->pachHeader, poOpenInfo->pabyHeader, ERD_HEADER_SIZE );
|
|
|
|
#ifdef CPL_LSB
|
|
bNeedSwap = bBigEndian;
|
|
#else
|
|
bNeedSwap = !bBigEndian;
|
|
#endif
|
|
|
|
if( bNeedSwap )
|
|
{
|
|
CPL_SWAP16PTR( poDS->pachHeader + 6 );
|
|
CPL_SWAP16PTR( poDS->pachHeader + 8 );
|
|
|
|
CPL_SWAP32PTR( poDS->pachHeader + 16 );
|
|
CPL_SWAP32PTR( poDS->pachHeader + 20 );
|
|
CPL_SWAP32PTR( poDS->pachHeader + 24 );
|
|
CPL_SWAP32PTR( poDS->pachHeader + 28 );
|
|
|
|
CPL_SWAP16PTR( poDS->pachHeader + 88 );
|
|
CPL_SWAP16PTR( poDS->pachHeader + 90 );
|
|
|
|
CPL_SWAP16PTR( poDS->pachHeader + 106 );
|
|
CPL_SWAP32PTR( poDS->pachHeader + 108 );
|
|
CPL_SWAP32PTR( poDS->pachHeader + 112 );
|
|
CPL_SWAP32PTR( poDS->pachHeader + 116 );
|
|
CPL_SWAP32PTR( poDS->pachHeader + 120 );
|
|
CPL_SWAP32PTR( poDS->pachHeader + 124 );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Capture some information from the file that is of interest. */
|
|
/* -------------------------------------------------------------------- */
|
|
int nBandCount, nPixelOffset;
|
|
GDALDataType eDataType;
|
|
|
|
if( EQUALN(poDS->pachHeader,"HEADER",7) )
|
|
{
|
|
float fTmp;
|
|
memcpy(&fTmp, poDS->pachHeader + 16, 4);
|
|
CPL_LSBPTR32(&fTmp);
|
|
poDS->nRasterXSize = (int) fTmp;
|
|
memcpy(&fTmp, poDS->pachHeader + 20, 4);
|
|
CPL_LSBPTR32(&fTmp);
|
|
poDS->nRasterYSize = (int) fTmp;
|
|
}
|
|
else
|
|
{
|
|
GInt32 nTmp;
|
|
memcpy(&nTmp, poDS->pachHeader + 16, 4);
|
|
CPL_LSBPTR32(&nTmp);
|
|
poDS->nRasterXSize = nTmp;
|
|
memcpy(&nTmp, poDS->pachHeader + 20, 4);
|
|
CPL_LSBPTR32(&nTmp);
|
|
poDS->nRasterYSize = nTmp;
|
|
}
|
|
|
|
GInt16 nTmp16;
|
|
memcpy(&nTmp16, poDS->pachHeader + 6, 2);
|
|
CPL_LSBPTR16(&nTmp16);
|
|
|
|
if( nTmp16 == 0 )
|
|
{
|
|
eDataType = GDT_Byte;
|
|
nPixelOffset = 1;
|
|
}
|
|
else if( nTmp16 == 1 ) /* 4bit! */
|
|
{
|
|
eDataType = GDT_Byte;
|
|
nPixelOffset = -1;
|
|
}
|
|
else if( nTmp16 == 2 )
|
|
{
|
|
nPixelOffset = 2;
|
|
eDataType = GDT_Int16;
|
|
}
|
|
else
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Unsupported pixel type (%d).",
|
|
nTmp16 );
|
|
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(&nTmp16, poDS->pachHeader + 8, 2);
|
|
CPL_LSBPTR16(&nTmp16);
|
|
nBandCount = nTmp16;
|
|
|
|
if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
|
|
!GDALCheckBandCount(nBandCount, FALSE))
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information object. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( int iBand = 1; iBand <= nBandCount; iBand++ )
|
|
{
|
|
if( nPixelOffset == -1 ) /* 4 bit case */
|
|
poDS->SetBand( iBand,
|
|
new LAN4BitRasterBand( poDS, iBand ) );
|
|
else
|
|
poDS->SetBand(
|
|
iBand,
|
|
new RawRasterBand( poDS, iBand, poDS->fpImage,
|
|
ERD_HEADER_SIZE + (iBand-1)
|
|
* nPixelOffset * poDS->nRasterXSize,
|
|
nPixelOffset,
|
|
poDS->nRasterXSize*nPixelOffset*nBandCount,
|
|
eDataType, !bNeedSwap, TRUE ));
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize any PAM information. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->SetDescription( poOpenInfo->pszFilename );
|
|
poDS->CheckForStatistics();
|
|
poDS->TryLoadXML();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check for overviews. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try to interprete georeferencing. */
|
|
/* -------------------------------------------------------------------- */
|
|
float fTmp;
|
|
|
|
memcpy(&fTmp, poDS->pachHeader + 112, 4);
|
|
CPL_LSBPTR32(&fTmp);
|
|
poDS->adfGeoTransform[0] = fTmp;
|
|
memcpy(&fTmp, poDS->pachHeader + 120, 4);
|
|
CPL_LSBPTR32(&fTmp);
|
|
poDS->adfGeoTransform[1] = fTmp;
|
|
poDS->adfGeoTransform[2] = 0.0;
|
|
memcpy(&fTmp, poDS->pachHeader + 116, 4);
|
|
CPL_LSBPTR32(&fTmp);
|
|
poDS->adfGeoTransform[3] = fTmp;
|
|
poDS->adfGeoTransform[4] = 0.0;
|
|
memcpy(&fTmp, poDS->pachHeader + 124, 4);
|
|
CPL_LSBPTR32(&fTmp);
|
|
poDS->adfGeoTransform[5] = - fTmp;
|
|
|
|
// adjust for center of pixel vs. top left corner of pixel.
|
|
poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5;
|
|
poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If we didn't get any georeferencing, try for a worldfile. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poDS->adfGeoTransform[1] == 0.0
|
|
|| poDS->adfGeoTransform[5] == 0.0 )
|
|
{
|
|
if( !GDALReadWorldFile( poOpenInfo->pszFilename, NULL,
|
|
poDS->adfGeoTransform ) )
|
|
GDALReadWorldFile( poOpenInfo->pszFilename, ".wld",
|
|
poDS->adfGeoTransform );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try to come up with something for the coordinate system. */
|
|
/* -------------------------------------------------------------------- */
|
|
memcpy(&nTmp16, poDS->pachHeader + 88, 2);
|
|
CPL_LSBPTR16(&nTmp16);
|
|
int nCoordSys = nTmp16;
|
|
|
|
if( nCoordSys == 0 )
|
|
{
|
|
poDS->pszProjection = CPLStrdup(SRS_WKT_WGS84);
|
|
|
|
}
|
|
else if( nCoordSys == 1 )
|
|
{
|
|
poDS->pszProjection =
|
|
CPLStrdup("LOCAL_CS[\"UTM - Zone Unknown\",UNIT[\"Meter\",1]]");
|
|
}
|
|
else if( nCoordSys == 2 )
|
|
{
|
|
poDS->pszProjection = CPLStrdup("LOCAL_CS[\"State Plane - Zone Unknown\",UNIT[\"US survey foot\",0.3048006096012192]]");
|
|
}
|
|
else
|
|
{
|
|
poDS->pszProjection =
|
|
CPLStrdup("LOCAL_CS[\"Unknown\",UNIT[\"Meter\",1]]");
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check for a trailer file with a colormap in it. */
|
|
/* -------------------------------------------------------------------- */
|
|
char *pszPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
|
|
char *pszBasename = CPLStrdup(CPLGetBasename(poOpenInfo->pszFilename));
|
|
const char *pszTRLFilename =
|
|
CPLFormCIFilename( pszPath, pszBasename, "trl" );
|
|
VSILFILE *fpTRL;
|
|
|
|
fpTRL = VSIFOpenL( pszTRLFilename, "rb" );
|
|
if( fpTRL != NULL )
|
|
{
|
|
char szTRLData[896];
|
|
int iColor;
|
|
GDALColorTable *poCT;
|
|
|
|
VSIFReadL( szTRLData, 1, 896, fpTRL );
|
|
VSIFCloseL( fpTRL );
|
|
|
|
poCT = new GDALColorTable();
|
|
for( iColor = 0; iColor < 256; iColor++ )
|
|
{
|
|
GDALColorEntry sEntry;
|
|
|
|
sEntry.c2 = ((GByte *) szTRLData)[iColor+128];
|
|
sEntry.c1 = ((GByte *) szTRLData)[iColor+128+256];
|
|
sEntry.c3 = ((GByte *) szTRLData)[iColor+128+512];
|
|
sEntry.c4 = 255;
|
|
poCT->SetColorEntry( iColor, &sEntry );
|
|
|
|
// only 16 colors in 4bit files.
|
|
if( nPixelOffset == -1 && iColor == 15 )
|
|
break;
|
|
}
|
|
|
|
poDS->GetRasterBand(1)->SetColorTable( poCT );
|
|
poDS->GetRasterBand(1)->SetColorInterpretation( GCI_PaletteIndex );
|
|
|
|
delete poCT;
|
|
}
|
|
|
|
CPLFree( pszPath );
|
|
CPLFree( pszBasename );
|
|
|
|
return( poDS );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr LANDataset::GetGeoTransform( double * padfTransform )
|
|
|
|
{
|
|
if( adfGeoTransform[1] != 0.0 && adfGeoTransform[5] != 0.0 )
|
|
{
|
|
memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
|
|
return CE_None;
|
|
}
|
|
else
|
|
return GDALPamDataset::GetGeoTransform( padfTransform );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr LANDataset::SetGeoTransform( double * padfTransform )
|
|
|
|
{
|
|
unsigned char abyHeader[128];
|
|
|
|
memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
|
|
|
|
VSIFSeekL( fpImage, 0, SEEK_SET );
|
|
VSIFReadL( abyHeader, 128, 1, fpImage );
|
|
|
|
// Upper Left X
|
|
float f32Val;
|
|
|
|
f32Val = (float) (adfGeoTransform[0] + 0.5 * adfGeoTransform[1]);
|
|
memcpy( abyHeader + 112, &f32Val, 4 );
|
|
|
|
// Upper Left Y
|
|
f32Val = (float) (adfGeoTransform[3] + 0.5 * adfGeoTransform[5]);
|
|
memcpy( abyHeader + 116, &f32Val, 4 );
|
|
|
|
// width of pixel
|
|
f32Val = (float) adfGeoTransform[1];
|
|
memcpy( abyHeader + 120, &f32Val, 4 );
|
|
|
|
// height of pixel
|
|
f32Val = (float) fabs(adfGeoTransform[5]);
|
|
memcpy( abyHeader + 124, &f32Val, 4 );
|
|
|
|
if( VSIFSeekL( fpImage, 0, SEEK_SET ) != 0
|
|
|| VSIFWriteL( abyHeader, 128, 1, fpImage ) != 1 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"File IO Error writing header with new geotransform." );
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetProjectionRef() */
|
|
/* */
|
|
/* Use PAM coordinate system if available in preference to the */
|
|
/* generally poor value derived from the file itself. */
|
|
/************************************************************************/
|
|
|
|
const char *LANDataset::GetProjectionRef()
|
|
|
|
{
|
|
const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
|
|
|
|
if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
|
|
return pszProjection;
|
|
else
|
|
return pszPamPrj;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetProjection() */
|
|
/************************************************************************/
|
|
|
|
CPLErr LANDataset::SetProjection( const char * pszWKT )
|
|
|
|
{
|
|
unsigned char abyHeader[128];
|
|
|
|
VSIFSeekL( fpImage, 0, SEEK_SET );
|
|
VSIFReadL( abyHeader, 128, 1, fpImage );
|
|
|
|
OGRSpatialReference oSRS( pszWKT );
|
|
|
|
GUInt16 nProjCode = 0;
|
|
|
|
if( oSRS.IsGeographic() )
|
|
nProjCode = 0;
|
|
|
|
else if( oSRS.GetUTMZone() != 0 )
|
|
nProjCode = 1;
|
|
|
|
// Too bad we have no way of recognising state plane projections.
|
|
|
|
else
|
|
{
|
|
const char *pszProjection = oSRS.GetAttrValue("PROJECTION");
|
|
|
|
if( pszProjection == NULL )
|
|
;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_ALBERS_CONIC_EQUAL_AREA) )
|
|
nProjCode = 3;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP) )
|
|
nProjCode = 4;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_MERCATOR_1SP) )
|
|
nProjCode = 5;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_POLAR_STEREOGRAPHIC) )
|
|
nProjCode = 6;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_POLYCONIC) )
|
|
nProjCode = 7;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_EQUIDISTANT_CONIC) )
|
|
nProjCode = 8;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_TRANSVERSE_MERCATOR) )
|
|
nProjCode = 9;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_STEREOGRAPHIC) )
|
|
nProjCode = 10;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) )
|
|
nProjCode = 11;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_AZIMUTHAL_EQUIDISTANT) )
|
|
nProjCode = 12;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_GNOMONIC) )
|
|
nProjCode = 13;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_ORTHOGRAPHIC) )
|
|
nProjCode = 14;
|
|
// we don't have GVNP.
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_SINUSOIDAL) )
|
|
nProjCode = 16;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_EQUIRECTANGULAR) )
|
|
nProjCode = 17;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_MILLER_CYLINDRICAL) )
|
|
nProjCode = 18;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_VANDERGRINTEN) )
|
|
nProjCode = 19;
|
|
else if( EQUAL(pszProjection,
|
|
SRS_PT_HOTINE_OBLIQUE_MERCATOR) )
|
|
nProjCode = 20;
|
|
}
|
|
|
|
memcpy( abyHeader + 88, &nProjCode, 2 );
|
|
|
|
VSIFSeekL( fpImage, 0, SEEK_SET );
|
|
VSIFWriteL( abyHeader, 128, 1, fpImage );
|
|
|
|
return GDALPamDataset::SetProjection( pszWKT );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFileList() */
|
|
/************************************************************************/
|
|
|
|
char **LANDataset::GetFileList()
|
|
|
|
{
|
|
char **papszFileList = NULL;
|
|
|
|
// Main data file, etc.
|
|
papszFileList = GDALPamDataset::GetFileList();
|
|
|
|
if( strlen(osSTAFilename) > 0 )
|
|
papszFileList = CSLAddString( papszFileList, osSTAFilename );
|
|
|
|
return papszFileList;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CheckForStatistics() */
|
|
/************************************************************************/
|
|
|
|
void LANDataset::CheckForStatistics()
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* Do we have a statistics file? */
|
|
/* -------------------------------------------------------------------- */
|
|
osSTAFilename = CPLResetExtension(GetDescription(),"sta");
|
|
|
|
VSILFILE *fpSTA = VSIFOpenL( osSTAFilename, "r" );
|
|
|
|
if( fpSTA == NULL && VSIIsCaseSensitiveFS(osSTAFilename) )
|
|
{
|
|
osSTAFilename = CPLResetExtension(GetDescription(),"STA");
|
|
fpSTA = VSIFOpenL( osSTAFilename, "r" );
|
|
}
|
|
|
|
if( fpSTA == NULL )
|
|
{
|
|
osSTAFilename = "";
|
|
return;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read it one band at a time. */
|
|
/* -------------------------------------------------------------------- */
|
|
GByte abyBandInfo[1152];
|
|
int iBand;
|
|
|
|
for( iBand = 0; iBand < nBands; iBand++ )
|
|
{
|
|
if( VSIFReadL( abyBandInfo, 1152, 1, fpSTA ) != 1 )
|
|
break;
|
|
|
|
int nBandNumber = abyBandInfo[7];
|
|
GDALRasterBand *poBand = GetRasterBand(nBandNumber);
|
|
if( poBand == NULL )
|
|
break;
|
|
|
|
float fMean, fStdDev;
|
|
GInt16 nMin, nMax;
|
|
|
|
if( poBand->GetRasterDataType() != GDT_Byte )
|
|
{
|
|
memcpy( &nMin, abyBandInfo + 28, 2 );
|
|
memcpy( &nMax, abyBandInfo + 30, 2 );
|
|
CPL_LSBPTR16( &nMin );
|
|
CPL_LSBPTR16( &nMax );
|
|
}
|
|
else
|
|
{
|
|
nMin = abyBandInfo[9];
|
|
nMax = abyBandInfo[8];
|
|
}
|
|
|
|
memcpy( &fMean, abyBandInfo + 12, 4 );
|
|
memcpy( &fStdDev, abyBandInfo + 24, 4 );
|
|
CPL_LSBPTR32( &fMean );
|
|
CPL_LSBPTR32( &fStdDev );
|
|
|
|
poBand->SetStatistics( nMin, nMax, fMean, fStdDev );
|
|
}
|
|
|
|
VSIFCloseL( fpSTA );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Create() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *LANDataset::Create( const char * pszFilename,
|
|
int nXSize,
|
|
int nYSize,
|
|
int nBands,
|
|
GDALDataType eType,
|
|
CPL_UNUSED char ** papszOptions )
|
|
{
|
|
if( eType != GDT_Byte && eType != GDT_Int16 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Attempt to create .GIS file with unsupported data type '%s'.",
|
|
GDALGetDataTypeName( eType ) );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try to create the file. */
|
|
/* -------------------------------------------------------------------- */
|
|
VSILFILE *fp;
|
|
|
|
fp = VSIFOpenL( pszFilename, "wb" );
|
|
|
|
if( fp == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OpenFailed,
|
|
"Attempt to create file `%s' failed.\n",
|
|
pszFilename );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write out the header. */
|
|
/* -------------------------------------------------------------------- */
|
|
unsigned char abyHeader[128];
|
|
GInt16 n16Val;
|
|
GInt32 n32Val;
|
|
|
|
memset( abyHeader, 0, sizeof(abyHeader) );
|
|
|
|
memcpy( abyHeader + 0, "HEAD74", 6 );
|
|
|
|
// Pixel type
|
|
if( eType == GDT_Byte ) // do we want 4bit?
|
|
n16Val = 0;
|
|
else
|
|
n16Val = 2;
|
|
memcpy( abyHeader + 6, &n16Val, 2 );
|
|
|
|
// Number of Bands.
|
|
n16Val = (GInt16) nBands;
|
|
memcpy( abyHeader + 8, &n16Val, 2 );
|
|
|
|
// Unknown (6)
|
|
|
|
// Width
|
|
n32Val = nXSize;
|
|
memcpy( abyHeader + 16, &n32Val, 4 );
|
|
|
|
// Height
|
|
n32Val = nYSize;
|
|
memcpy( abyHeader + 20, &n32Val, 4 );
|
|
|
|
// X Start (4)
|
|
// Y Start (4)
|
|
|
|
// Unknown (56)
|
|
|
|
// Coordinate System
|
|
n16Val = 0;
|
|
memcpy( abyHeader + 88, &n16Val, 2 );
|
|
|
|
// Classes in coverage
|
|
n16Val = 0;
|
|
memcpy( abyHeader + 90, &n16Val, 2 );
|
|
|
|
// Unknown (14)
|
|
|
|
// Area Unit
|
|
n16Val = 0;
|
|
memcpy( abyHeader + 106, &n16Val, 2 );
|
|
|
|
// Pixel Area
|
|
float f32Val;
|
|
|
|
f32Val = 0.0f;
|
|
memcpy( abyHeader + 108, &f32Val, 4 );
|
|
|
|
// Upper Left X
|
|
f32Val = 0.5f;
|
|
memcpy( abyHeader + 112, &f32Val, 4 );
|
|
|
|
// Upper Left Y
|
|
f32Val = (float) (nYSize - 0.5);
|
|
memcpy( abyHeader + 116, &f32Val, 4 );
|
|
|
|
// width of pixel
|
|
f32Val = 1.0f;
|
|
memcpy( abyHeader + 120, &f32Val, 4 );
|
|
|
|
// height of pixel
|
|
f32Val = 1.0f;
|
|
memcpy( abyHeader + 124, &f32Val, 4 );
|
|
|
|
VSIFWriteL( abyHeader, sizeof(abyHeader), 1, fp );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Extend the file to the target size. */
|
|
/* -------------------------------------------------------------------- */
|
|
vsi_l_offset nImageBytes;
|
|
|
|
if( eType != GDT_Byte )
|
|
nImageBytes = nXSize * (vsi_l_offset) nYSize * 2;
|
|
else
|
|
nImageBytes = nXSize * (vsi_l_offset) nYSize;
|
|
|
|
memset( abyHeader, 0, sizeof(abyHeader) );
|
|
|
|
while( nImageBytes > 0 )
|
|
{
|
|
vsi_l_offset nWriteThisTime = MIN(nImageBytes,sizeof(abyHeader));
|
|
|
|
if( VSIFWriteL( abyHeader, 1, (size_t)nWriteThisTime, fp )
|
|
!= nWriteThisTime )
|
|
{
|
|
VSIFCloseL( fp );
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Failed to write whole Istar file." );
|
|
return NULL;
|
|
}
|
|
nImageBytes -= nWriteThisTime;
|
|
}
|
|
|
|
VSIFCloseL( fp );
|
|
|
|
return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALRegister_LAN() */
|
|
/************************************************************************/
|
|
|
|
void GDALRegister_LAN()
|
|
|
|
{
|
|
GDALDriver *poDriver;
|
|
|
|
if( GDALGetDriverByName( "LAN" ) == NULL )
|
|
{
|
|
poDriver = new GDALDriver();
|
|
|
|
poDriver->SetDescription( "LAN" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
|
|
"Erdas .LAN/.GIS" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
|
|
"frmt_various.html#LAN" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
|
|
"Byte Int16" );
|
|
|
|
poDriver->pfnOpen = LANDataset::Open;
|
|
poDriver->pfnCreate = LANDataset::Create;
|
|
|
|
GetGDALDriverManager()->RegisterDriver( poDriver );
|
|
}
|
|
}
|