|
○ はじめに
DIB ( Device-Independent Bitmap )とは、X Window System における Bitmap のことではなく、カラー情報を自分で持っている Win32API 対応のカラービットマップを表します。世の中で一般的に言われているビットマップとはこの形式を指しています。ここでは、この DIB ファイルを読み込んで画面に表示する DIB Viewer を作成します。
○ DIB ファイルの形式
サンプルプログラムの前に、DIB ファイルの形式 ( フォーマット )について必要な部分についてのみ簡単に説明します。
DIB ファイルは以下の様に構成されています。なお、各構造体は Windows 上のヘッダで定義されているものであることに注意して下さい。
- BITMAPFILEHEADER 構造体 ( ファイルヘッダ )
- BITMAPINFOHEADER 構造体 ( 情報ヘッダ )
- RGBQUAD 構造体 ( 色情報 )
- ピクセルデータ
BITMAPFILEHEADER 構造体は 14 bytes、BITMAPINFOHEADER 構造体は 40 bytes であり、計 54 bytes が DIB ファイルのヘッダとなります。この先頭 54 bytes の中では以下の情報を使用します。
オフセット(byte) | サイズ(byte) | 識別名(構造体のメンバ名) | データの内容 |
---|---|---|---|
0 | 2 | bfType | "BM" という文字列であれば、ビットマップファイル |
10 | 4 | bfOffBits | ファイルの先頭からピクセルデータ領域の先頭までのオフセット。 下にある biBitCount が 16 以上の場合は常に 54。 |
18 | 4 | biWidth | 画像の幅(ピクセル単位) |
22 | 4 | biHeight | 画像の高さ(ピクセル単位) |
28 | 2 | biBitCount | 1 ピクセルあたりのカラービット数 |
30 | 4 | biCompression | ピクセルデータの圧縮の種類。0 ( BI_RGB )、1 ( BI_RLE8 )、2 ( BI_RLE4 )、 3 ( BI_BITFIELDS )のいずれかの値となる。BI_RGB の場合は無圧縮、BI_RLE4は 4 ビットカラー用のランレングス圧縮、BI_RLE8 は 8 ビットカラー用のランレングス 圧縮となる。BI_BITFIELDS の場合は、圧縮はされていないがカラーマスクが 設定されている。BI_BITFIELDS は 16 ビットカラーあるいは 32 ビットカラーの場合にのみ有効。 |
46 | 4 | biClrUsed | biBitCount < 16 であれば、biClrUsed は色数となる。biClrUsed が 0 であれば、 biBitCount に対応した最大色数が使われていることになる。biBitCount >= 16 の場合は Windows で参照される特殊な意味を持つが、特に気にしなくてよい。 |
54 bytes のヘッダが終った後は、色数に応じて RGBQUAD 構造体が続きます。RGBQUAD 構造体の内容は次の通りです。
オフセット(byte) | サイズ(byte) | 内容 |
---|---|---|
0 | 1 | 青の輝度 ( 0 〜 255 ) |
1 | 1 | 緑の輝度 ( 0 〜 255 ) |
2 | 1 | 赤の輝度 ( 0 〜 255 ) |
3 | 1 | 予備 |
ヘッダ情報の biBitCount が 8 以下の場合は、RGBQUAD 構造体が色数個並びます。16 以上の場合は、後述のピクセルデータ自身が色情報を表しているため、RGBQUAD 構造体領域は使用されません( 0 個 )。
RGBQUAD 構造体が並んだ後はピクセルデータが続きます。一般的(と思われる)な順序とは逆に、画像の下行から順に 1 行ずつのピクセルデータが並べられています。また、各行のピクセルデータのサイズが 4 バイト境界に満たない場合は、足りない部分が埋められています。
このピクセルデータは、ヘッダ情報の biBitCount が 8 以下の場合は biCompression が BI_RGB であれば各ピクセルのデータに対応する色番号 ( 前述の RGBQUAD 構造体領域に並べられた色の何番目の色かを表す )が 1 バイトずつ並べられています。biCompression が BI_RLE4 もしくは BI_RLE8 の場合は、カラービット数に応じたランレングス圧縮がかけられています。ランレングス圧縮についてはここではふれません。
biBitCount が 16 以上の場合は、各ピクセル毎に青、緑、赤の順に輝度が並べられています。biCompression が BI_RGB である場合、16 bpp ( biBitCount = 16 )の場合は青、緑、赤それぞれ 5 ビットで表され(残り 1 ビットは意味無し)、24 / 32 bpp の場合は 8 ビットで各色が表現されます(32 bpp の場合の残り 1 バイトは意味無し)。
biCompression が BI_BITFIELDS の場合、独自のカラーマスクが設定されています。カラーマスクの大きさは 4 バイトであり、biBitCount が 8 以下の場合に RGBQUAD 構造体が並べられる位置に 3 つ並べられています( それぞれ青、緑、赤色用)。このカラーマスクとピクセルデータのマスクをとって、実際の色値を取得することになります。
○ サンプルプログラム
256 色以下の DIB ファイルを読み込んで画面に表示する DIB Viewer のサンプルプログラム xdib.c です。画像ファイルの読み込みや書き込みを行う場合は、そのために作成されているライブラリを使うのが一般的だと思いますが、ここでは DIB を読み込む部分から作成します。
はじめに のページから、全てのサンプルプログラムを固めた tar ボールをダウンロードすることもできます。
冒頭にあるように、DIB ファイルは 256 色以下の色数のものを対象とします。ピクセルデータ部は無圧縮であることを前提とします( biCompression が BI_RGB )。また、スクリーンの深さは 16、32 bpp であることを前提とします。それ以外の深さのスクリーンで実行した場合や、256 色より色数の多い、あるいは biCompression が BI_RGB でない DIB ファイルを読み込んだ場合にはそこで終了します。
(24 bpp の場合は正常に動作しない場合がありました。陸さん、ありがとうございました。2004/11/28)
コンパイルを終えたら、DIB ファイル名を引数に与えて実行してみて下さい。DIB ファイルが画面に表示されると思います。ちなみに下図は知り合いの車をデジカメで写した DIB ファイルを表示させた画面をキャプチャしたものです。
--- xdib.c ---
1 #include <X11/Xlib.h> 2 #include <X11/Xutil.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #define WIN_X 100 /* ウィンドウ表示位置(X) */ 8 #define WIN_Y 100 /* ウィンドウ表示位置(Y) */ 9 10 11 /* DIB ファイルの画像情報を格納する構造体 */ 12 typedef struct _DIBImage_t 13 { 14 int width; /* 画像の幅 */ 15 int height; /* 画像の高さ */ 16 int n_color; /* 画像の色数 */ 17 unsigned char palette[256][3]; /* パレット情報 */ 18 unsigned char* data; /* ピクセルデータ */ 19 } 20 DIBImage; 21 22 23 static Display* dpy; /* ディスプレイ */ 24 static Window root, win; /* ルートウィンドウおよび表示ウィンドウ */ 25 static int screen; /* スクリーン */ 26 static int depth; /* スクリーンの深さ */ 27 static Pixmap pixmap; /* ピクスマップ */ 28 static GC gc; /* グラフィックスコンテキスト */ 29 static XColor* colors; /* DIB ファイルのパレット情報を格納する領域 */ 30 31 32 static int xdib_readFile( char* fname, DIBImage* dib_image ); 33 static void xdib_setup( DIBImage* dib_image ); 34 35 36 int 37 main( int argc, char** argv ) 38 { 39 XEvent evt; 40 DIBImage dib_image; 41 42 43 /* 指定された DIB ファイルを読み込んで画像情報を保存する */ 44 if ( xdib_readFile( argv[1], &dib_image ) == 0 ) { 45 printf( "Failed to read specified DIB file : %s\n", argv[1] ); 46 return 1; 47 } 48 49 dpy = XOpenDisplay( "" ); 50 51 root = DefaultRootWindow( dpy ); 52 screen = DefaultScreen( dpy ); 53 depth = DefaultDepth( dpy, screen ); 54 55 /* depth が 16、32 以外の場合はここで終了する */ 56 if ( depth != 16 && depth != 32 ) { 57 XCloseDisplay( dpy ); 58 printf( "Screen depth is not 16 nor 32 bpp.\n" ); 59 return 1; 60 } 61 62 63 win = XCreateSimpleWindow( dpy, root, WIN_X, WIN_Y, 64 dib_image.width, 65 dib_image.height, 66 0, 67 BlackPixel( dpy, screen ), 68 BlackPixel( dpy, screen ) ); 69 70 gc = XCreateGC( dpy, win, 0, NULL ); 71 72 /* 読み込んだ DIB ファイル情報を表示できるように設定する */ 73 xdib_setup( &dib_image ); 74 75 XSelectInput( dpy, win, ExposureMask | KeyPressMask ); 76 XMapWindow( dpy, win ); 77 78 while( 1 ) { 79 XNextEvent( dpy, &evt ); 80 81 switch( evt.type ) { 82 case Expose: 83 if ( evt.xexpose.count == 0 ) { 84 /* ピクスマップをウィンドウにコピーする */ 85 XCopyArea( dpy, pixmap, win, gc, 86 0, 0, 87 dib_image.width, 88 dib_image.height, 89 0, 0 ); 90 XFlush( dpy ); 91 } 92 break; 93 94 case KeyPress: 95 free( colors ); 96 XFreePixmap( dpy, pixmap ); 97 XDestroyWindow( dpy, win ); 98 XCloseDisplay( dpy ); 99 return 0; 100 } 101 } 102 } 103 104 105 /* 106 * 指定した DIB ファイルを読み込み、画像情報を dib_image 変数 107 * に格納する。ピクセルデータを保存するための dib_image.data 108 * 領域は関数内で確保する。そのため本関数を利用する際には、 109 * dib_image.data が未確保である dib_image 変数へのポインタを 110 * 引数に指定すること。 111 * 読み込み処理に失敗した場合は 0 を、成功した場合はそれ以外の値を返す。 112 */ 113 static int 114 xdib_readFile( char* fname, DIBImage* dib_image ) 115 { 116 unsigned char buf[4]; 117 FILE* fp; 118 int i; 119 int dib_depth; 120 int offset; 121 int bw; 122 int index; 123 124 125 if ( ( fp = fopen( fname, "r" ) ) == NULL ) { 126 printf( "Failed to open %s.\n", fname ); 127 return 0; 128 } 129 130 131 /* 先頭 2 バイトが "BM" であれば、BMP ファイル */ 132 fread( buf, 2, 1, fp ); 133 134 if ( strncmp( ( char* )buf, "BM", 2 ) != 0 ) { 135 printf( "Specified file is not DIB file.\n" ); 136 return 0; 137 } 138 139 140 /* ファイルの先頭から 28 バイトの位置に移動 */ 141 fseek( fp, 28, SEEK_SET ); 142 143 /* 1 ピクセルあたりのビット数を取得 */ 144 fread( buf, 2, 1, fp ); 145 dib_depth = buf[0] + ( buf[1] << 8 ); 146 147 /* 256 色以下のファイルが対象 */ 148 if ( dib_depth > 8 ) { 149 printf( "Specified file is more than 8 bpp ( %d bpp ).\n", dib_depth ); 150 return 0; 151 } 152 153 154 /* ファイルの先頭から 30 バイトの位置に移動 */ 155 fseek( fp, 30, SEEK_SET ); 156 fread( buf, 4, 1, fp ); 157 158 /* 読み込んだ値が 0 でなければ、biCompression が BI_RGB でない 159 (ピクセルデータが圧縮されている)ので、ここで終了する。*/ 160 161 if ( buf[0] != 0 ) { 162 printf( "Specified DIB file is compressed\n" ); 163 return 0; 164 } 165 166 167 /* ファイルの先頭から 46 バイトの位置に移動 */ 168 fseek( fp, 46, SEEK_SET ); 169 fread( buf, 4, 1, fp ); 170 171 /* 読み込んだ値が 0 でなければ、depth によって色数が決まる。 172 256 色以下のファイルであるため、最初の 1 バイトのみを考えれば良い */ 173 if ( buf[0] == 0 ) { 174 dib_image->n_color = 1 << dib_depth; 175 } 176 else { 177 dib_image->n_color = buf[0]; 178 } 179 180 181 /* ファイルの先頭から 10 バイトの位置に移動 */ 182 fseek( fp, 10, SEEK_SET ); 183 184 /* ファイルの先頭からピクセルデータ領域の先頭までのオフセットを取得 */ 185 fread( buf, 2, 1, fp ); 186 offset = buf[0] + ( buf[1] << 8 ); 187 188 189 /* ファイルの先頭から 18 バイトの位置に移動 */ 190 fseek( fp, 18, SEEK_SET ); 191 192 /* 画像の幅を取得 */ 193 fread( buf, 4, 1, fp ); 194 195 dib_image->width = buf[0] + ( buf[1] << 8 ) + 196 ( buf[2] << 16 ) + ( buf[3] << 24 ); 197 198 /* 画像の高さを取得 */ 199 fread( buf, 4, 1, fp ); 200 201 dib_image->height = buf[0] + ( buf[1] << 8 ) + 202 ( buf[2] << 16 ) + ( buf[3] << 24 ); 203 204 205 /* ファイルの先頭から 54 バイトの位置に移動 */ 206 fseek( fp, 54, SEEK_SET ); 207 208 /* パレット情報を取得 */ 209 for ( i = 0; i < dib_image->n_color; i ++ ) { 210 fread( buf, 4, 1, fp ); 211 dib_image->palette[i][0] = buf[2]; 212 dib_image->palette[i][1] = buf[1]; 213 dib_image->palette[i][2] = buf[0]; 214 } 215 216 217 /* 画像の 1 行分のバイト数は、画像の幅に 1 番近い 4 の倍数に繰り上げられる */ 218 bw = ( dib_image->width + 3 ) & ~3; 219 220 221 /* ピクセルデータ領域の確保 */ 222 dib_image->data = 223 ( unsigned char* )malloc( dib_image->width * dib_image->height ); 224 225 for ( i = 0; i < dib_image->height; i ++ ) { 226 /* ピクセルデータ領域の先頭から 1 行ずつ読み込む */ 227 fseek( fp, offset + bw * i, SEEK_SET ); 228 229 /* 230 * DIB 内のピクセルデータは下行から順に詰められている。 231 * dib_image->data には上行から順に詰めるため、対応する 232 * インデックスを計算している。 233 */ 234 index = dib_image->width * ( dib_image->height - i - 1 ); 235 236 /* 1 行読み込み */ 237 fread( &( dib_image->data[ index ] ), dib_image->width, 1, fp ); 238 } 239 240 fclose( fp ); 241 return 1; 242 } 243 244 245 /* 246 * 読み込んだ DIB ファイル情報を使って、実際にウィンドウ 247 * に表示できるように設定を行う 248 */ 249 static void 250 xdib_setup( DIBImage* dib_image ) 251 { 252 /* 253 * 読み込んだ DIB ファイルの画像情報をクライアント側で 254 * 保持するための XImage 構造体 255 */ 256 XImage* ximage; 257 258 /* クライアント側から X サーバに転送するピクセルデータを格納する領域 */ 259 unsigned char* img_data; 260 261 int size; 262 int i; 263 264 265 /* DIBImage 型変数に格納されたカラーパレット情報を、XColor 構造体の 266 配列形式に変換する */ 267 colors = ( XColor* )malloc( sizeof( XColor ) * dib_image->n_color ); 268 269 for ( i = 0; i < dib_image->n_color; i ++ ) { 270 colors[i].red = dib_image->palette[i][0] * 257; 271 colors[i].green = dib_image->palette[i][1] * 257; 272 colors[i].blue = dib_image->palette[i][2] * 257; 273 colors[i].flags = DoRed | DoGreen | DoBlue; 274 275 XAllocColor( dpy, DefaultColormap( dpy, screen ), &colors[i] ); 276 } 277 278 279 /* X サーバ側で画像を保持するためのピクスマップを作成する */ 280 pixmap = XCreatePixmap( dpy, win, 281 dib_image->width, 282 dib_image->height, 283 depth ); 284 285 286 /* スクリーンの深さに合わせた、転送用ピクセルデータを作成する */ 287 size = dib_image->width * dib_image->height; 288 img_data = ( unsigned char* )malloc( size * depth / 8 ); 289 290 memset( img_data, 0, size * depth / 8 ); 291 292 293 /* 294 * DIBImage 内のピクセルデータは、パレット情報配列のどの要素が 295 * ピクセルに対応する色であるかを表している。 転送用のピクセル 296 * データは、 スクリーンの深さと同じビット数で表された各色の 297 * ピクセル値でなければならないので、ここで変換を行う。 298 */ 299 for ( i = 0; i < size; i ++ ) { 300 memcpy( img_data + i * ( depth / 8 ) , 301 &( colors[dib_image->data[i]].pixel ), depth / 8 ); 302 } 303 304 305 /* クライアント側の画像情報保持領域である XImage 構造体変数を作成する */ 306 ximage = XCreateImage( dpy, DefaultVisual( dpy, screen ), 307 depth, ZPixmap, 0, 308 ( char* )img_data, 309 dib_image->width, 310 dib_image->height, 311 /* 16 bpp の場合は 16、24 / 32 bpp の場合は 32 にする */ 312 ( depth == 16 ) ? 16 : 32, 313 0 ); 314 315 /* ピクセルデータをピクスマップに転送する */ 316 XPutImage( dpy, pixmap, gc, ximage, 317 0, 0, 318 0, 0, 319 dib_image->width, 320 dib_image->height ); 321 322 XFlush( dpy ); 323 XDestroyImage( ximage ); 324 free( dib_image->data ); 325 } 326 327 328 /* End of xdib.c */
○ サンプルプログラムの説明
では、サンプルプログラムについて説明していきます。
- 11 〜 20 行目
105 行目からの DIB 読み込み関数 xdib_readFile() によって読み込んだ DIB ファイル情報 を格納するための構造体 DIBImage を定義しています。palette は、RGB の輝度 ( 0 〜 255 ) を最大 256 色分格納するための領域です。data には、画像の各ピクセルを palette に格納 されている何番目の色で表示するかを表す番号が、画像の上行から順に 1 バイトずつ格納され ます。
- 27 行目
ここで宣言されている pixmap には、ウィンドウに表示する画像がロードされます。main() を見る際には、この pixmap に画像がロードされているからそれをウィンドウにコピーして画 像を表示しているんだなと思って下さい。pixmap に画像がロードされる過程については main() の説明の後で説明します。
- 36 〜 102 行目 ( main() )
xdib.c の main 関数です。各処理について以下で説明していきます。
- 43 〜 47 行目
xdib_readFile() を実行して、引数で指定された DIB ファイルを読み込みます。読み込みに失 敗した場合はここで終了します。
- 55 〜 60 行目
直前にディスプレイマクロで取得したスクリーンの深さが 16、32 bpp 以外の場合は、ここで終了 しています。
- 63 〜 68 行目
画像表示用のウィンドウを作成しています。既に読み込み済みの DIB ファイル情報を使ってウ ィンドウの幅と高さを指定している点に注意してください。
- 72 〜 73 行目
xdib_setup() を実行して、読み込んだ DIB ファイル情報を作成したウィンドウに表示できる ようにするための処理を行っています。処理内容をおおまかに言うと、読み込んだ DIB ファイルのピクセルデータと XImage 構造体変数を関係付け、その XImage 構造体変数を使って最終的に ウィンドウに表示するために使用する pixmap に画像をロードしています。詳細は後述します。
- 82 〜 92 行目
Expose イベントに対するイベント処理部です。ここでは、xdib_setup() によって画像が ロードされた pixmap の内容を XCopyArea() を使ってそのままウィンドウにコピーしています。
- 105 〜 242 行目 ( xdib_readFile() )
DIB ファイルを読み込んで、DIBImage 型変数に情報を格納する関数です。この関数内では、 DIB ファイルの形式 において取り上げた必要な情報を読み込んで引数 で指定された DIBImage 型変数領域に内容を格納しているだけです。特に注意すべき点について、 以降で説明します。
- 167 〜 178 行目
DIB ファイルの形式 で取り上げた biClrUsed が 0 の場合は、色数を 2 の biOffBits 乗として計算し、biClrUsed が 0 である場合にはそれを色数としています。
- 205 〜 214 行目
カラーパレットデータを読み込んでいます。DIB ファイル内のパレットデータでは、輝度が青、 緑、赤の順に並んでいるのに対して DIBImage 構造体の palette メンバには赤、緑、青の順に 詰め直している点に注意して下さい。
- 217 〜 218 行目
DIB ファイル内のピクセルデータ 1 行分のバイト数を計算しています。DIB ファイル内では、 1 行のバイト数を 4 バイト境界に合わせるためにパディングされているため、画像幅に 1 番近い 4 の倍数として計算しています。
/* 画像の 1 行分のバイト数は、画像の幅に 1 番近い 4 の倍数に繰り上げられる */ bw = ( dib_image->width + 3 ) & ~3;
上のコードで ~3 ( 2進数で 11111100 )と AND 演算を行っていますが、これは 11111100 と の AND を取ることで下位 2 ビットを落しています。dib_image->width + 3 によって、画像 の幅に 1 番近い 4 の倍数もしくはそれより 1 〜 3 大きい数値が得られるので、 その数値の下位 2 ビットを落す( 0 〜 3 の数値を切捨てる ) ことによって 1 番近い 4 の倍数を計算しています。
- 221 〜 238 行目
ピクセルデータを読み込んでいます。DIB ファイル内ではピクセルデータは下行から順に詰められているのに対して、 DIBImage 構造体の data メンバには上行から順に詰めるため、読み込んだデータを格納する インデックスをあらかじめ計算してから読み込みを行っています。
- 245 〜 325 行目 ( xdib_setup() )
DIBImage 型変数に読み込んだ画像情報を pixmap にロードしてウィンドウにコピーできるようにするための 処理を行っています。
読み込んだピクセルデータとパレットデータを使って、ウィンドウに対して XDrawPoint() で全ての点を描画しても表示できるのですが、それではネットワーク遅延による影響が大きくなってしまいます。 それを避けるために、まずクライアント側にピクセルデータを格納できる XImage 構造体を作成して、そこに読み込んだピクセルデータを格納します。その後で X サーバ側の Pixmap にピクセルデータを一気に転送します。
なお、Pixmap ではなく表示用ウィンドウに直接転送しても構いませんが、その場合、表示用 ウィンドウが別のウィンドウに隠れたりして描画内容が失われた場合に再度クライアント側から ピクセルデータを転送しなおさなければなりません。Pixmap に転送しておけば、サーバ側での転送だけで済みます。
具体的な処理内容については、以降で説明していきます。
- 265 〜 276 行目
DIBImage 型変数に格納されたカラーパレットデータを、XColor 型の形式に変換しています。 各原色の輝度を 257 倍しているのは、DIBImage のパレットデータの輝度が 0 〜 255 であるのに対して、 X のカラーマップでは 0 〜 65535 の範囲で指定するためです。
XColor 形式に変換した後は、XAllocColor() で対応するピクセル値を取得しています。
- 286 〜 302 行目
DIBImage 型変数に格納されたピクセルデータを Pixmap に転送するためには、後程 XImage 構造体を作成する必要がありますが、その際に必要となるピクセルデータ格納領域を作成しています。 スクリーンの深さが 16、32 bpp の場合はそれぞれ 1 ピクセルを 2、4 バイトで格納するため、 サンプルの様なコードの書き方をしています。24 bpp の場合は、3 バイトで表す場合や 4 バイトで格納する場合があるため、 状況に応じて書き方を変える必要があります。 これには利用中の X サーバでサポートしている Pixmap フォーマットを XListPixmapFormats 等で調べる必要がありますが、ここでは 16、32 bpp に環境を限定して話を簡単にしています。
陸さん、情報ありがとうございました!(2004/11/28)
DIBImage 型変数に格納されたピクセルデータは、パレットデータの何番目の色で表示するかを表しています。 パレットデータの各色を、その順番通りのピクセル値で確保できれば良いのですが、16 bpp 以上の深さのスクリーンの場合はカラーマップの構造上不可能です ( 1 つのピクセル値を何ビットずつかに分けて、 それぞれが赤、緑、青に対応するピクセル値となるから。なお 8 bpp 以下の場合は可能ですが、その場合最大 256 色を確保するためには、専用のカラーマップを作成して XStoreColor() で任意のピクセル値に色を設定する必要があります)。
よって、XAllocColor() で得た各色に対応するピクセル値を使ってピクセルデータを変換しています。 変換後のピクセルデータは img_data に格納されますが、各ピクセルのピクセル値を格納している点に注意して下さい。
- 305 〜 313 行目
XCreateImage() を使って、クライアント側にピクセルデータを格納するための領域である XImage 構造体を作成しています。
XImage* XCreateImage( Display* dpy, Visual* visual, unsigned int depth, int format, int offset, char* data, unsigned int width, unsigned int height, int bitmap_pad, int bytes_per_line ); depth : 画像の深さ format : XYBitmap / XYPixmap / ZPixmap のいずれか offset : 画像データの各走査線の先頭で無視するピクセル数 data : 画像データ領域へのポインタ width : 画像の幅 height : 画像の高さ bitmap_pad : 画像データのある走査線の先頭から次の走査線の先頭までのビット数 が 8、16、32 のいずれの数で割り切れるかを指定する bytes_per_line : 画像データの 1 走査線のバイト数
第 4 引数の format に指定する XYBitmap / XYPixmap / ZPixmap についてですが、これは第 6 引数の data の形式を指定する値です。XYBitmap の場合、data の値はビットマップデータ ( 0 もしくは 1 ) が走査線順に並んでいると解釈されます。XYPixmap の場合は、ビットマップのデータが プレーンごとに並びます。ZPixmap を指定した場合、ピクセル値が走査線順に並んでいると解釈されます。 xdib.c ではピクセル値によってピクセルデータを指定することにしたため、ZPixmap を指定しています。
第 10 引数の bytes_per_line は、画像データの 1 走査線を表すために data に格納しているバイト数を指定します。ここを 0 に設定した場合、他のパラメータに従って Xlib が自動的に計算してくれます。
- 313 〜 318 行目
XImage 型変数に格納されたピクセルデータを、XPutImage() を使って X サーバ側のピクスマップに転送しています。 これにより、ピクセルデータを再度サーバ側に転送する必要が無くなります。 ここでピクスマップの代わりに表示用ウィンドウに転送すれば、直接表示することができます。
XPutImage( Display* dpy, Drawable d, GC gc, XImage* image, int src_x, src_y, int dest_x, dest_y, unsigned int width, height ); src_x, src_y : 転送元イメージの転送領域左上角の座標 dest_x, dest_y : 転送先イメージの転送領域左上角の座標 width, height : 転送領域の幅と高さ
- 322 行目
XFlush() を実行してリクエストバッファをフラッシュさせ、ピクスマップへの転送要求が実際 にサーバに送られるまで待っています。
- 323 〜 324 行目
xdib_setup() 内で確保したリソースのうち、不要になったものを解放しています。確保した XImage 構造体は、XDestroyImage() を使って解放します。
XDestroyImage( XImage* ximage );
XCreateImage()、XGetImage()、XGetSubImage() で作った XImage 型変数領域を解放する場合、 XImage 型変数領域そのものと data で指定されるデータ領域の両方が解放されます。この時データ領域が static 領域に確保されている場合はメモリを解放できないため、data メンバに NULL を設定する必要があります。
以上で xdib.c の説明は終りです。以降では、ここまでで紹介していない XImage 構造体データ操作用のいくつかの関数について説明していきます。
○ウィンドウもしくはピクスマップの画像データを取得する
ウィンドウもしくはピクスマップの画像データをクライアント側に取得するには、XGetImage() を使います。
XImage* XGetImage( Display* dpy, Drawable d, int x, y, unsigned int width, height, unsigned long plane_mask, int format ); d : 画像データを取得したい Drawable を指定 x, y : 画像データを取得したい領域の左上角の座標 width, height : 画像データを取得したい領域の幅と高さ plane_mask : 画像データを取得したいプレーンを指定 format : XYBitmap / XYPixmap / ZPixmap のいずれか
plane_mask には画像データを取得したいプレーンをマスク指定します。Xlib.h に AllPlanes という定数が定義されていて、これを指定すると全てのプレーンを指定することができます。
○ピクセルデータを操作する
XImage 型変数に対してピクセルデータの操作をする関数を以下にまとめて紹介します。
unsigned long XGetPixel( XImage* ximage, int x, int y ); XPutPixel( XImage* ximage, int x, int y, unsigned long pixel ); XAddPixel( XImage* ximage, long value );
XGetPixel() は、x、y で指定した位置のピクセルデータのピクセル値を取得します。XPutPixel() は、指定した位置のピクセルデータに指定したピクセル値を設定します。XAddPixel() は、全てのピクセル値に指定した値を加算します。