ネイティブ コードで 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;
}