Skip to content

Commit d69ec2e

Browse files
committed
save as raster: fix vrt creation (fixes #14171)
1 parent b369b20 commit d69ec2e

4 files changed

Lines changed: 119 additions & 117 deletions

File tree

src/app/qgisapp.cpp

Lines changed: 91 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5923,110 +5923,118 @@ void QgisApp::saveAsRasterFile()
59235923
mMapCanvas->extent(), rasterLayer->crs(),
59245924
mMapCanvas->mapSettings().destinationCrs(),
59255925
this );
5926-
if ( d.exec() == QDialog::Accepted )
5927-
{
5928-
QSettings settings;
5929-
settings.setValue( "/UI/lastRasterFileDir", QFileInfo( d.outputFileName() ).absolutePath() );
5926+
if ( d.exec() == QDialog::Rejected )
5927+
return;
59305928

5931-
QgsRasterFileWriter fileWriter( d.outputFileName() );
5932-
if ( d.tileMode() )
5933-
{
5934-
fileWriter.setTiledMode( true );
5935-
fileWriter.setMaxTileWidth( d.maximumTileSizeX() );
5936-
fileWriter.setMaxTileHeight( d.maximumTileSizeY() );
5937-
}
5929+
QSettings settings;
5930+
settings.setValue( "/UI/lastRasterFileDir", QFileInfo( d.outputFileName() ).absolutePath() );
59385931

5939-
QProgressDialog pd( nullptr, tr( "Abort..." ), 0, 0 );
5940-
// Show the dialo immediately because cloning pipe can take some time (WCS)
5941-
pd.setLabelText( tr( "Reading raster" ) );
5942-
pd.setWindowTitle( tr( "Saving raster" ) );
5943-
pd.show();
5944-
pd.setWindowModality( Qt::WindowModal );
5932+
QgsRasterFileWriter fileWriter( d.outputFileName() );
5933+
if ( d.tileMode() )
5934+
{
5935+
fileWriter.setTiledMode( true );
5936+
fileWriter.setMaxTileWidth( d.maximumTileSizeX() );
5937+
fileWriter.setMaxTileHeight( d.maximumTileSizeY() );
5938+
}
59455939

5946-
// TODO: show error dialogs
5947-
// TODO: this code should go somewhere else, but probably not into QgsRasterFileWriter
5948-
// clone pipe/provider is not really necessary, ready for threads
5949-
QScopedPointer<QgsRasterPipe> pipe( nullptr );
5940+
QProgressDialog pd( nullptr, tr( "Abort..." ), 0, 0 );
5941+
// Show the dialo immediately because cloning pipe can take some time (WCS)
5942+
pd.setLabelText( tr( "Reading raster" ) );
5943+
pd.setWindowTitle( tr( "Saving raster" ) );
5944+
pd.show();
5945+
pd.setWindowModality( Qt::WindowModal );
59505946

5951-
if ( d.mode() == QgsRasterLayerSaveAsDialog::RawDataMode )
5952-
{
5953-
QgsDebugMsg( "Writing raw data" );
5954-
//QgsDebugMsg( QString( "Writing raw data" ).arg( pos ) );
5955-
pipe.reset( new QgsRasterPipe() );
5956-
if ( !pipe->set( rasterLayer->dataProvider()->clone() ) )
5957-
{
5958-
QgsDebugMsg( "Cannot set pipe provider" );
5959-
return;
5960-
}
5947+
// TODO: show error dialogs
5948+
// TODO: this code should go somewhere else, but probably not into QgsRasterFileWriter
5949+
// clone pipe/provider is not really necessary, ready for threads
5950+
QScopedPointer<QgsRasterPipe> pipe( nullptr );
59615951

5962-
QgsRasterNuller *nuller = new QgsRasterNuller();
5963-
for ( int band = 1; band <= rasterLayer->dataProvider()->bandCount(); band ++ )
5964-
{
5965-
nuller->setNoData( band, d.noData() );
5966-
}
5967-
if ( !pipe->insert( 1, nuller ) )
5968-
{
5969-
QgsDebugMsg( "Cannot set pipe nuller" );
5970-
return;
5971-
}
5952+
if ( d.mode() == QgsRasterLayerSaveAsDialog::RawDataMode )
5953+
{
5954+
QgsDebugMsg( "Writing raw data" );
5955+
//QgsDebugMsg( QString( "Writing raw data" ).arg( pos ) );
5956+
pipe.reset( new QgsRasterPipe() );
5957+
if ( !pipe->set( rasterLayer->dataProvider()->clone() ) )
5958+
{
5959+
QgsDebugMsg( "Cannot set pipe provider" );
5960+
return;
5961+
}
59725962

5973-
// add projector if necessary
5974-
if ( d.outputCrs() != rasterLayer->crs() )
5975-
{
5976-
QgsRasterProjector * projector = new QgsRasterProjector;
5977-
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
5978-
if ( !pipe->insert( 2, projector ) )
5979-
{
5980-
QgsDebugMsg( "Cannot set pipe projector" );
5981-
return;
5982-
}
5983-
}
5963+
QgsRasterNuller *nuller = new QgsRasterNuller();
5964+
for ( int band = 1; band <= rasterLayer->dataProvider()->bandCount(); band ++ )
5965+
{
5966+
nuller->setNoData( band, d.noData() );
59845967
}
5985-
else // RenderedImageMode
5968+
if ( !pipe->insert( 1, nuller ) )
59865969
{
5987-
// clone the whole pipe
5988-
QgsDebugMsg( "Writing rendered image" );
5989-
pipe.reset( new QgsRasterPipe( *rasterLayer->pipe() ) );
5990-
QgsRasterProjector *projector = pipe->projector();
5991-
if ( !projector )
5970+
QgsDebugMsg( "Cannot set pipe nuller" );
5971+
return;
5972+
}
5973+
5974+
// add projector if necessary
5975+
if ( d.outputCrs() != rasterLayer->crs() )
5976+
{
5977+
QgsRasterProjector * projector = new QgsRasterProjector;
5978+
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
5979+
if ( !pipe->insert( 2, projector ) )
59925980
{
5993-
QgsDebugMsg( "Cannot get pipe projector" );
5981+
QgsDebugMsg( "Cannot set pipe projector" );
59945982
return;
59955983
}
5996-
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
59975984
}
5998-
5999-
if ( !pipe->last() )
5985+
}
5986+
else // RenderedImageMode
5987+
{
5988+
// clone the whole pipe
5989+
QgsDebugMsg( "Writing rendered image" );
5990+
pipe.reset( new QgsRasterPipe( *rasterLayer->pipe() ) );
5991+
QgsRasterProjector *projector = pipe->projector();
5992+
if ( !projector )
60005993
{
5994+
QgsDebugMsg( "Cannot get pipe projector" );
60015995
return;
60025996
}
6003-
fileWriter.setCreateOptions( d.createOptions() );
5997+
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
5998+
}
60045999

6005-
fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
6006-
fileWriter.setPyramidsList( d.pyramidsList() );
6007-
fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
6008-
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
6009-
fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );
6000+
if ( !pipe->last() )
6001+
{
6002+
return;
6003+
}
6004+
fileWriter.setCreateOptions( d.createOptions() );
60106005

6011-
QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe.data(), d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd );
6012-
if ( err != QgsRasterFileWriter::NoError )
6013-
{
6014-
QMessageBox::warning( this, tr( "Error" ),
6015-
tr( "Cannot write raster error code: %1" ).arg( err ),
6016-
QMessageBox::Ok );
6006+
fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
6007+
fileWriter.setPyramidsList( d.pyramidsList() );
6008+
fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
6009+
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
6010+
fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );
60176011

6012+
QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe.data(), d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd );
6013+
if ( err != QgsRasterFileWriter::NoError )
6014+
{
6015+
QMessageBox::warning( this, tr( "Error" ),
6016+
tr( "Cannot write raster error code: %1" ).arg( err ),
6017+
QMessageBox::Ok );
6018+
6019+
}
6020+
else
6021+
{
6022+
QString fileName( d.outputFileName() );
6023+
if ( d.tileMode() )
6024+
{
6025+
QFileInfo outputInfo( fileName );
6026+
fileName = QString( "%1/%2.vrt" ).arg( fileName, outputInfo.fileName() );
60186027
}
6019-
else
6028+
6029+
if ( d.addToCanvas() )
60206030
{
6021-
if ( d.addToCanvas() )
6022-
{
6023-
addRasterLayers( QStringList( d.outputFileName() ) );
6024-
}
6025-
emit layerSavedAs( rasterLayer, d.outputFileName() );
6026-
messageBar()->pushMessage( tr( "Saving done" ),
6027-
tr( "Export to raster file has been completed" ),
6028-
QgsMessageBar::INFO, messageTimeout() );
6031+
addRasterLayers( QStringList( fileName ) );
60296032
}
6033+
6034+
emit layerSavedAs( rasterLayer, fileName );
6035+
messageBar()->pushMessage( tr( "Saving done" ),
6036+
tr( "Export to raster file has been completed" ),
6037+
QgsMessageBar::INFO, messageTimeout() );
60306038
}
60316039
}
60326040

src/core/raster/qgsrasterfilewriter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(
362362

363363
// hmm why is there a for(;;) here ..
364364
// not good coding practice IMHO, it might be better to use [ for() and break ] or [ while (test) ]
365-
for ( ;; )
365+
Q_FOREVER
366366
{
367367
for ( int i = 1; i <= nBands; ++i )
368368
{

src/gui/qgsrasterlayersaveasdialog.cpp

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -167,53 +167,45 @@ void QgsRasterLayerSaveAsDialog::on_mBrowseButton_clicked()
167167

168168
if ( mTileModeCheckBox->isChecked() )
169169
{
170-
while ( true )
170+
Q_FOREVER
171171
{
172172
// TODO: would not it be better to select .vrt file instead of directory?
173173
fileName = QFileDialog::getExistingDirectory( this, tr( "Select output directory" ), dirName );
174174
//fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), QString(), tr( "VRT" ) + " (*.vrt *.VRT)" );
175175

176-
if ( fileName.isEmpty() ) break; // canceled
176+
if ( fileName.isEmpty() )
177+
break; // canceled
177178

178179
// Check if directory is empty
179180
QDir dir( fileName );
180181
QString baseName = QFileInfo( fileName ).baseName();
181182
QStringList filters;
182183
filters << QString( "%1.*" ).arg( baseName );
183184
QStringList files = dir.entryList( filters );
184-
if ( !files.isEmpty() )
185-
{
186-
QMessageBox::StandardButton button = QMessageBox::warning( this, tr( "Warning" ),
187-
tr( "The directory %1 contains files which will be overwritten: %2" ).arg( dir.absolutePath(), files.join( ", " ) ),
188-
QMessageBox::Ok | QMessageBox::Cancel );
185+
if ( files.isEmpty() )
186+
break;
189187

190-
if ( button == QMessageBox::Ok )
191-
{
192-
break;
193-
}
194-
else
195-
{
196-
fileName = "";
197-
}
198-
}
199-
else
200-
{
188+
if ( QMessageBox::warning( this, tr( "Warning" ),
189+
tr( "The directory %1 contains files which will be overwritten: %2" ).arg( dir.absolutePath(), files.join( ", " ) ),
190+
QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Ok )
201191
break;
202-
}
192+
193+
fileName = "";
203194
}
204195
}
205196
else
206197
{
207198
fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), dirName, tr( "GeoTIFF" ) + " (*.tif *.tiff *.TIF *.TIFF)" );
208-
}
209199

210-
if ( !fileName.isEmpty() )
211-
{
212-
// ensure the user never ommited the extension from the file name
213-
if ( !fileName.endsWith( ".tif", Qt::CaseInsensitive ) && !fileName.endsWith( ".tiff", Qt::CaseInsensitive ) )
200+
// ensure the user never omits the extension from the file name
201+
if ( !fileName.isEmpty() && !fileName.endsWith( ".tif", Qt::CaseInsensitive ) && !fileName.endsWith( ".tiff", Qt::CaseInsensitive ) )
214202
{
215203
fileName += ".tif";
216204
}
205+
}
206+
207+
if ( !fileName.isEmpty() )
208+
{
217209
mSaveAsLineEdit->setText( fileName );
218210
}
219211
}

src/ui/qgsrasterlayersaveasdialogbase.ui

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,8 @@ datasets with maximum width and height specified below.</string>
564564
<string>...</string>
565565
</property>
566566
<property name="icon">
567-
<iconset>
568-
<normaloff>../../images/themes/default/mActionNewAttribute.svg</normaloff>../../images/themes/default/mActionNewAttribute.svg</iconset>
567+
<iconset resource="../../images/images.qrc">
568+
<normaloff>:/images/themes/default/mActionNewAttribute.svg</normaloff>:/images/themes/default/mActionNewAttribute.svg</iconset>
569569
</property>
570570
</widget>
571571
</item>
@@ -578,8 +578,8 @@ datasets with maximum width and height specified below.</string>
578578
<string>...</string>
579579
</property>
580580
<property name="icon">
581-
<iconset>
582-
<normaloff>../../images/themes/default/mActionCopySelected.png</normaloff>../../images/themes/default/mActionCopySelected.png</iconset>
581+
<iconset resource="../../images/images.qrc">
582+
<normaloff>:/images/themes/default/mActionCopySelected.png</normaloff>:/images/themes/default/mActionCopySelected.png</iconset>
583583
</property>
584584
</widget>
585585
</item>
@@ -595,8 +595,8 @@ datasets with maximum width and height specified below.</string>
595595
<string>...</string>
596596
</property>
597597
<property name="icon">
598-
<iconset>
599-
<normaloff>../../images/themes/default/mActionDeleteAttribute.svg</normaloff>../../images/themes/default/mActionDeleteAttribute.svg</iconset>
598+
<iconset resource="../../images/images.qrc">
599+
<normaloff>:/images/themes/default/mActionDeleteAttribute.svg</normaloff>:/images/themes/default/mActionDeleteAttribute.svg</iconset>
600600
</property>
601601
</widget>
602602
</item>
@@ -609,8 +609,8 @@ datasets with maximum width and height specified below.</string>
609609
<string>...</string>
610610
</property>
611611
<property name="icon">
612-
<iconset>
613-
<normaloff>../../images/themes/default/mActionRemove.png</normaloff>../../images/themes/default/mActionRemove.png</iconset>
612+
<iconset resource="../../images/images.qrc">
613+
<normaloff>:/images/themes/default/mActionRemove.svg</normaloff>:/images/themes/default/mActionRemove.svg</iconset>
614614
</property>
615615
</widget>
616616
</item>
@@ -714,7 +714,9 @@ datasets with maximum width and height specified below.</string>
714714
<tabstop>mLoadTransparentNoDataToolButton</tabstop>
715715
<tabstop>mRemoveAllNoDataToolButton</tabstop>
716716
</tabstops>
717-
<resources/>
717+
<resources>
718+
<include location="../../images/images.qrc"/>
719+
</resources>
718720
<connections>
719721
<connection>
720722
<sender>mButtonBox</sender>

0 commit comments

Comments
 (0)