QColor到人类可读的字符串

问题描述 投票:0回答:3

我在QML中有一个颜色对象,我认为它是QColor的一个实例,使用调试器,我可以看到颜色对象包含:

    a                1
    b                0
    g                0
    hslHue           -1
    hslLightness     0
    hslSaturation    0
    hsvHue           -1
    hsvSaturation    0
    hsvValue         0
    r                0

是否有一种方法可以将其转换为人类可读的字符串,例如Red?

c++ qt tostring qcolor
3个回答
1
投票

颜色是一个困难的话题。 (如果您曾经将两个屏幕连接到计算机,并尝试将它们配置为相同的颜色配置文件,那么您知道我的意思。)

尽管如此,我认为OP的意图是合理的。如果Qt可以处理人类可读的颜色名称,为什么这不可逆?

首先,我看了一下手册– QColor

可以通过将RGB字符串(例如“#112233”)或ARGB字符串(例如“#ff112233”)或颜色名称(例如“ blue”)传递到setNamedColor()来设置颜色。功能。颜色名称取自SVG 1.0颜色名称。 name()函数以“ #RRGGBB”格式返回颜色的名称。

关于QColor::name()的陈述听起来很像OP所描述的。为了完全说服自己,我制作了一个MCVE,但它没有任何改变。

确定。因此,这不是错误,而是功能。

如果Qt中缺少它,如何添加? Qt似乎“知道”所有名称。因此,如果不能以某种方式加以利用,将很烦人。

我点击了一下文档。并发现例如在文档中。 QColor::setNamedColor的链接,指向SVG Color Names的表。

所以,我考虑了一秒钟只是为了复制它。

我也找到了SVG Colors。请注意,它带有[]

由于:Qt 5.14

并且仍然是qt5-dev文档的一部分。 (在撰写本文时)。

woboq.org上,我偶然发现了qtbase/src/gui/painting/qcolor.cpp中颜色名称的负责任源代码:

qtbase/src/gui/painting/qcolor.cpp

#ifndef QT_NO_COLORNAMES
/*
  CSS color names = SVG 1.0 color names + transparent (rgba(0,0,0,0))
*/
#ifdef rgb
#  undef rgb
#endif
#define rgb(r,g,b) (0xff000000 | (r << 16) |  (g << 8) | b)
static const struct RGBData {
    const char name[21];
    uint  value;
} rgbTbl[] = {
    { "aliceblue", rgb(240, 248, 255) },
    { "antiquewhite", rgb(250, 235, 215) },
    { "aqua", rgb( 0, 255, 255) },

最后,我以 { "yellow", rgb(255, 255, 0) }, { "yellowgreen", rgb(154, 205, 50) } }; static const int rgbTblSize = sizeof(rgbTbl) / sizeof(RGBData); #undef rgb 结尾:

[QColor::colorNames() QColor :: colorNames()[静态]

返回包含Qt知道的颜色名称的QStringList。>>

另请参见QStringList

具有所有颜色名称的列表(Qt可以识别),很容易建立反向映射表。

我做了一个Predefined Colors MCVE来证明这一点:

testQColorName.cc

输出:

#include <functional> #include <unordered_map> // Qt header: #include <QtWidgets> namespace std { template <> struct hash<QColor> { size_t operator()(const QColor &color) const { return std::hash<QRgb>()(color.rgb()); } }; } // namespace std typedef std::unordered_map<QColor, QString> ColorNameMap; class ColorButton: public QPushButton { private: QColor _qColor; public: explicit ColorButton( const QString &text = QString(), const QColor &qColor = Qt::black, QWidget *pQParent = nullptr): QPushButton(text, pQParent) { setColor(qColor); } virtual ~ColorButton() = default; ColorButton(const ColorButton&) = delete; ColorButton& operator=(const ColorButton&) = delete; const QColor& color() const { return _qColor; } void setColor(const QColor &qColor) { _qColor = qColor; QFontMetrics qFontMetrics(font()); const int h = qFontMetrics.height(); QPixmap qPixmap(h, h); qPixmap.fill(_qColor); setIcon(qPixmap); } QColor chooseColor() { setColor(QColorDialog::getColor(_qColor, this, text())); return _qColor; } }; // main application int main(int argc, char **argv) { qDebug() << "Qt Version:" << QT_VERSION_STR; QApplication app(argc, argv); // setup data const ColorNameMap qMapColorNames = []() { ColorNameMap qMapColorNames; const QStringList qColorNames = QColor::colorNames(); for (const QString &qColorName : qColorNames) { qMapColorNames[QColor(qColorName)] = qColorName; qDebug() << qColorName; } return qMapColorNames; }(); // setup GUI QWidget qWinMain; qWinMain.setWindowTitle(QString::fromUtf8("Test Color Name")); QHBoxLayout qHBox; QLabel qLblColor(QString::fromUtf8("Color:")); qHBox.addWidget(&qLblColor); QLineEdit qEditColor; qHBox.addWidget(&qEditColor, 1); ColorButton qBtnColor; qHBox.addWidget(&qBtnColor); qWinMain.setLayout(&qHBox); qWinMain.show(); qEditColor.setText(qBtnColor.color().name()); // install signal handlers QObject::connect(&qBtnColor, &QPushButton::clicked, [&]() { const QColor qColor = qBtnColor.chooseColor(); const ColorNameMap::const_iterator iter = qMapColorNames.find(qColor); qEditColor.setText(iter != qMapColorNames.end() ? iter->second : qColor.name()); }); QObject::connect(&qEditColor, &QLineEdit::textEdited, [&](const QString &text) { const QColor qColor(text); qBtnColor.setColor(qColor); }); // runtime loop return app.exec(); }

Snapshot of testQColorName (after text input)

控制台输出:

Snapshot of testQColorName (after chosing color #ff0000 with color button)

注意:

[似乎Qt Version: 5.13.0 "aliceblue" "antiquewhite" "aqua" "aquamarine" "azure" "beige" "bisque" "black" "blanchedalmond" "blue" "blueviolet" "brown" "burlywood" "cadetblue" "chartreuse" "chocolate" "coral" "cornflowerblue" "cornsilk" "crimson" "cyan" "darkblue" "darkcyan" "darkgoldenrod" "darkgray" "darkgreen" "darkgrey" "darkkhaki" "darkmagenta" "darkolivegreen" "darkorange" "darkorchid" "darkred" "darksalmon" "darkseagreen" "darkslateblue" "darkslategray" "darkslategrey" "darkturquoise" "darkviolet" "deeppink" "deepskyblue" "dimgray" "dimgrey" "dodgerblue" "firebrick" "floralwhite" "forestgreen" "fuchsia" "gainsboro" "ghostwhite" "gold" "goldenrod" "gray" "green" "greenyellow" "grey" "honeydew" "hotpink" "indianred" "indigo" "ivory" "khaki" "lavender" "lavenderblush" "lawngreen" "lemonchiffon" "lightblue" "lightcoral" "lightcyan" "lightgoldenrodyellow" "lightgray" "lightgreen" "lightgrey" "lightpink" "lightsalmon" "lightseagreen" "lightskyblue" "lightslategray" "lightslategrey" "lightsteelblue" "lightyellow" "lime" "limegreen" "linen" "magenta" "maroon" "mediumaquamarine" "mediumblue" "mediumorchid" "mediumpurple" "mediumseagreen" "mediumslateblue" "mediumspringgreen" "mediumturquoise" "mediumvioletred" "midnightblue" "mintcream" "mistyrose" "moccasin" "navajowhite" "navy" "oldlace" "olive" "olivedrab" "orange" "orangered" "orchid" "palegoldenrod" "palegreen" "paleturquoise" "palevioletred" "papayawhip" "peachpuff" "peru" "pink" "plum" "powderblue" "purple" "red" "rosybrown" "royalblue" "saddlebrown" "salmon" "sandybrown" "seagreen" "seashell" "sienna" "silver" "skyblue" "slateblue" "slategray" "slategrey" "snow" "springgreen" "steelblue" "tan" "teal" "thistle" "tomato" "transparent" "turquoise" "violet" "wheat" "white" "whitesmoke" "yellow" "yellowgreen" 的确提供了较少的内容(允许用作QColor中的键),也没有提供std::map的特殊化(允许用作std::hash中的键)。因此,我必须将std::unordered_map专门用于std::hash

QColor

不完全是我想要的,但是我向CPP添加了一个例程以使用QColor的.name()方法获取对象,我将对象转换回字符串,但是返回RGB值的十六进制表示法。

SO: How to specialize std::hash::operator() for user-defined type in unordered containers?

我的需求很简单,我只需要红色,绿色和蓝色。

这并不像听起来那样容易,因为人类总是会在上下文中看到颜色。因此,如果您想获得“人类将如何命名颜色”这个问题的答案,那将很难。上下文不能与此类分类分开。即使是我们可能称为“无上下文”的内容,例如在变黑的房间中的深黑色背景上均匀照明的颜色样本卡就是一种背景-实际上,这是不太可能的,并且可能与直觉相反的是这种“孤立的”颜色表示,虽然有助于给出可再现的结果(在人类同意的范围内)颜色名称),这与出现颜色命名的常见情况不太吻合-就像您可以想象的那样,这是一种“怪异”的情况。我们不在实验室环境中命名颜色,通常情况下不会如此。因此,我想也许这不是您所追求的。

但是看起来您可能对此不太在意,而只是在字符串和RGB三元组之间进行映射。您可以进行稀疏映射:使用颜色名称列表,例如 QString myClass::colourName(QColor colr) { QString hex = colr.name().toLower(); if ( hex.compare("#ff0000") == 0 ) { return "Red"; } else if ( hex.compare("#00ff00") == 0 ) { return "Green"; } else if ( hex.compare("#0000ff") == 0 ) { return "Blue"; } return hex; } ,并使用稀疏索引索引的容器(例如this oneQMap)执行最简单的32位RGBA到字符串查找。从QHash获取密钥。这样,大多数颜色将没有分配的名称,但是您执行的命名的语义非常简单:它是“可管理”列表中的精确RGB三元组,或者不是。

或者,您可能希望选择一些任意指标“这个足够接近”,并为一堆“附近”颜色分配相同的名称。这完全是任意的,因为在实践中上下文决定了人类会认为“相同颜色”的东西。但是对于某些用途,映射的简单性比表示人类视觉感知的映射更为重要。

[一旦您选择将各种颜色“聚在一起”,就可以使用一些前缀来消除歧义,例如QColor::rgba()可以是#FF0000,但是red可以显示为#EE0000almost red(这取决于距离度量的选择,RGB差向量的长度是一种可行的度量)。您可以选择将分类基于更具针对性的属性,例如只要饱和度和值都超过某个阈值,所有具有相同closest to red的颜色都可以使用相同的基本名称(对于任何人来说QColor::hue()看起来都不是红色,即使它是“纯”红色)。这将取决于您需要的名称。如果您想在“英文”字符串和RGB三元组之间进行无损往返,那么您无能为力,除了获取大量颜色列表(例如获得Pantone系统的许可证)并使用它,同时显式“污染”颜色不适合使用“几乎”或“喜欢”前缀的内容。

然而,另一个问题是RGB本身的三倍组合意义不大。校准后的色彩空间必须与之配合使用,例如#0100001CIE RGB。不幸的是,sRGB没有携带该信息。

[为了有趣,您可以看看QColor:)


0
投票

不完全是我想要的,但是我向CPP添加了一个例程以使用QColor的.name()方法获取对象,我将对象转换回字符串,但是返回RGB值的十六进制表示法。


0
投票

这并不像听起来那样容易,因为人类总是会在上下文中看到颜色。因此,如果您想获得“人类将如何命名颜色”这个问题的答案,那将很难。上下文不能与此类分类分开。即使是我们可能称为“无上下文”的内容,例如在变黑的房间中的深黑色背景上均匀照明的颜色样本卡就是一种背景-实际上,这是不太可能的,并且可能与直觉相反的是这种“孤立的”颜色表示,虽然有助于给出可再现的结果(在人类同意的范围内)颜色名称),这与出现颜色命名的常见情况不太吻合-就像您可以想象的那样,这是一种“怪异”的情况。我们不在实验室环境中命名颜色,通常情况下不会如此。因此,我想也许这不是您所追求的。

© www.soinside.com 2019 - 2024. All rights reserved.