rasters saveas data type conversion fix

This commit is contained in:
Radim Blazek 2012-09-12 11:34:52 +02:00
parent aa063f67f2
commit c4fa82e23a
9 changed files with 89 additions and 17 deletions

View File

@ -4023,6 +4023,9 @@ void QgisApp::saveAsRasterFile()
}
QProgressDialog pd( 0, tr( "Abort..." ), 0, 0 );
// Show the dialo immediately because cloning pipe can take some time (WCS)
pd.setLabelText( QObject::tr( "Reading raster" ) );
pd.show();
pd.setWindowModality( Qt::WindowModal );
// TODO: show error dialogs

View File

@ -528,6 +528,7 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
virtual QDateTime dataTimestamp() const { return QDateTime(); }
/**Writes into the provider datasource*/
// TODO: add data type (may be defferent from band type)
virtual bool write( void* data, int band, int width, int height, int xOffset, int yOffset )
{
Q_UNUSED( data );

View File

@ -157,11 +157,13 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
QList<QgsRasterInterface::DataType> destDataTypeList;
for ( int bandNo = 1; bandNo <= nBands; bandNo++ )
{
QgsRasterNuller *nuller = pipe->nuller();
bool srcHasNoDataValue = srcProvider->srcHasNoDataValue( bandNo );
bool destHasNoDataValue = false;
double destNoDataValue;
QgsRasterInterface::DataType destDataType = srcProvider->srcDataType( bandNo );
//QgsRasterInterface::DataType destDataType = srcProvider->srcDataType( bandNo );
QgsRasterInterface::DataType destDataType = srcProvider->dataType( bandNo );
if ( srcHasNoDataValue )
{
// If source has no data value, it is used by provider
@ -170,13 +172,12 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
destNoDataValue = srcProvider->noDataValue();
destHasNoDataValue = true;
}
#if 0
else if ( )
else if ( nuller && nuller->noData().size() > 0 )
{
// TODO: see if nuller has user defined aditional values, in that case use one as no data value
// Use one user defined no data value
destNoDataValue = nuller->noData().value( 0 ).min;
destHasNoDataValue = true;
}
#endif
else
{
// Verify if we realy need no data value, i.e.
@ -212,6 +213,8 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
destHasNoDataValue = true;
}
}
if ( nuller ) nuller->setOutputNoData( destNoDataValue );
QgsDebugMsg( QString( "bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( destDataType ).arg( destHasNoDataValue ).arg( destNoDataValue ) );
destDataTypeList.append( destDataType );
destHasNoDataValueList.append( destHasNoDataValue );
@ -282,11 +285,12 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
int iterCols = 0;
int iterRows = 0;
int dataTypeSize = srcProvider->typeSize( srcProvider->srcDataType( 1 ) );
int dataTypeSize = srcProvider->typeSize( srcProvider->dataType( 1 ) ) / 8;
QList<void*> dataList;
for ( int i = 1; i <= nBands; ++i )
{
iter->startRasterRead( i, nCols, nRows, outputExtent );
// TODO: no need to alloc memory, change to readBlock() returning the allocated block
dataList.push_back( VSIMalloc( dataTypeSize * mMaxTileWidth * mMaxTileHeight ) );
// TODO - fix segfault here when using tiles+vrt (reported by Etienne)
destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
@ -347,6 +351,24 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
}
}
// It may happen that internal data type (dataType) is wider than destDataType
QList<void*> destDataList;
for ( int i = 1; i <= nBands; ++i )
{
if ( srcProvider->dataType( i ) == destDataType )
{
destDataList.push_back( dataList[i-1] );
}
else
{
// TODO: this conversion should go to QgsRasterDataProvider::write with additional input data type param
void *destData = QgsRasterInterface::convert( dataList[i-1], srcProvider->srcDataType( i ), destDataType, iterCols * iterRows );
destDataList.push_back( destData );
CPLFree( dataList[i-1] );
}
dataList[i-1] = 0;
}
if ( mTiledMode ) //write to file
{
delete destProvider;
@ -356,8 +378,8 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
//write data to output file. todo: loop over the data list
for ( int i = 1; i <= nBands; ++i )
{
destProvider->write( dataList[i - 1], i, iterCols, iterRows, 0, 0 );
CPLFree( dataList[i - 1] );
destProvider->write( destDataList[i - 1], i, iterCols, iterRows, 0, 0 );
CPLFree( destDataList[i - 1] );
addToVRT( QString::number( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
}
}
@ -366,8 +388,8 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
//loop over data
for ( int i = 1; i <= nBands; ++i )
{
destProvider->write( dataList[i - 1], i, iterCols, iterRows, iterLeft, iterTop );
CPLFree( dataList[i - 1] );
destProvider->write( destDataList[i - 1], i, iterCols, iterRows, iterLeft, iterTop );
CPLFree( destDataList[i - 1] );
}
}
++fileIndex;

View File

@ -24,6 +24,8 @@
#include "qgslogger.h"
#include "qgsrasterinterface.h"
#include "cpl_conv.h"
QgsRasterInterface::QgsRasterInterface( QgsRasterInterface * input )
: mInput( input )
, mOn( true )
@ -248,3 +250,15 @@ QString QgsRasterInterface::printValue( double value )
QgsDebugMsg( "Cannot correctly parse printed value" );
return s;
}
void * QgsRasterInterface::convert( void *srcData, QgsRasterInterface::DataType srcDataType, QgsRasterInterface::DataType destDataType, int size )
{
int destDataTypeSize = typeSize( destDataType ) / 8;
void *destData = VSIMalloc( destDataTypeSize * size );
for ( int i = 0; i < size; i++ )
{
double value = readValue( srcData, srcDataType, i );
writeValue( destData, destDataType, i, value );
}
return destData;
}

View File

@ -18,6 +18,8 @@
#ifndef QGSRASTERINTERFACE_H
#define QGSRASTERINTERFACE_H
#include <limits>
#include <QImage>
#include "qgsrectangle.h"
@ -61,7 +63,7 @@ class CORE_EXPORT QgsRasterInterface
virtual ~QgsRasterInterface();
int typeSize( int dataType ) const
static int typeSize( int dataType )
{
// Modified and extended copy from GDAL
switch ( dataType )
@ -197,6 +199,15 @@ class CORE_EXPORT QgsRasterInterface
* @return string representing the value*/
static QString printValue( double value );
/** \brief Convert block of data from one type to another. Original block memory
* is not release.
* @param srcData source data
* @param srcDataType source data type
* @param destDataType dest data type
* @param size block size (width * height)
* @return block of data in destDataType */
static void * convert( void *srcData, QgsRasterInterface::DataType srcDataType, QgsRasterInterface::DataType destDataType, int size );
protected:
// QgsRasterInterface used as input
QgsRasterInterface* mInput;
@ -204,8 +215,8 @@ class CORE_EXPORT QgsRasterInterface
// On/off state, if off, it does not do anything, replicates input
bool mOn;
inline double readValue( void *data, QgsRasterInterface::DataType type, int index );
inline void writeValue( void *data, QgsRasterInterface::DataType type, int index, double value );
inline static double readValue( void *data, QgsRasterInterface::DataType type, int index );
inline static void writeValue( void *data, QgsRasterInterface::DataType type, int index, double value );
private:
// Last rendering cumulative (this and all preceding interfaces) times, from index 1
@ -217,6 +228,7 @@ class CORE_EXPORT QgsRasterInterface
inline double QgsRasterInterface::readValue( void *data, QgsRasterInterface::DataType type, int index )
{
#if 0
if ( !mInput )
{
return 0;
@ -226,6 +238,7 @@ inline double QgsRasterInterface::readValue( void *data, QgsRasterInterface::Dat
{
return mInput->noDataValue();
}
#endif
switch ( type )
{
@ -256,7 +269,8 @@ inline double QgsRasterInterface::readValue( void *data, QgsRasterInterface::Dat
}
// TODO: noDataValue is per band
return mInput->noDataValue();
//return mInput->noDataValue();
return std::numeric_limits<double>::quiet_NaN();
}
inline void QgsRasterInterface::writeValue( void *data, QgsRasterInterface::DataType type, int index, double value )

View File

@ -58,7 +58,9 @@ void * QgsRasterNuller::readBlock( int bandNo, QgsRectangle const & extent, int
QgsRasterInterface::DataType dataType = mInput->dataType( bandNo );
double noDataValue = mInput->noDataValue( bandNo );
// Input may be without no data value
//double noDataValue = mInput->noDataValue( bandNo );
double noDataValue = mOutputNoData;
for ( int i = 0; i < height; i++ )
{

View File

@ -45,8 +45,15 @@ class CORE_EXPORT QgsRasterNuller : public QgsRasterInterface
void setNoData( QList<QgsRasterNuller::NoData> noData ) { mNoData = noData; }
QList<QgsRasterNuller::NoData> noData() const { return mNoData; }
/** \brief Set output no data value. */
void setOutputNoData( double noData ) { mOutputNoData = noData; }
private:
QList<QgsRasterNuller::NoData> mNoData;
// no data to be set in output
double mOutputNoData;
};
#endif // QGSRASTERNULLER_H

View File

@ -127,6 +127,7 @@ QgsRasterPipe::Role QgsRasterPipe::interfaceRole( QgsRasterInterface * interface
if ( dynamic_cast<QgsRasterRenderer *>( interface ) ) return RendererRole;
if ( dynamic_cast<QgsRasterResampleFilter *>( interface ) ) return ResamplerRole;
if ( dynamic_cast<QgsRasterProjector *>( interface ) ) return ProjectorRole;
if ( dynamic_cast<QgsRasterNuller *>( interface ) ) return NullerRole;
return UnknownRole;
}
@ -225,6 +226,11 @@ QgsRasterProjector * QgsRasterPipe::projector() const
return dynamic_cast<QgsRasterProjector*>( interface( ProjectorRole ) );
}
QgsRasterNuller * QgsRasterPipe::nuller() const
{
return dynamic_cast<QgsRasterNuller*>( interface( NullerRole ) );
}
bool QgsRasterPipe::remove( int idx )
{
QgsDebugMsg( QString( "remove at %1" ).arg( idx ) );

View File

@ -25,6 +25,7 @@
#include "qgsrasterinterface.h"
#include "qgsrasterresamplefilter.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasternuller.h"
#include "qgsrasterrenderer.h"
#include "qgsrasterprojector.h"
@ -45,7 +46,8 @@ class CORE_EXPORT QgsRasterPipe
ProviderRole = 1,
RendererRole = 2,
ResamplerRole = 3,
ProjectorRole = 4
ProjectorRole = 4,
NullerRole = 5,
};
QgsRasterPipe( );
@ -91,6 +93,7 @@ class CORE_EXPORT QgsRasterPipe
QgsRasterRenderer * renderer() const;
QgsRasterResampleFilter * resampleFilter() const;
QgsRasterProjector * projector() const;
QgsRasterNuller * nuller() const;
/** Set on/off collection of statistics */
void setStatsOn( bool on ) { if ( last() ) last()->setStatsOn( on ); }