Skip to content

Commit 2fb78db

Browse files
committedJan 18, 2013
update raster format and pyramid save widgets for python, add pyramid config options support to raster writer, other fixes
1 parent 0dbb781 commit 2fb78db

21 files changed

+455
-187
lines changed
 

‎python/core/raster/qgsrasterdataprovider.sip

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,11 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface
169169
virtual QStringList subLayers() const;
170170

171171
/** \brief Create pyramid overviews */
172-
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
173-
const QString & theResamplingMethod = "NEAREST",
174-
RasterPyramidsFormat theFormat = PyramidsGTiff );
175-
172+
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
173+
const QString & theResamplingMethod = "NEAREST",
174+
RasterPyramidsFormat theFormat = PyramidsGTiff,
175+
const QStringList & theConfigOptions = QStringList() );
176+
176177
/** \brief Accessor for ths raster layers pyramid list.
177178
* @param overviewList used to construct the pyramid list (optional), when empty the list is defined by the provider.
178179
* A pyramid list defines the
@@ -269,13 +270,22 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface
269270
/** Remove dataset*/
270271
virtual bool remove();
271272

272-
static QStringList pyramidResamplingMethods( QString providerKey );
273+
/** Returns a list of pyramid resampling method names for given provider */
274+
static QStringList pyramidResamplingMethods( QString providerKey = "gdal" );
275+
/** Returns the pyramid resampling argument that corresponds to a given method */
276+
static QString pyramidResamplingArg( QString method, QString providerKey = "gdal" );
277+
278+
/** Validates creation options for a specific dataset and destination format.
279+
* @note used by GDAL provider only
280+
* @note see also validateCreationOptionsFormat() in gdal provider for validating options based on format only */
281+
virtual QString validateCreationOptions( const QStringList& createOptions, QString format );
273282

274-
/** Validates creation options for a specific dataset and destination format - used by GDAL provider only.
275-
* See also validateCreationOptionsFormat() in gdal provider for validating options based on format only. */
276-
virtual QString validateCreationOptions( const QStringList& createOptions, QString format );
283+
/** Validates pyramid creation options for a specific dataset and destination format
284+
* @note used by GDAL provider only */
285+
virtual QString validatePyramidsConfigOptions( RasterPyramidsFormat pyramidsFormat,
286+
const QStringList & theConfigOptions, const QString & fileFormat );
277287

278-
signals:
288+
signals:
279289
/** Emit a signal to notify of the progress event.
280290
* Emited theProgress is in percents (0.0-100.0) */
281291
void progress( int theType, double theProgress, QString theMessage );

‎python/core/raster/qgsrasterfilewriter.sip

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ class QgsRasterFileWriter
5959
void setMaxTileHeight( int h );
6060
int maxTileHeight() const;
6161

62-
// for now not putting createOptions in all methods, use createOptions()
6362
void setCreateOptions( const QStringList& list );
6463
QStringList createOptions() const;
64+
65+
QStringList pyramidsConfigOptions() const;
66+
void setPyramidsConfigOptions( const QStringList& list );
6567
};
6668

‎python/gui/qgsrasterformatsaveoptionswidget.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ class QgsRasterFormatSaveOptionsWidget : QWidget
2424
void setFormat( QString format );
2525
void setProvider( QString provider );
2626
void setRasterLayer( QgsRasterLayer* rasterLayer );
27+
void setRasterFileName( const QString& file );
2728
QStringList options() const;
2829
void setType( QgsRasterFormatSaveOptionsWidget::Type type = Default );
30+
void setPyramidsFormat( QgsRasterDataProvider::RasterPyramidsFormat format );
2931

3032
public slots:
3133

‎python/gui/qgsrasterlayersaveasdialog.sip

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ class QgsRasterLayerSaveAsDialog : QDialog
4848
QgsRectangle outputRectangle() const;
4949
QList<QgsRasterNuller::NoData> noData() const;
5050

51-
QList< int > overviewList() const;
51+
QList< int > pyramidsList() const;
5252
QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const;
53-
QString pyramidsResampling() const;
53+
QString pyramidsResamplingMethod() const;
5454
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const;
55+
QStringList pyramidsConfigOptions() const;
5556

5657
void hideFormat();
5758
void hideOutput();

‎python/gui/qgsrasterpyramidsoptionswidget.sip

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,26 @@ class QgsRasterPyramidsOptionsWidget: QWidget
1212
QgsRasterPyramidsOptionsWidget( QWidget* parent = 0, QString provider = "gdal" );
1313
~QgsRasterPyramidsOptionsWidget();
1414

15-
QStringList createOptions() const;
15+
QStringList configOptions() const;
1616
QgsRasterFormatSaveOptionsWidget* createOptionsWidget() /Factory/;
1717
const QList<int> overviewList() const;
1818
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const;
1919
QString resamplingMethod() const;
20+
void setRasterLayer( QgsRasterLayer* rasterLayer );
21+
void setRasterFileName( const QString& file );
2022

2123
public slots:
2224

2325
void apply();
2426
void checkAllLevels( bool checked );
2527

28+
private slots:
29+
30+
void on_cbxPyramidsLevelsCustom_toggled( bool toggled );
31+
void on_cbxPyramidsFormat_currentIndexChanged( int index );
32+
void setOverviewList();
33+
void updateUi();
34+
2635
signals:
2736
void overviewListChanged();
2837
};

‎src/app/qgisapp.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4204,9 +4204,10 @@ void QgisApp::saveAsRasterFile()
42044204
fileWriter.setCreateOptions( d.createOptions() );
42054205

42064206
fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
4207-
fileWriter.setPyramidsList( d.overviewList() );
4208-
fileWriter.setPyramidsResampling( d.pyramidsResampling() );
4207+
fileWriter.setPyramidsList( d.pyramidsList() );
4208+
fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
42094209
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
4210+
fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );
42104211

42114212
QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe, d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd );
42124213
if ( err != QgsRasterFileWriter::NoError )

‎src/core/qgis.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ const double DEFAULT_LINE_WIDTH = 0.26;
336336
/** default snapping tolerance for segments (@note added in 1.8) */
337337
const double DEFAULT_SEGMENT_EPSILON = 1e-8;
338338

339+
typedef QMap<QString, QString> QgsStringMap;
340+
339341
// FIXME: also in qgisinterface.h
340342
#ifndef QGISEXTERN
341343
#ifdef WIN32

‎src/core/raster/qgsrasterdataprovider.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,63 @@ QString QgsRasterDataProvider::lastErrorFormat()
387387
return "text/plain";
388388
}
389389

390+
// pyramids resampling
391+
392+
// TODO move this to gdal provider
393+
// but we need some way to get a static instance of the provider
394+
// or use function pointers like in QgsRasterFormatSaveOptionsWidget::helpOptions()
395+
396+
// see http://www.gdal.org/gdaladdo.html
397+
// http://www.gdal.org/classGDALDataset.html#a2aa6f88b3bbc840a5696236af11dde15
398+
// http://www.gdal.org/classGDALRasterBand.html#afaea945b13ec9c86c2d783b883c68432
399+
400+
// from http://www.gdal.org/gdaladdo.html
401+
// average_mp is unsuitable for use thus not included
402+
403+
// from qgsgdalprovider.cpp (removed)
404+
// NOTE magphase is disabled in the gui since it tends
405+
// to create corrupted images. The images can be repaired
406+
// by running one of the other resampling strategies below.
407+
// see ticket #284
408+
QStringList QgsRasterDataProvider::mPyramidResamplingListGdal = QStringList();
409+
QgsStringMap QgsRasterDataProvider::mPyramidResamplingMapGdal = QgsStringMap();
410+
411+
void QgsRasterDataProvider::initPyramidResamplingDefs()
412+
{
413+
mPyramidResamplingListGdal.clear();
414+
mPyramidResamplingListGdal << tr( "Nearest Neighbour" ) << tr( "Average" ) << tr( "Gauss" ) << tr( "Cubic" ) << tr( "Mode" ) << tr( "None" ); // << tr( "Average magphase" )
415+
mPyramidResamplingMapGdal.clear();
416+
mPyramidResamplingMapGdal[ tr( "Nearest Neighbour" )] = "NEAREST";
417+
mPyramidResamplingMapGdal[ tr( "Average" )] = "AVERAGE";
418+
mPyramidResamplingMapGdal[ tr( "Gauss" )] = "GAUSS";
419+
mPyramidResamplingMapGdal[ tr( "Cubic" )] = "CUBIC";
420+
mPyramidResamplingMapGdal[ tr( "Mode" )] = "MODE";
421+
// mPyramidResamplingMapGdal[ tr( "Average magphase" ) ] = "average_magphase";
422+
mPyramidResamplingMapGdal[ tr( "None" )] = "NONE" ;
423+
}
424+
425+
QStringList QgsRasterDataProvider::pyramidResamplingMethods( QString providerKey )
426+
{
427+
if ( mPyramidResamplingListGdal.isEmpty() )
428+
initPyramidResamplingDefs();
429+
430+
return providerKey == "gdal" ? mPyramidResamplingListGdal : QStringList();
431+
}
432+
433+
QString QgsRasterDataProvider::pyramidResamplingArg( QString method, QString providerKey )
434+
{
435+
if ( providerKey != "gdal" )
436+
return QString();
437+
438+
if ( mPyramidResamplingListGdal.isEmpty() )
439+
initPyramidResamplingDefs();
440+
441+
if ( mPyramidResamplingMapGdal.contains( method ) )
442+
return mPyramidResamplingMapGdal.value( method );
443+
else
444+
return "NEAREST";
445+
}
446+
390447
bool QgsRasterDataProvider::hasPyramids()
391448
{
392449
QList<QgsRasterPyramid> myPyramidList = buildPyramidList();

‎src/core/raster/qgsrasterdataprovider.h

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -290,11 +290,13 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
290290
}
291291

292292
/** \brief Create pyramid overviews */
293-
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
294-
const QString & theResamplingMethod = "NEAREST",
295-
RasterPyramidsFormat theFormat = PyramidsGTiff )
293+
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
294+
const QString & theResamplingMethod = "NEAREST",
295+
RasterPyramidsFormat theFormat = PyramidsGTiff,
296+
const QStringList & theConfigOptions = QStringList() )
296297
{
297-
Q_UNUSED( thePyramidList ); Q_UNUSED( theResamplingMethod ); Q_UNUSED( theFormat );
298+
Q_UNUSED( thePyramidList ); Q_UNUSED( theResamplingMethod );
299+
Q_UNUSED( theFormat ); Q_UNUSED( theConfigOptions );
298300
return "FAILED_NOT_SUPPORTED";
299301
};
300302

@@ -443,18 +445,23 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
443445
/** Remove dataset*/
444446
virtual bool remove() { return false; }
445447

446-
static QStringList pyramidResamplingMethods( QString providerKey )
447-
{
448-
return providerKey == "gdal" ?
449-
QStringList() << tr( "Average" ) << tr( "Nearest Neighbour" ) << tr( "Gauss" ) <<
450-
tr( "Cubic" ) << tr( "Mode" ) << tr( "None" ) : QStringList();
451-
}
448+
/** Returns a list of pyramid resampling method names for given provider */
449+
static QStringList pyramidResamplingMethods( QString providerKey = "gdal" );
450+
/** Returns the pyramid resampling argument that corresponds to a given method */
451+
static QString pyramidResamplingArg( QString method, QString providerKey = "gdal" );
452452

453-
/** Validates creation options for a specific dataset and destination format - used by GDAL provider only.
454-
* See also validateCreationOptionsFormat() in gdal provider for validating options based on format only. */
453+
/** Validates creation options for a specific dataset and destination format.
454+
* @note used by GDAL provider only
455+
* @note see also validateCreationOptionsFormat() in gdal provider for validating options based on format only */
455456
virtual QString validateCreationOptions( const QStringList& createOptions, QString format )
456457
{ Q_UNUSED( createOptions ); Q_UNUSED( format ); return QString(); }
457458

459+
/** Validates pyramid creation options for a specific dataset and destination format
460+
* @note used by GDAL provider only */
461+
virtual QString validatePyramidsConfigOptions( RasterPyramidsFormat pyramidsFormat,
462+
const QStringList & theConfigOptions, const QString & fileFormat )
463+
{ Q_UNUSED( pyramidsFormat ); Q_UNUSED( theConfigOptions ); Q_UNUSED( fileFormat ); return QString(); }
464+
458465
signals:
459466
/** Emit a signal to notify of the progress event.
460467
* Emited theProgress is in percents (0.0-100.0) */
@@ -496,5 +503,9 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
496503

497504
QgsRectangle mExtent;
498505

506+
static void initPyramidResamplingDefs();
507+
static QStringList mPyramidResamplingListGdal;
508+
static QgsStringMap mPyramidResamplingMapGdal;
509+
499510
};
500511
#endif

‎src/core/raster/qgsrasterfilewriter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,9 +717,10 @@ void QgsRasterFileWriter::buildPyramids( const QString& filename )
717717
myPyramidList[myCounterInt].build = true;
718718
}
719719

720-
QgsDebugMsg( QString( "building pyramids : %1 pyramids, %2 resampling, %3 format" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( mPyramidsFormat ) );
720+
QgsDebugMsg( QString( "building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( mPyramidsFormat ).arg( mPyramidsConfigOptions.count() ) );
721721
// QApplication::setOverrideCursor( Qt::WaitCursor );
722-
QString res = destProvider->buildPyramids( myPyramidList, mPyramidsResampling, mPyramidsFormat );
722+
QString res = destProvider->buildPyramids( myPyramidList, mPyramidsResampling,
723+
mPyramidsFormat, mPyramidsConfigOptions );
723724
// QApplication::restoreOverrideCursor();
724725

725726
// TODO put this in provider or elsewhere

‎src/core/raster/qgsrasterfilewriter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ class CORE_EXPORT QgsRasterFileWriter
8888
void setMaxTileHeight( int h ) { mMaxTileHeight = h; }
8989
int maxTileHeight() const { return mMaxTileHeight; }
9090

91-
// for now not putting createOptions in all methods, use createOptions()
9291
void setCreateOptions( const QStringList& list ) { mCreateOptions = list; }
9392
QStringList createOptions() const { return mCreateOptions; }
9493

94+
void setPyramidsConfigOptions( const QStringList& list ) { mPyramidsConfigOptions = list; }
95+
QStringList pyramidsConfigOptions() const { return mPyramidsConfigOptions; }
96+
9597
private:
9698
QgsRasterFileWriter(); //forbidden
9799
//WriterError writeDataRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
@@ -157,6 +159,7 @@ class CORE_EXPORT QgsRasterFileWriter
157159
QString mPyramidsResampling;
158160
QgsRasterDataProvider::RasterBuildPyramids mBuildPyramidsFlag;
159161
QgsRasterDataProvider::RasterPyramidsFormat mPyramidsFormat;
162+
QStringList mPyramidsConfigOptions;
160163

161164
QDomDocument mVRTDocument;
162165
QList<QDomElement> mVRTBands;

‎src/core/symbology-ng/qgssymbolv2.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class QgsSymbolLayerV2;
3636
class QgsRenderContext;
3737
class QgsVectorLayer;
3838

39-
typedef QMap<QString, QString> QgsStringMap;
4039
typedef QList<QgsSymbolLayerV2*> QgsSymbolLayerV2List;
4140

4241
class CORE_EXPORT QgsSymbolV2

‎src/gui/qgsrasterformatsaveoptionswidget.cpp

Lines changed: 95 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ QMap< QString, QStringList > QgsRasterFormatSaveOptionsWidget::mBuiltinProfiles;
3333

3434
QgsRasterFormatSaveOptionsWidget::QgsRasterFormatSaveOptionsWidget( QWidget* parent, QString format,
3535
QgsRasterFormatSaveOptionsWidget::Type type, QString provider )
36-
: QWidget( parent ), mFormat( format ), mProvider( provider ), mRasterLayer( 0 )
36+
: QWidget( parent ), mFormat( format ), mProvider( provider ), mRasterLayer( 0 ),
37+
mRasterFileName( QString() ), mPyramids( false ),
38+
mPyramidsFormat( QgsRasterDataProvider::PyramidsGTiff )
3739

3840
{
3941
setupUi( this );
@@ -58,8 +60,8 @@ QgsRasterFormatSaveOptionsWidget::QgsRasterFormatSaveOptionsWidget( QWidget* par
5860
( QStringList() << "GTiff" << tr( "High compression" )
5961
<< "COMPRESS=DEFLATE PREDICTOR=2 ZLEVEL=9" );
6062
mBuiltinProfiles[ "z_gtiff_4jpeg" ] =
61-
( QStringList() << "GTiff" << tr( "Lossy compression" )
62-
<< "COMPRESS=JPEG" );
63+
( QStringList() << "GTiff" << tr( "JPEG compression" )
64+
<< "COMPRESS=JPEG JPEG_QUALITY=75" );
6365

6466
// overview compression schemes for GTiff format, see
6567
// http://www.gdal.org/gdaladdo.html and http://www.gdal.org/frmt_gtiff.html
@@ -74,8 +76,8 @@ QgsRasterFormatSaveOptionsWidget::QgsRasterFormatSaveOptionsWidget( QWidget* par
7476
( QStringList() << "_pyramids" << tr( "High compression" )
7577
<< "COMPRESS_OVERVIEW=DEFLATE PREDICTOR_OVERVIEW=2 ZLEVEL=9" ); // how to set zlevel?
7678
mBuiltinProfiles[ "z__pyramids_gtiff_4jpeg" ] =
77-
( QStringList() << "_pyramids" << tr( "Lossy compression" )
78-
<< "COMPRESS_OVERVIEW=JPEG PHOTOMETRIC_OVERVIEW=YCBCR INTERLEAVE_OVERVIEW=PIXEL" );
79+
( QStringList() << "_pyramids" << tr( "JPEG compression" )
80+
<< "JPEG_QUALITY_OVERVIEW=75 COMPRESS_OVERVIEW=JPEG PHOTOMETRIC_OVERVIEW=YCBCR INTERLEAVE_OVERVIEW=PIXEL" );
7981
}
8082

8183
connect( mProfileComboBox, SIGNAL( currentIndexChanged( const QString & ) ),
@@ -91,6 +93,8 @@ QgsRasterFormatSaveOptionsWidget::QgsRasterFormatSaveOptionsWidget( QWidget* par
9193

9294
updateControls();
9395
updateProfiles();
96+
97+
QgsDebugMsg( "done" );
9498
}
9599

96100
QgsRasterFormatSaveOptionsWidget::~QgsRasterFormatSaveOptionsWidget()
@@ -123,7 +127,7 @@ void QgsRasterFormatSaveOptionsWidget::setType( QgsRasterFormatSaveOptionsWidget
123127
foreach ( QWidget* widget, mOptionsStackedWidget->findChildren<QWidget *>() )
124128
widget->setVisible( true );
125129

126-
// show elevant page
130+
// show relevant page
127131
if ( type == Table )
128132
swapOptionsUI( 0 );
129133
else if ( type == LineEdit )
@@ -146,17 +150,20 @@ void QgsRasterFormatSaveOptionsWidget::setType( QgsRasterFormatSaveOptionsWidget
146150
void QgsRasterFormatSaveOptionsWidget::updateProfiles()
147151
{
148152
// build profiles list = user + builtin(last)
153+
QString format = mPyramids ? "_pyramids" : mFormat;
149154
QStringList profileKeys = profiles();
150155
QMapIterator<QString, QStringList> it( mBuiltinProfiles );
151156
while ( it.hasNext() )
152157
{
153158
it.next();
154159
QString profileKey = it.key();
155-
if ( ! profileKeys.contains( profileKey ) )
160+
if ( ! profileKeys.contains( profileKey ) && it.value().count() > 0 )
156161
{
157162
// insert key if is for all formats or this format (GTiff)
158-
if ( it.value()[0] == "" || it.value()[0] == mFormat )
163+
if ( it.value()[0] == "" || it.value()[0] == format )
164+
{
159165
profileKeys.insert( 0, profileKey );
166+
}
160167
}
161168
}
162169
qSort( profileKeys );
@@ -188,7 +195,7 @@ void QgsRasterFormatSaveOptionsWidget::updateProfiles()
188195
// mProfileComboBox->setCurrentIndex( 0 );
189196
QSettings mySettings;
190197
mProfileComboBox->setCurrentIndex( mProfileComboBox->findData( mySettings.value(
191-
mProvider + "/driverOptions/" + mFormat.toLower() + "/defaultProfile",
198+
mProvider + "/driverOptions/" + format.toLower() + "/defaultProfile",
192199
"z_adefault" ) ) );
193200
updateOptions();
194201
}
@@ -217,6 +224,8 @@ void QgsRasterFormatSaveOptionsWidget::updateOptions()
217224
mOptionsLineEdit->setText( myOptions );
218225
mOptionsLineEdit->setCursorPosition( 0 );
219226
}
227+
228+
emit optionsChanged();
220229
}
221230

222231
void QgsRasterFormatSaveOptionsWidget::apply()
@@ -232,7 +241,7 @@ void QgsRasterFormatSaveOptionsWidget::helpOptions()
232241
{
233242
QString message;
234243

235-
if ( mProvider == "gdal" && mFormat != "" && mFormat != "_pyramids" )
244+
if ( mProvider == "gdal" && mFormat != "" && ! mPyramids )
236245
{
237246
// get helpCreationOptionsFormat() function ptr for provider
238247
QLibrary *library = QgsProviderRegistry::instance()->providerLibrary( mProvider );
@@ -256,14 +265,19 @@ void QgsRasterFormatSaveOptionsWidget::helpOptions()
256265
if ( message.isEmpty() )
257266
message = tr( "Cannot get create options for driver %1" ).arg( mFormat );
258267
}
268+
else if ( mProvider == "gdal" && mPyramids )
269+
{
270+
message = tr( "For details on pyramids options please see the following pages" );
271+
message += "\n\nhttp://www.gdal.org/gdaladdo.html\n\nhttp://www.gdal.org/frmt_gtiff.html";
272+
}
259273
else
260274
message = tr( "No help available" );
261275

262276
// show simple non-modal dialog - should we make the basic xml prettier?
263277
QgsDialog *dlg = new QgsDialog( this );
264278
QTextEdit *textEdit = new QTextEdit( dlg );
265279
textEdit->setReadOnly( true );
266-
message = tr( "Create Options:\n\n%1" ).arg( message );
280+
// message = tr( "Create Options:\n\n%1" ).arg( message );
267281
textEdit->setText( message );
268282
dlg->layout()->addWidget( textEdit );
269283
dlg->resize( 600, 400 );
@@ -275,12 +289,49 @@ QString QgsRasterFormatSaveOptionsWidget::validateOptions( bool gui, bool report
275289
QStringList createOptions = options();
276290
QString message;
277291

278-
if ( !createOptions.isEmpty() && mProvider == "gdal" && mFormat != "" && mFormat != "_pyramids" )
292+
QgsDebugMsg( QString( "layer: [%1] file: [%2] format: [%3]" ).arg( mRasterLayer ? mRasterLayer->id() : "none" ).arg( mRasterFileName ).arg( mFormat ) );
293+
// if no rasterLayer is defined, but we have a raster fileName, then create a temp. rasterLayer to validate options
294+
// ideally we should keep it for future access, but this is trickier
295+
QgsRasterLayer* rasterLayer = mRasterLayer;
296+
bool tmpLayer = false;
297+
if ( !( mRasterLayer && rasterLayer->dataProvider() ) && ! mRasterFileName.isNull() )
298+
{
299+
// temporarily override /Projections/defaultBehaviour to avoid dialog prompt
300+
// this is taken from qgsbrowserdockwidget.cpp
301+
// TODO - integrate this into qgis core
302+
QSettings settings;
303+
QString defaultProjectionOption = settings.value( "/Projections/defaultBehaviour", "prompt" ).toString();
304+
if ( settings.value( "/Projections/defaultBehaviour", "prompt" ).toString() == "prompt" )
305+
{
306+
settings.setValue( "/Projections/defaultBehaviour", "useProject" );
307+
}
308+
tmpLayer = true;
309+
rasterLayer = new QgsRasterLayer( mRasterFileName, QFileInfo( mRasterFileName ).baseName(), "gdal" );
310+
// restore /Projections/defaultBehaviour
311+
if ( defaultProjectionOption == "prompt" )
312+
{
313+
settings.setValue( "/Projections/defaultBehaviour", defaultProjectionOption );
314+
}
315+
}
316+
317+
if ( mProvider == "gdal" && mPyramids )
318+
{
319+
if ( rasterLayer && rasterLayer->dataProvider() )
320+
{
321+
QgsDebugMsg( "calling validate pyramids on layer's data provider" );
322+
message = rasterLayer->dataProvider()->validatePyramidsConfigOptions( mPyramidsFormat, createOptions, mFormat );
323+
}
324+
else
325+
{
326+
message = tr( "cannot validate pyramid options" );
327+
}
328+
}
329+
else if ( !createOptions.isEmpty() && mProvider == "gdal" && mFormat != "" )
279330
{
280-
if ( mRasterLayer )
331+
if ( rasterLayer && rasterLayer->dataProvider() )
281332
{
282333
QgsDebugMsg( "calling validate on layer's data provider" );
283-
message = mRasterLayer->dataProvider()->validateCreationOptions( createOptions, mFormat );
334+
message = rasterLayer->dataProvider()->validateCreationOptions( createOptions, mFormat );
284335
}
285336
else
286337
{
@@ -302,24 +353,30 @@ QString QgsRasterFormatSaveOptionsWidget::validateOptions( bool gui, bool report
302353
else
303354
message = QString( "cannot load provider library %1" ).arg( mProvider );
304355
}
356+
}
357+
else if ( ! createOptions.isEmpty() )
358+
{
359+
QMessageBox::information( this, "", tr( "Cannot validate creation options" ), QMessageBox::Close );
360+
if ( tmpLayer )
361+
delete rasterLayer;
362+
return QString();
363+
}
305364

306-
if ( gui )
365+
if ( gui )
366+
{
367+
if ( message.isNull() )
307368
{
308-
if ( message.isNull() )
309-
{
310-
if ( reportOK )
311-
QMessageBox::information( this, "", tr( "Valid" ), QMessageBox::Close );
312-
}
313-
else
314-
{
315-
QMessageBox::warning( this, "", tr( "Invalid creation option :\n\n%1\n\nClick on help button to get valid creation options for this format" ).arg( message ), QMessageBox::Close );
316-
}
369+
if ( reportOK )
370+
QMessageBox::information( this, "", tr( "Valid" ), QMessageBox::Close );
371+
}
372+
else
373+
{
374+
QMessageBox::warning( this, "", tr( "Invalid%1creation option :\n\n%2\n\nClick on help button to get valid creation options for this format" ).arg( mPyramids ? " pyramids " : " " ).arg( message ), QMessageBox::Close );
317375
}
318376
}
319-
else
320-
{
321-
QMessageBox::information( this, "", tr( "Cannot validate" ), QMessageBox::Close );
322-
}
377+
378+
if ( tmpLayer )
379+
delete rasterLayer;
323380

324381
return message;
325382
}
@@ -508,9 +565,9 @@ void QgsRasterFormatSaveOptionsWidget::swapOptionsUI( int newIndex )
508565

509566
void QgsRasterFormatSaveOptionsWidget::updateControls()
510567
{
511-
bool enabled = ( mProvider == "gdal" && mFormat != "" && mFormat != "_pyramids" );
512-
mOptionsValidateButton->setEnabled( enabled );
513-
mOptionsHelpButton->setEnabled( enabled );
568+
bool valid = mProvider == "gdal" && mFormat != "";
569+
mOptionsValidateButton->setEnabled( valid );
570+
mOptionsHelpButton->setEnabled( valid );
514571
}
515572

516573
// map options label left mouse click to optionsToggle()
@@ -546,3 +603,10 @@ bool QgsRasterFormatSaveOptionsWidget::eventFilter( QObject *obj, QEvent *event
546603
return QObject::eventFilter( obj, event );
547604
}
548605

606+
void QgsRasterFormatSaveOptionsWidget::showEvent( QShowEvent * event )
607+
{
608+
Q_UNUSED( event );
609+
mOptionsTable->horizontalHeader()->resizeSection( 0, mOptionsTable->width() - 115 );
610+
QgsDebugMsg( "done" );
611+
}
612+

‎src/gui/qgsrasterformatsaveoptionswidget.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#include "ui_qgsrasterformatsaveoptionswidgetbase.h"
2222

23+
#include "qgsrasterdataprovider.h"
24+
2325
class QgsRasterLayer;
2426

2527
/** \ingroup gui
@@ -48,9 +50,12 @@ class GUI_EXPORT QgsRasterFormatSaveOptionsWidget: public QWidget,
4850

4951
void setFormat( QString format );
5052
void setProvider( QString provider );
51-
void setRasterLayer( QgsRasterLayer* rasterLayer ) { mRasterLayer = rasterLayer; }
53+
void setRasterLayer( QgsRasterLayer* rasterLayer ) { mRasterLayer = rasterLayer; mRasterFileName = QString(); }
54+
void setRasterFileName( const QString& file ) { mRasterLayer = 0; mRasterFileName = file; }
5255
QStringList options() const;
5356
void setType( QgsRasterFormatSaveOptionsWidget::Type type = Default );
57+
void setPyramidsFormat( QgsRasterDataProvider::RasterPyramidsFormat format )
58+
{ mPyramids = true; mPyramidsFormat = format; }
5459

5560
public slots:
5661

@@ -73,13 +78,22 @@ class GUI_EXPORT QgsRasterFormatSaveOptionsWidget: public QWidget,
7378
void swapOptionsUI( int newIndex = -1 );
7479
void updateControls();
7580

81+
protected:
82+
virtual void showEvent( QShowEvent * event );
83+
84+
signals:
85+
void optionsChanged();
86+
7687
private:
7788

7889
QString mFormat;
7990
QString mProvider;
8091
QgsRasterLayer* mRasterLayer;
92+
QString mRasterFileName;
8193
QMap< QString, QString> mOptionsMap;
8294
static QMap< QString, QStringList > mBuiltinProfiles;
95+
bool mPyramids;
96+
QgsRasterDataProvider::RasterPyramidsFormat mPyramidsFormat;
8397

8498
QString settingsKey( QString profile ) const;
8599
QString currentProfileKey() const;

‎src/gui/qgsrasterlayersaveasdialog.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer* rasterLa
8585
mMaximumSizeYLineEdit->setText( QString::number( 2000 ) );
8686
}
8787

88+
// setup creation option widget
8889
mCreateOptionsWidget->setProvider( mDataProvider->name() );
8990
if ( mDataProvider->name() == "gdal" )
9091
{
@@ -97,7 +98,9 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer* rasterLa
9798
// Only do pyramids if dealing directly with GDAL.
9899
if ( mDataProvider->capabilities() & QgsRasterDataProvider::BuildPyramids )
99100
{
100-
mPyramidsOptionsWidget->createOptionsWidget()->setType( QgsRasterFormatSaveOptionsWidget::ProfileLineEdit );
101+
// setup pyramids option widget
102+
// mPyramidsOptionsWidget->createOptionsWidget()->setType( QgsRasterFormatSaveOptionsWidget::ProfileLineEdit );
103+
mPyramidsOptionsWidget->createOptionsWidget()->setRasterLayer( mRasterLayer );
101104

102105
// TODO enable "use existing", has no effect for now, because using Create() in gdal provider
103106
// if ( ! mDataProvider->hasPyramids() )
@@ -732,12 +735,13 @@ void QgsRasterLayerSaveAsDialog::on_mPyramidsGroupBox_toggled( bool toggled )
732735

733736
void QgsRasterLayerSaveAsDialog::populatePyramidsLevels()
734737
{
735-
// if selection != "Build pyramids", get pyramids from actual layer
736738
QString text;
737739

738740
if ( mPyramidsGroupBox->isChecked() )
739741
{
740742
QList<QgsRasterPyramid> myPyramidList;
743+
// if use existing, get pyramids from actual layer
744+
// but that's not available yet
741745
if ( mPyramidsUseExistingCheckBox->isChecked() )
742746
{
743747
myPyramidList = mDataProvider->buildPyramidList();
@@ -752,7 +756,7 @@ void QgsRasterLayerSaveAsDialog::populatePyramidsLevels()
752756
myRasterPyramidIterator != myPyramidList.end();
753757
++myRasterPyramidIterator )
754758
{
755-
if ( myRasterPyramidIterator->exists )
759+
if ( ! mPyramidsUseExistingCheckBox->isChecked() || myRasterPyramidIterator->exists )
756760
{
757761
text += QString::number( myRasterPyramidIterator->xDim ) + QString( "x" ) +
758762
QString::number( myRasterPyramidIterator->yDim ) + " ";
@@ -809,7 +813,7 @@ QList<QgsRasterNuller::NoData> QgsRasterLayerSaveAsDialog::noData() const
809813
return noDataList;
810814
}
811815

812-
QList<int> QgsRasterLayerSaveAsDialog::overviewList() const
816+
QList<int> QgsRasterLayerSaveAsDialog::pyramidsList() const
813817
{
814818
return mPyramidsGroupBox->isChecked() ? mPyramidsOptionsWidget->overviewList() : QList<int>();
815819
}
@@ -832,6 +836,12 @@ bool QgsRasterLayerSaveAsDialog::validate() const
832836
if ( !message.isNull() )
833837
return false;
834838
}
839+
if ( mPyramidsGroupBox->isChecked() )
840+
{
841+
QString message = mPyramidsOptionsWidget->createOptionsWidget()->validateOptions( true, false );
842+
if ( !message.isNull() )
843+
return false;
844+
}
835845
return true;
836846
}
837847

‎src/gui/qgsrasterlayersaveasdialog.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,13 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
7272
QgsRectangle outputRectangle() const;
7373
QList<QgsRasterNuller::NoData> noData() const;
7474

75-
QList< int > overviewList() const;
75+
QList< int > pyramidsList() const;
7676
QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const;
77-
QString pyramidsResampling() const { return mPyramidsOptionsWidget->resamplingMethod(); }
77+
QString pyramidsResamplingMethod() const { return mPyramidsOptionsWidget->resamplingMethod(); }
7878
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const
7979
{ return mPyramidsOptionsWidget->pyramidsFormat(); }
80+
QStringList pyramidsConfigOptions() const
81+
{ return mPyramidsOptionsWidget->configOptions(); }
8082

8183
void hideFormat();
8284
void hideOutput();

‎src/gui/qgsrasterpyramidsoptionswidget.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ QgsRasterPyramidsOptionsWidget::QgsRasterPyramidsOptionsWidget( QWidget* parent,
3333
{
3434
setupUi( this );
3535

36-
mPyramidsOptionsWidget->setProvider( provider );
37-
mPyramidsOptionsWidget->setFormat( "_pyramids" );
38-
// mPyramidsOptionsWidget->swapOptionsUI( 1 );
36+
mSaveOptionsWidget->setProvider( provider );
37+
mSaveOptionsWidget->setPyramidsFormat( QgsRasterDataProvider::PyramidsGTiff );
38+
mSaveOptionsWidget->setType( QgsRasterFormatSaveOptionsWidget::ProfileLineEdit );
3939

4040
updateUi();
4141
}
@@ -68,8 +68,9 @@ void QgsRasterPyramidsOptionsWidget::updateUi()
6868
mySettings.value( prefix + "resampling", "Average" ).toString() ) );
6969

7070
// validate string, only space-separated positive integers are allowed
71+
lePyramidsLevels->setEnabled( cbxPyramidsLevelsCustom->isChecked() );
7172
lePyramidsLevels->setValidator( new QRegExpValidator( QRegExp( "(\\d*)(\\s\\d*)*" ), lePyramidsLevels ) );
72-
connect( lePyramidsLevels, SIGNAL( editingFinished() ),
73+
connect( lePyramidsLevels, SIGNAL( textEdited( const QString & ) ),
7374
this, SLOT( setOverviewList() ) );
7475

7576
// overview list
@@ -99,14 +100,19 @@ void QgsRasterPyramidsOptionsWidget::updateUi()
99100
}
100101
setOverviewList();
101102

102-
mPyramidsOptionsWidget->updateProfiles();
103-
}
104-
103+
mSaveOptionsWidget->updateProfiles();
105104

105+
connect( cbxPyramidsFormat, SIGNAL( currentIndexChanged( int ) ),
106+
this, SIGNAL( someValueChanged() ) );
107+
connect( cboResamplingMethod, SIGNAL( currentIndexChanged( int ) ),
108+
this, SIGNAL( someValueChanged() ) );
109+
connect( mSaveOptionsWidget, SIGNAL( optionsChanged() ),
110+
this, SIGNAL( someValueChanged() ) );
111+
}
106112

107113
QString QgsRasterPyramidsOptionsWidget::resamplingMethod() const
108114
{
109-
return cboResamplingMethod->currentText().trimmed();
115+
return QgsRasterDataProvider::pyramidResamplingArg( cboResamplingMethod->currentText().trimmed() );
110116
}
111117

112118
void QgsRasterPyramidsOptionsWidget::apply()
@@ -135,7 +141,7 @@ void QgsRasterPyramidsOptionsWidget::apply()
135141
}
136142
mySettings.setValue( prefix + "overviewList", tmpStr.trimmed() );
137143

138-
mPyramidsOptionsWidget->apply();
144+
mSaveOptionsWidget->apply();
139145
}
140146

141147
void QgsRasterPyramidsOptionsWidget::checkAllLevels( bool checked )
@@ -153,13 +159,19 @@ void QgsRasterPyramidsOptionsWidget::on_cbxPyramidsLevelsCustom_toggled( bool to
153159
setOverviewList();
154160
}
155161

162+
void QgsRasterPyramidsOptionsWidget::on_cbxPyramidsFormat_currentIndexChanged( int index )
163+
{
164+
mSaveOptionsWidget->setEnabled( index != 2 );
165+
mSaveOptionsWidget->setPyramidsFormat(( QgsRasterDataProvider::RasterPyramidsFormat ) index );
166+
}
167+
156168
void QgsRasterPyramidsOptionsWidget::setOverviewList()
157169
{
158170
QgsDebugMsg( "Entered" );
159171

160172
mOverviewList.clear();
161173

162-
// if custum levels is toggled, get selection from line edit
174+
// if custom levels is toggled, get selection from line edit
163175
if ( cbxPyramidsLevelsCustom->isChecked() )
164176
{
165177
// should we also validate that numbers are increasing?

‎src/gui/qgsrasterpyramidsoptionswidget.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ class GUI_EXPORT QgsRasterPyramidsOptionsWidget: public QWidget,
3636
QgsRasterPyramidsOptionsWidget( QWidget* parent = 0, QString provider = "gdal" );
3737
~QgsRasterPyramidsOptionsWidget();
3838

39-
QStringList createOptions() const { return mPyramidsOptionsWidget->options(); }
40-
QgsRasterFormatSaveOptionsWidget* createOptionsWidget() { return mPyramidsOptionsWidget; }
39+
QStringList configOptions() const { return mSaveOptionsWidget->options(); }
40+
QgsRasterFormatSaveOptionsWidget* createOptionsWidget() { return mSaveOptionsWidget; }
4141
const QList<int> overviewList() const { return mOverviewList; }
4242
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const
4343
{ return ( QgsRasterDataProvider::RasterPyramidsFormat ) cbxPyramidsFormat->currentIndex(); }
4444
QString resamplingMethod() const;
45+
void setRasterLayer( QgsRasterLayer* rasterLayer ) { mSaveOptionsWidget->setRasterLayer( rasterLayer ); }
46+
void setRasterFileName( const QString& file ) { mSaveOptionsWidget->setRasterFileName( file ); }
4547

4648
public slots:
4749

@@ -51,17 +53,16 @@ class GUI_EXPORT QgsRasterPyramidsOptionsWidget: public QWidget,
5153
private slots:
5254

5355
void on_cbxPyramidsLevelsCustom_toggled( bool toggled );
54-
void on_cbxPyramidsFormat_currentIndexChanged( int index )
55-
{ mPyramidsOptionsWidget->setEnabled( index != 2 ); }
56+
void on_cbxPyramidsFormat_currentIndexChanged( int index );
5657
void setOverviewList();
58+
void updateUi();
5759

5860
signals:
5961
void overviewListChanged();
62+
void someValueChanged(); /* emitted when any other setting changes */
6063

6164
private:
6265

63-
void updateUi();
64-
6566
QString mProvider;
6667
QList< int > mOverviewList;
6768
QMap< int, QCheckBox* > mOverviewCheckBoxes;

‎src/providers/gdal/qgsgdalprovider.cpp

Lines changed: 108 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,8 +1321,9 @@ QgsRasterHistogram QgsGdalProvider::histogram( int theBandNo,
13211321
* @param theTryInternalFlag - Try to make the pyramids internal if supported (e.g. geotiff). If not supported it will revert to creating external .ovr file anyway.
13221322
* @return null string on success, otherwise a string specifying error
13231323
*/
1324-
QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRasterPyramidList,
1325-
QString const & theResamplingMethod, RasterPyramidsFormat theFormat )
1324+
QString QgsGdalProvider::buildPyramids( const QList<QgsRasterPyramid> & theRasterPyramidList,
1325+
const QString & theResamplingMethod, RasterPyramidsFormat theFormat,
1326+
const QStringList & theConfigOptions )
13261327
{
13271328
//TODO: Consider making theRasterPyramidList modifyable by this method to indicate if the pyramid exists after build attempt
13281329
//without requiring the user to rebuild the pyramid list to get the updated infomation
@@ -1337,14 +1338,6 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
13371338

13381339
// TODO add signal and connect from rasterlayer
13391340
//emit drawingProgress( 0, 0 );
1340-
//first test if the file is writable
1341-
//QFileInfo myQFile( mDataSource );
1342-
QFileInfo myQFile( dataSourceUri() );
1343-
1344-
if ( !myQFile.isWritable() )
1345-
{
1346-
return "ERROR_WRITE_ACCESS";
1347-
}
13481341

13491342
if ( mGdalDataset != mGdalBaseDataset )
13501343
{
@@ -1355,6 +1348,16 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
13551348
// check if building internally
13561349
if ( theFormat == PyramidsInternal )
13571350
{
1351+
1352+
// test if the file is writable
1353+
//QFileInfo myQFile( mDataSource );
1354+
QFileInfo myQFile( dataSourceUri() );
1355+
1356+
if ( !myQFile.isWritable() )
1357+
{
1358+
return "ERROR_WRITE_ACCESS";
1359+
}
1360+
13581361
// libtiff < 4.0 has a bug that prevents safe building of overviews on JPEG compressed files
13591362
// we detect libtiff < 4.0 by checking that BIGTIFF is not in the creation options of the GTiff driver
13601363
// see https://trac.osgeo.org/qgis/ticket/1357
@@ -1369,9 +1372,12 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
13691372
}
13701373
}
13711374

1372-
//if needed close the gdal dataset and reopen it in read / write mode
1375+
// if needed close the gdal dataset and reopen it in read / write mode
1376+
// TODO this doesn't seem to work anymore... must fix it before 2.0!!!
1377+
// no errors are reported, but pyramids are not present in file.
13731378
if ( GDALGetAccess( mGdalDataset ) == GA_ReadOnly )
13741379
{
1380+
QgsDebugMsg( "re-opening the dataset in read/write mode" );
13751381
GDALClose( mGdalDataset );
13761382
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri() ).constData(), GA_Update );
13771383

@@ -1389,12 +1395,29 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
13891395
}
13901396

13911397
// are we using Erdas Imagine external overviews?
1392-
char* myConfigUseRRD = strdup( CPLGetConfigOption( "USE_RRD", "NO" ) );
1398+
QgsStringMap myConfigOptionsOld;
1399+
myConfigOptionsOld[ "USE_RRD" ] = CPLGetConfigOption( "USE_RRD", "NO" );
13931400
if ( theFormat == PyramidsErdas )
13941401
CPLSetConfigOption( "USE_RRD", "YES" );
13951402
else
13961403
CPLSetConfigOption( "USE_RRD", "NO" );
13971404

1405+
// add any driver-specific configuration options, save values to be restored later
1406+
if ( theFormat != PyramidsErdas && ! theConfigOptions.isEmpty() )
1407+
{
1408+
foreach ( QString option, theConfigOptions )
1409+
{
1410+
QStringList opt = option.split( "=" );
1411+
QByteArray key = opt[0].toLocal8Bit();
1412+
QByteArray value = opt[1].toLocal8Bit();
1413+
// save previous value
1414+
myConfigOptionsOld[ opt[0] ] = QString( CPLGetConfigOption( key.data(), NULL ) );
1415+
// set temp. value
1416+
CPLSetConfigOption( key.data(), value.data() );
1417+
QgsDebugMsg( QString( "set option %1=%2" ).arg( key.data() ).arg( value.data() ) );
1418+
}
1419+
}
1420+
13981421
//
13991422
// Iterate through the Raster Layer Pyramid Vector, building any pyramid
14001423
// marked as exists in each RasterPyramid struct.
@@ -1420,36 +1443,20 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
14201443
myOverviewLevelsVector.append( myRasterPyramidIterator->level );
14211444
}
14221445
}
1423-
/* From : http://remotesensing.org/gdal/classGDALDataset.html#a23
1424-
* pszResampling : one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE", "AVERAGE_MAGPHASE" or "NONE"
1425-
* controlling the downsampling method applied.
1446+
/* From : http://www.gdal.org/classGDALDataset.html#a2aa6f88b3bbc840a5696236af11dde15
1447+
* pszResampling : one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE", "AVERAGE_MAGPHASE" or "NONE" controlling the downsampling method applied.
14261448
* nOverviews : number of overviews to build.
14271449
* panOverviewList : the list of overview decimation factors to build.
1428-
* nBand : number of bands to build overviews for in panBandList. Build for all bands if this is 0.
1450+
* nListBands : number of bands to build overviews for in panBandList. Build for all bands if this is 0.
14291451
* panBandList : list of band numbers.
14301452
* pfnProgress : a function to call to report progress, or NULL.
14311453
* pProgressData : application data to pass to the progress function.
14321454
*/
14331455

1434-
const char* theMethod;
1435-
if ( theResamplingMethod == tr( "Gauss" ) )
1436-
theMethod = "GAUSS";
1437-
else if ( theResamplingMethod == tr( "Cubic" ) )
1438-
theMethod = "CUBIC";
1439-
else if ( theResamplingMethod == tr( "Average" ) )
1440-
theMethod = "AVERAGE";
1441-
else if ( theResamplingMethod == tr( "Mode" ) )
1442-
theMethod = "MODE";
1443-
//NOTE magphase is disabled in the gui since it tends
1444-
//to create corrupted images. The images can be repaired
1445-
//by running one of the other resampling strategies below.
1446-
//see ticket #284
1447-
// else if ( theResamplingMethod == tr( "Average Magphase" ) )
1448-
// theMethod = "AVERAGE_MAGPHASE";
1449-
else if ( theResamplingMethod == tr( "None" ) )
1450-
theMethod = "NONE";
1451-
else // fall back to nearest neighbor
1452-
theMethod = "NEAREST";
1456+
// resampling method is now passed directly, via QgsRasterDataProvider::pyramidResamplingArg()
1457+
// average_mp and average_magphase have been removed from the gui
1458+
QByteArray ba = theResamplingMethod.toLocal8Bit();
1459+
const char *theMethod = ba.data();
14531460

14541461
//build the pyramid and show progress to console
14551462
QgsDebugMsg( QString( "Building overviews at %1 levels using resampling method %2"
@@ -1467,7 +1474,7 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
14671474

14681475
if ( myError == CE_Failure || CPLGetLastErrorNo() == CPLE_NotSupported )
14691476
{
1470-
QgsDebugMsg( "Building pyramids failed" );
1477+
QgsDebugMsg( QString( "Building pyramids failed using resampling method [%1]" ).arg( theMethod ) );
14711478
//something bad happenend
14721479
//QString myString = QString (CPLGetLastError());
14731480
GDALClose( mGdalBaseDataset );
@@ -1476,9 +1483,17 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
14761483
mGdalDataset = mGdalBaseDataset;
14771484

14781485
//emit drawingProgress( 0, 0 );
1479-
// restore former USE_RRD config (Erdas)
1480-
CPLSetConfigOption( "USE_RRD", myConfigUseRRD );
1481-
free( myConfigUseRRD );
1486+
1487+
// restore former configOptions
1488+
for ( QgsStringMap::const_iterator it = myConfigOptionsOld.begin();
1489+
it != myConfigOptionsOld.end(); ++it )
1490+
{
1491+
QByteArray key = it.key().toLocal8Bit();
1492+
QByteArray value = it.value().toLocal8Bit();
1493+
CPLSetConfigOption( key.data(), value.data() );
1494+
}
1495+
1496+
// TODO print exact error message
14821497
return "FAILED_NOT_SUPPORTED";
14831498
}
14841499
else
@@ -1493,9 +1508,14 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
14931508
QgsLogger::warning( "Pyramid overview building failed!" );
14941509
}
14951510

1496-
// restore former USE_RRD config (Erdas)
1497-
CPLSetConfigOption( "USE_RRD", myConfigUseRRD );
1498-
free( myConfigUseRRD );
1511+
// restore former configOptions
1512+
for ( QgsStringMap::const_iterator it = myConfigOptionsOld.begin();
1513+
it != myConfigOptionsOld.end(); ++it )
1514+
{
1515+
QByteArray key = it.key().toLocal8Bit();
1516+
QByteArray value = it.value().toLocal8Bit();
1517+
CPLSetConfigOption( key.data(), value.data() );
1518+
}
14991519

15001520
QgsDebugMsg( "Pyramid overviews built" );
15011521

@@ -2521,13 +2541,21 @@ QGISEXTERN QString helpCreationOptionsFormat( QString format )
25212541
GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
25222542
if ( myGdalDriver )
25232543
{
2524-
// need to serialize xml to get newlines
2525-
// should we make the basic xml prettier?
2544+
// first report details and help page
2545+
char ** GDALmetadata = GDALGetMetadata( myGdalDriver, NULL );
2546+
message += "Format Details:\n";
2547+
message += QString( " Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
2548+
message += QString( " Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
2549+
message += QString( " / Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
2550+
message += QString( " Help page: http://www.gdal.org/%1\n\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_HELPTOPIC ) );
2551+
2552+
// next get creation options
2553+
// need to serialize xml to get newlines, should we make the basic xml prettier?
25262554
CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
25272555
GDAL_DMD_CREATIONOPTIONLIST, "" ) );
25282556
char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
25292557
if ( pszFormattedXML )
2530-
message = QString( pszFormattedXML );
2558+
message += QString( pszFormattedXML );
25312559
if ( psCOL )
25322560
CPLDestroyXMLNode( psCOL );
25332561
if ( pszFormattedXML )
@@ -2608,3 +2636,38 @@ QString QgsGdalProvider::validateCreationOptions( const QStringList& createOptio
26082636

26092637
return message;
26102638
}
2639+
2640+
QString QgsGdalProvider::validatePyramidsCreationOptions( RasterPyramidsFormat pyramidsFormat,
2641+
const QStringList & theConfigOptions, const QString & fileFormat )
2642+
{
2643+
// Erdas Imagine format does not support config options
2644+
if ( pyramidsFormat == PyramidsErdas )
2645+
{
2646+
if ( ! theConfigOptions.isEmpty() )
2647+
return "Erdas Imagine format does not support config options";
2648+
else
2649+
return QString();
2650+
}
2651+
// Internal pyramids format only supported for gtiff/georaster/hfa/jp2kak/mrsid/nitf files
2652+
else if ( pyramidsFormat == PyramidsInternal )
2653+
{
2654+
QStringList supportedFormats;
2655+
supportedFormats << "gtiff" << "georaster" << "hfa" << "jp2kak" << "mrsid" << "nitf";
2656+
if ( ! supportedFormats.contains( fileFormat.toLower() ) )
2657+
return QString( "Internal pyramids format only supported for gtiff/georaster/hfa/jp2kak/mrsid/nitf files (using %1)" ).arg( fileFormat );
2658+
// TODO - check arguments for georaster hfa jp2kak mrsid nitf
2659+
// for now, only test gtiff
2660+
else if ( fileFormat.toLower() != "gtiff" )
2661+
return QString();
2662+
}
2663+
2664+
// for gtiff external or internal pyramids, validate gtiff-specific values
2665+
// PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)
2666+
if ( theConfigOptions.contains( "PHOTOMETRIC_OVERVIEW=YCBCR" ) )
2667+
{
2668+
if ( GDALGetRasterCount( mGdalDataset ) != 3 )
2669+
return "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)";
2670+
}
2671+
2672+
return QString();
2673+
}

‎src/providers/gdal/qgsgdalprovider.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,10 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
221221
int theSampleSize = 0,
222222
bool theIncludeOutOfRange = false );
223223

224-
QString buildPyramids( const QList<QgsRasterPyramid> &,
225-
const QString & theResamplingMethod = "NEAREST",
226-
RasterPyramidsFormat theFormat = PyramidsGTiff );
224+
QString buildPyramids( const QList<QgsRasterPyramid> & theRasterPyramidList,
225+
const QString & theResamplingMethod = "NEAREST",
226+
RasterPyramidsFormat theFormat = PyramidsGTiff,
227+
const QStringList & theCreateOptions = QStringList() );
227228
QList<QgsRasterPyramid> buildPyramidList( QList<int> overviewList = QList<int>() );
228229

229230
/** \brief Close data set and release related data */
@@ -257,6 +258,8 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
257258
bool remove();
258259

259260
QString validateCreationOptions( const QStringList& createOptions, QString format );
261+
QString validatePyramidsCreationOptions( RasterPyramidsFormat pyramidsFormat,
262+
const QStringList & theConfigOptions, const QString & fileFormat );
260263

261264
signals:
262265
void statusChanged( QString );
@@ -314,6 +317,7 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
314317

315318
/** \brief sublayers list saved for subsequent access */
316319
QStringList mSubLayers;
320+
317321
};
318322

319323
#endif

‎src/ui/qgsrasterpyramidsoptionswidgetbase.ui

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<x>0</x>
88
<y>0</y>
99
<width>366</width>
10-
<height>171</height>
10+
<height>156</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -17,14 +17,17 @@
1717
<property name="margin">
1818
<number>1</number>
1919
</property>
20-
<item row="3" column="0">
21-
<widget class="QCheckBox" name="cbxPyramidsLevelsCustom">
22-
<property name="text">
23-
<string>Custom levels</string>
20+
<item row="4" column="2">
21+
<widget class="QLineEdit" name="lePyramidsLevels">
22+
<property name="toolTip">
23+
<string>Insert positive integer values separated by spaces</string>
2424
</property>
2525
</widget>
2626
</item>
27-
<item row="0" column="2">
27+
<item row="3" column="2">
28+
<layout class="QHBoxLayout" name="layoutPyramidsLevels"/>
29+
</item>
30+
<item row="1" column="2">
2831
<widget class="QComboBox" name="cbxPyramidsFormat">
2932
<property name="sizePolicy">
3033
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -34,7 +37,7 @@
3437
</property>
3538
<item>
3639
<property name="text">
37-
<string>External</string>
40+
<string>External (GTiff .ovr)</string>
3841
</property>
3942
</item>
4043
<item>
@@ -44,19 +47,49 @@
4447
</item>
4548
<item>
4649
<property name="text">
47-
<string>External (Erdas Imagine)</string>
50+
<string>External (Erdas Imagine .aux)</string>
4851
</property>
4952
</item>
5053
</widget>
5154
</item>
52-
<item row="3" column="2">
53-
<widget class="QLineEdit" name="lePyramidsLevels">
54-
<property name="toolTip">
55-
<string>Insert positive integer values separated by spaces</string>
55+
<item row="3" column="0">
56+
<widget class="QLabel" name="label_5">
57+
<property name="text">
58+
<string>Levels</string>
5659
</property>
5760
</widget>
5861
</item>
59-
<item row="1" column="2">
62+
<item row="8" column="0" colspan="3">
63+
<widget class="QLabel" name="label_4">
64+
<property name="text">
65+
<string>Create Options</string>
66+
</property>
67+
</widget>
68+
</item>
69+
<item row="4" column="1">
70+
<spacer name="horizontalSpacer">
71+
<property name="orientation">
72+
<enum>Qt::Horizontal</enum>
73+
</property>
74+
<property name="sizeType">
75+
<enum>QSizePolicy::Fixed</enum>
76+
</property>
77+
<property name="sizeHint" stdset="0">
78+
<size>
79+
<width>10</width>
80+
<height>20</height>
81+
</size>
82+
</property>
83+
</spacer>
84+
</item>
85+
<item row="2" column="0">
86+
<widget class="QLabel" name="textLabel4_2">
87+
<property name="text">
88+
<string>Resampling method</string>
89+
</property>
90+
</widget>
91+
</item>
92+
<item row="2" column="2">
6093
<widget class="QComboBox" name="cboResamplingMethod">
6194
<item>
6295
<property name="text">
@@ -70,63 +103,30 @@
70103
</item>
71104
</widget>
72105
</item>
73-
<item row="2" column="2">
74-
<layout class="QHBoxLayout" name="layoutPyramidsLevels"/>
75-
</item>
76-
<item row="0" column="0">
77-
<widget class="QLabel" name="label_2">
106+
<item row="4" column="0">
107+
<widget class="QCheckBox" name="cbxPyramidsLevelsCustom">
78108
<property name="text">
79-
<string>Overview format</string>
109+
<string>Custom levels</string>
80110
</property>
81111
</widget>
82112
</item>
83113
<item row="7" column="0" colspan="3">
84-
<widget class="QLabel" name="label_4">
85-
<property name="text">
86-
<string>Create Options</string>
87-
</property>
88-
</widget>
89-
</item>
90-
<item row="2" column="0">
91-
<widget class="QLabel" name="label_5">
92-
<property name="text">
93-
<string>Levels</string>
94-
</property>
95-
</widget>
96-
</item>
97-
<item row="6" column="0" colspan="3">
98114
<widget class="Line" name="line">
99115
<property name="orientation">
100116
<enum>Qt::Horizontal</enum>
101117
</property>
102118
</widget>
103119
</item>
120+
<item row="9" column="0" colspan="3">
121+
<widget class="QgsRasterFormatSaveOptionsWidget" name="mSaveOptionsWidget" native="true"/>
122+
</item>
104123
<item row="1" column="0">
105-
<widget class="QLabel" name="textLabel4_2">
124+
<widget class="QLabel" name="label_2">
106125
<property name="text">
107-
<string>Resampling method</string>
126+
<string>Overview format</string>
108127
</property>
109128
</widget>
110129
</item>
111-
<item row="8" column="0" colspan="3">
112-
<widget class="QgsRasterFormatSaveOptionsWidget" name="mPyramidsOptionsWidget" native="true"/>
113-
</item>
114-
<item row="3" column="1">
115-
<spacer name="horizontalSpacer">
116-
<property name="orientation">
117-
<enum>Qt::Horizontal</enum>
118-
</property>
119-
<property name="sizeType">
120-
<enum>QSizePolicy::Fixed</enum>
121-
</property>
122-
<property name="sizeHint" stdset="0">
123-
<size>
124-
<width>10</width>
125-
<height>20</height>
126-
</size>
127-
</property>
128-
</spacer>
129-
</item>
130130
</layout>
131131
</widget>
132132
<customwidgets>

0 commit comments

Comments
 (0)
Please sign in to comment.