Skip to content

Commit e906783

Browse files
authoredMar 21, 2019
Merge pull request #9362 from pblottiere/legend_json
Add json format for legend
2 parents efc7e87 + 90b46f6 commit e906783

File tree

18 files changed

+463
-2
lines changed

18 files changed

+463
-2
lines changed
 

‎python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ Entry point called from QgsLegendRenderer to do the rendering.
9494
Default implementation calls drawSymbol() and drawSymbolText() methods.
9595

9696
If ctx is ``None``, this is just first stage when preparing layout - without actual rendering.
97+
%End
98+
99+
void exportToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json );
100+
%Docstring
101+
Entry point called from QgsLegendRenderer to do the rendering in a
102+
JSON object.
103+
104+
:param settings: Legend layout configuration
105+
:param context: Rendering context
106+
:param json: The json object to update
107+
108+
.. versionadded:: 3.8
97109
%End
98110

99111
virtual QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const;
@@ -105,6 +117,17 @@ Draws symbol on the left side of the item
105117
:param itemHeight: Minimal height of the legend item - used for correct positioning when rendering
106118

107119
:return: Real size of the symbol (may be bigger than "normal" symbol size from settings)
120+
%End
121+
122+
virtual void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const;
123+
%Docstring
124+
Adds a symbol in base64 string within a JSON object with the key "icon".
125+
126+
:param settings: Legend layout configuration
127+
:param context: Rendering context
128+
:param json: The json object to update
129+
130+
.. versionadded:: 3.8
108131
%End
109132

110133
virtual QSizeF drawSymbolText( const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize ) const;
@@ -116,6 +139,16 @@ Draws label on the right side of the item
116139
:param symbolSize: Real size of the associated symbol - used for correct positioning when rendering
117140

118141
:return: Size of the label (may span multiple lines)
142+
%End
143+
144+
void exportSymbolTextToJson( const QgsLegendSettings &settings, QJsonObject &json ) const;
145+
%Docstring
146+
Adds a label in a JSON object with the key "title".
147+
148+
:param settings: Legend layout configuration
149+
:param json: The json object to update
150+
151+
.. versionadded:: 3.8
119152
%End
120153

121154
signals:
@@ -172,6 +205,9 @@ Constructor for QgsSymbolLegendNode.
172205
virtual QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const;
173206

174207

208+
virtual void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const;
209+
210+
175211
virtual void setEmbeddedInParent( bool embedded );
176212

177213

@@ -358,6 +394,9 @@ Constructor for QgsImageLegendNode.
358394
virtual QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const;
359395

360396

397+
virtual void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const;
398+
399+
361400
};
362401

363402
class QgsRasterSymbolLegendNode : QgsLayerTreeModelLegendNode
@@ -389,6 +428,9 @@ Constructor for QgsRasterSymbolLegendNode.
389428
virtual QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const;
390429

391430

431+
virtual void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const;
432+
433+
392434
};
393435

394436

@@ -419,6 +461,9 @@ Constructor for QgsWmsLegendNode.
419461
virtual QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const;
420462

421463

464+
virtual void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const;
465+
466+
422467
virtual void invalidateMapBasedData();
423468

424469

‎python/core/auto_generated/qgslegendrenderer.sip.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ The ``painter`` should be scaled beforehand so that units correspond to millimet
7676
Draws the legend using a given render ``context``. The legend will occupy the area reported in legendSize().
7777

7878
.. versionadded:: 3.6
79+
%End
80+
81+
void exportLegendToJson( const QgsRenderContext &context, QJsonObject &json );
82+
%Docstring
83+
Renders the legend in a ``json`` object.
84+
85+
.. versionadded:: 3.8
7986
%End
8087

8188
static void setNodeLegendStyle( QgsLayerTreeNode *node, QgsLegendStyle::Style style );

‎src/core/layertree/qgslayertreemodellegendnode.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ QgsLayerTreeModelLegendNode::ItemMetrics QgsLayerTreeModelLegendNode::draw( cons
7171
return im;
7272
}
7373

74+
void QgsLayerTreeModelLegendNode::exportToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json )
75+
{
76+
exportSymbolToJson( settings, context, json );
77+
exportSymbolTextToJson( settings, json );
78+
}
7479

7580
QSizeF QgsLayerTreeModelLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
7681
{
@@ -84,6 +89,19 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbol( const QgsLegendSettings &setting
8489
return settings.symbolSize();
8590
}
8691

92+
void QgsLayerTreeModelLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &, QJsonObject &json ) const
93+
{
94+
const QIcon icon = data( Qt::DecorationRole ).value<QIcon>();
95+
if ( icon.isNull() )
96+
return;
97+
98+
const QImage image( icon.pixmap( settings.symbolSize().width(), settings.symbolSize().height() ).toImage() );
99+
QByteArray byteArray;
100+
QBuffer buffer( &byteArray );
101+
image.save( &buffer, "PNG" );
102+
const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
103+
json[ "icon" ] = base64;
104+
}
87105

88106
QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize ) const
89107
{
@@ -129,6 +147,12 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings &set
129147
return labelSize;
130148
}
131149

150+
void QgsLayerTreeModelLegendNode::exportSymbolTextToJson( const QgsLegendSettings &, QJsonObject &json ) const
151+
{
152+
const QString text = data( Qt::DisplayRole ).toString();
153+
json[ "title" ] = text;
154+
}
155+
132156
// -------------------------------------------------------------------------
133157

134158
QgsSymbolLegendNode::QgsSymbolLegendNode( QgsLayerTreeLayer *nodeLayer, const QgsLegendSymbolItem &item, QObject *parent )
@@ -490,6 +514,47 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
490514
std::max( height + 2 * heightOffset, static_cast< double >( settings.symbolSize().height() ) ) );
491515
}
492516

517+
void QgsSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const
518+
{
519+
const QgsSymbol *s = mItem.symbol();
520+
if ( !s )
521+
{
522+
return;
523+
}
524+
525+
QgsRenderContext ctx;
526+
ctx.setScaleFactor( settings.dpi() / 25.4 );
527+
ctx.setRendererScale( settings.mapScale() );
528+
ctx.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * ctx.scaleFactor() ) ) );
529+
ctx.setForceVectorOutput( true );
530+
531+
// ensure that a minimal expression context is available
532+
QgsExpressionContext expContext = context.expressionContext();
533+
expContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
534+
ctx.setExpressionContext( expContext );
535+
536+
const QPixmap pix = QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), minimumIconSize(), 0, &ctx );
537+
QImage img( pix.toImage().convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
538+
539+
int opacity = 255;
540+
if ( QgsVectorLayer *vectorLayer = dynamic_cast<QgsVectorLayer *>( layerNode()->layer() ) )
541+
opacity = ( 255 * vectorLayer->opacity() );
542+
543+
if ( opacity != 255 )
544+
{
545+
QPainter painter;
546+
painter.begin( &img );
547+
painter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
548+
painter.fillRect( pix.rect(), QColor( 0, 0, 0, opacity ) );
549+
painter.end();
550+
}
551+
552+
QByteArray byteArray;
553+
QBuffer buffer( &byteArray );
554+
img.save( &buffer, "PNG" );
555+
const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
556+
json[ "icon" ] = base64;
557+
}
493558

494559
void QgsSymbolLegendNode::setEmbeddedInParent( bool embedded )
495560
{
@@ -598,6 +663,15 @@ QSizeF QgsImageLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemCo
598663
return settings.wmsLegendSize();
599664
}
600665

666+
void QgsImageLegendNode::exportSymbolToJson( const QgsLegendSettings &, const QgsRenderContext &, QJsonObject &json ) const
667+
{
668+
QByteArray byteArray;
669+
QBuffer buffer( &byteArray );
670+
mImage.save( &buffer, "PNG" );
671+
const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
672+
json[ "icon" ] = base64;
673+
}
674+
601675
// -------------------------------------------------------------------------
602676

603677
QgsRasterSymbolLegendNode::QgsRasterSymbolLegendNode( QgsLayerTreeLayer *nodeLayer, const QColor &color, const QString &label, QObject *parent )
@@ -654,6 +728,44 @@ QSizeF QgsRasterSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings,
654728
return settings.symbolSize();
655729
}
656730

731+
void QgsRasterSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &, QJsonObject &json ) const
732+
{
733+
QImage img = QImage( settings.symbolSize().toSize(), QImage::Format_ARGB32 );
734+
img.fill( Qt::transparent );
735+
736+
QPainter painter( &img );
737+
painter.setRenderHint( QPainter::Antialiasing );
738+
739+
QColor itemColor = mColor;
740+
if ( QgsRasterLayer *rasterLayer = dynamic_cast<QgsRasterLayer *>( layerNode()->layer() ) )
741+
{
742+
if ( QgsRasterRenderer *rasterRenderer = rasterLayer->renderer() )
743+
itemColor.setAlpha( rasterRenderer->opacity() * 255.0 );
744+
}
745+
painter.setBrush( itemColor );
746+
747+
if ( settings.drawRasterStroke() )
748+
{
749+
QPen pen;
750+
pen.setColor( settings.rasterStrokeColor() );
751+
pen.setWidthF( settings.rasterStrokeWidth() );
752+
pen.setJoinStyle( Qt::MiterJoin );
753+
painter.setPen( pen );
754+
}
755+
else
756+
{
757+
painter.setPen( Qt::NoPen );
758+
}
759+
760+
painter.drawRect( QRectF( 0, 0, settings.symbolSize().width(), settings.symbolSize().height() ) );
761+
762+
QByteArray byteArray;
763+
QBuffer buffer( &byteArray );
764+
img.save( &buffer, "PNG" );
765+
const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
766+
json[ "icon" ] = base64;
767+
}
768+
657769
// -------------------------------------------------------------------------
658770

659771
QgsWmsLegendNode::QgsWmsLegendNode( QgsLayerTreeLayer *nodeLayer, QObject *parent )
@@ -722,6 +834,15 @@ QSizeF QgsWmsLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemCont
722834
return settings.wmsLegendSize();
723835
}
724836

837+
void QgsWmsLegendNode::exportSymbolToJson( const QgsLegendSettings &, const QgsRenderContext &, QJsonObject &json ) const
838+
{
839+
QByteArray byteArray;
840+
QBuffer buffer( &byteArray );
841+
mImage.save( &buffer, "PNG" );
842+
const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
843+
json[ "icon" ] = base64;
844+
}
845+
725846
/* private */
726847
QImage QgsWmsLegendNode::renderMessage( const QString &msg ) const
727848
{

‎src/core/layertree/qgslayertreemodellegendnode.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject
110110
*/
111111
virtual ItemMetrics draw( const QgsLegendSettings &settings, ItemContext *ctx );
112112

113+
/**
114+
* Entry point called from QgsLegendRenderer to do the rendering in a
115+
* JSON object.
116+
* \param settings Legend layout configuration
117+
* \param context Rendering context
118+
* \param json The json object to update
119+
* \since QGIS 3.8
120+
*/
121+
void exportToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json );
122+
113123
/**
114124
* Draws symbol on the left side of the item
115125
* \param settings Legend layout configuration
@@ -119,6 +129,15 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject
119129
*/
120130
virtual QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const;
121131

132+
/**
133+
* Adds a symbol in base64 string within a JSON object with the key "icon".
134+
* \param settings Legend layout configuration
135+
* \param context Rendering context
136+
* \param json The json object to update
137+
* \since QGIS 3.8
138+
*/
139+
virtual void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const;
140+
122141
/**
123142
* Draws label on the right side of the item
124143
* \param settings Legend layout configuration
@@ -128,6 +147,14 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject
128147
*/
129148
virtual QSizeF drawSymbolText( const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize ) const;
130149

150+
/**
151+
* Adds a label in a JSON object with the key "title".
152+
* \param settings Legend layout configuration
153+
* \param json The json object to update
154+
* \since QGIS 3.8
155+
*/
156+
void exportSymbolTextToJson( const QgsLegendSettings &settings, QJsonObject &json ) const;
157+
131158
signals:
132159
//! Emitted on internal data change so the layer tree model can forward the signal to views
133160
void dataChanged();
@@ -175,6 +202,8 @@ class CORE_EXPORT QgsSymbolLegendNode : public QgsLayerTreeModelLegendNode
175202

176203
QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const override;
177204

205+
void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const override;
206+
178207
void setEmbeddedInParent( bool embedded ) override;
179208

180209
void setUserLabel( const QString &userLabel ) override { mUserLabel = userLabel; updateLabel(); }
@@ -354,6 +383,8 @@ class CORE_EXPORT QgsImageLegendNode : public QgsLayerTreeModelLegendNode
354383

355384
QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const override;
356385

386+
void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const override;
387+
357388
private:
358389
QImage mImage;
359390
};
@@ -383,6 +414,8 @@ class CORE_EXPORT QgsRasterSymbolLegendNode : public QgsLayerTreeModelLegendNode
383414

384415
QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const override;
385416

417+
void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const override;
418+
386419
private:
387420
QColor mColor;
388421
QString mLabel;
@@ -413,6 +446,8 @@ class CORE_EXPORT QgsWmsLegendNode : public QgsLayerTreeModelLegendNode
413446

414447
QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const override;
415448

449+
void exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const override;
450+
416451
void invalidateMapBasedData() override;
417452

418453
private slots:

‎src/core/qgslegendrenderer.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "qgsvectorlayer.h"
2626
#include "qgsexpressioncontextutils.h"
2727

28+
#include <QJsonObject>
2829
#include <QPainter>
2930

3031

@@ -45,6 +46,77 @@ void QgsLegendRenderer::drawLegend( QPainter *painter )
4546
paintAndDetermineSize( painter );
4647
}
4748

49+
void QgsLegendRenderer::exportLegendToJson( const QgsRenderContext &context, QJsonObject &json )
50+
{
51+
QgsLayerTreeGroup *rootGroup = mLegendModel->rootGroup();
52+
if ( !rootGroup )
53+
return;
54+
55+
json["title"] = mSettings.title();
56+
exportLegendToJson( context, rootGroup, json );
57+
}
58+
59+
void QgsLegendRenderer::exportLegendToJson( const QgsRenderContext &context, QgsLayerTreeGroup *nodeGroup, QJsonObject &json )
60+
{
61+
QJsonArray nodes;
62+
for ( auto node : nodeGroup->children() )
63+
{
64+
if ( QgsLayerTree::isGroup( node ) )
65+
{
66+
QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );
67+
const QModelIndex idx = mLegendModel->node2index( nodeGroup );
68+
const QString text = mLegendModel->data( idx, Qt::DisplayRole ).toString();
69+
70+
QJsonObject group;
71+
group[ "type" ] = "group";
72+
group[ "title" ] = text;
73+
exportLegendToJson( context, nodeGroup, group );
74+
nodes.append( group );
75+
}
76+
else if ( QgsLayerTree::isLayer( node ) )
77+
{
78+
QJsonObject group;
79+
group[ "type" ] = "layer";
80+
81+
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
82+
83+
QString text;
84+
if ( nodeLegendStyle( nodeLayer ) != QgsLegendStyle::Hidden )
85+
{
86+
const QModelIndex idx = mLegendModel->node2index( nodeLayer );
87+
text = mLegendModel->data( idx, Qt::DisplayRole ).toString();
88+
}
89+
90+
QList<QgsLayerTreeModelLegendNode *> legendNodes = mLegendModel->layerLegendNodes( nodeLayer );
91+
92+
if ( legendNodes.isEmpty() && mLegendModel->legendFilterMapSettings() )
93+
continue;
94+
95+
if ( legendNodes.count() == 1 )
96+
{
97+
legendNodes.at( 0 )->exportToJson( mSettings, context, group );
98+
nodes.append( group );
99+
}
100+
else if ( legendNodes.count() > 1 )
101+
{
102+
QJsonArray symbols;
103+
for ( int j = 0; j < legendNodes.count(); j++ )
104+
{
105+
QgsLayerTreeModelLegendNode *legendNode = legendNodes.at( j );
106+
QJsonObject symbol;
107+
legendNode->exportToJson( mSettings, context, symbol );
108+
symbols.append( symbol );
109+
}
110+
group[ "title" ] = text;
111+
group[ "symbols" ] = symbols;
112+
nodes.append( group );
113+
}
114+
}
115+
}
116+
117+
json["nodes"] = nodes;
118+
}
119+
48120
QSizeF QgsLegendRenderer::paintAndDetermineSize( QPainter *painter )
49121
{
50122
return paintAndDetermineSizeInternal( nullptr, painter );

‎src/core/qgslegendrenderer.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
class QRectF;
2323
class QStandardItem;
24+
class QJsonObject;
2425

2526
class QgsLayerTreeGroup;
2627
class QgsLayerTreeLayer;
@@ -92,6 +93,13 @@ class CORE_EXPORT QgsLegendRenderer
9293
*/
9394
void drawLegend( QgsRenderContext &context );
9495

96+
/**
97+
* Renders the legend in a \a json object.
98+
*
99+
* \since QGIS 3.8
100+
*/
101+
void exportLegendToJson( const QgsRenderContext &context, QJsonObject &json );
102+
95103
/**
96104
* Sets the \a style of a \a node.
97105
*
@@ -232,6 +240,13 @@ class CORE_EXPORT QgsLegendRenderer
232240
*/
233241
QSizeF drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QPainter *painter = nullptr, QPointF point = QPointF() );
234242

243+
/**
244+
* Renders a group item in a \a json object.
245+
*
246+
* \since QGIS 3.8
247+
*/
248+
void exportLegendToJson( const QgsRenderContext &context, QgsLayerTreeGroup *nodeGroup, QJsonObject &json );
249+
235250
/**
236251
* Draws the legend using the specified render \a context, and returns the actual size of the legend.
237252
*

‎tests/src/core/testqgslegendrenderer.cpp

Lines changed: 168 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ static void _setStandardTestFont( QgsLegendSettings &settings, const QString &st
5656
}
5757
}
5858

59+
static QImage _base64ToImage( const QString &base64 )
60+
{
61+
const QByteArray bytearray = QByteArray::fromBase64( base64.toStdString().c_str() );
62+
return QImage::fromData( bytearray, "PNG" );
63+
}
64+
5965
static void _renderLegend( const QString &testName, QgsLayerTreeModel *legendModel, QgsLegendSettings &settings )
6066
{
6167
settings.setTitle( QStringLiteral( "Legend" ) );
@@ -77,14 +83,24 @@ static void _renderLegend( const QString &testName, QgsLayerTreeModel *legendMod
7783
img.save( _fileNameForTest( testName ) );
7884
}
7985

80-
static bool _verifyImage( const QString &testName, QString &report )
86+
static QJsonObject _renderJsonLegend( QgsLayerTreeModel *legendModel, const QgsLegendSettings &settings )
87+
{
88+
QgsLegendRenderer legendRenderer( legendModel, settings );
89+
90+
QJsonObject json;
91+
QgsRenderContext context;
92+
legendRenderer.exportLegendToJson( context, json );
93+
return json;
94+
}
95+
96+
static bool _verifyImage( const QString &testName, QString &report, int diff = 500 )
8197
{
8298
QgsRenderChecker checker;
8399
checker.setControlPathPrefix( QStringLiteral( "legend" ) );
84100
checker.setControlName( "expected_" + testName );
85101
checker.setRenderedImage( _fileNameForTest( testName ) );
86102
checker.setSizeTolerance( 3, 3 );
87-
bool equal = checker.compareImages( testName, 500 );
103+
bool equal = checker.compareImages( testName, diff );
88104
report += checker.report();
89105
return equal;
90106
}
@@ -125,6 +141,10 @@ class TestQgsLegendRenderer : public QObject
125141
void testDataDefinedSizeCollapsed();
126142
void testTextOnSymbol();
127143

144+
void testBasicJson();
145+
void testOpacityJson();
146+
void testBigMarkerJson();
147+
128148
private:
129149
QgsLayerTree *mRoot = nullptr;
130150
QgsVectorLayer *mVL1 = nullptr ; // line
@@ -829,6 +849,152 @@ void TestQgsLegendRenderer::testTextOnSymbol()
829849
delete root;
830850
}
831851

852+
void TestQgsLegendRenderer::testBasicJson()
853+
{
854+
QgsLayerTreeModel legendModel( mRoot );
855+
856+
QgsLegendSettings settings;
857+
settings.setTitle( QStringLiteral( "Legend" ) );
858+
_setStandardTestFont( settings );
859+
const QJsonObject json = _renderJsonLegend( &legendModel, settings );
860+
861+
QCOMPARE( json[ "title" ].toString(), QString( "Legend" ) );
862+
863+
const QJsonArray root = json["nodes"].toArray();
864+
865+
const QJsonObject grp1 = root[0].toObject();
866+
QCOMPARE( grp1["title"].toString(), QString( "Line + Polygon" ) );
867+
QCOMPARE( grp1["type"].toString(), QString( "group" ) );
868+
869+
const QJsonArray grp1_nodes = grp1["nodes"].toArray();
870+
871+
const QJsonObject line_layer = grp1_nodes[0].toObject();
872+
QCOMPARE( line_layer["title"].toString(), QString( "Line Layer" ) );
873+
QCOMPARE( line_layer["type"].toString(), QString( "layer" ) );
874+
const QImage line_layer_icon = _base64ToImage( line_layer["icon"].toString() );
875+
QString test_name = "line_layer_icon";
876+
line_layer_icon.save( _fileNameForTest( test_name ) );
877+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
878+
879+
const QJsonObject polygon_layer = grp1_nodes[1].toObject();
880+
QCOMPARE( polygon_layer["title"].toString(), QString( "Polygon Layer" ) );
881+
QCOMPARE( polygon_layer["type"].toString(), QString( "layer" ) );
882+
const QImage polygon_layer_icon = _base64ToImage( polygon_layer["icon"].toString() );
883+
test_name = "polygon_layer_icon";
884+
polygon_layer_icon.save( _fileNameForTest( test_name ) );
885+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
886+
887+
const QJsonObject point_layer = root[1].toObject();
888+
QCOMPARE( point_layer["title"].toString(), QString( "Point Layer" ) );
889+
QCOMPARE( point_layer["type"].toString(), QString( "layer" ) );
890+
const QJsonArray point_layer_symbols = point_layer["symbols"].toArray();
891+
892+
const QJsonObject point_layer_symbol_red = point_layer_symbols[0].toObject();
893+
QCOMPARE( point_layer_symbol_red["title"].toString(), QString( "Red" ) );
894+
const QImage point_layer_icon_red = _base64ToImage( point_layer_symbol_red["icon"].toString() );
895+
test_name = "point_layer_icon_red";
896+
point_layer_icon_red.save( _fileNameForTest( test_name ) );
897+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
898+
899+
const QJsonObject point_layer_symbol_green = point_layer_symbols[1].toObject();
900+
QCOMPARE( point_layer_symbol_green["title"].toString(), QString( "Green" ) );
901+
const QImage point_layer_icon_green = _base64ToImage( point_layer_symbol_green["icon"].toString() );
902+
test_name = "point_layer_icon_green";
903+
point_layer_icon_green.save( _fileNameForTest( test_name ) );
904+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
905+
906+
const QJsonObject point_layer_symbol_blue = point_layer_symbols[2].toObject();
907+
QCOMPARE( point_layer_symbol_blue["title"].toString(), QString( "Blue" ) );
908+
const QImage point_layer_icon_blue = _base64ToImage( point_layer_symbol_blue["icon"].toString() );
909+
test_name = "point_layer_icon_blue";
910+
point_layer_icon_blue.save( _fileNameForTest( test_name ) );
911+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
912+
913+
const QJsonObject raster_layer = root[2].toObject();
914+
QCOMPARE( raster_layer["title"].toString(), QString( "Raster Layer" ) );
915+
QCOMPARE( raster_layer["type"].toString(), QString( "layer" ) );
916+
const QJsonArray raster_layer_symbols = raster_layer["symbols"].toArray();
917+
918+
const QJsonObject raster_layer_symbol_1 = raster_layer_symbols[0].toObject();
919+
QCOMPARE( raster_layer_symbol_1["title"].toString(), QString( "1" ) );
920+
const QImage raster_layer_icon_1 = _base64ToImage( raster_layer_symbol_1["icon"].toString() );
921+
test_name = "raster_layer_icon_1";
922+
raster_layer_icon_1.save( _fileNameForTest( test_name ) );
923+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
924+
925+
const QJsonObject raster_layer_symbol_2 = raster_layer_symbols[1].toObject();
926+
QCOMPARE( raster_layer_symbol_2["title"].toString(), QString( "2" ) );
927+
const QImage raster_layer_icon_2 = _base64ToImage( raster_layer_symbol_2["icon"].toString() );
928+
test_name = "raster_layer_icon_2";
929+
raster_layer_icon_2.save( _fileNameForTest( test_name ) );
930+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
931+
}
932+
933+
void TestQgsLegendRenderer::testOpacityJson()
934+
{
935+
const int opacity = mVL3->opacity();
936+
mVL3->setOpacity( 0.5 );
937+
QgsLayerTreeModel legendModel( mRoot );
938+
939+
QgsLegendSettings settings;
940+
settings.setTitle( QStringLiteral( "Legend" ) );
941+
_setStandardTestFont( settings );
942+
const QJsonObject json = _renderJsonLegend( &legendModel, settings );
943+
944+
const QJsonArray root = json["nodes"].toArray();
945+
946+
const QJsonObject point_layer = root[1].toObject();
947+
const QJsonArray point_layer_symbols = point_layer["symbols"].toArray();
948+
949+
const QJsonObject point_layer_symbol_red = point_layer_symbols[0].toObject();
950+
const QImage point_layer_icon_red = _base64ToImage( point_layer_symbol_red["icon"].toString() );
951+
QString test_name = "point_layer_icon_red_opacity";
952+
point_layer_icon_red.save( _fileNameForTest( test_name ) );
953+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
954+
955+
const QJsonObject point_layer_symbol_green = point_layer_symbols[1].toObject();
956+
const QImage point_layer_icon_green = _base64ToImage( point_layer_symbol_green["icon"].toString() );
957+
test_name = "point_layer_icon_green_opacity";
958+
point_layer_icon_green.save( _fileNameForTest( test_name ) );
959+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
960+
961+
const QJsonObject point_layer_symbol_blue = point_layer_symbols[2].toObject();
962+
const QImage point_layer_icon_blue = _base64ToImage( point_layer_symbol_blue["icon"].toString() );
963+
test_name = "point_layer_icon_blue_opacity";
964+
point_layer_icon_blue.save( _fileNameForTest( test_name ) );
965+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
966+
967+
mVL3->setOpacity( opacity );
968+
}
969+
970+
void TestQgsLegendRenderer::testBigMarkerJson()
971+
{
972+
QgsMarkerSymbol *sym = new QgsMarkerSymbol();
973+
sym->setColor( Qt::red );
974+
sym->setSize( sym->size() * 6 );
975+
QgsCategorizedSymbolRenderer *catRenderer = dynamic_cast<QgsCategorizedSymbolRenderer *>( mVL3->renderer() );
976+
QVERIFY( catRenderer );
977+
catRenderer->updateCategorySymbol( 0, sym );
978+
979+
QgsLayerTreeModel legendModel( mRoot );
980+
981+
QgsLegendSettings settings;
982+
settings.setTitle( QStringLiteral( "Legend" ) );
983+
_setStandardTestFont( settings );
984+
const QJsonObject json = _renderJsonLegend( &legendModel, settings );
985+
986+
const QJsonArray root = json["nodes"].toArray();
987+
988+
const QJsonObject point_layer = root[1].toObject();
989+
const QJsonArray point_layer_symbols = point_layer["symbols"].toArray();
990+
991+
const QJsonObject point_layer_symbol_red = point_layer_symbols[0].toObject();
992+
const QImage point_layer_icon_red = _base64ToImage( point_layer_symbol_red["icon"].toString() );
993+
QString test_name = "point_layer_icon_red_big";
994+
point_layer_icon_red.save( _fileNameForTest( test_name ) );
995+
QVERIFY( _verifyImage( test_name, mReport, 50 ) );
996+
}
997+
832998

833999
QGSTEST_MAIN( TestQgsLegendRenderer )
8341000
#include "testqgslegendrenderer.moc"
105 Bytes

Error rendering embedded code

Invalid image source.

299 Bytes

Error rendering embedded code

Invalid image source.

Error rendering embedded code

Invalid image source.

303 Bytes

Error rendering embedded code

Invalid image source.

Loading
305 Bytes

Error rendering embedded code

Invalid image source.

1.3 KB

Error rendering embedded code

Invalid image source.

302 Bytes

Error rendering embedded code

Invalid image source.

144 Bytes

Error rendering embedded code

Invalid image source.

99 Bytes

Error rendering embedded code

Invalid image source.

126 Bytes

Error rendering embedded code

Invalid image source.

0 commit comments

Comments
 (0)
Please sign in to comment.