From 9d84a6a36aabc357f08480b5a1165be74fd78e73 Mon Sep 17 00:00:00 2001 From: Radim Blazek Date: Wed, 19 Dec 2012 19:30:42 +0100 Subject: [PATCH] raster save as VRT fixes and improvements, fixes #6821 --- src/app/qgisapp.cpp | 9 +- src/core/raster/qgscontrastenhancement.cpp | 16 +- src/core/raster/qgsrasterfilewriter.cpp | 273 ++++++++++++--------- src/core/raster/qgsrasterfilewriter.h | 24 +- src/gui/qgsrasterlayersaveasdialog.cpp | 67 ++++- src/ui/qgsrasterlayersaveasdialogbase.ui | 238 +++++++++--------- 6 files changed, 366 insertions(+), 261 deletions(-) diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 83eea3b45d43..c96dbdd9cb07 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -4131,7 +4131,14 @@ void QgisApp::saveAsRasterFile() fileWriter.setPyramidsResampling( d.pyramidsResampling() ); fileWriter.setPyramidsFormat( d.pyramidsFormat() ); - fileWriter.writeRaster( pipe, d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd ); + QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe, d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd ); + if ( err != QgsRasterFileWriter::NoError ) + { + QMessageBox::warning( this, tr( "Error" ), + tr( "Cannot write raster error code: %1" ).arg( err ), + QMessageBox::Ok ); + + } delete pipe; } } diff --git a/src/core/raster/qgscontrastenhancement.cpp b/src/core/raster/qgscontrastenhancement.cpp index a58ed4038fda..223be213e9f8 100644 --- a/src/core/raster/qgscontrastenhancement.cpp +++ b/src/core/raster/qgscontrastenhancement.cpp @@ -55,29 +55,23 @@ QgsContrastEnhancement::QgsContrastEnhancement( QgsRasterDataType theDataType ) QgsContrastEnhancement::QgsContrastEnhancement( const QgsContrastEnhancement& ce ) { mLookupTable = 0; - mEnhancementDirty = ce.mEnhancementDirty; - mContrastEnhancementAlgorithm = ce.mContrastEnhancementAlgorithm; + mContrastEnhancementFunction = 0; + mEnhancementDirty = true; mRasterDataType = ce.mRasterDataType; mMinimumValue = ce.mMinimumValue; mMaximumValue = ce.mMaximumValue; mRasterDataTypeRange = ce.mRasterDataTypeRange; - mLookupTableOffset = ce.mLookupTableOffset; + mLookupTableOffset = mMinimumValue * -1; - mContrastEnhancementFunction = new QgsContrastEnhancementFunction( mRasterDataType, mMinimumValue, mMaximumValue ); + // setContrastEnhancementAlgorithm sets also QgsContrastEnhancementFunction + setContrastEnhancementAlgorithm( ce.mContrastEnhancementAlgorithm, false ); //If the data type is larger than 16-bit do not generate a lookup table if ( mRasterDataTypeRange <= 65535.0 ) { mLookupTable = new int[static_cast ( mRasterDataTypeRange+1 )]; - if ( !ce.mEnhancementDirty ) - { - for ( int myIterator = 0; myIterator <= mRasterDataTypeRange; myIterator++ ) - { - mLookupTable[myIterator] = ce.mLookupTable[myIterator]; - } - } } } diff --git a/src/core/raster/qgsrasterfilewriter.cpp b/src/core/raster/qgsrasterfilewriter.cpp index 9020c612a16e..e83b1f6d2231 100644 --- a/src/core/raster/qgsrasterfilewriter.cpp +++ b/src/core/raster/qgsrasterfilewriter.cpp @@ -27,11 +27,11 @@ #include QgsRasterFileWriter::QgsRasterFileWriter( const QString& outputUrl ): - mOutputUrl( outputUrl ), mOutputProviderKey( "gdal" ), mOutputFormat( "GTiff" ), + mMode( Raw ), mOutputUrl( outputUrl ), mOutputProviderKey( "gdal" ), mOutputFormat( "GTiff" ), mTiledMode( false ), mMaxTileWidth( 500 ), mMaxTileHeight( 500 ), mBuildPyramidsFlag( QgsRasterDataProvider::PyramidsFlagNo ), mPyramidsFormat( QgsRasterDataProvider::PyramidsGTiff ), - mProgressDialog( 0 ) + mProgressDialog( 0 ), mPipe( 0 ), mInput( 0 ) { } @@ -57,6 +57,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( const QgsRast { return SourceProviderError; } + mPipe = pipe; //const QgsRasterInterface* iface = iter->input(); const QgsRasterInterface* iface = pipe->last(); @@ -64,6 +65,16 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( const QgsRast { return SourceProviderError; } + mInput = iface; + + if ( QgsRasterBlock::typeIsColor( iface->dataType( 1 ) ) ) + { + mMode = Image; + } + else + { + mMode = Raw; + } QgsDebugMsg( QString( "reading from %1" ).arg( typeid( *iface ).name() ) ); @@ -78,8 +89,22 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( const QgsRast QgsRasterIterator iter( pipe->last() ); - if ( iface->dataType( 1 ) == QGis::ARGB32 || - iface->dataType( 1 ) == QGis::ARGB32_Premultiplied ) + //create directory for output files + if ( mTiledMode ) + { + QFileInfo fileInfo( mOutputUrl ); + if ( !fileInfo.exists() ) + { + QDir dir = fileInfo.dir(); + if ( !dir.mkdir( fileInfo.fileName() ) ) + { + QgsDebugMsg( "Cannot create output VRT directory " + fileInfo.fileName() + " in " + dir.absolutePath() ); + return CreateDatasourceError; + } + } + } + + if ( mMode == Image ) { WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent, crs, progressDialog ); mProgressDialog = 0; @@ -118,13 +143,6 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs return SourceProviderError; } - //create directory for output files - QDir destDir( mOutputUrl ); - if ( mTiledMode ) - { - destDir.mkdir( mOutputUrl ); - } - iter->setMaximumTileWidth( mMaxTileWidth ); iter->setMaximumTileHeight( mMaxTileHeight ); @@ -134,11 +152,6 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs return SourceProviderError; } - //create destProvider for whole dataset here - QgsRasterDataProvider* destProvider = 0; - double pixelSize; - double geoTransform[6]; - globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize ); //check if all the bands have the same data type size, otherwise we cannot write it to the provider //(at least not with the current interface) @@ -238,15 +251,30 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs } } - destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType ); + //create destProvider for whole dataset here + QgsRasterDataProvider* destProvider = 0; + double pixelSize; + double geoTransform[6]; + globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize ); + + // initOutput() returns 0 in tile mode! + destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ); WriterError error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog ); if ( error == NoDataConflict ) { // The value used for no data was found in source data, we must use wider data type - destProvider->remove(); - delete destProvider; + if ( destProvider ) // no tiles + { + destProvider->remove(); + delete destProvider; + destProvider = 0; + } + else // VRT + { + // TODO: remove created VRT + } // But we don't know which band -> wider all for ( int i = 0; i < nBands; i++ ) @@ -259,9 +287,10 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs destDataType = destDataTypeList.value( 0 ); // Try again - destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType ); + destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType , destHasNoDataValueList, destNoDataValueList ); error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog ); } + if ( destProvider ) delete destProvider; return error; } @@ -285,6 +314,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const QgsRasterInterface* iface = iter->input(); const QgsRasterDataProvider* srcProvider = dynamic_cast( iface->srcInput() ); int nBands = iface->bandCount(); + QgsDebugMsg( QString( "nBands = %1" ).arg( nBands ) ); //Get output map units per pixel int iterLeft = 0; @@ -299,8 +329,10 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( // TODO: no need to alloc memory, change to readBlock() returning the allocated block //blockList.push_back( QgsMalloc( dataTypeSize * mMaxTileWidth * mMaxTileHeight ) ); blockList.push_back( 0 ); - // TODO - fix segfault here when using tiles+vrt (reported by Etienne) - destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) ); + if ( destProvider ) // no tiles + { + destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) ); + } } int nParts = 0; @@ -323,18 +355,24 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( { if ( !iter->readNextRasterPart( i, iterCols, iterRows, &( blockList[i - 1] ), iterLeft, iterTop ) ) { - delete destProvider; + // No more parts, create VRT and return + //delete destProvider; if ( mTiledMode ) { QFileInfo outputInfo( mOutputUrl ); QString vrtFilePath( mOutputUrl + "/" + outputInfo.baseName() + ".vrt" ); writeVRT( vrtFilePath ); - buildPyramids( vrtFilePath ); + if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes ) + { + buildPyramids( vrtFilePath ); + } } else { if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes ) + { buildPyramids( mOutputUrl ); + } } QgsDebugMsg( "Done" ); @@ -369,9 +407,6 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( else { // TODO: this conversion should go to QgsRasterDataProvider::write with additional input data type param - //void *destData = QgsRasterBlock::convert( blockList[i-1], srcProvider->dataType( i ), destDataType, iterCols * iterRows ); - //destBlockList.push_back( destData ); - //QgsFree( blockList[i-1] ); blockList[i-1]->convert( destDataType ); destBlockList.push_back( blockList[i-1] ); } @@ -380,17 +415,21 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( if ( mTiledMode ) //write to file { - delete destProvider; - destProvider = createPartProvider( outputExtent, nCols, iterCols, iterRows, - iterLeft, iterTop, mOutputUrl, fileIndex, nBands, destDataType, crs ); + //delete destProvider; + QgsRasterDataProvider* partDestProvider = createPartProvider( outputExtent, + nCols, iterCols, iterRows, + iterLeft, iterTop, mOutputUrl, + fileIndex, nBands, destDataType, crs ); //write data to output file. todo: loop over the data list for ( int i = 1; i <= nBands; ++i ) { - destProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 ); + partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) ); + partDestProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 ); delete destBlockList[i - 1]; - addToVRT( QString::number( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop ); + addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop ); } + delete partDestProvider; } else { @@ -425,13 +464,6 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste return SourceProviderError; } - //create directory for output files - QDir destDir( mOutputUrl ); - if ( mTiledMode ) - { - destDir.mkdir( mOutputUrl ); - } - iter->setMaximumTileWidth( mMaxTileWidth ); iter->setMaximumTileHeight( mMaxTileHeight ); @@ -518,20 +550,23 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste //create output file if ( mTiledMode ) { - delete destProvider; - destProvider = createPartProvider( outputExtent, nCols, iterCols, iterRows, - iterLeft, iterTop, mOutputUrl, fileIndex, 4, QGis::Byte, crs ); + //delete destProvider; + QgsRasterDataProvider* partDestProvider = createPartProvider( outputExtent, + nCols, iterCols, iterRows, + iterLeft, iterTop, mOutputUrl, fileIndex, + 4, QGis::Byte, crs ); //write data to output file - destProvider->write( redData, 1, iterCols, iterRows, 0, 0 ); - destProvider->write( greenData, 2, iterCols, iterRows, 0, 0 ); - destProvider->write( blueData, 3, iterCols, iterRows, 0, 0 ); - destProvider->write( alphaData, 4, iterCols, iterRows, 0, 0 ); - - addToVRT( QString::number( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop ); - addToVRT( QString::number( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop ); - addToVRT( QString::number( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop ); - addToVRT( QString::number( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop ); + partDestProvider->write( redData, 1, iterCols, iterRows, 0, 0 ); + partDestProvider->write( greenData, 2, iterCols, iterRows, 0, 0 ); + partDestProvider->write( blueData, 3, iterCols, iterRows, 0, 0 ); + partDestProvider->write( alphaData, 4, iterCols, iterRows, 0, 0 ); + + addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop ); + addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop ); + addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop ); + addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop ); + delete partDestProvider; } else { @@ -544,7 +579,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste ++fileIndex; } - delete destProvider; + if ( destProvider ) delete destProvider; QgsFree( redData ); QgsFree( greenData ); QgsFree( blueData ); QgsFree( alphaData ); if ( progressDialog ) @@ -557,37 +592,24 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRaste QFileInfo outputInfo( mOutputUrl ); QString vrtFilePath( mOutputUrl + "/" + outputInfo.baseName() + ".vrt" ); writeVRT( vrtFilePath ); - buildPyramids( vrtFilePath ); + if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes ) + { + buildPyramids( vrtFilePath ); + } } else { if ( mBuildPyramidsFlag == QgsRasterDataProvider::PyramidsFlagYes ) + { buildPyramids( mOutputUrl ); + } } return NoError; } void QgsRasterFileWriter::addToVRT( const QString& filename, int band, int xSize, int ySize, int xOffset, int yOffset ) { - QDomElement bandElem; - - switch ( band ) - { - case 1: - bandElem = mVRTRedBand; - break; - case 2: - bandElem = mVRTGreenBand; - break; - case 3: - bandElem = mVRTBlueBand; - break; - case 4: - bandElem = mVRTAlphaBand; - break; - default: - return; - } + QDomElement bandElem = mVRTBands.value( band - 1 ); QDomElement simpleSourceElem = mVRTDocument.createElement( "SimpleSource" ); @@ -665,6 +687,7 @@ void QgsRasterFileWriter::buildPyramids( const QString& filename ) void QgsRasterFileWriter::buildPyramids( const QString& filename ) { + QgsDebugMsg( "filename = " + filename ); // open new dataProvider so we can build pyramids with it //QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, filename ); QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, filename ); @@ -722,6 +745,7 @@ void QgsRasterFileWriter::buildPyramids( const QString& filename ) QMessageBox::warning( 0, title, message ); QgsDebugMsg( res + " - " + message ); } + delete destProvider; } #if 0 @@ -744,7 +768,7 @@ int QgsRasterFileWriter::pyramidsProgress( double dfComplete, const char *pszMes } #endif -void QgsRasterFileWriter::createVRT( int xSize, int ySize, const QgsCoordinateReferenceSystem& crs, double* geoTransform ) +void QgsRasterFileWriter::createVRT( int xSize, int ySize, const QgsCoordinateReferenceSystem& crs, double* geoTransform, QGis::DataType type, QList destHasNoDataValueList, QList destNoDataValueList ) { mVRTDocument.clear(); QDomElement VRTDatasetElem = mVRTDocument.createElement( "VRTDataset" ); @@ -771,43 +795,56 @@ void QgsRasterFileWriter::createVRT( int xSize, int ySize, const QgsCoordinateRe VRTDatasetElem.appendChild( geoTransformElem ); } - //VRT rasterbands - mVRTRedBand = mVRTDocument.createElement( "VRTRasterBand" ); - mVRTRedBand.setAttribute( "dataType", "Byte" ); - mVRTRedBand.setAttribute( "band", "1" ); - QDomElement colorInterpRedElement = mVRTDocument.createElement( "ColorInterp" ); - QDomText redInterprText = mVRTDocument.createTextNode( "Red" ); - colorInterpRedElement.appendChild( redInterprText ); - mVRTRedBand.appendChild( colorInterpRedElement ); - - mVRTGreenBand = mVRTDocument.createElement( "VRTRasterBand" ); - mVRTGreenBand.setAttribute( "dataType", "Byte" ); - mVRTGreenBand.setAttribute( "band", "2" ); - QDomElement colorInterpGreenElement = mVRTDocument.createElement( "ColorInterp" ); - QDomText greenInterprText = mVRTDocument.createTextNode( "Green" ); - colorInterpGreenElement.appendChild( greenInterprText ); - mVRTGreenBand.appendChild( colorInterpGreenElement ); - - mVRTBlueBand = mVRTDocument.createElement( "VRTRasterBand" ); - mVRTBlueBand.setAttribute( "dataType", "Byte" ); - mVRTBlueBand.setAttribute( "band", "3" ); - QDomElement colorInterpBlueElement = mVRTDocument.createElement( "ColorInterp" ); - QDomText blueInterprText = mVRTDocument.createTextNode( "Blue" ); - colorInterpBlueElement.appendChild( blueInterprText ); - mVRTBlueBand.appendChild( colorInterpBlueElement ); - - mVRTAlphaBand = mVRTDocument.createElement( "VRTRasterBand" ); - mVRTAlphaBand.setAttribute( "dataType", "Byte" ); - mVRTAlphaBand.setAttribute( "band", "4" ); - QDomElement colorInterpAlphaElement = mVRTDocument.createElement( "ColorInterp" ); - QDomText alphaInterprText = mVRTDocument.createTextNode( "Alpha" ); - colorInterpAlphaElement.appendChild( alphaInterprText ); - mVRTAlphaBand.appendChild( colorInterpAlphaElement ); - - VRTDatasetElem.appendChild( mVRTRedBand ); - VRTDatasetElem.appendChild( mVRTGreenBand ); - VRTDatasetElem.appendChild( mVRTBlueBand ); - VRTDatasetElem.appendChild( mVRTAlphaBand ); + int nBands; + if ( mMode == Raw ) + { + nBands = mInput->bandCount(); + } + else + { + nBands = 4; + } + + QStringList colorInterp; + colorInterp << "Red" << "Green" << "Blue" << "Alpha"; + + QMap dataTypes; + dataTypes.insert( QGis::Byte, "Byte" ); + dataTypes.insert( QGis::UInt16, "UInt16" ); + dataTypes.insert( QGis::Int16, "Int16" ); + dataTypes.insert( QGis::UInt32, "Int32" ); + dataTypes.insert( QGis::Float32, "Float32" ); + dataTypes.insert( QGis::Float64, "Float64" ); + dataTypes.insert( QGis::CInt16, "CInt16" ); + dataTypes.insert( QGis::CInt32, "CInt32" ); + dataTypes.insert( QGis::CFloat32, "CFloat32" ); + dataTypes.insert( QGis::CFloat64, "CFloat64" ); + + for ( int i = 1; i <= nBands; i++ ) + { + QDomElement VRTBand = mVRTDocument.createElement( "VRTRasterBand" ); + + VRTBand.setAttribute( "band", QString::number( i ) ); + QString dataType = dataTypes.value( type ); + VRTBand.setAttribute( "dataType", dataType ); + + if ( mMode == Image ) + { + VRTBand.setAttribute( "dataType", "Byte" ); + QDomElement colorInterpElement = mVRTDocument.createElement( "ColorInterp" ); + QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) ); + colorInterpElement.appendChild( interpText ); + VRTBand.appendChild( colorInterpElement ); + } + + if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) ) + { + VRTBand.setAttribute( "NoDataValue", QString::number( destNoDataValueList.value( i - 1 ) ) ); + } + + mVRTBands.append( VRTBand ); + VRTDatasetElem.appendChild( VRTBand ); + } } bool QgsRasterFileWriter::writeVRT( const QString& file ) @@ -834,7 +871,7 @@ QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectang double mapBottom = mapTop - iterRows * mup; QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop ); - QString outputFile = outputUrl + "/" + QString::number( fileIndex ); + QString outputFile = outputUrl + "/" + partFileName( fileIndex ); //QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, outputFile ); QgsRasterDataProvider* destProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( mOutputProviderKey, outputFile ); if ( !destProvider ) @@ -862,11 +899,12 @@ QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectang } QgsRasterDataProvider* QgsRasterFileWriter::initOutput( int nCols, int nRows, const QgsCoordinateReferenceSystem& crs, - double* geoTransform, int nBands, QGis::DataType type ) + double* geoTransform, int nBands, QGis::DataType type, + QList destHasNoDataValueList, QList destNoDataValueList ) { if ( mTiledMode ) { - createVRT( nCols, nRows, crs, geoTransform ); + createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList ); return 0; } else @@ -911,6 +949,9 @@ void QgsRasterFileWriter::globalOutputParameters( const QgsRectangle& extent, in geoTransform[5] = -( extent.height() / nRows ); } - - - +QString QgsRasterFileWriter::partFileName( int fileIndex ) +{ + // .tif for now + QFileInfo outputInfo( mOutputUrl ); + return QString( "%1.%2.tif" ).arg( outputInfo.baseName() ).arg( fileIndex ); +} diff --git a/src/core/raster/qgsrasterfilewriter.h b/src/core/raster/qgsrasterfilewriter.h index 8fe7cbdc4c03..411cc04bb3aa 100644 --- a/src/core/raster/qgsrasterfilewriter.h +++ b/src/core/raster/qgsrasterfilewriter.h @@ -32,6 +32,11 @@ class QgsRasterIterator; class CORE_EXPORT QgsRasterFileWriter { public: + enum Mode + { + Raw = 0, // Raw data + Image = 1 // Rendered image + }; enum WriterError { NoError = 0, @@ -109,7 +114,7 @@ class CORE_EXPORT QgsRasterFileWriter const QgsCoordinateReferenceSystem& crs, QProgressDialog* progressDialog = 0 ); //initialize vrt member variables - void createVRT( int xSize, int ySize, const QgsCoordinateReferenceSystem& crs, double* geoTransform ); + void createVRT( int xSize, int ySize, const QgsCoordinateReferenceSystem& crs, double* geoTransform, QGis::DataType type, QList destHasNoDataValueList, QList destNoDataValueList ); //write vrt document to disk bool writeVRT( const QString& file ); //add file entry to vrt @@ -125,12 +130,17 @@ class CORE_EXPORT QgsRasterFileWriter const QgsCoordinateReferenceSystem& crs ); /**Init VRT (for tiled mode) or create global output provider (single-file mode)*/ - QgsRasterDataProvider* initOutput( int nCols, int nRows, const QgsCoordinateReferenceSystem& crs, double* geoTransform, int nBands, - QGis::DataType type ); + QgsRasterDataProvider* initOutput( int nCols, int nRows, + const QgsCoordinateReferenceSystem& crs, double* geoTransform, int nBands, + QGis::DataType type, + QList destHasNoDataValueList = QList(), QList destNoDataValueList = QList() ); /**Calculate nRows, geotransform and pixel size for output*/ void globalOutputParameters( const QgsRectangle& extent, int nCols, int& nRows, double* geoTransform, double& pixelSize ); + QString partFileName( int fileIndex ); + + Mode mMode; QString mOutputUrl; QString mOutputProviderKey; QString mOutputFormat; @@ -148,12 +158,12 @@ class CORE_EXPORT QgsRasterFileWriter QgsRasterDataProvider::RasterPyramidsFormat mPyramidsFormat; QDomDocument mVRTDocument; - QDomElement mVRTRedBand; - QDomElement mVRTGreenBand; - QDomElement mVRTBlueBand; - QDomElement mVRTAlphaBand; + QList mVRTBands; QProgressDialog* mProgressDialog; + + const QgsRasterPipe* mPipe; + const QgsRasterInterface* mInput; }; #endif // QGSRASTERFILEWRITER_H diff --git a/src/gui/qgsrasterlayersaveasdialog.cpp b/src/gui/qgsrasterlayersaveasdialog.cpp index 13fb4350adb3..065f122250be 100644 --- a/src/gui/qgsrasterlayersaveasdialog.cpp +++ b/src/gui/qgsrasterlayersaveasdialog.cpp @@ -22,9 +22,9 @@ #include "qgsgenericprojectionselector.h" #include +#include #include - QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer* rasterLayer, QgsRasterDataProvider* sourceProvider, const QgsRectangle& currentExtent, const QgsCoordinateReferenceSystem& layerCrs, const QgsCoordinateReferenceSystem& currentCrs, @@ -117,10 +117,12 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer* rasterLa // restore checked state for most groupboxes (default is to restore collapsed state) // create options and pyramids will be preset, if user has selected defaults in the gdal options dlg mCreateOptionsGroupBox->setSaveCheckedState( true ); - mTilesGroupBox->setSaveCheckedState( true ); + //mTilesGroupBox->setSaveCheckedState( true ); // don't restore nodata, it needs user input // pyramids are not necessarily built every time + mTilesGroupBox->hide(); + updateCrsGroup(); QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok ); @@ -153,11 +155,44 @@ void QgsRasterLayerSaveAsDialog::on_mBrowseButton_clicked() QString fileName; if ( mTileModeCheckBox->isChecked() ) { - fileName = QFileDialog::getExistingDirectory( this, tr( "Select output directory" ) ); + while ( true ) + { + // TODO: would not it be better to select .vrt file instead of directory? + fileName = QFileDialog::getExistingDirectory( this, tr( "Select output directory" ) ); + //fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), QString(), tr( "VRT" ) + " (*.vrt *.VRT)" ); + + if ( fileName.isEmpty() ) break; // canceled + + // Check if directory is empty + QDir dir( fileName ); + QString baseName = QFileInfo( fileName ).baseName(); + QStringList filters; + filters << QString( "%1.*" ).arg( baseName ); + QStringList files = dir.entryList( filters ); + if ( !files.isEmpty() ) + { + QMessageBox::StandardButton button = QMessageBox::warning( this, tr( "Warning" ), + tr( "The directory %1 contains files which will be overwritten: %2" ).arg( dir.absolutePath() ).arg( files.join( ", " ) ), + QMessageBox::Ok | QMessageBox::Cancel ); + + if ( button == QMessageBox::Ok ) + { + break; + } + else + { + fileName = ""; + } + } + else + { + break; + } + } } else { - fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ) ); + fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), QString(), tr( "GeoTIFF" ) + " (*.tif *.tiff *.TIF *.TIFF)" ); } if ( !fileName.isEmpty() ) @@ -667,11 +702,25 @@ void QgsRasterLayerSaveAsDialog::on_mTileModeCheckBox_toggled( bool toggled ) if ( toggled ) { // enable pyramids - if ( ! mPyramidsGroupBox->isChecked() ) - mPyramidsGroupBox->setChecked( true ); - if ( mPyramidsGroupBox->isCollapsed() ) - mPyramidsGroupBox->setCollapsed( false ); - mPyramidsOptionsWidget->checkAllLevels( true ); + + // Disabled (Radim), auto enabling of pyramids was making impression that + // we (programmers) know better what you (user) want to do, + // certainly auto expaning was bad experience + + //if ( ! mPyramidsGroupBox->isChecked() ) + // mPyramidsGroupBox->setChecked( true ); + + // Auto expanding mPyramidsGroupBox is bad - it auto crolls content of dialog + //if ( mPyramidsGroupBox->isCollapsed() ) + // mPyramidsGroupBox->setCollapsed( false ); + //mPyramidsOptionsWidget->checkAllLevels( true ); + + // Show / hide tile options + mTilesGroupBox->show(); + } + else + { + mTilesGroupBox->hide(); } } diff --git a/src/ui/qgsrasterlayersaveasdialogbase.ui b/src/ui/qgsrasterlayersaveasdialogbase.ui index 02a0a241decd..cc5b75917bca 100644 --- a/src/ui/qgsrasterlayersaveasdialogbase.ui +++ b/src/ui/qgsrasterlayersaveasdialogbase.ui @@ -86,6 +86,17 @@ + + + + Create GDAL Virtual Format composed of multiple +datasets with maximum width and height specified below. + + + Create VRT + + + @@ -146,7 +157,7 @@ - + 0 0 @@ -162,7 +173,7 @@ - + 0 0 @@ -190,8 +201,8 @@ 0 0 - 536 - 779 + 549 + 700 @@ -453,30 +464,6 @@ - - - - - 0 - 0 - - - - Create Options - - - true - - - false - - - - - - - - @@ -486,10 +473,10 @@ - Tiles + VRT Tiles - true + false false @@ -529,10 +516,111 @@ - - + + + + + + + + 0 + 0 + + + + Create Options + + + true + + + false + + + + + + + + + + + + + 0 + 0 + + + + Pyramids + + + true + + + false + + + + + + + + + Qt::Horizontal + + + + + + + + + Resolutions + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 0 + + + + + + + + Pyramid resolutions corresponding to levels given + + + false + + + + + + false + + + true + + + + + + + - Create VRT + Use existing @@ -642,90 +730,6 @@ - - - - - 0 - 0 - - - - Pyramids - - - true - - - false - - - - - - - - - Qt::Horizontal - - - - - - - - - Resolutions - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 0 - - - - - - - - Pyramid resolutions corresponding to levels given - - - false - - - - - - false - - - true - - - - - - - - - Use existing - - - - - -