18 changes: 12 additions & 6 deletions python/plugins/GdalTools/tools/doTranslate.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ def __init__(self, iface):
(self.outSelector, SIGNAL("filenameChanged()")),
(self.targetSRSEdit, SIGNAL("textChanged(const QString &)"), self.targetSRSCheck),
(self.selectTargetSRSButton, None, self.targetSRSCheck),
(self.creationOptionsTable, [SIGNAL("cellValueChanged(int, int)"), SIGNAL("rowRemoved()")], self.creationGroupBox),
(self.creationOptionsWidget, SIGNAL("optionsChanged()")),
(self.outsizeSpin, SIGNAL("valueChanged(const QString &)"), self.outsizeCheck),
(self.nodataSpin, SIGNAL("valueChanged(int)"), self.nodataCheck),
(self.expandCombo, SIGNAL("currentIndexChanged(int)"), self.expandCheck, "1.6.0"),
(self.expandCombo, SIGNAL("currentIndexChanged(int)"), self.expandCheck, 1600),
(self.sdsCheck, SIGNAL("stateChanged(int)")),
(self.srcwinEdit, SIGNAL("textChanged(const QString &)"), self.srcwinCheck),
(self.prjwinEdit, SIGNAL("textChanged(const QString &)"), self.prjwinCheck)
Expand Down Expand Up @@ -188,10 +188,9 @@ def getArguments(self):
if self.targetSRSCheck.isChecked() and not self.targetSRSEdit.text().isEmpty():
arguments << "-a_srs"
arguments << self.targetSRSEdit.text()
if self.creationGroupBox.isChecked():
for opt in self.creationOptionsTable.options():
arguments << "-co"
arguments << opt
if self.creationOptionsGroupBox.isChecked():
for opt in self.creationOptionsWidget.options():
arguments << "-co" << opt
if self.outsizeCheck.isChecked() and self.outsizeSpin.value() != 100:
arguments << "-outsize"
arguments << self.outsizeSpin.text()
Expand Down Expand Up @@ -244,6 +243,13 @@ def getArguments(self):
arguments << self.outputFormat
arguments << self.getInputFileName()
arguments << outputFn

# set creation options filename/layer for validation
if self.inSelector.layer():
self.creationOptionsWidget.setRasterLayer(self.inSelector.layer())
else:
self.creationOptionsWidget.setRasterFileName(self.getInputFileName())

return arguments

def getInputFileName(self):
Expand Down
537 changes: 285 additions & 252 deletions python/plugins/GdalTools/tools/widgetDEM.ui

Large diffs are not rendered by default.

325 changes: 181 additions & 144 deletions python/plugins/GdalTools/tools/widgetOverview.ui
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>376</width>
<height>311</height>
<height>342</height>
</rect>
</property>
<property name="sizePolicy">
Expand Down Expand Up @@ -39,62 +39,6 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="algorithmCheck">
<property name="text">
<string>Resampling method</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="algorithmCombo">
<item>
<property name="text">
<string>nearest</string>
</property>
</item>
<item>
<property name="text">
<string>average</string>
</property>
</item>
<item>
<property name="text">
<string>gauss</string>
</property>
</item>
<item>
<property name="text">
<string>cubic</string>
</property>
</item>
<item>
<property name="text">
<string>average_mp</string>
</property>
</item>
<item>
<property name="text">
<string>average_magphase</string>
</property>
</item>
<item>
<property name="text">
<string>mode</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Levels (space delimited)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="levelsEdit"/>
</item>
<item row="0" column="1">
<widget class="GdalToolsInOutSelector" name="inSelector" native="true"/>
</item>
Expand All @@ -111,96 +55,183 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="roModeCheck">
<property name="toolTip">
<string>In order to generate external overview (for GeoTIFF especially).</string>
</property>
<property name="text">
<string>Open in read-only mode</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="tiffjpegCheck">
<property name="toolTip">
<string>Create external overviews in TIFF format, compressed using JPEG.</string>
</property>
<property name="text">
<string>Overviews in TIFF format with JPEG compression</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="jpegQualityContainer">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>24</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="jpegQualityLabel">
<property name="toolTip">
<string>For JPEG compressed external overviews,
the JPEG quality can be set.</string>
</property>
<property name="text">
<string>JPEG Quality (1-100)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="jpegQualitySpin">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>For JPEG compressed external overviews,
the JPEG quality can be set.</string>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="rrdCheck">
<property name="toolTip">
<string>Alternate overview format using Erdas Imagine format,
<widget class="QWidget" name="tab">
<attribute name="title">
<string>old</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Levels (space delimited)</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="rrdCheck">
<property name="toolTip">
<string>Alternate overview format using Erdas Imagine format,
placing the overviews in an associated .aux file
suitable for direct use with Imagine,ArcGIS, GDAL.</string>
</property>
<property name="text">
<string>Use Imagine format (.aux file)</string>
</property>
</property>
<property name="text">
<string>Use Imagine format (.aux file)</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QFrame" name="jpegQualityContainer">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>24</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="jpegQualityLabel">
<property name="toolTip">
<string>For JPEG compressed external overviews,
the JPEG quality can be set.</string>
</property>
<property name="text">
<string>JPEG Quality (1-100)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="jpegQualitySpin">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>For JPEG compressed external overviews,
the JPEG quality can be set.</string>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="levelsEdit"/>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="tiffjpegCheck">
<property name="toolTip">
<string>Create external overviews in TIFF format, compressed using JPEG.</string>
</property>
<property name="text">
<string>Overviews in TIFF format with JPEG compression</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="roModeCheck">
<property name="toolTip">
<string>In order to generate external overview (for GeoTIFF especially).</string>
</property>
<property name="text">
<string>Open in read-only mode</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="algorithmCheck">
<property name="text">
<string>Resampling method</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="algorithmCombo">
<item>
<property name="text">
<string>nearest</string>
</property>
</item>
<item>
<property name="text">
<string>average</string>
</property>
</item>
<item>
<property name="text">
<string>gauss</string>
</property>
</item>
<item>
<property name="text">
<string>cubic</string>
</property>
</item>
<item>
<property name="text">
<string>average_mp</string>
</property>
</item>
<item>
<property name="text">
<string>average_magphase</string>
</property>
</item>
<item>
<property name="text">
<string>mode</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>new</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QgsRasterPyramidsOptionsWidget" name="mPyramidOptionsWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
Expand All @@ -215,6 +246,12 @@ suitable for direct use with Imagine,ArcGIS, GDAL.</string>
<header>inOutSelector</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsRasterPyramidsOptionsWidget</class>
<extends>QWidget</extends>
<header>qgis.gui</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
Expand Down
13 changes: 12 additions & 1 deletion python/plugins/GdalTools/tools/widgetPluginBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,18 @@ def setParamsStatus(self, wdgts_sgnls_chk_ver_list):
return

# if check version fails, disable the widget then hide both it and its enabler checkbox
if ver != None:
# new check for gdal 1.10, must update all widgets for this and then remove previous check
if ver != None and isinstance(ver, int):
gdalVerNum = Utils.GdalConfig.versionNum()
if ver > gdalVerNum:
wdgt.setVisible(False)
if isinstance(chk, QWidget):
chk.setVisible(False)
chk.setChecked(False)
sgnls = None
chk = False

elif ver != None:
if not isinstance(ver, Utils.Version):
ver = Utils.Version(ver)
gdalVer = Utils.GdalConfig.version()
Expand Down
19 changes: 14 additions & 5 deletions python/plugins/GdalTools/tools/widgetTranslate.ui
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ The 'gray' value (from GDAL 1.7.0) enables to expand a dataset with a color tabl
</layout>
</item>
<item>
<widget class="QGroupBox" name="creationGroupBox">
<widget class="QgsCollapsibleGroupBox" name="creationOptionsGroupBox">
<property name="title">
<string>&amp;Creation Options</string>
</property>
Expand All @@ -261,11 +261,14 @@ The 'gray' value (from GDAL 1.7.0) enables to expand a dataset with a color tabl
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>0</number>
<number>9</number>
</property>
<item>
<widget class="GdalToolsOptionsTable" name="creationOptionsTable" native="true"/>
<widget class="QgsRasterFormatSaveOptionsWidget" name="creationOptionsWidget" native="true"/>
</item>
</layout>
</widget>
Expand All @@ -283,9 +286,15 @@ The 'gray' value (from GDAL 1.7.0) enables to expand a dataset with a color tabl
<container>1</container>
</customwidget>
<customwidget>
<class>GdalToolsOptionsTable</class>
<class>QgsCollapsibleGroupBox</class>
<extends>QGroupBox</extends>
<header>qgis.gui</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsRasterFormatSaveOptionsWidget</class>
<extends>QWidget</extends>
<header>optionsTable</header>
<header>qgis.gui</header>
<container>1</container>
</customwidget>
</customwidgets>
Expand Down
5 changes: 3 additions & 2 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4180,9 +4180,10 @@ void QgisApp::saveAsRasterFile()
fileWriter.setCreateOptions( d.createOptions() );

fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
fileWriter.setPyramidsList( d.overviewList() );
fileWriter.setPyramidsResampling( d.pyramidsResampling() );
fileWriter.setPyramidsList( d.pyramidsList() );
fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );

QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe, d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd );
if ( err != QgsRasterFileWriter::NoError )
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgis.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ const double DEFAULT_LINE_WIDTH = 0.26;
/** default snapping tolerance for segments (@note added in 1.8) */
const double DEFAULT_SEGMENT_EPSILON = 1e-8;

typedef QMap<QString, QString> QgsStringMap;

// FIXME: also in qgisinterface.h
#ifndef QGISEXTERN
#ifdef WIN32
Expand Down
57 changes: 57 additions & 0 deletions src/core/raster/qgsrasterdataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,63 @@ QString QgsRasterDataProvider::lastErrorFormat()
return "text/plain";
}

// pyramids resampling

// TODO move this to gdal provider
// but we need some way to get a static instance of the provider
// or use function pointers like in QgsRasterFormatSaveOptionsWidget::helpOptions()

// see http://www.gdal.org/gdaladdo.html
// http://www.gdal.org/classGDALDataset.html#a2aa6f88b3bbc840a5696236af11dde15
// http://www.gdal.org/classGDALRasterBand.html#afaea945b13ec9c86c2d783b883c68432

// from http://www.gdal.org/gdaladdo.html
// average_mp is unsuitable for use thus not included

// from qgsgdalprovider.cpp (removed)
// 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
QStringList QgsRasterDataProvider::mPyramidResamplingListGdal = QStringList();
QgsStringMap QgsRasterDataProvider::mPyramidResamplingMapGdal = QgsStringMap();

void QgsRasterDataProvider::initPyramidResamplingDefs()
{
mPyramidResamplingListGdal.clear();
mPyramidResamplingListGdal << tr( "Nearest Neighbour" ) << tr( "Average" ) << tr( "Gauss" ) << tr( "Cubic" ) << tr( "Mode" ) << tr( "None" ); // << tr( "Average magphase" )
mPyramidResamplingMapGdal.clear();
mPyramidResamplingMapGdal[ tr( "Nearest Neighbour" )] = "NEAREST";
mPyramidResamplingMapGdal[ tr( "Average" )] = "AVERAGE";
mPyramidResamplingMapGdal[ tr( "Gauss" )] = "GAUSS";
mPyramidResamplingMapGdal[ tr( "Cubic" )] = "CUBIC";
mPyramidResamplingMapGdal[ tr( "Mode" )] = "MODE";
// mPyramidResamplingMapGdal[ tr( "Average magphase" ) ] = "average_magphase";
mPyramidResamplingMapGdal[ tr( "None" )] = "NONE" ;
}

QStringList QgsRasterDataProvider::pyramidResamplingMethods( QString providerKey )
{
if ( mPyramidResamplingListGdal.isEmpty() )
initPyramidResamplingDefs();

return providerKey == "gdal" ? mPyramidResamplingListGdal : QStringList();
}

QString QgsRasterDataProvider::pyramidResamplingArg( QString method, QString providerKey )
{
if ( providerKey != "gdal" )
return QString();

if ( mPyramidResamplingListGdal.isEmpty() )
initPyramidResamplingDefs();

if ( mPyramidResamplingMapGdal.contains( method ) )
return mPyramidResamplingMapGdal.value( method );
else
return "NEAREST";
}

bool QgsRasterDataProvider::hasPyramids()
{
QList<QgsRasterPyramid> myPyramidList = buildPyramidList();
Expand Down
35 changes: 23 additions & 12 deletions src/core/raster/qgsrasterdataprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,13 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
}

/** \brief Create pyramid overviews */
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
const QString & theResamplingMethod = "NEAREST",
RasterPyramidsFormat theFormat = PyramidsGTiff )
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
const QString & theResamplingMethod = "NEAREST",
RasterPyramidsFormat theFormat = PyramidsGTiff,
const QStringList & theConfigOptions = QStringList() )
{
Q_UNUSED( thePyramidList ); Q_UNUSED( theResamplingMethod ); Q_UNUSED( theFormat );
Q_UNUSED( thePyramidList ); Q_UNUSED( theResamplingMethod );
Q_UNUSED( theFormat ); Q_UNUSED( theConfigOptions );
return "FAILED_NOT_SUPPORTED";
};

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

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

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

/** Validates pyramid creation options for a specific dataset and destination format
* @note used by GDAL provider only */
virtual QString validatePyramidsConfigOptions( RasterPyramidsFormat pyramidsFormat,
const QStringList & theConfigOptions, const QString & fileFormat )
{ Q_UNUSED( pyramidsFormat ); Q_UNUSED( theConfigOptions ); Q_UNUSED( fileFormat ); return QString(); }

signals:
/** Emit a signal to notify of the progress event.
* Emited theProgress is in percents (0.0-100.0) */
Expand Down Expand Up @@ -496,5 +503,9 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast

QgsRectangle mExtent;

static void initPyramidResamplingDefs();
static QStringList mPyramidResamplingListGdal;
static QgsStringMap mPyramidResamplingMapGdal;

};
#endif
5 changes: 3 additions & 2 deletions src/core/raster/qgsrasterfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -717,9 +717,10 @@ void QgsRasterFileWriter::buildPyramids( const QString& filename )
myPyramidList[myCounterInt].build = true;
}

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

// TODO put this in provider or elsewhere
Expand Down
5 changes: 4 additions & 1 deletion src/core/raster/qgsrasterfilewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,12 @@ class CORE_EXPORT QgsRasterFileWriter
void setMaxTileHeight( int h ) { mMaxTileHeight = h; }
int maxTileHeight() const { return mMaxTileHeight; }

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

void setPyramidsConfigOptions( const QStringList& list ) { mPyramidsConfigOptions = list; }
QStringList pyramidsConfigOptions() const { return mPyramidsConfigOptions; }

private:
QgsRasterFileWriter(); //forbidden
//WriterError writeDataRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent,
Expand Down Expand Up @@ -157,6 +159,7 @@ class CORE_EXPORT QgsRasterFileWriter
QString mPyramidsResampling;
QgsRasterDataProvider::RasterBuildPyramids mBuildPyramidsFlag;
QgsRasterDataProvider::RasterPyramidsFormat mPyramidsFormat;
QStringList mPyramidsConfigOptions;

QDomDocument mVRTDocument;
QList<QDomElement> mVRTBands;
Expand Down
1 change: 0 additions & 1 deletion src/core/symbology-ng/qgssymbolv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class QgsSymbolLayerV2;
class QgsRenderContext;
class QgsVectorLayer;

typedef QMap<QString, QString> QgsStringMap;
typedef QList<QgsSymbolLayerV2*> QgsSymbolLayerV2List;

class CORE_EXPORT QgsSymbolV2
Expand Down
126 changes: 95 additions & 31 deletions src/gui/qgsrasterformatsaveoptionswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ QMap< QString, QStringList > QgsRasterFormatSaveOptionsWidget::mBuiltinProfiles;

QgsRasterFormatSaveOptionsWidget::QgsRasterFormatSaveOptionsWidget( QWidget* parent, QString format,
QgsRasterFormatSaveOptionsWidget::Type type, QString provider )
: QWidget( parent ), mFormat( format ), mProvider( provider ), mRasterLayer( 0 )
: QWidget( parent ), mFormat( format ), mProvider( provider ), mRasterLayer( 0 ),
mRasterFileName( QString() ), mPyramids( false ),
mPyramidsFormat( QgsRasterDataProvider::PyramidsGTiff )

{
setupUi( this );
Expand All @@ -58,8 +60,8 @@ QgsRasterFormatSaveOptionsWidget::QgsRasterFormatSaveOptionsWidget( QWidget* par
( QStringList() << "GTiff" << tr( "High compression" )
<< "COMPRESS=DEFLATE PREDICTOR=2 ZLEVEL=9" );
mBuiltinProfiles[ "z_gtiff_4jpeg" ] =
( QStringList() << "GTiff" << tr( "Lossy compression" )
<< "COMPRESS=JPEG" );
( QStringList() << "GTiff" << tr( "JPEG compression" )
<< "COMPRESS=JPEG JPEG_QUALITY=75" );

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

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

updateControls();
updateProfiles();

QgsDebugMsg( "done" );
}

QgsRasterFormatSaveOptionsWidget::~QgsRasterFormatSaveOptionsWidget()
Expand Down Expand Up @@ -123,7 +127,7 @@ void QgsRasterFormatSaveOptionsWidget::setType( QgsRasterFormatSaveOptionsWidget
foreach ( QWidget* widget, mOptionsStackedWidget->findChildren<QWidget *>() )
widget->setVisible( true );

// show elevant page
// show relevant page
if ( type == Table )
swapOptionsUI( 0 );
else if ( type == LineEdit )
Expand All @@ -146,17 +150,20 @@ void QgsRasterFormatSaveOptionsWidget::setType( QgsRasterFormatSaveOptionsWidget
void QgsRasterFormatSaveOptionsWidget::updateProfiles()
{
// build profiles list = user + builtin(last)
QString format = mPyramids ? "_pyramids" : mFormat;
QStringList profileKeys = profiles();
QMapIterator<QString, QStringList> it( mBuiltinProfiles );
while ( it.hasNext() )
{
it.next();
QString profileKey = it.key();
if ( ! profileKeys.contains( profileKey ) )
if ( ! profileKeys.contains( profileKey ) && it.value().count() > 0 )
{
// insert key if is for all formats or this format (GTiff)
if ( it.value()[0] == "" || it.value()[0] == mFormat )
if ( it.value()[0] == "" || it.value()[0] == format )
{
profileKeys.insert( 0, profileKey );
}
}
}
qSort( profileKeys );
Expand Down Expand Up @@ -188,7 +195,7 @@ void QgsRasterFormatSaveOptionsWidget::updateProfiles()
// mProfileComboBox->setCurrentIndex( 0 );
QSettings mySettings;
mProfileComboBox->setCurrentIndex( mProfileComboBox->findData( mySettings.value(
mProvider + "/driverOptions/" + mFormat.toLower() + "/defaultProfile",
mProvider + "/driverOptions/" + format.toLower() + "/defaultProfile",
"z_adefault" ) ) );
updateOptions();
}
Expand Down Expand Up @@ -217,6 +224,8 @@ void QgsRasterFormatSaveOptionsWidget::updateOptions()
mOptionsLineEdit->setText( myOptions );
mOptionsLineEdit->setCursorPosition( 0 );
}

emit optionsChanged();
}

void QgsRasterFormatSaveOptionsWidget::apply()
Expand All @@ -232,7 +241,7 @@ void QgsRasterFormatSaveOptionsWidget::helpOptions()
{
QString message;

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

// show simple non-modal dialog - should we make the basic xml prettier?
QgsDialog *dlg = new QgsDialog( this );
QTextEdit *textEdit = new QTextEdit( dlg );
textEdit->setReadOnly( true );
message = tr( "Create Options:\n\n%1" ).arg( message );
// message = tr( "Create Options:\n\n%1" ).arg( message );
textEdit->setText( message );
dlg->layout()->addWidget( textEdit );
dlg->resize( 600, 400 );
Expand All @@ -279,12 +293,49 @@ QString QgsRasterFormatSaveOptionsWidget::validateOptions( bool gui, bool report
QStringList createOptions = options();
QString message;

if ( !createOptions.isEmpty() && mProvider == "gdal" && mFormat != "" && mFormat != "_pyramids" )
QgsDebugMsg( QString( "layer: [%1] file: [%2] format: [%3]" ).arg( mRasterLayer ? mRasterLayer->id() : "none" ).arg( mRasterFileName ).arg( mFormat ) );
// if no rasterLayer is defined, but we have a raster fileName, then create a temp. rasterLayer to validate options
// ideally we should keep it for future access, but this is trickier
QgsRasterLayer* rasterLayer = mRasterLayer;
bool tmpLayer = false;
if ( !( mRasterLayer && rasterLayer->dataProvider() ) && ! mRasterFileName.isNull() )
{
// temporarily override /Projections/defaultBehaviour to avoid dialog prompt
// this is taken from qgsbrowserdockwidget.cpp
// TODO - integrate this into qgis core
QSettings settings;
QString defaultProjectionOption = settings.value( "/Projections/defaultBehaviour", "prompt" ).toString();
if ( settings.value( "/Projections/defaultBehaviour", "prompt" ).toString() == "prompt" )
{
settings.setValue( "/Projections/defaultBehaviour", "useProject" );
}
tmpLayer = true;
rasterLayer = new QgsRasterLayer( mRasterFileName, QFileInfo( mRasterFileName ).baseName(), "gdal" );
// restore /Projections/defaultBehaviour
if ( defaultProjectionOption == "prompt" )
{
settings.setValue( "/Projections/defaultBehaviour", defaultProjectionOption );
}
}

if ( mProvider == "gdal" && mPyramids )
{
if ( rasterLayer && rasterLayer->dataProvider() )
{
QgsDebugMsg( "calling validate pyramids on layer's data provider" );
message = rasterLayer->dataProvider()->validatePyramidsConfigOptions( mPyramidsFormat, createOptions, mFormat );
}
else
{
message = tr( "cannot validate pyramid options" );
}
}
else if ( !createOptions.isEmpty() && mProvider == "gdal" && mFormat != "" )
{
if ( mRasterLayer )
if ( rasterLayer && rasterLayer->dataProvider() )
{
QgsDebugMsg( "calling validate on layer's data provider" );
message = mRasterLayer->dataProvider()->validateCreationOptions( createOptions, mFormat );
message = rasterLayer->dataProvider()->validateCreationOptions( createOptions, mFormat );
}
else
{
Expand All @@ -306,24 +357,30 @@ QString QgsRasterFormatSaveOptionsWidget::validateOptions( bool gui, bool report
else
message = QString( "cannot load provider library %1" ).arg( mProvider );
}
}
else if ( ! createOptions.isEmpty() )
{
QMessageBox::information( this, "", tr( "Cannot validate creation options" ), QMessageBox::Close );
if ( tmpLayer )
delete rasterLayer;
return QString();
}

if ( gui )
if ( gui )
{
if ( message.isNull() )
{
if ( message.isNull() )
{
if ( reportOK )
QMessageBox::information( this, "", tr( "Valid" ), QMessageBox::Close );
}
else
{
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 );
}
if ( reportOK )
QMessageBox::information( this, "", tr( "Valid" ), QMessageBox::Close );
}
else
{
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 );
}
}
else
{
QMessageBox::information( this, "", tr( "Cannot validate" ), QMessageBox::Close );
}

if ( tmpLayer )
delete rasterLayer;

return message;
}
Expand Down Expand Up @@ -512,9 +569,9 @@ void QgsRasterFormatSaveOptionsWidget::swapOptionsUI( int newIndex )

void QgsRasterFormatSaveOptionsWidget::updateControls()
{
bool enabled = ( mProvider == "gdal" && mFormat != "" && mFormat != "_pyramids" );
mOptionsValidateButton->setEnabled( enabled );
mOptionsHelpButton->setEnabled( enabled );
bool valid = mProvider == "gdal" && mFormat != "";
mOptionsValidateButton->setEnabled( valid );
mOptionsHelpButton->setEnabled( valid );
}

// map options label left mouse click to optionsToggle()
Expand Down Expand Up @@ -550,3 +607,10 @@ bool QgsRasterFormatSaveOptionsWidget::eventFilter( QObject *obj, QEvent *event
return QObject::eventFilter( obj, event );
}

void QgsRasterFormatSaveOptionsWidget::showEvent( QShowEvent * event )
{
Q_UNUSED( event );
mOptionsTable->horizontalHeader()->resizeSection( 0, mOptionsTable->width() - 115 );
QgsDebugMsg( "done" );
}

16 changes: 15 additions & 1 deletion src/gui/qgsrasterformatsaveoptionswidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include "ui_qgsrasterformatsaveoptionswidgetbase.h"

#include "qgsrasterdataprovider.h"

class QgsRasterLayer;

/** \ingroup gui
Expand Down Expand Up @@ -48,9 +50,12 @@ class GUI_EXPORT QgsRasterFormatSaveOptionsWidget: public QWidget,

void setFormat( QString format );
void setProvider( QString provider );
void setRasterLayer( QgsRasterLayer* rasterLayer ) { mRasterLayer = rasterLayer; }
void setRasterLayer( QgsRasterLayer* rasterLayer ) { mRasterLayer = rasterLayer; mRasterFileName = QString(); }
void setRasterFileName( const QString& file ) { mRasterLayer = 0; mRasterFileName = file; }
QStringList options() const;
void setType( QgsRasterFormatSaveOptionsWidget::Type type = Default );
void setPyramidsFormat( QgsRasterDataProvider::RasterPyramidsFormat format )
{ mPyramids = true; mPyramidsFormat = format; }

public slots:

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

protected:
virtual void showEvent( QShowEvent * event );

signals:
void optionsChanged();

private:

QString mFormat;
QString mProvider;
QgsRasterLayer* mRasterLayer;
QString mRasterFileName;
QMap< QString, QString> mOptionsMap;
static QMap< QString, QStringList > mBuiltinProfiles;
bool mPyramids;
QgsRasterDataProvider::RasterPyramidsFormat mPyramidsFormat;

QString settingsKey( QString profile ) const;
QString currentProfileKey() const;
Expand Down
18 changes: 14 additions & 4 deletions src/gui/qgsrasterlayersaveasdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer* rasterLa
mMaximumSizeYLineEdit->setText( QString::number( 2000 ) );
}

// setup creation option widget
mCreateOptionsWidget->setProvider( mDataProvider->name() );
if ( mDataProvider->name() == "gdal" )
{
Expand All @@ -97,7 +98,9 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer* rasterLa
// Only do pyramids if dealing directly with GDAL.
if ( mDataProvider->capabilities() & QgsRasterDataProvider::BuildPyramids )
{
mPyramidsOptionsWidget->createOptionsWidget()->setType( QgsRasterFormatSaveOptionsWidget::ProfileLineEdit );
// setup pyramids option widget
// mPyramidsOptionsWidget->createOptionsWidget()->setType( QgsRasterFormatSaveOptionsWidget::ProfileLineEdit );
mPyramidsOptionsWidget->createOptionsWidget()->setRasterLayer( mRasterLayer );

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

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

if ( mPyramidsGroupBox->isChecked() )
{
QList<QgsRasterPyramid> myPyramidList;
// if use existing, get pyramids from actual layer
// but that's not available yet
if ( mPyramidsUseExistingCheckBox->isChecked() )
{
myPyramidList = mDataProvider->buildPyramidList();
Expand All @@ -752,7 +756,7 @@ void QgsRasterLayerSaveAsDialog::populatePyramidsLevels()
myRasterPyramidIterator != myPyramidList.end();
++myRasterPyramidIterator )
{
if ( myRasterPyramidIterator->exists )
if ( ! mPyramidsUseExistingCheckBox->isChecked() || myRasterPyramidIterator->exists )
{
text += QString::number( myRasterPyramidIterator->xDim ) + QString( "x" ) +
QString::number( myRasterPyramidIterator->yDim ) + " ";
Expand Down Expand Up @@ -809,7 +813,7 @@ QList<QgsRasterNuller::NoData> QgsRasterLayerSaveAsDialog::noData() const
return noDataList;
}

QList<int> QgsRasterLayerSaveAsDialog::overviewList() const
QList<int> QgsRasterLayerSaveAsDialog::pyramidsList() const
{
return mPyramidsGroupBox->isChecked() ? mPyramidsOptionsWidget->overviewList() : QList<int>();
}
Expand All @@ -832,6 +836,12 @@ bool QgsRasterLayerSaveAsDialog::validate() const
if ( !message.isNull() )
return false;
}
if ( mPyramidsGroupBox->isChecked() )
{
QString message = mPyramidsOptionsWidget->createOptionsWidget()->validateOptions( true, false );
if ( !message.isNull() )
return false;
}
return true;
}

6 changes: 4 additions & 2 deletions src/gui/qgsrasterlayersaveasdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
QgsRectangle outputRectangle() const;
QList<QgsRasterNuller::NoData> noData() const;

QList< int > overviewList() const;
QList< int > pyramidsList() const;
QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const;
QString pyramidsResampling() const { return mPyramidsOptionsWidget->resamplingMethod(); }
QString pyramidsResamplingMethod() const { return mPyramidsOptionsWidget->resamplingMethod(); }
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const
{ return mPyramidsOptionsWidget->pyramidsFormat(); }
QStringList pyramidsConfigOptions() const
{ return mPyramidsOptionsWidget->configOptions(); }

void hideFormat();
void hideOutput();
Expand Down
32 changes: 22 additions & 10 deletions src/gui/qgsrasterpyramidsoptionswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ QgsRasterPyramidsOptionsWidget::QgsRasterPyramidsOptionsWidget( QWidget* parent,
{
setupUi( this );

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

updateUi();
}
Expand Down Expand Up @@ -68,8 +68,9 @@ void QgsRasterPyramidsOptionsWidget::updateUi()
mySettings.value( prefix + "resampling", "Average" ).toString() ) );

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

// overview list
Expand Down Expand Up @@ -99,14 +100,19 @@ void QgsRasterPyramidsOptionsWidget::updateUi()
}
setOverviewList();

mPyramidsOptionsWidget->updateProfiles();
}

mSaveOptionsWidget->updateProfiles();

connect( cbxPyramidsFormat, SIGNAL( currentIndexChanged( int ) ),
this, SIGNAL( someValueChanged() ) );
connect( cboResamplingMethod, SIGNAL( currentIndexChanged( int ) ),
this, SIGNAL( someValueChanged() ) );
connect( mSaveOptionsWidget, SIGNAL( optionsChanged() ),
this, SIGNAL( someValueChanged() ) );
}

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

void QgsRasterPyramidsOptionsWidget::apply()
Expand Down Expand Up @@ -135,7 +141,7 @@ void QgsRasterPyramidsOptionsWidget::apply()
}
mySettings.setValue( prefix + "overviewList", tmpStr.trimmed() );

mPyramidsOptionsWidget->apply();
mSaveOptionsWidget->apply();
}

void QgsRasterPyramidsOptionsWidget::checkAllLevels( bool checked )
Expand All @@ -153,13 +159,19 @@ void QgsRasterPyramidsOptionsWidget::on_cbxPyramidsLevelsCustom_toggled( bool to
setOverviewList();
}

void QgsRasterPyramidsOptionsWidget::on_cbxPyramidsFormat_currentIndexChanged( int index )
{
mSaveOptionsWidget->setEnabled( index != 2 );
mSaveOptionsWidget->setPyramidsFormat(( QgsRasterDataProvider::RasterPyramidsFormat ) index );
}

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

mOverviewList.clear();

// if custum levels is toggled, get selection from line edit
// if custom levels is toggled, get selection from line edit
if ( cbxPyramidsLevelsCustom->isChecked() )
{
// should we also validate that numbers are increasing?
Expand Down
13 changes: 7 additions & 6 deletions src/gui/qgsrasterpyramidsoptionswidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ class GUI_EXPORT QgsRasterPyramidsOptionsWidget: public QWidget,
QgsRasterPyramidsOptionsWidget( QWidget* parent = 0, QString provider = "gdal" );
~QgsRasterPyramidsOptionsWidget();

QStringList createOptions() const { return mPyramidsOptionsWidget->options(); }
QgsRasterFormatSaveOptionsWidget* createOptionsWidget() { return mPyramidsOptionsWidget; }
QStringList configOptions() const { return mSaveOptionsWidget->options(); }
QgsRasterFormatSaveOptionsWidget* createOptionsWidget() { return mSaveOptionsWidget; }
const QList<int> overviewList() const { return mOverviewList; }
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const
{ return ( QgsRasterDataProvider::RasterPyramidsFormat ) cbxPyramidsFormat->currentIndex(); }
QString resamplingMethod() const;
void setRasterLayer( QgsRasterLayer* rasterLayer ) { mSaveOptionsWidget->setRasterLayer( rasterLayer ); }
void setRasterFileName( const QString& file ) { mSaveOptionsWidget->setRasterFileName( file ); }

public slots:

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

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

signals:
void overviewListChanged();
void someValueChanged(); /* emitted when any other setting changes */

private:

void updateUi();

QString mProvider;
QList< int > mOverviewList;
QMap< int, QCheckBox* > mOverviewCheckBoxes;
Expand Down
153 changes: 108 additions & 45 deletions src/providers/gdal/qgsgdalprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1321,8 +1321,9 @@ QgsRasterHistogram QgsGdalProvider::histogram( int theBandNo,
* @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.
* @return null string on success, otherwise a string specifying error
*/
QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRasterPyramidList,
QString const & theResamplingMethod, RasterPyramidsFormat theFormat )
QString QgsGdalProvider::buildPyramids( const QList<QgsRasterPyramid> & theRasterPyramidList,
const QString & theResamplingMethod, RasterPyramidsFormat theFormat,
const QStringList & theConfigOptions )
{
//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 All @@ -1337,14 +1338,6 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste

// TODO add signal and connect from rasterlayer
//emit drawingProgress( 0, 0 );
//first test if the file is writable
//QFileInfo myQFile( mDataSource );
QFileInfo myQFile( dataSourceUri() );

if ( !myQFile.isWritable() )
{
return "ERROR_WRITE_ACCESS";
}

if ( mGdalDataset != mGdalBaseDataset )
{
Expand All @@ -1355,6 +1348,16 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
// check if building internally
if ( theFormat == PyramidsInternal )
{

// test if the file is writable
//QFileInfo myQFile( mDataSource );
QFileInfo myQFile( dataSourceUri() );

if ( !myQFile.isWritable() )
{
return "ERROR_WRITE_ACCESS";
}

// 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
// see https://trac.osgeo.org/qgis/ticket/1357
Expand All @@ -1369,9 +1372,12 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
}
}

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

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

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

// add any driver-specific configuration options, save values to be restored later
if ( theFormat != PyramidsErdas && ! theConfigOptions.isEmpty() )
{
foreach ( QString option, theConfigOptions )
{
QStringList opt = option.split( "=" );
QByteArray key = opt[0].toLocal8Bit();
QByteArray value = opt[1].toLocal8Bit();
// save previous value
myConfigOptionsOld[ opt[0] ] = QString( CPLGetConfigOption( key.data(), NULL ) );
// set temp. value
CPLSetConfigOption( key.data(), value.data() );
QgsDebugMsg( QString( "set option %1=%2" ).arg( key.data() ).arg( value.data() ) );
}
}

//
// Iterate through the Raster Layer Pyramid Vector, building any pyramid
// marked as exists in each RasterPyramid struct.
Expand All @@ -1420,36 +1443,20 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
myOverviewLevelsVector.append( myRasterPyramidIterator->level );
}
}
/* From : http://remotesensing.org/gdal/classGDALDataset.html#a23
* pszResampling : one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE", "AVERAGE_MAGPHASE" or "NONE"
* controlling the downsampling method applied.
/* From : http://www.gdal.org/classGDALDataset.html#a2aa6f88b3bbc840a5696236af11dde15
* 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.
* nListBands : number of bands to build overviews for in panBandList. Build for all bands if this is 0.
* panBandList : list of band numbers.
* pfnProgress : a function to call to report progress, or NULL.
* pProgressData : application data to pass to the progress function.
*/

const char* theMethod;
if ( theResamplingMethod == tr( "Gauss" ) )
theMethod = "GAUSS";
else if ( theResamplingMethod == tr( "Cubic" ) )
theMethod = "CUBIC";
else if ( theResamplingMethod == tr( "Average" ) )
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
theMethod = "NEAREST";
// resampling method is now passed directly, via QgsRasterDataProvider::pyramidResamplingArg()
// average_mp and average_magphase have been removed from the gui
QByteArray ba = theResamplingMethod.toLocal8Bit();
const char *theMethod = ba.data();

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

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

//emit drawingProgress( 0, 0 );
// restore former USE_RRD config (Erdas)
CPLSetConfigOption( "USE_RRD", myConfigUseRRD );
free( myConfigUseRRD );

// restore former configOptions
for ( QgsStringMap::const_iterator it = myConfigOptionsOld.begin();
it != myConfigOptionsOld.end(); ++it )
{
QByteArray key = it.key().toLocal8Bit();
QByteArray value = it.value().toLocal8Bit();
CPLSetConfigOption( key.data(), value.data() );
}

// TODO print exact error message
return "FAILED_NOT_SUPPORTED";
}
else
Expand All @@ -1493,9 +1508,14 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
QgsLogger::warning( "Pyramid overview building failed!" );
}

// restore former USE_RRD config (Erdas)
CPLSetConfigOption( "USE_RRD", myConfigUseRRD );
free( myConfigUseRRD );
// restore former configOptions
for ( QgsStringMap::const_iterator it = myConfigOptionsOld.begin();
it != myConfigOptionsOld.end(); ++it )
{
QByteArray key = it.key().toLocal8Bit();
QByteArray value = it.value().toLocal8Bit();
CPLSetConfigOption( key.data(), value.data() );
}

QgsDebugMsg( "Pyramid overviews built" );

Expand Down Expand Up @@ -2521,13 +2541,21 @@ QGISEXTERN QString helpCreationOptionsFormat( QString format )
GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
if ( myGdalDriver )
{
// need to serialize xml to get newlines
// should we make the basic xml prettier?
// first report details and help page
char ** GDALmetadata = GDALGetMetadata( myGdalDriver, NULL );
message += "Format Details:\n";
message += QString( " Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
message += QString( " Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
message += QString( " / Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
message += QString( " Help page: http://www.gdal.org/%1\n\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_HELPTOPIC ) );

// next get creation options
// need to serialize xml to get newlines, should we make the basic xml prettier?
CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
GDAL_DMD_CREATIONOPTIONLIST, "" ) );
char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
if ( pszFormattedXML )
message = QString( pszFormattedXML );
message += QString( pszFormattedXML );
if ( psCOL )
CPLDestroyXMLNode( psCOL );
if ( pszFormattedXML )
Expand Down Expand Up @@ -2608,3 +2636,38 @@ QString QgsGdalProvider::validateCreationOptions( const QStringList& createOptio

return message;
}

QString QgsGdalProvider::validatePyramidsCreationOptions( RasterPyramidsFormat pyramidsFormat,
const QStringList & theConfigOptions, const QString & fileFormat )
{
// Erdas Imagine format does not support config options
if ( pyramidsFormat == PyramidsErdas )
{
if ( ! theConfigOptions.isEmpty() )
return "Erdas Imagine format does not support config options";
else
return QString();
}
// Internal pyramids format only supported for gtiff/georaster/hfa/jp2kak/mrsid/nitf files
else if ( pyramidsFormat == PyramidsInternal )
{
QStringList supportedFormats;
supportedFormats << "gtiff" << "georaster" << "hfa" << "jp2kak" << "mrsid" << "nitf";
if ( ! supportedFormats.contains( fileFormat.toLower() ) )
return QString( "Internal pyramids format only supported for gtiff/georaster/hfa/jp2kak/mrsid/nitf files (using %1)" ).arg( fileFormat );
// TODO - check arguments for georaster hfa jp2kak mrsid nitf
// for now, only test gtiff
else if ( fileFormat.toLower() != "gtiff" )
return QString();
}

// for gtiff external or internal pyramids, validate gtiff-specific values
// PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)
if ( theConfigOptions.contains( "PHOTOMETRIC_OVERVIEW=YCBCR" ) )
{
if ( GDALGetRasterCount( mGdalDataset ) != 3 )
return "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)";
}

return QString();
}
10 changes: 7 additions & 3 deletions src/providers/gdal/qgsgdalprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,10 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
int theSampleSize = 0,
bool theIncludeOutOfRange = false );

QString buildPyramids( const QList<QgsRasterPyramid> &,
const QString & theResamplingMethod = "NEAREST",
RasterPyramidsFormat theFormat = PyramidsGTiff );
QString buildPyramids( const QList<QgsRasterPyramid> & theRasterPyramidList,
const QString & theResamplingMethod = "NEAREST",
RasterPyramidsFormat theFormat = PyramidsGTiff,
const QStringList & theCreateOptions = QStringList() );
QList<QgsRasterPyramid> buildPyramidList( QList<int> overviewList = QList<int>() );

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

QString validateCreationOptions( const QStringList& createOptions, QString format );
QString validatePyramidsCreationOptions( RasterPyramidsFormat pyramidsFormat,
const QStringList & theConfigOptions, const QString & fileFormat );

signals:
void statusChanged( QString );
Expand Down Expand Up @@ -314,6 +317,7 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase

/** \brief sublayers list saved for subsequent access */
QStringList mSubLayers;

};

#endif
Expand Down
108 changes: 54 additions & 54 deletions src/ui/qgsrasterpyramidsoptionswidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>366</width>
<height>171</height>
<height>156</height>
</rect>
</property>
<property name="windowTitle">
Expand All @@ -17,14 +17,17 @@
<property name="margin">
<number>1</number>
</property>
<item row="3" column="0">
<widget class="QCheckBox" name="cbxPyramidsLevelsCustom">
<property name="text">
<string>Custom levels</string>
<item row="4" column="2">
<widget class="QLineEdit" name="lePyramidsLevels">
<property name="toolTip">
<string>Insert positive integer values separated by spaces</string>
</property>
</widget>
</item>
<item row="0" column="2">
<item row="3" column="2">
<layout class="QHBoxLayout" name="layoutPyramidsLevels"/>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="cbxPyramidsFormat">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
Expand All @@ -34,7 +37,7 @@
</property>
<item>
<property name="text">
<string>External</string>
<string>External (GTiff .ovr)</string>
</property>
</item>
<item>
Expand All @@ -44,19 +47,49 @@
</item>
<item>
<property name="text">
<string>External (Erdas Imagine)</string>
<string>External (Erdas Imagine .aux)</string>
</property>
</item>
</widget>
</item>
<item row="3" column="2">
<widget class="QLineEdit" name="lePyramidsLevels">
<property name="toolTip">
<string>Insert positive integer values separated by spaces</string>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Levels</string>
</property>
</widget>
</item>
<item row="1" column="2">
<item row="8" column="0" colspan="3">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Create Options</string>
</property>
</widget>
</item>
<item row="4" 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="2" column="0">
<widget class="QLabel" name="textLabel4_2">
<property name="text">
<string>Resampling method</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="cboResamplingMethod">
<item>
<property name="text">
Expand All @@ -70,63 +103,30 @@
</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">
<item row="4" column="0">
<widget class="QCheckBox" name="cbxPyramidsLevelsCustom">
<property name="text">
<string>Overview format</string>
<string>Custom levels</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="6" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="9" column="0" colspan="3">
<widget class="QgsRasterFormatSaveOptionsWidget" name="mSaveOptionsWidget" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="textLabel4_2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Resampling method</string>
<string>Overview format</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>
<customwidgets>
Expand Down