From 90622beb5300a1f2c2af193d9b98b937c3f4d119 Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Wed, 18 Sep 2024 18:09:56 +0200 Subject: [PATCH 1/2] [server] WMS GetLegendGr.. cascading size Fix #57422 by adjusting the legend size considering the cascaded legend imag size. --- .../qgslayertreemodellegendnode.sip.in | 10 ++++++ .../qgslayertreemodellegendnode.sip.in | 10 ++++++ .../layertree/qgslayertreemodellegendnode.h | 10 ++++-- src/server/services/wms/qgswmsrenderer.cpp | 31 +++++++++++++++++-- 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/python/PyQt6/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in b/python/PyQt6/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in index e45129f8600..577ef0a8273 100644 --- a/python/PyQt6/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in +++ b/python/PyQt6/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in @@ -661,6 +661,16 @@ Constructor for QgsWmsLegendNode. virtual void invalidateMapBasedData(); + QImage getLegendGraphic( bool synchronous = false ) const; +%Docstring +Lazily initializes mImage + +:param synchronous: if ``True``, the image is fetched synchronously, otherwise asynchronously + +.. versionadded:: 3.40 +%End + + SIP_PYOBJECT __repr__(); %MethodCode QString str = QStringLiteral( "" ).arg( sipCpp->data( Qt::DisplayRole ).toString() ); diff --git a/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in b/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in index bc31f329c95..3b4fc11b2bc 100644 --- a/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in @@ -661,6 +661,16 @@ Constructor for QgsWmsLegendNode. virtual void invalidateMapBasedData(); + QImage getLegendGraphic( bool synchronous = false ) const; +%Docstring +Lazily initializes mImage + +:param synchronous: if ``True``, the image is fetched synchronously, otherwise asynchronously + +.. versionadded:: 3.40 +%End + + SIP_PYOBJECT __repr__(); %MethodCode QString str = QStringLiteral( "" ).arg( sipCpp->data( Qt::DisplayRole ).toString() ); diff --git a/src/core/layertree/qgslayertreemodellegendnode.h b/src/core/layertree/qgslayertreemodellegendnode.h index 77048a8cdf1..d49f05d91d8 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.h +++ b/src/core/layertree/qgslayertreemodellegendnode.h @@ -747,6 +747,14 @@ class CORE_EXPORT QgsWmsLegendNode : public QgsLayerTreeModelLegendNode void invalidateMapBasedData() override; + /** + * Lazily initializes mImage + * \param synchronous if TRUE, the image is fetched synchronously, otherwise asynchronously + * \since QGIS 3.40 + */ + QImage getLegendGraphic( bool synchronous = false ) const; + + #ifdef SIP_RUN SIP_PYOBJECT __repr__(); % MethodCode @@ -763,8 +771,6 @@ class CORE_EXPORT QgsWmsLegendNode : public QgsLayerTreeModelLegendNode private: - // Lazily initializes mImage - QImage getLegendGraphic( bool synchronous = false ) const; QImage renderMessage( const QString &msg ) const; diff --git a/src/server/services/wms/qgswmsrenderer.cpp b/src/server/services/wms/qgswmsrenderer.cpp index 23295830361..1710096c89d 100644 --- a/src/server/services/wms/qgswmsrenderer.cpp +++ b/src/server/services/wms/qgswmsrenderer.cpp @@ -124,8 +124,36 @@ namespace QgsWms QList layers = mContext.layersToRender(); configureLayers( layers ); - // init renderer + const qreal dpmm = mContext.dotsPerMm(); + QgsLegendSettings settings = legendSettings(); + + // adjust the size settings if there any WMS cascading layers to renderer + const auto layersToRender = mContext.layersToRender(); + for ( const auto &layer : std::as_const( layersToRender ) ) + { + // If it is a cascading WMS layer, get legend node image size + if ( layer->dataProvider()->name() == QStringLiteral( "wms" ) ) + { + if ( QgsWmsLegendNode *layerNode = qobject_cast( model.findLegendNode( layer->id(), QString() ) ) ) + { + const auto image { layerNode->getLegendGraphic( true ) }; + if ( ! image.isNull() ) + { + // Check that we are not exceeding the maximum size + if ( mContext.isValidWidthHeight( image.width(), image.height() ) ) + { + const double w = image.width() / dpmm; + const double h = image.height() / dpmm; + const QSizeF newWmsSize { w, h }; + settings.setWmsLegendSize( newWmsSize ); + } + } + } + } + } + + // init renderer QgsLegendRenderer renderer( &model, settings ); // create context @@ -146,7 +174,6 @@ namespace QgsWms // create image according to context std::unique_ptr image; - const qreal dpmm = mContext.dotsPerMm(); const QSizeF minSize = renderer.minimumSize( &context ); const QSize size( static_cast( minSize.width() * dpmm ), static_cast( minSize.height() * dpmm ) ); if ( !mContext.isValidWidthHeight( size.width(), size.height() ) ) From 1f86ad11b7aba9d8e3e48b0c5021e1d75afb1cfc Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Fri, 20 Sep 2024 16:03:14 +0200 Subject: [PATCH 2/2] Add a blocking variant --- .../layertree/qgslayertreemodellegendnode.sip.in | 6 ++---- .../layertree/qgslayertreemodellegendnode.sip.in | 6 ++---- src/core/layertree/qgslayertreemodellegendnode.cpp | 5 +++++ src/core/layertree/qgslayertreemodellegendnode.h | 7 ++++--- src/server/services/wms/qgswmsrenderer.cpp | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/python/PyQt6/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in b/python/PyQt6/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in index 577ef0a8273..c0b284923f3 100644 --- a/python/PyQt6/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in +++ b/python/PyQt6/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in @@ -661,11 +661,9 @@ Constructor for QgsWmsLegendNode. virtual void invalidateMapBasedData(); - QImage getLegendGraphic( bool synchronous = false ) const; + QImage getLegendGraphicBlocking( ) const; %Docstring -Lazily initializes mImage - -:param synchronous: if ``True``, the image is fetched synchronously, otherwise asynchronously +Fetches the image from the server and returns it. .. versionadded:: 3.40 %End diff --git a/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in b/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in index 3b4fc11b2bc..f2b7406ccbd 100644 --- a/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreemodellegendnode.sip.in @@ -661,11 +661,9 @@ Constructor for QgsWmsLegendNode. virtual void invalidateMapBasedData(); - QImage getLegendGraphic( bool synchronous = false ) const; + QImage getLegendGraphicBlocking( ) const; %Docstring -Lazily initializes mImage - -:param synchronous: if ``True``, the image is fetched synchronously, otherwise asynchronously +Fetches the image from the server and returns it. .. versionadded:: 3.40 %End diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index 118dbbd6fbd..b6ab6529605 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -1462,6 +1462,11 @@ void QgsWmsLegendNode::invalidateMapBasedData() emit dataChanged(); } +QImage QgsWmsLegendNode::getLegendGraphicBlocking() const +{ + return getLegendGraphic( true ); +} + // ------------------------------------------------------------------------- QgsDataDefinedSizeLegendNode::QgsDataDefinedSizeLegendNode( QgsLayerTreeLayer *nodeLayer, const QgsDataDefinedSizeLegend &settings, QObject *parent ) diff --git a/src/core/layertree/qgslayertreemodellegendnode.h b/src/core/layertree/qgslayertreemodellegendnode.h index d49f05d91d8..cc5d179aa9e 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.h +++ b/src/core/layertree/qgslayertreemodellegendnode.h @@ -748,11 +748,10 @@ class CORE_EXPORT QgsWmsLegendNode : public QgsLayerTreeModelLegendNode void invalidateMapBasedData() override; /** - * Lazily initializes mImage - * \param synchronous if TRUE, the image is fetched synchronously, otherwise asynchronously + * Fetches the image from the server and returns it. * \since QGIS 3.40 */ - QImage getLegendGraphic( bool synchronous = false ) const; + QImage getLegendGraphicBlocking( ) const; #ifdef SIP_RUN @@ -771,6 +770,8 @@ class CORE_EXPORT QgsWmsLegendNode : public QgsLayerTreeModelLegendNode private: + // Lazy loading of the image + QImage getLegendGraphic( bool synchronous = false ) const; QImage renderMessage( const QString &msg ) const; diff --git a/src/server/services/wms/qgswmsrenderer.cpp b/src/server/services/wms/qgswmsrenderer.cpp index 1710096c89d..86e1a5c844a 100644 --- a/src/server/services/wms/qgswmsrenderer.cpp +++ b/src/server/services/wms/qgswmsrenderer.cpp @@ -137,7 +137,7 @@ namespace QgsWms { if ( QgsWmsLegendNode *layerNode = qobject_cast( model.findLegendNode( layer->id(), QString() ) ) ) { - const auto image { layerNode->getLegendGraphic( true ) }; + const auto image { layerNode->getLegendGraphicBlocking( ) }; if ( ! image.isNull() ) { // Check that we are not exceeding the maximum size