工程源码:http://download.csdn.net/detail/victoryckl/4074654


一个增强版本源码:通过对fb0的操作,实现截屏,和送图片到fb0,支持rgb565 rgb888 xrgb8888格式的bmp和fb0


android上用C语言读取fb0实现截屏,保存为bmp图片,

支持16位(rgb565)、24位(rbg888)两种格式数据,并在android2.2和4.0模拟器上验证通过。

截屏实现主要有两个方面的工作,读取屏幕数据和生成图片。

1.读取屏幕数据

只读方式打开显存设备/dev/graphics/fb0,再通过mmap用共享方式(MAP_SHARED)映射到一片内存中,其他地方就可以直接以内存的方式读取屏幕数据了。

要注意的是,fb0的虚拟显示设备尺寸,大于实际屏幕显示设备的尺寸,mmap映射时需将安装虚拟尺寸进行映射,否则,截屏可能失败。

针对显存设备的主要代码:

/********************************************************************created:2012/02/07filename: myfb.cauthor:purpose:*********************************************************************/#ifndef WIN32//-------------------------------------------------------------------#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <sys/mman.h>#include <sys/stat.h>#include <sys/types.h>#include <linux/fb.h>#include <linux/kd.h>struct FB {    unsigned short *bits;    unsigned size;    int fd;    struct fb_fix_screeninfo fi;    struct fb_var_screeninfo vi;};int fb_bpp(struct FB *fb){if (fb) {return fb->vi.bits_per_pixel;}return 0;}int fb_width(struct FB *fb){if (fb) {return fb->vi.xres;}return 0;}int fb_height(struct FB *fb){if (fb) {return fb->vi.yres;}return 0;}int fb_size(struct FB *fb){if (fb) {unsigned bytespp = fb->vi.bits_per_pixel / 8;return (fb->vi.xres * fb->vi.yres * bytespp);}return 0;}int fb_virtual_size(struct FB *fb){if (fb) {unsigned bytespp = fb->vi.bits_per_pixel / 8;return (fb->vi.xres_virtual * fb->vi.yres_virtual * bytespp);}return 0;}void * fb_bits(struct FB *fb){unsigned short * bits = NULL;if (fb) {int offset, bytespp;bytespp = fb->vi.bits_per_pixel / 8;/* HACK: for several of our 3d cores a specific alignment* is required so the start of the fb may not be an integer number of lines* from the base.  As a result we are storing the additional offset in* xoffset. This is not the correct usage for xoffset, it should be added* to each line, not just once at the beginning */offset = fb->vi.xoffset * bytespp;offset += fb->vi.xres * fb->vi.yoffset * bytespp;bits = fb->bits + offset / sizeof(*fb->bits);}return bits;}void fb_update(struct FB *fb){if (fb) {fb->vi.yoffset = 1;ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);fb->vi.yoffset = 0;ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);}}static int fb_open(struct FB *fb){if (NULL == fb) {return -1;}    fb->fd = open("/dev/graphics/fb0", O_RDONLY);    if (fb->fd < 0) {printf("open(\"/dev/graphics/fb0\") failed!\n");        return -1;}    if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) {printf("FBIOGET_FSCREENINFO failed!\n");        goto fail;}    if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) {printf("FBIOGET_VSCREENINFO failed!\n");        goto fail;}    fb->bits = mmap(0, fb_virtual_size(fb), PROT_READ, MAP_SHARED, fb->fd, 0);    if (fb->bits == MAP_FAILED) {printf("mmap() failed!\n");        goto fail;}    return 0;fail:    close(fb->fd);    return -1;}static void fb_close(struct FB *fb){if (fb) {munmap(fb->bits, fb_virtual_size(fb));close(fb->fd);}}static struct FB g_fb;struct FB * fb_create(void){memset(&g_fb, 0, sizeof(struct FB));if (fb_open(&g_fb)) {return NULL;}return &g_fb;}void fb_destory(struct FB *fb){fb_close(fb);}//-------------------------------------------------------------------#endif//#ifndef WIN32


2.生成图片

这里生成的图片是bmp格式的,可以根据设备像素的位数自动生成16位(rgb565)、24位(rbg888)两种图片。

主要工作是要正确填充bmp的文件头信息,24位(rbg888)较简单。

16位(rgb565)复杂一点,biCompression成员的值必须是BI_BITFIELDS,原来调色板的前三个位置被三个DWORD变量占据,称为红、绿、蓝掩码,在565格式下,它们则分别为:0xF800、0x07E0、0x001F。

另外,需要主要的是windows要求文件大小必须是4的倍数,文件大小需要做下面的处理才能正确显示。

head->bfSize = head->bfOffBits + size;head->bfSize = (head->bfSize + 3) & ~3;size = head->bfSize - head->bfOffBits;

生成图片的主要代码:

/********************************************************************created:2012/02/07filename: savebmp.cauthor:purpose:*********************************************************************/#include <stdlib.h>#include <stdio.h>#include <memory.h>//-------------------------------------------------------------------/*  位图文件的组成  结构名称 符 号  位图文件头 (bitmap-file header) BITMAPFILEHEADER bmfh  位图信息头 (bitmap-information header) BITMAPINFOHEADER bmih  彩色表 (color table) RGBQUAD aColors[]  图象数据阵列字节 BYTE aBitmapBits[]*/typedef struct bmp_header {short twobyte;//两个字节,用来保证下面成员紧凑排列,这两个字符不能写到文件中//14Bchar bfType[2];//!文件的类型,该值必需是0x4D42,也就是字符'BM'unsigned int bfSize;//!说明文件的大小,用字节为单位unsigned int bfReserved1;//保留,必须设置为0unsigned int bfOffBits;//!说明从文件头开始到实际的图象数据之间的字节的偏移量,这里为14B+sizeof(BMPINFO)}BMPHEADER;typedef struct bmp_info{//40Bunsigned int biSize;//!BMPINFO结构所需要的字数int biWidth;//!图象的宽度,以象素为单位int biHeight;//!图象的宽度,以象素为单位,如果该值是正数,说明图像是倒向的,如果该值是负数,则是正向的unsigned short biPlanes;//!目标设备说明位面数,其值将总是被设为1unsigned short biBitCount;//!比特数/象素,其值为1、4、8、16、24、或32unsigned int biCompression;//说明图象数据压缩的类型#define BI_RGB        0L//没有压缩#define BI_RLE8       1L//每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);#define BI_RLE4       2L//每个象素4比特的RLE压缩编码,压缩格式由2字节组成#define BI_BITFIELDS  3L//每个象素的比特由指定的掩码决定。unsigned int biSizeImage;//图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0int biXPelsPerMeter;//水平分辨率,用象素/米表示int biYPelsPerMeter;//垂直分辨率,用象素/米表示unsigned int biClrUsed;//位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)unsigned int biClrImportant;//对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。}BMPINFO;typedef struct tagRGBQUAD {unsigned char rgbBlue;unsigned char rgbGreen;unsigned char rgbRed;unsigned char rgbReserved;} RGBQUAD;typedef struct tagBITMAPINFO {    BMPINFO    bmiHeader;    //RGBQUAD    bmiColors[1];unsigned int rgb[3];} BITMAPINFO;static int get_rgb888_header(int w, int h, BMPHEADER * head, BMPINFO * info){int size = 0;if (head && info) {size = w * h * 3;memset(head, 0, sizeof(* head));memset(info, 0, sizeof(* info));head->bfType[0] = 'B';head->bfType[1] = 'M';head->bfOffBits = 14 + sizeof(* info);head->bfSize = head->bfOffBits + size;head->bfSize = (head->bfSize + 3) & ~3;//windows要求文件大小必须是4的倍数size = head->bfSize - head->bfOffBits;info->biSize = sizeof(BMPINFO);info->biWidth = w;info->biHeight = -h;info->biPlanes = 1;info->biBitCount = 24;info->biCompression = BI_RGB;info->biSizeImage = size;printf("rgb888:%dbit,%d*%d,%d\n", info->biBitCount, w, h, head->bfSize);}return size;}static int get_rgb565_header(int w, int h, BMPHEADER * head, BITMAPINFO * info){int size = 0;if (head && info) {size = w * h * 2;memset(head, 0, sizeof(* head));memset(info, 0, sizeof(* info));head->bfType[0] = 'B';head->bfType[1] = 'M';head->bfOffBits = 14 + sizeof(* info);head->bfSize = head->bfOffBits + size;head->bfSize = (head->bfSize + 3) & ~3;size = head->bfSize - head->bfOffBits;info->bmiHeader.biSize = sizeof(info->bmiHeader);info->bmiHeader.biWidth = w;info->bmiHeader.biHeight = -h;info->bmiHeader.biPlanes = 1;info->bmiHeader.biBitCount = 16;info->bmiHeader.biCompression = BI_BITFIELDS;info->bmiHeader.biSizeImage = size;info->rgb[0] = 0xF800;info->rgb[1] = 0x07E0;info->rgb[2] = 0x001F;printf("rgb565:%dbit,%d*%d,%d\n", info->bmiHeader.biBitCount, w, h, head->bfSize);}return size;}static int save_bmp_rgb565(FILE * hfile, int w, int h, void * pdata){int success = 0;int size = 0;BMPHEADER head;BITMAPINFO info;size = get_rgb565_header(w, h, &head, &info);if (size > 0) {fwrite(head.bfType, 1, 14, hfile);fwrite(&info, 1, sizeof(info), hfile);fwrite(pdata, 1, size, hfile);success = 1;}return success;}static int save_bmp_rgb888(FILE * hfile, int w, int h, void * pdata){int success = 0;int size = 0;BMPHEADER head;BMPINFO info;size = get_rgb888_header(w, h, &head, &info);if (size > 0) {fwrite(head.bfType, 1, 14, hfile);fwrite(&info, 1, sizeof(info), hfile);fwrite(pdata, 1, size, hfile);success = 1;}return success;}int save_bmp(const char * path, int w, int h, void * pdata, int bpp){int success = 0;FILE * hfile = NULL;do {if (path == NULL || w <= 0 || h <= 0 || pdata == NULL) {printf("if (path == NULL || w <= 0 || h <= 0 || pdata == NULL)\n");break;}remove(path);hfile = fopen(path, "wb");if (hfile == NULL) {printf("open(%s) failed!\n", path);break;}switch (bpp){case 16:success = save_bmp_rgb565(hfile, w, h, pdata);break;case 24:success = save_bmp_rgb888(hfile, w, h, pdata);break;default:printf("error: not support format!\n");success = 0;break;}} while (0);if (hfile != NULL)fclose(hfile);return success;}//-------------------------------------------------------------------


3.运行方式:

cygwin下用ndk编译成可执行文件,再将生成的可执行文件push到模拟器的/data/local路径,

修改文件为可执行的,直接运行便可以截屏,图片保存到/mnt/sdcard/s.bmp。

[email protected] /cygdrive/e$ cd myprj/screenshot/jni/[email protected] /cygdrive/e/myprj/screenshot/jni$ ndk-buildCompile thumb  : savebmp <= savebmp.cCompile thumb  : savebmp <= screenshot.cStaticLibrary  : libsavebmp.aExecutable     : saveInstall        : save => libs/armeabi/save[email protected] /cygdrive/e/myprj/screenshot/jni$ adb shellerror: device offline[email protected] /cygdrive/e/myprj/screenshot/jni$ adb shell#[email protected] /cygdrive/e/myprj/screenshot/jni$ adb push ../libs/armeabi/save /data/local83 KB/s (10636 bytes in 0.125s)[email protected] /cygdrive/e/myprj/screenshot/jni$ adb shell# cd /data/localcd /data/local# chmod 777 savechmod 777 save# ./save./savergb565:16bit,800*480,768068# ls -l /mnt/sdcardls -l /mnt/sdcardd---rwxr-x system  sdcard_rw     2012-02-19 12:39 LOST.DIRd---rwxr-x system  sdcard_rw     2012-02-20 13:22 DCIM----rwxr-x system  sdcard_rw  768068 2012-02-20 13:22 s.bmp#


PS:工程源码中的VC工程主要用来调试生成图片的功能。


=====================================================================================================

目前,在增强版本中添加了32位的支持,但是没有32位的设备进行测试,已经有几位网友测试过,32位截图会出现颜色偏差和位置偏移,目前我这里还没有办法调试,所以32位截图的问题我还没有解决。

有位网友在小米手机上测试过也是有色差和错位问题,但后来直接在java中用Runtime.exec("/system/bin/screencap -p path")来截屏,还是png格式的。不是每个设备上都有screencap。

关于fb0中像素的格式可以参考

android4.0p-ics-src/system/core/adb# vi framebuffer_service.c,里面列举了五种格式,不过有些设备上可能不是下面的任何一种。

        case 1: /* RGBA_8888 */            fbinfo.bpp = 32;            fbinfo.size = w * h * 4;            fbinfo.width = w;            fbinfo.height = h;            fbinfo.red_offset = 0;            fbinfo.red_length = 8;            fbinfo.green_offset = 8;            fbinfo.green_length = 8;            fbinfo.blue_offset = 16;            fbinfo.blue_length = 8;            fbinfo.alpha_offset = 24;            fbinfo.alpha_length = 8;            break;        case 2: /* RGBX_8888 */            fbinfo.bpp = 32;            fbinfo.size = w * h * 4;            fbinfo.width = w;            fbinfo.height = h;            fbinfo.red_offset = 0;            fbinfo.red_length = 8;            fbinfo.green_offset = 8;            fbinfo.green_length = 8;            fbinfo.blue_offset = 16;            fbinfo.blue_length = 8;            fbinfo.alpha_offset = 24;            fbinfo.alpha_length = 0;            break;        case 3: /* RGB_888 */            fbinfo.bpp = 24;            fbinfo.size = w * h * 3;            fbinfo.width = w;            fbinfo.height = h;            fbinfo.red_offset = 0;            fbinfo.red_length = 8;            fbinfo.green_offset = 8;            fbinfo.green_length = 8;            fbinfo.blue_offset = 16;            fbinfo.blue_length = 8;            fbinfo.alpha_offset = 24;            fbinfo.alpha_length = 0;            break;        case 4: /* RGB_565 */            fbinfo.bpp = 16;            fbinfo.size = w * h * 2;            fbinfo.width = w;            fbinfo.height = h;            fbinfo.red_offset = 11;            fbinfo.red_length = 5;            fbinfo.green_offset = 5;            fbinfo.green_length = 6;            fbinfo.blue_offset = 0;            fbinfo.blue_length = 5;            fbinfo.alpha_offset = 0;            fbinfo.alpha_length = 0;            break;        case 5: /* BGRA_8888 */            fbinfo.bpp = 32;            fbinfo.size = w * h * 4;            fbinfo.width = w;            fbinfo.height = h;            fbinfo.red_offset = 16;            fbinfo.red_length = 8;            fbinfo.green_offset = 8;            fbinfo.green_length = 8;            fbinfo.blue_offset = 0;            fbinfo.blue_length = 8;            fbinfo.alpha_offset = 24;            fbinfo.alpha_length = 8;           break;

另外,关于截屏在android4.0的源码用有两个程序可以参考,这两个程序都可以截屏,一个是c++实现的,另一个是c的。

ics-src\frameworks\base\cmds\screencap\screencap.cpp

ics-src\frameworks\base\cmds\screenshot\screenshot.c

更多相关文章

  1. 一起学android之DigitalClock与TextClock的创建(8)
  2. android 判断手机号是否格式正确
  3. Android中自定义属性与格式标签详解
  4. Android(安卓)KitCat 4.4.2 ADB 官方所支持的所有Services格式翻
  5. Anroid 视频开发浅析
  6. Android学习笔记(十一):Activity-ListView
  7. Android(安卓)Repo的manifest XML文件格式
  8. Android(安卓)Dex文件格式(一)
  9. Android显示gif格式图片

随机推荐

  1. 用一句SQL解决SQL中断号问题 推荐
  2. SQL Server触发器及触发器中的事务学习
  3. MSSQL存储过程学习笔记一 关于存储过程
  4. 关于 SQL Server ErrorLog 错误日志说明
  5. sqlserver 高性能分页实现分析
  6. SQL里类似SPLIT的分割字符串函数
  7. sqlserver存储过程中SELECT 与 SET 对变
  8. sqlserver Case函数应用介绍
  9. SQL 中sp_executesql存储过程的使用帮助
  10. SQL 复合查询条件(AND,OR,NOT)对NULL值的