(注意)南校舎のSolaris2.Xでは X11 Window System の本当の 置き場所は /usr/local/X11R6.4 です。 しかし、多くの Linux ディストリビューションと設定状況を 合わせるために、 /usr/X11R6.4 および /usr/X11R6 から /usr/local/X11R6.4へ シンボリック・リンクが張られています。 このプリントでは今まで
/usr/X11R6 ← Linuxの場合
/usr/X11R6.4 ← 南校舎のSolaris2.Xの場合
としてOS別に説明してきましたが、以後、X11の置き場所として
/usr/X11R6 に統一して説明することにします。
色は「光の3原色」である「赤(Red)」、「緑(Green)」、「青(Blue)」 それぞれの明るさを混ぜ合わせたものです。 赤、緑、青それぞれについて256段階(すなわち8bit)の明るさが 区別できるとすると、それらを組合せて表現できる色の数は
256×256×256 = 16777216 (= 2^24) 通り
となります。
ただし全ての計算機が1600万色を同時に出力できる表示装置を持っている
わけではなく、同時に利用できる色数はシステムによって異なります。
最近のパソコンは同時に 1600万色使えるものが多くなってきました。
津田塾大学の南校舎のWorkStationでも同時に1600万色を使うことができます。
同時発色数が限られたなかで色を最大限に利用するために X Window Systemでは『カラーマップ (colormap)』を使います。 カラーマップとは色を登録した表のことで、表の各項目は カラーセルと呼ばれます。 ある色をカラーマップに登録したときの 「表の何番目に登録されたか(=インデックス)」 がピクセル値で、描画における色の指定はこのピクセル値を 用いて行ないます。 すなわち、X Windowのプログラムではまず使いたい色をカラーマップに 登録しておいて、登録したピクセル値を用いてグラフィックコンテクスト に色を設定し、そのグラフィック・コンテクストを用いて描画するわけです。
デフォルトのカラーマップはDefaultColormap()マクロによって 取得することができます。 デフォルトのカラーマップを使うと1つのカラーマップを 他のアプリケーションと共有することになります。
Colormap DefaultColormap(Display *dpy, int scr)マクロ 指定したスクリーンに割り当てられているカラーマップのIDを返す
![]()
デフォルト・カラーマップの取得 Display *dpy; int scr; Colormap cmap; ... dpy = XOpenDisplay(...); scr = DefaultScreen(dpy); cmap = DefaultColormap(dpy,scr);
![]()
取得したカラーマップに、RGB値で指定する色を割り当てるには XAllocColor()関数を使います。 色の指定には XColor 構造体を用います。
XColor構造体のflagで使う定数 (X11/X.hより抜粋) /* Flags used in StoreNamedColor, StoreColors */ #define DoRed (1<<0) #define DoGreen (1<<1) #define DoBlue (1<<2)
![]()
XColor構造体の定義 (X11/Xlib.hより抜粋) typedef struct { unsigned long pixel; unsigned short red, green, blue; char flags; /* do_red, do_green, do_blue */ char pad; } XColor;
![]()
関数 Status XAllocColor(Display *dpy,Colormap cmap, XColor *def); カラーマップ中の空いているカラーセルに色を割り当てます。 割り当てに失敗した場合は0が返されます。
![]()
RGB値で色をカラーマップに登録するコード XColor color_def; ... color_def.flags = DoRed | DoGreen | DoBlue; color_def.red = 赤の明るさ; color_def.green = 緑の明るさ; color_def.blue = 青の明るさ; if (XAllocColor(dpy,cmap,&color_def) == 0) { /* 色の割り当てに失敗 */ } ... gcv.foreground = color_def.pixel; /* 割り当てたピクセル値を使う */ gc = XCreateGC(dpy,win,GCForeground | ..., &gcv); ...
![]()
「RGB値」の代わりに「色の名前」を使うには、XParseColor()関数を使って 「色の名前」から「RGB値」に変換します。 XParseColor()関数は、色の名前(たとえば "red"や"pink")以外にも、 RGB値を16進数で表現した文字列 ("#RRGGBB" または "#RRRRGGGGBBBB" の形式) を解釈することができます。
ちなみにXサーバが参照する「色の名前」と「RGB値」の対応表は /usr/X11R6/lib/X11/rgb.txt にあります。関数 Status XParseColor(Display *dpy, Colormap cmap, char *spec, XColor *def) 色の名前からRGB値をdefに得ます。 失敗の場合は0を返します。
![]()
色の名前からRGB値への変換 XColor color_def; Colormap cmap; char *colorname = "red"; .... if (XParseColor(dpy,cmap,colorname,&color_def) == 0) { エラー } /* color_defの中のred,green,blueフィールドにRGB値が設定されている */
![]()
rgb.txt (色の名前とRGB値の対応表) 255 250 250 snow 248 248 255 ghost white 248 248 255 GhostWhite ... 255 0 0 red 255 105 180 hot pink ... 255 255 255 white 0 0 0 black ...
![]()
色を使う例 x4.cを示します。 x4.cの中では、「ルート・ウィンドウの深さを返す」関数
DisplayDepth(Display *dpy, int scr)の返り値を用いて、カラーが使えるか否かを判断しています (値が1の場合はモノクロ、それ以外はカラーが使えると判断します)。

| x4.c |
#include <stdio.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int main(int argc, char **argv) {
Display *dpy;
int scr;
Window win;
XSetWindowAttributes xswa;
char *xservname=NULL;
GC gc;
XGCValues gcv;
char *colorname="red";
if (argc >= 2) {
colorname = argv[1];
}
if ((dpy=XOpenDisplay(xservname)) == NULL) {
fprintf(stderr,"can not open %s\n",XDisplayName(xservname));
exit(-1);
}
scr = DefaultScreen(dpy);
xswa.background_pixel = WhitePixel(dpy,scr);
xswa.border_pixel = BlackPixel(dpy,scr);
xswa.event_mask = ExposureMask | ButtonPressMask;
win = XCreateWindow(dpy,RootWindow(dpy,scr),0,0,320,240,1,
CopyFromParent,CopyFromParent,CopyFromParent,
CWBackPixel | CWBorderPixel | CWEventMask, &xswa);
if (DefaultDepth(dpy,scr) == 1) {
gcv.foreground = BlackPixel(dpy,scr);
} else {
XColor color_def;
Colormap cmap = DefaultColormap(dpy,scr);
if (!XParseColor(dpy,cmap,colorname,&color_def)) {
fprintf(stderr,"color %s not in database\n",colorname);
exit(-1);
}
if (!XAllocColor(dpy,cmap,&color_def)) {
fprintf(stderr,"all colorcells allocated and read/write\n");
exit(-1);
}
gcv.foreground = color_def.pixel;
}
gcv.background = WhitePixel(dpy,scr);
gc = XCreateGC(dpy,win,GCForeground|GCBackground,&gcv);
XMapWindow(dpy,win);
for (;;) {
XEvent ev;
XNextEvent(dpy,&ev);
switch (ev.type) {
case Expose:
XClearWindow(dpy,win);
XFillRectangle(dpy,win,gc,10,10,100,50);
break;
case ButtonPress:
if (ev.xbutton.button == 3) exit(0);
break;
default:
printf("unknown event %d\n",ev.type);
break;
}
}
}
|
| x4.cの実行 (指定する色を何種類か変えて起動してみましょう) |
[コンパイル] Solaris2.Xの豺腓 侑詫來髭苳紫窿 ㍗齟臼匐釿跿粤 ㍼ ㌣齟臼匐蛯 ㈹惘㈹齒站續 ㈹銖讀踉晒髭苳浜嘔箪跫竅讚蜒闔鶩緕鬯芍罌 也銛ぢの豺腓 侑詫來髭苳紫窿 ㍗齟臼匐釿跿粤 ㍼ ㌣齟臼匐蛯 ㈹惘右踉晒髭苳浜嘔箪跫竅讚蜒闔鶩緕鬯芍罌 ぢ孫侑詫來髭苳侍闌續ゔ 浜嘔箪跫竅讚蜒闔鶩緕鬯芍罌 ← x4 #ee82ee と同じ (∵ 238 130 238 violet) PROMPT$ <I>x4 tomato</I> <IMG SRC="/local-icons/enter.gif"> ← x4 #ff6347 と同じ (∵ 255 99 71 tomato) PROMPT$ <I>x4 slateblue</I> <IMG SRC="/local-icons/enter.gif"> ← x4 #6a5acd と同じ (∵ 106 90 205 slateblue) |
XサーバのVisual(=色の表し方)には以下のクラスがあります。
red, green, blue はそれぞれ 0〜255の値を取るものとして、 TrueColorのXサーバで(red, green, blue)の組み合わせて表現できる 色を画面に表示するには以下のようなコードを書きます。
| visual.c |
static int getshiftbit(unsigned long mask) {
int i, n;
for (i=0; i<sizeof(mask)*8; i++) {
if (mask & 1) {
if (mask == 0xff) return(i);
else return(-1);
}
mask >>= 1;
}
return(-1);
}
int use_truecolor=0;
int nshift_red, nshift_green, nshift_blue;
int main() {
int red, gree, blue;
XGCValues xgcv;
...
if (DefaultDepath(dpy,scr) == 24) {
XVisualInfo xvit, *xvi;
int n, i;
xvit.depth = 24;
xvit.class = TrueColor;
xvi = XGetVisualInfo(xwin->dpy,VisualDepthMask|VisualClassMask,&xvit,&n);
if (xvi) {
for (i=0; i<n; i++) {
nshift_red = getshiftbit(xvi->red_mask);
nshift_green = getshiftbit(xvi->green_mask);
nshift_blue = getshiftbit(xvi->blue_mask);
if (nshift_red >= 0 && nshift_green >= 0
&& nshift_blue >= 0) {
use_truecolor=1;
break;
}
xvi++;
}
}
}
...
for (;;) {
...
if (use_truecolor) {
gcv.forground =
red << nshift_red
+ green << nshift_green
+ blue << nshift_blue;
} else {
gcv.foreground = (red, green, blue)に似た色のピクセル値;
}
XChangeGC(dpy,gc,GCForeground,&gcv);
...
XDrawPoint(dpy,win,gc,x,y);
}
}
|

課題が完成したら x11.c を p2r10@nw.tsuda.ac.jp へ送って下さい。 Subject は report として下さい。
オプション課題ができた人は、課題番号に応じて Subjectを option 3 または option 4として x11b.c または x11c.c をp2r10@nw.tsuda.ac.jpに送って下さい。
上記の Email アドレス宛に送ったメイルは http://nw.tsuda.ac.jp/cgi-bin/cgiwrap/p2r10/mailhead でヘッダ部が参照できます。 Emailを送ったあとで、正しく提出されたかどうか確認しておいて下さい。
提出期限は来週木曜日の8:50a.m. です。