背景:用framebuffer 去实现截屏功能,并想将图片保存位24位深的bmp图片
网上关于截屏的代码解析挺多的,这里不做太多的描述
framebuffer 直接保存bmp 图片是 32 位的,需要进行转化
注意一下,如何将图片保存为24位bmp 图片即可
直接上源码
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <linux/ioctl.h>
#include <sys/ioctl.h>
// 保存BMP图像所需的Header结构
#pragma pack(push,2)
typedef struct BitmapFileHeader_s
{
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
} BitmapFileHeader;
#pragma pack(pop)
typedef struct BitmapInfoHeader_s{
unsigned int biSize;
unsigned int biWidth;
unsigned int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
unsigned int biXPelsPerMeter;
unsigned int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} BitmapInfoHeader;
void screenshot()
{
int i = 0;
int fbfd = 0;
int fd = 0;
char* fbp = NULL;
char* fp = NULL;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int linesize = 0;
long int screensize = 0;
long int fsize = 0;
BitmapFileHeader* fileHeader = NULL;
BitmapInfoHeader* infoHeader = NULL;
/*打开设备文件*/
fbfd = open("/dev/fb0", O_RDONLY);
/*取得屏幕相关参数*/
ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo);
ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);
/*计算屏幕缓冲区大小*/
linesize = vinfo.xres * vinfo.bits_per_pixel / 8;
screensize = linesize * vinfo.yres;
/*映射屏幕缓冲区到用户地址空间*/
fbp=(char*)mmap(0,screensize,PROT_READ,MAP_SHARED, fbfd, 0);
fd = open("screenshot.bmp", O_CREAT|O_RDWR);
/*计算BMP文件大小*/
fsize = screensize + sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader);
/*调整BMP文件大小,避免mmap之后写内存时出现SIGBUS*/
ftruncate(fd, fsize);
fp = (char*)mmap(0,fsize,PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0);
/*设置BMP图像信息*/
fileHeader = (BitmapFileHeader*)fp;
infoHeader = (BitmapInfoHeader*)(fp + sizeof(BitmapFileHeader));
fileHeader->bfOffBits = fsize-screensize;
fileHeader->bfSize = fsize;
fileHeader->bfType = 0x4d42;
infoHeader->biHeight = vinfo.yres;
infoHeader->biWidth = vinfo.xres;
infoHeader->biPlanes = 1;
infoHeader->biBitCount = 24; // 修改为24位深度
infoHeader->biSizeImage = screensize;
infoHeader->biSize = sizeof(BitmapInfoHeader);
/*逐行拷贝图像,反转行顺序,并将32位颜色转换为24位颜色*/
for (i = 0; i < vinfo.yres; ++i)
{
char* src = fbp + (vinfo.yres - i - 1) * linesize;
char* dest = fp + (fsize - screensize) + i * (vinfo.xres * 3);
int j;
for (j = 0; j < vinfo.xres; ++j)
{
/*从32位颜色中提取RGB分量,并将其写入24位深度的目标图像中*/
unsigned int color = *((unsigned int*)src);
unsigned char blue = (color >> 0) & 0xFF;
unsigned char green = (color >> 8) & 0xFF;
unsigned char red = (color >> 16) & 0xFF;
*dest = blue;
*(dest + 1) = green;
*(dest + 2) = red;
src += 4;
dest += 3;
}
}
munmap(fp, fsize);
close(fd);
/*释放缓冲区,关闭设备*/
munmap(fbp, screensize);
close(fbfd);
}
int main()
{
screenshot();
return 0;
}