Palm Programmer's Laboratory

トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

Palm OS Programmer's Companion Volume I/4-10

← 9 節に戻る ↑4 章トップへ 11 節に進む →


4-10 ビットマップ

 
ビットマップは Palm OS によって表示されるグラフィックです。Constructor でビットマップリソースを作成する方法はいくつかあります。

  • フォームの決まった場所にビットマップを単純に表示したいのであれば、フォーム上にフォームビットマップオブジェクトをドラッグします。ビットマップIDフィールドにリソースIDを設定することでビットマップリソースを作成できます。ビットマップリソースは 'Tbmp' リソースであり、それを包含するフォームビットマップオブジェクトは 'tFBM' リソースです。
  • 上記以外の目的でビットマップを作成したい(例えばアニメーションをしたりガジェットを表示するなどの)場合、メインプロジェクトウィンドウにてビットマップリソースまたはビットマップファミリリソースを作成します。この場合、Constructor は 'tbmf' リソースを作成し、PalmRez ポストリンカーがそれを PICT フォーマットに変換して 'Tbmp' リソースに関連付けます。(Constructor は Macintosh および Microsoft Windows オペレーティングシステムの両方に対応した PICT フォーマットイメージを作成します。)

 

ビットマップサポートのバージョン

ビットマップのエンコーディングには4種類あります。

  • バージョン 0 は Palm OS の全てのリリースでサポートされます。
  • バージョン 1 のエンコーディングは Palm OS 3.0 以降でサポートされます。Consructor においてビットマップを作成する際に明示的に透過色インデックスか圧縮タイプを指定しない限り、PalmRez はバージョン 1 のビットマップを作成します。
  • バージョン 2 のエンコーディングは Palm OS 3.5 以降でサポートされます。このエンコーディングでは透過インデックスと RLE 圧縮がサポートされます。バージョン 2 ビットマップを使えば、作成時に透過色のカラーインデックスを指定できます。透過インデックスはマスキングの代替方法です。システムは透過インデックス値と等しい値を持つビットを描画しません。透過インデックスを指定されたビットマップが自身の色深度と異なる深度で描画される場合、透過色はまず対応する深度の色に変換され、変換後の色が透過色とみなされます。これにより、複数の色が透過色となります。
  • バージョン 3 のエンコーディングは Palm OS Garnet で高密度ディスプレイフィーチャセットのあるハンドヘルドでサポートされます。このバージョンでは異なる密度での表示がサポートされます。

 

高密度ビットマップ

BitmapTypeV3 データ構造体は 16 ビットの density フィールドを含んでいます。スクリーンビットマップでは、このフィールドはスクリーンの密度を表しています。密度を表す列挙値のリストは Bitmap.h で定義されています。

typedef enum {
    kDensityLow         =  72,
    kDensityOneAndAHalf = 108,
    kDensityDouble      = 144,
    kDensityTriple      = 216,
    kDensityQuadruple   = 288
} DensityType;

kDensityLow の値である 72 は恣意的なものです。この値はインチあたりのピクセル数を表しているわけではありませんが、そう考えるのもいいでしょう。

IMPORTANT
DensityType 列挙値でリストされている全ての密度が現在のバージョンの高密度ディスプレイフィーチャセットでサポートされているわけではありません。現在のリリースでは、kDensityLow と kDensityDouble だけがサポートされています。

Palm OS 4.0 はバージョン 2 の BitmapType 構造体でリリースされました。density フィールドは 2 よりも大きなバージョンの BitmapType 構造体でのみ定義されています。あるビットマップ構造体がバージョン 2 以下だった場合、オペレーティングシステムはそのビットマップを低密度とみなします。

描画エンジンは適切な拡縮比率を求めるためにソースと描画先の両方のビットマップの density フィールドを使用します。デフォルト密度のビットマップは高密度ディスプレイでは拡大する必要があるため、高密度ディスプレイのハンドヘルドではグラフィックアクセラレータを使用する場合があります。その場合でも、ソフトウェア描画エンジンは描画先がオフスクリーンウィンドウの場合のために拡縮ロジックを内蔵します。

kDensityDouble から kDensityLow へのスケールダウンを行う場合、描画エンジンはビットマップデータを縮小します。結果はほぼ常に kDensityLow で作成されたビットマップよりも低品質なイメージになります。

以下の例で、上記の考え方のデモンストレーションをします。

 

  • アプリケーションが低密度ビットマップを倍密度スクリーンに描画する。

描画するデータは 16 x 16 のビットマップです。アプリケーションは以下の関数、

WinDrawBitmap(bitmapP, 31, 23);

標準的な 160 x 160 の座標系でスクリーン座標( 31, 23 )を基点としてビットマップを描画する目的でコールします。

Palm OS はデフォルトでは標準座標系を使用し、このハンドヘルドは倍密度スクリーンを有していることから、描画ウィンドウの描画ステートは拡縮比率として 2.0 を保持しています。WinDrawBitmap 関数は座標( 31, 23 )に対して拡縮比率をかけることで高密度座標に変換を行ない、その後描画エンジンを座標( 62, 46 )でコールします。

描画エンジンは低密度ビットマップと一緒にスクリーン座標( 62, 46 )を受けとります。描画エンジンはビットマップの BitmapType 構造体のバージョンを元にそれが低密度であることを認識し、倍密度スクリーンに描画する際にピクセルレベルでビットマップデータを 2 倍にします。

以下のイラストでは、左に元データを示しています。低密度ウィンドウにおける座標を左上と右下に付記しています。右側のイラストはスクリーンに表示された結果を示しており、左上の座標はウィンドウマネージャによって、ビットマップデータは描画エンジンによってそれぞれ倍にされています。

図 4.19 倍密度スクリーンにおける低密度ビットマップ

 

  • 新しいアプリケーションが倍密度ビットマップを倍密度スクリーンに描画する。

元データは 32 x 32 の倍密度ビットマップです。ビットマップを倍密度スクリーンに描画しようとしていることを認識し、アプリケーションは倍密度座標系を使用するための新しい関数を使用してから WinDrawBitmap を高密度座標でコールします。

WinPushDrawState();
oldScale = WinSetCoordinateSystem(kCoordinatesNative);
WinDrawBitmap(bitmapP, 61, 45);
WinPopDrawState();

図 4.20 倍密度スクリーンにおける倍密度ビットマップ

倍密度座標( 61, 45 )によって、アプリケーションはスクリーン上のビットマップの位置をより精密に指定できます。この座標は標準座標系の( 30.5, 22.5 )に等しいことになります。

ウィンドウのネイティブ座標系がアクティブになっているため、ウィンドウマネージャは倍密度座標( 61, 45 )に変更を加えずにそのままにします。描画エンジンはこの座標と倍密度のビットマップを受け取ります。スクリーンビットマップが同じ密度のため、描画エンジンは元データに変更を加えずに画面にコピーします。

WinSetCoordinateSystem をコールしているのは OS に倍密度ビットマップを描画させるためではなく、ビットマップの左上座標を倍密度座標で指定するためのものであることに注意して下さい。アプリケーションが倍密度座標の精度を必要としない場合、単純に WinDrawBitmap をコールして標準座標の x, y を渡すこともできます。

WinDrawBitmap(bitmapP, x, y);

ウィンドウマネージャは( x, y )をスクリーンの座標系に変換し、描画エンジンは倍密度ビットマップをその位置に描画します。

標準座標が使用可能で、アプリケーションのビットマップファミリに低密度と倍密度のビットマップが両方含まれている場合、WinDrawBitmap は描画先ウィンドウの密度を元に、ビットマップファミリから適切なビットマップを選択します。アプリケーション側には追加のロジックは必要ありません。ビットマップファミリに倍密度と低密度の両方のビットマップを用意することで、アプリケーションはコードパスを分離することなく様々なスクリーン密度のハンドヘルドで画像を正しく表示することができます。

訳注:「コードパスを分離( separate code paths )」という
   表現は、要するに if 文などを使った分岐のことを指して
   いると思われます。

ビットマップファミリのより詳細な記述は、“高密度ビットマップファミリ”を参照して下さい。

 

  • 新しいアプリケーションが倍密度ビットマップを低密度スクリーンに描画する。

アプリケーションが高密度ビットマップしか用意していない場合、描画エンジンはそれをスクリーンに描画する際に縮小する必要があります。アプリケーションはスクリーンの密度を以下のようにして求めることができます。

UInt32 density;
err = WinScreenGetAttribute(winScreenDensity, &density);

描画先が低密度であることを認識して、アプリケーションは WinDrawBitmap を標準座標系でコールします。

WinDrawBitmap(bitmapP, 31, 23);

描画先ウィンドウは低密度であり、渡された座標は標準座標であることから、ウィンドウマネージャはその座標を拡縮しません。しかし、描画エンジンは描画するビットマップの密度が kDensityDouble であることを認識し、低密度スクリーンの描画する際にオリジナルサイズの半分に縮小します。

図 4.21 低密度スクリーンにおける倍密度ビットマップ

上の図の右に示すように、結果は貧弱なものになります。このため、アプリケーションを低密度でも高密度でも見栄えの良いものにするためには、低密度と高密度の両方のビットマップを用意するべきです。

高密度ディスプレイフィーチャセットに含まれる描画エンジンが必要に応じてビットマップを拡縮できても、このフィーチャセットのないハンドヘルド上においてアプリケーションのビットマップファミリが高密度ビットマップのみを含む場合、何も描画されないことに注意して下さい。

 

ビットマップファミリ

'Tbmp' リソースは単一のビットマップかビットマップファミリを定義します。ビットマップファミリはビットマップのグループで、同一の画像でピクセル深度が異なるものを格納します( 図 4.22 参照 )。ビットマップファミリの描画がリクエストされると、オペレーティングシステムはディスプレイと同じピクセル深度を持つビットマップを選択します。一致するビットマップが存在しない場合、ディスプレイ深度よりも低い深度でもっとも近いものが選択されます。ディスプレイ深度よりも低い深度のビットマップが存在しない場合、ディスプレイ深度にもっとも近い深度のビットマップが使用されます。

プログラム的には、ビットマップおよびビットマップファミリは BitmapType 構造体で表現されます。この構造体は単純にヘッダです。同じメモリブロック内でこれにビットマップデータが続きます。Palm OS 3.0 以降のビットマップはそれぞれが自身のカラーテーブルを持つこともできます。ビットマップがカラーテーブルを持つ場合、それはビットマップヘッダとビットマップデータの間に配置されます。

図 4.22 単密度のビットマップファミリ

 

高密度ビットマップファミリ

ビットマップファミリは、異なるビット深度を持つ Palm ハンドヘルドの様々なスクリーンに渡る単一のイメージを表現します。高密度ディスプレイフィーチャセットよりも前には、ビットマップファミリは NULL 終端を伴うビットマップのリンクドリストで、ビット深度は低から高の順になっていました。WinDrawBitmap 関数はリンクドリストを走査して、描画ウィンドウのビット深度以下で最大の深度を持つビットマップを選択します。

ビットマップファミリが NULL 終端を伴うビットマップのリンクドリストとして表現されていることに変わりはありませんが、高密度ディスプレイセットでは、状況に応じて最適なビットマップを選択するために使用されるアルゴリズムが異なります。この違いには理由が2つあります。第一に、描画ウィンドウが 8 ビットの場合、グレイスケールイメージよりも 16 ビットイメージを選択した方が良いこと。2つ目は、ビットマップの選択の際に密度を考慮に入れなければならないことです。

高密度ディスプレイフィーチャセットで使用されるアルゴリズムは、描画ウィンドウの密度に依存します。描画ウィンドウが低密度の場合、ビットマップの深度にかかわらず、低密度ビットマップが常に倍密度ビットマップよりも優先されます。しかし、描画ウィンドウが倍密度の場合、カラードメイン( カラーかグレイスケールかの区別 )の一致しない倍密度ビットマップよりもカラードメインの一致する単密度ビットマップが優先されます。倍密度スクリーンでは以下のアルゴリズムが適用されます。

If draw window is low density {
    Favor low-density over double-density
    If draw window is color {
        Favor color bitmap
    } else {
        Favor grayscale, picking greatest depth
        less than or equal to draw window’s
        depth
    }
} else {
    If draw window is color {
        Favor color
    } else {
        Favor grayscale
    }
}

 
以下の表に、この倍密度アルゴリズムを適用した結果を示します。左の2列は描画ウィンドウの深度と密度を示しています。3列目は選択の優先度のリストで、優先度の高い順に並んでいます( 'd' は倍密度を示しています )。

表 4.17 倍密度アルゴリズムの結果

深度 密度 ビットマップ選択の順序
1 Single 1,2,4,8,16
2 Single 2,1,4,8,16
4 Single 4,2,1,8,16
8 Single 8,16,4,2,1
16 Single 16,8,4,2,1
1 Double 1d,2d,4d,1,2,4,8d,16d,8,16
2 Double 2d,1d,4d,2,1,4,8d,16d,8,16
4 Double 4d,2d,1d,4,2,1,8d,16d,8,16
8 Double 8d,16d,8,16,4d,2d,1d,4,2,1
16 Double 16d,8d,16,8,4d,2d,1d,4,2,1

ビットマップファミリのビットマップは密度ごとにグループ分けされています。下位互換性のために、デフォルト密度のビットマップのリンクドリストが最初に配置され、残りがビット深度の低い方から順に並べられます。ビットマップファミリが高密度ビットマップを含む場合、低密度ビットマップの後に高密度ビットマップが深度の低い順に続きます。ビットマップファミリが複数の密度を含む場合、各密度のセットが密度の低い順に並びます。

IMPORTANT
グラフィックボタンやスライダー、あるいはフォームビットマップに使用するビットマップファミリは、少なくとも1つの低密度ビットマップを備えている必要があります。この制約はカスタムガジェットに使用されるビットマップには適用されません。アプリケーションが高密度ディスプレイのハンドヘルド上でのみ動作する予定であれば、カスタムガジェット用のビットマップファミリに低密度画像を用意する必要はありません。

高密度ディスプレイフィーチャセットを備えていないハンドヘルドは、高密度ビットマップを表示しません。しかし、低密度と高密度の両方のビットマップを含むアプリケーションであれば低密度ビットマップを表示します。これは古いバージョンの OS が、ビットマップファミリのリンクドリストを低密度部分を越えて高密度部分まで走査しないからです。これは、ビットマップファミリ内の低密度部分と高密度部分の間にダミーのバージョン1ビットマップ構造体を挟むことで実現されます。ダミーのビットマップはビットマップデータもカラーテーブルも持たず、不正なビット深度の値が設定されています。ダミービットマップのビット深度を 0xFF に設定することで、古いバージョンの OS におけるビットマップのリンクドリストを走査するロジックはリストの適切な位置でストップすることになります。

高密度ディスプレイフィーチャセットはダミービットマップの後ろに高密度ビットマップが後続することを認識し、ダミービットマップをスキップして走査を続行します。高密度ビットマップが1つ以上ある場合にのみダミービットマップが存在し、高密度ビットマップが存在する場合には常にダミービットマップが存在することに注意して下さい。高密度ビットマップだけで低密度ビットマップが存在しない場合、ダミービットマップが最初のビットマップになります。

図 4.23 にビットマップファミリのビットマップを走査するプロセスを図示します。点線部分は高密度ディスプレイフィーチャセットを備えたハンドヘルドでのみ実行されるステップです。

図 4.23 ビットマップファミリにおけるビットマップのリンクドリスト

 

ビットマップの描画

フォームビットマップオブジェクトを使用している場合、ビットマップはフォームの描画の際に描画されます。追加のコーディングは必要ありません。

フォームビットマップオブジェクトを使用していない場合、ビットマップを描画するにはまずリソースデータベースから取得し、次に WinDrawBitmap または WinPaintBitmap をコールします( フォームマネージャのコードはフォームビットマップオブジェクトを描画するのに WinDrawBitmap を使用します )。ビットマップファミリを渡した場合、これら2の関数は描画ウィンドウの深度に等しい深度を持つビットマップを描画し、なければ描画ウィンドウの深度よりも低い深度のビットマップのうち、もっとも近い深度のものを使用し、それもなければ大きな深度のビットマップのうちもっとも近いものを使用します。

リスト 4.7 ビットマップの描画

MemHandle resH = DmGetResource (bitmapRsc, rscID);
BitmapType *bitmap = MemHandleLock (resH);
WinPaintBitmap(bitmap, 0, 0);

ビットマップを変更したい場合、Palm OS 3.5 以降であれば BmpCreate によってプログラム的にビットマップを作成できますし、WinCreateBitmapWindow を使うことでオフスクリーンウィンドウラッパーを作成することもできます。新しいビットマップウィンドウをアクティブウィンドウに設定すれば、ウィンドウ描画関数を使用してビットマップに描画を行うことができます。

リスト 4.8 プログラムによるビットマップの作成

BitmapType *bmpP;
WinHandle win;
Err error;
bmpP = BmpCreate(10, 10, 8, NULL, &error);
if (bmpP) {
    win = WinCreateBitmapWindow(bmpP, &error);
    if (win) {
        WinSetDrawWindow(win);
        WinDrawLines(win, ...);
        /* etc */
    }
}

BmpCreate は常にバージョン 2 のビットマップを作成することに注意して下さい。

Palm OS 3.5 未満の環境でビットマップを変更する方法については、Palm OS Developer ウェブサイトのナレッジベースから Signatures サンプルアプリケーションをダウンロードして下さい。

 

カラーテーブルとビットマップ

前述の通り、ビットマップは個別にカラーテーブルを保持することができます。デフォルトのシステムパレットと異なるパレットが必要な場合、ビットマップはカスタムカラーテーブルを持つことになります。ビットマップが独自のカラーテーブルを持つ場合、システムはビットマップを描画する前に描画ウィンドウのカラーテーブルを変換するための変換テーブルを作成しなければなりません。この変換はパフォーマンスの浪費になるため、パフォーマンス要求が重要であればカスタムカラーテーブルの使用はお勧めしません。

ビットマップにカスタムパレットが必要な場合の別の選択肢として、WinPalette 関数を使用して現在使用されているシステムパレットを変更してからビットマップを描画する方法があります。ビットマップが可視状態でなくなったら、再度 WinPalette を使ってシステムパレットを以前の状態に戻して下さい。

 


← 9 節に戻る ↑4 章トップへ 11 節に進む →