試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

X Window Systemでnvidia,fglrx以外のドライバを用いた環境における明るさとガンマの調整について(ページ2/3)

X Window Systemでnvidia,fglrx以外のドライバを用いた環境における明るさとガンマの調整について(ページ1/3)」の続き。

自作のツールを作成

ページ1で扱った2つのツールは「明るさと各色成分ごとのガンマ補正を両方変更する」ということを実現するには不足があるため、何とかならないかとxbrightnessのソースを見たのだが、ライブラリlibXxf86vm(ヘッダファイルは/usr/include/X11/extensions/xf86vmode.h)のXF86VidModeSetGammaRamp()という関数を用いて明るさとガンマの変更を行っており、この関数自体は赤/緑/青の各色成分ごとの調整に対応していることが分かったので、自分でツールを作成してみることにした。
(2011/5/22)xrandrを用いることで明るさと色成分ごとのガンマを同時に設定できることが分かった。実行は

$ xrandr --output [出力先の名前] --gamma [赤ガンマ]:[緑ガンマ]:[青ガンマ] --brightness [明るさ]

の形で、出力先の名前は、引数を付けずに実行した場合に

$ xrandr
Screen 0: minimum 320 x 200, current 1280 x 1024, maximum 8192 x 8192
VGA-0 disconnected (normal left inverted right x axis y axis)
DVI-0 connected 1280x1024+0+0 (normal left inverted right x axis y axis) 376mm x 301mm
(以下略)

のように表示されるものを利用し、上の場合は「DVI-0」となる(「disconnected」な「VGA-0」ではない)。ガンマの指定値はxgammaとは逆で、明るさは0から1の範囲で指定する。なお、ハードウェア的な輝度の調整が可能な環境における輝度の調整については、ここで扱ったツールや「nvidia,fglrx以外のドライバ向けのX Window Systemの明るさとガンマのGUI調整ツールを作成」のツールではなく、xbacklightのようなものを先に試すのがよい。
以下は自作ツール作成上のメモとなる。

XF86VidModeSetGammaRamp()による明るさ/ガンマ調整のために必要なもの

XF86VidModeSetGammaRamp()X11のディスプレイとスクリーン以外に

  • ガンマランプのサイズ
  • 色成分ごと(赤,緑,青のそれぞれ)のガンマランプの配列の場所

が引数に必要となる。
ガンマランプというのは「各色成分の強さの段階ごとガンマ補正後の実際に出力される強さの値」を順に並べた符合なしshort型の配列で、それぞれの値は0 - 65535の範囲となる。この配列に含まれるデータの並びが色曲線のデータとなる。
ガンマランプのサイズというのはこの段階数(配列長)で、XF86VidModeGetGammaRampSize()で取得した値を用いる。

処理の流れ

処理の流れとしては以下のようになる。

  1. OpenDisplay()X Window Systemのディスプレイを開く(NULL指定で環境変数DISPLAYを使用)
  2. XDefaultScreen()でディスプレイ上の既定のスクリーンを開く
  3. XF86VidModeGetGammaRampSize()でガンマランプのサイズを取得
  4. 取得した長さの符合なしshort型配列を確保
  5. 各色成分のガンマランプの一連の値(強さ段階ごとのガンマ補正後の出力の強さ)を、明るさ設定の値と(その色に対応する)ガンマ補正値を用いて計算
  6. 出来上がった赤/緑/青それぞれのガンマランプのデータをXF86VidModeSetGammaRamp()に渡す
  7. 最後にXCloseDisplay()でディスプレイを閉じる

もちろん、プログラムとして明るさや各色成分のガンマ補正値を受け付けて上記の処理にデータを渡す処理も必要となる。

明るさ指定値とガンマ補正値を用いてガンマランプのデータを作成する

ガンマランプのサイズの数(段階数)でループをして、その段階の値(0からXF86VidModeGetGammaRampSize()の値 - 1まで)を「XF86VidModeGetGammaRampSize()の値 - 1」で割った値をpow()で「1 / ガンマ補正値」乗したものに明るさ設定値(範囲は0 - 65535)を掛けた値を入れていくと、それぞれの計算結果のまとまりがガンマランプのデータとなる。
例として、ガンマ2.2の特性(下に膨らむグラフ)を持つ環境においてガンマ1(色の強さの値と実際の出力の強さとが常に同じ)の表示を得るためには「1 / 2.2」のガンマをかけることになる(上に膨らむグラフ)。なお、ここでは、ガンマ2.2の特性を持つ環境でガンマ1の出力を得るためのガンマ補正の値を(2.2の逆数ではなく)「2.2」とする(xgammaなどと同じ計算方式)。

横方向が色成分ごとの強さの段階,縦方向がガンマ補正後のモニタへ渡される強さとなる。
もし明るさが設定可能な最大値の半分だと

それぞれの段階におけるガンマ補正後の強さ(縦方向の座標)は常に最大の明るさのときの半分になる。

現在の明るさとガンマ補正値を取得

XF86VidModeGetGammaRamp()を用いると、この関数を呼び出した時点の各色成分ごとのガンマランプのデータを取得してあらかじめ確保したデータ領域に書き込む。
このとき

この配列の最後の要素(最大の出力)の値は明るさの値(上の「A」の値)となり、その明るさの値と中央の要素の値(上の「B」の値)とを用いると、(各色成分ごとの段階の値,ガンマ補正値,明るさ,ガンマ補正後の出力の強さの関係から)ガンマ補正値は

1 / (log ([中央の要素の値] / [明るさの値]) / log ([ガンマランプのサイズ / 2] / [ガンマランプのサイズ - 1]))

のように、上の画像では

1 / (log ([Bの値] / [Aの値]) / log ([Cの値 = Dの値 / 2] / [Dの値 - 1]))

となる。
XF86VidModeGetGammaRamp()では明るさやガンマ補正値を直接取得することはできないので、これらの値が必要な場合はガンマランプのデータの並びから上のように導き出す必要がある。このようにすることで、「ガンマ補正は現在の値を用いつつ、明るさのみ指定値に修正する」「明るさの値は現在の値を用いつつガンマ補正のみ指定値に修正する」といったことが実現できる。

(「X Window Systemでnvidia,fglrx以外のドライバを用いた環境における明るさとガンマの調整について(ページ3/3)」に続く)

関連記事: