Skip to content

Commit

Permalink
save as raster: fix vrt creation (fixes #14171)
Browse files Browse the repository at this point in the history
(cherry picked from commit d69ec2e)
  • Loading branch information
jef-n committed Jun 26, 2016
1 parent 57c199f commit 852bd53
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 117 deletions.
174 changes: 91 additions & 83 deletions src/app/qgisapp.cpp
Expand Up @@ -5538,110 +5538,118 @@ void QgisApp::saveAsRasterFile()
mMapCanvas->extent(), rasterLayer->crs(),
mMapCanvas->mapSettings().destinationCrs(),
this );
if ( d.exec() == QDialog::Accepted )
{
QSettings settings;
settings.setValue( "/UI/lastRasterFileDir", QFileInfo( d.outputFileName() ).absolutePath() );
if ( d.exec() == QDialog::Rejected )
return;

QgsRasterFileWriter fileWriter( d.outputFileName() );
if ( d.tileMode() )
{
fileWriter.setTiledMode( true );
fileWriter.setMaxTileWidth( d.maximumTileSizeX() );
fileWriter.setMaxTileHeight( d.maximumTileSizeY() );
}
QSettings settings;
settings.setValue( "/UI/lastRasterFileDir", QFileInfo( d.outputFileName() ).absolutePath() );

QProgressDialog pd( nullptr, tr( "Abort..." ), 0, 0 );
// Show the dialo immediately because cloning pipe can take some time (WCS)
pd.setLabelText( tr( "Reading raster" ) );
pd.setWindowTitle( tr( "Saving raster" ) );
pd.show();
pd.setWindowModality( Qt::WindowModal );
QgsRasterFileWriter fileWriter( d.outputFileName() );
if ( d.tileMode() )
{
fileWriter.setTiledMode( true );
fileWriter.setMaxTileWidth( d.maximumTileSizeX() );
fileWriter.setMaxTileHeight( d.maximumTileSizeY() );
}

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

if ( d.mode() == QgsRasterLayerSaveAsDialog::RawDataMode )
{
QgsDebugMsg( "Writing raw data" );
//QgsDebugMsg( QString( "Writing raw data" ).arg( pos ) );
pipe.reset( new QgsRasterPipe() );
if ( !pipe->set( rasterLayer->dataProvider()->clone() ) )
{
QgsDebugMsg( "Cannot set pipe provider" );
return;
}
// TODO: show error dialogs
// TODO: this code should go somewhere else, but probably not into QgsRasterFileWriter
// clone pipe/provider is not really necessary, ready for threads
QScopedPointer<QgsRasterPipe> pipe( nullptr );

QgsRasterNuller *nuller = new QgsRasterNuller();
for ( int band = 1; band <= rasterLayer->dataProvider()->bandCount(); band ++ )
{
nuller->setNoData( band, d.noData() );
}
if ( !pipe->insert( 1, nuller ) )
{
QgsDebugMsg( "Cannot set pipe nuller" );
return;
}
if ( d.mode() == QgsRasterLayerSaveAsDialog::RawDataMode )
{
QgsDebugMsg( "Writing raw data" );
//QgsDebugMsg( QString( "Writing raw data" ).arg( pos ) );
pipe.reset( new QgsRasterPipe() );
if ( !pipe->set( rasterLayer->dataProvider()->clone() ) )
{
QgsDebugMsg( "Cannot set pipe provider" );
return;
}

// add projector if necessary
if ( d.outputCrs() != rasterLayer->crs() )
{
QgsRasterProjector * projector = new QgsRasterProjector;
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
if ( !pipe->insert( 2, projector ) )
{
QgsDebugMsg( "Cannot set pipe projector" );
return;
}
}
QgsRasterNuller *nuller = new QgsRasterNuller();
for ( int band = 1; band <= rasterLayer->dataProvider()->bandCount(); band ++ )
{
nuller->setNoData( band, d.noData() );
}
else // RenderedImageMode
if ( !pipe->insert( 1, nuller ) )
{
// clone the whole pipe
QgsDebugMsg( "Writing rendered image" );
pipe.reset( new QgsRasterPipe( *rasterLayer->pipe() ) );
QgsRasterProjector *projector = pipe->projector();
if ( !projector )
QgsDebugMsg( "Cannot set pipe nuller" );
return;
}

// add projector if necessary
if ( d.outputCrs() != rasterLayer->crs() )
{
QgsRasterProjector * projector = new QgsRasterProjector;
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
if ( !pipe->insert( 2, projector ) )
{
QgsDebugMsg( "Cannot get pipe projector" );
QgsDebugMsg( "Cannot set pipe projector" );
return;
}
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
}

if ( !pipe->last() )
}
else // RenderedImageMode
{
// clone the whole pipe
QgsDebugMsg( "Writing rendered image" );
pipe.reset( new QgsRasterPipe( *rasterLayer->pipe() ) );
QgsRasterProjector *projector = pipe->projector();
if ( !projector )
{
QgsDebugMsg( "Cannot get pipe projector" );
return;
}
fileWriter.setCreateOptions( d.createOptions() );
projector->setCRS( rasterLayer->crs(), d.outputCrs() );
}

fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
fileWriter.setPyramidsList( d.pyramidsList() );
fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );
if ( !pipe->last() )
{
return;
}
fileWriter.setCreateOptions( d.createOptions() );

QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe.data(), 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 );
fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
fileWriter.setPyramidsList( d.pyramidsList() );
fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
fileWriter.setPyramidsFormat( d.pyramidsFormat() );
fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );

QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe.data(), 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 );

}
else
{
QString fileName( d.outputFileName() );
if ( d.tileMode() )
{
QFileInfo outputInfo( fileName );
fileName = QString( "%1/%2.vrt" ).arg( fileName, outputInfo.fileName() );
}
else

if ( d.addToCanvas() )
{
if ( d.addToCanvas() )
{
addRasterLayers( QStringList( d.outputFileName() ) );
}
emit layerSavedAs( rasterLayer, d.outputFileName() );
messageBar()->pushMessage( tr( "Saving done" ),
tr( "Export to raster file has been completed" ),
QgsMessageBar::INFO, messageTimeout() );
addRasterLayers( QStringList( fileName ) );
}

emit layerSavedAs( rasterLayer, fileName );
messageBar()->pushMessage( tr( "Saving done" ),
tr( "Export to raster file has been completed" ),
QgsMessageBar::INFO, messageTimeout() );
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/raster/qgsrasterfilewriter.cpp
Expand Up @@ -355,7 +355,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(

// hmm why is there a for(;;) here ..
// not good coding practice IMHO, it might be better to use [ for() and break ] or [ while (test) ]
for ( ;; )
Q_FOREVER
{
for ( int i = 1; i <= nBands; ++i )
{
Expand Down
40 changes: 16 additions & 24 deletions src/gui/qgsrasterlayersaveasdialog.cpp
Expand Up @@ -163,53 +163,45 @@ void QgsRasterLayerSaveAsDialog::on_mBrowseButton_clicked()

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

if ( fileName.isEmpty() ) break; // canceled
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(), files.join( ", " ) ),
QMessageBox::Ok | QMessageBox::Cancel );
if ( files.isEmpty() )
break;

if ( button == QMessageBox::Ok )
{
break;
}
else
{
fileName = "";
}
}
else
{
if ( QMessageBox::warning( this, tr( "Warning" ),
tr( "The directory %1 contains files which will be overwritten: %2" ).arg( dir.absolutePath(), files.join( ", " ) ),
QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Ok )
break;
}

fileName = "";
}
}
else
{
fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), dirName, tr( "GeoTIFF" ) + " (*.tif *.tiff *.TIF *.TIFF)" );
}

if ( !fileName.isEmpty() )
{
// ensure the user never ommited the extension from the file name
if ( !fileName.endsWith( ".tif", Qt::CaseInsensitive ) && !fileName.endsWith( ".tiff", Qt::CaseInsensitive ) )
// ensure the user never omits the extension from the file name
if ( !fileName.isEmpty() && !fileName.endsWith( ".tif", Qt::CaseInsensitive ) && !fileName.endsWith( ".tiff", Qt::CaseInsensitive ) )
{
fileName += ".tif";
}
}

if ( !fileName.isEmpty() )
{
mSaveAsLineEdit->setText( fileName );
}
}
Expand Down
20 changes: 11 additions & 9 deletions src/ui/qgsrasterlayersaveasdialogbase.ui
Expand Up @@ -564,8 +564,8 @@ datasets with maximum width and height specified below.</string>
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>../../images/themes/default/mActionNewAttribute.png</normaloff>../../images/themes/default/mActionNewAttribute.png</iconset>
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionNewAttribute.svg</normaloff>:/images/themes/default/mActionNewAttribute.svg</iconset>
</property>
</widget>
</item>
Expand All @@ -578,8 +578,8 @@ datasets with maximum width and height specified below.</string>
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>../../images/themes/default/mActionCopySelected.png</normaloff>../../images/themes/default/mActionCopySelected.png</iconset>
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionCopySelected.png</normaloff>:/images/themes/default/mActionCopySelected.png</iconset>
</property>
</widget>
</item>
Expand All @@ -595,8 +595,8 @@ datasets with maximum width and height specified below.</string>
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>../../images/themes/default/mActionDeleteAttribute.png</normaloff>../../images/themes/default/mActionDeleteAttribute.png</iconset>
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionDeleteAttribute.png</normaloff>:/images/themes/default/mActionDeleteAttribute.png</iconset>
</property>
</widget>
</item>
Expand All @@ -609,8 +609,8 @@ datasets with maximum width and height specified below.</string>
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>../../images/themes/default/mActionRemove.png</normaloff>../../images/themes/default/mActionRemove.png</iconset>
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionRemove.png</normaloff>:/images/themes/default/mActionRemove.png</iconset>
</property>
</widget>
</item>
Expand Down Expand Up @@ -714,7 +714,9 @@ datasets with maximum width and height specified below.</string>
<tabstop>mLoadTransparentNoDataToolButton</tabstop>
<tabstop>mRemoveAllNoDataToolButton</tabstop>
</tabstops>
<resources/>
<resources>
<include location="../../images/images.qrc"/>
</resources>
<connections>
<connection>
<sender>mButtonBox</sender>
Expand Down

0 comments on commit 852bd53

Please sign in to comment.