QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
ColoredSvgImageProvider.cc
Go to the documentation of this file.
2
3#include <QtCore/QFileInfo>
4#include <QtCore/QLoggingCategory>
5#include <QtGui/QImage>
6#include <QtGui/QPainter>
7#include <QtSvg/QSvgRenderer>
8
9Q_LOGGING_CATEGORY(ColoredSvgImageProviderLog, "QmlControls.ColoredSvgImageProvider")
10
12 : QQuickImageProvider(QQuickImageProvider::Image)
13{
14}
15
16QImage ColoredSvgImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
17{
18 qCDebug(ColoredSvgImageProviderLog) << "id:" << id << "requestedSize:" << requestedSize;
19
20 const qsizetype q = id.indexOf(QLatin1Char('?'));
21 if (q < 0) {
22 qCWarning(ColoredSvgImageProviderLog) << "missing ?color= in id:" << id;
23 return {};
24 }
25
26 QString path = id.left(q);
27 const QString query = id.mid(q + 1);
28
29 // Normalize "/foo" or "qrc:/foo" to a Qt resource path ":/foo".
30 if (path.startsWith(QLatin1String("qrc:/"))) {
31 path = path.mid(3);
32 } else if (path.startsWith(QLatin1Char('/'))) {
33 path = QLatin1Char(':') + path;
34 } else {
35 path = QStringLiteral(":/") + path;
36 }
37
38 QColor tint;
39 for (const QString &kv : query.split(QLatin1Char('&'), Qt::SkipEmptyParts)) {
40 if (kv.startsWith(QLatin1String("color="))) {
41 tint = QColor(QLatin1Char('#') + kv.mid(6));
42 break;
43 }
44 }
45 if (!tint.isValid()) {
46 qCWarning(ColoredSvgImageProviderLog) << "invalid color in id:" << id;
47 return {};
48 }
49
50 const bool isSvg = QFileInfo(path).suffix().compare(QLatin1String("svg"), Qt::CaseInsensitive) == 0;
51
52 QSize outSize = requestedSize;
53 QImage rendered;
54
55 // QML callers commonly set only sourceSize.height, leaving width=0 ("scale by aspect").
56 // Fill the missing dim from the source's intrinsic aspect so we rasterize at the final
57 // display resolution rather than defaultSize() and let Image scale it (blurry).
58 auto fillMissingDim = [](QSize req, QSize intrinsic) -> QSize {
59 if (intrinsic.width() <= 0 || intrinsic.height() <= 0) {
60 return req;
61 }
62 const bool hasW = req.width() > 0;
63 const bool hasH = req.height() > 0;
64 if (hasW && !hasH) {
65 return {req.width(), qRound(req.width() * (qreal(intrinsic.height()) / intrinsic.width()))};
66 }
67 if (hasH && !hasW) {
68 return {qRound(req.height() * (qreal(intrinsic.width()) / intrinsic.height())), req.height()};
69 }
70 return req;
71 };
72
73 if (isSvg) {
74 QSvgRenderer renderer(path);
75 if (!renderer.isValid()) {
76 qCWarning(ColoredSvgImageProviderLog) << "QSvgRenderer rejected:" << path;
77 return {};
78 }
79 // Default is IgnoreAspectRatio — would distort the icon when target size isn't square.
80 renderer.setAspectRatioMode(Qt::KeepAspectRatio);
81 outSize = fillMissingDim(outSize, renderer.defaultSize());
82 if (outSize.width() <= 0 || outSize.height() <= 0) {
83 outSize = renderer.defaultSize();
84 }
85 outSize = outSize.expandedTo(QSize(1, 1));
86 rendered = QImage(outSize, QImage::Format_ARGB32_Premultiplied);
87 rendered.fill(Qt::transparent);
88 QPainter p(&rendered);
89 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
90 renderer.render(&p);
91 } else {
92 QImage src(path);
93 if (src.isNull()) {
94 qCWarning(ColoredSvgImageProviderLog) << "failed to load:" << path;
95 return {};
96 }
97 outSize = fillMissingDim(outSize, src.size());
98 if (outSize.width() > 0 && outSize.height() > 0 && outSize != src.size()) {
99 src = src.scaled(outSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
100 }
101 outSize = src.size().expandedTo(QSize(1, 1));
102 rendered = src.convertToFormat(QImage::Format_ARGB32_Premultiplied);
103 }
104
105 // SourceIn replaces RGB but preserves the source alpha mask — exactly the old ColorOverlay semantic.
106 QPainter p(&rendered);
107 p.setCompositionMode(QPainter::CompositionMode_SourceIn);
108 p.fillRect(rendered.rect(), tint);
109 p.end();
110
111 if (size != nullptr) {
112 *size = outSize;
113 }
114 return rendered;
115}
Image provider that rasterizes an SVG (or any QImage-loadable Qt resource)
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) final