linux__frameBuffer__操作2--写入和截屏
1,读写:
转自: http://blog.sina.com.cn/s/blog_4a0a39c30100ax1v.html
虽然现在能通过交叉环境编译程序,并push到Android上执行,但那只是console台程序,是不是有些单调呢?下面就要看如何通过Linux的 framebuffer 技术在Android上画图形,关于Linux的framebuffer技术,这里就不再详细讲解了,请大家google一下。
操作framebuffer的主要步骤如下:
1、打开一个可用的FrameBuffer设备;
2、通过mmap调用把显卡的物理内存空间映射到用户空间;
3、更改内存空间里的像素数据并显示;
4、退出时关闭framebuffer设备。
下面的这个例子简单地用framebuffer画了一个渐变的进度条,代码 framebuf.c 如下:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
inline static unsigned short int make16color(unsigned char r, unsigned char g, unsigned char b)
{
return (
(((r >> 3) & 31) << 11) |
(((g >> 2) & 63) << 5) |
((b >> 3) & 31) );
}
int main() {
int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
char *fbp = 0;
int x = 0, y = 0;
int guage_height = 20, step = 10;
long int location = 0;
// Open the file for reading and writing
fbfd = open("/dev/graphics/fb0", O_RDWR);
if (!fbfd) {
printf("Error: cannot open framebuffer device.\n");
exit(1);
}
printf("The framebuffer device was opened successfully.\n");
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
printf("Error reading fixed information.\n");
exit(2);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
exit(3);
}
printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short));
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
printf("xoffset:%d, yoffset:%d, line_length: %d\n", vinfo.xoffset, vinfo.yoffset, finfo.line_length );
// Figure out the size of the screen in bytes
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
fbfd, 0);
if ((int)fbp == -1) {
printf("Error: failed to map framebuffer device to memory.\n");
exit(4);
}
printf("The framebuffer device was mapped to memory successfully.\n");
//set to black color first
memset(fbp, 0, screensize);
//draw rectangle
y = (vinfo.yres - guage_height) / 2 - 2; // Where we are going to put the pixel
for (x = step - 2; x < vinfo.xres - step + 2; x++) {
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
(y+vinfo.yoffset) * finfo.line_length;
*((unsigned short int*)(fbp + location)) = 255;
}
y = (vinfo.yres + guage_height) / 2 + 2; // Where we are going to put the pixel
for (x = step - 2; x < vinfo.xres - step + 2; x++) {
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
(y+vinfo.yoffset) * finfo.line_length;
*((unsigned short int*)(fbp + location)) = 255;
}
x = step - 2;
for (y = (vinfo.yres - guage_height) / 2 - 2; y < (vinfo.yres + guage_height) / 2 + 2; y++) {
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
(y+vinfo.yoffset) * finfo.line_length;
*((unsigned short int*)(fbp + location)) = 255;
}
x = vinfo.xres - step + 2;
for (y = (vinfo.yres - guage_height) / 2 - 2; y < (vinfo.yres + guage_height) / 2 + 2; y++) {
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
(y+vinfo.yoffset) * finfo.line_length;
*((unsigned short int*)(fbp + location)) = 255;
}
// Figure out where in memory to put the pixel
for ( x = step; x < vinfo.xres - step; x++ ) {
for ( y = (vinfo.yres - guage_height) / 2; y < (vinfo.yres + guage_height) / 2; y++ ) {
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
(y+vinfo.yoffset) * finfo.line_length;
if ( vinfo.bits_per_pixel == 32 ) {
*(fbp + location) = 100; // Some blue
*(fbp + location + 1) = 15+(x-100)/2; // A little green
*(fbp + location + 2) = 200-(y-100)/5; // A lot of red
*(fbp + location + 3) = 0; // No transparency
} else { //assume 16bpp
unsigned char b = 255 * x / (vinfo.xres - step);
unsigned char g = 255; // (x - 100)/6 A little green
unsigned char r = 255; // A lot of red
unsigned short int t = make16color(r, g, b);
*((unsigned short int*)(fbp + location)) = t;
}
}
//printf("x = %d, temp = %d\n", x, temp);
//sleep to see it
usleep(200);
}
//clean framebuffer
munmap(fbp, screensize);
close(fbfd);
return 0;
}
注意,在Android环境,framebuffer设备不是象linux一样的 /dev/fb0,而是 /dev/graphics/fb0 ,
fbfd = open("/dev/graphics/fb0", O_RDWR);
打开framebuffer设备,
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
fbfd, 0);
将设备map到一块内存,然后就可以操作这块内存空间来显示你想画的图形了。
最后别忘了关闭设备:
munmap(fbp, screensize);
close(fbfd);
2,-------------------------------------截屏:
转自:http://www.eoeandroid.com/thread-57688-1-1.html
嵌入式Linux通过帧缓存截图 - Embedded Linux Framebuffer Screenshot
【目的】
板子上已经可以运行Qtopia的demo和example了,想要将其qt的demo程序的画面截取下来,给其他人看。
最原始的方法就是,找个相机,对着板子照几张即可。另外的办法,通过framebuffer去截图,截取运行中的qtdemo的画面,效果会更好,图片也更清晰。
【解决过程】
1.将framebuffer数据cat出来,用支持raw格式图片的工具处理它,得到我们要的图片
此想法很简单,就是:
cat /dev/fb0 > fb_data.raw
得到一个LCD屏幕输出的数据,不过后来去看了下代码,发现framebuffer驱动中,cat出来的,并不是正好一个屏幕的数据,而是程序里面固定的1M,那是因为该framebuffer程序支持多种LCD,所以为了通用性,一次申请了足够大的数据,以便不同的LCD都可以工作,所以,此处要去算出实际的一个屏幕的数据有多少。
此处我这里的framebuffer是32位的,驱动内部是将32位设置为RGB 888模式。所以实际有效数据是:
宽x高x一个像素数据的字节数=420 x 272 x 4=0x7F800,
其中2是因为RGB888,实际占用了8+8+8=24位,以字节对齐,共占用4个字节。
所以,1M的输出数据中,只有前面0x7F800是有效的。得到真正有效的数据后,就去找了,支持raw格式的软件来打开此图像,结果试用了很多软件,包括Photo shop CS,acd see,画图,美图看看,Stepok RAW转换器等,除了Photo Shop CS外,在打开的时候,可以让你自己设置宽,高,像素深度,但是也还是无法准确识别外,其他的都无法识别。所以只能放弃。
2.使用framebuffer截图工具,将LCD输出保存成一张图片:
(1)fbshot:将framebuffer数据,保存成一张png图片
最新版本源码:fbshot-0.3.tar.gz
http://www.sfires.net/stuff/fbshot/fbshot-0.3.tar.gz
下载源码后,用arm-linux-gcc编译:
gcc fbshot.c -lpng -lz -o fbshot
将生成的fbshot下载到板子上,先运行任意一个qt的demo,加上&使其在后台运行,这样就可以用fbshot去截图了,结果虽然fbshot可以正常运行和输出对应png图片,但是所有图片内容都是空白,而不是我所想要的qt运行的那些内容。折腾半天,还是同样结果,只有放弃。
(2)fbgrab:将framebuffer数据,保存成一张png图片
源码下载地址:fbgrab-1.0.tar.gz
http://hem.bredband.net/gmogmo/fbgrab/fbgrab-1.0.tar.gz
下载源码,解压后,改了makefile,用arm-linux-gcc编译,即:
arm-linux-gcc fbgrab.c -lpng -lz -o fbgrab
之后,将生成的fbgrab下载到板子里,用其折腾了半天,所得截图,图片内容都是空白的。始终无法得到我所要的qt的那些运行界面。索性放弃。
后来,仔细看了上面两个程序对应的说明文档:
fbshot的“This utility was written on x86 hardware (typical PC), therefore it has no support for other architectures and their framebuffers, especially not for Amiga nor Atari. On the other hand it should work on machines like Alpha's and maybe SUN's. I'm not sure.”
而fbgrab又是基于fbshot的-->>这时才知道,这两个工具,都是基于X86系统的framebuffer而写的,并不保证支持其他架构的,所以,此处不支持arm的,所以也就很正常了。。。
(3)gsnap:截图framebuffer保存成一张jpg图片
此工具,原先是李先静写的,支持对framebuffer截图,存成jpg图片:
http://www.limodev.cn/blog/archives/985
gsnap源码下载地址:
http://www.limodev.cn/download/gsnap.tar.gz
后来又有人在此基础上,加了对png的支持:
“程序非原创,是在李先静的工具基础上增加了保存为png格式的支持,在基于framebuffer的x86上和android模拟器上测试成功。”
http://www.fengfly.com/plus/view-163880-1.html
支持png的gsnap的源码下载地址:
http://blogimg.chinaunix.net/blog/upfile2/090828170135.bz2
下载源码后,编译:arm-linux-gcc gsnap.c -ljpg -lpng -o gsnap
(如果板子上像我这里一样,没有jpg或png的库,那么加上-static静态编译即可):
arm-linux-gcc gsnap.c -static -ljpg -lpng -o gsnap
下载编译后的gsnap到板子上,去截图,比前面的fbsnab和fbshot有进步,虽然截图只是截取了实际LCD输出图像的一部分,而且极其难看:
但是至少是截取了真正我要的图像。
后来继续折腾,最后发现,将framebuffer设置为16位,驱动内部处理位RGB 565的模式,此gsnap就可以正常的将framebuffer截图保存成jpg图片了,然后用sz上传到PC上,发现输出的图片效果,还是很逼真的。赞一个:
【总结】
1.fbshot与fbgrab(基于fbshot)都是普通PC下的Linux版本中的framebuffer或者说console的截图工具,即你PC版本的Linux中运行一个终端,然后用其来截图,不能用于我此处的,需要直接对LCD的输出中framebuffer截图。
2.gsnap不能很好地支持32位的framebuffer(驱动中对应着RGB 888模式),可以很好地支持常见的16位的framebuffer(驱动中我此处是RGB 565模式)。
【结论】
用gsnap,可以将嵌入式Linux中的LCD输出的图像,通过framebuffer,保存成jpg图片。
更多推荐
所有评论(0)