Qtの色変換をマスター:toExtendedRgb()の代替メソッドと活用例

2025-05-27

「拡張 RGB」とは?

通常の RGB カラーモデルでは、各コンポーネント(赤、緑、青)の値は通常 0 から 255 の整数で表現されます。これは 8 ビットの精度に相当します。

しかし、HDR (High Dynamic Range) の画像処理など、より広い色域やより高い精度が必要な場合、浮動小数点数(通常は float または double)で RGB 値を表現することがあります。これが「拡張 RGB」の考え方です。Qt における toExtendedRgb() は、各コンポーネントが 0.0 から 1.0 の浮動小数点数で表現される RGB 値を持つ QColor オブジェクトを返します。

なぜ toExtendedRgb() を使うのか?

この関数が役立つ主なケースは以下の通りです。

  1. 高精度な色表現が必要な場合
    HDR イメージの処理や、非常に微妙な色のグラデーションを扱う場合など、8 ビット RGB では表現しきれない色情報を保持したいときに使用します。

  2. 他の浮動小数点数ベースのカラーシステムとの連携
    OpenGL や Vulkan などのグラフィックス API では、色のコンポーネントを 0.0 から 1.0 の浮動小数点数で扱うのが一般的です。toExtendedRgb() を使用することで、Qt の QColor オブジェクトからこれらの API に直接渡せる形式で色データを取得できます。

  3. 色の線形補間など
    浮動小数点数で表現された色値は、線形補間(LOD など)を行う際に、より正確な結果をもたらします。

#include <QColor>
#include <QDebug>

int main() {
    // 通常の255ベースのRGB色を作成
    QColor originalColor(255, 128, 0); // オレンジ色

    // 拡張RGB形式に変換
    QColor extendedRgbColor = originalColor.toExtendedRgb();

    // 拡張RGBの各コンポーネント(0.0-1.0)を取得
    qreal r = extendedRgbColor.redF();
    qreal g = extendedRgbColor.greenF();
    qreal b = extendedRgbColor.blueF();
    qreal a = extendedRgbColor.alphaF(); // アルファ値も同様に0.0-1.0

    qDebug() << "Original RGB: (" << originalColor.red() << ","
             << originalColor.green() << "," << originalColor.blue() << ")";
    qDebug() << "Extended RGB: (" << r << "," << g << "," << b << "," << a << ")";

    // 別の色を拡張RGBで作成することも可能
    QColor customExtendedColor;
    customExtendedColor.setRedF(0.5);
    customExtendedColor.setGreenF(0.2);
    customExtendedColor.setBlueF(0.8);
    customExtendedColor.setAlphaF(1.0); // 不透明

    qDebug() << "Custom Extended RGB: (" << customExtendedColor.redF() << ","
             << customExtendedColor.greenF() << "," << customExtendedColor.blueF() << ")";

    return 0;
}

このコードを実行すると、以下のような出力が得られます。

Original RGB: ( 255 , 128 , 0 )
Extended RGB: ( 1 , 0.501961 , 0 , 1 ) // 255/255=1, 128/255=0.501961
Custom Extended RGB: ( 0.5 , 0.2 , 0.8 )


Qt の QColor QColor::toExtendedRgb() 関数自体は非常にシンプルで、通常、それ単体で直接的なエラーを引き起こすことは稀です。この関数が問題を発生させるとすれば、それは通常、その変換結果の利用方法に起因します。

以下に、toExtendedRgb() に関連する一般的なエラーとトラブルシューティングについて説明します。

誤解: toExtendedRgb() が色空間変換を行うと誤解する

エラーの症状
toExtendedRgb() を呼び出すことで、色が線形RGBに変換されたり、広色域に変換されたりすると誤解し、期待した色の表示が得られない。

説明
toExtendedRgb() は、単に内部の色の表現形式(通常は整数値)を、0.0〜1.0 の浮動小数点数に正規化して返すだけです。色空間の変換(例: sRGBからRec.2020への変換)や、ガンマ補正(線形RGBへの変換)は行いません。元の QColor オブジェクトがどのような色空間(sRGB、Display P3など)に属しているかによって、返される浮動小数点数もその色空間の値を反映します。

トラブルシューティング

  • ガンマ補正の考慮
    多くのディスプレイは非線形なガンマ補正が適用されています。もし物理的な輝度に対応する「線形RGB」の値が欲しい場合は、toExtendedRgb() で得られた値にガンマ補正の逆変換(通常は x2.2 など)を適用する必要があります。
  • 色空間の理解
    Qt の QColor は、通常 sRGB 色空間を仮定しています。もし別の色空間の色を扱いたいのであれば、別途色空間変換の処理(ICCプロファイルなど)を行う必要があります。

精度の損失: 浮動小数点数の丸め誤差

エラーの症状
toExtendedRgb() で得られた浮動小数点数を再度整数値の RGB に戻した際に、元の色とわずかに異なる。

説明
浮動小数点数(floatdouble)は有限の精度しか持たないため、特に 0.0〜1.0 の範囲に正規化された値を再び 0〜255 の整数に戻す際に、わずかな丸め誤差が生じることがあります。

トラブルシューティング

  • 必要性の再検討
    そもそも「拡張 RGB」が必要なのかを再検討してください。最終的に整数値の RGB に戻すのであれば、中間で浮動小数点数に変換する手間や誤差を避けるために、最初から整数値の RGB で処理を完結できないか確認してください。
  • qRound や qFuzzyCompare の利用
    比較を行う際には、直接 == で比較するのではなく、qFuzzyCompare のような近似比較関数を使用するか、適切な丸め(qRound など)を適用してから比較することを検討してください。
  • 誤差の許容
    ほとんどの場合、このわずかな誤差は視覚的に知覚できるレベルではありません。許容範囲内であれば、特に問題視する必要はありません。

他のシステムや API との連携における不一致

エラーの症状
toExtendedRgb() で得られた色値を OpenGL やカスタムシェーダーなどの外部グラフィックシステムに渡した際に、期待通りの色が表示されない。

説明
これは、外部システムが期待する浮動小数点数の範囲や、色空間の解釈が Qt の QColor と異なる場合に発生します。例えば、OpenGL の多くの関数は 0.0〜1.0 の範囲を期待しますが、一部のシェーダーでは異なる範囲を仮定しているかもしれません。また、シェーダーが線形RGBを期待しているのに、toExtendedRgb() が返す非線形(ガンマ補正済み)の値をそのまま渡している、といったケースも考えられます。

トラブルシューティング

  • アルファ値の扱い
    アルファ値も同様に、0.0〜1.0 の範囲で正しく扱われているか確認してください。プリマルチプライドアルファなど、特殊なアルファの扱いが必要な場合もあります。
  • ガンマ補正の適用/解除
    外部システムが線形RGBを期待している場合は、toExtendedRgb() で得られた値にガンマ補正の逆変換を適用して線形化する必要があります。逆に、非線形な値を表示したい場合は、最後にガンマ補正を適用します。
  • 値のスケール調整
    外部システムが 0.0〜1.0 以外の範囲(例: -1.0〜1.0)を期待している場合、適宜値をスケーリングする必要があります。
  • 外部システムのドキュメント確認
    連携する外部グラフィックライブラリや API が、色の各コンポーネントにどのような値の範囲と色空間を期待しているかを正確に確認してください。

エラーの症状
無効な QColor オブジェクトに対して toExtendedRgb() を呼び出し、結果が意図しないものになる。

説明
QColor オブジェクトは、無効な状態(例: デフォルトコンストラクタで初期化された後、色が設定されていない場合)であることがあります。isValid() メソッドで確認できます。無効な色を変換しても、意味のある結果は得られません。

トラブルシューティング

  • isValid() の確認
    toExtendedRgb() を呼び出す前に、QColor オブジェクトが isValid() であることを確認してください。
    QColor myColor; // 無効な状態
    // myColor.setRgb(255, 0, 0); // これで有効になる
    
    if (myColor.isValid()) {
        QColor extended = myColor.toExtendedRgb();
        // ... 処理 ...
    } else {
        qWarning() << "QColor object is invalid!";
    }
    

QColor QColor::toExtendedRgb() 自体は単なるデータ変換関数であり、Qt の内部で安定して動作します。問題が発生する場合のほとんどは、その結果として得られる浮動小数点数の RGB 値が、次の処理段階で期待される形式や意味と一致しないことが原因です。

トラブルシューティングの鍵は、以下の点を明確にすることです。

  1. 元の QColor オブジェクトの色空間は何か?
  2. toExtendedRgb() が返す浮動小数点数の RGB 値が示すのは何か?
  3. その浮動小数点数の RGB 値を渡す先のシステムや API が期待する形式、範囲、色空間は何か?


基本的な使用法:整数RGBから浮動小数点RGBへ

最も基本的な使用例は、通常の 0-255 の整数値で表現された色を、浮動小数点数で表現された色に変換することです。

#include <QColor>
#include <QDebug> // デバッグ出力用

int main() {
    // 1. 255段階の整数値で色を定義 (例: 鮮やかな赤)
    QColor originalColor(255, 0, 0); // R=255, G=0, B=0, A=255 (不透明)

    qDebug() << "元の色 (整数値):"
             << "R:" << originalColor.red()
             << "G:" << originalColor.green()
             << "B:" << originalColor.blue()
             << "A:" << originalColor.alpha();

    // 2. toExtendedRgb() を使って拡張RGB (浮動小数点数) に変換
    QColor extendedRgbColor = originalColor.toExtendedRgb();

    // 3. 変換後の浮動小数点数の各コンポーネントを取得
    //    redF(), greenF(), blueF(), alphaF() を使用
    qreal r = extendedRgbColor.redF();
    qreal g = extendedRgbColor.greenF();
    qreal b = extendedRgbColor.blueF();
    qreal a = extendedRgbColor.alphaF();

    qDebug() << "拡張RGB (浮動小数点数):"
             << "R:" << r
             << "G:" << g
             << "B:" << b
             << "A:" << a;

    // 検証: 255/255 = 1.0, 0/255 = 0.0 となるはずです
    // Qt::red は Qt::GlobalColor の一つで、(255,0,0) を表します
    QColor qtRed = Qt::red;
    QColor extendedQtRed = qtRed.toExtendedRgb();
    qDebug() << "Qt::red の拡張RGB:"
             << "R:" << extendedQtRed.redF()
             << "G:" << extendedQtRed.greenF()
             << "B:" << extendedQtRed.blueF()
             << "A:" << extendedQtRed.alphaF();


    return 0;
}

出力例

元の色 (整数値): R: 255 G: 0 B: 0 A: 255
拡張RGB (浮動小数点数): R: 1 G: 0 B: 0 A: 1
Qt::red の拡張RGB: R: 1 G: 0 B: 0 A: 1

浮動小数点数RGBから QColor オブジェクトの作成

toExtendedRgb() は既存の QColor を変換するのに使いますが、0.0-1.0 の浮動小数点数から直接 QColor を作成することもできます。これは、外部のデータ(例: OpenGLのテクスチャデータ)から色を読み込む場合に便利です。

#include <QColor>
#include <QDebug>

int main() {
    // 0.0 から 1.0 の範囲で浮動小数点数の色値を定義
    qreal floatR = 0.5;  // 50% の赤
    qreal floatG = 0.25; // 25% の緑
    qreal floatB = 0.75; // 75% の青
    qreal floatA = 0.8;  // 80% の不透明度

    // QColor::fromRgbF() を使って浮動小数点数の色値から QColor を作成
    QColor colorFromFloat = QColor::fromRgbF(floatR, floatG, floatB, floatA);

    qDebug() << "浮動小数点数から作成された色 (浮動小数点数):"
             << "R:" << colorFromFloat.redF()
             << "G:" << colorFromFloat.greenF()
             << "B:" << colorFromFloat.blueF()
             << "A:" << colorFromFloat.alphaF();

    // 整数値に戻して確認
    qDebug() << "浮動小数点数から作成された色 (整数値):"
             << "R:" << colorFromFloat.red() // 約 0.5 * 255 = 127.5 -> 128
             << "G:" << colorFromFloat.green() // 約 0.25 * 255 = 63.75 -> 64
             << "B:" << colorFromFloat.blue() // 約 0.75 * 255 = 191.25 -> 191
             << "A:" << colorFromFloat.alpha(); // 約 0.8 * 255 = 204
    return 0;
}

出力例

浮動小数点数から作成された色 (浮動小数点数): R: 0.5 G: 0.25 B: 0.75 A: 0.8
浮動小数点数から作成された色 (整数値): R: 128 G: 64 B: 191 A: 204

グラフィックス API (例: OpenGL) との連携

toExtendedRgb() の主な用途の一つは、OpenGL などのグラフィックス API に色データを渡す際です。これらの API は通常、色のコンポーネントを 0.0 から 1.0 の浮動小数点数として期待します。

この例では、QColorQPainter で描画する簡単なウィジェットを作成し、その色を拡張 RGB で取得してデバッグ出力します。実際の OpenGL コードは複雑になるため、ここでは擬似コードで概念を示します。

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QColor>
#include <QDebug>

class ColorDisplayWidget : public QWidget {
public:
    ColorDisplayWidget(QWidget *parent = nullptr) : QWidget(parent) {
        setWindowTitle("QColor toExtendedRgb() Example");
        resize(300, 200);
        _displayColor = QColor(200, 100, 50, 255); // 少しオレンジがかった色
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        Q_UNUSED(event);
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);

        // ウィジェットの背景を toExtendedRgb() で取得した色で塗りつぶす(デモンストレーション目的)
        // 実際には、QPainter には QColor を直接渡すことができます。
        // ここでは、一旦浮動小数点数に変換してから使用する例としています。
        QColor extendedColor = _displayColor.toExtendedRgb();

        qreal r = extendedColor.redF();
        qreal g = extendedColor.greenF();
        qreal b = extendedColor.blueF();
        qreal a = extendedColor.alphaF();

        qDebug() << "描画する色 (拡張RGB):"
                 << "R:" << r
                 << "G:" << g
                 << "B:" << b
                 << "A:" << a;

        // QPainter は QColor を直接受け取れますが、
        // 浮動小数点数から新しい QColor を作成してセットすることも可能
        painter.fillRect(rect(), QColor::fromRgbF(r, g, b, a));

        // 擬似コード: OpenGL に色を渡す例
        // float gl_color[4] = { r, g, b, a };
        // glColor4fv(gl_color); // またはシェーダーのuniform変数に渡す
    }

private:
    QColor _displayColor;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    ColorDisplayWidget widget;
    widget.show();

    return app.exec();
}

出力例 (ウィジェットが表示され、デバッグ出力もされます)

描画する色 (拡張RGB): R: 0.784314 G: 0.392157 B: 0.196078 A: 1

色を線形に補間する場合、通常はガンマ補正されていない線形RGB空間で計算を行うのが望ましいとされています。toExtendedRgb() は、各コンポーネントを 0.0-1.0 の範囲に正規化してくれるため、この線形補間計算に適しています。

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QColor>
#include <QDebug>
#include <cmath> // pow, sqrt 用

// ガンマ補正を考慮した線形補間を行うウィジェット
class InterpolatedColorWidget : public QWidget {
public:
    InterpolatedColorWidget(QWidget *parent = nullptr) : QWidget(parent) {
        setWindowTitle("Color Interpolation Example");
        resize(400, 200);
        _color1 = QColor(255, 0, 0); // 赤
        _color2 = QColor(0, 0, 255); // 青
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        Q_UNUSED(event);
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);

        // ガンマ補正値 (一般的なsRGBのガンマは2.2)
        const qreal GAMMA = 2.2;
        const qreal INV_GAMMA = 1.0 / GAMMA;

        // 開始色と終了色を拡張RGBに変換
        QColor extColor1 = _color1.toExtendedRgb();
        QColor extColor2 = _color2.toExtendedRgb();

        // 線形RGB空間に変換(ガンマ補正解除)
        qreal r1_linear = qPow(extColor1.redF(), GAMMA);
        qreal g1_linear = qPow(extColor1.greenF(), GAMMA);
        qreal b1_linear = qPow(extColor1.blueF(), GAMMA);

        qreal r2_linear = qPow(extColor2.redF(), GAMMA);
        qreal g2_linear = qPow(extColor2.greenF(), GAMMA);
        qreal b2_linear = qPow(extColor2.blueF(), GAMMA);

        int steps = width(); // ウィジェットの幅を補間ステップ数とする

        for (int i = 0; i < steps; ++i) {
            qreal t = (qreal)i / (steps - 1); // 0.0 から 1.0 の補間係数

            // 線形RGB空間で補間
            qreal interpolatedR_linear = r1_linear * (1.0 - t) + r2_linear * t;
            qreal interpolatedG_linear = g1_linear * (1.0 - t) + g2_linear * t;
            qreal interpolatedB_linear = b1_linear * (1.0 - t) + b2_linear * t;

            // ディスプレイ表示のためにガンマ補正を再適用
            qreal displayR = qPow(interpolatedR_linear, INV_GAMMA);
            qreal displayG = qPow(interpolatedG_linear, INV_GAMMA);
            qreal displayB = qPow(interpolatedB_linear, INV_GAMMA);

            // QColor を浮動小数点数から作成
            QColor interpolatedColor = QColor::fromRgbF(displayR, displayG, displayB);

            painter.setPen(interpolatedColor);
            painter.drawLine(i, 0, i, height());
        }
    }

private:
    QColor _color1;
    QColor _color2;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    InterpolatedColorWidget widget;
    widget.show();

    return app.exec();
}

この補間例では、toExtendedRgb() が、ガンマ補正を解除して線形空間で計算を行うための最初のステップとして使用されています。これにより、より視覚的に自然な色のグラデーションが得られます。



ここでは、toExtendedRgb() の代替となる方法や、関連するプログラミングアプローチについて説明します。

各コンポーネントを個別に取得して手動で正規化する

toExtendedRgb() は新しい QColor オブジェクトを返しますが、元の QColor オブジェクトから各 RGB コンポーネントを整数値で取得し、それを手動で 255.0 で割って正規化することも可能です。これは最も直接的な代替方法であり、toExtendedRgb() の内部で行われていることとほぼ同じです。

#include <QColor>
#include <QDebug>

int main() {
    QColor myColor(128, 64, 192, 255); // 赤:128, 緑:64, 青:192, 不透明

    // 各コンポーネントを整数値で取得
    int r_int = myColor.red();
    int g_int = myColor.green();
    int b_int = myColor.blue();
    int a_int = myColor.alpha();

    // 手動で 0.0-1.0 の範囲に正規化
    qreal r_float = static_cast<qreal>(r_int) / 255.0;
    qreal g_float = static_cast<qreal>(g_int) / 255.0;
    qreal b_float = static_cast<qreal>(b_int) / 255.0;
    qreal a_float = static_cast<qreal>(a_int) / 255.0;

    qDebug() << "手動正規化 RGBF: (" << r_float << "," << g_float << "," << b_float << "," << a_float << ")";

    // toExtendedRgb() と比較
    QColor extendedColor = myColor.toExtendedRgb();
    qDebug() << "toExtendedRgb() RGBF: (" << extendedColor.redF() << ","
             << extendedColor.greenF() << "," << extendedColor.blueF() << ","
             << extendedColor.alphaF() << ")";

    return 0;
}

利点
非常に明確で、toExtendedRgb() を呼び出す追加の QColor オブジェクトを作成する必要がないため、わずかなパフォーマンスの向上が期待できる可能性があります(通常は無視できるレベル)。 欠点: 複数のコンポーネントを扱う場合、コードが冗長になる可能性があります。

getRgbF() を使用する

QColor クラスには、getRgbF() というヘルパー関数も用意されており、これは引数として浮動小数点数のポインタを受け取り、そこに正規化された RGB コンポーネントを格納します。これは toExtendedRgb() と同様に浮動小数点数表現を取得しますが、新しい QColor オブジェクトを返さずに既存の変数を埋める点が異なります。

#include <QColor>
#include <QDebug>

int main() {
    QColor myColor(128, 64, 192, 255);

    qreal r, g, b, a;
    myColor.getRgbF(&r, &g, &b, &a); // ポインタを渡して値を埋める

    qDebug() << "getRgbF() RGBF: (" << r << "," << g << "," << b << "," << a << ")";

    return 0;
}

利点
新しい QColor オブジェクトの作成を避けつつ、各コンポーネントを一度に取得できます。 欠点: ポインタを扱う必要があります。

他の色空間に変換し、そこからRGB値を取得する

toExtendedRgb() は常に RGB 形式で返しますが、場合によっては HSV (Hue, Saturation, Value) や HSL (Hue, Saturation, Lightness) などの他色空間の浮動小数点表現が必要になることがあります。

QColor は、これらの色空間にも浮動小数点数でアクセスするためのメソッドを提供しています。

  • toCmyk() / cyanF(), magentaF(), yellowF(), blackF()
  • toHsl() / hslHueF(), hslSaturationF(), lightnessF()
  • toHsv() / hueF(), saturationF(), valueF()

これらのメソッドは、それぞれ対応する色空間の浮動小数点数を返します。

#include <QColor>
#include <QDebug>

int main() {
    QColor myColor(Qt::red); // 赤色

    // HSV に変換して浮動小数点値を取得
    QColor hsvColor = myColor.toHsv();
    qDebug() << "HSV (浮動小数点数): H:" << hsvColor.hueF()
             << "S:" << hsvColor.saturationF()
             << "V:" << hsvColor.valueF()
             << "A:" << hsvColor.alphaF();

    // HSL に変換して浮動小数点値を取得
    QColor hslColor = myColor.toHsl();
    qDebug() << "HSL (浮動小数点数): H:" << hslColor.hslHueF()
             << "S:" << hslColor.hslSaturationF()
             << "L:" << hslColor.lightnessF()
             << "A:" << hslColor.alphaF();

    return 0;
}

利点
特定の色空間での計算や表現が必要な場合に便利です。 欠点: RGB 以外の色空間への変換が必要な場合にのみ適用可能です。

QRgb 型と手動変換(非推奨または注意が必要)

QColor の内部表現は QRgb 型(unsigned int の typedef)であり、これは 0xAARRGGBB の形式で色を表します。一部のレガシーコードや低レベルなグラフィックス処理では、この QRgb 値を直接扱うことがあります。

QRgb から浮動小数点数 RGB を手動で計算することも可能ですが、これは通常推奨されません。

#include <QColor>
#include <QDebug>
#include <QtGlobal> // qRed, qGreen, qBlue, qAlpha 用

int main() {
    QColor myColor(128, 64, 192, 255);
    QRgb rgbValue = myColor.rgba(); // QColor::rgb() はアルファを無視するので注意

    // QRgb から各コンポーネントを抽出し、手動で正規化
    qreal r = static_cast<qreal>(qRed(rgbValue)) / 255.0;
    qreal g = static_cast<qreal>(qGreen(rgbValue)) / 255.0;
    qreal b = static_cast<qreal>(qBlue(rgbValue)) / 255.0;
    qreal a = static_cast<qreal>(qAlpha(rgbValue)) / 255.0;

    qDebug() << "QRgb 手動正規化 RGBF: (" << r << "," << g << "," << b << "," << a << ")";

    return 0;
}

利点
非常に低レベルな制御が可能。 欠点:

  • Qt の設計思想に反する
    QColor クラスが提供するより高レベルな抽象化を利用すべきです。
  • エラーの可能性
    QColor::rgb() はアルファチャネルを無視するため、rgba() を使用しないとアルファ値が失われる可能性があります。
  • 可読性が低い
    qRed(), qGreen(), qBlue(), qAlpha() といったマクロ(関数)を使用する必要があり、コードが読みにくくなります。

より高度な色処理、特に線形RGB空間への変換や、ICCプロファイルに基づいた厳密な色空間変換が必要な場合は、Qt 5.14 以降で導入された QColorSpace クラスと QColorTransform クラスを使用することが代替手段となり得ます。

toExtendedRgb() は、QColor の現在の RGB 値を 0.0-1.0 に正規化するだけで、色空間変換(例えば sRGB から線形 RGB へのガンマ補正の解除)は行いません。もし本当に「線形 RGB」の値が必要な場合、QColorSpace を使って明示的に変換するのが最も正確な方法です。

#include <QColor>
#include <QDebug>
#include <QColorSpace> // Qt 5.14以降

int main() {
    QColor srgbColor(255, 128, 0); // sRGB 空間のオレンジ色

    // sRGB 色空間を定義 (Qt の QColor はデフォルトで sRGB を仮定)
    QColorSpace srgbSpace = QColorSpace::SRgb;

    // 線形 sRGB 色空間を定義
    QColorSpace srgbLinearSpace = QColorSpace::SRgbLinear;

    // sRGB から線形 sRGB への変換トランスフォームを作成
    QColorTransform transform = srgbSpace.transformationToColorSpace(srgbLinearSpace);

    // 変換を適用
    QColor linearRgbColor = transform.map(srgbColor);

    qDebug() << "元のsRGB (255ベース): R:" << srgbColor.red()
             << "G:" << srgbColor.green()
             << "B:" << srgbColor.blue();

    qDebug() << "元のsRGB (拡張RGB): R:" << srgbColor.toExtendedRgb().redF()
             << "G:" << srgbColor.toExtendedRgb().greenF()
             << "B:" << srgbColor.toExtendedRgb().blueF();

    qDebug() << "線形RGB (拡張RGB): R:" << linearRgbColor.redF()
             << "G:" << linearRgbColor.greenF()
             << "B:" << linearRgbColor.blueF();

    // 比較: sRGBの0.5は線形ではもっと小さい値になるはず
    QColor midGraySrgb(128, 128, 128);
    QColor midGrayLinear = srgbSpace.transformationToColorSpace(srgbLinearSpace).map(midGraySrgb);
    qDebug() << "中間の灰色sRGB (拡張RGB): R:" << midGraySrgb.toExtendedRgb().redF();
    qDebug() << "中間の灰色線形RGB (拡張RGB): R:" << midGrayLinear.redF();


    return 0;
}

出力例

元のsRGB (255ベース): R: 255 G: 128 B: 0
元のsRGB (拡張RGB): R: 1 G: 0.501961 B: 0
線形RGB (拡張RGB): R: 1 G: 0.215861 B: 0
中間の灰色sRGB (拡張RGB): R: 0.501961
中間の灰色線形RGB (拡張RGB): R: 0.215861

toExtendedRgb() が 0.501961 を返すのに対し、線形変換後の値は 0.215861 と、かなり小さい値になっていることがわかります。これは、sRGB のガンマ補正が解除され、物理的な輝度により近い値になっているためです。

利点
色管理が重要なアプリケーションで、正確な色空間変換を行うことができます。 欠点: Qt 5.14 以降でしか利用できず、使用がより複雑になります。

QColor QColor::toExtendedRgb() は、QColor の整数値を 0.0-1.0 の浮動小数点数に正規化するための、シンプルで直接的な方法を提供します。

しかし、その代替となる方法や、より複雑な色処理が必要な場合は以下の選択肢があります。

  • 厳密な色管理
    真に「線形RGB」や他の定義された色空間への変換が必要な場合は、Qt 5.14以降の QColorSpaceQColorTransform を使用します。
  • 他色空間への変換
    HSV, HSL など、特定の目的で別の色空間の浮動小数点数表現が必要な場合に、対応する toXxx() 関数や xxxF() 関数を使用します。
  • 簡単な正規化
    各コンポーネントを個別に取得して手動で 255.0 で割るか、getRgbF() を使用します。