Skip to content

Commit

Permalink
[feature] Handy null painter device class to use with map renderer cu…
Browse files Browse the repository at this point in the history
…stom painter jobs
  • Loading branch information
nirvn committed Dec 30, 2021
1 parent 6c6e011 commit 6e60731
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 0 deletions.
53 changes: 53 additions & 0 deletions python/core/auto_generated/qgsnullpainterdevice.sip.in
@@ -0,0 +1,53 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsnullpainterdevice.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/







class QgsNullPaintDevice: QPaintDevice
{
%Docstring(signature="appended")
Null painter device that can be used for map renderer jobs which use custom painters.

.. versionadded:: 3.24
%End

%TypeHeaderCode
#include "qgsnullpainterdevice.h"
%End
public:

QgsNullPaintDevice();

virtual QPaintEngine *paintEngine() const;


virtual int metric( PaintDeviceMetric metric ) const;


void setOutputSize( const QSize &size );
%Docstring
Sets the ``size`` of the device in pixels.
%End
void setOutputDpi( const int dpi );
%Docstring
Sets the ``dpi`` of the device.
%End
};


/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsnullpainterdevice.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Expand Up @@ -122,6 +122,7 @@
%Include auto_generated/qgsmessageoutput.sip
%Include auto_generated/qgsmimedatautils.sip
%Include auto_generated/qgsmultirenderchecker.sip
%Include auto_generated/qgsnullpainterdevice.sip
%Include auto_generated/qgsobjectcustomproperties.sip
%Include auto_generated/qgsofflineediting.sip
%Include auto_generated/qgsogcutils.sip
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -422,6 +422,7 @@ set(QGIS_CORE_SRCS
qgsmessageoutput.cpp
qgsmimedatautils.cpp
qgsmultirenderchecker.cpp
qgsnullpainterdevice.cpp
qgsobjectcustomproperties.cpp
qgsofflineediting.cpp
qgsogcutils.cpp
Expand Down Expand Up @@ -1063,6 +1064,7 @@ set(QGIS_CORE_HDRS
qgsmessageoutput.h
qgsmimedatautils.h
qgsmultirenderchecker.h
qgsnullpainterdevice.h
qgsobjectcustomproperties.h
qgsofflineediting.h
qgsogcutils.h
Expand Down
56 changes: 56 additions & 0 deletions src/core/qgsnullpainterdevice.cpp
@@ -0,0 +1,56 @@
/***************************************************************************
qgsnullpainterdevice.cpp
--------------------------------------
Date : December 2021
Copyright : (C) 2013 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 "qgsnullpainterdevice.h"


QgsNullPaintDevice::QgsNullPaintDevice()
{
mPaintEngine = std::make_unique<QgsNullPaintEngine>();
}

QPaintEngine *QgsNullPaintDevice::paintEngine() const
{
return mPaintEngine.get();
}

int QgsNullPaintDevice::metric( PaintDeviceMetric metric ) const
{
switch ( metric )
{
case QPaintDevice::PdmWidth:
return mSize.width();
case QPaintDevice::PdmHeight:
return mSize.height();
case QPaintDevice::PdmWidthMM:
return mSize.width();
case QPaintDevice::PdmHeightMM:
return mSize.height();
case QPaintDevice::PdmNumColors:
return std::numeric_limits<int>::max();
case QPaintDevice::PdmDepth:
return 32;
case QPaintDevice::PdmDpiX:
case QPaintDevice::PdmDpiY:
case QPaintDevice::PdmPhysicalDpiX:
case QPaintDevice::PdmPhysicalDpiY:
return mDpi;
case QPaintDevice::PdmDevicePixelRatio:
return 1;
case QPaintDevice::PdmDevicePixelRatioScaled:
return 1;
}
return 0;
}
98 changes: 98 additions & 0 deletions src/core/qgsnullpainterdevice.h
@@ -0,0 +1,98 @@
/***************************************************************************
qgsnullpainterdevice.h
--------------------------------------
Date : December 2021
Copyright : (C) 2013 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 QGSNULLPAINTERDEVICE_H
#define QGSNULLPAINTERDEVICE_H

#include "qgis_core.h"
#include "qgis_sip.h"

#include <QPaintDevice>
#include <QPaintEngine>
#include <memory>


#ifndef SIP_RUN
///@cond PRIVATE
class QgsNullPaintEngine: public QPaintEngine
{

public:

QgsNullPaintEngine() : QPaintEngine( QPaintEngine::AllFeatures ) {};

bool begin( QPaintDevice * ) override { return true; };
bool end() override { return true; };
QPaintEngine::Type type() const override { return QPaintEngine::User; };
void updateState( const QPaintEngineState & ) override { return; };

void drawRects( const QRect *, int ) override { return; };
void drawRects( const QRectF *, int ) override { return; };
void drawLines( const QLine *, int ) override { return; };
void drawLines( const QLineF *, int ) override { return; };
void drawEllipse( const QRectF & ) override { return; };
void drawEllipse( const QRect & ) override { return; };
void drawPath( const QPainterPath & ) override { return; };
void drawPoints( const QPointF *, int ) override { return; };
void drawPoints( const QPoint *, int ) override { return; };
void drawPolygon( const QPointF *, int, PolygonDrawMode ) override { return; };
void drawPolygon( const QPoint *, int, PolygonDrawMode ) override { return; };
void drawPixmap( const QRectF &, const QPixmap &, const QRectF & ) override { return; };
void drawTextItem( const QPointF &, const QTextItem & ) override { return; };
void drawTiledPixmap( const QRectF &, const QPixmap &, const QPointF & ) override { return; };
void drawImage( const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags ) override { return; };

};
///@endcond
#endif


/**
* \ingroup core
* \brief Null painter device that can be used for map renderer jobs which use custom painters.
* \since QGIS 3.24
*/
class CORE_EXPORT QgsNullPaintDevice: public QPaintDevice
{

public:

QgsNullPaintDevice();

QPaintEngine *paintEngine() const override;

int metric( PaintDeviceMetric metric ) const override;

/**
* Sets the \a size of the device in pixels.
*/
void setOutputSize( const QSize &size ) { mSize = size; };

/**
* Sets the \a dpi of the device.
*/
void setOutputDpi( const int dpi ) { mDpi = dpi; };

private:

std::unique_ptr<QgsNullPaintEngine> mPaintEngine;

QSize mSize;
int mDpi = 96;

};


#endif // QGSNULLPAINTERDEVICE_H
47 changes: 47 additions & 0 deletions tests/src/core/testqgsmaprendererjob.cpp
Expand Up @@ -32,6 +32,8 @@
#include "qgsfield.h"
#include "qgis.h"
#include "qgsmaprenderersequentialjob.h"
#include "qgsmaprenderercustompainterjob.h"
#include "qgsnullpainterdevice.h"
#include "qgsmaplayer.h"
#include "qgsreadwritecontext.h"
#include "qgsproviderregistry.h"
Expand Down Expand Up @@ -96,6 +98,8 @@ class TestQgsMapRendererJob : public QObject
void labelSink();
void skipSymbolRendering();

void customNullPainterJob();

private:
bool imageCheck( const QString &type, const QImage &image, int mismatchCount = 0 );

Expand Down Expand Up @@ -1042,6 +1046,49 @@ void TestQgsMapRendererJob::skipSymbolRendering()
QVERIFY( imageCheck( QStringLiteral( "skip_symbol_rendering" ), img ) );
}

void TestQgsMapRendererJob::customNullPainterJob()
{
std::unique_ptr< QgsVectorLayer > pointsLayer = std::make_unique< QgsVectorLayer >( TEST_DATA_DIR + QStringLiteral( "/points.shp" ),
QStringLiteral( "points" ), QStringLiteral( "ogr" ) );
QVERIFY( pointsLayer->isValid() );

QgsPalLayerSettings settings;
settings.fieldName = QStringLiteral( "Class" );
QgsTextFormat format;
format.setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) ).family() );
format.setSize( 12 );
format.setNamedStyle( QStringLiteral( "Bold" ) );
format.setColor( QColor( 200, 0, 200 ) );
settings.setFormat( format );
settings.zIndex = 1;

pointsLayer->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );
pointsLayer->setLabelsEnabled( true );

QgsMapSettings mapSettings;
mapSettings.setDestinationCrs( pointsLayer->crs() );
mapSettings.setExtent( pointsLayer->extent() );
mapSettings.setOutputSize( QSize( 512, 512 ) );
mapSettings.setFlag( Qgis::MapSettingsFlag::DrawLabeling, true );
mapSettings.setOutputDpi( 96 );
mapSettings.setLayers( QList< QgsMapLayer * >() << pointsLayer.get() );

std::unique_ptr<QgsNullPaintDevice> nullPaintDevice = std::make_unique<QgsNullPaintDevice>();
nullPaintDevice->setOutputSize( QSize( 512, 512 ) );
nullPaintDevice->setOutputDpi( 96 );
std::unique_ptr<QPainter> painter = std::make_unique<QPainter>( nullPaintDevice.get() );

QgsMapRendererCustomPainterJob renderJob( mapSettings, painter.get() );

std::unique_ptr<TestLabelSink> labelSink = std::make_unique<TestLabelSink>();
renderJob.setLabelSink( labelSink.get() );

renderJob.start();
renderJob.waitForFinished();

QCOMPARE( labelSink->drawnCount, 17 );
}

bool TestQgsMapRendererJob::imageCheck( const QString &testName, const QImage &image, int mismatchCount )
{
mReport += "<h2>" + testName + "</h2>\n";
Expand Down

0 comments on commit 6e60731

Please sign in to comment.