4. Image  
在 GUI 介面下, 常会需要将一张图片直接 show 在视窗上, 像是 show 照片. Xlib 提供一些可以直接在 client 和 server 间传送影像(image)的函数, 以直接处理一张张的影像, 例如, 图形档. 在这提到的 image 相关函数, 都会使用 XImage 结构做为函数的输入参数. Xlib 在 client 端使用 XImage 描述影像资料, 当你要使用 Xlib 的函数处理影像资料时, 必需透过 XImage 进行操作. XImage 提供一个物件化的介面, 透过物件提供的函数, 我们可以相同的方式, 处理不同的影像资料.  
-------------------------------------------------------------------------------- 

/* 
* Data structure for "image" data, used by image manipulation routines. 
*/ 
typedef struct _XImage { 
     int width, height;           /* size of image */ 
     int xoffset;                 /* number of pixels offset in X direction */ 
     int format;                  /* XYBitmap, XYPixmap, ZPixmap */ 
     char *data;                  /* pointer to image data */ 
     int byte_order;              /* data byte order, LSBFirst, MSBFirst */ 
     int bitmap_unit;             /* quant. of scanline 8, 16, 32 */ 
     int bitmap_bit_order;        /* LSBFirst, MSBFirst */ 
     int bitmap_pad;              /* 8, 16, 32 either XY or ZPixmap */ 
     int depth;                   /* depth of image */ 
     int bytes_per_line;          /* accelarator to next line */ 
     int bits_per_pixel;          /* bits per pixel (ZPixmap) */ 
     unsigned long red_mask;      /* bits in z arrangment */ 
     unsigned long green_mask; 
     unsigned long blue_mask; 
     XPointer obdata;             /* hook for the object routines to hang on */ 
     struct funcs {               /* image manipulation routines */ 
         struct _XImage *(*create_image)(); 
#if NeedFunctionPrototypes 
         int (*destroy_image)         (struct _XImage *); 
         unsigned long (*get_pixel)   (struct _XImage *, int, int); 
         int (*put_pixel)             (struct _XImage *, int, int, unsigned long); 
         struct _XImage *(*sub_image)(struct _XImage *, int, int, unsigned int, unsigned int); 
         int (*add_pixel)             (struct _XImage *, long); 
#else 
         int (*destroy_image)(); 
         unsigned long (*get_pixel)(); 
         int (*put_pixel)(); 
         struct _XImage *(*sub_image)(); 
         int (*add_pixel)(); 
#endif 
         } f; 
} XImage; 


-------------------------------------------------------------------------------- 
XImage 可以建过 XInitImage 和 XCreateImage 建立. 建立之後的 object, 可以使用 XGetPixel, XPutPixel, XSubImage 和 XAddPixel 读取和修改内容. 使用 XPutImage 输出到 drawable (视窗或 pixmap), 使用 XGetImage 从 drawable 读取. object 最後必需使用 XDestroyImage 释放. 


-------------------------------------------------------------------------------- 

        Status XInitImage(image) 
              XImage *image; 


-------------------------------------------------------------------------------- 
XImage 在使用之前, 必需先经过 XInitImage 进行 initialize. 在呼叫 XInitImage 之前, 除了 manipulate functions 之外, 其它的栏位都必需 先设定好. 成功的话, 传回非0值, 否则传回 0. 


-------------------------------------------------------------------------------- 

        XImage *XCreateImage(display, visual, depth, format, off- 
        set, data, width, height, bitmap_pad, 
                                bytes_per_line) 
              Display *display; 
              Visual *visual; 
              unsigned int depth; 
              int format; 
              int offset; 
              char *data; 
              unsigned int width; 
              unsigned int height; 
              int bitmap_pad; 
              int bytes_per_line; 


-------------------------------------------------------------------------------- 
XCreateImage 会为输入之影像资料产生一个 XImage 结构, 并传回结构. 是一个包装 XInitImage 的函数. 'format' 指定影像储存的形式, 有 ZPixmap, XYPixmap 和 XYBitmap. ZPixmap 的储存方式是一个 pixel 接 着一个 pixel 存放. XYPixmap 则是 plane 接着 plane, 将所有 pixel 特定 plane 的内容集成 bitmap, 然後依 plane 的顺序储存各 plane 形式的 bitmap. XYBitmap 和 XYPixmap 一样, 但是 XYBitmap只有一个 plane. 而, 影像的内容则存在 data 所指定的 memory block . 使用者必需指定一块记忆(data)以储存影像, XCreateImage 并不会主动为您配置. data 的大小和 image 的大小和深度(depth)有关, format 也会影响. 下面是 data 大小和 bytes_per_line 的计算公式.  
format   size of data   bytes_per_line   
ZPixmap width * height * ((depth + 7) / 8) width * ((depth + 7) / 8)  
XYPixmap ((width + 7) / 8) * height * depth (width + 7) / 8  
XYBitmap ((width + 7) / 8) * height * 1   (width + 7) / 8  



-------------------------------------------------------------------------------- 

        unsigned long XGetPixel(ximage, x, y) 
              XImage *ximage; 
              int x; 
              int y; 


-------------------------------------------------------------------------------- 
取得影像内的一个图点. 


-------------------------------------------------------------------------------- 

        XPutPixel(ximage, x, y, pixel) 
              XImage *ximage; 
              int x; 
              int y; 
              unsigned long pixel; 


-------------------------------------------------------------------------------- 
在影像上放上一个点. 


-------------------------------------------------------------------------------- 

        XImage *XSubImage(ximage, x, y, subimage_width, 
        subimage_height) 
              XImage *ximage; 
              int x; 
              int y; 
              unsigned int subimage_width; 
              unsigned int subimage_height;  


-------------------------------------------------------------------------------- 
读取影像的一部分内容, 并传回 XImage. x, y, subimage_width, 和 subimage_height 指定 image 内的一个方框的位置和大小, 读 取方框内的资料. 


-------------------------------------------------------------------------------- 

        XAddPixel(ximage, value) 
              XImage *ximage; 
              long value; 


-------------------------------------------------------------------------------- 
把 image 内每个点的 pixel 值都加上指定的 valuex. 


-------------------------------------------------------------------------------- 

        XDestroyImage(ximage) 
                XImage *ximage; 


-------------------------------------------------------------------------------- 
由上面和下面各函数所产生的 XImage 物件, 最後不用时, 都要使用 XDestroyImage 释放掉。注意, XDestroyImage 会主动将 data 释放  


-------------------------------------------------------------------------------- 

        XPutImage(display, d, gc, image, src_x, src_y, dest_x, 
        dest_y, width, height) 
                Display *display; 
                Drawable d; 
                GC gc; 
                XImage *image; 
                int src_x, src_y; 
                int dest_x, dest_y; 
                unsigned int width, height; 


-------------------------------------------------------------------------------- 
将 image 输出 'd' 所指定的 drawable. 


-------------------------------------------------------------------------------- 

        XImage *XGetImage(display, d, x, y, width, height, 
        plane_mask, format) 
                Display *display; 
                Drawable d; 
                int x, y; 
                unsigned int width, height; 
                unsigned long plane_mask; 
                int format; 


-------------------------------------------------------------------------------- 
读取 'd' 所指定之 drawable 的影像. 'plane_mask' 指定要读取的 planes. 若指定的 planes, 为 drawable 所有 planes 的 subset, 那麽传回的 image 的 depth 将和指定的 planes 数目相同. 


-------------------------------------------------------------------------------- 

        XImage *XGetSubImage(display, d, x, y, width, height, 
        plane_mask, format, dest_image, dest_x, 
                             dest_y) 
              Display *display; 
              Drawable d; 
              int x, y; 
              unsigned int width, height; 
              unsigned long plane_mask; 
              int format; 
              XImage *dest_image; 
              int dest_x, dest_y; 


-------------------------------------------------------------------------------- 


下面是处理影像的例.  
-------------------------------------------------------------------------------- 

/* -- Image-test.c -- */ 
#include 
#include 
#include 
#include 
#include 
#include 
#include "gnu.xpm" 
#include "doomface.xpm" 
#include "Boss2.xpm" 


struct ColorElm { 
char *tag; 
unsigned long pixel; 
}; 


unsigned long 
get_pixel(Display *display, Colormap colormap, char *str) 

char *cp = str; 
XColor color, excolor; 

if(*cp == '#') { 
int j, k; 
int t; 
int rgbl; 
unsigned short rgb[3]; 

cp++; 
if(strlen(cp) == 6) 
rgbl = 2; 
else 
rgbl = 4; 

for(k = 0; k < 3; k++) { 
t = 0; 
for(j = 0; j < rgbl; j++) { 
char c = *(cp++); 

t <<= 4; 
if(c >= 'A' && c <= 'F') 
t += c - 'A' + 10; 
else if(c >= 'a' && c <= 'f') 
t += c - 'a' + 10; 
else 
t += c - '0'; 

rgb[k] = t; 


color.red = rgb[0]; 
color.green = rgb[1]; 
color.blue = rgb[2]; 
color.flags = DoRed | DoGreen | DoBlue; 
XAllocColor(display, colormap, &color); 
} else { 
char *cp; 

if(strcasecmp(str, "None") == 0) 
cp = "black"; 
else 
cp = str; 
XAllocNamedColor(display, colormap, cp, &color, &excolor); 


return color.pixel; 



/* 
* 从 *.xpm 转换成 Xlib 能处理的 image 资料形式 (ZPixmap) 
*/ 
char * 
xpm_to_data(char **xpm, Display *display, 
Colormap colormap, int depth, int *width, int *height) 

int nc, el; /* # of color, and element length */ 
int i; 
int bpp; /* byte per pixel */ 
struct ColorElm *ce, *cep; 
unsigned short rgb[3]; 
XColor color; 
char *data, *dp; 

sscanf(*(xpm++), "%d %d %d %d", width, height, &nc, &el); 
bpp = (depth + 7) / 8; 

data = (char *)malloc(sizeof(char) * bpp * 
*width * *height); 
ce = (struct ColorElm *)malloc(sizeof(struct ColorElm) * nc); 

cep = ce; 
for(i = 0; i < nc; i++) { 
char *cp; 

cep->tag = (char *)malloc(sizeof(char) * el); 
memcpy(cep->tag, *xpm, el); 

cp = *xpm + el; 
/* 
* skip redundant character 
*/ 
while(isspace(*cp)) cp++; 
while(*(cp++) != 'c') { 
while(isspace(*cp)) cp++; 
while(!isspace(*cp)) cp++; 
while(isspace(*cp)) cp++; 

/* 
* get pixel of color 
*/ 
while(isspace(*cp)) cp++; 
cep->pixel = get_pixel(display, colormap, cp); 

cep++; 
xpm++; 


/* 
* generate image data 
*/ 
dp = data; 
for(i = 0; i < *height; i++) { 
int j; 
char *p; 

p = *(xpm++); 
for(j = 0; j < *width; j++) { 
int idx; 
unsigned long pixel; 

/* 
* find pixel of point 
*/ 
for(idx = 0; idx < nc; idx++) 
if(!memcmp(p, ce[idx].tag, el)) { 
memcpy(dp, &ce[idx].pixel, bpp); 
break; 

dp += bpp; 
p += el; 



free(ce); 
return data; 



main()  

Display *display; 
Window window; 
XSetWindowAttributes attr; 
Colormap colormap; 
XColor color1, color2; 
XGCValues gcvalue; 
GC gc; 
XSizeHints *sz; 
XImage *img1, *img2, *img3; 
int screen; 
char *data; /* image data */ 
int w, h; /* width & height */ 
int bpp; /* byte per pixel */ 

display = XOpenDisplay("0:0"); 

colormap = DefaultColormap(display, screen = DefaultScreen(display)); 
color1.red = color1.blue = 0xffff; 
color1.green = 0; 
color2.red = color2.green = color2.blue = 0xff; 
color1.flags = color2.flags = DoRed | DoGreen | DoBlue;  
XAllocColor(display, colormap, &color1); 
XAllocColor(display, colormap, &color2); 

attr.background_pixel = color2.pixel; 
window = XCreateWindow(display, XDefaultRootWindow(display), 
100, 100, 500, 300, 2, XDefaultDepth(display, 0), 
InputOutput, CopyFromParent, CWBackPixel, &attr); 

XStoreName(display, window, "hello!! world!!"); 
sz = XAllocSizeHints(); 
sz->x = 100; 
sz->y = 100; 
sz->width = 300; 
sz->height = 500; 
sz->flags = USPosition | USSize; 
XSetNormalHints(display, window, sz); 
XMapWindow(display, window); 

gc = XCreateGC(display, window, 0, &gcvalue); 
XSetForeground(display, gc, color1.pixel); 
XSetBackground(display, gc, color2.pixel); 
XFlush(display); 

printf("Show image!!\n"); 
bpp = (DefaultDepth(display, screen) + 7) / 8; 
/* 
* Create gnu.xpm 
*/ 
data = xpm_to_data(image_name, display, colormap, 
DefaultDepth(display, screen), &w, &h); 
img1 = XCreateImage(display, 
DefaultVisual(display, screen), 
DefaultDepth(display, screen), 
ZPixmap, 0, data, 
w, h, 8, w * bpp); 
/* (w, h) 是影像的宽和高 */ 

/* 
* Create doomface.xpm 
*/ 
data = xpm_to_data(xpm, display, colormap, 
DefaultDepth(display, screen), &w, &h); 
img2 = XCreateImage(display, 
DefaultVisual(display, screen), 
DefaultDepth(display, screen), 
ZPixmap, 0, data, 
w, h, 8, w * bpp); 
/* (w, h) 是影像的宽和高 */ 

/* 
* Create Boss2.xpm 
*/ 
data = xpm_to_data(Boss2_xpm, display, colormap, 
DefaultDepth(display, screen), &w, &h); 
img3 = XCreateImage(display, 
DefaultVisual(display, screen), 
DefaultDepth(display, screen), 
ZPixmap, 0, data, 
w, h, 8, w * bpp); 
/* (w, h) 是影像的宽和高 */ 

/* 
* Show images 
*/ 
XPutImage(display, window, gc, img1, 0, 0, 10, 10, w, h); 
XPutImage(display, window, gc, img2, 0, 0, 10, 100, w, h); 
XPutImage(display, window, gc, img3, 0, 0, 200, 50, w, h); 
XFlush(display); 

/* 
* Destroy images 
*/ 
XDestroyImage(img1); 
XDestroyImage(img2); 
XDestroyImage(img3); 
sleep(3); 

XDestroyWindow(display, window); 
XFlush(display); 

XCloseDisplay(display); 



-------------------------------------------------------------------------------- 
执行结果 

颜色和原图有些不同, 主要原因是使用 default 的 colormap. 上面的程式 在视窗显示三张 .xpm 的图形档, 分别是 gnu.xpm, doomface.xpm 和 Boss2.xpm.  

5. 例 

-------------------------------------------------------------------------------- 

/* ---- XGraph.c ---- */ 

#include 
#include 
#include 
#include 

main() { 
Display *display; 
Window window; 
XSetWindowAttributes attr; 
Colormap colormap; 
XColor color1, color2; 
XGCValues gcvalue; 
GC gc; 
XSizeHints *sz; 

display = XOpenDisplay("0:0"); 

/* 取得预设之 colormap */ 
colormap = DefaultColormap(display,  
DefaultScreen(display)); 
/* 取得 colorcell */ 
color1.red = color1.blue = 0xffff; 
color1.green = 0; 
color2.red = color2.green = color2.blue = 0xff; 
color1.flags = color2.flags = DoRed | DoGreen | DoBlue;  
XAllocColor(display, colormap, &color1); 
XAllocColor(display, colormap, &color2); 

/* 设定视窗的 attribute 和建设 */ 
attr.background_pixel = color2.pixel; /* 背景颜色 */ 
window = XCreateWindow(display, 
XDefaultRootWindow(display), 100, 100, 300, 300, 
2, XDefaultDepth(display, 0), InputOutput,  
CopyFromParent, CWBackPixel, &attr); 

/* 设定和 window manager 进行沟通 */ 
XStoreName(display, window, "hello!! world!!"); 
sz = XAllocSizeHints(); 
sz->x = 100; 
sz->y = 100; 
sz->width = 300; 
sz->height = 300; 
sz->flags = USPosition | USSize; 
XSetNormalHints(display, window, sz); 

/* 显示视窗 */ 
printf("Map window\n"); 
XMapWindow(display, window); 
XFlush(display); 
getchar(); 

/* 建立并设定 GC */ 
gc = XCreateGC(display, window, 0, &gcvalue); 
XSetForeground(display, gc, color1.pixel); 
XSetBackground(display, gc, color2.pixel); 

/* 画一个矩形 */ 
printf("Draw rectangle\n"); 
XDrawRectangle(display, window, gc, 10, 10, 100, 100); 
XFlush(display); 
getchar(); 

/* 清除视窗 */ 
XClearWindow(display, window); 

/* 设定 GC 内,线的形式 */ 
XSetLineAttributes(display, gc, 5, LineOnOffDash, 
CapButt, JoinRound); 
/* 画线 (200, 10) - (200, 290) */ 
printf("Draw line\n"); 
XDrawLine(display, window, gc, 200, 10, 200, 290); 
XFlush(display); 
getchar(); 

/* 关闭视窗 */ 
printf("Destory Window\n"); 
XDestroyWindow(display, window); 
XFlush(display); 
getchar(); 

printf("close display\n"); 
XCloseDisplay(display); 
getchar(); 



-------------------------------------------------------------------------------- 

gcc -o XGraph XGraph.c -L/usr/X11R6/lib -lX11 


-------------------------------------------------------------------------------- 
上面是一个简单的例程式和 compile 的方法。
 posted on 2009-04-26 10:31  清水湾  阅读(3525)  评论(0编辑  收藏  举报