Skip to content
Permalink
Browse files

raster save as optional nodata

  • Loading branch information
blazek committed Aug 23, 2012
1 parent 13a790d commit c339a57034077fea821ff96eb71132366637a47f
@@ -163,6 +163,7 @@
#include "qgsrasteriterator.h"
#include "qgsrasterlayer.h"
#include "qgsrasterlayerproperties.h"
#include "qgsrasternuller.h"
#include "qgsrasterrenderer.h"
#include "qgsrasterlayersaveasdialog.h"
#include "qgsrectangle.h"
@@ -3924,7 +3925,7 @@ void QgisApp::saveAsRasterFile()
return;
}

QgsRasterLayerSaveAsDialog d( rasterLayer->dataProvider(), mMapCanvas->extent(), rasterLayer->crs(), mMapCanvas->mapRenderer()->destinationCrs() );
QgsRasterLayerSaveAsDialog d( rasterLayer, rasterLayer->dataProvider(), mMapCanvas->extent(), rasterLayer->crs(), mMapCanvas->mapRenderer()->destinationCrs() );
if ( d.exec() == QDialog::Accepted )
{
QgsRasterFileWriter fileWriter( d.outputFileName() );
@@ -3953,12 +3954,21 @@ void QgisApp::saveAsRasterFile()
QgsDebugMsg( "Cannot set pipe provider" );
return;
}

QgsRasterNuller *nuller = new QgsRasterNuller();
nuller->setNoData( d.noData() );
if ( !pipe->insert( 1, nuller ) )
{
QgsDebugMsg( "Cannot set pipe nuller" );
return;
}

// add projector if necessary
if ( d.outputCrs() != rasterLayer->crs() )
{
QgsRasterProjector * projector = new QgsRasterProjector;
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
if ( !pipe->set( projector ) )
if ( !pipe->insert( 2, projector ) )
{
QgsDebugMsg( "Cannot set pipe projector" );
return;
@@ -166,6 +166,7 @@ SET(QGIS_CORE_SRCS
raster/qgsrasterinterface.cpp
raster/qgsrasteriterator.cpp
raster/qgsrasterlayer.cpp
raster/qgsrasternuller.cpp
raster/qgsrastertransparency.cpp
raster/qgsrasterpipe.cpp
raster/qgsrastershader.cpp
@@ -209,3 +209,4 @@ double QgsRasterInterface::time( bool cumulative )
}
return t;
}

@@ -22,6 +22,8 @@

#include "qgsrectangle.h"

#include "gdal.h"

/** \ingroup core
* Base class for processing modules.
*/
@@ -196,6 +198,9 @@ 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 );

private:
// Last rendering cumulative (this and all preceding interfaces) times, from index 1
QVector<double> mTime;
@@ -204,6 +209,84 @@ class CORE_EXPORT QgsRasterInterface
int mStatsOn;
};

inline double QgsRasterInterface::readValue( void *data, QgsRasterInterface::DataType type, int index )
{
if ( !mInput )
{
return 0;
}

if ( !data )
{
return mInput->noDataValue();
}

switch ( type )
{
case QgsRasterInterface::Byte:
return ( double )(( GByte * )data )[index];
break;
case QgsRasterInterface::UInt16:
return ( double )(( GUInt16 * )data )[index];
break;
case QgsRasterInterface::Int16:
return ( double )(( GInt16 * )data )[index];
break;
case QgsRasterInterface::UInt32:
return ( double )(( GUInt32 * )data )[index];
break;
case QgsRasterInterface::Int32:
return ( double )(( GInt32 * )data )[index];
break;
case QgsRasterInterface::Float32:
return ( double )(( float * )data )[index];
break;
case QgsRasterInterface::Float64:
return ( double )(( double * )data )[index];
break;
default:
//QgsMessageLog::logMessage( tr( "GDAL data type %1 is not supported" ).arg( type ), tr( "Raster" ) );
break;
}

// TODO: noDataValue is per band
return mInput->noDataValue();
}

inline void QgsRasterInterface::writeValue( void *data, QgsRasterInterface::DataType type, int index, double value )
{
if ( !mInput ) return;
if ( !data ) return;

switch ( type )
{
case QgsRasterInterface::Byte:
(( GByte * )data )[index] = ( GByte ) value;
break;
case QgsRasterInterface::UInt16:
(( GUInt16 * )data )[index] = ( GUInt16 ) value;
break;
case QgsRasterInterface::Int16:
(( GInt16 * )data )[index] = ( GInt16 ) value;
break;
case QgsRasterInterface::UInt32:
(( GUInt32 * )data )[index] = ( GUInt32 ) value;
break;
case QgsRasterInterface::Int32:
(( GInt32 * )data )[index] = ( GInt32 ) value;
break;
case QgsRasterInterface::Float32:
(( float * )data )[index] = ( float ) value;
break;
case QgsRasterInterface::Float64:
(( double * )data )[index] = value;
break;
default:
//QgsMessageLog::logMessage( tr( "GDAL data type %1 is not supported" ).arg( type ), tr( "Raster" ) );
break;
}
}

#endif


@@ -0,0 +1,86 @@
/***************************************************************************
qgsrasternuller.cpp
---------------------
begin : August 2012
copyright : (C) 2012 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsrasterdataprovider.h"
#include "qgsrasternuller.h"

QgsRasterNuller::QgsRasterNuller( QgsRasterInterface* input )
: QgsRasterInterface( input )
{
}

QgsRasterNuller::~QgsRasterNuller()
{
}

QgsRasterInterface * QgsRasterNuller::clone() const
{
QgsDebugMsg( "Entered" );
QgsRasterNuller * nuller = new QgsRasterNuller( 0 );
nuller->mNoData = mNoData;
return nuller;
}

int QgsRasterNuller::bandCount() const
{
if ( mInput ) return mInput->bandCount();
return 0;
}

QgsRasterInterface::DataType QgsRasterNuller::dataType( int bandNo ) const
{
if ( mInput ) return mInput->dataType( bandNo );
return QgsRasterInterface::UnknownDataType;
}

void * QgsRasterNuller::readBlock( int bandNo, QgsRectangle const & extent, int width, int height )
{
QgsDebugMsg( "Entered" );
if ( !mInput ) return 0;

//QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() );

void * rasterData = mInput->block( bandNo, extent, width, height );

QgsRasterInterface::DataType dataType = mInput->dataType( bandNo );
int pixelSize = mInput->typeSize( dataType ) / 8;

double noDataValue = mInput->noDataValue ( bandNo );

for ( int i = 0; i < height; ++i )
{
for ( int j = 0; j < width; ++j )
{
int index = pixelSize * ( i * width + j );

double value = readValue( rasterData, dataType, index );

foreach ( NoData noData, mNoData )
{
if ( ( value >= noData.min && value <= noData.max ) ||
doubleNear( value, noData.min ) ||
doubleNear( value, noData.max ) )
{
writeValue( rasterData, dataType, index, noDataValue );
}
}
}
}

return rasterData;
}

@@ -0,0 +1,52 @@
/***************************************************************************
qgsrasternuller.h
-------------------
begin : August 2012
copyright : (C) 2012 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSRASTERNULLER_H
#define QGSRASTERNULLER_H

#include "qgsrasterdataprovider.h"
#include "qgsrasterinterface.h"

#include <QList>

class CORE_EXPORT QgsRasterNuller : public QgsRasterInterface
{
public:
QgsRasterNuller( QgsRasterInterface* input = 0 );
~QgsRasterNuller();

struct NoData
{
double min;
double max;
};

QgsRasterInterface * clone() const;

int bandCount() const;

QgsRasterInterface::DataType dataType( int bandNo ) const;

void * readBlock( int bandNo, QgsRectangle const & extent, int width, int height );

void setNoData( QList<QgsRasterNuller::NoData> noData ) { mNoData = noData; }

private:
QList<QgsRasterNuller::NoData> mNoData;
};

#endif // QGSRASTERNULLER_H

0 comments on commit c339a57

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