mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-26 06:12:49 -06:00
489 lines
18 KiB
C++
489 lines
18 KiB
C++
/*
|
|
* $Id: keacopy.cpp 28437 2015-02-07 15:50:57Z rouault $
|
|
* keacopy.cpp
|
|
*
|
|
* Created by Pete Bunting on 01/08/2012.
|
|
* Copyright 2012 LibKEA. All rights reserved.
|
|
*
|
|
* This file is part of LibKEA.
|
|
*
|
|
* 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 <cmath>
|
|
#include "gdal_priv.h"
|
|
#include "gdal_rat.h"
|
|
#include "libkea/KEAImageIO.h"
|
|
#include "libkea/KEAAttributeTable.h"
|
|
#include "libkea/KEAAttributeTableInMem.h"
|
|
|
|
// Support functions for CreateCopy()
|
|
|
|
// Copies GDAL Band to KEA Band if nOverview == -1
|
|
// Otherwise it is assumed we are writing to the specified overview
|
|
static
|
|
bool KEACopyRasterData( GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand, int nOverview, int nTotalBands, GDALProgressFunc pfnProgress, void *pProgressData)
|
|
{
|
|
// get some info
|
|
kealib::KEADataType eKeaType = pImageIO->getImageBandDataType(nBand);
|
|
unsigned int nBlockSize;
|
|
if( nOverview == -1 )
|
|
nBlockSize = pImageIO->getImageBlockSize( nBand );
|
|
else
|
|
nBlockSize = pImageIO->getOverviewBlockSize(nBand, nOverview);
|
|
|
|
GDALDataType eGDALType = pBand->GetRasterDataType();
|
|
unsigned int nXSize = pBand->GetXSize();
|
|
unsigned int nYSize = pBand->GetYSize();
|
|
|
|
// allocate some space
|
|
int nPixelSize = GDALGetDataTypeSize( eGDALType ) / 8;
|
|
void *pData = VSIMalloc3( nPixelSize, nBlockSize, nBlockSize);
|
|
if( pData == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined, "Unable to allocate memory" );
|
|
return false;
|
|
}
|
|
// for progress
|
|
int nTotalBlocks = std::ceil( (double)nXSize / (double)nBlockSize ) * std::ceil( (double)nYSize / (double)nBlockSize );
|
|
int nBlocksComplete = 0;
|
|
double dLastFraction = -1;
|
|
// go through the image
|
|
for( unsigned int nY = 0; nY < nYSize; nY += nBlockSize )
|
|
{
|
|
// adjust for edge blocks
|
|
unsigned int nysize = nBlockSize;
|
|
unsigned int nytotalsize = nY + nBlockSize;
|
|
if( nytotalsize > nYSize )
|
|
nysize -= (nytotalsize - nYSize);
|
|
for( unsigned int nX = 0; nX < nXSize; nX += nBlockSize )
|
|
{
|
|
// adjust for edge blocks
|
|
unsigned int nxsize = nBlockSize;
|
|
unsigned int nxtotalsize = nX + nBlockSize;
|
|
if( nxtotalsize > nXSize )
|
|
nxsize -= (nxtotalsize - nXSize);
|
|
|
|
// read in from GDAL
|
|
if( pBand->RasterIO( GF_Read, nX, nY, nxsize, nysize, pData, nxsize, nysize, eGDALType, nPixelSize, nPixelSize * nBlockSize, NULL) != CE_None )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined, "Unable to read blcok at %d %d\n", nX, nY );
|
|
return false;
|
|
}
|
|
// write out to KEA
|
|
if( nOverview == -1 )
|
|
pImageIO->writeImageBlock2Band( nBand, pData, nX, nY, nxsize, nysize, nBlockSize, nBlockSize, eKeaType);
|
|
else
|
|
pImageIO->writeToOverview( nBand, nOverview, pData, nX, nY, nxsize, nysize, nBlockSize, nBlockSize, eKeaType);
|
|
|
|
// progress
|
|
nBlocksComplete++;
|
|
if( nOverview == -1 )
|
|
{
|
|
double dFraction = (((double)nBlocksComplete / (double)nTotalBlocks) / (double)nTotalBands) + ((double)(nBand-1) * (1.0 / (double)nTotalBands));
|
|
if( dFraction != dLastFraction )
|
|
{
|
|
if( !pfnProgress( dFraction, NULL, pProgressData ) )
|
|
{
|
|
CPLFree( pData );
|
|
return false;
|
|
}
|
|
dLastFraction = dFraction;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CPLFree( pData );
|
|
return true;
|
|
}
|
|
|
|
static const int RAT_CHUNKSIZE = 1000;
|
|
// copies the raster attribute table
|
|
static void KEACopyRAT(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand)
|
|
{
|
|
const GDALRasterAttributeTable *gdalAtt = pBand->GetDefaultRAT();
|
|
if((gdalAtt != NULL) && (gdalAtt->GetRowCount() > 0))
|
|
{
|
|
// some operations depend on whether the input dataset is HFA
|
|
int bInputHFA = pBand->GetDataset()->GetDriver() != NULL &&
|
|
EQUAL(pBand->GetDataset()->GetDriver()->GetDescription(), "HFA");
|
|
|
|
kealib::KEAAttributeTable *keaAtt = pImageIO->getAttributeTable(kealib::kea_att_file, nBand);
|
|
|
|
/*bool redDef = false;
|
|
int redIdx = -1;
|
|
bool greenDef = false;
|
|
int greenIdx = -1;
|
|
bool blueDef = false;
|
|
int blueIdx = -1;
|
|
bool alphaDef = false;
|
|
int alphaIdx = -1;*/
|
|
|
|
int numCols = gdalAtt->GetColumnCount();
|
|
std::vector<kealib::KEAATTField*> *fields = new std::vector<kealib::KEAATTField*>();
|
|
kealib::KEAATTField *field;
|
|
for(int ni = 0; ni < numCols; ++ni)
|
|
{
|
|
field = new kealib::KEAATTField();
|
|
field->name = gdalAtt->GetNameOfCol(ni);
|
|
|
|
field->dataType = kealib::kea_att_string;
|
|
switch(gdalAtt->GetTypeOfCol(ni))
|
|
{
|
|
case GFT_Integer:
|
|
field->dataType = kealib::kea_att_int;
|
|
break;
|
|
case GFT_Real:
|
|
field->dataType = kealib::kea_att_float;
|
|
break;
|
|
case GFT_String:
|
|
field->dataType = kealib::kea_att_string;
|
|
break;
|
|
default:
|
|
// leave as "kea_att_string"
|
|
break;
|
|
}
|
|
|
|
if(bInputHFA && (field->name == "Histogram"))
|
|
{
|
|
field->usage = "PixelCount";
|
|
field->dataType = kealib::kea_att_int;
|
|
}
|
|
else if(bInputHFA && (field->name == "Opacity"))
|
|
{
|
|
field->name = "Alpha";
|
|
field->usage = "Alpha";
|
|
field->dataType = kealib::kea_att_int;
|
|
/*alphaDef = true;
|
|
alphaIdx = ni;*/
|
|
}
|
|
else
|
|
{
|
|
field->usage = "Generic";
|
|
switch(gdalAtt->GetUsageOfCol(ni))
|
|
{
|
|
case GFU_PixelCount:
|
|
field->usage = "PixelCount";
|
|
break;
|
|
case GFU_Name:
|
|
field->usage = "Name";
|
|
break;
|
|
case GFU_Red:
|
|
field->usage = "Red";
|
|
if( bInputHFA )
|
|
{
|
|
field->dataType = kealib::kea_att_int;
|
|
/*redDef = true;
|
|
redIdx = ni;*/
|
|
}
|
|
break;
|
|
case GFU_Green:
|
|
field->usage = "Green";
|
|
if( bInputHFA )
|
|
{
|
|
field->dataType = kealib::kea_att_int;
|
|
/*greenDef = true;
|
|
greenIdx = ni;*/
|
|
}
|
|
break;
|
|
case GFU_Blue:
|
|
field->usage = "Blue";
|
|
if( bInputHFA )
|
|
{
|
|
field->dataType = kealib::kea_att_int;
|
|
/*blueDef = true;
|
|
blueIdx = ni;*/
|
|
}
|
|
break;
|
|
case GFU_Alpha:
|
|
field->usage = "Alpha";
|
|
break;
|
|
default:
|
|
// leave as "Generic"
|
|
break;
|
|
}
|
|
}
|
|
|
|
fields->push_back(field);
|
|
}
|
|
|
|
keaAtt->addFields(fields); // This function will populate the field indexs used within the KEA RAT.
|
|
|
|
int numRows = gdalAtt->GetRowCount();
|
|
keaAtt->addRows(numRows);
|
|
|
|
int *pnIntBuffer = new int[RAT_CHUNKSIZE];
|
|
int64_t *pnInt64Buffer = new int64_t[RAT_CHUNKSIZE];
|
|
double *pfDoubleBuffer = new double[RAT_CHUNKSIZE];
|
|
for(int ni = 0; ni < numRows; ni += RAT_CHUNKSIZE )
|
|
{
|
|
int nLength = RAT_CHUNKSIZE;
|
|
if( ( ni + nLength ) > numRows )
|
|
{
|
|
nLength = numRows - ni;
|
|
}
|
|
for(int nj = 0; nj < numCols; ++nj)
|
|
{
|
|
field = fields->at(nj);
|
|
|
|
switch(field->dataType)
|
|
{
|
|
case kealib::kea_att_int:
|
|
((GDALRasterAttributeTable*)gdalAtt)->ValuesIO(GF_Read, nj, ni, nLength, pnIntBuffer);
|
|
for( int i = 0; i < nLength; i++ )
|
|
{
|
|
pnInt64Buffer[i] = pnIntBuffer[i];
|
|
}
|
|
keaAtt->setIntFields(ni, nLength, field->idx, pnInt64Buffer);
|
|
break;
|
|
case kealib::kea_att_float:
|
|
((GDALRasterAttributeTable*)gdalAtt)->ValuesIO(GF_Read, nj, ni, nLength, pfDoubleBuffer);
|
|
keaAtt->setFloatFields(ni, nLength, field->idx, pfDoubleBuffer);
|
|
break;
|
|
case kealib::kea_att_string:
|
|
{
|
|
char **papszColData = (char**)VSIMalloc2(nLength, sizeof(char*));
|
|
((GDALRasterAttributeTable*)gdalAtt)->ValuesIO(GF_Read, nj, ni, nLength, papszColData);
|
|
|
|
std::vector<std::string> aStringBuffer;
|
|
for( int i = 0; i < nLength; i++ )
|
|
{
|
|
aStringBuffer.push_back(papszColData[i]);
|
|
}
|
|
|
|
for( int i = 0; i < nLength; i++ )
|
|
CPLFree(papszColData[i]);
|
|
CPLFree(papszColData);
|
|
|
|
keaAtt->setStringFields(ni, nLength, field->idx, &aStringBuffer);
|
|
}
|
|
break;
|
|
default:
|
|
// Ignore as data type is not known or available from a HFA/GDAL RAT."
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] pnIntBuffer;
|
|
delete[] pnInt64Buffer;
|
|
delete[] pfDoubleBuffer;
|
|
|
|
delete keaAtt;
|
|
for(std::vector<kealib::KEAATTField*>::iterator iterField = fields->begin(); iterField != fields->end(); ++iterField)
|
|
{
|
|
delete *iterField;
|
|
}
|
|
delete fields;
|
|
}
|
|
}
|
|
|
|
// copies the metadata
|
|
// pass nBand == -1 to copy a dataset's metadata
|
|
// or band index to copy a band's metadata
|
|
static void KEACopyMetadata( GDALMajorObject *pObject, kealib::KEAImageIO *pImageIO, int nBand)
|
|
{
|
|
char **ppszMetadata = pObject->GetMetadata();
|
|
if( ppszMetadata != NULL )
|
|
{
|
|
char *pszName;
|
|
const char *pszValue;
|
|
int nCount = 0;
|
|
while( ppszMetadata[nCount] != NULL )
|
|
{
|
|
pszName = NULL;
|
|
pszValue = CPLParseNameValue( ppszMetadata[nCount], &pszName );
|
|
if( pszValue == NULL )
|
|
pszValue = "";
|
|
if( pszName != NULL )
|
|
{
|
|
// it is LAYER_TYPE and a Band? if so handle seperately
|
|
if( ( nBand != -1 ) && EQUAL( pszName, "LAYER_TYPE" ) )
|
|
{
|
|
if( EQUAL( pszValue, "athematic" ) )
|
|
{
|
|
pImageIO->setImageBandLayerType(nBand, kealib::kea_continuous );
|
|
}
|
|
else
|
|
{
|
|
pImageIO->setImageBandLayerType(nBand, kealib::kea_thematic );
|
|
}
|
|
}
|
|
else if( ( nBand != -1 ) && EQUAL( pszName, "STATISTICS_HISTOBINVALUES") )
|
|
{
|
|
// this gets copied accross as part of the attributes
|
|
// so ignore for now
|
|
}
|
|
else
|
|
{
|
|
// write it into the image
|
|
if( nBand != -1 )
|
|
pImageIO->setImageBandMetaData(nBand, pszName, pszValue );
|
|
else
|
|
pImageIO->setImageMetaData(pszName, pszValue );
|
|
}
|
|
CPLFree(pszName);
|
|
}
|
|
nCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// copies the description over
|
|
static void KEACopyDescription(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand)
|
|
{
|
|
const char *pszDesc = pBand->GetDescription();
|
|
pImageIO->setImageBandDescription(nBand, pszDesc);
|
|
}
|
|
|
|
// copies the no data value accross
|
|
static void KEACopyNoData(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand)
|
|
{
|
|
int bSuccess = 0;
|
|
double dNoData = pBand->GetNoDataValue(&bSuccess);
|
|
if( bSuccess )
|
|
{
|
|
pImageIO->setNoDataValue(nBand, &dNoData, kealib::kea_64float);
|
|
}
|
|
}
|
|
|
|
static bool KEACopyBand( GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand, int nTotalbands, GDALProgressFunc pfnProgress, void *pProgressData)
|
|
{
|
|
// first copy the raster data over
|
|
if( !KEACopyRasterData( pBand, pImageIO, nBand, -1, nTotalbands, pfnProgress, pProgressData) )
|
|
return false;
|
|
|
|
// are there any overviews?
|
|
int nOverviews = pBand->GetOverviewCount();
|
|
for( int nOverviewCount = 0; nOverviewCount < nOverviews; nOverviewCount++ )
|
|
{
|
|
GDALRasterBand *pOverview = pBand->GetOverview(nOverviewCount);
|
|
int nOverviewXSize = pOverview->GetXSize();
|
|
int nOverviewYSize = pOverview->GetYSize();
|
|
pImageIO->createOverview( nBand, nOverviewCount + 1, nOverviewXSize, nOverviewYSize);
|
|
if( !KEACopyRasterData( pOverview, pImageIO, nBand, nOverviewCount + 1, nTotalbands, pfnProgress, pProgressData) )
|
|
return false;
|
|
}
|
|
|
|
// now metadata
|
|
KEACopyMetadata(pBand, pImageIO, nBand);
|
|
|
|
// and attributes
|
|
KEACopyRAT(pBand, pImageIO, nBand);
|
|
|
|
// and description
|
|
KEACopyDescription(pBand, pImageIO, nBand);
|
|
|
|
// and no data
|
|
KEACopyNoData(pBand, pImageIO, nBand);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void KEACopySpatialInfo(GDALDataset *pDataset, kealib::KEAImageIO *pImageIO)
|
|
{
|
|
kealib::KEAImageSpatialInfo *pSpatialInfo = pImageIO->getSpatialInfo();
|
|
|
|
double padfTransform[6];
|
|
if( pDataset->GetGeoTransform(padfTransform) == CE_None )
|
|
{
|
|
// convert back from GDAL's array format
|
|
pSpatialInfo->tlX = padfTransform[0];
|
|
pSpatialInfo->xRes = padfTransform[1];
|
|
pSpatialInfo->xRot = padfTransform[2];
|
|
pSpatialInfo->tlY = padfTransform[3];
|
|
pSpatialInfo->yRot = padfTransform[4];
|
|
pSpatialInfo->yRes = padfTransform[5];
|
|
}
|
|
|
|
const char *pszProjection = pDataset->GetProjectionRef();
|
|
pSpatialInfo->wktString = pszProjection;
|
|
|
|
pImageIO->setSpatialInfo( pSpatialInfo );
|
|
}
|
|
|
|
// copies the GCP's accross
|
|
static void KEACopyGCPs(GDALDataset *pDataset, kealib::KEAImageIO *pImageIO)
|
|
{
|
|
int nGCPs = pDataset->GetGCPCount();
|
|
|
|
if( nGCPs > 0 )
|
|
{
|
|
std::vector<kealib::KEAImageGCP*> KEAGCPs;
|
|
const GDAL_GCP *pGDALGCPs = pDataset->GetGCPs();
|
|
|
|
for( int n = 0; n < nGCPs; n++ )
|
|
{
|
|
kealib::KEAImageGCP *pGCP = new kealib::KEAImageGCP;
|
|
pGCP->pszId = pGDALGCPs[n].pszId;
|
|
pGCP->pszInfo = pGDALGCPs[n].pszInfo;
|
|
pGCP->dfGCPPixel = pGDALGCPs[n].dfGCPPixel;
|
|
pGCP->dfGCPLine = pGDALGCPs[n].dfGCPLine;
|
|
pGCP->dfGCPX = pGDALGCPs[n].dfGCPX;
|
|
pGCP->dfGCPY = pGDALGCPs[n].dfGCPY;
|
|
pGCP->dfGCPZ = pGDALGCPs[n].dfGCPZ;
|
|
KEAGCPs.push_back(pGCP);
|
|
}
|
|
|
|
const char *pszGCPProj = pDataset->GetGCPProjection();
|
|
try
|
|
{
|
|
pImageIO->setGCPs(&KEAGCPs, pszGCPProj);
|
|
}
|
|
catch(kealib::KEAException &e)
|
|
{
|
|
}
|
|
|
|
for( std::vector<kealib::KEAImageGCP*>::iterator itr = KEAGCPs.begin(); itr != KEAGCPs.end(); itr++)
|
|
{
|
|
delete (*itr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool KEACopyFile( GDALDataset *pDataset, kealib::KEAImageIO *pImageIO, GDALProgressFunc pfnProgress, void *pProgressData )
|
|
{
|
|
// Main function - copies pDataset to pImageIO
|
|
|
|
// copy accross the spatial info
|
|
KEACopySpatialInfo( pDataset, pImageIO);
|
|
|
|
// dataset metadata
|
|
KEACopyMetadata(pDataset, pImageIO, -1);
|
|
|
|
// GCPs
|
|
KEACopyGCPs(pDataset, pImageIO);
|
|
|
|
// now copy all the bands over
|
|
int nBands = pDataset->GetRasterCount();
|
|
for( int nBand = 0; nBand < nBands; nBand++ )
|
|
{
|
|
GDALRasterBand *pBand = pDataset->GetRasterBand(nBand + 1);
|
|
if( !KEACopyBand( pBand, pImageIO, nBand +1, nBands, pfnProgress, pProgressData ) )
|
|
return false;
|
|
}
|
|
|
|
pfnProgress( 1.0, NULL, pProgressData );
|
|
return true;
|
|
}
|