当前位置:操作系统 > 安卓/Android >>

编程实现Android模拟器中窗口截图存成文件

Android模拟器内容是用OpenGL渲染的,所以用一般的编程截图(如PrintWindow()等)会是黑屏。这是因为画的东西放在framebuffer里。
 
一种方法是通过adb把guest的framebuffer数据/dev/graphics/fb0倒到host,再转为图片。但这样速度比较慢。
 
好在Android模拟器中把guest的framebuffer传到host进行显示,所以在host端只要将framebuffer输出到文件即可。
 
首先定义每次framebuffer更新时的回调函数:
 
 
[cpp]  
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;  
}  
 
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窗口显示之后: 
 
 
[cpp] 
android_showOpenglesWindow(winhandle, drect.pos.x, drect.pos.y,  
                           drect.size.w, drect.size.h, disp->rotation * -90.);  
android_setPostCallback(zjin_fb_update, NULL);  
 
        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里有现成的函数可供调用。
 
 
补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,