Palm Programmer's Laboratory
Palm OS Programmer's Companion Volume I/4-15
4-15 カラーとグレイスケールのサポート
Palm OS 3.5 以降では、オペレーティングシステムはピクセルあたり 1, 2, 4, 8 ビットの以下に示すシステムパレットをサポートしています。
- 1 ビット:白(0) および黒(1)
- 2 ビット:白(0)、淡灰色(1)、濃灰色(2)、および黒(3)
- 4 ビット:白(0) から黒(0xF) までの 16 階調のグレイスケール
- 8 ビット:赤、緑、青のそれぞれ 0x00、0x33、0x66、0x99、0xCC、および 0xFF の組み合わせを含む 216 色の“Web-safe”パレット、および 0x00, 0x11, 0x22, ... 0xFF の 16 階調のグレイスケール。さらに、HTML カラーと呼ばれる追加のカラー ── 0xC0C0C0 (silver)、0x808080 (gray)、0x800000 (maroon)、0x800080 (purple)、0x008000 (green)、および 0x008080 (teal) ── が含まれます。残りの 24 エントリ( インデックス 0xE7 〜 0xFE )は未指定であり、黒が指定されています。これらの未指定エントリはアプリケーションで指定することができます。
カラーテーブルは全てのビット深度でサポートされていますが、標準以外のカラーテーブルを使用した場合、パフォーマンスの低下が発生します。
Palm OS 4.0 以降では、オペレーティングシステムは 16 ビットカラーをサポートしています。しかし、OS の UI レイヤーによる 16 ビットカラーモードの利用はサポートされていません。ボタン、コントロール、およびその他のガジェットは引き続き 8 ビット以下のカラービット深度で表示されます。
インデックスカラー表示とダイレクトカラー表示
1、2、4、および 8 ビットの深度をサポートするディスプレイは、ピクセル値を色情報に対応付けるためのディスプレイハードウェアによる色検索テーブルに依存しています。スクリーンに表示できる色は、ディスプレイの色検索テーブルにある色だけです。
一方、ダイレクトカラー表示は各ピクセル位置に赤・緑・青の色情報が直接保存されるため、色検索テーブルに依存しません。例えば、16 ビットのダイレクトカラー表示では赤色に 5 ビット、緑色に 6 ビット、青色に 5 ビットの情報をピクセルごとに保持できます。このタイプの表示では、色検索テーブルを使用した場合のような制限はありません。
Palm OS 4.0 以前で使用されていた、前景色、背景色、およびテキストカラーを設定するためのインデックスカラーモードは、ダイレクトカラーディスプレイでも引き続き機能します。なぜなら、システムがインデックス値をダイレクトカラーに対応付けるために変換テーブルを使用するからです。
スクリーンがダイレクトカラーディスプレイの場合、色検索テーブルはインデックスカラーモードの互換性を保つためだけに存在します。ハードウェアはフレームバッファの各ピクセル位置に保存された赤、緑、青の各ビット値から色を導出するため、色検索テーブルはディスプレイハードウェアには何の影響も及ぼしません。
カラーテーブル
システムのカラーテーブルは 'tclt' リソース(シンボル名は colorTableRsc )に保存されています。カラーテーブルはエントリ数とそれに後続する RGBColorType 型の色情報の配列で構成されています。RGBColorType 構造体は赤・緑・青の各 8 ビットに加えてインデックス値を保持する“extra”バイトを持っています。
カラーインデックスはソフトウェアレイヤーによって異なる使われ方をします。色の照会やフィッティングを行う場合、インデックスには参照カラーテーブルの RGB 値に最も近いインデックスが格納されます。カラーテーブルの色を設定する場合、インデックスにはその色が占めるべきスロットを指定できます。いくつかのルーチンでは、インデックスは無視されます。
通常、描画ルーチンとオペレーティングシステムは RGB 値よりもインデックスカラーを使用します。インデックスカラーはパフォーマンス上の理由から使用されます。というのは、ほとんどの描画処理において RGB 値からインデックスへの変換が不要になるからです。
フルカラーテーブル(カウント情報を含む)と RGB 色情報の配列を混同しないように注意して下さい。一部のルーチンはカラーテーブル全体を使用しますが、カラーエントリのリストを使用するものもあります。
色変換テーブル
レンダリングの際にある深度から別の深度に変換する必要があると、色変換テーブルが使用されます。例えば、8 ビットのカラービットマップを 2 ビットのディスプレイに表示しようとしているとしましょう。Palm OS は表示のためにカラービットマップをグレイスケールビットマップに変換しなければなりません。このために、元データ( 8 ビットのビットマップ )のカラーテーブルの各要素に対し、変換先のカラーテーブルのもっとも近い要素を探すことで変換テーブルを作成します。このテーブルは一度作成すればそれが有効である限り全ての描画に使用されます。
Palm OS は変換テーブルの作成のために以下の2つのうちいずれかのアルゴリズムを使用します。
- 変換先テーブルがグレイスケールの場合、明度によるマッチを行ないます。
- 変換先テーブルがカラーの場合、RGB 空間の最短距離が使用されます。
RGB の最短距離マッチは知覚的に常にベストな結果をもたらすわけではありませんが、高速であり、また Palm OS で利用できるパレットにおいてはうまく機能します。
カラーテーブルの管理
描画ウィンドウで使用されているカラーテーブルを変更したい場合、WinPalette 関数を使用することができます。描画ウィンドウがオンスクリーンであった場合、ディスプレイハードウェアのパレットも変更されます。WinPalette 関数についての詳細は 「 Palm OS Programmer's API Reference 」を参照して下さい。
RGB カラーに対応する現在のパレットのインデックスカラーを知りたい場合、WinRGBToIndex と WinIndexToRGB を使用することができます。WinRGBToIndex をコールする場合、完全に一致する結果が得られない場合があります。これはパレットにない色の RGB 値を指定して WinRGBToIndex をコールした場合で、結果として対応するインデックスがなかった場合に発生します。完全にマッチする RGB 値がなかった場合、現状ではインデックスを決定するためにベストフィットアルゴリズムを使用しています。WinIndexToRGB の場合、返される RGB 値は常に完全マッチです( インデックスが範囲外だった場合、デバッグ ROM ではエラーが表示されます )。
UI カラーリスト
システムはシステムカラーテーブルに加えて UI カラーリストを構築します。UI カラーリストは様々なユーザーインターフェース要素で使用される色を含んでいます。それぞれの UI カラーはシンボリックなカラー定数で表現されます。使用される色のリストは表 4.18 を参照して下さい。
モノクロ、グレイスケール、カラーモードといった異なるカラースキーマに対応するため、UI カラーリストはビット深度ごとに準備されています。このことが重要なのは、デフォルトのルック&フィールドがモノクロだったとしても、フィールドのハイライトテキストはカラーでは黄色の背景に黒字、その他のモードでは黒い背景に白字となるためです。
カラーリストを取得するために、システムはまず sysResIDPrefUIColorTableBase にスクリーンのビット深度を加算した値を使用してプリファレンスデータベースからロードしようとします。プリファレンスを使用することにより、個人ユーザーがサードパーティ製の“personality”あるいは“themes”といったエディタを使用して見栄えをカスタマイズできるようになります。プリファレンスが定義されていなければ、システムは現在のスクリーン深度を使用してシステムのカラーテーブルリソースカラーデフォルトのカラーテーブルをロードします。
カラーリストの使用により、Palm ハンドヘルド全体のカラースキーマをパーソナライズするのであれ、アプリケーションに閉じた調整をするのであれ、UI 要素のカラーバリエーションを容易に変更できるようになります。これらをカラークラスとして定義することにより、UI 要素の一貫性を保つことができます。
Table 4.18 UI objects and colors
UI オブジェクト | カラーシンボル |
---|---|
フォーム | UIFormFrame,UIFormFill |
モーダルダイアログ | UIDialogFrame,UIDialogFill |
アラートダイアログ | UIAlertFrame,UIAlertFill |
ボタン(プッシュボタン,リピートボタン,チェックボックス,セレクタトリガー) | UIObjectFrame,UIObjectFill,UIObjectForeground,UIObjectSelectedFill,UIObjectSelectedForeground |
フィールド | UIFieldBackground,UIFieldText,UIFieldTextLines,UIFieldTextHighlightBackground,UIFieldTextHighlightForeground |
メニュー | UIMenuFrame,UIMenuFill,UIMenuForeground,UIMenuSelectedFill,UIMenuSelectedForeground |
テーブル | 背景色には UIFieldBackground を使用し、その他はテーブルセル内部のコントロールに依存。 |
リスト、およびポップアップトリガー | UIObjectFrame,UIObjectFill,UIObjectForeground,UIObjectSelectedFill,UIObjectSelectedForeground |
ラベル | コントロール上のラベルや編集不可のフィールドでは UIObjectForeground を使用し、WinDrawChars および WinPaintChars でフォーム上に書かれたテキストには描画ステートのテキストカラー設定を使用。 |
スクロールバー | UIObjectFill,UIObjectForeground,UIObjectSelectedFill,UIObjectSelectedForeground |
挿入ポイント | UIFieldCaret |
フロントエンドプロセッサ(日本語システムのみ) | UIFieldFepRawText,UIFieldFepRawBackground,UIFieldFepConvertedText,UIFieldFepConvertedBackground,UIFieldFepUnderline |
アプリケーションで UI カラーリストが使用する色を変更する必要がある場合、UIColorSetTableEntry 関数を使用することができます。使用されている色を取得する必要がある場合、UIColorGetTableEntryIndex または UIColorGetTableEntryRGB が使用できます。
UI カラーリストを変更したとしても、その変更はアプリケーションがアクティブな間だけしか有効ではありません。UI カラーリストは他のアプリケーションにスイッチした時点でリセットされます。再びアプリケーションが起動された場合、UIColorSetTableEntry を再度コールする必要があります。
ダイレクトカラー関数
ダイレクトカラー関数は対応するインデックス形式の関数よりも汎用的なもので、インデックスカラー(1, 2, 4, 8 ビット)ディスプレイでも 16 ビットのダイレクトカラーディスプレイでも使用することができます。システムは必要に応じて、もっとも近い色のインデックス値を自動的に探します。
ダイレクトカラー関数は、WinSetForeColorRGB、WinSetBackColorRGB、WinSetTextColorRGB、および WinGetPixelRGB です。
これらの関数はダイレクトカラー機能を備えたシステムでなければ利用できないため、アプリケーションは通常、色の選択やダイナミックレンジをより緻密に制御する必要が限り、対応するインデックス形式の方 ―― WinSetForeColor, WinSetBackColor, WinSetTextColor, and WinGetPixel ―― を使用することになるはずです。
ピクセルの読み取りと書き込み
ピクセル値を読み取るための Palm OS 3.5 の API コールである WinGetPixel は、色のインデックス値を返すようにデザインされています。この関数がダイレクトカラーディスプレイ上でコールされた場合、まずは実際のピクセル値( 16 ビットまたは 24 ビットのダイレクトカラー値 )を取得する必要があります。システムは次にシステムの仮想 8 ビット色検索テーブルからもっとも近い色を探し、見つかった色のインデックス値を返します。この処理によって、WinGetPixel の復帰値を WinSetForeColor、WinSetBackColor、あるいは WinSetTextColor に渡すようなアプリケーションの互換性を保っています。
ダイレクトカラーディスプレイにおいて、ある場所から別の場所へピクセルを正確にコピーしたい場合、アプリケーションは WinGetPixel のかわりに WinGetPixelRGB を使うべきです。WinGetPixel をダイレクトカラーディスプレイで使用すると、WinGetPixel によるカラーテーブル検索によってもっとも近いインデックス値が選ばれるため、結果として色情報が失われる可能性があります。
WinGetPixelRGB 関数はピクセル情報を RGBColorType で返します。これは赤、緑、青の各色が 8 ビットで表現され、色解像度に損失が発生しないことを保証します。この関数は WinGetPixel よりも汎用的で、インデックスカラーモード( 1, 2, 4, 8 ビット )でもダイレクトカラーモードでも使用することができます。システムは必要に応じてインデックスカラーピクセルの RGB コンポーネントを検索します。
ピクセルを設定する API( WinPaintPixel、WinDrawPixel など )は全て前景色や背景色などの使用に依存しており、ダイレクトカラーモードにおいても新しい形式を必要としません。アプリケーションは単純に WinGetPixelRGB が返した RGBColorType を使って WinSetForeColorRGB をコールし、続いてダイレクトカラーのピクセルをコピーするために WinDrawPixel をコールすることができます。
ダイレクトカラービットマップ
Palm OS 4.0 では、ウィンドウマネージャはこれまでサポートしていた 1、2、4、および 8 ビットのインデックスカラービットマップに加え、ピクセルあたり 16 ビットのダイレクトカラービットマップをサポートしています。ダイレクトカラービットマップは、BitmapType データ構造体の BitmapFlagsType ビットフィールドに新しく追加された directColor ビットによって識別されます。このフラグに加えて、ダイレクトカラービットマップには BitmapDirectInfoType フィールド ―― redBits、greenBits、blueBits、reserved、および transparentColor ―― も含まれます。
redBits、greenBits、および blueBits フィールドは各ピクセルにおけるそれぞれの色コンポーネントのビット数を示しています。現在の実装ではピクセルあたり赤 5 ビット、緑 6 ビット、青 5 ビットの計 16 ビットのみをサポートしています。
──────────────── R R R R R G G G G G G B B B B B MSB LSB ────────────────
transparentColor フィールドはビットマップの透過色の赤、緑、青の各コンポーネントを含んでいます。ダイレクトカラービットマップでは、transparentIndex フィールドのかわりにこのフィールドが透過色の指定に使用されます。なぜなら、transparentIndex は 8 ビット幅しかなく、インデックスカラーしか表現できないからです。transparentColor も transparentIndex 同様、ビットマップのフラグフィールドで hasTransparency ビットが設定されていない限り無視されます。
Palm OS 4.0 では、実際のスクリーン深度に関係なく、常に 16 ビットダイレクトカラービットマップを描画できます。16 ビットカラー関数は描画先の深度がなんであれ、描画に必要なビット深度の変換を自動的に行ないます。
ビットマップリソースは、各深度に対応する複数のイメージを1つのリソースの中に含むように作成できます。アプリケーションがダイレクトカラービットマップのビットマップしか含んでいない場合、非互換が発生する可能性があります。そのため、アプリケーションはダイレクトカラービットマップを描画する前に Palm OS 4.0 であるかどうかをチェックするか、さもなければダイレクトカラーだけでなく 1、2、4、8 ビットのイメージも常に用意する必要があります。
特殊描画モード
winErase、winMask、winInvert、および winOverlay の特殊描画モードは、ダイレクトカラーモデルの導入によって複雑な問題を起こします。これらの描画モードはもともと、ビット 1 で黒を、ビット 0 で白を表すモノクロビットマップにおける使用を前提としてデザインされました。この色指定では、これらの特殊描画モードは以下のように説明されます。
- WinErase 関数は AND 演算を行ないます( 変換元で白のピクセルが変換先で白になるのに対し、変換元で黒のピクセルはそのままになります )。
- WinMask 関数は AND NOT 演算を行ないます( 変換元が白のピクセルが変換先をそのままにしておくのに対し、変換元が黒のピクセルは変換先を白にします )。
- WinInvert 関数は XOR 演算を行ないます( 変換元が白のピクセルが変換先をそのままにしておくのに対し、変換元が黒のピクセルは変換先のピクセルを反転します )。
- WinOverlay 関数は OR 演算を行ないます( 変換元が黒のピクセルは変換先を黒にし、変換元が白のピクセルは変換先をそのままにします )。
ダイレクトカラービットマップでは、黒は全て 0 のビットで、白は全て 1 のビットでそれぞれ表現されます。このため、全ての描画モードがインデックスカラーモード特殊同じ方法の論理演算で実装されているとすると、期待どおりの結果にはなりません。
ダイレクトカラー関数が想定しているのは、「期待どおりの結果」というのが実際の論理演算の実行よりも呼出し元にとって重要だということです。そのため、各種の描画モードは、ダイレクトカラービットマップでは以下のようになります。
- WinErase 関数は AND 演算を行ないます( 変換元で白のピクセルが変換先で白になるのに対し、変換元で黒のピクセルはそのままになります )。
- WinMask 関数は OR NOT 演算を行ないます( 変換元が白のピクセルが変換先をそのままにしておくのに対し、変換元が黒のピクセルは変換先を白にします )。
- WinInvert 関数は XOR NOT 演算を行ないます( 変換元が白のピクセルが変換先をそのままにしておくのに対し、変換元が黒のピクセルは変換先のピクセルを反転します )。
- WinOverlay 関数は AND 演算を行ないます( 変換元が黒のピクセルは変換先を黒にし、変換元が白のピクセルは変換先をそのままにします )。
変換元および変換先のビットマップに黒と白しか含まれない場合、ダイレクトカラーモードにおける新しい描画モードの変換によってインデックスカラーモードと同じ結果を得ることができます。
しかし、それ以外の色の場合、ダイレクトカラー関数呼び出しがダイレクトカラーモードにおいてインデックスカラーモードと同じ論理演算を行うことを前提としていると、予期しない結果になる可能性があります。