[vlc-commits] [Git][videolan/vlc][master] 5 commits: qt: add `ImageHelper::createSvgImageIOHandler()`

Steve Lhomme (@robUx4) gitlab at videolan.org
Thu Feb 20 16:23:16 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
338fda17 by Fatih Uzunoglu at 2025-02-20T16:10:25+00:00
qt: add `ImageHelper::createSvgImageIOHandler()`

- - - - -
c059d2d0 by Fatih Uzunoglu at 2025-02-20T16:10:25+00:00
qt: use svg handler instead of `QSvgRenderer` in `ImageHelper::loadSvgToPixmap()`

- - - - -
075b981e by Fatih Uzunoglu at 2025-02-20T16:10:25+00:00
qt: use svg handler instead of `QSvgRenderer` in `SVGColorImageReader::execute()`

- - - - -
4ce8539e by Fatih Uzunoglu at 2025-02-20T16:10:25+00:00
qt: do not depend on qt svg module anymore

The image handler plugin is used instead of the svg module.

- - - - -
a61e338c by Fatih Uzunoglu at 2025-02-20T16:10:25+00:00
qt: remove fake qt modules in meson

These are not real qt modules (but qt libraries),
they are here for historical reasons as they were
useful when qmake or cmake was not used to generate
dependencies for static qt.

- - - - -


6 changed files:

- modules/gui/qt/meson.build
- modules/gui/qt/network/qml/NetworkCustomCover.qml
- modules/gui/qt/qt6.pro
- modules/gui/qt/util/color_svg_image_provider.cpp
- modules/gui/qt/util/imagehelper.cpp
- modules/gui/qt/util/imagehelper.hpp


Changes:

=====================================
modules/gui/qt/meson.build
=====================================
@@ -15,8 +15,7 @@ qt6_dep = dependency('qt6',
     # Note that Qt < 6.2.5 does not provide pc files!
     version: '>=6.2',
     modules: [
-        'Core', 'Gui', 'Widgets', 'Svg', 'Qml', 'QmlModels',
-        'QuickLayouts', 'QuickTemplates2', 'QmlWorkerScript',
+        'Core', 'Gui', 'Widgets', 'Qml',
         'Quick', 'QuickControls2'
         ],
     private_headers: true,


=====================================
modules/gui/qt/network/qml/NetworkCustomCover.qml
=====================================
@@ -53,7 +53,7 @@ Item {
 
         visible: !artwork.visible
 
-        sourceSize: Qt.size(width, height)
+        sourceSize: Qt.size(0, height) // preserve aspect ratio
 
         fillMode: root.fillMode
         horizontalAlignment: root.horizontalAlignment


=====================================
modules/gui/qt/qt6.pro
=====================================
@@ -1,6 +1,6 @@
 TEMPLATE = app
 
-QT = core gui qml svg quick widgets quickcontrols2
+QT = core gui qml quick widgets quickcontrols2
 QTPLUGIN = qsvgicon qsvg qjpeg qico
 
 CONFIG -= entrypoint


=====================================
modules/gui/qt/util/color_svg_image_provider.cpp
=====================================
@@ -19,14 +19,16 @@
 #include "color_svg_image_provider.hpp"
 #include "qt.hpp"
 #include "util/asynctask.hpp"
+#include "util/imagehelper.hpp"
 
-#include <QSvgRenderer>
 #include <QUrl>
 #include <QUrlQuery>
 #include <QPainter>
 #include <QFile>
 #include <QQmlFile>
 #include <QDebug>
+#include <QBuffer>
+#include <QImageIOHandler>
 
 static const QMap<QString, QString> predefinedSubst = {
     {COLOR1_KEY, "#FF00FF"},
@@ -88,7 +90,7 @@ public:
 
     QImage execute() override
     {
-        if (m_requestedSize.width() == 0 || m_requestedSize.height() == 0)
+        if (m_requestedSize.width() < 0 || m_requestedSize.height() < 0)
         {
             m_error = "invalid size requested";
             return {};
@@ -102,47 +104,70 @@ public:
             return {};
         }
 
-        QColor backgroundColor{Qt::transparent};
+        const auto svgHandler = QScopedPointer<QImageIOHandler>(ImageHelper::createSvgImageIOHandler());
 
-        if (data.second.has_value())
-            backgroundColor = *data.second;
+        QImage image;
 
-        QSvgRenderer renderer(data.first);
-        if (!renderer.isValid())
+        if (svgHandler)
         {
-            m_error = "can't parse SVG content";
-            return {};
+            QBuffer buffer;
+            buffer.setData(data.first);
+
+            if (Q_LIKELY(buffer.open(QFile::ReadOnly)))
+            {
+                svgHandler->setDevice(&buffer);
+
+                if (Q_LIKELY(svgHandler->canRead()))
+                {
+                    QSize scaledSize;
+
+                    if ((m_requestedSize.width() == 0 || m_requestedSize.height() == 0))
+                    {
+                        // QImageReader standard behavior, if width or height is 0,
+                        // it is calculated to preserve the aspect ratio:
+
+                        const QSize naturalSize = svgHandler->option(QImageIOHandler::Size).toSize();
+
+                        if (m_requestedSize.width() == 0)
+                            scaledSize.setWidth(m_requestedSize.height() * ((qreal)naturalSize.width() / naturalSize.height()));
+                        else if (m_requestedSize.height() == 0)
+                            scaledSize.setHeight(m_requestedSize.width() * ((qreal)naturalSize.height() / naturalSize.width()));
+                    }
+                    else
+                    {
+                        scaledSize = m_requestedSize;
+                    }
+
+                    if (!scaledSize.isEmpty())
+                        svgHandler->setOption(QImageIOHandler::ScaledSize, scaledSize);
+
+                    if (data.second.has_value())
+                        svgHandler->setOption(QImageIOHandler::BackgroundColor, *data.second);
+
+                    svgHandler->read(&image);
+                }
+                else
+                {
+                    m_error = QStringLiteral("Svg Image Provider: svg image handler can not read the svg contents, is the file svg specification compliant?");
+                }
+            }
+            else
+            {
+                m_error = QStringLiteral("Svg Image Provider: can not open colorized svg buffer for read.");
+            }
         }
-
-        //FIXME QT < 5.15 doesn't support QSvgRenderer::setAspectRatioMode
-        //scale to fit manually
-        QRect bounds;
-        QSize bbox = renderer.defaultSize();
-        float sourceAR = bbox.width() / (float)bbox.height();
-        float destAR = m_requestedSize.width() / (float)m_requestedSize.height();
-        if (qFuzzyCompare(sourceAR, destAR))
-            bounds = QRect({0,0}, m_requestedSize);
-        else if (sourceAR < destAR) {
-            float scaledWidth = m_requestedSize.height() * sourceAR;
-            bounds = QRect((m_requestedSize.width() - scaledWidth) / 2, 0,
-                           scaledWidth, m_requestedSize.height());
-        } else {
-            float scaledHeight = m_requestedSize.width() / sourceAR;
-            bounds = QRect(0, (m_requestedSize.height() - scaledHeight) / 2,
-                           m_requestedSize.width(), scaledHeight);
+        else
+        {
+            m_error = QStringLiteral("Svg Image Provider: can not found QSvgPlugin, is it installed?");
         }
 
-        QImage image;
-        if (backgroundColor.alpha() == 255)
+        if (Q_UNLIKELY(image.isNull()))
+        {
+            if (m_error.isEmpty())
+                m_error = QStringLiteral("Svg Image Provider: unspecified error.");
             image = QImage(m_requestedSize, QImage::Format_RGB32);
-        else
-            image = QImage(m_requestedSize, QImage::Format_ARGB32_Premultiplied);
-        image.fill(backgroundColor);
-
-        QPainter painter;
-        painter.begin(&image);
-        renderer.render(&painter, bounds);
-        painter.end();
+            image.fill(QColor("purple"));
+        }
 
         return image;
     }


=====================================
modules/gui/qt/util/imagehelper.cpp
=====================================
@@ -28,25 +28,76 @@
 #include <QApplication>
 #include <QPainter>
 #include <QScreen>
-#include <QSvgRenderer>
+#include <QImageIOHandler>
+#include <QPluginLoader>
+#include <QFile>
 #include "imagehelper.hpp"
 
 
 QPixmap ImageHelper::loadSvgToPixmap( const QString &path, qint32 i_width, qint32 i_height )
 {
     qreal ratio = QApplication::primaryScreen()->devicePixelRatio();
-    QPixmap pixmap( QSize( i_width, i_height ) * ratio );
 
+    const auto svgHandler = QScopedPointer<QImageIOHandler>(createSvgImageIOHandler());
 
-    pixmap.fill( Qt::transparent );
+    QImage image;
+    const auto size = QSize( i_width, i_height ) * ratio;
 
-    QSvgRenderer renderer( path );
-    QPainter painter;
+    if (svgHandler)
+    {
+        QFile file(path);
 
-    painter.begin( &pixmap );
-    renderer.render( &painter );
-    painter.end();
+        if (file.open(QFile::ReadOnly))
+        {
+            svgHandler->setDevice(&file);
+            svgHandler->setOption(QImageIOHandler::ScaledSize, size);
 
-    pixmap.setDevicePixelRatio( ratio );
-    return pixmap;
+            if (svgHandler->canRead())
+                svgHandler->read(&image);
+            else
+                qWarning() << "ImageHelper: svg image handler can not read file " << path << ".";
+        }
+        else
+        {
+            qWarning() << "ImageHelper: can not open file " << path << ".";
+        }
+    }
+
+    if (Q_UNLIKELY(image.isNull()))
+    {
+        image = QImage(size, QImage::Format_RGB32);
+        image.fill(QColor("purple"));
+    }
+
+    image.setDevicePixelRatio(ratio);
+    return QPixmap::fromImage(image);
+}
+
+QImageIOHandler *ImageHelper::createSvgImageIOHandler()
+{
+    static const auto plugin = []() -> QPointer<QImageIOPlugin> {
+#ifdef QT_STATIC
+        const auto& staticPlugins = QPluginLoader::staticInstances();
+        const auto it = std::find_if(staticPlugins.begin(), staticPlugins.end(), [](QObject *obj) -> bool {
+            return obj->inherits("QSvgPlugin");
+        });
+
+        if (it != staticPlugins.end())
+            return qobject_cast<QImageIOPlugin*>(*it);
+        else
+            return nullptr;
+#else
+        QPluginLoader loader(QStringLiteral("imageformats/qsvg")); // Official Qt plugin
+        // No need to check the metadata (or inherits `QSvgPlugin`), a plugin named "qsvg" should already support svg.
+        return qobject_cast<QImageIOPlugin*>(loader.instance());
+#endif
+    }();
+
+    if (!plugin)
+    {
+        qWarning() << "ImageHelper: svg image plugin is not found.";
+        return nullptr;
+    }
+
+    return plugin->create(nullptr);
 }


=====================================
modules/gui/qt/util/imagehelper.hpp
=====================================
@@ -31,6 +31,8 @@ class ImageHelper
 public:
     /* render a Svg to a pixmap with current device pixel ratio */
     static QPixmap loadSvgToPixmap(const QString& path, qint32 i_width, qint32 i_height);
+
+    static class QImageIOHandler* createSvgImageIOHandler();
 };
 
 #endif // IMAGEHELPER_HPP



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/7efd22371c8260f2b9a672474d3c264e576fcf65...a61e338c6ef16ba58d8aebdd8709c66256e8a098

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/7efd22371c8260f2b9a672474d3c264e576fcf65...a61e338c6ef16ba58d8aebdd8709c66256e8a098
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list