QColor для человека читаемой строки - PullRequest
0 голосов
/ 18 марта 2020

У меня есть цветовой объект в QML, который я считаю экземпляром QColor, используя отладчик, который, как я вижу, содержит цветовой объект:

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

Есть ли способ перевести это в читабельный для человека строка, например красная?

Ответы [ 3 ]

1 голос
/ 19 марта 2020

Цвета - сложный топи c. (Если вы когда-либо подключали два экрана к компьютеру и пытались настроить их для одинаковых цветовых профилей, вы понимаете, о чем я.)

Тем не менее, я считаю, что намерение OP разумно. Если Qt может обрабатывать понятные человеку названия цветов, почему это не должно быть обратимо?

Сначала я посмотрел в руководство - QColor :

Цвет можно установить, передав строку RGB (например, «# 112233») или строку ARGB (например, «# ff112233») или имя цвета (например, «синий»), в функция setNamedColor () . Названия цветов взяты из имен цветов SVG 1.0. Функция name () возвращает имя цвета в формате "#RRGGBB".

Утверждение о QColor::name() звучит точно так же, как описано в OP. Чтобы полностью убедить себя, я сделал MCVE, но это ничего не изменило.

ОК. Итак, это не ошибка - это особенность.

Если в Qt этого нет, как это можно добавить? Кажется, Qt «знает» все имена. Таким образом, было бы неприятно, если бы это нельзя было как-то использовать.

Я немного нажал на do c. и найдено, например, в do c. из QColor :: setNamedColor ссылка для таблицы SVG Color Names .

Итак, я рассмотрел на секунду просто скопировать его.

Я также нашел SVG Colors . Пожалуйста, обратите внимание, что он отмечен как

Так как: Qt 5.14

и все еще часть qt5-dev do c. (на момент написания этой статьи).

На woboq.org я наткнулся на ответственный исходный код для имен цветов в 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 () :

QStringList QColor :: colorNames () [статические]

Возвращает QStringList , содержащий имена цветов, о которых Qt знает.

См. Также Предопределенные цвета .

Со списком всех названий цветов (которые может распознать Qt) легко построить таблицу обратного отображения.

Я сделал 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.

SO: Как специализировать std :: ha sh :: operator () для пользовательского типа в неупорядоченных контейнерах )

0 голосов
/ 19 марта 2020

Это не так просто, как кажется, потому что люди всегда видят цвета в контексте. Итак, если вы хотите получить ответ на вопрос «как бы человек назвал цвет», это будет сложно. Контекст нельзя отделить от такой классификации. Даже то, что мы можем назвать «без контекста», например, карта образца цвета с равномерной подсветкой на глубоком черном фоне в затемненной комнате, является контекстом - на самом деле маловероятным и, возможно, нелогичным таким «изолированным» цветовым представлением, хотя полезен для получения воспроизводимых результатов (если люди вообще согласны с названиями цветов), не очень хорошо согласуется с общим сценарием ios, в котором происходит присвоение имен цветам - это такая же «странная» ситуация, как вы можете себе представить , Мы не называем цвета в лабораторных условиях, обычно. Поэтому я предполагаю, что, возможно, это не то, что вам нужно.

Но похоже, что, возможно, вас это мало заботит, а скорее просто сопоставят строку и тройку RGB. Вы можете go для разреженного отображения: используйте список имен цветов, например, этот , и выполните самый простой 32-битный поиск RGBA-в-строке, используя контейнер с индексом разреженных ключей, такой как QMap или QHash. Получите ключ от QColor::rgba(). Таким образом, большинству цветов не будет присвоено имя, но семантика именования, которую вы выполняете, очень проста: либо это точная тройка RGB из «управляемого» списка, либо это не так.

В качестве альтернативы вы можете выбрать произвольную метрику c из "эта достаточно близка" и назначить одно и то же имя для группы "соседних" цветов. Это совершенно произвольно, потому что на практике контекст диктует то, что человек считает «одним цветом». Но для некоторых случаев простота сопоставления более важна, чем сопоставление, представляющее зрительное восприятие человека.

Как только вы решите "собрать воедино" "близлежащие" цвета, вы можете устранить неоднозначность с некоторым префиксом, например #FF0000 может быть red, но #EE0000 может отображаться как almost red или closest to red (это зависит от выбора метрического расстояния c, длина разностного вектора RGB равна одному жизнеспособному метри c). Вы можете выбрать классификацию на основе более целевого свойства, например, всем цветам с одинаковым QColor::hue() может быть присвоено одинаковое базовое имя, если насыщенность и значение превышают некоторый порог (#0100001 не очень похож на красный для всех, хотя это "чистый" красный). Это будет зависеть от того, для чего вам нужно название. Если вы хотите получить обход без потерь между строками «Engli sh» и тройками RGB, вы мало что можете сделать, кроме как взять большой список цветов (например, получить лицензию для системы Pantone) и использовать его, хотя и явно » окрашивание «цветов, которые не соответствуют префиксу« почти »или« как ».

Еще одна проблема заключается в том, что RGB-тройки сами по себе не имеют большого значения. Что-то вроде калиброванного цветового пространства должно go с этим, как CIE RGB или sRGB. К сожалению, QColor не несет эту информацию.

Для развлечения вы можете взглянуть на Параметр c Модель для вычислительного именования цветов :)

0 голосов
/ 18 марта 2020

Не совсем то, что мне было нужно, однако я добавил в CPP подпрограмму для получения объекта с помощью метода .name () QColor. Я перевел объект обратно в строку, но он возвращает шестнадцатеричное представление значение 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;
    }

Мне нужно было просто, мне нужны были только красный, зеленый и синий.

...