Skip to content
Permalink
Browse files

rasters saveas data type conversion fix

  • Loading branch information
blazek committed Sep 12, 2012
1 parent aa063f6 commit c4fa82e23ae12731a99d52c8db75f95ca56ba6f7
@@ -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
@@ -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 );
@@ -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;
@@ -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;
}
@@ -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,15 +199,24 @@ 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;

// 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 )
@@ -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++ )
{
@@ -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
@@ -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 ) );
@@ -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 ); }

0 comments on commit c4fa82e

Please sign in to comment.
You can’t perform that action at this time.