implement pyramids in raster save dialog ; improve pyramids creation ; remove pyramid-related stuff from qgsrasterlayer

This commit is contained in:
Etienne Tourigny 2012-08-26 20:16:51 -03:00
parent 4cfc365477
commit eda71f5a9c
19 changed files with 838 additions and 303 deletions

View File

@ -6,7 +6,7 @@
class QgsRasterLayer : QgsMapLayer
{
%TypeHeaderCode
#include <qgsrasterpyramid.h>
// #include <qgsrasterpyramid.h>
#include <qgsrasterlayer.h>
#include <qgscontrastenhancement.h>
#include <qgsrastertransparency.h>
@ -91,7 +91,7 @@ public:
* to be added to the list. Each time a RasterPyramid is created
* we will check to see if a pyramid matching these dimensions already exists
* in the raster layer, and if so mark the exists flag as true */
typedef QList<QgsRasterPyramid> RasterPyramidList;
// typedef QList<QgsRasterPyramid> RasterPyramidList;
/** \brief A list containing one RasterBandStats struct per raster band in this raster layer.
* Note that while every RasterBandStats element will have the name and number of its associated
@ -151,7 +151,7 @@ public:
//QString greenBandName() const; //removed with raster redesign
/** \brief Accessor for mHasPyramids (READ ONLY) */
bool hasPyramids();
// bool hasPyramids();
/** \brief Accessor for mUserDefinedGrayMinimumMaximum */
bool hasUserDefinedGrayMinimumMaximum() const;
@ -248,7 +248,7 @@ public:
* ACTUALLY exists you need to look at the existsFlag member in each struct stored in the
* list.
*/
RasterPyramidList buildPyramidList();
// RasterPyramidList buildPyramidList();
/** \brief Accessor for color shader algorithm */
QString colorShadingAlgorithmAsString() const;
@ -470,9 +470,9 @@ public:
public slots:
/** \brief Create GDAL pyramid overviews */
QString buildPyramids( const RasterPyramidList &,
const QString & theResamplingMethod = "NEAREST",
bool theTryInternalFlag = false );
// QString buildPyramids( const RasterPyramidList &,
// const QString & theResamplingMethod = "NEAREST",
// bool theTryInternalFlag = false );
void showStatusMessage( const QString & theMessage );

View File

@ -3997,6 +3997,11 @@ void QgisApp::saveAsRasterFile()
}
fileWriter.setCreateOptions( d.createOptions() );
fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
fileWriter.setPyramidsList( d.overviewList() );
fileWriter.setPyramidsResampling( d.pyramidsResampling() );
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
fileWriter.writeRaster( pipe, d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd );
delete pipe;
}

View File

@ -117,13 +117,20 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
{
return;
}
QgsRasterDataProvider* provider = mRasterLayer->dataProvider();
// Only do pyramids if dealing directly with GDAL.
if ( provider->capabilities() & QgsRasterDataProvider::BuildPyramids )
{
QgsRasterLayer::RasterPyramidList myPyramidList = mRasterLayer->buildPyramidList();
QgsRasterLayer::RasterPyramidList::iterator myRasterPyramidIterator;
// initialize resampling methods
cboResamplingMethod->clear();
foreach ( QString method, QgsRasterDataProvider::pyramidResamplingMethods( mRasterLayer->providerType() ) )
cboResamplingMethod->addItem( method );
// build pyramid list
QList< QgsRasterPyramid > myPyramidList = provider->buildPyramidList();
QList< QgsRasterPyramid >::iterator myRasterPyramidIterator;
for ( myRasterPyramidIterator = myPyramidList.begin();
myRasterPyramidIterator != myPyramidList.end();
@ -762,13 +769,14 @@ void QgsRasterLayerProperties::apply()
void QgsRasterLayerProperties::on_buttonBuildPyramids_clicked()
{
QgsRasterDataProvider* provider = mRasterLayer->dataProvider();
connect( mRasterLayer, SIGNAL( progressUpdate( int ) ), mPyramidProgress, SLOT( setValue( int ) ) );
connect( provider, SIGNAL( progressUpdate( int ) ), mPyramidProgress, SLOT( setValue( int ) ) );
//
// Go through the list marking any files that are selected in the listview
// as true so that we can generate pyramids for them.
//
QgsRasterLayer::RasterPyramidList myPyramidList = mRasterLayer->buildPyramidList();
QList< QgsRasterPyramid> myPyramidList = provider->buildPyramidList();
for ( int myCounterInt = 0; myCounterInt < lbxPyramidResolutions->count(); myCounterInt++ )
{
QListWidgetItem *myItem = lbxPyramidResolutions->item( myCounterInt );
@ -781,15 +789,14 @@ void QgsRasterLayerProperties::on_buttonBuildPyramids_clicked()
// let the user know we're going to possibly be taking a while
QApplication::setOverrideCursor( Qt::WaitCursor );
bool myBuildInternalFlag = cbxInternalPyramids->isChecked();
QString res = mRasterLayer->buildPyramids(
QString res = provider->buildPyramids(
myPyramidList,
cboResamplingMethod->currentText(),
myBuildInternalFlag );
( QgsRasterDataProvider::RasterPyramidsFormat ) cbxPyramidsFormat->currentIndex() );
QApplication::restoreOverrideCursor();
mPyramidProgress->setValue( 0 );
buttonBuildPyramids->setEnabled( false );
disconnect( mRasterLayer, SIGNAL( progressUpdate( int ) ), mPyramidProgress, SLOT( setValue( int ) ) );
disconnect( provider, SIGNAL( progressUpdate( int ) ), mPyramidProgress, SLOT( setValue( int ) ) );
if ( !res.isNull() )
{
if ( res == "ERROR_WRITE_ACCESS" )
@ -821,17 +828,16 @@ void QgsRasterLayerProperties::on_buttonBuildPyramids_clicked()
}
//
// repopulate the pyramids list
//
lbxPyramidResolutions->clear();
// Need to rebuild list as some or all pyramids may have failed to build
myPyramidList = mRasterLayer->buildPyramidList();
myPyramidList = provider->buildPyramidList();
QIcon myPyramidPixmap( QgsApplication::getThemeIcon( "/mIconPyramid.png" ) );
QIcon myNoPyramidPixmap( QgsApplication::getThemeIcon( "/mIconNoPyramid.png" ) );
QgsRasterLayer::RasterPyramidList::iterator myRasterPyramidIterator;
QList< QgsRasterPyramid >::iterator myRasterPyramidIterator;
for ( myRasterPyramidIterator = myPyramidList.begin();
myRasterPyramidIterator != myPyramidList.end();
++myRasterPyramidIterator )

View File

@ -272,6 +272,26 @@ QByteArray QgsRasterDataProvider::noValueBytes( int theBandNo )
return ba;
}
bool QgsRasterDataProvider::hasPyramids()
{
QList<QgsRasterPyramid> myPyramidList = buildPyramidList();
if ( myPyramidList.isEmpty() )
return false;
QList<QgsRasterPyramid>::iterator myRasterPyramidIterator;
for ( myRasterPyramidIterator = myPyramidList.begin();
myRasterPyramidIterator != myPyramidList.end();
++myRasterPyramidIterator )
{
if ( myRasterPyramidIterator->exists )
{
return true;
}
}
return false;
}
#if 0
QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo )
{

View File

@ -102,6 +102,20 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
ProgressStatistics = 2
};
enum RasterBuildPyramids
{
PyramidsFlagNo = 0,
PyramidsFlagYes = 1,
CopyExisting = 2
};
enum RasterPyramidsFormat
{
PyramidsGTiff = 0,
PyramidsInternal = 1,
PyramidsErdas = 2
};
QgsRasterDataProvider();
QgsRasterDataProvider( QString const & uri );
@ -345,15 +359,24 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
/** \brief Create pyramid overviews */
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
const QString & theResamplingMethod = "NEAREST",
bool theTryInternalFlag = false )
{ Q_UNUSED( thePyramidList ); Q_UNUSED( theResamplingMethod ); Q_UNUSED( theTryInternalFlag ); return "FAILED_NOT_SUPPORTED"; };
RasterPyramidsFormat theFormat = PyramidsGTiff )
{
Q_UNUSED( thePyramidList ); Q_UNUSED( theResamplingMethod ); Q_UNUSED( theFormat );
return "FAILED_NOT_SUPPORTED";
};
/** \brief Accessor for ths raster layers pyramid list. A pyramid list defines the
/** \brief Accessor for ths raster layers pyramid list.
* @param overviewList used to construct the pyramid list (optional), when empty the list is defined by the provider.
* A pyramid list defines the
* POTENTIAL pyramids that can be in a raster. To know which of the pyramid layers
* ACTUALLY exists you need to look at the existsFlag member in each struct stored in the
* list.
*/
virtual QList<QgsRasterPyramid> buildPyramidList() { return QList<QgsRasterPyramid>(); };
virtual QList<QgsRasterPyramid> buildPyramidList( QList<int> overviewList = QList<int>() )
{ Q_UNUSED( overviewList ); return QList<QgsRasterPyramid>(); };
/** \brief Returns true if raster has at least one populated histogram. */
bool hasPyramids();
/** If the provider supports it, return band stats for the
given band. Default behaviour is to blockwise read the data
@ -537,13 +560,21 @@ 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();
}
signals:
/** Emit a signal to notify of the progress event.
* Emited theProgress is in percents (0.0-100.0) */
void progress( int theType, double theProgress, QString theMessage );
void progressUpdate( int theProgress );
protected:
/**Dots per intch. Extended WMS (e.g. QGIS mapserver) support DPI dependent output and therefore
/**Dots per inch. Extended WMS (e.g. QGIS mapserver) support DPI dependent output and therefore
are suited for printing. A value of -1 means it has not been set
@note: this member has been added in version 1.2*/
int mDpi;

View File

@ -18,13 +18,20 @@
#include "qgsrasteriterator.h"
#include "qgsrasterlayer.h"
#include "qgsrasterprojector.h"
#include <QCoreApplication>
#include <QProgressDialog>
#include <QTextStream>
#include <QMessageBox>
#include "gdal.h"
QgsRasterFileWriter::QgsRasterFileWriter( const QString& outputUrl ): mOutputUrl( outputUrl ), mOutputProviderKey( "gdal" ), mOutputFormat( "GTiff" ), mTiledMode( false ),
mMaxTileWidth( 500 ), mMaxTileHeight( 500 ), mProgressDialog( 0 )
QgsRasterFileWriter::QgsRasterFileWriter( const QString& outputUrl ):
mOutputUrl( outputUrl ), mOutputProviderKey( "gdal" ), mOutputFormat( "GTiff" ),
mTiledMode( false ), mMaxTileWidth( 500 ), mMaxTileHeight( 500 ),
mBuildPyramidsFlag( QgsRasterDataProvider::PyramidsFlagNo ),
mPyramidsFormat( QgsRasterDataProvider::PyramidsGTiff ),
mProgressDialog( 0 )
{
}
@ -210,6 +217,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
destNoDataValueList.append( destNoDataValue );
}
// TODO - what is this code doing here in the middle of the file, outside of a function???
QgsRasterInterface::DataType destDataType = destDataTypeList.value( 0 );
// Currently write API supports one output type for dataset only -> find the widest
@ -281,6 +289,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
{
iter->startRasterRead( i, nCols, nRows, outputExtent );
dataList.push_back( VSIMalloc( dataTypeSize * mMaxTileWidth * mMaxTileHeight ) );
// TODO - fix segfault here when using tiles+vrt (reported by Etienne)
destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
}
@ -296,6 +305,8 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
}
// hmm why is there a while( true ) here ..
// not good coding practice IMHO, it might be better to use [ for() and break ] or [ while (test) ]
while ( true )
{
for ( int i = 1; i <= nBands; ++i )
@ -310,7 +321,13 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
writeVRT( vrtFilePath );
buildPyramids( vrtFilePath );
}
else
{
if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes )
buildPyramids( mOutputUrl );
}
QgsDebugMsg( "Done" );
return NoError; //reached last tile, bail out
}
// TODO: verify if NoDataConflict happened, to do that we need the whole pipe or nuller interface
@ -356,6 +373,8 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
}
++fileIndex;
}
QgsDebugMsg( "Done" );
return NoError;
}
@ -482,6 +501,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste
++fileIndex;
}
delete destProvider;
CPLFree( redData ); CPLFree( greenData ); CPLFree( blueData ); CPLFree( alphaData );
@ -497,6 +517,11 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste
writeVRT( vrtFilePath );
buildPyramids( vrtFilePath );
}
else
{
if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes )
buildPyramids( mOutputUrl );
}
return NoError;
}
@ -565,6 +590,7 @@ void QgsRasterFileWriter::addToVRT( const QString& filename, int band, int xSize
bandElem.appendChild( simpleSourceElem );
}
#if 0
void QgsRasterFileWriter::buildPyramids( const QString& filename )
{
GDALDatasetH dataSet;
@ -593,6 +619,67 @@ void QgsRasterFileWriter::buildPyramids( const QString& filename )
}*/
GDALBuildOverviews( dataSet, "AVERAGE", 6, overviewList, 0, 0, /*pyramidsProgress*/ 0, /*mProgressDialog*/ 0 );
}
#endif
void QgsRasterFileWriter::buildPyramids( const QString& filename )
{
// open new dataProvider so we can build pyramids with it
QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, filename );
if ( !destProvider )
{
return;
}
// TODO progress report
// TODO test mTiledMode - not tested b/c segfault at line # 289
// connect( provider, SIGNAL( progressUpdate( int ) ), mPyramidProgress, SLOT( setValue( int ) ) );
QList< QgsRasterPyramid> myPyramidList;
if ( ! mPyramidsList.isEmpty() )
myPyramidList = destProvider->buildPyramidList( mPyramidsList );
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
myPyramidList[myCounterInt].build = true;
}
QgsDebugMsg( QString( "building pyramids : %1 pyramids, %2 resampling, %3 format" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( mPyramidsFormat ) );
// QApplication::setOverrideCursor( Qt::WaitCursor );
QString res = destProvider->buildPyramids( myPyramidList, mPyramidsResampling, mPyramidsFormat );
// QApplication::restoreOverrideCursor();
// TODO put this in provider or elsewhere
if ( !res.isNull() )
{
QString title, message;
if ( res == "ERROR_WRITE_ACCESS" )
{
title = QObject::tr( "Building pyramids failed - write access denied" );
message = QObject::tr( "Write access denied. Adjust the file permissions and try again." );
}
else if ( res == "ERROR_WRITE_FORMAT" )
{
title = QObject::tr( "Building pyramids failed." );
message = QObject::tr( "The file was not writable. Some formats do not "
"support pyramid overviews. Consult the GDAL documentation if in doubt." );
}
else if ( res == "FAILED_NOT_SUPPORTED" )
{
title = QObject::tr( "Building pyramids failed." );
message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
}
else if ( res == "ERROR_JPEG_COMPRESSION" )
{
title = QObject::tr( "Building pyramids failed." );
message = QObject::tr( "Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
}
else if ( res == "ERROR_VIRTUAL" )
{
title = QObject::tr( "Building pyramids failed." );
message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
}
QMessageBox::warning( 0, title, message );
QgsDebugMsg( res + " - " + message );
}
}
int QgsRasterFileWriter::pyramidsProgress( double dfComplete, const char *pszMessage, void* pData )
{
@ -744,6 +831,11 @@ QgsRasterDataProvider* QgsRasterFileWriter::initOutput( int nCols, int nRows, co
return 0;
}
// TODO enable "use existing", has no effect for now, because using Create() in gdal provider
// should this belong in provider? should also test that source provider is gdal
// if ( mBuildPyramidsFlag == -4 && mOutputProviderKey == "gdal" && mOutputFormat.toLower() == "gtiff" )
// mCreateOptions << "COPY_SRC_OVERVIEWS=YES";
if ( !destProvider->create( mOutputFormat, nBands, type, nCols, nRows, geoTransform,
crs, mCreateOptions ) )
{

View File

@ -66,6 +66,18 @@ class CORE_EXPORT QgsRasterFileWriter
void setMaxTileWidth( int w ) { mMaxTileWidth = w; }
int maxTileWidth() const { return mMaxTileWidth; }
QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const { return mBuildPyramidsFlag; }
void setBuildPyramidsFlag( QgsRasterDataProvider::RasterBuildPyramids f ) { mBuildPyramidsFlag = f; }
QList< int > pyramidsList() const { return mPyramidsList; }
void setPyramidsList( const QList< int > & list ) { mPyramidsList = list; }
QString pyramidsResampling() const { return mPyramidsResampling; }
void setPyramidsResampling( const QString & str ) { mPyramidsResampling = str; }
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const { return mPyramidsFormat; }
void setPyramidsFormat( QgsRasterDataProvider::RasterPyramidsFormat f ) { mPyramidsFormat = f; }
void setMaxTileHeight( int h ) { mMaxTileHeight = h; }
int maxTileHeight() const { return mMaxTileHeight; }
@ -128,6 +140,11 @@ class CORE_EXPORT QgsRasterFileWriter
double mMaxTileWidth;
double mMaxTileHeight;
QList< int > mPyramidsList;
QString mPyramidsResampling;
QgsRasterDataProvider::RasterBuildPyramids mBuildPyramidsFlag;
QgsRasterDataProvider::RasterPyramidsFormat mPyramidsFormat;
QDomDocument mVRTDocument;
QDomElement mVRTRedBand;
QDomElement mVRTGreenBand;

View File

@ -23,9 +23,7 @@ email : tim at linfiniti.com
#include "qgsmaptopixel.h"
#include "qgsprojectfiletransform.h"
#include "qgsproviderregistry.h"
#include "qgsrasterbandstats.h"
#include "qgsrasterlayer.h"
#include "qgsrasterpyramid.h"
#include "qgsrasterrendererregistry.h"
#include "qgsrectangle.h"
#include "qgsrendercontext.h"
@ -423,7 +421,6 @@ const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBand
return QgsRasterBandStats(); // return a null one
}
#endif
QString QgsRasterLayer::buildPyramids( RasterPyramidList const & theRasterPyramidList,
QString const & theResamplingMethod, bool theTryInternalFlag )
@ -436,6 +433,7 @@ QgsRasterLayer::RasterPyramidList QgsRasterLayer::buildPyramidList()
{
return mDataProvider->buildPyramidList();
}
#endif
QString QgsRasterLayer::colorShadingAlgorithmAsString() const
{
@ -1558,7 +1556,6 @@ void QgsRasterLayer::init()
setDrawingStyle( QgsRasterLayer::UndefinedDrawingStyle );
mBandCount = 0;
mHasPyramids = false;
mNoDataValue = -9999.0;
mValidNoDataValue = false;
@ -1822,12 +1819,7 @@ void QgsRasterLayer::closeDataProvider()
mValid = false;
mPipe.remove( mDataProvider );
mDataProvider = 0;
//mRasterStatsList.clear();
mContrastEnhancementList.clear();
mHasPyramids = false;
mPyramidList.clear();
}
void QgsRasterLayer::setColorShadingAlgorithm( ColorShadingAlgorithm )

View File

@ -51,8 +51,6 @@
//
class QgsMapToPixel;
class QgsRectangle;
class QgsRasterBandStats;
class QgsRasterPyramid;
class QgsRasterRenderer;
class QImage;
class QPixmap;
@ -273,12 +271,12 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
* to be added to the list. Each time a RasterPyramid is created
* we will check to see if a pyramid matching these dimensions already exists
* in the raster layer, and if so mark the exists flag as true */
typedef QList<QgsRasterPyramid> RasterPyramidList;
/* typedef QList<QgsRasterPyramid> RasterPyramidList; */
/** \brief A list containing one RasterBandStats struct per raster band in this raster layer.
* Note that while every RasterBandStats element will have the name and number of its associated
* band populated, any additional stats are calculated on a need to know basis.*/
typedef QList<QgsRasterBandStats> RasterStatsList;
/* typedef QList<QgsRasterBandStats> RasterStatsList; */
//
// Static methods:
@ -332,7 +330,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
DrawingStyle drawingStyle() { return mDrawingStyle; }
/** \brief Accessor for mHasPyramids (READ ONLY) */
bool hasPyramids() { return mHasPyramids; }
/* bool hasPyramids() { return dataProvider() != NULL ? dataProvider()->hasPyramids() : false ; } */
/** \brief Accessor for mUserDefinedGrayMinimumMaximum */
bool hasUserDefinedGrayMinimumMaximum() const { return mUserDefinedGrayMinimumMaximum; }
@ -414,7 +412,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
* ACTUALLY exists you need to look at the existsFlag member in each struct stored in the
* list.
*/
RasterPyramidList buildPyramidList();
// RasterPyramidList buildPyramidList();
/** \brief Accessor for color shader algorithm */
QString colorShadingAlgorithmAsString() const;
@ -677,9 +675,9 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
public slots:
/** \brief Create GDAL pyramid overviews */
QString buildPyramids( const RasterPyramidList &,
const QString & theResamplingMethod = "NEAREST",
bool theTryInternalFlag = false );
// QString buildPyramids( const RasterPyramidList &,
// const QString & theResamplingMethod = "NEAREST",
// bool theTryInternalFlag = false );
void showStatusMessage( const QString & theMessage );
@ -853,9 +851,6 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
/** \brief Values for mapping pixel to world coordinates. Contents of this array are the same as the GDAL adfGeoTransform */
double mGeoTransform[6];
/** \brief Whether this raster has overviews / pyramids or not */
bool mHasPyramids;
/** \brief Raster width */
int mWidth;
@ -880,7 +875,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
QString mProviderKey;
/** \brief This list holds a series of RasterPyramid structs which store information for each potential pyramid level */
RasterPyramidList mPyramidList;
/* RasterPyramidList mPyramidList; */
/** \brief A collection of stats - one for each band in the layer */
//RasterStatsList mRasterStatsList;

View File

@ -77,10 +77,32 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer* rasterLa
mCreateOptionsWidget->setFormat( myFormats[0] );
}
mCreateOptionsWidget->update();
}
// Only do pyramids if dealing directly with GDAL.
if ( mDataProvider->capabilities() & QgsRasterDataProvider::BuildPyramids )
{
mPyramidsOptionsWidget->createOptionsWidget()->setType( QgsRasterFormatSaveOptionsWidget::ProfileLineEdit );
// init. pyramids button group
for ( int i = -2, j = 0 ; i >= -4 ; i--, j++ )
mPyramidsButtonGroup->setId( mPyramidsButtonGroup->button( i ), j );
// TODO enable "use existing", has no effect for now, because using Create() in gdal provider
// if ( ! mDataProvider->hasPyramids() )
// mPyramidsButtonGroup->button( QgsRasterDataProvider::CopyExisting )->setEnabled( false );
mPyramidsButtonGroup->button( QgsRasterDataProvider::CopyExisting )->setEnabled( false );
mPyramidsButtonGroup->button( QgsRasterDataProvider::PyramidsFlagNo )->click();
mPyramidsButtonGroup->button( QgsRasterDataProvider::PyramidsFlagNo )->setChecked( true );
populatePyramidsLevels();
connect( mPyramidsOptionsWidget, SIGNAL( overviewListChanged() ),
this, SLOT( populatePyramidsLevels() ) );
}
else
{
mPyramidsGroupBox->setEnabled( false );
}
updateCrsGroup();
QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok );
@ -627,6 +649,75 @@ void QgsRasterLayerSaveAsDialog::noDataCellTextEdited( const QString & text )
}
}
void QgsRasterLayerSaveAsDialog::on_mTileModeCheckBox_toggled( bool toggled )
{
if ( toggled )
{
// enable pyramids
if ( ! mPyramidsGroupBox->isChecked() )
mPyramidsGroupBox->setChecked( true );
if ( mPyramidsButtonGroup->checkedId() == QgsRasterDataProvider::PyramidsFlagNo )
{
mPyramidsButtonGroup->button( QgsRasterDataProvider::PyramidsFlagYes )->click();
mPyramidsButtonGroup->button( QgsRasterDataProvider::PyramidsFlagYes )->setChecked( true );
}
mPyramidsOptionsWidget->checkAllLevels( true );
}
}
void QgsRasterLayerSaveAsDialog::on_mPyramidsButtonGroup_buttonClicked( int id )
{
if ( id == QgsRasterDataProvider::PyramidsFlagNo || id == QgsRasterDataProvider::CopyExisting )
{
mPyramidsOptionsWidget->setEnabled( false );
mPyramidResolutionsLabel->setEnabled( false );
mPyramidResolutionsLineEdit->setEnabled( false );
}
else if ( id == QgsRasterDataProvider::PyramidsFlagYes )
{
mPyramidsOptionsWidget->setEnabled( true );
mPyramidResolutionsLabel->setEnabled( true );
mPyramidResolutionsLineEdit->setEnabled( true );
}
else
QgsDebugMsg( QString( "invalid button id %1" ).arg( id ) );
populatePyramidsLevels();
}
void QgsRasterLayerSaveAsDialog::populatePyramidsLevels()
{
// if selection != "Build pyramids", get pyramids from actual layer
QString text;
if ( mPyramidsButtonGroup->checkedId() != QgsRasterDataProvider::PyramidsFlagNo )
{
QList<QgsRasterPyramid> myPyramidList;
if ( mPyramidsButtonGroup->checkedId() == QgsRasterDataProvider::CopyExisting )
{
myPyramidList = mDataProvider->buildPyramidList();
}
else if ( mPyramidsButtonGroup->checkedId() == QgsRasterDataProvider::PyramidsFlagYes )
{
if ( ! mPyramidsOptionsWidget->overviewList().isEmpty() )
myPyramidList = mDataProvider->buildPyramidList( mPyramidsOptionsWidget->overviewList() );
}
QList<QgsRasterPyramid>::iterator myRasterPyramidIterator;
for ( myRasterPyramidIterator = myPyramidList.begin();
myRasterPyramidIterator != myPyramidList.end();
++myRasterPyramidIterator )
{
if ( mPyramidsButtonGroup->checkedId() == QgsRasterDataProvider::PyramidsFlagYes
|| myRasterPyramidIterator->exists )
{
text += QString::number( myRasterPyramidIterator->xDim ) + QString( "x" ) +
QString::number( myRasterPyramidIterator->yDim ) + " ";
}
}
}
mPyramidResolutionsLineEdit->setText( text.trimmed() );
}
void QgsRasterLayerSaveAsDialog::setNoDataToEdited( int row )
{
if ( row >= mNoDataToEdited.size() )

View File

@ -58,6 +58,14 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
QgsRectangle outputRectangle() const;
QList<QgsRasterNuller::NoData> noData() const;
QList< int > overviewList() const { return mPyramidsOptionsWidget->overviewList(); }
QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const
{ return ( QgsRasterDataProvider::RasterBuildPyramids ) mPyramidsButtonGroup->checkedId(); }
QString pyramidsResampling() const { return mPyramidsOptionsWidget->resamplingMethod(); }
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const
{ return mPyramidsOptionsWidget->pyramidsFormat(); }
void hideFormat();
void hideOutput();
@ -92,6 +100,9 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
void on_mRemoveSelectedNoDataToolButton_clicked();
void on_mRemoveAllNoDataToolButton_clicked();
void noDataCellTextEdited( const QString & text );
void on_mTileModeCheckBox_toggled( bool toggled );
void on_mPyramidsButtonGroup_buttonClicked( int id );
void populatePyramidsLevels();
private:
QgsRasterLayer* mRasterLayer;

View File

@ -34,10 +34,10 @@
QgsRasterPyramidsOptionsWidget::QgsRasterPyramidsOptionsWidget( QWidget* parent, QString provider )
: QWidget( parent ), mProvider( provider )
: QWidget( parent ), mProvider( provider )
{
setupUi( this );
mPyramidsOptionsWidget->setProvider( provider );
mPyramidsOptionsWidget->setFormat( "_pyramids" );
// mPyramidsOptionsWidget->swapOptionsUI( 1 );
@ -59,14 +59,23 @@ void QgsRasterPyramidsOptionsWidget::updateUi()
// cbxPyramidsInternal->setChecked( mySettings.value( prefix + "internal", false ).toBool() );
tmpStr = mySettings.value( prefix + "format", "gtiff" ).toString();
if ( tmpStr == "internal" )
cboPyramidsFormat->setCurrentIndex( 0 );
else if ( tmpStr == "erdas" )
cboPyramidsFormat->setCurrentIndex( 2 );
cbxPyramidsFormat->setCurrentIndex( 1 );
else if ( tmpStr == "external_erdas" )
cbxPyramidsFormat->setCurrentIndex( 2 );
else
cboPyramidsFormat->setCurrentIndex( 1 );
cboResamplingMethod->setCurrentIndex( cboResamplingMethod->findText(
mySettings.value( prefix + "resampling", "Average" ).toString() ) );
lePyramidsLevels->setText( mySettings.value( prefix + "overviewStr", "bla" ).toString() );
cbxPyramidsFormat->setCurrentIndex( 0 );
// initialize resampling methods
cboResamplingMethod->clear();
foreach ( QString method, QgsRasterDataProvider::pyramidResamplingMethods( mProvider ) )
cboResamplingMethod->addItem( method );
cboResamplingMethod->setCurrentIndex( cboResamplingMethod->findText(
mySettings.value( prefix + "resampling", "Average" ).toString() ) );
// validate string, only space-separated positive integers are allowed
lePyramidsLevels->setValidator( new QRegExpValidator( QRegExp( "(\\d*)(\\s\\d*)*" ), lePyramidsLevels ) );
connect( lePyramidsLevels, SIGNAL( editingFinished() ),
this, SLOT( setOverviewList() ) );
// overview list
if ( mOverviewCheckBoxes.isEmpty() )
@ -74,48 +83,57 @@ void QgsRasterPyramidsOptionsWidget::updateUi()
QList<int> overviewList;
overviewList << 2 << 4 << 8 << 16 << 32 << 64;
mOverviewCheckBoxes.clear();
foreach( int i, overviewList )
foreach ( int i, overviewList )
{
mOverviewCheckBoxes[ i ] = new QCheckBox( QString::number( i ), this );
layoutPyramidLevels->addWidget( mOverviewCheckBoxes[ i ] );
connect( mOverviewCheckBoxes[ i ], SIGNAL( toggled( bool ) ),
this, SLOT( setOverviewList() ) );
layoutPyramidsLevels->addWidget( mOverviewCheckBoxes[ i ] );
}
}
else
{
foreach( int i, mOverviewCheckBoxes.keys() )
foreach ( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setChecked( false );
}
tmpStr = mySettings.value( prefix + "overviewList", "" ).toString();
foreach( QString lev, tmpStr.split( " ", QString::SkipEmptyParts ) )
foreach ( QString lev, tmpStr.split( " ", QString::SkipEmptyParts ) )
{
if( mOverviewCheckBoxes.contains( lev.toInt() ) )
mOverviewCheckBoxes[ lev.toInt() ]->setChecked( true );
if ( mOverviewCheckBoxes.contains( lev.toInt() ) )
mOverviewCheckBoxes[ lev.toInt()]->setChecked( true );
}
on_lePyramidsLevels_editingFinished();
setOverviewList();
mPyramidsOptionsWidget->updateProfiles();
}
QString QgsRasterPyramidsOptionsWidget::resamplingMethod() const
{
return cboResamplingMethod->currentText().trimmed();
}
void QgsRasterPyramidsOptionsWidget::apply()
{
QSettings mySettings;
QString prefix = mProvider + "/driverOptions/_pyramids/";
QString tmpStr;
// mySettings.setValue( prefix + "internal", cbxPyramidsInternal->isChecked() );
if ( cboPyramidsFormat->currentIndex() == 0 )
if ( cbxPyramidsFormat->currentIndex() == 1 )
tmpStr = "internal";
else if ( cboPyramidsFormat->currentIndex() == 2 )
tmpStr = "erdas";
else
tmpStr = "tiff";
else if ( cbxPyramidsFormat->currentIndex() == 2 )
tmpStr = "external_erdas";
else
tmpStr = "external";
mySettings.setValue( prefix + "format", tmpStr );
mySettings.setValue( prefix + "resampling", cboResamplingMethod->currentText().trimmed() );
mySettings.setValue( prefix + "overviewStr", lePyramidsLevels->text().trimmed() );
// overview list
tmpStr = "";
foreach( int i, mOverviewCheckBoxes.keys() )
foreach ( int i, mOverviewCheckBoxes.keys() )
{
if ( mOverviewCheckBoxes[ i ]->isChecked() )
tmpStr += QString::number( i ) + " ";
@ -125,29 +143,51 @@ void QgsRasterPyramidsOptionsWidget::apply()
mPyramidsOptionsWidget->apply();
}
void QgsRasterPyramidsOptionsWidget::on_lePyramidsLevels_editingFinished()
void QgsRasterPyramidsOptionsWidget::checkAllLevels( bool checked )
{
// validate string, only space-separated positive integers are allowed
// should we also validate that numbers are increasing?
QString tmpStr;
int tmpInt;
foreach( QString lev, lePyramidsLevels->text().trimmed().split( " ", QString::SkipEmptyParts ) )
{
tmpInt = lev.toInt();
if ( tmpInt > 0 )
tmpStr += QString::number( tmpInt ) + " ";
}
lePyramidsLevels->setText( tmpStr.trimmed() );
foreach ( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setChecked( checked );
}
// if text is non-empty, disable checkboxes
if ( lePyramidsLevels->text() == "" )
void QgsRasterPyramidsOptionsWidget::on_cbxPyramidsLevelsCustom_toggled( bool toggled )
{
// if toggled, disable checkboxes and enable line edit
lePyramidsLevels->setEnabled( toggled );
foreach ( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setEnabled( ! toggled );
setOverviewList();
}
void QgsRasterPyramidsOptionsWidget::setOverviewList()
{
QgsDebugMsg( "Entered" );
mOverviewList.clear();
// if custum levels is toggled, get selection from line edit
if ( cbxPyramidsLevelsCustom->isChecked() )
{
foreach( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setEnabled( true );
// should we also validate that numbers are increasing?
foreach ( QString lev, lePyramidsLevels->text().trimmed().split( " ", QString::SkipEmptyParts ) )
{
QgsDebugMsg( "lev= " + lev );
int tmpInt = lev.toInt();
if ( tmpInt > 0 )
{
QgsDebugMsg( "tmpInt= " + QString::number( tmpInt ) );
// if number is valid, add to overview list
mOverviewList << tmpInt;
}
}
}
else
{
foreach( int i, mOverviewCheckBoxes.keys() )
mOverviewCheckBoxes[ i ]->setEnabled( false );
foreach ( int i, mOverviewCheckBoxes.keys() )
{
if ( mOverviewCheckBoxes[ i ]->isChecked() )
mOverviewList << i;
}
}
emit overviewListChanged();
}

View File

@ -19,6 +19,7 @@
#define QGSRASTERPYRAMIDSOPTIONSWIDGET_H
#include "ui_qgsrasterpyramidsoptionswidgetbase.h"
#include "qgsrasterdataprovider.h"
class QCheckBox;
@ -32,31 +33,38 @@ class GUI_EXPORT QgsRasterPyramidsOptionsWidget: public QWidget,
public:
QgsRasterPyramidsOptionsWidget( QWidget* parent = 0, QString provider = "gdal" );
QgsRasterPyramidsOptionsWidget( QWidget* parent = 0, QString provider = "gdal" );
~QgsRasterPyramidsOptionsWidget();
void setProvider( QString provider );
QStringList createOptions() const { return mPyramidsOptionsWidget->options(); }
QgsRasterFormatSaveOptionsWidget* createOptionsWidget() { return mPyramidsOptionsWidget; }
const QList<int> overviewList() const { return mOverviewList; }
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const
{ return ( QgsRasterDataProvider::RasterPyramidsFormat ) cbxPyramidsFormat->currentIndex(); }
QString resamplingMethod() const;
public slots:
void apply();
void checkAllLevels( bool checked );
private slots:
void on_lePyramidsLevels_editingFinished();
void on_cboPyramidsFormat_currentIndexChanged( int index )
void on_cbxPyramidsLevelsCustom_toggled( bool toggled );
void on_cbxPyramidsFormat_currentIndexChanged( int index )
{ mPyramidsOptionsWidget->setEnabled( index != 2 ); }
void setOverviewList();
signals:
void overviewListChanged();
private:
void updateUi();
QString mProvider;
bool mInternal;
QString mResamplingMethod;
QList<int> mOverviewList;
QList< int > mOverviewList;
QMap< int, QCheckBox* > mOverviewCheckBoxes;
};

View File

@ -82,6 +82,7 @@ int CPL_STDCALL progressCallback( double dfComplete,
if ( floor( dfLastComplete*10 ) != floor( dfComplete*10 ) )
{
mypProvider->emitProgress( prog->type, dfComplete * 100, QString( pszMessage ) );
mypProvider->emitProgressUpdate( dfComplete * 100 );
}
dfLastComplete = dfComplete;
@ -1294,7 +1295,7 @@ QgsRasterHistogram QgsGdalProvider::histogram( int theBandNo,
* @return null string on success, otherwise a string specifying error
*/
QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRasterPyramidList,
QString const & theResamplingMethod, bool theTryInternalFlag )
QString const & theResamplingMethod, RasterPyramidsFormat theFormat )
{
//TODO: Consider making theRasterPyramidList modifyable by this method to indicate if the pyramid exists after build attempt
//without requiring the user to rebuild the pyramid list to get the updated infomation
@ -1324,7 +1325,8 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
return "ERROR_VIRTUAL";
}
if ( theTryInternalFlag )
// check if building internally
if ( theFormat == PyramidsInternal )
{
// libtiff < 4.0 has a bug that prevents safe building of overviews on JPEG compressed files
// we detect libtiff < 4.0 by checking that BIGTIFF is not in the creation options of the GTiff driver
@ -1340,26 +1342,37 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
}
}
//close the gdal dataset and reopen it in read / write mode
GDALClose( mGdalDataset );
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri() ).constData(), GA_Update );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_Update );
// if the dataset couldn't be opened in read / write mode, tell the user
if ( !mGdalBaseDataset )
//if needed close the gdal dataset and reopen it in read / write mode
if ( GDALGetAccess( mGdalDataset ) == GA_ReadOnly )
{
//mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_ReadOnly );
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri()).constData(), GA_ReadOnly );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_ReadOnly );
//Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
mGdalDataset = mGdalBaseDataset;
return "ERROR_WRITE_FORMAT";
GDALClose( mGdalDataset );
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri() ).constData(), GA_Update );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_Update );
// if the dataset couldn't be opened in read / write mode, tell the user
if ( !mGdalBaseDataset )
{
//mGdalBaseDataset = GDALOpen( QFile::encodeName( mDataSource ).constData(), GA_ReadOnly );
//mGdalBaseDataset = GDALOpen( QFile::encodeName( dataSourceUri()).constData(), GA_ReadOnly );
mGdalBaseDataset = GDALOpen( TO8F( dataSourceUri() ), GA_ReadOnly );
//Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
mGdalDataset = mGdalBaseDataset;
return "ERROR_WRITE_FORMAT";
}
}
}
// are we using Erdas Imagine external overviews?
const char* myConfigUseRRD = CPLGetConfigOption( "USE_RRD", "NO" );
if ( theFormat == PyramidsErdas )
CPLSetConfigOption( "USE_RRD", "YES" );
else
CPLSetConfigOption( "USE_RRD", "NO" );
//
// Iterate through the Raster Layer Pyramid Vector, building any pyramid
// marked as exists in eaxh RasterPyramid struct.
// marked as exists in each RasterPyramid struct.
//
CPLErr myError; //in case anything fails
int myCount = 1;
@ -1380,7 +1393,8 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
//emit drawingProgress( myCount, myTotal );
int myOverviewLevelsArray[1] = { myRasterPyramidIterator->level };
/* From : http://remotesensing.org/gdal/classGDALDataset.html#a23
* pszResampling : one of "NEAREST", "AVERAGE" or "MODE" controlling the downsampling method applied.
* pszResampling : one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE", "AVERAGE_MAGPHASE" or "NONE"
* controlling the downsampling method applied.
* nOverviews : number of overviews to build.
* panOverviewList : the list of overview decimation factors to build.
* nBand : number of bands to build overviews for in panBandList. Build for all bands if this is 0.
@ -1391,31 +1405,35 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
//build the pyramid and show progress to console
try
{
//build the pyramid and show progress to console
//NOTE this (magphase) is disabled in the gui since it tends
//to create corrupted images. The images can be repaired
//by running one of the other resampling strategies below.
//see ticket #284
QgsGdalProgress myProg;
myProg.type = ProgressPyramids;
myProg.provider = this;
if ( theResamplingMethod == tr( "Average Magphase" ) )
{
myError = GDALBuildOverviews( mGdalBaseDataset, "MODE", 1, myOverviewLevelsArray, 0, NULL,
progressCallback, &myProg ); //this is the arg for the gdal progress callback
}
const char* theMethod;
if ( theResamplingMethod == tr( "Gauss" ) )
theMethod = "GAUSS";
else if ( theResamplingMethod == tr( "Cubic" ) )
theMethod = "CUBIC";
else if ( theResamplingMethod == tr( "Average" ) )
{
myError = GDALBuildOverviews( mGdalBaseDataset, "AVERAGE", 1, myOverviewLevelsArray, 0, NULL,
progressCallback, &myProg ); //this is the arg for the gdal progress callback
}
theMethod = "AVERAGE";
else if ( theResamplingMethod == tr( "Mode" ) )
theMethod = "MODE";
//NOTE magphase is disabled in the gui since it tends
//to create corrupted images. The images can be repaired
//by running one of the other resampling strategies below.
//see ticket #284
// else if ( theResamplingMethod == tr( "Average Magphase" ) )
// theMethod = "AVERAGE_MAGPHASE";
else if ( theResamplingMethod == tr( "None" ) )
theMethod = "NONE";
else // fall back to nearest neighbor
{
myError = GDALBuildOverviews( mGdalBaseDataset, "NEAREST", 1, myOverviewLevelsArray, 0, NULL,
progressCallback, &myProg ); //this is the arg for the gdal progress callback
}
theMethod = "NEAREST";
QgsDebugMsg( QString( "building overview at level %1 using resampling method %2"
).arg( myRasterPyramidIterator->level ).arg( theMethod ) );
// TODO - it would be more efficient to do it once instead of for each level
myError = GDALBuildOverviews( mGdalBaseDataset, theMethod, 1,
myOverviewLevelsArray, 0, NULL,
progressCallback, &myProg ); //this is the arg for the gdal progress callback
if ( myError == CE_Failure || CPLGetLastErrorNo() == CPLE_NotSupported )
{
@ -1429,6 +1447,8 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
mGdalDataset = mGdalBaseDataset;
//emit drawingProgress( 0, 0 );
// restore former USE_RRD config (Erdas)
CPLSetConfigOption( "USE_RRD", myConfigUseRRD );
return "FAILED_NOT_SUPPORTED";
}
else
@ -1446,8 +1466,11 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
}
}
// restore former USE_RRD config (Erdas)
CPLSetConfigOption( "USE_RRD", myConfigUseRRD );
QgsDebugMsg( "Pyramid overviews built" );
if ( theTryInternalFlag )
if ( theFormat == PyramidsInternal )
{
//close the gdal dataset and reopen it in read only mode
GDALClose( mGdalBaseDataset );
@ -1460,6 +1483,7 @@ QString QgsGdalProvider::buildPyramids( QList<QgsRasterPyramid> const & theRaste
return NULL; // returning null on success
}
#if 0
QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList()
{
//
@ -1535,6 +1559,95 @@ QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList()
return mPyramidList;
}
#endif
QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList( QList<int> overviewList )
{
int myWidth = mWidth;
int myHeight = mHeight;
GDALRasterBandH myGDALBand = GDALGetRasterBand( mGdalDataset, 1 ); //just use the first band
mPyramidList.clear();
// if overviewList is empty (default) build the pyramid list
if ( overviewList.isEmpty() )
{
int myDivisor = 2;
QgsDebugMsg( "Building initial pyramid list" );
while (( myWidth / myDivisor > 32 ) && (( myHeight / myDivisor ) > 32 ) )
{
overviewList.append( myDivisor );
//sqare the divisor each step
myDivisor = ( myDivisor * 2 );
}
}
// loop over pyramid list
foreach ( int myDivisor, overviewList )
{
//
// First we build up a list of potential pyramid layers
//
QgsRasterPyramid myRasterPyramid;
myRasterPyramid.level = myDivisor;
myRasterPyramid.xDim = ( int )( 0.5 + ( myWidth / ( double )myDivisor ) );
myRasterPyramid.yDim = ( int )( 0.5 + ( myHeight / ( double )myDivisor ) );
myRasterPyramid.exists = false;
QgsDebugMsg( QString( "Pyramid %1 xDim %2 yDim %3" ).arg( myRasterPyramid.level ).arg( myRasterPyramid.xDim ).arg( myRasterPyramid.yDim ) );
//
// Now we check if it actually exists in the raster layer
// and also adjust the dimensions if the dimensions calculated
// above are only a near match.
//
const int myNearMatchLimit = 5;
if ( GDALGetOverviewCount( myGDALBand ) > 0 )
{
int myOverviewCount;
for ( myOverviewCount = 0;
myOverviewCount < GDALGetOverviewCount( myGDALBand );
++myOverviewCount )
{
GDALRasterBandH myOverview;
myOverview = GDALGetOverview( myGDALBand, myOverviewCount );
int myOverviewXDim = GDALGetRasterBandXSize( myOverview );
int myOverviewYDim = GDALGetRasterBandYSize( myOverview );
//
// here is where we check if its a near match:
// we will see if its within 5 cells either side of
//
QgsDebugMsg( "Checking whether " + QString::number( myRasterPyramid.xDim ) + " x " +
QString::number( myRasterPyramid.yDim ) + " matches " +
QString::number( myOverviewXDim ) + " x " + QString::number( myOverviewYDim ) );
if (( myOverviewXDim <= ( myRasterPyramid.xDim + myNearMatchLimit ) ) &&
( myOverviewXDim >= ( myRasterPyramid.xDim - myNearMatchLimit ) ) &&
( myOverviewYDim <= ( myRasterPyramid.yDim + myNearMatchLimit ) ) &&
( myOverviewYDim >= ( myRasterPyramid.yDim - myNearMatchLimit ) ) )
{
//right we have a match so adjust the a / y before they get added to the list
myRasterPyramid.xDim = myOverviewXDim;
myRasterPyramid.yDim = myOverviewYDim;
myRasterPyramid.exists = true;
QgsDebugMsg( ".....YES!" );
}
else
{
//no match
QgsDebugMsg( ".....no." );
}
}
}
mPyramidList.append( myRasterPyramid );
}
return mPyramidList;
}
QStringList QgsGdalProvider::subLayers() const
{
@ -1546,6 +1659,11 @@ void QgsGdalProvider::emitProgress( int theType, double theProgress, QString the
emit progress( theType, theProgress, theMessage );
}
void QgsGdalProvider::emitProgressUpdate( int theProgress )
{
emit progressUpdate( theProgress );
}
/**
* Class factory to return a pointer to a newly created
* QgsGdalProvider object
@ -2221,6 +2339,11 @@ bool QgsGdalProvider::create( const QString& format, int nBands,
return false;
}
QString tmpStr = "create options:";
foreach ( QString option, createOptions )
tmpStr += " " + option;
QgsDebugMsg( tmpStr );
//create dataset
char **papszOptions = papszFromStringList( createOptions );
GDALDatasetH dataset = GDALCreate( driver, dataSourceUri().toLocal8Bit().data(), width, height, nBands, ( GDALDataType )type, papszOptions );

View File

@ -252,14 +252,15 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
QString buildPyramids( const QList<QgsRasterPyramid> &,
const QString & theResamplingMethod = "NEAREST",
bool theTryInternalFlag = false );
QList<QgsRasterPyramid> buildPyramidList();
RasterPyramidsFormat theFormat = PyramidsGTiff );
QList<QgsRasterPyramid> buildPyramidList( QList<int> overviewList = QList<int>() );
/** \brief Close data set and release related data */
void closeDataset();
/** Emit a signal to notify of the progress event. */
void emitProgress( int theType, double theProgress, QString theMessage );
void emitProgressUpdate( int theProgress );
static QMap<QString, QString> supportedMimes();

View File

@ -799,66 +799,6 @@
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Notes</string>
</property>
</widget>
</item>
<item row="0" column="3" colspan="2">
<widget class="QLabel" name="textLabel5">
<property name="text">
<string>Pyramid resolutions</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QTextEdit" name="tePyramidDescription">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>5</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="html">
<string></string>
</property>
</widget>
</item>
<item row="1" column="3" colspan="2">
<widget class="QListWidget" name="lbxPyramidResolutions">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32767</height>
</size>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="5">
<widget class="QCheckBox" name="cbxInternalPyramids">
<property name="text">
<string>Build pyramids internally if possible</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="textLabel4_2">
<property name="text">
<string>Resampling method</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="cboResamplingMethod">
<item>
@ -890,6 +830,95 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Notes</string>
</property>
</widget>
</item>
<item row="0" column="3" colspan="2">
<widget class="QLabel" name="textLabel5">
<property name="text">
<string>Pyramid resolutions</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QTextEdit" name="tePyramidDescription">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>5</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="3" colspan="2">
<widget class="QListWidget" name="lbxPyramidResolutions">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32767</height>
</size>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="textLabel4_2">
<property name="text">
<string>Resampling method</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Overview format</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cbxPyramidsFormat">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>External</string>
</property>
</item>
<item>
<property name="text">
<string>Internal (if possible)</string>
</property>
</item>
<item>
<property name="text">
<string>External (Erdas Imagine)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabPageHistogram">
@ -919,9 +948,6 @@
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>550</width>
<width>575</width>
<height>580</height>
</rect>
</property>
@ -29,9 +29,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-239</y>
<width>514</width>
<height>784</height>
<y>-293</y>
<width>539</width>
<height>831</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
@ -278,7 +278,7 @@
<widget class="QPushButton" name="mOriginalExtentButton">
<property name="minimumSize">
<size>
<width>140</width>
<width>150</width>
<height>0</height>
</size>
</property>
@ -307,7 +307,7 @@
<widget class="QPushButton" name="mCurrentExtentButton">
<property name="minimumSize">
<size>
<width>140</width>
<width>150</width>
<height>0</height>
</size>
</property>
@ -452,6 +452,9 @@
</property>
<item>
<widget class="QLabel" name="mMaximumSizeXLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Maximum number of columns in one tile.</string>
</property>
@ -462,6 +465,9 @@
</item>
<item>
<widget class="QLineEdit" name="mMaximumSizeXLineEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Maximum number of columns in one tile.</string>
</property>
@ -469,6 +475,9 @@
</item>
<item>
<widget class="QLabel" name="mMaximumSizeYLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Maximum number of rows in one tile.</string>
</property>
@ -479,6 +488,9 @@
</item>
<item>
<widget class="QLineEdit" name="mMaximumSizeYLineEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Maximum number of rows in one tile.</string>
</property>
@ -486,6 +498,9 @@
</item>
<item>
<widget class="QCheckBox" name="mTileModeCheckBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Create VRT</string>
</property>
@ -554,7 +569,7 @@
<item row="2" column="0">
<widget class="QToolButton" name="mLoadTransparentNoDataToolButton">
<property name="enabled">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="toolTip">
<string>Load user defined fully transparent (100%) values </string>
@ -604,7 +619,7 @@
<item>
<widget class="QgsCollapsibleGroupBox" name="mPyramidsGroupBox">
<property name="title">
<string>Pyramids (not yet implemented)</string>
<string>Pyramids</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -612,19 +627,100 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="cbxPyramidsBuild">
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="0">
<widget class="QgsRasterPyramidsOptionsWidget" name="mPyramidsOptionsWidget" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Build pyramids</string>
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QgsRasterPyramidsOptionsWidget" name="mPyramidsOptionsWidget" native="true"/>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string>No pyramids</string>
</property>
<attribute name="buttonGroup">
<string notr="true">mPyramidsButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_2">
<property name="text">
<string>Build pyramids</string>
</property>
<attribute name="buttonGroup">
<string notr="true">mPyramidsButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_3">
<property name="text">
<string>Use existing</string>
</property>
<attribute name="buttonGroup">
<string notr="true">mPyramidsButtonGroup</string>
</attribute>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="mPyramidResolutionsLabel">
<property name="text">
<string>Resolutions</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="mPyramidResolutionsLineEdit">
<property name="toolTip">
<string>Pyramid resolutions corresponding to levels given</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -700,4 +796,7 @@
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="mPyramidsButtonGroup"/>
</buttongroups>
</ui>

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>351</width>
<height>195</height>
<width>366</width>
<height>171</height>
</rect>
</property>
<property name="windowTitle">
@ -17,48 +17,15 @@
<property name="margin">
<number>1</number>
</property>
<item row="3" column="2">
<widget class="QLineEdit" name="lePyramidsLevels">
<property name="toolTip">
<string>Insert positive integer values separated by spaces</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<widget class="QLabel" name="label_4">
<item row="3" column="0">
<widget class="QCheckBox" name="cbxPyramidsLevelsCustom">
<property name="text">
<string>Create Options</string>
<string>Custom levels</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<widget class="QgsRasterFormatSaveOptionsWidget" name="mPyramidsOptionsWidget" native="true"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Overview format</string>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="cboPyramidsFormat">
<widget class="QComboBox" name="cbxPyramidsFormat">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -67,12 +34,12 @@
</property>
<item>
<property name="text">
<string>Internal (if possible)</string>
<string>External</string>
</property>
</item>
<item>
<property name="text">
<string>External (GTiff)</string>
<string>Internal (if possible)</string>
</property>
</item>
<item>
@ -82,44 +49,10 @@
</item>
</widget>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="lePyramidResolutions">
<item row="3" column="2">
<widget class="QLineEdit" name="lePyramidsLevels">
<property name="toolTip">
<string>Pyramid resolutions corresponding to levels given</string>
</property>
<property name="text">
<string>to be done</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Custom levels</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Resolutions</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="textLabel4_2">
<property name="text">
<string>Resampling method</string>
<string>Insert positive integer values separated by spaces</string>
</property>
</widget>
</item>
@ -137,6 +70,23 @@
</item>
</widget>
</item>
<item row="2" column="2">
<layout class="QHBoxLayout" name="layoutPyramidsLevels"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Overview format</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Create Options</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
@ -144,8 +94,38 @@
</property>
</widget>
</item>
<item row="2" column="2">
<layout class="QHBoxLayout" name="layoutPyramidLevels"/>
<item row="6" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="textLabel4_2">
<property name="text">
<string>Resampling method</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<widget class="QgsRasterFormatSaveOptionsWidget" name="mPyramidsOptionsWidget" native="true"/>
</item>
<item row="3" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>

View File

@ -30,6 +30,7 @@
#include <qgsrasterlayer.h>
#include <qgsrasterpyramid.h>
#include <qgsrasterbandstats.h>
#include <qgsrasterpyramid.h>
#include <qgsmaplayerregistry.h>
#include <qgsapplication.h>
#include <qgsmaprenderer.h>
@ -339,24 +340,21 @@ void TestQgsRasterLayer::buildExternalOverviews()
// Ok now we can go on to test
//
bool myInternalFlag = false;
QgsRasterLayer::RasterPyramidList myPyramidList = mypLayer->buildPyramidList();
QgsRasterDataProvider::RasterPyramidsFormat myFormatFlag = QgsRasterDataProvider::PyramidsGTiff;
QList< QgsRasterPyramid > myPyramidList = mypLayer->dataProvider()->buildPyramidList();
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
//mark to be pyramided
myPyramidList[myCounterInt].build = true;
}
//now actually make the pyramids
QString myResult = mypLayer->buildPyramids(
myPyramidList,
"NEAREST",
myInternalFlag
);
QString myResult =
mypLayer->dataProvider()->buildPyramids( myPyramidList, "NEAREST", myFormatFlag );
qDebug( "%s", myResult.toLocal8Bit().constData() );
//
// Lets verify we have pyramids now...
//
myPyramidList = mypLayer->buildPyramidList();
myPyramidList = mypLayer->dataProvider()->buildPyramidList();
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
//mark to be pyramided