Skip to content

Commit

Permalink
save as raster: fix vrt creation (fixes #14171)
Browse files Browse the repository at this point in the history
  • Loading branch information
jef-n committed Jun 22, 2016
1 parent b369b20 commit d69ec2e
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
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5923,110 +5923,118 @@ void QgisApp::saveAsRasterFile()
mMapCanvas->extent(), rasterLayer->crs(), mMapCanvas->extent(), rasterLayer->crs(),
mMapCanvas->mapSettings().destinationCrs(), mMapCanvas->mapSettings().destinationCrs(),
this ); this );
if ( d.exec() == QDialog::Accepted ) if ( d.exec() == QDialog::Rejected )
{ return;
QSettings settings;
settings.setValue( "/UI/lastRasterFileDir", QFileInfo( d.outputFileName() ).absolutePath() );


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


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


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


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


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


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


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


QgsRasterFileWriter::WriterError err = fileWriter.writeRaster( pipe.data(), d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs(), &pd ); fileWriter.setBuildPyramidsFlag( d.buildPyramidsFlag() );
if ( err != QgsRasterFileWriter::NoError ) fileWriter.setPyramidsList( d.pyramidsList() );
{ fileWriter.setPyramidsResampling( d.pyramidsResamplingMethod() );
QMessageBox::warning( this, tr( "Error" ), fileWriter.setPyramidsFormat( d.pyramidsFormat() );
tr( "Cannot write raster error code: %1" ).arg( err ), fileWriter.setPyramidsConfigOptions( d.pyramidsConfigOptions() );
QMessageBox::Ok );


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( fileName ) );
{
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() );
} }

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
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster(


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


if ( mTileModeCheckBox->isChecked() ) if ( mTileModeCheckBox->isChecked() )
{ {
while ( true ) Q_FOREVER
{ {
// TODO: would not it be better to select .vrt file instead of directory? // TODO: would not it be better to select .vrt file instead of directory?
fileName = QFileDialog::getExistingDirectory( this, tr( "Select output directory" ), dirName ); fileName = QFileDialog::getExistingDirectory( this, tr( "Select output directory" ), dirName );
//fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), QString(), tr( "VRT" ) + " (*.vrt *.VRT)" ); //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 // Check if directory is empty
QDir dir( fileName ); QDir dir( fileName );
QString baseName = QFileInfo( fileName ).baseName(); QString baseName = QFileInfo( fileName ).baseName();
QStringList filters; QStringList filters;
filters << QString( "%1.*" ).arg( baseName ); filters << QString( "%1.*" ).arg( baseName );
QStringList files = dir.entryList( filters ); QStringList files = dir.entryList( filters );
if ( !files.isEmpty() ) if ( files.isEmpty() )
{ break;
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 ( button == QMessageBox::Ok ) if ( QMessageBox::warning( this, tr( "Warning" ),
{ tr( "The directory %1 contains files which will be overwritten: %2" ).arg( dir.absolutePath(), files.join( ", " ) ),
break; QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Ok )
}
else
{
fileName = "";
}
}
else
{
break; break;
}
fileName = "";
} }
} }
else else
{ {
fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), dirName, tr( "GeoTIFF" ) + " (*.tif *.tiff *.TIF *.TIFF)" ); fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), dirName, tr( "GeoTIFF" ) + " (*.tif *.tiff *.TIF *.TIFF)" );
}


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

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

0 comments on commit d69ec2e

Please sign in to comment.