mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
rasters saveas data type conversion fix
This commit is contained in:
parent
aa063f67f2
commit
c4fa82e23a
@ -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,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 )
|
||||
|
@ -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 ); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user