0

我想使用本机代码在 Android 中捕获屏幕截图。我读取framebuffer以获取原始数据,然后转换为 24bmp 以另存为文件。但我刚得到一张模糊的图像,它的像素看起来错位了。有人可以看看我的代码以提供任何帮助吗?3Q。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>

#include <sys/types.h>
#include <linux/fb.h>

#pragma pack(1)

typedef struct bmp_header
{
    //14B
    unsigned short bfType;
    unsigned int bfSize;
    unsigned short bfReserved1;
    unsigned short bfReserved2;
    unsigned int headersize;

    //40B
    unsigned int infoSize;
    int width;
    int height;
    unsigned short biPlanes;
    unsigned short bits;
    unsigned int biCompression;
    unsigned int biSizeImage;
    int biXPelsPerMeter;
    int biYPelsPerMeter;
    unsigned int biClrUsed;
    unsigned int biClrImportant;

} BMPHEADER;


typedef struct {
    unsigned char *bits;
    unsigned size;
    int fd;
    struct fb_fix_screeninfo fi;
    struct fb_var_screeninfo vi;
} FB;

static int get_framebuffer(FB *fb)
{
    fb->fd = open("/dev/graphics/fb0", O_RDWR);
    if(fb->fd < 0) {
        perror("cannot open fb0");
        return -1;
    }

    if(ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) {
        perror("failed to get fb0 info");
        return -1;
    }

    if(ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) {
        perror("failed to get fb0 info");
        return -1;
    }

    //dumpinfo(&fi, &vi);
    fb->bits = mmap(0, fb->fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0);
    if(fb->bits == MAP_FAILED) {
        perror("failed to mmap framebuffer");
        return -1;
    }

}

int fb_bpp(FB *fb)
{
    if (fb) {
        return fb->vi.bits_per_pixel;
    }
    return 0;
}

int fb_width(FB *fb)
{
    if (fb) {
        return fb->vi.xres;
    }
    return 0;
}

int fb_height(FB *fb)
{
    if (fb) {
        return fb->vi.yres;
    }
    return 0;
}

int take_screenshot(char *path)
{
    int w, h;
    int depth;
    unsigned short *bits;
    FB gr_fb;

    get_framebuffer(&gr_fb);

    w = fb_width(&gr_fb);
    h = fb_height(&gr_fb);
    depth = fb_bpp(&gr_fb);

    //convert pixel data
    uint8_t *rgb24;
    if (depth == 16) {
        rgb24 = (uint8_t *)malloc(w * h * 3);
        int i = 0;
        for ( ; i < w*h; i++) {
            uint16_t pixel16 = ((uint16_t *)gr_fb.bits)[i];
            // RRRRRGGGGGGBBBBBB -> RRRRRRRRGGGGGGGGBBBBBBBB
            // in rgb24 color max is 2^8 per channel (*255/32 *255/64 *255/32)
            rgb24[3*i+0]   = (255*(pixel16 & 0x001F))/ 32;      //Blue
            rgb24[3*i+1]   = (255*((pixel16 & 0x07E0) >> 5))/64;    //Green
            rgb24[3*i+2]     = (255*((pixel16 & 0xF800) >> 11))/32;     //Red
        }
    } else if (depth == 24) {
        rgb24 = (uint8_t *)gr_fb.bits;
    } else if (depth == 32) {
        //skip transparency channel
        rgb24 = (uint8_t *) malloc(w * h * 3);
        int i=0;
        for ( ; i <w*h; i++)
        {
            uint32_t pixel32 = ((uint32_t *)gr_fb.bits)[i];
            // in rgb24 color max is 2^8 per channel
            rgb24[3*i+2]   =  pixel32 & 0x000000FF;         //Blue
            rgb24[3*i+1]   = (pixel32 & 0x0000FF00) >> 8;   //Green
            rgb24[3*i+0]   = (pixel32 & 0x00FF0000) >> 16;  //Red
        }
    } else {
        //free
        close(gr_fb.fd);
        exit(2);
    };


    //save RGB 24 Bitmap
    int bytes_per_pixel = 3;
    BMPHEADER bh;
    memset ((char *)&bh,0,sizeof(BMPHEADER)); // sets everything to 0
    //bh.filesize  =   calculated size of your file (see below)
    //bh.reserved  = two zero bytes
    bh.bfType = 0x4D42;
    bh.bfReserved1 = 0;
    bh.bfReserved2 = 0;
    bh.headersize = 54L;
    bh.infoSize  =  0x28L;      // for 24 bit images
    bh.width     = w;           // width of image in pixels
    bh.height    = -h;          // height of image in pixels
    bh.biPlanes  = 1;           // for 24 bit images
    bh.bits      = 8 * bytes_per_pixel; // for 24 bit images
    bh.biCompression = 0L;      // no compression
    int bytesPerLine;
    bytesPerLine = w * bytes_per_pixel;     // for 24 bit images
    //round up to a dword boundary
    if (bytesPerLine & 0x0003) {
        bytesPerLine |= 0x0003;
        ++bytesPerLine;
    }
    bh.biSizeImage = (long)bytesPerLine * bh.height;
    bh.bfSize = bh.headersize + bh.biSizeImage;
    FILE * bmpfile;
    //printf("Bytes per line : %d\n", bytesPerLine);
    bmpfile = fopen(path, "wb");
    if (bmpfile == NULL) {
        close(gr_fb.fd);
        exit(3);
    }
    fwrite((char *)&bh, 1, sizeof (bh), bmpfile);
    fwrite(rgb24,1,w*h*3,bmpfile);

    fclose(bmpfile);
    close(gr_fb.fd);

    return 0;
}

测试截图

4

0 回答 0