mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Upgrade the save as image function into a background task (#4382)
This commit is contained in:
parent
20197c2fa3
commit
db848a3f1a
@ -95,6 +95,7 @@
|
||||
%Include qgsmaprendererjob.sip
|
||||
%Include qgsmaprendererparalleljob.sip
|
||||
%Include qgsmaprenderersequentialjob.sip
|
||||
%Include qgsmaprenderertask.sip
|
||||
%Include qgsmapsettings.sip
|
||||
%Include qgsmaptopixel.sip
|
||||
%Include qgsmapunitscale.sip
|
||||
|
76
python/core/qgsmaprenderertask.sip
Normal file
76
python/core/qgsmaprenderertask.sip
Normal file
@ -0,0 +1,76 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsmaprenderertask.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsMapRendererTask : QgsTask
|
||||
{
|
||||
%Docstring
|
||||
QgsTask task which draws a map to an image file or a painter as a background
|
||||
task. This can be used to draw maps without blocking the QGIS interface.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsmaprenderertask.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum ErrorType
|
||||
{
|
||||
ImageAllocationFail,
|
||||
ImageSaveFail
|
||||
};
|
||||
|
||||
QgsMapRendererTask( const QgsMapSettings &ms,
|
||||
const QString &fileName,
|
||||
const QString &fileFormat = QString( "PNG" ) );
|
||||
%Docstring
|
||||
Constructor for QgsMapRendererTask to render a map to an image file.
|
||||
%End
|
||||
|
||||
QgsMapRendererTask( const QgsMapSettings &ms,
|
||||
QPainter *p );
|
||||
%Docstring
|
||||
Constructor for QgsMapRendererTask to render a map to a painter object.
|
||||
%End
|
||||
|
||||
void addAnnotations( QList< QgsAnnotation * > annotations );
|
||||
%Docstring
|
||||
Adds ``annotations`` to be rendered on the map.
|
||||
%End
|
||||
|
||||
signals:
|
||||
|
||||
void renderingComplete();
|
||||
%Docstring
|
||||
Emitted when the map rendering is successfully completed.
|
||||
%End
|
||||
|
||||
void errorOccurred( int error );
|
||||
%Docstring
|
||||
Emitted when map rendering failed.
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool run();
|
||||
virtual void finished( bool result );
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsmaprenderertask.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
@ -270,6 +270,7 @@
|
||||
#include "qgsvectorlayerutils.h"
|
||||
#include "qgshelp.h"
|
||||
#include "qgsvectorfilewritertask.h"
|
||||
#include "qgsmaprenderertask.h"
|
||||
#include "qgsnewnamedialog.h"
|
||||
|
||||
#include "qgssublayersdialog.h"
|
||||
@ -5772,9 +5773,48 @@ void QgisApp::saveMapAsImage()
|
||||
QPair< QString, QString> myFileNameAndFilter = QgisGui::getSaveAsImageName( this, tr( "Choose a file name to save the map image as" ) );
|
||||
if ( myFileNameAndFilter.first != QLatin1String( "" ) )
|
||||
{
|
||||
//save the mapview to the selected file
|
||||
mMapCanvas->saveAsImage( myFileNameAndFilter.first, nullptr, myFileNameAndFilter.second );
|
||||
statusBar()->showMessage( tr( "Saved map image to %1" ).arg( myFileNameAndFilter.first ) );
|
||||
//TODO: GUI
|
||||
int dpi = 90;
|
||||
QSize size = mMapCanvas->size() * ( dpi / 90 );
|
||||
|
||||
QgsMapSettings ms = QgsMapSettings();
|
||||
ms.setDestinationCrs( QgsProject::instance()->crs() );
|
||||
ms.setExtent( mMapCanvas->extent() );
|
||||
ms.setOutputSize( size );
|
||||
ms.setOutputDpi( dpi );
|
||||
ms.setBackgroundColor( mMapCanvas->canvasColor() );
|
||||
ms.setRotation( mMapCanvas->rotation() );
|
||||
ms.setLayers( mMapCanvas->layers() );
|
||||
|
||||
QgsMapRendererTask *mapRendererTask = new QgsMapRendererTask( ms, myFileNameAndFilter.first, myFileNameAndFilter.second );
|
||||
mapRendererTask->addAnnotations( QgsProject::instance()->annotationManager()->annotations() );
|
||||
|
||||
connect( mapRendererTask, &QgsMapRendererTask::renderingComplete, this, [ = ]
|
||||
{
|
||||
QgsMessageBarItem *successMsg = new QgsMessageBarItem(
|
||||
tr( "Successfully saved canvas to image" ),
|
||||
QgsMessageBar::SUCCESS );
|
||||
messageBar()->pushItem( successMsg );
|
||||
} );
|
||||
connect( mapRendererTask, &QgsMapRendererTask::errorOccurred, this, [ = ]( int error )
|
||||
{
|
||||
if ( error == QgsMapRendererTask::ImageAllocationFail )
|
||||
{
|
||||
QgsMessageBarItem *errorMsg = new QgsMessageBarItem(
|
||||
tr( "Could not allocate required memory for image" ),
|
||||
QgsMessageBar::WARNING );
|
||||
messageBar()->pushItem( errorMsg );
|
||||
}
|
||||
else if ( error == QgsMapRendererTask::ImageAllocationFail )
|
||||
{
|
||||
QgsMessageBarItem *errorMsg = new QgsMessageBarItem(
|
||||
tr( "Could not save the image to file" ),
|
||||
QgsMessageBar::WARNING );
|
||||
messageBar()->pushItem( errorMsg );
|
||||
}
|
||||
} );
|
||||
|
||||
QgsApplication::taskManager()->addTask( mapRendererTask );
|
||||
}
|
||||
|
||||
} // saveMapAsImage
|
||||
|
@ -173,6 +173,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsmaprendererjob.cpp
|
||||
qgsmaprendererparalleljob.cpp
|
||||
qgsmaprenderersequentialjob.cpp
|
||||
qgsmaprenderertask.cpp
|
||||
qgsmapsettings.cpp
|
||||
qgsmaptopixel.cpp
|
||||
qgsmaptopixelgeometrysimplifier.cpp
|
||||
@ -521,6 +522,7 @@ SET(QGIS_CORE_MOC_HDRS
|
||||
qgsmaprendererjob.h
|
||||
qgsmaprendererparalleljob.h
|
||||
qgsmaprenderersequentialjob.h
|
||||
qgsmaprenderertask.h
|
||||
qgsmessagelog.h
|
||||
qgsmessageoutput.h
|
||||
qgsnetworkaccessmanager.h
|
||||
|
133
src/core/qgsmaprenderertask.cpp
Normal file
133
src/core/qgsmaprenderertask.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
/***************************************************************************
|
||||
qgsmaprenderertask.h
|
||||
-------------------------
|
||||
begin : Apr 2017
|
||||
copyright : (C) 2017 by Mathieu Pellerin
|
||||
email : nirvn dot asia at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsannotation.h"
|
||||
#include "qgsannotationmanager.h"
|
||||
#include "qgsmaprenderertask.h"
|
||||
#include "qgsmaprenderercustompainterjob.h"
|
||||
|
||||
|
||||
QgsMapRendererTask::QgsMapRendererTask( const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat )
|
||||
: QgsTask( tr( "Saving as image" ) )
|
||||
, mMapSettings( ms )
|
||||
, mFileName( fileName )
|
||||
, mFileFormat( fileFormat )
|
||||
{
|
||||
}
|
||||
|
||||
QgsMapRendererTask::QgsMapRendererTask( const QgsMapSettings &ms, QPainter *p )
|
||||
: QgsTask( tr( "Saving as image" ) )
|
||||
, mMapSettings( ms )
|
||||
, mPainter( p )
|
||||
{
|
||||
}
|
||||
|
||||
void QgsMapRendererTask::addAnnotations( QList< QgsAnnotation * > annotations )
|
||||
{
|
||||
qDeleteAll( mAnnotations );
|
||||
mAnnotations.clear();
|
||||
|
||||
Q_FOREACH ( const QgsAnnotation *a, annotations )
|
||||
{
|
||||
mAnnotations << a->clone();
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsMapRendererTask::run()
|
||||
{
|
||||
QImage img;
|
||||
std::unique_ptr< QPainter > tempPainter;
|
||||
QPainter *destPainter = mPainter;
|
||||
|
||||
if ( !mPainter )
|
||||
{
|
||||
// save rendered map to an image file
|
||||
img = QImage( mMapSettings.outputSize(), QImage::Format_ARGB32 );
|
||||
if ( img.isNull() )
|
||||
{
|
||||
mError = ImageAllocationFail;
|
||||
return false;
|
||||
}
|
||||
|
||||
tempPainter.reset( new QPainter( &img ) );
|
||||
destPainter = tempPainter.get();
|
||||
}
|
||||
|
||||
if ( !destPainter )
|
||||
return false;
|
||||
|
||||
QgsMapRendererCustomPainterJob r( mMapSettings, destPainter );
|
||||
r.renderSynchronously();
|
||||
|
||||
QgsRenderContext context = QgsRenderContext::fromMapSettings( mMapSettings );
|
||||
context.setPainter( destPainter );
|
||||
|
||||
Q_FOREACH ( QgsAnnotation *annotation, mAnnotations )
|
||||
{
|
||||
if ( !annotation || !annotation->isVisible() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ( annotation->mapLayer() && !mMapSettings.layers().contains( annotation->mapLayer() ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
context.painter()->save();
|
||||
context.painter()->setRenderHint( QPainter::Antialiasing, context.flags() & QgsRenderContext::Antialiasing );
|
||||
|
||||
double itemX, itemY;
|
||||
if ( annotation->hasFixedMapPosition() )
|
||||
{
|
||||
itemX = mMapSettings.outputSize().width() * ( annotation->mapPosition().x() - mMapSettings.extent().xMinimum() ) / mMapSettings.extent().width();
|
||||
itemY = mMapSettings.outputSize().height() * ( 1 - ( annotation->mapPosition().y() - mMapSettings.extent().yMinimum() ) / mMapSettings.extent().height() );
|
||||
}
|
||||
else
|
||||
{
|
||||
itemX = annotation->relativePosition().x() * mMapSettings.outputSize().width();
|
||||
itemY = annotation->relativePosition().y() * mMapSettings.outputSize().height();
|
||||
}
|
||||
|
||||
context.painter()->translate( itemX, itemY );
|
||||
|
||||
annotation->render( context );
|
||||
context.painter()->restore();
|
||||
}
|
||||
qDeleteAll( mAnnotations );
|
||||
mAnnotations.clear();
|
||||
|
||||
if ( !mFileName.isEmpty() )
|
||||
{
|
||||
destPainter->end();
|
||||
bool success = img.save( mFileName, mFileFormat.toLocal8Bit().data() );
|
||||
if ( !success )
|
||||
{
|
||||
mError = ImageSaveFail;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsMapRendererTask::finished( bool result )
|
||||
{
|
||||
if ( result )
|
||||
emit renderingComplete();
|
||||
else
|
||||
emit errorOccurred( mError );
|
||||
}
|
99
src/core/qgsmaprenderertask.h
Normal file
99
src/core/qgsmaprenderertask.h
Normal file
@ -0,0 +1,99 @@
|
||||
/***************************************************************************
|
||||
qgsmaprenderertask.h
|
||||
-------------------------
|
||||
begin : Apr 2017
|
||||
copyright : (C) 2017 by Mathieu Pellerin
|
||||
email : nirvn dot asia at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMAPRENDERERTASK_H
|
||||
#define QGSMAPRENDERERTASK_H
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgis_core.h"
|
||||
#include "qgsannotation.h"
|
||||
#include "qgsannotationmanager.h"
|
||||
#include "qgsmapsettings.h"
|
||||
#include "qgstaskmanager.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
/**
|
||||
* \class QgsMapRendererTask
|
||||
* \ingroup core
|
||||
* QgsTask task which draws a map to an image file or a painter as a background
|
||||
* task. This can be used to draw maps without blocking the QGIS interface.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsMapRendererTask : public QgsTask
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
//! \brief Error type
|
||||
enum ErrorType
|
||||
{
|
||||
ImageAllocationFail = 1, // Image allocation failure
|
||||
ImageSaveFail // Image save failure
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for QgsMapRendererTask to render a map to an image file.
|
||||
*/
|
||||
QgsMapRendererTask( const QgsMapSettings &ms,
|
||||
const QString &fileName,
|
||||
const QString &fileFormat = QString( "PNG" ) );
|
||||
|
||||
/**
|
||||
* Constructor for QgsMapRendererTask to render a map to a painter object.
|
||||
*/
|
||||
QgsMapRendererTask( const QgsMapSettings &ms,
|
||||
QPainter *p );
|
||||
|
||||
/**
|
||||
* Adds \a annotations to be rendered on the map.
|
||||
*/
|
||||
void addAnnotations( QList< QgsAnnotation * > annotations );
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted when the map rendering is successfully completed.
|
||||
*/
|
||||
void renderingComplete();
|
||||
|
||||
/**
|
||||
* Emitted when map rendering failed.
|
||||
*/
|
||||
void errorOccurred( int error );
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool run() override;
|
||||
virtual void finished( bool result ) override;
|
||||
|
||||
private:
|
||||
|
||||
QgsMapSettings mMapSettings;
|
||||
|
||||
QPainter *mPainter = nullptr;
|
||||
|
||||
QString mFileName;
|
||||
QString mFileFormat;
|
||||
|
||||
QList< QgsAnnotation * > mAnnotations;
|
||||
|
||||
int mError = 0;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user