- 论坛徽章:
- 0
|
Linux图形系统开发基础
做了很长时间的图形开发,自己打算把相关的技术重头屡屡,一点一点的写,不着急,先发一篇入门的
1:搭建Linux下的图形系统开发环境
图形输出在嵌入式开发中,多数是向FrameBuffer中写数据,然后会显示在LCD中,在Linux下做图形开发的时候,需要模拟各种环境,比如16位色的环境,32位色的环境等,这个时候需要在Linux中做一个配置的修改:
[Copy to clipboard]
[ - ]
CODE:
[root@localhost root]# vi /boot/grub/grub.conf
上面这条命令是用来编辑grub引导配置文件。该配置文件原来的内容为:
[Copy to clipboard]
[ - ]
CODE:
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE: You have a /boot partition. This means that
# all kernel and initrd paths are relative to /boot/, eg.
# root (hd0,0)
# kernel /vmlinuz-version ro root=/dev/sda2
# initrd /initrd-version.img
#boot=/dev/sda
default=0
timeout=10
splashimage=(hd0,0)/grub/splash.xpm.gz
title Red Hat Linux (2.6.26)
root (hd0,0)
kernel /vmlinuz-2.6.26
initrd /initrd-2.6.26.img
将其修改为:
[Copy to clipboard]
[ - ]
CODE:
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE: You have a /boot partition. This means that
# all kernel and initrd paths are relative to /boot/, eg.
# root (hd0,0)
# kernel /vmlinuz-version ro root=/dev/sda2
# initrd /initrd-version.img
#boot=/dev/sda
default=0
timeout=10
splashimage=(hd0,0)/grub/splash.xpm.gz
title Red Hat Linux (2.6.26)
root (hd0,0)
kernel /vmlinuz-2.6.26 vga=0x314
initrd /initrd-2.6.26.img
其实仅仅是在kernel /vmlinuz-2.6.26这一行末尾处加了一个vga=0x314,将Framebuffer设置为800x600x16的显示模式,其中 800x600是屏幕分辨率,16表示显示的是16bit的彩色。下面详细的说一下关于vesa vga参数的含义:
[Copy to clipboard]
[ - ]
CODE:
4bit 8bit 15bit 16bit 24bit 32bit
640x400 x 0x300 x x x x
640x480 x 0x301 0x310 0x311 0x312 x
800x600 0x302 0x303 0x313 0x314 0x315 x
1024x768 x 0x305 0x316 0x317 0x318 x
1280x1024 x 0x307 0x319 0x31A 0x31B x
1600x1200 x 0x31C 0x31D 0x31E 0x31F x
而在现在的开发环境中,和嵌入式平台中,用16bit的颜色的还是主流,所以,主要介绍一下16bit的颜色的类型,而颜色是由RGB组成:
常见16位颜色的类型分为:
(1)565:依次排列为Red,Green,Blue,二进制表示为:
[Copy to clipboard]
[ - ]
CODE:
Red Green Blue
RRRRR GGGGGG BBBBB
(2)1555:依次排列为Alpha,Red,Green,Blue
[Copy to clipboard]
[ - ]
CODE:
Alpha Red Green Blue
A RRRRR GGGGG BBBBB
565排列的颜色:
0xFFFF的颜色是白色,在RGB565中排列形式为:
[Copy to clipboard]
[ - ]
CODE:
R G B
11111 111111 111111
0xF800的颜色是红色,在RGB565中排列的形式为:
[Copy to clipboard]
[ - ]
CODE:
R G B
11111 000000 000000
0X7e0的颜色是绿色,在RGB565中排列的形式为:
[Copy to clipboard]
[ - ]
CODE:
R G B
00000 111111 000000
假设Alpha值为1的1555排列的颜色:
0XFC00的颜色是红色,在ARGB1555中排列形式为:
[Copy to clipboard]
[ - ]
CODE:
A R G B
1 11111 00000 00000
0X83E0的颜色是绿色,在ARGB1555中排列形式为:
[Copy to clipboard]
[ - ]
CODE:
A R G B
1 00000 11111 00000
其他颜色就不在这里一一赘述,需要在实践中慢慢累积与总结。
RGB简介
前面介绍了做了很多表来体现的就是RGB颜色排列形式,那么什么是RGB呢?
概述
RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。
RGB色彩模式使用RGB模型为图像中每一个像素的RGB分量分配一个0~255范围内的强度值。例如:纯红色R值为255,G值为0,B值为0;灰色的R、G、B三个值相等(除了0和255);白色的R、G、B都为255;黑色的R、G、B都为0。RGB图像只使用三种颜色,就可以使它们按照不同的比例混合,在屏幕上重现16777216种颜色。
在 RGB 模式下,每种 RGB 成分都可使用从 0(黑色)到 255(白色)的值。 例如,亮红色使用 R 值 246、G 值 20 和 B 值 50。 当所有三种成分值相等时,产生灰色阴影。 当所有成分的值均为 255 时,结果是纯白色;当该值为 0 时,结果是纯黑色。
应用
目前的显示器大都是采用了RGB颜色标准,在显示器上,是通过电子枪打在屏幕的红、绿、蓝三色发光极上来产生色彩的,目前的电脑一般都能显示32位颜色,约有一百万种以上的颜色。
原理
RGB是从颜色发光的原理来设计定的,通俗点说它的颜色混合方式就好像有红、绿、蓝三盏灯,当它们的光相互叠合的时候,色彩相混,而亮度却等于两者亮度之总和(两盏灯的亮度嘛!),越混合亮度越高,即加法混合。
有色光可被无色光冲淡并变亮。如蓝色光与白光相遇,结果是产生更加明亮的浅蓝色光。知道它的混合原理后,在软件中设定颜色就容易理解了。
红、绿、蓝三盏灯的叠加情况,中心三色最亮的叠加区为白色,加法混合的特点:越叠加越明亮。
红、绿、蓝三个颜色通道每种色各分为255阶亮度,在0时“灯”最弱——是关掉的,而在255时“灯”最亮。当三色数值相同时为无色彩的灰度色,而三色都为255时为最亮的白色,都为0时为黑色。
RGB 颜色称为加成色,因为您通过将 R、G 和 B 添加在一起(即所有光线反射回眼睛)可产生白色。 加成色用于照明光、电视和计算机显示器。例如,显示器通过红色、绿色和蓝色荧光粉发射光线产生颜色。绝大多数可视光谱都可表示为红、绿、蓝 (RGB) 三色光在不同比例和强度上的混合。这些颜色若发生重叠,则产生青、洋红和黄。
在嵌入式设备图形系统开发中,常用到的设备就是Framebuffer,所以,本书介绍的图形系统开发,主要是针对Framebuffer的操作进行。
首先打开framebuffer设备,framebuffer设备可以根据环境变量FRAMEBUFFER来获得,也可以手动输入下面是一个打开设备的里子:
[Copy to clipboard]
[ - ]
CODE:
1 /**************************************************
2 * example1.c
3 * Author: T-bagwell
4 *
5 * Compile:gcc -Wall example1.c -o example1
6 *************************************************/
7 #include
8 #include
9 #include
10 #include
11 #include
12
13 int main(int argc, char *argv[])
14 {
15 int screen_fbd=0;
16 char *env=NULL;
17
18 if(!(env = getenv("FRAMEBUFFER")))
19 {
20 env = "/dev/fb0";
21 }
22
23 screen_fbd = open(env, O_RDWR);
24
25 if(screen_fbd
打开设备成功以后会输出:
[Copy to clipboard]
[ - ]
CODE:
Success Opening FrameBuffer Device:/dev/fb0
framebuffer设备打开成功,接着需要获得framebuffer的相关参数,framebuffer对应的参数不多,如下:
[Copy to clipboard]
[ - ]
CODE:
struct fb_fix_screeninfo {
char id[16]; /* 用来辨认的字符串,例如 "TT Builtin" */
unsigned long smem_start; /* framebuffer的内存起始地址*/
/* (物理地址) */
__u32 smem_len; /* framebuffer内存的长度 */
__u32 type; /* 类型描述*/
__u32 type_aux; /*插入区域 */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /*没有硬件设备,这里就是0*/
__u16 ypanstep;
__u16 ywrapstep;
__u32 line_length; /*字节在一行的表示*/
unsigned long mmio_start; /* 内存io映射的开始*/
/* (物理地址) */
__u32 mmio_len; /* 内存io映射的长度*/
__u32 accel; /*可用的加速类型 */
/* specific chip/card we have */
__u16 reserved[3]; /* Reserved for future compatibility */
};
struct fb_var_screeninfo {
__u32 xres; /*可视区域*/
__u32 yres;
__u32 xres_virtual; /*虚拟区域*/
__u32 yres_virtual;
__u32 xoffset; /* 从虚拟到可视区域的偏移 */
__u32 yoffset;
__u32 bits_per_pixel; /*每一像素的bit数*/
__u32 grayscale; /* 如果这里设置为0就是黑白色的 */
struct fb_bitfield red; /*如果是真彩涩就在这里添红色*/
struct fb_bitfield green; /* 否则只有长度是有意义的 */
struct fb_bitfield blue;
struct fb_bitfield transp; /* 通明色处理*/
__u32 nonstd; /* != 0这里就是非标准格式 */
__u32 activate; /* see FB_ACTIVATE_**/
__u32 height; /* 图象高度*/
__u32 width; /*图象宽度*/
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /*水平可视区域*/
__u32 vsync_len; /*垂直可视区域*/
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 reserved[5]; /* Reserved for future compatibility */
};
struct fb_cmap {
__u32 start; /*入口地址*/
__u32 len;
__u16 *red; /* 红色值*/
__u16 *green;
__u16 *blue;
__u16 *transp; /*透明色, 可以为NULL */
};
通过Linux系统中的ioctl来获得framebuffer的参数,代码如下:
[Copy to clipboard]
[ - ]
CODE:
1 /**************************************************
2 * example1.c
3 * Author: T-bagwell
4 *
5 * Compile:gcc -Wall example2.c -o example2
6 *************************************************/
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 int main(int argc, char *argv[])
14 {
15 int screen_fbd=0;
16 struct fb_fix_screeninfo fb_fix;
17 struct fb_var_screeninfo fb_var;
18 char *env=NULL;
19
20 if(!(env = getenv("FRAMEBUFFER")))
21 {
22 env = "/dev/fb0";
23 }
24
25 screen_fbd = open(env, O_RDWR);
26
27 if(screen_fbd
代码看上去并不是很多,其目的主要是通过ioctl获得framebuffer参数,然后输出,输出结果为:
[Copy to clipboard]
[ - ]
CODE:
Success Opening FrameBuffer Device:/dev/fb0
fb_fix.id="VESA VGA"
fb_fix.smem_start=0xf0000000
fb_fix.mem_len=1920000
fb_fix.type=0
fb_fix.type_aux=0
fb_fix.visual=2
fb_fix.xpanstep=0
fb_fix.ypanstep=0
fb_fix.ywrapstep=0
fb_fix.line_length=1600
fb_fix.mmio_start=0
fb_fix.mmio_len=0
fb_fix.accel=0
fb_fix.reserved[0]=0
fb_fix.reserved[1]=0
fb_fix.reserved[2]=0
fb_var.xres=800
fb_var.yres=600
fb_var.xres_virtual=800
fb_var.yres_virtual=600
fb_var.xoffset=0
fb_var.yoffset=0
fb_var.bits_per_pixel=16
fb_var.grayscale=0
fb_var.red=0xb
fb_var.green=0x5
fb_var.blue=0
fb_var.transp=0
fb_var.nonstd=0
fb_var.activate=0
fb_var.height=-1
fb_var.width=-1
fb_var.accel_flags=0
fb_var.pixclock=20833
fb_var.left_margin=96
fb_var.right_margin=32
fb_var.upper_margin=16
fb_var.lower_margin=4
fb_var.hsync_len=96
fb_var.vsync_len=4
fb_var.sync=0
fb_var.vmode=0
fb_var.rotate=0
fb_var.reserved[0]=0
fb_var.reserved[1]=0
fb_var.reserved[2]=0
fb_var.reserved[3]=0
fb_var.reserved[4]=0
虽然输出了很多的参数,读者可能会觉得这些参数看上去很眼花缭乱,不要紧,挑出一些关键的参数来使用即可,从输出信息中可以看到 fb_var.xres=800,fb_var.yres=600,说明这个framebuffer的x最大值可以为800,y最大值可以为600。
当得到所有需要得到的值以后,可以开辟一段内存:
[Copy to clipboard]
[ - ]
CODE:
/**************************************************
* example3.c
* Author: T-bagwell
*
* Compile:gcc -Wall example3.c -o example3
*************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
char *fb_addr;
unsigned fb_size;
int main(int argc, char *argv[])
{
int screen_fbd=0;
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
char *env=NULL;
if(!(env = getenv("FRAMEBUFFER")))
{
env = "/dev/fb0";
}
screen_fbd = open(env, O_RDWR);
if(screen_fbd
首先得到整个framebuffer的大小 fb_size = fb_var.yres * fb_fix.line_length;然后映射framebuffer的内存,这样,当向指定的内存处写入数据的时候,framebuffer中就会写入对应的数据,也就会有对应的数据表示的图象显示在屏幕中。
以向屏幕中显示一个纯白色的页面为例,当RGB值为255、255、255时,颜色将为白色,代码如下:
[Copy to clipboard]
[ - ]
CODE:
/**************************************************
* example4.c
* Author: T-bagwell
*
* Compile:gcc -Wall example4.c -o example4
*************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int print_screen(char *buf,int width,int height);
char *fb_addr;
unsigned fb_size;
int main(int argc, char *argv[])
{
int screen_fbd=0;
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
char *env=NULL;
short *color_white;
if(!(env = getenv("FRAMEBUFFER")))
{
env = "/dev/fb0";
}
screen_fbd = open(env, O_RDWR);
if(screen_fbd = 0)
{
memcpy(t_fb_addr,t_data,bytew);
t_fb_addr += width;
t_data += width;
}
}
这部分代码实现的是在屏幕中画出一个白色的界面,其中,最关键的部分是在print_screen函数中,从main到print_screen中需要将一个buffer,宽度和高度传给print_screen,当print_screen得到相关的参数后,将会在framebuffer中画对应的颜色,也就是memcpy(t_fb_addr,t_data,bytew);这句话是画一行的颜色,当然,这个前提是从main中传进来的buffer也是 16位色的值。当画完一行以后,将buffer指针下移一行,直到画完framebuffer最后一行为止。画出的图象会显示在屏幕中,如图:
![]()
![]()
接下来可以增加一些功能,例如画线功能:
[Copy to clipboard]
[ - ]
CODE:
1 /**************************************************
2 * example5.c
3 * Author: T-bagwell
4 *
5 * Compile:gcc -Wall example5.c -o example5
6 *************************************************/
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18
19 int print_screen(short *buf,int width,int height);
20 void draw_hline(short *buffer,int x,int y,int maxy,int maxx);
21 char *fb_addr;
22 unsigned fb_size;
23
24 int main(int argc, char *argv[])
25 {
26 int screen_fbd=0;
27 struct fb_fix_screeninfo fb_fix;
28 struct fb_var_screeninfo fb_var;
29 char *env=NULL;
30 short *color_white;
31
32 if(!(env = getenv("FRAMEBUFFER")))
33 {
34 env = "/dev/fb0";
35 }
36
37 screen_fbd = open(env, O_RDWR);
38
39 if(screen_fbd = 0)
80 {
81 memcpy(t_fb_addr,t_data,bytew);
82 t_fb_addr += width;
83 t_data += width;
84 }
85 return 0;
86 }
87
88 /*********************************************************
89 * function: draw_hline
90 *args
91 * line_buffer: the address of the buffer
92 * x: the x of the line start point on the framebuffer
93 * y: the y of the line start point on the framebuffer
94 * maxy: the height of the framebuffer
95 * maxx: the width of the framebuffer
96 ********************************************************/
97 void draw_hline(short *line_buffer,int x,int y,int maxy,int maxx)
98 {
99 int i=0,j=0;
100
101 for(j=0;j
上述代码实现了在屏幕中坐标为x坐标为0,y坐标为30处画一条红色的横线,当然,颜色值可以作为参数进行传递,只要对上面的函数进行少量的修改即可。手累了,先写这么点吧。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/103474/showart_2032317.html |
|