preserve image quality when scaling svg (#5554)

* preserve image quality when scaling svg

* fix missing colorless counter

* do it in a way that doesn't cause warnings to be logged
This commit is contained in:
RickyRister 2025-02-02 18:50:21 -08:00 committed by GitHub
parent c00b41f3bd
commit f782bd709a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -9,6 +9,40 @@
#include <QPalette>
#include <QSvgRenderer>
/**
* Loads in an svg from file and scales it without affecting image quality.
*
* @param svgPath The path to the svg file. Automatically appends ".svg" to the end if not present
* @param size The desired size of the pixmap
*
* @return The svg loaded into a Pixmap with the given size, or an empty Pixmap if the loading failed.
*/
static QPixmap loadSvg(const QString &svgPath, const QSize &size)
{
QString path = svgPath;
if (!path.endsWith(".svg")) {
path += ".svg";
}
QSvgRenderer svgRenderer(path);
if (!svgRenderer.isValid()) {
qCWarning(PixelMapGeneratorLog) << "Failed to load" << path;
return {};
}
// Makes sure the pixmap is at least as large as the svg, so that we don't lose any detail.
// QIcon.pixmap(size) will automatically scale down the image, but it won't scale it up.
QPixmap pix(svgRenderer.defaultSize().expandedTo(size));
pix.fill(Qt::transparent);
QPainter pixPainter(&pix);
svgRenderer.render(&pixPainter);
// Converting the pixmap to a QIcon and back is the easiest way to scale down a svg without affecting image quality
return QIcon(pix).pixmap(size);
}
QMap<QString, QPixmap> PhasePixmapGenerator::pmCache;
QPixmap PhasePixmapGenerator::generatePixmap(int height, QString name)
@ -17,8 +51,7 @@ QPixmap PhasePixmapGenerator::generatePixmap(int height, QString name)
if (pmCache.contains(key))
return pmCache.value(key);
QPixmap pixmap =
QPixmap("theme:phases/" + name).scaled(height, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmap pixmap = loadSvg("theme:phases/" + name, QSize(height, height));
pmCache.insert(key, pixmap);
return pixmap;
@ -28,20 +61,25 @@ QMap<QString, QPixmap> CounterPixmapGenerator::pmCache;
QPixmap CounterPixmapGenerator::generatePixmap(int height, QString name, bool highlight)
{
// The colorless counter is named "x" by the server but the file is named "general.svg"
if (name == "x") {
name = "general";
}
if (highlight)
name.append("_highlight");
QString key = name + QString::number(height);
if (pmCache.contains(key))
return pmCache.value(key);
QPixmap pixmap =
QPixmap("theme:counters/" + name).scaled(height, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmap pixmap = loadSvg("theme:counters/" + name, QSize(height, height));
// fall back to colorless counter if the name can't be found
if (pixmap.isNull()) {
name = "general";
if (highlight)
name.append("_highlight");
pixmap =
QPixmap("theme:counters/" + name).scaled(height, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
pixmap = loadSvg("theme:counters/" + name, QSize(height, height));
}
pmCache.insert(key, pixmap);
@ -85,12 +123,12 @@ QPixmap CountryPixmapGenerator::generatePixmap(int height, const QString &countr
return pmCache.value(key);
int width = height * 2;
QPixmap pixmap = QPixmap("theme:countries/" + countryCode.toLower())
.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmap pixmap = loadSvg("theme:countries/" + countryCode.toLower(), QSize(width, height));
QPainter painter(&pixmap);
painter.setPen(Qt::black);
painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
// determined through trial-and-error that /2 maps the pixmap coords to the painter coords
painter.drawRect(0, 0, pixmap.width() / 2, pixmap.height() / 2);
pmCache.insert(key, pixmap);
return pixmap;
@ -239,8 +277,7 @@ QIcon UserLevelPixmapGenerator::generateIconDefault(int height,
levelString.append("_buddy");
}
auto pixmap = QPixmap("theme:userlevels/" + levelString)
.scaled(height, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
auto pixmap = loadSvg("theme:userlevels/" + levelString, QSize(height, height));
QIcon icon(pixmap);
iconCache.insert(key, icon);
return icon;
@ -286,7 +323,7 @@ QPixmap LockPixmapGenerator::generatePixmap(int height)
if (pmCache.contains(key))
return pmCache.value(key);
QPixmap pixmap = QPixmap("theme:icons/lock").scaled(height, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmap pixmap = loadSvg("theme:icons/lock", QSize(height, height));
pmCache.insert(key, pixmap);
return pixmap;
}