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

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

ガンマ調整用のチャート画像を自動生成してGTK+のGUIで表示する

NVIDIA製GPU/ドライバ使用時の設定ツールと明るさ/コントラスト/ガンマ調整について」や「AMD(ATI) RadeonのCatalyst(fglrx)ドライバに関するメモ(バージョン10.4現在)」,「X Window Systemでnvidia,fglrx以外のドライバを用いた環境における明るさとガンマの調整について(ページ1/3)」とその続きの記事ではガンマ調整を行うためのツールについてを扱ったが、調整に用いる画像を別途入手して表示する必要がある。
この画像をプログラムで生成して表示できないかと色々試した結果、GTK+GUIプログラムで対象のガンマ特性の値(例:2.2)から

  • 全色成分
  • 赤成分
  • 緑成分
  • 青成分

のそれぞれについて

  • 0%と50%の色の値を交互に並べたパターンと25%の色の値を単色で配置したパターンを並べたもの
  • 0%と100%の色の値を交互に並べたパターンと50%...
  • 50%と100%の色の値を交互に並べたパターンと75%...

の3つを横に並べた形のガンマ調整用のチャート画像を生成できるようになった。

色の値(0%,25%,50%,75%,100%)ごとの表示色については対象のガンマの値の逆のガンマをかけて計算した値に基づいている。この値から16進表記の文字列を取得し、その文字列を用いてパターンごとのXPM画像のデータを内部で生成し、このそれぞれのXPM画像データから生成されるGdkPixbufオブジェクトを出力の(画面に表示される)GdkPixbufオブジェクトの中の適切な位置にコピーしていくという作業を繰り返して、それをGtkImageのGUI部品に表示するという流れとなる。
下のコードは表示されるパターンごとに全て手動でデータを並べており、コード記述量も多い。
[任意]ファイル名: gammachart.py ライセンス: MIT

#! /usr/bin/python
#
# Generate/display gamma chart
# version 20110522
# (C) 2011 kakurasan
# Licensed under MIT

import sys
try:
  import pygtk
  pygtk.require ('2.0')
except:
  pass
try:
  import gtk
except:
  sys.exit ('PyGTK not installed')


class LabelWithUnderline (gtk.Label):
  """
  Label with underline
  """
  def __init__ (self, label_str=None):
    gtk.Label.__init__ (self, label_str)
    self.props.use_underline = True

class Xpm:
  """
  XPM data
  """
  _data = []
  size = 16
  @property
  def data (self): return self._data

class SingleColorXpm (Xpm):
  """
  XPM data (single color)
  """
  def __init__ (self, red, green, blue):
    self._data = ['{0} {0} 1 1\n'.format (Xpm.size * 2),
                  ' \tc #{0}{1}{2}'.format (red, green, blue)]
    for i in range (Xpm.size * 2):
      self._data.append (' ' * (Xpm.size * 2))

class AlternateXpm (Xpm):
  """
  XPM data (alternate)
  """
  def __init__ (self, red1, green1, blue1, red2, green2, blue2):
    self._data = ['{0} {0} 2 1'.format (Xpm.size * 2),
                  ' \tc #{0}{1}{2}'.format (red1, green1, blue1),
                  '.\tc #{0}{1}{2}'.format (red2, green2, blue2)]
    for i in range (Xpm.size):
      self._data.append ('. ' * Xpm.size)
      self._data.append (' .' * Xpm.size)

class GammaChart (gtk.Image):
  """
  Gamma chart
  """
  def __init__ (self, gamma):
    gtk.Image.__init__ (self)
    v000 = '{0:02x}'.format (int (round (pow (  0 / 255.0, 1.0 / gamma) * 255)))
    v025 = '{0:02x}'.format (int (round (pow ( 63 / 255.0, 1.0 / gamma) * 255)))
    v050 = '{0:02x}'.format (int (round (pow (127 / 255.0, 1.0 / gamma) * 255)))
    v075 = '{0:02x}'.format (int (round (pow (191 / 255.0, 1.0 / gamma) * 255)))
    v100 = '{0:02x}'.format (int (round (pow (255 / 255.0, 1.0 / gamma) * 255)))
    xpm_side = Xpm.size * 2
    image_side = xpm_side * 12
    # all
    pb_all_a025 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v000,
                                                                  v050, v050, v050).data)
    pb_all_a050 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v000,
                                                                  v100, v100, v100).data)
    pb_all_a075 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v050, v050, v050,
                                                                  v100, v100, v100).data)
    pb_all_s025 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v025, v025, v025).data)
    pb_all_s050 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v050, v050, v050).data)
    pb_all_s075 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v075, v075, v075).data)
    # red
    pb_red_a025 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v000,
                                                                  v050, v000, v000).data)
    pb_red_a050 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v000,
                                                                  v100, v000, v000).data)
    pb_red_a075 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v050, v000, v000,
                                                                  v100, v000, v000).data)
    pb_red_s025 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v025, v000, v000).data)
    pb_red_s050 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v050, v000, v000).data)
    pb_red_s075 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v075, v000, v000).data)
    # green
    pb_green_a025 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v000,
                                                                    v000, v050, v000).data)
    pb_green_a050 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v000,
                                                                    v000, v100, v000).data)
    pb_green_a075 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v050, v000,
                                                                    v000, v100, v000).data)
    pb_green_s025 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v000, v025, v000).data)
    pb_green_s050 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v000, v050, v000).data)
    pb_green_s075 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v000, v075, v000).data)
    # blue
    pb_blue_a025 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v000,
                                                                   v000, v000, v050).data)
    pb_blue_a050 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v000,
                                                                   v000, v000, v100).data)
    pb_blue_a075 = gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (v000, v000, v050,
                                                                   v000, v000, v100).data)
    pb_blue_s025 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v000, v000, v025).data)
    pb_blue_s050 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v000, v000, v050).data)
    pb_blue_s075 = gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (v000, v000, v075).data)
    # output
    pb_out = gtk.gdk.Pixbuf (gtk.gdk.COLORSPACE_RGB, False, 8, image_side, image_side)
    # build
    # all/a025
    pb_all_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, 0)
    pb_all_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, 0)
    pb_all_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side)
    pb_all_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side)
    pb_all_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 2)
    pb_all_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 2)
    # all/s025
    pb_all_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, 0)
    pb_all_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, 0)
    pb_all_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side)
    pb_all_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side)
    pb_all_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 2)
    pb_all_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 2)
    # all/a050
    pb_all_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, 0)
    pb_all_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, 0)
    pb_all_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side)
    pb_all_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side)
    pb_all_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 2)
    pb_all_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 2)
    # all/s050
    pb_all_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, 0)
    pb_all_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, 0)
    pb_all_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side)
    pb_all_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side)
    pb_all_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 2)
    pb_all_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 2)
    # all/a075
    pb_all_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, 0)
    pb_all_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, 0)
    pb_all_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side)
    pb_all_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side)
    pb_all_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 2)
    pb_all_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 2)
    # all/s075
    pb_all_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, 0)
    pb_all_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, 0)
    pb_all_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side)
    pb_all_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side)
    pb_all_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 2)
    pb_all_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 2)
    # red/a025
    pb_red_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 3)
    pb_red_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 3)
    pb_red_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 4)
    pb_red_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 4)
    pb_red_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 5)
    pb_red_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 5)
    # red/s025
    pb_red_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 3)
    pb_red_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 3)
    pb_red_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 4)
    pb_red_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 4)
    pb_red_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 5)
    pb_red_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 5)
    # red/a050
    pb_red_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 3)
    pb_red_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 3)
    pb_red_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 4)
    pb_red_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 4)
    pb_red_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 5)
    pb_red_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 5)
    # red/s050
    pb_red_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 3)
    pb_red_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 3)
    pb_red_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 4)
    pb_red_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 4)
    pb_red_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 5)
    pb_red_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 5)
    # red/a075
    pb_red_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 3)
    pb_red_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 3)
    pb_red_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 4)
    pb_red_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 4)
    pb_red_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 5)
    pb_red_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 5)
    # red/s075
    pb_red_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 3)
    pb_red_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 3)
    pb_red_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 4)
    pb_red_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 4)
    pb_red_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 5)
    pb_red_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 5)
    # green/a025
    pb_green_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 6)
    pb_green_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 6)
    pb_green_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 7)
    pb_green_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 7)
    pb_green_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 8)
    pb_green_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 8)
    # green/s025
    pb_green_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 6)
    pb_green_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 6)
    pb_green_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 7)
    pb_green_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 7)
    pb_green_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 8)
    pb_green_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 8)
    # green/a050
    pb_green_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 6)
    pb_green_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 6)
    pb_green_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 7)
    pb_green_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 7)
    pb_green_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 8)
    pb_green_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 8)
    # green/s050
    pb_green_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 6)
    pb_green_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 6)
    pb_green_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 7)
    pb_green_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 7)
    pb_green_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 8)
    pb_green_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 8)
    # green/a075
    pb_green_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 6)
    pb_green_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 6)
    pb_green_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 7)
    pb_green_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 7)
    pb_green_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 8)
    pb_green_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 8)
    # green/s075
    pb_green_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 6)
    pb_green_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 6)
    pb_green_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 7)
    pb_green_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 7)
    pb_green_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 8)
    pb_green_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 8)
    # blue/a025
    pb_blue_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 9)
    pb_blue_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 9)
    pb_blue_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 10)
    pb_blue_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 10)
    pb_blue_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 11)
    pb_blue_a025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 11)
    # blue/s025
    pb_blue_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 9)
    pb_blue_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 9)
    pb_blue_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, 0, xpm_side * 10)
    pb_blue_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 2, xpm_side * 10)
    pb_blue_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side, xpm_side * 11)
    pb_blue_s025.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 3, xpm_side * 11)
    # blue/a050
    pb_blue_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 9)
    pb_blue_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 9)
    pb_blue_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 10)
    pb_blue_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 10)
    pb_blue_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 11)
    pb_blue_a050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 11)
    # blue/s050
    pb_blue_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 9)
    pb_blue_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 9)
    pb_blue_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 4, xpm_side * 10)
    pb_blue_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 6, xpm_side * 10)
    pb_blue_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 5, xpm_side * 11)
    pb_blue_s050.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 7, xpm_side * 11)
    # blue/a075
    pb_blue_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 9)
    pb_blue_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 9)
    pb_blue_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 10)
    pb_blue_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 10)
    pb_blue_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 11)
    pb_blue_a075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 11)
    # blue/s075
    pb_blue_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 9)
    pb_blue_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 9)
    pb_blue_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 8, xpm_side * 10)
    pb_blue_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 10, xpm_side * 10)
    pb_blue_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 9, xpm_side * 11)
    pb_blue_s075.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * 11, xpm_side * 11)
    # set pixbuf
    self.props.pixbuf = pb_out

class MainWindow (gtk.Window):
  """
  Application main window
  """
  def __init__ (self, *args, **kwargs):
    gtk.Window.__init__ (self, *args, **kwargs)
    self.__accelgroup = gtk.AccelGroup ()
    self.add_accel_group (self.__accelgroup)
    self.__item_quit = gtk.ImageMenuItem (gtk.STOCK_QUIT, self.__accelgroup)
    self.__menu_file = gtk.Menu ()
    self.__menu_file.add (self.__item_quit)
    self.__item_file = gtk.MenuItem ('_File')
    self.__item_file.props.submenu = self.__menu_file
    self.__menubar = gtk.MenuBar ()
    self.__menubar.append (self.__item_file)
    self.__notebook = gtk.Notebook ()
    self.__notebook.append_page (GammaChart (gamma=2.2), LabelWithUnderline ('Gamma=2._2'))
    self.__notebook.append_page (GammaChart (gamma=2.0), LabelWithUnderline ('Gamma=2._0'))
    self.__notebook.append_page (GammaChart (gamma=1.8), LabelWithUnderline ('Gamma=1._8'))
    self.__notebook.append_page (GammaChart (gamma=1.0), LabelWithUnderline ('Gamma=_1.0'))
    self.__vbox = gtk.VBox ()
    self.__vbox.pack_start (self.__menubar, expand=False, fill=False)
    self.__vbox.pack_start (self.__notebook)
    # signals
    self.__item_quit.connect ('activate', gtk.main_quit)
    self.connect ('delete_event', gtk.main_quit)
    # window
    self.props.title = 'Gamma chart'
    self.add (self.__vbox)


def main ():
  """
  Main
  """
  win = MainWindow ()
  win.show_all ()
  gtk.main ()


if __name__ == '__main__':
  main ()

これをもとにして、ループ処理を用いて記述量を減らしたものが下(GammaChartクラスのみ異なるので同クラスのみ貼り付ける)。
[一部][任意]ファイル名: gammachart2.py ライセンス: MIT

class GammaChart (gtk.Image):
  """
  Gamma chart
  """
  def __init__ (self, gamma):
    gtk.Image.__init__ (self)
    (V000, V025, V050, V075, V100) = range (5)
    values = []
    values.append ('{0:02x}'.format (int (round (pow (  0 / 255.0, 1.0 / gamma) * 255))))
    values.append ('{0:02x}'.format (int (round (pow ( 63 / 255.0, 1.0 / gamma) * 255))))
    values.append ('{0:02x}'.format (int (round (pow (127 / 255.0, 1.0 / gamma) * 255))))
    values.append ('{0:02x}'.format (int (round (pow (191 / 255.0, 1.0 / gamma) * 255))))
    values.append ('{0:02x}'.format (int (round (pow (255 / 255.0, 1.0 / gamma) * 255))))
    xpm_side = Xpm.size * 2
    image_side = xpm_side * 12
    pixbufs = []
    # all
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V000], values[V050], values[V050], values[V050]).data),
                    gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V025], values[V025], values[V025]).data)))
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V000], values[V100], values[V100], values[V100]).data),
                   gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V050], values[V050], values[V050]).data)))
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V050], values[V050], values[V050], values[V100], values[V100], values[V100]).data),
                    gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V075], values[V075], values[V075]).data)))
    # red
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V000], values[V050], values[V000], values[V000]).data),
                    gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V025], values[V000], values[V000]).data)))
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V000], values[V100], values[V000], values[V000]).data),
                     gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V050], values[V000], values[V000]).data)))
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V050], values[V000], values[V000], values[V100], values[V000], values[V000]).data),
                     gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V075], values[V000], values[V000]).data)))
    # green
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V000], values[V000], values[V050], values[V000]).data),
                      gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V000], values[V025], values[V000]).data)))
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V000], values[V000], values[V100], values[V000]).data),
                       gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V000], values[V050], values[V000]).data)))
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V050], values[V000], values[V000], values[V100], values[V000]).data),
                       gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V000], values[V075], values[V000]).data)))
    # blue
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V000], values[V000], values[V000], values[V050]).data),
                      gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V000], values[V000], values[V025]).data)))
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V000], values[V000], values[V000], values[V100]).data),
                      gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V000], values[V000], values[V050]).data)))
    pixbufs.append ((gtk.gdk.pixbuf_new_from_xpm_data (AlternateXpm (values[V000], values[V000], values[V050], values[V000], values[V000], values[V100]).data),
                      gtk.gdk.pixbuf_new_from_xpm_data (SingleColorXpm (values[V000], values[V000], values[V075]).data)))
    # output
    pb_out = gtk.gdk.Pixbuf (gtk.gdk.COLORSPACE_RGB, False, 8, image_side, image_side)
    # build
    for (i, (pb_alternate, pb_single)) in enumerate (pixbufs):
      for j in range (3):
        k = j + (i / 3) * 3
        l = i % 3
        if j % 2 == 0:
          pb_alternate.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * (l * 4), xpm_side * k)
          pb_alternate.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * (l * 4) + xpm_side * 2, xpm_side * k)
          pb_single.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * (l * 4) + xpm_side * 1, xpm_side * k)
          pb_single.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * (l * 4) + xpm_side * 3, xpm_side * k)
        else:
          pb_alternate.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * (l * 4) + xpm_side, xpm_side * k)
          pb_alternate.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * (l * 4) + xpm_side * 3, xpm_side * k)
          pb_single.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * (l * 4) + xpm_side * 2, xpm_side * k)
          pb_single.copy_area (0, 0, xpm_side, xpm_side, pb_out, xpm_side * (l * 4), xpm_side * k)
    # set pixbuf
    self.props.pixbuf = pb_out

こちらのバージョンに基づいたものを「nvidia,fglrx以外のドライバ向けのX Window Systemの明るさとガンマの調整ツールのパッケージを作成」で扱ったツールの新しいバージョンの中に組み込んだ。これで同じツールの中でガンマ調整チャートの表示とガンマ補正の調整が同時に行えるようになった。

関連記事:

参考URL: