From 991f9359449463a23e23e2557d407abb57f2cbe7 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Fri, 25 Jun 2021 15:21:29 +0200 Subject: [PATCH 1/8] Feature: possibility to use placeholder icon in legend for raster layer --- .../raster/qgsrasterlayer.sip.in | 12 ++++++ src/core/qgsmaplayerlegend.cpp | 8 +++- src/core/raster/qgsrasterlayer.cpp | 4 ++ src/core/raster/qgsrasterlayer.h | 11 +++++ src/gui/raster/qgsrasterlayerproperties.cpp | 2 + src/ui/qgsrasterlayerpropertiesbase.ui | 41 ++++++++----------- 6 files changed, 53 insertions(+), 25 deletions(-) diff --git a/python/core/auto_generated/raster/qgsrasterlayer.sip.in b/python/core/auto_generated/raster/qgsrasterlayer.sip.in index e0338306453..f3a7bed55c3 100644 --- a/python/core/auto_generated/raster/qgsrasterlayer.sip.in +++ b/python/core/auto_generated/raster/qgsrasterlayer.sip.in @@ -420,6 +420,18 @@ to be drawn outside the data extent. virtual QgsMapLayerTemporalProperties *temporalProperties(); + bool usePlaceholderLegendIcon() const; +%Docstring +True if a placeholder legend is shown in the legend rather than all the color entries +%End + + void setUsePlaceholderLegendIcon( bool usePlaceholderIcon ); +%Docstring +Set if a placeholder legend is shown in the legend + +:param usePlaceholderIcon: true if placeholder icon will be shown instead of symbology items +%End + public slots: void showStatusMessage( const QString &message ); diff --git a/src/core/qgsmaplayerlegend.cpp b/src/core/qgsmaplayerlegend.cpp index c633484a657..3ee181faf36 100644 --- a/src/core/qgsmaplayerlegend.cpp +++ b/src/core/qgsmaplayerlegend.cpp @@ -14,7 +14,7 @@ ***************************************************************************/ #include "qgsmaplayerlegend.h" - +#include "qgsiconutils.h" #include "qgssettings.h" #include "qgslayertree.h" #include "qgslayertreemodellegendnode.h" @@ -502,7 +502,11 @@ QList QgsDefaultRasterLayerLegend::createLayerTre nodes << new QgsWmsLegendNode( nodeLayer ); } - if ( mLayer->renderer() ) + if ( mLayer->usePlaceholderLegendIcon() ) + { + nodes << new QgsSimpleLegendNode( nodeLayer, QString(), QgsIconUtils::iconRaster() ); + } + else if ( mLayer->renderer() ) nodes.append( mLayer->renderer()->createLegendNodes( nodeLayer ) ); return nodes; } diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index 81dbdfdb734..3c4a08f3119 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -2163,6 +2163,8 @@ bool QgsRasterLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c readStyleManager( layer_node ); + mUsePlaceholderLegendIcon = layer_node.toElement().attribute( QStringLiteral( "usePlaceholderLegendIcon" ), QStringLiteral( "0" ) ).compare( QStringLiteral( "1" ) ) == 0; + return res; } @@ -2278,6 +2280,8 @@ bool QgsRasterLayer::writeXml( QDomNode &layer_node, writeStyleManager( layer_node, document ); + mapLayerNode.setAttribute( QStringLiteral( "usePlaceholderLegendIcon" ), mUsePlaceholderLegendIcon ); + //write out the symbology QString errorMsg; return writeSymbology( layer_node, document, errorMsg, context ); diff --git a/src/core/raster/qgsrasterlayer.h b/src/core/raster/qgsrasterlayer.h index a5bf35ecc5b..bb6fffa507e 100644 --- a/src/core/raster/qgsrasterlayer.h +++ b/src/core/raster/qgsrasterlayer.h @@ -467,6 +467,15 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer QgsMapLayerTemporalProperties *temporalProperties() override; + //! True if a placeholder legend is shown in the legend rather than all the color entries + bool usePlaceholderLegendIcon() const { return mUsePlaceholderLegendIcon; } + + /** + * Set if a placeholder legend is shown in the legend + * \param usePlaceholderIcon true if placeholder icon will be shown instead of symbology items + */ + void setUsePlaceholderLegendIcon( bool usePlaceholderIcon ) { mUsePlaceholderLegendIcon = usePlaceholderIcon; } + public slots: void showStatusMessage( const QString &message ); @@ -565,6 +574,8 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer QDomDocument mOriginalStyleDocument; QDomElement mOriginalStyleElement; + + bool mUsePlaceholderLegendIcon = false; }; // clazy:excludeall=qstring-allocations diff --git a/src/gui/raster/qgsrasterlayerproperties.cpp b/src/gui/raster/qgsrasterlayerproperties.cpp index 01e4d3270c9..7aa2e040d33 100644 --- a/src/gui/raster/qgsrasterlayerproperties.cpp +++ b/src/gui/raster/qgsrasterlayerproperties.cpp @@ -914,6 +914,7 @@ void QgsRasterLayerProperties::sync() QVariant wmsBackgroundLayer = mRasterLayer->customProperty( QStringLiteral( "WMSBackgroundLayer" ), false ); mBackgroundLayerCheckBox->setChecked( wmsBackgroundLayer.toBool() ); + mPlaceholderIconCheckBox->setCheckState( mRasterLayer->usePlaceholderLegendIcon() ? Qt::Checked : Qt::Unchecked ); mLegendConfigEmbeddedWidget->setLayer( mRasterLayer ); mTemporalWidget->syncToLayer(); @@ -946,6 +947,7 @@ void QgsRasterLayerProperties::apply() /* * Legend Tab */ + mRasterLayer->setUsePlaceholderLegendIcon( mPlaceholderIconCheckBox->isChecked() ); mLegendConfigEmbeddedWidget->applyToLayer(); QgsDebugMsgLevel( QStringLiteral( "apply processing symbology tab" ), 3 ); diff --git a/src/ui/qgsrasterlayerpropertiesbase.ui b/src/ui/qgsrasterlayerpropertiesbase.ui index 94769bff22f..00561bc7936 100644 --- a/src/ui/qgsrasterlayerpropertiesbase.ui +++ b/src/ui/qgsrasterlayerpropertiesbase.ui @@ -254,7 +254,7 @@ - 1 + 0 @@ -299,8 +299,8 @@ 0 0 - 643 - 679 + 650 + 673 @@ -1563,8 +1563,8 @@ border-radius: 2px; 0 0 - 577 - 190 + 650 + 673 @@ -1633,8 +1633,8 @@ border-radius: 2px; <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Fira Sans'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell';"><br /></span></p></body></html> +</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Cantarell'; font-size:11pt;"><br /></span></p></body></html> @@ -1739,20 +1739,15 @@ p, li { white-space: pre-wrap; } - - - 0 - - - 0 - - - 0 - - - 0 - - + + + + + Show placeholder icon in legend + + + + Embedded Widgets in Legend @@ -1793,8 +1788,8 @@ p, li { white-space: pre-wrap; } 0 0 - 343 - 684 + 394 + 793 From b7b9470a684ed4e35be70e7862bebb4a113e2384 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Tue, 29 Jun 2021 11:30:22 +0200 Subject: [PATCH 2/8] Possibility to select an image as legend placeholder --- python/core/auto_generated/qgsmaplayer.sip.in | 16 +++++++ .../raster/qgsrasterlayer.sip.in | 12 ----- src/core/qgsmaplayer.cpp | 4 ++ src/core/qgsmaplayer.h | 16 +++++++ src/core/qgsmaplayerlegend.cpp | 5 ++- src/core/raster/qgsrasterlayer.cpp | 4 -- src/core/raster/qgsrasterlayer.h | 11 ----- src/gui/raster/qgsrasterlayerproperties.cpp | 16 ++++++- src/gui/raster/qgsrasterlayerproperties.h | 2 + src/ui/qgsrasterlayerpropertiesbase.ui | 44 +++++++++++++++---- 10 files changed, 91 insertions(+), 39 deletions(-) diff --git a/python/core/auto_generated/qgsmaplayer.sip.in b/python/core/auto_generated/qgsmaplayer.sip.in index 42c7685244b..2c640567f17 100644 --- a/python/core/auto_generated/qgsmaplayer.sip.in +++ b/python/core/auto_generated/qgsmaplayer.sip.in @@ -1429,6 +1429,22 @@ Returns the layer's temporal properties. This may be ``None``, depending on the Returns the layer's elevation properties. This may be ``None``, depending on the layer type. .. versionadded:: 3.18 +%End + + QString legendPlaceholderImage() const; +%Docstring +Returns path to the placeholder image or an empty string if a generated legend is shown + +:return: placholder image path +%End + + void setLegendPlaceholderImage( const QString &imgPath ); +%Docstring +Set placeholder image for legend. If the string is empty, a generated legend will be shown. + +:param imgPath: file path to the placeholder image + +.. versionadded:: 3.22 %End public slots: diff --git a/python/core/auto_generated/raster/qgsrasterlayer.sip.in b/python/core/auto_generated/raster/qgsrasterlayer.sip.in index f3a7bed55c3..e0338306453 100644 --- a/python/core/auto_generated/raster/qgsrasterlayer.sip.in +++ b/python/core/auto_generated/raster/qgsrasterlayer.sip.in @@ -420,18 +420,6 @@ to be drawn outside the data extent. virtual QgsMapLayerTemporalProperties *temporalProperties(); - bool usePlaceholderLegendIcon() const; -%Docstring -True if a placeholder legend is shown in the legend rather than all the color entries -%End - - void setUsePlaceholderLegendIcon( bool usePlaceholderIcon ); -%Docstring -Set if a placeholder legend is shown in the legend - -:param usePlaceholderIcon: true if placeholder icon will be shown instead of symbology items -%End - public slots: void showStatusMessage( const QString &message ); diff --git a/src/core/qgsmaplayer.cpp b/src/core/qgsmaplayer.cpp index 9e77be0826e..4f789807dd4 100644 --- a/src/core/qgsmaplayer.cpp +++ b/src/core/qgsmaplayer.cpp @@ -406,6 +406,8 @@ bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteCon mWgs84Extent = QgsXmlUtils::readRectangle( wgs84ExtentNode.toElement() ); } + mLegendPlaceholderImage = layerElement.attribute( QStringLiteral( "legendPlaceholderImage" ) ); + return ! layerError; } // bool QgsMapLayer::readLayerXML @@ -576,6 +578,8 @@ bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &docume mMetadata.writeMetadataXml( myMetadataElem, document ); layerElement.appendChild( myMetadataElem ); + layerElement.setAttribute( QStringLiteral( "legendPlaceholderImage" ), mLegendPlaceholderImage ); + // now append layer node to map layer node return writeXml( layerElement, document, context ); } diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h index 7e02738b15b..b39bfcc158c 100644 --- a/src/core/qgsmaplayer.h +++ b/src/core/qgsmaplayer.h @@ -1279,6 +1279,19 @@ class CORE_EXPORT QgsMapLayer : public QObject */ virtual QgsMapLayerElevationProperties *elevationProperties() { return nullptr; } + /** + * Returns path to the placeholder image or an empty string if a generated legend is shown + * \return placholder image path + */ + QString legendPlaceholderImage() const { return mLegendPlaceholderImage;} + + /** + * Set placeholder image for legend. If the string is empty, a generated legend will be shown. + * \param imgPath file path to the placeholder image + * \since QGIS 3.22 + */ + void setLegendPlaceholderImage( const QString &imgPath ) { mLegendPlaceholderImage = imgPath; } + public slots: /** @@ -1867,6 +1880,9 @@ class CORE_EXPORT QgsMapLayer : public QObject //! To avoid firing multiple time repaintRequested signal on circular layer circular dependencies bool mRepaintRequestedFired = false; + //! Path to placeholder image for layer legend. If the string is empty, a generated legend is shown + QString mLegendPlaceholderImage; + friend class QgsVectorLayer; }; diff --git a/src/core/qgsmaplayerlegend.cpp b/src/core/qgsmaplayerlegend.cpp index 3ee181faf36..65b3c0666d5 100644 --- a/src/core/qgsmaplayerlegend.cpp +++ b/src/core/qgsmaplayerlegend.cpp @@ -502,9 +502,10 @@ QList QgsDefaultRasterLayerLegend::createLayerTre nodes << new QgsWmsLegendNode( nodeLayer ); } - if ( mLayer->usePlaceholderLegendIcon() ) + QString placeholderImage = mLayer->legendPlaceholderImage(); + if ( !placeholderImage.isEmpty() ) { - nodes << new QgsSimpleLegendNode( nodeLayer, QString(), QgsIconUtils::iconRaster() ); + nodes << new QgsImageLegendNode( nodeLayer, QImage( placeholderImage ) ); } else if ( mLayer->renderer() ) nodes.append( mLayer->renderer()->createLegendNodes( nodeLayer ) ); diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index 3c4a08f3119..81dbdfdb734 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -2163,8 +2163,6 @@ bool QgsRasterLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c readStyleManager( layer_node ); - mUsePlaceholderLegendIcon = layer_node.toElement().attribute( QStringLiteral( "usePlaceholderLegendIcon" ), QStringLiteral( "0" ) ).compare( QStringLiteral( "1" ) ) == 0; - return res; } @@ -2280,8 +2278,6 @@ bool QgsRasterLayer::writeXml( QDomNode &layer_node, writeStyleManager( layer_node, document ); - mapLayerNode.setAttribute( QStringLiteral( "usePlaceholderLegendIcon" ), mUsePlaceholderLegendIcon ); - //write out the symbology QString errorMsg; return writeSymbology( layer_node, document, errorMsg, context ); diff --git a/src/core/raster/qgsrasterlayer.h b/src/core/raster/qgsrasterlayer.h index bb6fffa507e..a5bf35ecc5b 100644 --- a/src/core/raster/qgsrasterlayer.h +++ b/src/core/raster/qgsrasterlayer.h @@ -467,15 +467,6 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer QgsMapLayerTemporalProperties *temporalProperties() override; - //! True if a placeholder legend is shown in the legend rather than all the color entries - bool usePlaceholderLegendIcon() const { return mUsePlaceholderLegendIcon; } - - /** - * Set if a placeholder legend is shown in the legend - * \param usePlaceholderIcon true if placeholder icon will be shown instead of symbology items - */ - void setUsePlaceholderLegendIcon( bool usePlaceholderIcon ) { mUsePlaceholderLegendIcon = usePlaceholderIcon; } - public slots: void showStatusMessage( const QString &message ); @@ -574,8 +565,6 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer QDomDocument mOriginalStyleDocument; QDomElement mOriginalStyleElement; - - bool mUsePlaceholderLegendIcon = false; }; // clazy:excludeall=qstring-allocations diff --git a/src/gui/raster/qgsrasterlayerproperties.cpp b/src/gui/raster/qgsrasterlayerproperties.cpp index 7aa2e040d33..ff789c3f1f2 100644 --- a/src/gui/raster/qgsrasterlayerproperties.cpp +++ b/src/gui/raster/qgsrasterlayerproperties.cpp @@ -914,7 +914,7 @@ void QgsRasterLayerProperties::sync() QVariant wmsBackgroundLayer = mRasterLayer->customProperty( QStringLiteral( "WMSBackgroundLayer" ), false ); mBackgroundLayerCheckBox->setChecked( wmsBackgroundLayer.toBool() ); - mPlaceholderIconCheckBox->setCheckState( mRasterLayer->usePlaceholderLegendIcon() ? Qt::Checked : Qt::Unchecked ); + mLegendPlaceholderLineEdit->setText( mRasterLayer->legendPlaceholderImage() ); mLegendConfigEmbeddedWidget->setLayer( mRasterLayer ); mTemporalWidget->syncToLayer(); @@ -947,7 +947,7 @@ void QgsRasterLayerProperties::apply() /* * Legend Tab */ - mRasterLayer->setUsePlaceholderLegendIcon( mPlaceholderIconCheckBox->isChecked() ); + mRasterLayer->setLegendPlaceholderImage( mLegendPlaceholderLineEdit->text() ); mLegendConfigEmbeddedWidget->applyToLayer(); QgsDebugMsgLevel( QStringLiteral( "apply processing symbology tab" ), 3 ); @@ -1277,6 +1277,18 @@ void QgsRasterLayerProperties::urlClicked( const QUrl &url ) QDesktopServices::openUrl( url ); } +void QgsRasterLayerProperties::on_mLegendPlaceholderToolButton_clicked() +{ + QgsSettings myQSettings; + QString myLastDir = myQSettings.value( QStringLiteral( "lastPlaceholderDir" ), QDir::homePath() ).toString(); + QString myFileName = QFileDialog::getOpenFileName( this, tr( "Open file" ), myLastDir ); + if ( !myFileName.isEmpty() ) + { + mLegendPlaceholderLineEdit->setText( myFileName ); + myQSettings.setValue( QStringLiteral( "lastPlaceholderDir" ), QFileInfo( myFileName ).absolutePath() ); + } +} + void QgsRasterLayerProperties::mRenderTypeComboBox_currentIndexChanged( int index ) { if ( index < 0 || mDisableRenderTypeComboBoxCurrentIndexChanged || ! mRasterLayer->renderer() ) diff --git a/src/gui/raster/qgsrasterlayerproperties.h b/src/gui/raster/qgsrasterlayerproperties.h index abe9e1368d6..fb294bef77e 100644 --- a/src/gui/raster/qgsrasterlayerproperties.h +++ b/src/gui/raster/qgsrasterlayerproperties.h @@ -214,6 +214,8 @@ class GUI_EXPORT QgsRasterLayerProperties : public QgsOptionsDialogBase, private void urlClicked( const QUrl &url ); + void on_mLegendPlaceholderToolButton_clicked(); + private: QPushButton *mBtnStyle = nullptr; QPushButton *mBtnMetadata = nullptr; diff --git a/src/ui/qgsrasterlayerpropertiesbase.ui b/src/ui/qgsrasterlayerpropertiesbase.ui index 00561bc7936..0262df1e67a 100644 --- a/src/ui/qgsrasterlayerpropertiesbase.ui +++ b/src/ui/qgsrasterlayerpropertiesbase.ui @@ -1740,15 +1740,14 @@ p, li { white-space: pre-wrap; } - - - - Show placeholder icon in legend - - - + + + 0 + 0 + + Embedded Widgets in Legend @@ -1759,6 +1758,35 @@ p, li { white-space: pre-wrap; } + + + + + 0 + 0 + + + + Legend placeholder image + + + + + + + + + + + ... + + + + + + + + @@ -1788,7 +1816,7 @@ p, li { white-space: pre-wrap; } 0 0 - 394 + 629 793 From 6effd6bd753427e4e32c16e85d1f9da3fb84ad3c Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Tue, 29 Jun 2021 15:53:43 +0200 Subject: [PATCH 3/8] Use QgsImageSourceLineEdit and allow placeholder images also for vector layers --- src/core/qgsmaplayerlegend.cpp | 19 +++++++- src/gui/raster/qgsrasterlayerproperties.cpp | 17 ++----- src/gui/raster/qgsrasterlayerproperties.h | 2 - src/gui/vector/qgsvectorlayerlegendwidget.cpp | 17 ++++++- src/gui/vector/qgsvectorlayerlegendwidget.h | 3 ++ src/ui/qgsrasterlayerpropertiesbase.ui | 48 +++++++++---------- 6 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/core/qgsmaplayerlegend.cpp b/src/core/qgsmaplayerlegend.cpp index 65b3c0666d5..d95251d2a61 100644 --- a/src/core/qgsmaplayerlegend.cpp +++ b/src/core/qgsmaplayerlegend.cpp @@ -15,6 +15,7 @@ #include "qgsmaplayerlegend.h" #include "qgsiconutils.h" +#include "qgsimagecache.h" #include "qgssettings.h" #include "qgslayertree.h" #include "qgslayertreemodellegendnode.h" @@ -359,6 +360,19 @@ QList QgsDefaultVectorLayerLegend::createLayerTre { QList nodes; + if ( mLayer ) + { + QString placeholderImage = mLayer->legendPlaceholderImage(); + if ( !placeholderImage.isEmpty() ) + { + QgsImageCache ic; + bool fitsInCache; + QImage img = ic.pathAsImage( placeholderImage, QSize(), false, 1.0, fitsInCache ); + nodes << new QgsImageLegendNode( nodeLayer, img ); + return nodes; + } + } + QgsFeatureRenderer *r = mLayer->renderer(); if ( !r ) return nodes; @@ -505,7 +519,10 @@ QList QgsDefaultRasterLayerLegend::createLayerTre QString placeholderImage = mLayer->legendPlaceholderImage(); if ( !placeholderImage.isEmpty() ) { - nodes << new QgsImageLegendNode( nodeLayer, QImage( placeholderImage ) ); + QgsImageCache ic; + bool fitsInCache; + QImage img = ic.pathAsImage( placeholderImage, QSize(), false, 1.0, fitsInCache ); + nodes << new QgsImageLegendNode( nodeLayer, img ); } else if ( mLayer->renderer() ) nodes.append( mLayer->renderer()->createLegendNodes( nodeLayer ) ); diff --git a/src/gui/raster/qgsrasterlayerproperties.cpp b/src/gui/raster/qgsrasterlayerproperties.cpp index ff789c3f1f2..71443ed0f50 100644 --- a/src/gui/raster/qgsrasterlayerproperties.cpp +++ b/src/gui/raster/qgsrasterlayerproperties.cpp @@ -914,7 +914,8 @@ void QgsRasterLayerProperties::sync() QVariant wmsBackgroundLayer = mRasterLayer->customProperty( QStringLiteral( "WMSBackgroundLayer" ), false ); mBackgroundLayerCheckBox->setChecked( wmsBackgroundLayer.toBool() ); - mLegendPlaceholderLineEdit->setText( mRasterLayer->legendPlaceholderImage() ); + mLegendPlaceholderWidget->setLastPathSettingsKey( QStringLiteral( "lastLegendPlaceholderDir" ) ); + mLegendPlaceholderWidget->setSource( mRasterLayer->legendPlaceholderImage() ); mLegendConfigEmbeddedWidget->setLayer( mRasterLayer ); mTemporalWidget->syncToLayer(); @@ -947,7 +948,7 @@ void QgsRasterLayerProperties::apply() /* * Legend Tab */ - mRasterLayer->setLegendPlaceholderImage( mLegendPlaceholderLineEdit->text() ); + mRasterLayer->setLegendPlaceholderImage( mLegendPlaceholderWidget->source() ); mLegendConfigEmbeddedWidget->applyToLayer(); QgsDebugMsgLevel( QStringLiteral( "apply processing symbology tab" ), 3 ); @@ -1277,18 +1278,6 @@ void QgsRasterLayerProperties::urlClicked( const QUrl &url ) QDesktopServices::openUrl( url ); } -void QgsRasterLayerProperties::on_mLegendPlaceholderToolButton_clicked() -{ - QgsSettings myQSettings; - QString myLastDir = myQSettings.value( QStringLiteral( "lastPlaceholderDir" ), QDir::homePath() ).toString(); - QString myFileName = QFileDialog::getOpenFileName( this, tr( "Open file" ), myLastDir ); - if ( !myFileName.isEmpty() ) - { - mLegendPlaceholderLineEdit->setText( myFileName ); - myQSettings.setValue( QStringLiteral( "lastPlaceholderDir" ), QFileInfo( myFileName ).absolutePath() ); - } -} - void QgsRasterLayerProperties::mRenderTypeComboBox_currentIndexChanged( int index ) { if ( index < 0 || mDisableRenderTypeComboBoxCurrentIndexChanged || ! mRasterLayer->renderer() ) diff --git a/src/gui/raster/qgsrasterlayerproperties.h b/src/gui/raster/qgsrasterlayerproperties.h index fb294bef77e..abe9e1368d6 100644 --- a/src/gui/raster/qgsrasterlayerproperties.h +++ b/src/gui/raster/qgsrasterlayerproperties.h @@ -214,8 +214,6 @@ class GUI_EXPORT QgsRasterLayerProperties : public QgsOptionsDialogBase, private void urlClicked( const QUrl &url ); - void on_mLegendPlaceholderToolButton_clicked(); - private: QPushButton *mBtnStyle = nullptr; QPushButton *mBtnMetadata = nullptr; diff --git a/src/gui/vector/qgsvectorlayerlegendwidget.cpp b/src/gui/vector/qgsvectorlayerlegendwidget.cpp index af36769acd4..87f2540a86f 100644 --- a/src/gui/vector/qgsvectorlayerlegendwidget.cpp +++ b/src/gui/vector/qgsvectorlayerlegendwidget.cpp @@ -21,6 +21,7 @@ #include #include "qgsexpressionbuilderdialog.h" +#include "qgsfilecontentsourcelineedit.h" #include "qgsmapcanvas.h" #include "qgsmaplayerlegend.h" #include "qgsrenderer.h" @@ -71,10 +72,19 @@ QgsVectorLayerLegendWidget::QgsVectorLayerLegendWidget( QWidget *parent ) labelLegendLayout->addWidget( mLabelLegendTreeWidget ); mLabelLegendGroupBox->setLayout( labelLegendLayout ); + mPlaceholderImageLabel = new QLabel( tr( "Legend placeholder image" ) ); + mImageSourceLineEdit = new QgsImageSourceLineEdit(); + mImageSourceLineEdit->setLastPathSettingsKey( QStringLiteral( "lastLegendPlaceholderDir" ) ); + if ( mLayer ) + { + mImageSourceLineEdit->setSource( mLayer->legendPlaceholderImage() ); + } QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins( 0, 0, 0, 0 ); + layout->addWidget( mPlaceholderImageLabel ); + layout->addWidget( mImageSourceLineEdit ); layout->addWidget( mShowLabelLegendCheckBox ); layout->addWidget( mLabelLegendGroupBox ); layout->addWidget( mTextOnSymbolGroupBox ); @@ -122,7 +132,10 @@ void QgsVectorLayerLegendWidget::setLayer( QgsVectorLayer *layer ) mTextOnSymbolGroupBox->setChecked( legend->textOnSymbolEnabled() ); mTextOnSymbolFormatButton->setTextFormat( legend->textOnSymbolTextFormat() ); populateLegendTreeView( legend->textOnSymbolContent() ); - + if ( mLayer ) + { + mImageSourceLineEdit->setSource( mLayer->legendPlaceholderImage() ); + } } void QgsVectorLayerLegendWidget::populateLabelLegendTreeWidget() @@ -221,6 +234,8 @@ void QgsVectorLayerLegendWidget::applyToLayer() applyLabelLegend(); } + mLayer->setLegendPlaceholderImage( mImageSourceLineEdit->source() ); + mLayer->setLegend( legend ); } diff --git a/src/gui/vector/qgsvectorlayerlegendwidget.h b/src/gui/vector/qgsvectorlayerlegendwidget.h index 2c5518b934e..2fc59d4978f 100644 --- a/src/gui/vector/qgsvectorlayerlegendwidget.h +++ b/src/gui/vector/qgsvectorlayerlegendwidget.h @@ -25,6 +25,7 @@ #include "qgis_gui.h" class QCheckBox; +class QgsImageSourceLineEdit; class QLabel; class QPushButton; class QTreeView; @@ -76,6 +77,8 @@ class GUI_EXPORT QgsVectorLayerLegendWidget : public QWidget QCheckBox *mShowLabelLegendCheckBox = nullptr; QgsCollapsibleGroupBox *mLabelLegendGroupBox = nullptr; QTreeWidget *mLabelLegendTreeWidget = nullptr; + QLabel *mPlaceholderImageLabel = nullptr; + QgsImageSourceLineEdit *mImageSourceLineEdit = nullptr; QgsMapCanvas *mCanvas = nullptr; QgsVectorLayer *mLayer = nullptr; diff --git a/src/ui/qgsrasterlayerpropertiesbase.ui b/src/ui/qgsrasterlayerpropertiesbase.ui index 0262df1e67a..1d615d9143d 100644 --- a/src/ui/qgsrasterlayerpropertiesbase.ui +++ b/src/ui/qgsrasterlayerpropertiesbase.ui @@ -1740,7 +1740,7 @@ p, li { white-space: pre-wrap; } - + @@ -1758,33 +1758,14 @@ p, li { white-space: pre-wrap; } + + + - - - - 0 - 0 - - - + + Legend placeholder image - - - - - - - - - - ... - - - - - - @@ -2338,6 +2319,23 @@ p, li { white-space: pre-wrap; } QComboBox
qgsblendmodecombobox.h
+ + QgsOpacityWidget + QWidget +
qgsopacitywidget.h
+ 1 +
+ + QgsRasterBandComboBox + QComboBox +
qgsrasterbandcombobox.h
+
+ + QgsImageSourceLineEdit + QWidget +
qgsfilecontentsourcelineedit.h
+ 1 +
mSearchLineEdit From d76fa2bf3b233c933f06a7c7271bc780399a4438 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Tue, 29 Jun 2021 16:39:32 +0200 Subject: [PATCH 4/8] Preserve image aspect ratio in legend --- src/core/layertree/qgslayertreemodellegendnode.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index 719a0d89b3d..88dfc937ee5 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -948,17 +948,16 @@ QSizeF QgsImageLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemCo if ( ctx && ctx->painter ) { + QImage scaledImg = mImage.scaled( settings.wmsLegendSize().toSize(), Qt::KeepAspectRatio, Qt::FastTransformation ); switch ( settings.symbolAlignment() ) { case Qt::AlignLeft: default: - ctx->painter->drawImage( QRectF( ctx->columnLeft, ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ), - mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) ); + ctx->painter->drawImage( QPointF( ctx->columnLeft, ctx->top ), scaledImg ); break; case Qt::AlignRight: - ctx->painter->drawImage( QRectF( ctx->columnRight - settings.wmsLegendSize().width(), ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ), - mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) ); + ctx->painter->drawImage( QPointF( ctx->columnRight - settings.wmsLegendSize().width(), ctx->top ), scaledImg ); break; } } From f2878727984d76e55c3881cf5ee728b939a847a9 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Wed, 30 Jun 2021 10:48:52 +0200 Subject: [PATCH 5/8] Use application image cache --- python/core/auto_generated/qgsmaplayer.sip.in | 2 ++ src/core/qgsmaplayer.h | 1 + src/core/qgsmaplayerlegend.cpp | 6 ++---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/python/core/auto_generated/qgsmaplayer.sip.in b/python/core/auto_generated/qgsmaplayer.sip.in index 2c640567f17..bb9b2ed0846 100644 --- a/python/core/auto_generated/qgsmaplayer.sip.in +++ b/python/core/auto_generated/qgsmaplayer.sip.in @@ -1436,6 +1436,8 @@ Returns the layer's elevation properties. This may be ``None``, depending on the Returns path to the placeholder image or an empty string if a generated legend is shown :return: placholder image path + +.. versionadded:: 3.22 %End void setLegendPlaceholderImage( const QString &imgPath ); diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h index b39bfcc158c..c5ac3beb4cd 100644 --- a/src/core/qgsmaplayer.h +++ b/src/core/qgsmaplayer.h @@ -1282,6 +1282,7 @@ class CORE_EXPORT QgsMapLayer : public QObject /** * Returns path to the placeholder image or an empty string if a generated legend is shown * \return placholder image path + * \since QGIS 3.22 */ QString legendPlaceholderImage() const { return mLegendPlaceholderImage;} diff --git a/src/core/qgsmaplayerlegend.cpp b/src/core/qgsmaplayerlegend.cpp index d95251d2a61..1c06baffab9 100644 --- a/src/core/qgsmaplayerlegend.cpp +++ b/src/core/qgsmaplayerlegend.cpp @@ -365,9 +365,8 @@ QList QgsDefaultVectorLayerLegend::createLayerTre QString placeholderImage = mLayer->legendPlaceholderImage(); if ( !placeholderImage.isEmpty() ) { - QgsImageCache ic; bool fitsInCache; - QImage img = ic.pathAsImage( placeholderImage, QSize(), false, 1.0, fitsInCache ); + QImage img = QgsApplication::imageCache()->pathAsImage( placeholderImage, QSize(), false, 1.0, fitsInCache ); nodes << new QgsImageLegendNode( nodeLayer, img ); return nodes; } @@ -519,9 +518,8 @@ QList QgsDefaultRasterLayerLegend::createLayerTre QString placeholderImage = mLayer->legendPlaceholderImage(); if ( !placeholderImage.isEmpty() ) { - QgsImageCache ic; bool fitsInCache; - QImage img = ic.pathAsImage( placeholderImage, QSize(), false, 1.0, fitsInCache ); + QImage img = QgsApplication::imageCache()->pathAsImage( placeholderImage, QSize(), false, 1.0, fitsInCache ); nodes << new QgsImageLegendNode( nodeLayer, img ); } else if ( mLayer->renderer() ) From ccc601b31fe51608f512187f54268fc219799ed2 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Fri, 2 Jul 2021 09:45:34 +0200 Subject: [PATCH 6/8] Fix painter scaling and add unit test --- .../layertree/qgslayertreemodellegendnode.cpp | 13 +- .../test_qgsserver_wms_getlegendgraphic.py | 13 + ...tLegendGraphic_Legend_Placeholder_Icon.png | Bin 0 -> 8897 bytes .../test_project_legend_placeholder_image.qgs | 3257 +++++++++++++++++ 4 files changed, 3279 insertions(+), 4 deletions(-) create mode 100644 tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_Legend_Placeholder_Icon/WMS_GetLegendGraphic_Legend_Placeholder_Icon.png create mode 100644 tests/testdata/qgis_server/test_project_legend_placeholder_image.qgs diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index 88dfc937ee5..4ca8aebf9ca 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -946,18 +946,23 @@ QSizeF QgsImageLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemCo { Q_UNUSED( itemHeight ) - if ( ctx && ctx->painter ) + if ( ctx && ctx->painter && ctx->context ) { - QImage scaledImg = mImage.scaled( settings.wmsLegendSize().toSize(), Qt::KeepAspectRatio, Qt::FastTransformation ); + QgsScopedRenderContextScaleToPixels scopedScaleToPixels( *( ctx->context ) ); + double scaleFactor = ctx->context->scaleFactor(); + double imgWidth = settings.wmsLegendSize().width() * scaleFactor; + double imgHeight = settings.wmsLegendSize().height() * scaleFactor; + + QImage scaledImg = mImage.scaled( QSizeF( imgWidth, imgHeight ).toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation ); switch ( settings.symbolAlignment() ) { case Qt::AlignLeft: default: - ctx->painter->drawImage( QPointF( ctx->columnLeft, ctx->top ), scaledImg ); + ctx->painter->drawImage( QPointF( ctx->columnLeft * scaleFactor, ctx->top * scaleFactor ), scaledImg ); break; case Qt::AlignRight: - ctx->painter->drawImage( QPointF( ctx->columnRight - settings.wmsLegendSize().width(), ctx->top ), scaledImg ); + ctx->painter->drawImage( QPointF( ctx->columnRight * scaleFactor - imgWidth, ctx->top * scaleFactor ), scaledImg ); break; } } diff --git a/tests/src/python/test_qgsserver_wms_getlegendgraphic.py b/tests/src/python/test_qgsserver_wms_getlegendgraphic.py index 54cd59c796e..24450f32cbc 100644 --- a/tests/src/python/test_qgsserver_wms_getlegendgraphic.py +++ b/tests/src/python/test_qgsserver_wms_getlegendgraphic.py @@ -1045,6 +1045,19 @@ class TestQgsServerWMSGetLegendGraphic(TestQgsServerWMSTestBase): self.assertEqual(node['scaleMaxDenom'], 1000) self.assertEqual(node['scaleMinDenom'], 10000) + def testLegendPlaceholderIcon(self): + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": self.testdata_path + 'test_project_legend_placeholder_image.qgs', + "SERVICE": "WMS", + "VERSION": "1.3", + "REQUEST": "GetLegendGraphic", + "LAYER": "landsat", + "FORMAT": "image/png", + }.items())]) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetLegendGraphic_Legend_Placeholder_Icon") + if __name__ == '__main__': unittest.main() diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_Legend_Placeholder_Icon/WMS_GetLegendGraphic_Legend_Placeholder_Icon.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_Legend_Placeholder_Icon/WMS_GetLegendGraphic_Legend_Placeholder_Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c799039210374c19d36844abfe7c3050a6943c48 GIT binary patch literal 8897 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 LN2L;C8} + + + QGIS Test Project + + + + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + testlayer20150528120452665 + testlayer_c0988fd7_97ca_451d_adbc_37ad6d10583a + testlayer_0b835118_a5d5_4255_b5dd_f42253c0a4a0 + testlayer_2b89ed65_ef2f_4897_af15_9b32d4c4e040 + testlayer_èé_cf86cf11_222f_4b62_929c_12cfc82b9774 + testlayer_èé_2_a5f61891_b949_43e3_ad30_84013fc922de + landsat_a7d15b35_ca83_4b23_a9fb_af3fbdd60d15 + + + + + + + + + + + + + + + + degrees + + 17.92123882869385909 + 30.1492204088525888 + 18.0486921925404431 + 30.25992437587047235 + + 0 + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Beschriftungen_bd4c1b29_b8ad_49b9_a322_c2680ab442c5 + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + 1 + 0 + + + + + 781662.375 + 3339523.125 + 793062.375 + 3350923.125 + + + 17.92427343259496908 + 30.15185621759111001 + 18.04565758863933667 + 30.25728856713195114 + + landsat_a7d15b35_ca83_4b23_a9fb_af3fbdd60d15 + ../landsat.tif + + + + landsat + + + PROJCRS["WGS 84 / UTM zone 33N",BASEGEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["UTM zone 33N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",15,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["unknown"],AREA["World - N hemisphere - 12°E to 18°E - by country"],BBOX[0,12,84,18]],ID["EPSG",32633]] + +proj=utm +zone=33 +datum=WGS84 +units=m +no_defs + 3117 + 32633 + EPSG:32633 + WGS 84 / UTM zone 33N + utm + EPSG:7030 + false + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + gdal + + + + + + + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + MinMax + WholeRaster + Estimated + 0.02 + 0.98 + 2 + + + 122 + 130 + StretchToMinimumMaximum + + + + + + + + + + + resamplingFilter + + 0 + + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + testlayer20150528120452665 + ./testlayer.shp + A test vector layer + A test vector layer with unicode òà + + + + testlayer èé + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + ogr + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + 0 + . + + 0 + generatedlayout + + + + + + "name" + [% 'Name: ' || "name" %] + + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + testlayer_0b835118_a5d5_4255_b5dd_f42253c0a4a0 + ./testlayer.shp + + + + testlayer3 + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + ogr + + + + + + + + + + 0 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + 0 + + + 0 + generatedlayout + + + + + + + + + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + testlayer_2b89ed65_ef2f_4897_af15_9b32d4c4e040 + ./testlayer.shp + + + + testlayer2 + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + ogr + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + id + + + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + testlayer_c0988fd7_97ca_451d_adbc_37ad6d10583a + ./testlayer.shp + layer_with_short_name + A Layer with a short name + A Layer with an abstract + + + + testlayer + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + ogr + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + id + + + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + testlayer_èé_2_a5f61891_b949_43e3_ad30_84013fc922de + ./testlayer.shp + A test vector layer + A test vector layer with unicode òà + + + + exclude_attribute + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + ogr + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + 0 + . + + 0 + generatedlayout + + + + + + + + + + + + + + name + [% 'Name: ' || "name" %] + + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + + 8.20345930703634352 + 44.90139483904469131 + 8.20354699399348775 + 44.90148252600183554 + + testlayer_èé_cf86cf11_222f_4b62_929c_12cfc82b9774 + ./testlayer.shp + A test vector layer + A test vector layer with unicode òà + + + + fields_alias + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + ogr + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + . + + 0 + . + + 0 + generatedlayout + + + + + + + + + + + + + + name + [% 'Name: ' || "name" %] + + + + + + + + + + + + + + 255 + + + + + 1 + true + + + + 2 + 0 + 2 + off + + + + + + current_layer + + + 255 + 255 + 255 + 255 + 0 + 255 + 255 + + + + testlayer_0b835118_a5d5_4255_b5dd_f42253c0a4a0 + + + + false + + + + + + WGS84 + + + m2 + meters + + + 50 + 5 + 16 + 30 + 2.5 + true + false + false + 0 + 0 + false + false + true + 0 + 255,0,0,255 + + + false + + + true + 2 + D + + + + + + 3452 + +proj=longlat +datum=WGS84 +no_defs + EPSG:4326 + 1 + + + + 0 + + + + + + + + + testlayer20150528120452665 + + + 8 + + + + testlayer20150528120452665 + + + testlayer20150528120452665 + + + testlayer20150528120452665 + + + + None + true + elpaso@itopen.it + QGIS dev team + Alessandro Pasotti + + + + 8.20315414376310059 + 44.901236559338642 + 8.204164917965862 + 44.90159838674664172 + + conditions unknown + 90 + + + + + 4 + false + + + false + Some UTF8 text èòù + true + QGIS TestProject + + false + + + + + + + + + + + + QGIS Test Project + + + + + + + + + + + + + 2000-01-01T00:00:00 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["unknown"],AREA["World"],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + From 9e990cb6bd268769934389aa71f717a92d975819 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Fri, 2 Jul 2021 17:03:41 +0200 Subject: [PATCH 7/8] Add mask image --- ...gendGraphic_Legend_Placeholder_Icon_mask.png | Bin 0 -> 12010 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_Legend_Placeholder_Icon/WMS_GetLegendGraphic_Legend_Placeholder_Icon_mask.png diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_Legend_Placeholder_Icon/WMS_GetLegendGraphic_Legend_Placeholder_Icon_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_Legend_Placeholder_Icon/WMS_GetLegendGraphic_Legend_Placeholder_Icon_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..4064ef10bdf77bb1f9f004cfe4875f7a13df4b28 GIT binary patch literal 12010 zcmb_?hdb5pANR>lvLg~glueQ(J0u}lAxSDp_R5wdSs_%CBuPS&Y_bViNwP^uR`z~g z=llByp6hy^>pF3&Gd`dDe!pMqeTV33tM8^}rzQ{xyH9JV>fv`i{yd_hz|Zf@*BJ3@ zr-Q}?X99ulGV#xjHwtMt2n24zX;meCk7rYfw{3gIe6|NlX4YS;>b>NfeE+Ln)4SI3 z*^mA~sT-71Hw|B0G^8Od+G4Z){E0;+n7sauYu|g8@uECaw>|YmuNp{X8i&@RFV;nf zm`1yX79EZr_8Ax$;MzK=qw(aWXkA><7`gX>(BY|>^>y#*U`l_|z=}6Jx6hUDptvGX zMOJC?Enw%}iZ`T8RDtIx`ROTAXtlU$)b>AC+#4n<9w5Hg)q>=*_@B@JPcL*Ox0Ftp z%ggrJEt_c9BlfMcGbr14F{8(qlVap@Ri-P4y!YdT=g)s@@pn93?jD~DxAzWAc=pU} zeunt^>S3qC_wF<1CEHu;i_@PDe0_e>bbcxRk}q3IO3Ge#_P49=pn~Rc#)a8oA^9TjTi3>rBm3TPfSeon5$u(+ghI) zIdf@^F)luSt|MuSxzLQ3;IOuEgX4tTU-=_bL9FJA_V!}!6H@)&^Jh1$=2HBO0eGwB|%X-p{7x+JZz*ca-`3FpvI`|-yXT`jd_B#rv(sTi?1x?w}KPX{|ke_PXEFb#eA^;@zARjD6T( z^}eJetS8@|H&(OL$M4eiTG!l|-_}^d8p+-;&u&qj5Ix|+*y2>Lg z#P7SvhUfQt?s9f^_L$7f$H#mgnREEv#J2JGx`N8}>(@JD{chi8yLIc<`)=C;*GU%b zXEFh4Nxtl&@w?WSrUK1Gg9m2nh|w=zWMci-M`y@z;BUq&T;veKS=QV%)o zRgdJXX>VuL;%Bn!EeP1&XxYBoXIH1=w{~7jM~9b#RwdJLBs0ICgs?G@v~~Dv;)!6( z94ai!WLNe`;n;Ihg53JwTx(m~yB!nNAxr|Tot=x^-rdD8;^eIdR52I7Wl7x4N3l9g8ZO zsO?<7UR>UIR$JT2$H%9)$G*IIacRj(jx#bLDQV37_UNAJ*`cc5`0|ab+8Lcr3TthV z1-$AJ4upb^G#%%@zCI4Zw1C3u&gGb-jk{&}`;OT;_$|Bpsrw}*CXR0X$=>=Cr7r(t zZqoVN(VXXgTeoF6Xg5~s6l#C`*gHHYv$nQ2o13&rGq6&7j61%OAw(5F|LaoX7dia- zcG#@MgF!lBw;w9?KB~vBc5b9j;>3wiu8l!TYisMztMg-Xnf5-rs;a71vbWd7-gMfO ztPF?B_-@Gj?CF{NdSd4D*!)m^6z?IHP>a! zW0Lu)U)@6d)7gvUn{8a14Dnk06EoUrFm5oF|(TEfG_9ka{U1S$Rhdq=`Cdnd+_yG&GMSf1j6P0{>4ZYRwKTtB>L8M1l9H8qpFTMe3StCwoQ$%~N6WT1XPnoUXU0U$OX^EeRttIE)RhsG zKDI^Qew8lwlcLL~2DWZ_FSMykJu7Azbz;*?f3(F(Mb_HhPC_^ot7)(-!c6_Jag?4q zXeCf#g>+$IK`~i(u+!*LP>p59`b>Ew5sex4PDMM6LsERvfr*f%uGEU zYh*s8nab$C`tRy=__6-ME&N9uz^Zp(dvm~9K1YzA>cJ$LB_!o~+|KE=`{pSpCX- z>3Mg~I$i(vcHQguCYc06QcHe!u%0l>E`7m0uV25OUQf^$45}JZlufK{Z`bP_c$$#F zKtmCw!8h&25m~2l^QMqx&R&v$&v66$0+oJ5gVeT#-uwRlVY$oaopU&)gk^tF!?XFMWo%-GM(w2AN5yJO z2{6)Mw-dI~`xZP;y2$STXd?2>=BSk<8z19N{O=yE9AnjFT@(_i;uKGmqA-gJAEOc< zW5t&*)GVy5IUhdU(ct^{MuF!_a4s*IvLSV;IbCQCNk%7iU9K+S@#fk zOaq=AUQc6qrPfbl(+u7agv=fmdw;??<4uDG@bKI==#+1Yd#FJ2ViOM{+ysG0gugAbi^D8BKV z6_2kD$-3j` zyibPhuT!KR0h@Tu=W+rNMd{Hl*SumEGJ)A-|F(QK61|-m6_4a3Uz=+Hv&4YK9 z4|tTCH#Ij`jLcbhda_@+a)pW_a8f(|`o`LvE?MQ+JeK=K*Cg86@mDHfBTAAckkX!A6ipC>NLCR4Y^jCX__xCDR~F7 z0~LrmG!s=fA}6?#e=wohS6DQU)>-vN#cA*{7JVt`vjdn8ehwgYC^T!GTqOA8ZK$!{ zGN0lJp7VuNs@(MGk{75-N;=MJ*0Nc0DQRhCKE?x_kyY3xCnrW=>5(Hx9w#LQ zw~VRe7{7BW;*!Q?%O=vg74L_LvCH2lA|f(AKJMRUeOF(QxJZ6}3i4~?yfn15dgqS# zo?JB}d)a2~@b`zrGr8N0!LNZlnULR>-W>a}NX*7AdLp3AOVZr>ewG zKT{pKn|=BH&fnG&8myGBUl-7RE*J9ktG1Msl%i-nZ&J$@>>rokhJ@(FqPrCp6-6__ zIbIBemFYlFNy)XC`y)AZoPjl#N;$^WShm^e;+f$@_x_6Jgkxxbr=(od#QE; z`+W>^Ws^Si&tK2I@b29^3u|jCT#QDl9^liU+gq|wo;})M0S6jk8iwcm3sk? zU-P#CPxumDzqctVq-YkCOcoSuM@Pr~x{(Cmfw06zQd1=w3R2(6eBWJZ+KI~Q>Xbl0 zegOf;#Xklc!>r|>6HmCK=if$qEgB20srn9xE+rYq^F$RR zd*Z}gHIq*3zeg1nN^$xdM=zU_9N77}zu#PLxz~C8&!0QcyPrQ3h`R=sy<0W3&Y6F1 zKE$lM#!}*y-eD0v{fy3!FV3ZPD4|C1^?ZzNBsG9q4L%Y`pxD?wPp$cCLSv5_CP<8d z9$+!hj1F5Hw~6o{bDCK5<83MQRAiv~#|a54(g}UD^OA1-J&gC2lhF;7#7cB=bK`lU z^S7bcd@A?DeBubH9t)H4NM%c4MnxaD2HKq4lY4#j=&DnX5-cdCZ``|N_vvx7}C zvrLDIf2M&;#1op~Ch&q&@L0He@uNqB8X8VlkIWs-aO+y5`L#4UdUauWImK9b7@E9_ zNk=Y#=otW*%+%nr_v7D1uQih7m}LGa_fv@AJox}{LNrMQ-m8+huTLdTKr0l~UK)zO z1La)m5gZlCD!~@wd%2@D2)!q|K?hL7C<75=zD46#6lXxNqVX!JdP=C2mo?C-fIv7% z8XB6x%Aj43pFUMS#H`F8)9pfdVJyr8&DNo#fFkwR;8S*Y|F0ldS8wCh;sJjxKk?Bg z>)wCl>!p0aSw z$Z$UTfjKxHOXuS1nw*wKc`di_i`n^feeow+QiltkEbADXm{bZRd6N|PMFdjPy##(l zDs0K11$J#u>q#G^2U6#mgv0E-NKfAxr9s9jW?nrzE8ZvOlPeHwEPM|(E=ET_T?|JldqHvXTV!UO6N_Jh$SLdT5c@Kx8Dw=H|8EzA@Vkl!gEPeeL6? zPcIP(0QIF4!k;>&>r=N`e-xA|WdK51VQgFqV8TF!8=R=f3 zRPWroN3rpBW`h<@KHXaw2wzVppJd0MtK~XjvB=&jKDcM-Ka%Oqtd#35i zsF+_!?)8@8-^~e+pFDwpQ$jZ{+;rp!wv|3pmCcuuq{R;nVC@`>PDPJs@u#F7Oh`2o zy>j&`Ib#SJ5D;pMDoAjwN`&=u}*0nA*7VFM35kMUBA!rMbE2d+0r(yR;T$G zlT%a4brd$Gp8G6a02V-ITmc^t%|%3{{2CST{gg0^*Pym&oudYSjIo(n_23})%QjFK z`8z`)=ui~?t%|dJjLYFHCNl(o=sI8*G6VD?4|_ODKj+`d#oE_oA3*VPtG{C4^9meC zD6%e{@SAv|jpM zNC0DDHD@;HBOtwY8WW^DBu!{&C@yI7TEEdHW{uX*HhJw8%+Qp=Rb`Do9x7@`udmFF z$heHtXI(75hnr=_>py;a`#pz+B5(&R^2!&ZG7_v3u-2^1n~lqN<$&m=vM^Pixz@jn zPK99(GGReMBm;xYAZS#Y}XhHhdodCc(){{1qpf0)fgS&;%b4powSZ_L%9ay+dBbl_3I z*HN&Cp*6ELV!jL~Po9Lnfo^o&e3$p9;X}7DF{Ox$V}Z7=8g)9r9u6JpGo2JXXYr$z z`lY^LTUQq)0w!E?W4stIh`jH5DW?OYXXk_q@msYMWrGyC{n5Zg3;^vL9DfwNyUwwG zZ2sFa58=I0aOU8q522b@DMVSFyg3p@BJ``gyvE#n;$NZRrly{Jlk^<<8 zT9$v@=X$Ao$bl$g<-PZMmU706U8)V*#p*EjHF5uu7a|a?5U@!t9ZROeR$^jeUEW$E zxzYOY8CPX>3eeYR-k6vey2%moPYp%9yH2mFtEiBooMC~j-?(N{X^W)Af}2y?23wO= zS|?mU`kyJey!~@>a$06OZbhNuh;a-=Cb56}OTD0}0sDl(vKH+(C7J)^Aqa3!0frf= zJ6kiqr%P~(PEy}}^fV^J8ZB06mi6?|hwnQ{z1`X$$|1uNKz++^t&E6_vCG?|)dBtY z?%kVh5J>uLEmb+>pqSF8c&KFTQ>V$%?@tS0Ht69HLTd=UM=l6a{*rJbez+FzGl0y$ ze@@MgNwM$b9qY@d+)l{K$`S~?yu1Z26O4=@)qz`bbdM$`ZV(Bxv9S?8eSCWQ^~v$c zQ-1_!&LgAK;+K$>eE{`XRUekva*xbXe6P5?JZ*ND>E__}j7Qg*$5DPgD9WQpFFQCq zlr23`Gh-YIa|PimWR%67(EJjtA^GIpANdTUmOMj)c73-gf$fmrTsRNORA450zh<~d zr0{MhYlLMEQDgsdIu6~>|L|gE(e+3`uLj>suj{tIei`2iJ;TTNQ%FKyzARN-VD5^B z*qZ0VWyOuxnco$!<`VtiAV`V0=J?<#AA#)L{<|!L&o42Bt3@?mOMg=PWA&ZTLx`|- z5yQ|IPE=JUm7p8gL5;MI$IqYlJKfrI+Hh%UiO3E?%9mA6pGs;8#*+3HI#V`SIdx>8 z`NxZBBsVu#7wg$Lx=<)csrl~OqPub})xnt4ac2h(;`2dO`ho^W1>)aFWqd$;bla+- z6YJ~ikgHD@M&_&=9_(4xkPlEqb(}cqrEo1X89%Pq!cUEcE z3#u)hv0~D3lb&P|q9!9@_t_zTX2U=)dnCeEPvz6)e$iCDogibouNMjr2ppz;CwCd5 z4UG(jM-XIUV)9l~?Pc5ez2c4fkVNgYn}$o@h4RzylF8NIdj%JA@9k}&gqKv4o#s(J z4WfBgZk=uic)0nglUlNWZa6RAW%{?)U={s|BBq}u({NW(i;-((7wlYHq1j~OkHs>s z4>p|-Xe8ZO(E8sPJCE>wmt_;=+I~UF@^Fl|+cioyl&f%wM|x% z;Bt!_H*ToRM4GMU&tIr_udL3QzhJ~|6>r=gU)rq#HJ8%nUpI1cHh}!*6Vp|1PJ~Aw zd9@S!R~P2I?U6HDp?{?wdcQx0sOu z#cI}6=bQoSJklI}Do>&7ck>83BT<{EhL&f3*rbQ_*`@vNudGxyFpih`S{)*gy7J3- zvmeMD7Wl0_h_K7VH=>;pvKaA z#9Z@<0T{{&MhwEc6A)kW&`g0F&CWs?b7vMvN<8YOKH0g`P&+< z9#VKPRs0H~aG50rNI;x;>>8c$fTG=PQKJBzHeMk%mX=w_W6eMy=*yoXGW)H_QuUl(M~39+yU?gNFxq{RprToM17&Q0 zeHgMAx`$x3hMWrVW#>fW5muv;ryF0!jK?)t!6Ls<3f46Ai$fY~CQ6BK2ll~n0Zk$7 ztn*Ahe*6f#*U{&So$4%k-`R4QF{HJ%m4K2N?5}<_wNNY0NxSdstDY%0um|FqZy&QK zV-pBTyZx+h-h|w){QLKB+_SC!<+Q3iJ5UO!HH1;9Rm3_)Ubja7=w6sty*9J9=?lv* zEG!Hh+lhLIkbNt=;i~}I1b=|38nPWU;^3SIH)DuJe$Qn*a*Pok12e4ChHU0FlXWcy z%6u?LgcKnfDANOfNu>4P!S*}O4l1FK!Ld)5)0rtHjtcHS$2rq~x0X1%!vJ>Iu3e`6 z#bQXte0@2Ajeyo`xopS~VMjj>SmqU;@@D*yeOY`j1jAjVFetX)zkd%ddggrmNS58T zE4wQcIk2%XMM@i0p2=Aw_{hUFyLTIOx*X@AwXut0DsTU#m(l6*`^k0PL(EWK5x@(# zXFtgy8I+R=Sn=!6Z{L$<@62d4xyg3}raN7~64}EJ40&^m!%|aIZyi0y;Cx0jzRF7S zoO7tH=|ixtcI6iyr2s`mfk*mrUr3WeN@0|M2zzPZ+N&m9l+*PQ99(vEWPpmkXPEIW zut}6apnXU@3vdd}iUB}hapK>{XPzU3sJfOr^s6BTs<(fkOfXEn4oJ3#nw*H(4Oa9t z6f?Q=LKlRpw6rOZ^9NTEjYCsY6G9E!ZWe*xhH{)~zYUFySY;wq#P_}`5aq z4~jspET5#4yAhjbUSk>MYaTHIafp(g~&W*Ox=beQTwF5_FFt{Z`dU5eS z82!B*99E|*FIL{u63#KEiD@9iasX=!3k!?9lDmo|85R8h7JX}L+mUIAbTI&6bSrN- zOFAE=2)x*TLG{`&$%{Q7t%!^O$k0E;_s`&l=cb_?Prodr{M2h`vY~ewcP)rJ1ySjpr10pK1w6*;!zkNT) zxqFr~2$c&Dh-9!5(fSmrz&qN-Eb_y|0D_n*qrV}H24>We9(~ZLw^4EuMlbzuGT=ha zO&%VbQDx&C`i?L5_HG_Gy=dho5nvBGJEq}oNXSmDvuE2JL?sH5-eA6pi3TzJ$DV(? z=)-m*ba#GlbaG>Jb2I1~Vib1%-Qh6JePt{lTli>X+t8eVBxEojxvscgT2(vn+mJsd z0LY@97Kp&R(bXPSXDN(F0KexM*mxgl39DGwodhLfM0{+Fqc>-zyPx4Q!@&N(1NO${!yp9Qs_;EHs9g~q9<5#&^(kD!Un}#*hI$SAdv89z~DW_<|3-v}8sDx<&P726! z|FjT)k(|5(k`z%2R+@iS`l&ki?>H0;;wfagZPsWTb-~yo`-f5&(gjmYUxmIml+4i= zMAB3>Hh<3f47N2{7vwNFl|S(M^`R@vIfnxXNyq>4>EF!lh6T>}J)LC`pJ!-vNj@n} zWj{b3ff`~6ECMPV90_CsUs^l9fQ>`MY9^Xi#&BF?`6ZT%n2!m-x$?(^e76HI;>y`c z_`ikP8GNGYdSDmZcoqDN2W}R+t>~s`_8p(F zN#v{U{kQ5p>sbnXH4s4X7L0v;e$s0eBLHH;M$DI&ru#xsvM*qfFexGuDj*gk@8CKv zKMrEnM$081wzTAiMaK#tLDut2&dFf_fuW#>918xNWN^;V7wlv0S?$5{ajo` z%ERp+HLBP7-*_{`4W4;-$&MEys4kDCoDOL~C8dzh&*$X%!}k>$t14y=*iT?9zrA zo$q_52>zHcKv57UA<8O@Bw5#iILd}mU#u)s?bWn&83TBK$Dt7pF~7W`-K`1h`aw~H z)PRpMKrMwR1W_0wGiYN|C#{B^@y*wW({D@*Ftg#Ir^5KO!`GRy_H0@Q(r9S+1%Zi1 zh;%7xwP(H`qQ((?qr5O~#{mL-kW-=AS?3HVZ^6U1d?VUM0!%{9nbuOosX5j&QCq!P zgz@4Pp6*rK3)}>2AI5Y?r{X>YRJs|R=t8MU8rxf{0us&|yx(x3$F9F5B*Q4%(!zq6 z0X=^9ta@QV3TFd|gB7Sy+;nfrZ6;!hjnfd~Cr|FifsSHcoRjFwfB4w+RR=v`w?fyE z{CYBVOS{ZzdjX-4ftj@1oB%Y)PHU+L9&%ruc#8dR?IbH;r9J3%|6y4ekPaga`1rfZ z$#0|QGZnMiyKUpLXmIYS!s6ky+0kRih#@_o5DzSnC4`iDHfx0i(I27Ikg%dy2>u8= znp#@UJ7=J#LAQ{bcss2Rx4v3FM79!Hl!ks@03CyVYN3H(EXF3*)s2&jcGfTDM%q5y z3Lq#7#=hL|^vcK#a}1ybZ7^w@wM+AEJLxl5&+1D)dDRyHoc1l}!cUC5%dW{LzE&C3 z7>Newblcv8W|GX;aLGtc4v;>B)^OT$fFVoMIdq{Qn{$W0Fw4XipH=<Hw3XDi1^A z#<{|lTF-<36mN08?w`syP;6B*;)sA85*AKECQ+L(nP3__Rm^9Z_p_HL&-9lwLo&U9 zLZbHh?R$SYntpW4i3iYQxCGgZv;v=q%gTIv%g&A%WhQq_z=zgs_7QO@7aAXyI@*(uk3_YfVP#`5IH-|0vOC zoM5_nD&JVc-Thx7)!iRsR%ALd9Iv}w(E|`3$i9JQMU{jX{L~Xw+`k*uwBCo8i4Epj zS;=sy3A3aG9)`Zcoxz*kI4m!bkEOv>(a_NFZFERRqIMi;^6G zEyl3{qEKZF!T1bvxUD`CN)bH|0Zg3cVuFHYl|B1hO55P+;fy0aH~Y#st<>xeF;}+u zZ8<}6y(};1;*1P79D{Bo&O^f09&7O9vpC4`8{XPaz{r+04=<Mo8GU{aW z(_lKMviigP?L#CxruQ6Utb0at$Iiy)?H@kD)L61Tz5GMhRysf5kZ5vy>Fh8`z!)p7?FRO#$I&g2?`)rEL zL`_7?JQ>&3-q_l_EeYRv4p~D(k@Nn&KagBYTiepch8ln|=dn>X#yd09^yCQfC@BCN z2M0heW_z|S_R*+G{^MKQLmLd24*zK!KO{OBMg5AAafqigk0LPOUQkH3B0oQ4(jC>( z`ahtmiRx<09F56p!F7F&=m@D}K~c<9+Y$2;Ws=9TLmWpmj;~o_d4-QFjmu8n8i5r`#PD* zYu2pi*^q89mexWuHcBwjswr(}BL^F-Bny1jr2(sZN?);Ma8^rYJX_m(q1+YL62G7K zp$Waf$%JM-fui=bHyqSCPrryHhqNef#80^`;*4nf+B?jVWjG>Sxm3KPzc{L4Y!D%l z Date: Sat, 3 Jul 2021 13:11:10 +0200 Subject: [PATCH 8/8] Change expected test image --- ...tLegendGraphic_Legend_Placeholder_Icon.png | Bin 8897 -> 8578 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_Legend_Placeholder_Icon/WMS_GetLegendGraphic_Legend_Placeholder_Icon.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_Legend_Placeholder_Icon/WMS_GetLegendGraphic_Legend_Placeholder_Icon.png index c799039210374c19d36844abfe7c3050a6943c48..c371296ceb7f49232c5c948763a7dbdbd71c49d4 100644 GIT binary patch literal 8578 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 N>D_y|a_Fb8{{zQGk#hh5 literal 8897 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 LN2L;C8}