Skip to content

Commit 852bd53

Browse files
committed
save as raster: fix vrt creation (fixes #14171)
(cherry picked from commit d69ec2e)
1 parent 57c199f commit 852bd53

File tree

4 files changed

+119
-117
lines changed

4 files changed

+119
-117
lines changed

src/app/qgisapp.cpp

Lines changed: 91 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5538,110 +5538,118 @@ void QgisApp::saveAsRasterFile()
55385538
mMapCanvas->extent(), rasterLayer->crs(),
55395539
mMapCanvas->mapSettings().destinationCrs(),
55405540
this );
5541-
if ( d.exec() == QDialog::Accepted )
5542-
{
5543-
QSettings settings;
5544-
settings.setValue( "/UI/lastRasterFileDir", QFileInfo( d.outputFileName() ).absolutePath() );
5541+
if ( d.exec() == QDialog::Rejected )
5542+
return;
55455543

5546-
QgsRasterFileWriter fileWriter( d.outputFileName() );
5547-
if ( d.tileMode() )
5548-
{
5549-
fileWriter.setTiledMode( true );
5550-
fileWriter.setMaxTileWidth( d.maximumTileSizeX() );
5551-
fileWriter.setMaxTileHeight( d.maximumTileSizeY() );
5552-
}
5544+
QSettings settings;
5545+
settings.setValue( "/UI/lastRasterFileDir", QFileInfo( d.outputFileName() ).absolutePath() );
55535546

5554-
QProgressDialog pd( nullptr, tr( "Abort..." ), 0, 0 );
5555-
// Show the dialo immediately because cloning pipe can take some time (WCS)
5556-
pd.setLabelText( tr( "Reading raster" ) );
5557-
pd.setWindowTitle( tr( "Saving raster" ) );
5558-
pd.show();
5559-
pd.setWindowModality( Qt::WindowModal );
5547+
QgsRasterFileWriter fileWriter( d.outputFileName() );
5548+
if ( d.tileMode() )
5549+
{
5550+
fileWriter.setTiledMode( true );
5551+
fileWriter.setMaxTileWidth( d.maximumTileSizeX() );
5552+
fileWriter.setMaxTileHeight( d.maximumTileSizeY() );
5553+
}
55605554

5561-
// TODO: show error dialogs
5562-
// TODO: this code should go somewhere else, but probably not into QgsRasterFileWriter
5563-
// clone pipe/provider is not really necessary, ready for threads
5564-
QScopedPointer<QgsRasterPipe> pipe( nullptr );
5555+
QProgressDialog pd( nullptr, tr( "Abort..." ), 0, 0 );
5556+
// Show the dialo immediately because cloning pipe can take some time (WCS)
5557+
pd.setLabelText( tr( "Reading raster" ) );
5558+
pd.setWindowTitle( tr( "Saving raster" ) );
5559+
pd.show();
5560+
pd.setWindowModality( Qt::WindowModal );
55655561

5566-
if ( d.mode() == QgsRasterLayerSaveAsDialog::RawDataMode )
5567-
{
5568-
QgsDebugMsg( "Writing raw data" );
5569-
//QgsDebugMsg( QString( "Writing raw data" ).arg( pos ) );
5570-
pipe.reset( new QgsRasterPipe() );
5571-
if ( !pipe->set( rasterLayer->dataProvider()->clone() ) )
5572-
{
5573-
QgsDebugMsg( "Cannot set pipe provider" );
5574-
return;
5575-
}
5562+
// TODO: show error dialogs
5563+
// TODO: this code should go somewhere else, but probably not into QgsRasterFileWriter
5564+
// clone pipe/provider is not really necessary, ready for threads
5565+
QScopedPointer<QgsRasterPipe> pipe( nullptr );
55765566

5577-
QgsRasterNuller *nuller = new QgsRasterNuller();
5578-
for ( int band = 1; band <= rasterLayer->dataProvider()->bandCount(); band ++ )
5579-
{
5580-
nuller->setNoData( band, d.noData() );
5581-
}
5582-
if ( !pipe->insert( 1, nuller ) )
5583-
{
5584-
QgsDebugMsg( "Cannot set pipe nuller" );
5585-
return;
5586-
}
5567+
if ( d.mode() == QgsRasterLayerSaveAsDialog::RawDataMode )
5568+
{
5569+
QgsDebugMsg( "Writing raw data" );
5570+
//QgsDebugMsg( QString( "Writing raw data" ).arg( pos ) );
5571+
pipe.reset( new QgsRasterPipe() );
5572+
if ( !pipe->set( rasterLayer->dataProvider()->clone() ) )
5573+
{
5574+
QgsDebugMsg( "Cannot set pipe provider" );
5575+
return;
5576+
}
55875577

5588-
// add projector if necessary
5589-
if ( d.outputCrs() != rasterLayer->crs() )
5590-
{
5591-
QgsRasterProjector * projector = new QgsRasterProjector;
5592-
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
5593-
if ( !pipe->insert( 2, projector ) )
5594-
{
5595-
QgsDebugMsg( "Cannot set pipe projector" );
5596-
return;
5597-
}
5598-
}
5578+
QgsRasterNuller *nuller = new QgsRasterNuller();
5579+
for ( int band = 1; band <= rasterLayer->dataProvider()->bandCount(); band ++ )
5580+
{
5581+
nuller->setNoData( band, d.noData() );
55995582
}
5600-
else // RenderedImageMode
5583+
if ( !pipe->insert( 1, nuller ) )
56015584
{
5602-
// clone the whole pipe
5603-
QgsDebugMsg( "Writing rendered image" );
5604-
pipe.reset( new QgsRasterPipe( *rasterLayer->pipe() ) );
5605-
QgsRasterProjector *projector = pipe->projector();
5606-
if ( !projector )
5585+
QgsDebugMsg( "Cannot set pipe nuller" );
5586+
return;
5587+
}
5588+
5589+
// add projector if necessary
5590+
if ( d.outputCrs() != rasterLayer->crs() )
5591+
{
5592+
QgsRasterProjector * projector = new QgsRasterProjector;
5593+
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
5594+
if ( !pipe->insert( 2, projector ) )
56075595
{
5608-
QgsDebugMsg( "Cannot get pipe projector" );
5596+
QgsDebugMsg( "Cannot set pipe projector" );
56095597
return;
56105598
}
5611-
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
56125599
}
5613-
5614-
if ( !pipe->last() )
5600+
}
5601+
else // RenderedImageMode
5602+
{
5603+
// clone the whole pipe
5604+
QgsDebugMsg( "Writing rendered image" );
5605+
pipe.reset( new QgsRasterPipe( *rasterLayer->pipe() ) );
5606+
QgsRasterProjector *projector = pipe->projector();
5607+
if ( !projector )
56155608
{
5609+
QgsDebugMsg( "Cannot get pipe projector" );
56165610
return;
56175611
}
5618-
fileWriter.setCreateOptions( d.createOptions() );
5612+
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
5613+
}
56195614

5620-
fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
5621-
fileWriter.setPyramidsList( d.pyramidsList() );
5622-
fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
5623-
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
5624-
fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );
5615+
if ( !pipe->last() )
5616+
{
5617+
return;
5618+
}
5619+
fileWriter.setCreateOptions( d.createOptions() );
56255620

5626-
QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe.data(), d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd );
5627-
if ( err != QgsRasterFileWriter::NoError )
5628-
{
5629-
QMessageBox::warning( this, tr( "Error" ),
5630-
tr( "Cannot write raster error code: %1" ).arg( err ),
5631-
QMessageBox::Ok );
5621+
fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
5622+
fileWriter.setPyramidsList( d.pyramidsList() );
5623+
fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
5624+
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
5625+
fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );
56325626

5627+
QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe.data(), d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd );
5628+
if ( err != QgsRasterFileWriter::NoError )
5629+
{
5630+
QMessageBox::warning( this, tr( "Error" ),
5631+
tr( "Cannot write raster error code: %1" ).arg( err ),
5632+
QMessageBox::Ok );
5633+
5634+
}
5635+
else
5636+
{
5637+
QString fileName( d.outputFileName() );
5638+
if ( d.tileMode() )
5639+
{
5640+
QFileInfo outputInfo( fileName );
5641+
fileName = QString( "%1/%2.vrt" ).arg( fileName, outputInfo.fileName() );
56335642
}
5634-
else
5643+
5644+
if ( d.addToCanvas() )
56355645
{
5636-
if ( d.addToCanvas() )
5637-
{
5638-
addRasterLayers( QStringList( d.outputFileName() ) );
5639-
}
5640-
emit layerSavedAs( rasterLayer, d.outputFileName() );
5641-
messageBar()->pushMessage( tr( "Saving done" ),
5642-
tr( "Export to raster file has been completed" ),
5643-
QgsMessageBar::INFO, messageTimeout() );
5646+
addRasterLayers( QStringList( fileName ) );
56445647
}
5648+
5649+
emit layerSavedAs( rasterLayer, fileName );
5650+
messageBar()->pushMessage( tr( "Saving done" ),
5651+
tr( "Export to raster file has been completed" ),
5652+
QgsMessageBar::INFO, messageTimeout() );
56455653
}
56465654
}
56475655

src/core/raster/qgsrasterfilewriter.cpp

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

356356
// hmm why is there a for(;;) here ..
357357
// not good coding practice IMHO, it might be better to use [ for() and break ] or [ while (test) ]
358-
for ( ;; )
358+
Q_FOREVER
359359
{
360360
for ( int i = 1; i <= nBands; ++i )
361361
{

src/gui/qgsrasterlayersaveasdialog.cpp

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

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

172-
if ( fileName.isEmpty() ) break; // canceled
172+
if ( fileName.isEmpty() )
173+
break; // canceled
173174

174175
// Check if directory is empty
175176
QDir dir( fileName );
176177
QString baseName = QFileInfo( fileName ).baseName();
177178
QStringList filters;
178179
filters << QString( "%1.*" ).arg( baseName );
179180
QStringList files = dir.entryList( filters );
180-
if ( !files.isEmpty() )
181-
{
182-
QMessageBox::StandardButton button = QMessageBox::warning( this, tr( "Warning" ),
183-
tr( "The directory %1 contains files which will be overwritten: %2" ).arg( dir.absolutePath(), files.join( ", " ) ),
184-
QMessageBox::Ok | QMessageBox::Cancel );
181+
if ( files.isEmpty() )
182+
break;
185183

186-
if ( button == QMessageBox::Ok )
187-
{
188-
break;
189-
}
190-
else
191-
{
192-
fileName = "";
193-
}
194-
}
195-
else
196-
{
184+
if ( QMessageBox::warning( this, tr( "Warning" ),
185+
tr( "The directory %1 contains files which will be overwritten: %2" ).arg( dir.absolutePath(), files.join( ", " ) ),
186+
QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Ok )
197187
break;
198-
}
188+
189+
fileName = "";
199190
}
200191
}
201192
else
202193
{
203194
fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), dirName, tr( "GeoTIFF" ) + " (*.tif *.tiff *.TIF *.TIFF)" );
204-
}
205195

206-
if ( !fileName.isEmpty() )
207-
{
208-
// ensure the user never ommited the extension from the file name
209-
if ( !fileName.endsWith( ".tif", Qt::CaseInsensitive ) && !fileName.endsWith( ".tiff", Qt::CaseInsensitive ) )
196+
// ensure the user never omits the extension from the file name
197+
if ( !fileName.isEmpty() && !fileName.endsWith( ".tif", Qt::CaseInsensitive ) && !fileName.endsWith( ".tiff", Qt::CaseInsensitive ) )
210198
{
211199
fileName += ".tif";
212200
}
201+
}
202+
203+
if ( !fileName.isEmpty() )
204+
{
213205
mSaveAsLineEdit->setText( fileName );
214206
}
215207
}

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.png</normaloff>../../images/themes/default/mActionNewAttribute.png</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.png</normaloff>../../images/themes/default/mActionDeleteAttribute.png</iconset>
598+
<iconset resource="../../images/images.qrc">
599+
<normaloff>:/images/themes/default/mActionDeleteAttribute.png</normaloff>:/images/themes/default/mActionDeleteAttribute.png</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.png</normaloff>:/images/themes/default/mActionRemove.png</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)