26#include <QtConcurrentRun>
31static void _fixQPictureDPI( QPainter *p )
37 p->scale(
static_cast< double >(
qt_defaultDpiX() ) / p->device()->logicalDpiX(),
38 static_cast< double >(
qt_defaultDpiY() ) / p->device()->logicalDpiY() );
61 QPaintDevice *paintDevice = painter->device();
62 const QString errMsg = QStringLiteral(
"pre-set DPI not equal to painter's DPI (%1 vs %2)" )
63 .arg( paintDevice->logicalDpiX() )
66 "Job::startRender()", errMsg.toLatin1().data() );
79 , mRenderSynchronously( false )
87 Q_ASSERT( !mFutureWatcher.isRunning() );
91void QgsMapRendererCustomPainterJob::startPrivate()
105 QgsDebugMsgLevel( QStringLiteral(
"Preparing list of layer jobs for rendering" ), 5 );
106 QElapsedTimer prepareTime;
111 mLabelingEngineV2.reset();
116 mLabelingEngineV2->setMapSettings(
mSettings );
120 mLayerJobs =
prepareJobs( mPainter, mLabelingEngineV2.get() );
121 mLabelJob =
prepareLabelingJob( mPainter, mLabelingEngineV2.get(), canUseLabelCache );
124 QgsDebugMsgLevel( QStringLiteral(
"Rendering prepared in (seconds): %1" ).arg( prepareTime.elapsed() / 1000.0 ), 4 );
126 if ( mRenderSynchronously )
137 connect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
139 mFuture = QtConcurrent::run( staticRender,
this );
140 mFutureWatcher.setFuture( mFuture );
153 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
159 mFutureWatcher.waitForFinished();
161 QgsDebugMsgLevel( QStringLiteral(
"QPAINER cancel waited %1 ms" ).arg( t.elapsed() / 1000.0 ), 5 );
172 QgsDebugMsg( QStringLiteral(
"QPAINTER not running!" ) );
176 mLabelJob.context.setRenderingStopped(
true );
177 for ( LayerRenderJob &job : mLayerJobs )
179 job.context()->setRenderingStopped(
true );
180 if ( job.renderer && job.renderer->feedback() )
181 job.renderer->feedback()->cancel();
190 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
195 mFutureWatcher.waitForFinished();
197 QgsDebugMsgLevel( QStringLiteral(
"waitForFinished: %1 ms" ).arg( t.elapsed() / 1000.0 ), 4 );
209 return mLabelJob.cached;
214 if ( mLabelingEngineV2 )
215 return mLabelingEngineV2->takeResults();
224 connect( &mFutureWatcher, &QFutureWatcher<void>::finished, &loop, &QEventLoop::quit );
231 mRenderSynchronously =
true;
234 mRenderSynchronously =
false;
239 mRenderSynchronously =
true;
252 mRenderSynchronously =
false;
253 mPrepareOnly =
false;
257void QgsMapRendererCustomPainterJob::futureFinished()
287 catch ( std::exception &e )
290 QgsDebugMsg(
"Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
294 QgsDebugMsg( QStringLiteral(
"Caught unhandled unknown exception" ) );
298void QgsMapRendererCustomPainterJob::doRender()
300 const bool hasSecondPass = ! mSecondPassLayerJobs.empty();
302 QElapsedTimer renderTime;
305 for ( LayerRenderJob &job : mLayerJobs )
307 if ( job.context()->renderingStopped() )
312 if ( ! hasSecondPass && job.context()->useAdvancedEffects() )
316 mPainter->setCompositionMode( job.blendMode );
321 QElapsedTimer layerTime;
327 job.imageInitialized =
true;
330 job.completed = job.renderer->render();
334 job.renderer->renderContext()->painter()->end();
337 job.renderingTime += layerTime.elapsed();
340 if ( ! hasSecondPass && job.img )
343 mPainter->setOpacity( job.opacity );
344 mPainter->drawImage( 0, 0, *job.img );
345 mPainter->setOpacity( 1.0 );
356 if ( !mLabelJob.cached )
358 QElapsedTimer labelTime;
364 mLabelJob.img->fill( 0 );
365 painter.begin( mLabelJob.img );
366 mLabelJob.context.setPainter( &painter );
367 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
370 else if ( mLabelJob.picture )
373 painter.begin( mLabelJob.picture.get() );
374 mLabelJob.context.setPainter( &painter );
375 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
380 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), mPainter );
383 mLabelJob.complete =
true;
384 mLabelJob.renderingTime = labelTime.elapsed();
385 mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
389 if ( ! hasSecondPass )
391 if ( mLabelJob.img && mLabelJob.complete )
393 mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
394 mPainter->setOpacity( 1.0 );
395 mPainter->drawImage( 0, 0, *mLabelJob.img );
402 for ( LayerRenderJob &job : mSecondPassLayerJobs )
404 if ( job.context()->renderingStopped() )
409 QElapsedTimer layerTime;
415 job.imageInitialized =
true;
418 job.completed = job.renderer->render();
422 job.renderer->renderContext()->painter()->end();
425 job.renderingTime += layerTime.elapsed();
436 mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
437 mPainter->setOpacity( 1.0 );
438 mPainter->drawImage( 0, 0, finalImage );
443 for ( LayerRenderJob &job : mLayerJobs )
449 _fixQPictureDPI( mPainter );
450 mPainter->drawPicture( 0, 0, *job.picture );
454 mPainter->drawImage( 0, 0, *job.img );
457 if ( mLabelJob.picture )
460 _fixQPictureDPI( mPainter );
461 mPainter->drawPicture( 0, 0, *mLabelJob.picture );
467 QgsDebugMsgLevel( QStringLiteral(
"Rendering completed in (seconds): %1" ).arg( renderTime.elapsed() / 1000.0 ), 2 );
@ ForceVectorOutput
Vector graphics should not be cached and drawn as raster images.
@ ForceRasterMasks
Force symbol masking to be applied using a raster method. This is considerably faster when compared t...
@ LosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
@ Antialiasing
Enable anti-aliasing for map rendering.
@ DrawLabeling
Enable drawing of labels on top of the map.
@ HighQualityImageTransforms
Enable high quality image transformations, which results in better appearance of scaled or rotated ra...
Default QgsLabelingEngine implementation, which completes the whole labeling operation (including lab...
Defines a QGIS exception class.
Class that stores computed placement from labeling engine.
Abstract base class for map renderer jobs which use custom painters.
void preparePainter(QPainter *painter, const QColor &backgroundColor=Qt::transparent)
Prepares the given painter ready for a map render.
QgsMapRendererAbstractCustomPainterJob(const QgsMapSettings &settings)
Constructor for QgsMapRendererAbstractCustomPainterJob, using the given map settings.
Job implementation that renders everything sequentially using a custom painter.
QgsMapRendererCustomPainterJob(const QgsMapSettings &settings, QPainter *painter)
~QgsMapRendererCustomPainterJob() override
void renderSynchronously()
Render the map synchronously in this thread.
void cancel() override
Stop the rendering job - does not return until the job has terminated.
void waitForFinishedWithEventLoop(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Wait for the job to be finished - and keep the thread's event loop running while waiting.
void renderPrepared()
Render a pre-prepared job.
QgsLabelingResults * takeLabelingResults() override
Gets pointer to internal labeling engine (in order to get access to the results).
void cancelWithoutBlocking() override
Triggers cancellation of the rendering job without blocking.
void prepare()
Prepares the job for rendering synchronously in a background thread.
void waitForFinished() override
Block until the job has finished.
bool isActive() const override
Tell whether the rendering job is currently running in background.
bool usedCachedLabels() const override
Returns true if the render job was able to use a cached labeling solution.
Abstract base class for map rendering implementations.
void logRenderingTime(const std::vector< LayerRenderJob > &jobs, const std::vector< LayerRenderJob > &secondPassJobs, const LabelRenderJob &labelJob)
static QImage composeImage(const QgsMapSettings &settings, const std::vector< LayerRenderJob > &jobs, const LabelRenderJob &labelJob, const QgsMapRendererCache *cache=nullptr)
void cleanupSecondPassJobs(std::vector< LayerRenderJob > &jobs)
void initSecondPassJobs(std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob) const
Initialize secondPassJobs according to what have been rendered (mask clipping path e....
static Q_DECL_DEPRECATED void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
void layerRendered(const QString &layerId)
Emitted when a layer has completed rendering.
std::vector< LayerRenderJob > prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet=false)
Creates a list of layer rendering jobs and prepares them for later render.
void renderingLayersFinished()
Emitted when the layers are rendered.
void cleanupJobs(std::vector< LayerRenderJob > &jobs)
QElapsedTimer mRenderingStart
void finished()
emitted when asynchronous rendering is finished (or canceled).
void start()
Start the rendering job and immediately return.
void layerRenderingStarted(const QString &layerId)
Emitted just before rendering starts for a particular layer.
static void composeSecondPass(std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob, bool forceVector=false)
Compose second pass images into first pass images.
std::vector< LayerRenderJob > prepareSecondPassJobs(std::vector< LayerRenderJob > &firstPassJobs, LabelRenderJob &labelJob)
Prepares jobs for a second pass, if selective masks exist (from labels or symbol layers).
LabelRenderJob prepareLabelingJob(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache=true)
Prepares a labeling job.
void cleanupLabelJob(LabelRenderJob &job)
Handles clean up tasks for a label job, including deletion of images and storing cached label results...
bool prepareLabelCache() const
Prepares the cache for storing the result of labeling.
The QgsMapSettings class contains configuration for rendering of the map.
QSize deviceOutputSize() const
Returns the device output size of the map render.
QColor backgroundColor() const
Returns the background color of the map.
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
bool testFlag(Qgis::MapSettingsFlag flag) const
Check whether a particular flag is enabled.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
#define QgsDebugMsgLevel(str, level)
Q_GUI_EXPORT int qt_defaultDpiX()
Q_GUI_EXPORT int qt_defaultDpiY()