diff --git a/cockatrice/src/client/ui/pixel_map_generator.cpp b/cockatrice/src/client/ui/pixel_map_generator.cpp index 670a18873..350bdb5d1 100644 --- a/cockatrice/src/client/ui/pixel_map_generator.cpp +++ b/cockatrice/src/client/ui/pixel_map_generator.cpp @@ -9,6 +9,40 @@ #include #include +/** + * 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 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 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; }