(注意)南校舎の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. です。