Android模拟器中窗口截图存成文件实现思路及代码
程序员文章站
2023-12-01 08:17:16
android模拟器内容是用opengl渲染的,所以用一般的编程截图(如printwindow()等)会是黑屏。这是因为画的东西放在framebuffer里。 一种方法是通...
android模拟器内容是用opengl渲染的,所以用一般的编程截图(如printwindow()等)会是黑屏。这是因为画的东西放在framebuffer里。
一种方法是通过adb把guest的framebuffer数据/dev/graphics/fb0倒到host,再转为图片。但这样速度比较慢。
好在android模拟器中把guest的framebuffer传到host进行显示,所以在host端只要将framebuffer输出到文件即可。
首先定义每次framebuffer更新时的回调函数:
复制代码 代码如下:
void zjin_fb_update(void* context,
int w, int h, int ydir,
int format, int type,
unsigned char* pixels)
{
#define channel 4
bitmapfileheader bf;
bitmapinfoheader bi;
int width = w;
int height = h;
file *file = fopen("capture.bmp", "wb");
if( file!=null )
{
memset( &bf, 0, sizeof( bf ) );
memset( &bi, 0, sizeof( bi ) );
bf.bftype = 'mb';//bm?
bf.bfsize = sizeof(bf)+sizeof(bi)+width*height*channel;
bf.bfoffbits = sizeof(bf)+sizeof(bi);
bi.bisize = sizeof(bi);
bi.biwidth = width;
bi.biheight = height;
bi.biplanes = 1;
bi.bibitcount = 8 * channel;
bi.bisizeimage = width*height*channel;
fwrite( &bf, sizeof(bf), 1, file );
fwrite( &bi, sizeof(bi), 1, file );
fwrite( pixels, sizeof(unsigned char), height*width*channel, file );
fclose( file );
}
return;
}
然后把这个回调函数注册上去,比如在opengl窗口显示之后:
复制代码 代码如下:
android_showopengleswindow(winhandle, drect.pos.x, drect.pos.y,
drect.size.w, drect.size.h, disp->rotation * -90.);
android_setpostcallback(zjin_fb_update, null);
这样,每次有framebuffer的更新时,guest的屏幕都会存成一张bmp图片,这和用/dev/graphics/fb0的效果是一样的。
注意用以上方法截下来的图和原图有两点不同,一是blue和red通道互换,这是因为framebuffer是rgb,bmp格式里是bgr。还有就是y轴的零点是左下角,这是由于framebuffer中是opengl的坐标系。也就是说,要得到原图还要经过rgb到bgr的转换和y-inversion。建议到处理图片时再做这些处理,一方面不会拖慢模拟器速度,另一方面像opencv里有现成的函数可供调用。