96 changes: 94 additions & 2 deletions src/core/raster/qgsrasterfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@
#include "qgsrasteriterator.h"
#include "qgsrasterlayer.h"
#include "qgsrasterprojector.h"

#include <QCoreApplication>
#include <QProgressDialog>
#include <QTextStream>
#include <QMessageBox>

#include "gdal.h"

QgsRasterFileWriter::QgsRasterFileWriter( const QString& outputUrl ): mOutputUrl( outputUrl ), mOutputProviderKey( "gdal" ), mOutputFormat( "GTiff" ), mTiledMode( false ),
mMaxTileWidth( 500 ), mMaxTileHeight( 500 ), mProgressDialog( 0 )
QgsRasterFileWriter::QgsRasterFileWriter( const QString& outputUrl ):
mOutputUrl( outputUrl ), mOutputProviderKey( "gdal" ), mOutputFormat( "GTiff" ),
mTiledMode( false ), mMaxTileWidth( 500 ), mMaxTileHeight( 500 ),
mBuildPyramidsFlag( QgsRasterDataProvider::PyramidsFlagNo ),
mPyramidsFormat( QgsRasterDataProvider::PyramidsGTiff ),
mProgressDialog( 0 )
{

}
Expand Down Expand Up @@ -210,6 +217,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
destNoDataValueList.append( destNoDataValue );
}

// TODO - what is this code doing here in the middle of the file, outside of a function???

QgsRasterInterface::DataType destDataType = destDataTypeList.value( 0 );
// Currently write API supports one output type for dataset only -> find the widest
Expand Down Expand Up @@ -281,6 +289,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
{
iter->startRasterRead( i, nCols, nRows, outputExtent );
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 ) );
}

Expand All @@ -296,6 +305,8 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
}

// hmm why is there a while( true ) here ..
// not good coding practice IMHO, it might be better to use [ for() and break ] or [ while (test) ]
while ( true )
{
for ( int i = 1; i <= nBands; ++i )
Expand All @@ -310,7 +321,13 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
writeVRT( vrtFilePath );
buildPyramids( vrtFilePath );
}
else
{
if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes )
buildPyramids( mOutputUrl );
}

QgsDebugMsg( "Done" );
return NoError; //reached last tile, bail out
}
// TODO: verify if NoDataConflict happened, to do that we need the whole pipe or nuller interface
Expand Down Expand Up @@ -356,6 +373,8 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
}
++fileIndex;
}

QgsDebugMsg( "Done" );
return NoError;
}

Expand Down Expand Up @@ -482,6 +501,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste

++fileIndex;
}

delete destProvider;
CPLFree( redData ); CPLFree( greenData ); CPLFree( blueData ); CPLFree( alphaData );

Expand All @@ -497,6 +517,11 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste
writeVRT( vrtFilePath );
buildPyramids( vrtFilePath );
}
else
{
if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes )
buildPyramids( mOutputUrl );
}
return NoError;
}

Expand Down Expand Up @@ -565,6 +590,7 @@ void QgsRasterFileWriter::addToVRT( const QString& filename, int band, int xSize
bandElem.appendChild( simpleSourceElem );
}

#if 0
void QgsRasterFileWriter::buildPyramids( const QString& filename )
{
GDALDatasetH dataSet;
Expand Down Expand Up @@ -593,6 +619,67 @@ void QgsRasterFileWriter::buildPyramids( const QString& filename )
}*/
GDALBuildOverviews( dataSet, "AVERAGE", 6, overviewList, 0, 0, /*pyramidsProgress*/ 0, /*mProgressDialog*/ 0 );
}
#endif

void QgsRasterFileWriter::buildPyramids( const QString& filename )
{
// open new dataProvider so we can build pyramids with it
QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, filename );
if ( !destProvider )
{
return;
}

// TODO progress report
// TODO test mTiledMode - not tested b/c segfault at line # 289
// connect( provider, SIGNAL( progressUpdate( int ) ), mPyramidProgress, SLOT( setValue( int ) ) );
QList< QgsRasterPyramid> myPyramidList;
if ( ! mPyramidsList.isEmpty() )
myPyramidList = destProvider->buildPyramidList( mPyramidsList );
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
myPyramidList[myCounterInt].build = true;
}

QgsDebugMsg( QString( "building pyramids : %1 pyramids, %2 resampling, %3 format" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( mPyramidsFormat ) );
// QApplication::setOverrideCursor( Qt::WaitCursor );
QString res = destProvider->buildPyramids( myPyramidList, mPyramidsResampling, mPyramidsFormat );
// QApplication::restoreOverrideCursor();

// TODO put this in provider or elsewhere
if ( !res.isNull() )
{
QString title, message;
if ( res == "ERROR_WRITE_ACCESS" )
{
title = QObject::tr( "Building pyramids failed - write access denied" );
message = QObject::tr( "Write access denied. Adjust the file permissions and try again." );
}
else if ( res == "ERROR_WRITE_FORMAT" )
{
title = QObject::tr( "Building pyramids failed." );
message = QObject::tr( "The file was not writable. Some formats do not "
"support pyramid overviews. Consult the GDAL documentation if in doubt." );
}
else if ( res == "FAILED_NOT_SUPPORTED" )
{
title = QObject::tr( "Building pyramids failed." );
message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
}
else if ( res == "ERROR_JPEG_COMPRESSION" )
{
title = QObject::tr( "Building pyramids failed." );
message = QObject::tr( "Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
}
else if ( res == "ERROR_VIRTUAL" )
{
title = QObject::tr( "Building pyramids failed." );
message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
}
QMessageBox::warning( 0, title, message );
QgsDebugMsg( res + " - " + message );
}
}

int QgsRasterFileWriter::pyramidsProgress( double dfComplete, const char *pszMessage, void* pData )
{
Expand Down Expand Up @@ -744,6 +831,11 @@ QgsRasterDataProvider* QgsRasterFileWriter::initOutput( int nCols, int nRows, co
return 0;
}

// TODO enable "use existing", has no effect for now, because using Create() in gdal provider
// should this belong in provider? should also test that source provider is gdal
// if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.toLower() == "gtiff" )
// mCreateOptions << "COPY_SRC_OVERVIEWS=YES";

if ( !destProvider->create( mOutputFormat, nBands, type, nCols, nRows, geoTransform,
crs, mCreateOptions ) )
{
Expand Down
17 changes: 17 additions & 0 deletions src/core/raster/qgsrasterfilewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ class CORE_EXPORT QgsRasterFileWriter
void setMaxTileWidth( int w ) { mMaxTileWidth = w; }
int maxTileWidth() const { return mMaxTileWidth; }

QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const { return mBuildPyramidsFlag; }
void setBuildPyramidsFlag( QgsRasterDataProvider::RasterBuildPyramids f ) { mBuildPyramidsFlag = f; }

QList< int > pyramidsList() const { return mPyramidsList; }
void setPyramidsList( const QList< int > & list ) { mPyramidsList = list; }

QString pyramidsResampling() const { return mPyramidsResampling; }
void setPyramidsResampling( const QString & str ) { mPyramidsResampling = str; }

QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const { return mPyramidsFormat; }
void setPyramidsFormat( QgsRasterDataProvider::RasterPyramidsFormat f ) { mPyramidsFormat = f; }

void setMaxTileHeight( int h ) { mMaxTileHeight = h; }
int maxTileHeight() const { return mMaxTileHeight; }

Expand Down Expand Up @@ -128,6 +140,11 @@ class CORE_EXPORT QgsRasterFileWriter
double mMaxTileWidth;
double mMaxTileHeight;

QList< int > mPyramidsList;
QString mPyramidsResampling;
QgsRasterDataProvider::RasterBuildPyramids mBuildPyramidsFlag;
QgsRasterDataProvider::RasterPyramidsFormat mPyramidsFormat;

QDomDocument mVRTDocument;
QDomElement mVRTRedBand;
QDomElement mVRTGreenBand;
Expand Down
10 changes: 1 addition & 9 deletions src/core/raster/qgsrasterlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ email : tim at linfiniti.com
#include "qgsmaptopixel.h"
#include "qgsprojectfiletransform.h"
#include "qgsproviderregistry.h"
#include "qgsrasterbandstats.h"
#include "qgsrasterlayer.h"
#include "qgsrasterpyramid.h"
#include "qgsrasterrendererregistry.h"
#include "qgsrectangle.h"
#include "qgsrendercontext.h"
Expand Down Expand Up @@ -423,7 +421,6 @@ const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBand

return QgsRasterBandStats(); // return a null one
}
#endif

QString QgsRasterLayer::buildPyramids( RasterPyramidList const & theRasterPyramidList,
QString const & theResamplingMethod, bool theTryInternalFlag )
Expand All @@ -436,6 +433,7 @@ QgsRasterLayer::RasterPyramidList QgsRasterLayer::buildPyramidList()
{
return mDataProvider->buildPyramidList();
}
#endif

QString QgsRasterLayer::colorShadingAlgorithmAsString() const
{
Expand Down Expand Up @@ -1558,7 +1556,6 @@ void QgsRasterLayer::init()
setDrawingStyle( QgsRasterLayer::UndefinedDrawingStyle );

mBandCount = 0;
mHasPyramids = false;
mNoDataValue = -9999.0;
mValidNoDataValue = false;

Expand Down Expand Up @@ -1822,12 +1819,7 @@ void QgsRasterLayer::closeDataProvider()
mValid = false;
mPipe.remove( mDataProvider );
mDataProvider = 0;

//mRasterStatsList.clear();
mContrastEnhancementList.clear();

mHasPyramids = false;
mPyramidList.clear();
}

void QgsRasterLayer::setColorShadingAlgorithm( ColorShadingAlgorithm )
Expand Down
21 changes: 8 additions & 13 deletions src/core/raster/qgsrasterlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@
//
class QgsMapToPixel;
class QgsRectangle;
class QgsRasterBandStats;
class QgsRasterPyramid;
class QgsRasterRenderer;
class QImage;
class QPixmap;
Expand Down Expand Up @@ -273,12 +271,12 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
* to be added to the list. Each time a RasterPyramid is created
* we will check to see if a pyramid matching these dimensions already exists
* in the raster layer, and if so mark the exists flag as true */
typedef QList<QgsRasterPyramid> RasterPyramidList;
/* typedef QList<QgsRasterPyramid> RasterPyramidList; */

/** \brief A list containing one RasterBandStats struct per raster band in this raster layer.
* Note that while every RasterBandStats element will have the name and number of its associated
* band populated, any additional stats are calculated on a need to know basis.*/
typedef QList<QgsRasterBandStats> RasterStatsList;
/* typedef QList<QgsRasterBandStats> RasterStatsList; */

//
// Static methods:
Expand Down Expand Up @@ -332,7 +330,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
DrawingStyle drawingStyle() { return mDrawingStyle; }

/** \brief Accessor for mHasPyramids (READ ONLY) */
bool hasPyramids() { return mHasPyramids; }
/* bool hasPyramids() { return dataProvider() != NULL ? dataProvider()->hasPyramids() : false ; } */

/** \brief Accessor for mUserDefinedGrayMinimumMaximum */
bool hasUserDefinedGrayMinimumMaximum() const { return mUserDefinedGrayMinimumMaximum; }
Expand Down Expand Up @@ -414,7 +412,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
* ACTUALLY exists you need to look at the existsFlag member in each struct stored in the
* list.
*/
RasterPyramidList buildPyramidList();
// RasterPyramidList buildPyramidList();

/** \brief Accessor for color shader algorithm */
QString colorShadingAlgorithmAsString() const;
Expand Down Expand Up @@ -677,9 +675,9 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer

public slots:
/** \brief Create GDAL pyramid overviews */
QString buildPyramids( const RasterPyramidList &,
const QString & theResamplingMethod = "NEAREST",
bool theTryInternalFlag = false );
// QString buildPyramids( const RasterPyramidList &,
// const QString & theResamplingMethod = "NEAREST",
// bool theTryInternalFlag = false );

void showStatusMessage( const QString & theMessage );

Expand Down Expand Up @@ -853,9 +851,6 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
/** \brief Values for mapping pixel to world coordinates. Contents of this array are the same as the GDAL adfGeoTransform */
double mGeoTransform[6];

/** \brief Whether this raster has overviews / pyramids or not */
bool mHasPyramids;

/** \brief Raster width */
int mWidth;

Expand All @@ -880,7 +875,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
QString mProviderKey;

/** \brief This list holds a series of RasterPyramid structs which store information for each potential pyramid level */
RasterPyramidList mPyramidList;
/* RasterPyramidList mPyramidList; */

/** \brief A collection of stats - one for each band in the layer */
//RasterStatsList mRasterStatsList;
Expand Down
91 changes: 91 additions & 0 deletions src/gui/qgsrasterlayersaveasdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,32 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer* rasterLa
mCreateOptionsWidget->setFormat( myFormats[0] );
}
mCreateOptionsWidget->update();
}

// Only do pyramids if dealing directly with GDAL.
if ( mDataProvider->capabilities() & QgsRasterDataProvider::BuildPyramids )
{
mPyramidsOptionsWidget->createOptionsWidget()->setType( QgsRasterFormatSaveOptionsWidget::ProfileLineEdit );

// init. pyramids button group
for ( int i = -2, j = 0 ; i >= -4 ; i--, j++ )
mPyramidsButtonGroup->setId( mPyramidsButtonGroup->button( i ), j );
// TODO enable "use existing", has no effect for now, because using Create() in gdal provider
// if ( ! mDataProvider->hasPyramids() )
// mPyramidsButtonGroup->button( QgsRasterDataProvider::CopyExisting )->setEnabled( false );
mPyramidsButtonGroup->button( QgsRasterDataProvider::CopyExisting )->setEnabled( false );
mPyramidsButtonGroup->button( QgsRasterDataProvider::PyramidsFlagNo )->click();
mPyramidsButtonGroup->button( QgsRasterDataProvider::PyramidsFlagNo )->setChecked( true );

populatePyramidsLevels();
connect( mPyramidsOptionsWidget, SIGNAL( overviewListChanged() ),
this, SLOT( populatePyramidsLevels() ) );
}
else
{
mPyramidsGroupBox->setEnabled( false );
}

updateCrsGroup();

QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok );
Expand Down Expand Up @@ -627,6 +649,75 @@ void QgsRasterLayerSaveAsDialog::noDataCellTextEdited( const QString & text )
}
}

void QgsRasterLayerSaveAsDialog::on_mTileModeCheckBox_toggled( bool toggled )
{
if ( toggled )
{
// enable pyramids
if ( ! mPyramidsGroupBox->isChecked() )
mPyramidsGroupBox->setChecked( true );
if ( mPyramidsButtonGroup->checkedId() == QgsRasterDataProvider::PyramidsFlagNo )
{
mPyramidsButtonGroup->button( QgsRasterDataProvider::PyramidsFlagYes )->click();
mPyramidsButtonGroup->button( QgsRasterDataProvider::PyramidsFlagYes )->setChecked( true );
}
mPyramidsOptionsWidget->checkAllLevels( true );
}
}

void QgsRasterLayerSaveAsDialog::on_mPyramidsButtonGroup_buttonClicked( int id )
{
if ( id == QgsRasterDataProvider::PyramidsFlagNo || id == QgsRasterDataProvider::CopyExisting )
{
mPyramidsOptionsWidget->setEnabled( false );
mPyramidResolutionsLabel->setEnabled( false );
mPyramidResolutionsLineEdit->setEnabled( false );
}
else if ( id == QgsRasterDataProvider::PyramidsFlagYes )
{
mPyramidsOptionsWidget->setEnabled( true );
mPyramidResolutionsLabel->setEnabled( true );
mPyramidResolutionsLineEdit->setEnabled( true );
}
else
QgsDebugMsg( QString( "invalid button id %1" ).arg( id ) );
populatePyramidsLevels();
}

void QgsRasterLayerSaveAsDialog::populatePyramidsLevels()
{
// if selection != "Build pyramids", get pyramids from actual layer
QString text;

if ( mPyramidsButtonGroup->checkedId() != QgsRasterDataProvider::PyramidsFlagNo )
{
QList<QgsRasterPyramid> myPyramidList;
if ( mPyramidsButtonGroup->checkedId() == QgsRasterDataProvider::CopyExisting )
{
myPyramidList = mDataProvider->buildPyramidList();
}
else if ( mPyramidsButtonGroup->checkedId() == QgsRasterDataProvider::PyramidsFlagYes )
{
if ( ! mPyramidsOptionsWidget->overviewList().isEmpty() )
myPyramidList = mDataProvider->buildPyramidList( mPyramidsOptionsWidget->overviewList() );
}
QList<QgsRasterPyramid>::iterator myRasterPyramidIterator;
for ( myRasterPyramidIterator = myPyramidList.begin();
myRasterPyramidIterator != myPyramidList.end();
++myRasterPyramidIterator )
{
if ( mPyramidsButtonGroup->checkedId() == QgsRasterDataProvider::PyramidsFlagYes
|| myRasterPyramidIterator->exists )
{
text += QString::number( myRasterPyramidIterator->xDim ) + QString( "x" ) +
QString::number( myRasterPyramidIterator->yDim ) + " ";
}
}
}

mPyramidResolutionsLineEdit->setText( text.trimmed() );
}

void QgsRasterLayerSaveAsDialog::setNoDataToEdited( int row )
{
if ( row >= mNoDataToEdited.size() )
Expand Down
11 changes: 11 additions & 0 deletions src/gui/qgsrasterlayersaveasdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
QgsRectangle outputRectangle() const;
QList<QgsRasterNuller::NoData> noData() const;

QList< int > overviewList() const { return mPyramidsOptionsWidget->overviewList(); }
QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const
{ return ( QgsRasterDataProvider::RasterBuildPyramids ) mPyramidsButtonGroup->checkedId(); }
QString pyramidsResampling() const { return mPyramidsOptionsWidget->resamplingMethod(); }
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const
{ return mPyramidsOptionsWidget->pyramidsFormat(); }


void hideFormat();
void hideOutput();

Expand Down Expand Up @@ -92,6 +100,9 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
void on_mRemoveSelectedNoDataToolButton_clicked();
void on_mRemoveAllNoDataToolButton_clicked();
void noDataCellTextEdited( const QString & text );
void on_mTileModeCheckBox_toggled( bool toggled );
void on_mPyramidsButtonGroup_buttonClicked( int id );
void populatePyramidsLevels();

private:
QgsRasterLayer* mRasterLayer;
Expand Down
124 changes: 82 additions & 42 deletions src/gui/qgsrasterpyramidsoptionswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@


QgsRasterPyramidsOptionsWidget::QgsRasterPyramidsOptionsWidget( QWidget* parent, QString provider )
: QWidget( parent ), mProvider( provider )
: QWidget( parent ), mProvider( provider )
{
setupUi( this );

mPyramidsOptionsWidget->setProvider( provider );
mPyramidsOptionsWidget->setFormat( "_pyramids" );
// mPyramidsOptionsWidget->swapOptionsUI( 1 );
Expand All @@ -59,63 +59,81 @@ void QgsRasterPyramidsOptionsWidget::updateUi()
// cbxPyramidsInternal->setChecked( mySettings.value( prefix + "internal", false ).toBool() );
tmpStr = mySettings.value( prefix + "format", "gtiff" ).toString();
if ( tmpStr == "internal" )
cboPyramidsFormat->setCurrentIndex( 0 );
else if ( tmpStr == "erdas" )
cboPyramidsFormat->setCurrentIndex( 2 );
cbxPyramidsFormat->setCurrentIndex( 1 );
else if ( tmpStr == "external_erdas" )
cbxPyramidsFormat->setCurrentIndex( 2 );
else
cboPyramidsFormat->setCurrentIndex( 1 );
cboResamplingMethod->setCurrentIndex( cboResamplingMethod->findText(
mySettings.value( prefix + "resampling", "Average" ).toString() ) );
lePyramidsLevels->setText( mySettings.value( prefix + "overviewStr", "bla" ).toString() );
cbxPyramidsFormat->setCurrentIndex( 0 );

// initialize resampling methods
cboResamplingMethod->clear();
foreach ( QString method, QgsRasterDataProvider::pyramidResamplingMethods( mProvider ) )
cboResamplingMethod->addItem( method );
cboResamplingMethod->setCurrentIndex( cboResamplingMethod->findText(
mySettings.value( prefix + "resampling", "Average" ).toString() ) );

// validate string, only space-separated positive integers are allowed
lePyramidsLevels->setValidator( new QRegExpValidator( QRegExp( "(\\d*)(\\s\\d*)*" ), lePyramidsLevels ) );
connect( lePyramidsLevels, SIGNAL( editingFinished() ),
this, SLOT( setOverviewList() ) );

// overview list
if ( mOverviewCheckBoxes.isEmpty() )
{
QList<int> overviewList;
overviewList << 2 << 4 << 8 << 16 << 32 << 64;
mOverviewCheckBoxes.clear();
foreach( int i, overviewList )
foreach ( int i, overviewList )
{
mOverviewCheckBoxes[ i ] = new QCheckBox( QString::number( i ), this );
layoutPyramidLevels->addWidget( mOverviewCheckBoxes[ i ] );
connect( mOverviewCheckBoxes[ i ], SIGNAL( toggled( bool ) ),
this, SLOT( setOverviewList() ) );
layoutPyramidsLevels->addWidget( mOverviewCheckBoxes[ i ] );
}
}
else
{
foreach( int i, mOverviewCheckBoxes.keys() )
foreach ( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setChecked( false );
}
tmpStr = mySettings.value( prefix + "overviewList", "" ).toString();
foreach( QString lev, tmpStr.split( " ", QString::SkipEmptyParts ) )
foreach ( QString lev, tmpStr.split( " ", QString::SkipEmptyParts ) )
{
if( mOverviewCheckBoxes.contains( lev.toInt() ) )
mOverviewCheckBoxes[ lev.toInt() ]->setChecked( true );
if ( mOverviewCheckBoxes.contains( lev.toInt() ) )
mOverviewCheckBoxes[ lev.toInt()]->setChecked( true );
}
on_lePyramidsLevels_editingFinished();
setOverviewList();

mPyramidsOptionsWidget->updateProfiles();
}



QString QgsRasterPyramidsOptionsWidget::resamplingMethod() const
{
return cboResamplingMethod->currentText().trimmed();
}

void QgsRasterPyramidsOptionsWidget::apply()
{
QSettings mySettings;
QString prefix = mProvider + "/driverOptions/_pyramids/";
QString tmpStr;

// mySettings.setValue( prefix + "internal", cbxPyramidsInternal->isChecked() );
if ( cboPyramidsFormat->currentIndex() == 0 )
if ( cbxPyramidsFormat->currentIndex() == 1 )
tmpStr = "internal";
else if ( cboPyramidsFormat->currentIndex() == 2 )
tmpStr = "erdas";
else
tmpStr = "tiff";
else if ( cbxPyramidsFormat->currentIndex() == 2 )
tmpStr = "external_erdas";
else
tmpStr = "external";
mySettings.setValue( prefix + "format", tmpStr );
mySettings.setValue( prefix + "resampling", cboResamplingMethod->currentText().trimmed() );
mySettings.setValue( prefix + "overviewStr", lePyramidsLevels->text().trimmed() );

// overview list
tmpStr = "";
foreach( int i, mOverviewCheckBoxes.keys() )
foreach ( int i, mOverviewCheckBoxes.keys() )
{
if ( mOverviewCheckBoxes[ i ]->isChecked() )
tmpStr += QString::number( i ) + " ";
Expand All @@ -125,29 +143,51 @@ void QgsRasterPyramidsOptionsWidget::apply()
mPyramidsOptionsWidget->apply();
}

void QgsRasterPyramidsOptionsWidget::on_lePyramidsLevels_editingFinished()
void QgsRasterPyramidsOptionsWidget::checkAllLevels( bool checked )
{
// validate string, only space-separated positive integers are allowed
// should we also validate that numbers are increasing?
QString tmpStr;
int tmpInt;
foreach( QString lev, lePyramidsLevels->text().trimmed().split( " ", QString::SkipEmptyParts ) )
{
tmpInt = lev.toInt();
if ( tmpInt > 0 )
tmpStr += QString::number( tmpInt ) + " ";
}
lePyramidsLevels->setText( tmpStr.trimmed() );
foreach ( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setChecked( checked );
}

void QgsRasterPyramidsOptionsWidget::on_cbxPyramidsLevelsCustom_toggled( bool toggled )
{
// if toggled, disable checkboxes and enable line edit
lePyramidsLevels->setEnabled( toggled );
foreach ( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setEnabled( ! toggled );
setOverviewList();
}

void QgsRasterPyramidsOptionsWidget::setOverviewList()
{
QgsDebugMsg( "Entered" );

mOverviewList.clear();

// if text is non-empty, disable checkboxes
if ( lePyramidsLevels->text() == "" )
// if custum levels is toggled, get selection from line edit
if ( cbxPyramidsLevelsCustom->isChecked() )
{
foreach( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setEnabled( true );
// should we also validate that numbers are increasing?
foreach ( QString lev, lePyramidsLevels->text().trimmed().split( " ", QString::SkipEmptyParts ) )
{
QgsDebugMsg( "lev= " + lev );
int tmpInt = lev.toInt();
if ( tmpInt > 0 )
{
QgsDebugMsg( "tmpInt= " + QString::number( tmpInt ) );
// if number is valid, add to overview list
mOverviewList << tmpInt;
}
}
}
else
{
foreach( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setEnabled( false );
foreach ( int i, mOverviewCheckBoxes.keys() )
{
if ( mOverviewCheckBoxes[ i ]->isChecked() )
mOverviewList << i;
}
}

emit overviewListChanged();
}
22 changes: 15 additions & 7 deletions src/gui/qgsrasterpyramidsoptionswidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define QGSRASTERPYRAMIDSOPTIONSWIDGET_H

#include "ui_qgsrasterpyramidsoptionswidgetbase.h"
#include "qgsrasterdataprovider.h"

class QCheckBox;

Expand All @@ -32,31 +33,38 @@ class GUI_EXPORT QgsRasterPyramidsOptionsWidget: public QWidget,

public:

QgsRasterPyramidsOptionsWidget( QWidget* parent = 0, QString provider = "gdal" );
QgsRasterPyramidsOptionsWidget( QWidget* parent = 0, QString provider = "gdal" );
~QgsRasterPyramidsOptionsWidget();

void setProvider( QString provider );
QStringList createOptions() const { return mPyramidsOptionsWidget->options(); }
QgsRasterFormatSaveOptionsWidget* createOptionsWidget() { return mPyramidsOptionsWidget; }
const QList<int> overviewList() const { return mOverviewList; }
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const
{ return ( QgsRasterDataProvider::RasterPyramidsFormat ) cbxPyramidsFormat->currentIndex(); }
QString resamplingMethod() const;

public slots:

void apply();
void checkAllLevels( bool checked );

private slots:

void on_lePyramidsLevels_editingFinished();
void on_cboPyramidsFormat_currentIndexChanged( int index )
void on_cbxPyramidsLevelsCustom_toggled( bool toggled );
void on_cbxPyramidsFormat_currentIndexChanged( int index )
{ mPyramidsOptionsWidget->setEnabled( index != 2 ); }
void setOverviewList();

signals:
void overviewListChanged();

private:

void updateUi();

QString mProvider;
bool mInternal;
QString mResamplingMethod;
QList<int> mOverviewList;
QList< int > mOverviewList;
QMap< int, QCheckBox* > mOverviewCheckBoxes;
};

Expand Down
197 changes: 160 additions & 37 deletions src/providers/gdal/qgsgdalprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ int CPL_STDCALL progressCallback( double dfComplete,
if ( floor( dfLastComplete*10 ) != floor( dfComplete*10 ) )
{
mypProvider->emitProgress( prog->type, dfComplete * 100, QString( pszMessage ) );
mypProvider->emitProgressUpdate( dfComplete * 100 );
}
dfLastComplete = dfComplete;

Expand Down Expand Up @@ -1294,7 +1295,7 @@ QgsRasterHistogram QgsGdalProvider::histogram( int theBandNo,
* @return null string on success, otherwise a string specifying error
*/
QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRasterPyramidList,
QString const & theResamplingMethod, bool theTryInternalFlag )
QString const & theResamplingMethod, RasterPyramidsFormat theFormat )
{
//TODO: Consider making theRasterPyramidList modifyable by this method to indicate if the pyramid exists after build attempt
//without requiring the user to rebuild the pyramid list to get the updated infomation
Expand Down Expand Up @@ -1324,7 +1325,8 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
return "ERROR_VIRTUAL";
}

if ( theTryInternalFlag )
// check if building internally
if ( theFormat == PyramidsInternal )
{
// libtiff < 4.0 has a bug that prevents safe building of overviews on JPEG compressed files
// we detect libtiff < 4.0 by checking that BIGTIFF is not in the creation options of the GTiff driver
Expand All @@ -1340,26 +1342,37 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
}
}

//close the gdal dataset and reopen it in read / write mode
GDALClose( mGdalDataset );
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri() ).constData(), GA_Update );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_Update );

// if the dataset couldn't be opened in read / write mode, tell the user
if ( !mGdalBaseDataset )
//if needed close the gdal dataset and reopen it in read / write mode
if ( GDALGetAccess( mGdalDataset ) == GA_ReadOnly )
{
//mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_ReadOnly );
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri()).constData(), GA_ReadOnly );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_ReadOnly );
//Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
mGdalDataset = mGdalBaseDataset;
return "ERROR_WRITE_FORMAT";
GDALClose( mGdalDataset );
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri() ).constData(), GA_Update );

mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_Update );

// if the dataset couldn't be opened in read / write mode, tell the user
if ( !mGdalBaseDataset )
{
//mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_ReadOnly );
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri()).constData(), GA_ReadOnly );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_ReadOnly );
//Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
mGdalDataset = mGdalBaseDataset;
return "ERROR_WRITE_FORMAT";
}
}
}

// are we using Erdas Imagine external overviews?
const char* myConfigUseRRD = CPLGetConfigOption( "USE_RRD", "NO" );
if ( theFormat == PyramidsErdas )
CPLSetConfigOption( "USE_RRD", "YES" );
else
CPLSetConfigOption( "USE_RRD", "NO" );

//
// Iterate through the Raster Layer Pyramid Vector, building any pyramid
// marked as exists in eaxh RasterPyramid struct.
// marked as exists in each RasterPyramid struct.
//
CPLErr myError; //in case anything fails
int myCount = 1;
Expand All @@ -1380,7 +1393,8 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
//emit drawingProgress( myCount, myTotal );
int myOverviewLevelsArray[1] = { myRasterPyramidIterator->level };
/* From : http://remotesensing.org/gdal/classGDALDataset.html#a23
* pszResampling : one of "NEAREST", "AVERAGE" or "MODE" controlling the downsampling method applied.
* pszResampling : one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE", "AVERAGE_MAGPHASE" or "NONE"
* controlling the downsampling method applied.
* nOverviews : number of overviews to build.
* panOverviewList : the list of overview decimation factors to build.
* nBand : number of bands to build overviews for in panBandList. Build for all bands if this is 0.
Expand All @@ -1391,31 +1405,35 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
//build the pyramid and show progress to console
try
{

//build the pyramid and show progress to console
//NOTE this (magphase) is disabled in the gui since it tends
//to create corrupted images. The images can be repaired
//by running one of the other resampling strategies below.
//see ticket #284
QgsGdalProgress myProg;
myProg.type = ProgressPyramids;
myProg.provider = this;
if ( theResamplingMethod == tr( "Average Magphase" ) )
{
myError = GDALBuildOverviews( mGdalBaseDataset, "MODE", 1, myOverviewLevelsArray, 0, NULL,
progressCallback, &myProg ); //this is the arg for the gdal progress callback
}
const char* theMethod;
if ( theResamplingMethod == tr( "Gauss" ) )
theMethod = "GAUSS";
else if ( theResamplingMethod == tr( "Cubic" ) )
theMethod = "CUBIC";
else if ( theResamplingMethod == tr( "Average" ) )

{
myError = GDALBuildOverviews( mGdalBaseDataset, "AVERAGE", 1, myOverviewLevelsArray, 0, NULL,
progressCallback, &myProg ); //this is the arg for the gdal progress callback
}
theMethod = "AVERAGE";
else if ( theResamplingMethod == tr( "Mode" ) )
theMethod = "MODE";
//NOTE magphase is disabled in the gui since it tends
//to create corrupted images. The images can be repaired
//by running one of the other resampling strategies below.
//see ticket #284
// else if ( theResamplingMethod == tr( "Average Magphase" ) )
// theMethod = "AVERAGE_MAGPHASE";
else if ( theResamplingMethod == tr( "None" ) )
theMethod = "NONE";
else // fall back to nearest neighbor
{
myError = GDALBuildOverviews( mGdalBaseDataset, "NEAREST", 1, myOverviewLevelsArray, 0, NULL,
progressCallback, &myProg ); //this is the arg for the gdal progress callback
}
theMethod = "NEAREST";
QgsDebugMsg( QString( "building overview at level %1 using resampling method %2"
).arg( myRasterPyramidIterator->level ).arg( theMethod ) );
// TODO - it would be more efficient to do it once instead of for each level
myError = GDALBuildOverviews( mGdalBaseDataset, theMethod, 1,
myOverviewLevelsArray, 0, NULL,
progressCallback, &myProg ); //this is the arg for the gdal progress callback

if ( myError == CE_Failure || CPLGetLastErrorNo() == CPLE_NotSupported )
{
Expand All @@ -1429,6 +1447,8 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
mGdalDataset = mGdalBaseDataset;

//emit drawingProgress( 0, 0 );
// restore former USE_RRD config (Erdas)
CPLSetConfigOption( "USE_RRD", myConfigUseRRD );
return "FAILED_NOT_SUPPORTED";
}
else
Expand All @@ -1446,8 +1466,11 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
}
}

// restore former USE_RRD config (Erdas)
CPLSetConfigOption( "USE_RRD", myConfigUseRRD );

QgsDebugMsg( "Pyramid overviews built" );
if ( theTryInternalFlag )
if ( theFormat == PyramidsInternal )
{
//close the gdal dataset and reopen it in read only mode
GDALClose( mGdalBaseDataset );
Expand All @@ -1460,6 +1483,7 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
return NULL; // returning null on success
}

#if 0
QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList()
{
//
Expand Down Expand Up @@ -1535,6 +1559,95 @@ QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList()

return mPyramidList;
}
#endif

QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList( QList<int> overviewList )
{
int myWidth = mWidth;
int myHeight = mHeight;
GDALRasterBandH myGDALBand = GDALGetRasterBand( mGdalDataset, 1 ); //just use the first band

mPyramidList.clear();

// if overviewList is empty (default) build the pyramid list
if ( overviewList.isEmpty() )
{
int myDivisor = 2;

QgsDebugMsg( "Building initial pyramid list" );

while (( myWidth / myDivisor > 32 ) && (( myHeight / myDivisor ) > 32 ) )
{
overviewList.append( myDivisor );
//sqare the divisor each step
myDivisor = ( myDivisor * 2 );
}
}

// loop over pyramid list
foreach ( int myDivisor, overviewList )
{
//
// First we build up a list of potential pyramid layers
//

QgsRasterPyramid myRasterPyramid;
myRasterPyramid.level = myDivisor;
myRasterPyramid.xDim = ( int )( 0.5 + ( myWidth / ( double )myDivisor ) );
myRasterPyramid.yDim = ( int )( 0.5 + ( myHeight / ( double )myDivisor ) );
myRasterPyramid.exists = false;

QgsDebugMsg( QString( "Pyramid %1 xDim %2 yDim %3" ).arg( myRasterPyramid.level ).arg( myRasterPyramid.xDim ).arg( myRasterPyramid.yDim ) );

//
// Now we check if it actually exists in the raster layer
// and also adjust the dimensions if the dimensions calculated
// above are only a near match.
//
const int myNearMatchLimit = 5;
if ( GDALGetOverviewCount( myGDALBand ) > 0 )
{
int myOverviewCount;
for ( myOverviewCount = 0;
myOverviewCount < GDALGetOverviewCount( myGDALBand );
++myOverviewCount )
{
GDALRasterBandH myOverview;
myOverview = GDALGetOverview( myGDALBand, myOverviewCount );
int myOverviewXDim = GDALGetRasterBandXSize( myOverview );
int myOverviewYDim = GDALGetRasterBandYSize( myOverview );
//
// here is where we check if its a near match:
// we will see if its within 5 cells either side of
//
QgsDebugMsg( "Checking whether " + QString::number( myRasterPyramid.xDim ) + " x " +
QString::number( myRasterPyramid.yDim ) + " matches " +
QString::number( myOverviewXDim ) + " x " + QString::number( myOverviewYDim ) );


if (( myOverviewXDim <= ( myRasterPyramid.xDim + myNearMatchLimit ) ) &&
( myOverviewXDim >= ( myRasterPyramid.xDim - myNearMatchLimit ) ) &&
( myOverviewYDim <= ( myRasterPyramid.yDim + myNearMatchLimit ) ) &&
( myOverviewYDim >= ( myRasterPyramid.yDim - myNearMatchLimit ) ) )
{
//right we have a match so adjust the a / y before they get added to the list
myRasterPyramid.xDim = myOverviewXDim;
myRasterPyramid.yDim = myOverviewYDim;
myRasterPyramid.exists = true;
QgsDebugMsg( ".....YES!" );
}
else
{
//no match
QgsDebugMsg( ".....no." );
}
}
}
mPyramidList.append( myRasterPyramid );
}

return mPyramidList;
}

QStringList QgsGdalProvider::subLayers() const
{
Expand All @@ -1546,6 +1659,11 @@ void QgsGdalProvider::emitProgress( int theType, double theProgress, QString the
emit progress( theType, theProgress, theMessage );
}

void QgsGdalProvider::emitProgressUpdate( int theProgress )
{
emit progressUpdate( theProgress );
}

/**
* Class factory to return a pointer to a newly created
* QgsGdalProvider object
Expand Down Expand Up @@ -2221,6 +2339,11 @@ bool QgsGdalProvider::create( const QString& format, int nBands,
return false;
}

QString tmpStr = "create options:";
foreach ( QString option, createOptions )
tmpStr += " " + option;
QgsDebugMsg( tmpStr );

//create dataset
char **papszOptions = papszFromStringList( createOptions );
GDALDatasetH dataset = GDALCreate( driver, dataSourceUri().toLocal8Bit().data(), width, height, nBands, ( GDALDataType )type, papszOptions );
Expand Down
5 changes: 3 additions & 2 deletions src/providers/gdal/qgsgdalprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,14 +252,15 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase

QString buildPyramids( const QList<QgsRasterPyramid> &,
const QString & theResamplingMethod = "NEAREST",
bool theTryInternalFlag = false );
QList<QgsRasterPyramid> buildPyramidList();
RasterPyramidsFormat theFormat = PyramidsGTiff );
QList<QgsRasterPyramid> buildPyramidList( QList<int> overviewList = QList<int>() );

/** \brief Close data set and release related data */
void closeDataset();

/** Emit a signal to notify of the progress event. */
void emitProgress( int theType, double theProgress, QString theMessage );
void emitProgressUpdate( int theProgress );

static QMap<QString, QString> supportedMimes();

Expand Down
88 changes: 57 additions & 31 deletions src/ui/qgsrasterlayerpropertiesbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,37 @@
<property name="margin">
<number>0</number>
</property>
<item row="3" column="1">
<widget class="QComboBox" name="cboResamplingMethod">
<item>
<property name="text">
<string>Average</string>
</property>
</item>
<item>
<property name="text">
<string>Nearest Neighbour</string>
</property>
</item>
</widget>
</item>
<item row="3" column="2" colspan="2">
<widget class="QProgressBar" name="mPyramidProgress">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QPushButton" name="buttonBuildPyramids">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Build pyramids</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
Expand All @@ -822,7 +853,11 @@
</sizepolicy>
</property>
<property name="html">
<string></string>
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
Expand All @@ -845,49 +880,43 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="5">
<widget class="QCheckBox" name="cbxInternalPyramids">
<item row="3" column="0">
<widget class="QLabel" name="textLabel4_2">
<property name="text">
<string>Build pyramids internally if possible</string>
<string>Resampling method</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="textLabel4_2">
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Resampling method</string>
<string>Overview format</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="cboResamplingMethod">
<item row="2" column="1">
<widget class="QComboBox" name="cbxPyramidsFormat">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Average</string>
<string>External</string>
</property>
</item>
<item>
<property name="text">
<string>Nearest Neighbour</string>
<string>Internal (if possible)</string>
</property>
</item>
<item>
<property name="text">
<string>External (Erdas Imagine)</string>
</property>
</item>
</widget>
</item>
<item row="3" column="2" colspan="2">
<widget class="QProgressBar" name="mPyramidProgress">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QPushButton" name="buttonBuildPyramids">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Build pyramids</string>
</property>
</widget>
</item>
</layout>
Expand Down Expand Up @@ -919,9 +948,6 @@
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
Expand Down
131 changes: 115 additions & 16 deletions src/ui/qgsrasterlayersaveasdialogbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>550</width>
<width>575</width>
<height>580</height>
</rect>
</property>
Expand All @@ -29,9 +29,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-239</y>
<width>514</width>
<height>784</height>
<y>-293</y>
<width>539</width>
<height>831</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
Expand Down Expand Up @@ -278,7 +278,7 @@
<widget class="QPushButton" name="mOriginalExtentButton">
<property name="minimumSize">
<size>
<width>140</width>
<width>150</width>
<height>0</height>
</size>
</property>
Expand Down Expand Up @@ -307,7 +307,7 @@
<widget class="QPushButton" name="mCurrentExtentButton">
<property name="minimumSize">
<size>
<width>140</width>
<width>150</width>
<height>0</height>
</size>
</property>
Expand Down Expand Up @@ -452,6 +452,9 @@
</property>
<item>
<widget class="QLabel" name="mMaximumSizeXLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Maximum number of columns in one tile.</string>
</property>
Expand All @@ -462,13 +465,19 @@
</item>
<item>
<widget class="QLineEdit" name="mMaximumSizeXLineEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Maximum number of columns in one tile.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="mMaximumSizeYLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Maximum number of rows in one tile.</string>
</property>
Expand All @@ -479,13 +488,19 @@
</item>
<item>
<widget class="QLineEdit" name="mMaximumSizeYLineEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Maximum number of rows in one tile.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mTileModeCheckBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Create VRT</string>
</property>
Expand Down Expand Up @@ -554,7 +569,7 @@
<item row="2" column="0">
<widget class="QToolButton" name="mLoadTransparentNoDataToolButton">
<property name="enabled">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="toolTip">
<string>Load user defined fully transparent (100%) values </string>
Expand Down Expand Up @@ -604,27 +619,108 @@
<item>
<widget class="QgsCollapsibleGroupBox" name="mPyramidsGroupBox">
<property name="title">
<string>Pyramids (not yet implemented)</string>
<string>Pyramids</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="cbxPyramidsBuild">
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="0">
<widget class="QgsRasterPyramidsOptionsWidget" name="mPyramidsOptionsWidget" native="true">
<property name="enabled">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="text">
<string>Build pyramids</string>
</widget>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string>No pyramids</string>
</property>
<attribute name="buttonGroup">
<string notr="true">mPyramidsButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_2">
<property name="text">
<string>Build pyramids</string>
</property>
<attribute name="buttonGroup">
<string notr="true">mPyramidsButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_3">
<property name="text">
<string>Use existing</string>
</property>
<attribute name="buttonGroup">
<string notr="true">mPyramidsButtonGroup</string>
</attribute>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QgsRasterPyramidsOptionsWidget" name="mPyramidsOptionsWidget" native="true"/>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="mPyramidResolutionsLabel">
<property name="text">
<string>Resolutions</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="mPyramidResolutionsLineEdit">
<property name="toolTip">
<string>Pyramid resolutions corresponding to levels given</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
Expand Down Expand Up @@ -700,4 +796,7 @@
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="mPyramidsButtonGroup"/>
</buttongroups>
</ui>
140 changes: 60 additions & 80 deletions src/ui/qgsrasterpyramidsoptionswidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>351</width>
<height>195</height>
<width>366</width>
<height>171</height>
</rect>
</property>
<property name="windowTitle">
Expand All @@ -17,48 +17,15 @@
<property name="margin">
<number>1</number>
</property>
<item row="3" column="2">
<widget class="QLineEdit" name="lePyramidsLevels">
<property name="toolTip">
<string>Insert positive integer values separated by spaces</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Create Options</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<widget class="QgsRasterFormatSaveOptionsWidget" name="mPyramidsOptionsWidget" native="true"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<item row="3" column="0">
<widget class="QCheckBox" name="cbxPyramidsLevelsCustom">
<property name="text">
<string>Overview format</string>
<string>Custom levels</string>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="cboPyramidsFormat">
<widget class="QComboBox" name="cbxPyramidsFormat">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
Expand All @@ -67,12 +34,12 @@
</property>
<item>
<property name="text">
<string>Internal (if possible)</string>
<string>External</string>
</property>
</item>
<item>
<property name="text">
<string>External (GTiff)</string>
<string>Internal (if possible)</string>
</property>
</item>
<item>
Expand All @@ -82,44 +49,10 @@
</item>
</widget>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="lePyramidResolutions">
<item row="3" column="2">
<widget class="QLineEdit" name="lePyramidsLevels">
<property name="toolTip">
<string>Pyramid resolutions corresponding to levels given</string>
</property>
<property name="text">
<string>to be done</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Custom levels</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Resolutions</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="textLabel4_2">
<property name="text">
<string>Resampling method</string>
<string>Insert positive integer values separated by spaces</string>
</property>
</widget>
</item>
Expand All @@ -137,15 +70,62 @@
</item>
</widget>
</item>
<item row="2" column="2">
<layout class="QHBoxLayout" name="layoutPyramidsLevels"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Overview format</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Create Options</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Levels</string>
</property>
</widget>
</item>
<item row="2" column="2">
<layout class="QHBoxLayout" name="layoutPyramidLevels"/>
<item row="6" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="textLabel4_2">
<property name="text">
<string>Resampling method</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<widget class="QgsRasterFormatSaveOptionsWidget" name="mPyramidsOptionsWidget" native="true"/>
</item>
<item row="3" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
Expand Down
14 changes: 6 additions & 8 deletions tests/src/core/testqgsrasterlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <qgsrasterlayer.h>
#include <qgsrasterpyramid.h>
#include <qgsrasterbandstats.h>
#include <qgsrasterpyramid.h>
#include <qgsmaplayerregistry.h>
#include <qgsapplication.h>
#include <qgsmaprenderer.h>
Expand Down Expand Up @@ -339,24 +340,21 @@ void TestQgsRasterLayer::buildExternalOverviews()
// Ok now we can go on to test
//

bool myInternalFlag = false;
QgsRasterLayer::RasterPyramidList myPyramidList = mypLayer->buildPyramidList();
QgsRasterDataProvider::RasterPyramidsFormat myFormatFlag = QgsRasterDataProvider::PyramidsGTiff;
QList< QgsRasterPyramid > myPyramidList = mypLayer->dataProvider()->buildPyramidList();
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
//mark to be pyramided
myPyramidList[myCounterInt].build = true;
}
//now actually make the pyramids
QString myResult = mypLayer->buildPyramids(
myPyramidList,
"NEAREST",
myInternalFlag
);
QString myResult =
mypLayer->dataProvider()->buildPyramids( myPyramidList, "NEAREST", myFormatFlag );
qDebug( "%s", myResult.toLocal8Bit().constData() );
//
// Lets verify we have pyramids now...
//
myPyramidList = mypLayer->buildPyramidList();
myPyramidList = mypLayer->dataProvider()->buildPyramidList();
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
//mark to be pyramided
Expand Down