您的位置:首页 > 其它

X Window 程式设计入门--第三章 绘图(Graphic)(下)

2009-04-26 10:31 411 查看
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 的方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: