0.framebuffer简介
帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,把显存抽象后的一种设备,他允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。framebuffer是LCD对应的一中HAL(硬件抽象层),提供抽象的,统一的接口操作,用户不必关心硬件层是怎么实施的。这些都是由Framebuffer设备驱动来完成的。
1.图片
下载图片的大小应该和显示屏大小一致
显示屏大小可以通过代码来查看,参考:什么是framebuffer,怎么应用(一)————如何画点、线、矩形、圆
2.代码
2.1位图文件头
位图文件头(BITMAPFILEHEADER)是BMP位图文件的一个重要组成部分,主要用于识别文件是否为位图文件,并提供文件大小和位图数据的位置等信息。以下是位图文件头的详细结构和说明:
-
结构定义:
- 位图文件头通常占据14个字节,其结构定义如下:
typedef struct tagBITMAPFILEHEADER { WORD bfType; // 2字节,位图文件类型,必须为'BM'(0x4D42) DWORD bfSize; // 4字节,文件大小(以字节为单位) WORD bfReserved1; // 2字节,保留字段,通常为0 WORD bfReserved2; // 2字节,保留字段,通常为0 DWORD bfOffBits; // 4字节,从文件头到实际位图数据的偏移量(以字节为单位) } BITMAPFILEHEADER;
- 位图文件头通常占据14个字节,其结构定义如下:
-
字段解释:
bfType
:该字段用于标识文件类型,对于BMP文件,这个值必须是’BM’(即0x4D42)。这是识别文件是否为位图文件的关键。bfSize
:该字段表示整个文件的大小,以字节为单位。这有助于确定文件是否已完整下载或传输。bfReserved1
和bfReserved2
:这两个字段是保留字段,通常设置为0。在某些情况下,这些字段可能被用于特定的用途,但在标准的BMP文件中,它们不被使用。bfOffBits
:该字段表示从文件头到实际位图数据的偏移量,以字节为单位。通过这个字段,程序可以快速地定位到位图数据的起始位置。
-
作用:
- 位图文件头的主要作用是标识文件类型,确保程序能够正确地解析文件。同时,它还提供了关于文件大小和位图数据位置的信息,这些信息对于读取和解析位图文件至关重要。
在解析BMP文件时,程序首先会读取文件头,并检查bfType
字段的值是否为’BM’。如果不是,则该文件不是有效的BMP文件。然后,程序会根据bfSize
和bfOffBits
字段的值来读取和解析文件的其余部分。
2.2具体实现
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <errno.h>
typedef struct
{
char cfType[2];
long cfSize;
long cfReserved;
long cfoffBits;
}__attribute__((packed)) BITMAPFILEHEADER;
typedef struct
{
char ciSize[4];
long ciWidth;
long ciHeight;
char ciPlanes[2];
int ciBitCount;
char ciCompress[4];
char ciSizeImage[4];
char ciXPelsPerMeter[4];
char ciYPelsPerMeter[4];
char ciClrUsed[4];
char ciClrImportant[4];
}__attribute__((packed)) BITMAPINFOHEADER;
typedef struct
{
unsigned short blue;
unsigned short green;
unsigned short red;
unsigned short reserved;
}__attribute__((packed)) PIXEL;
BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;
static char *fbp = 0;
static int xres = 0;
static int yres = 0;
static int bits_per_pixel = 0;
int show_bmp();
int show_bmp2();
int fbfd = 0;
static void fb_update(struct fb_var_screeninfo *vi)
{
vi->yoffset = 1;
ioctl(fbfd, FBIOPUT_VSCREENINFO, vi);
vi->yoffset = 0;
ioctl(fbfd, FBIOPUT_VSCREENINFO, vi);
}
int width, height;
static int cursor_bitmpa_format_convert(char *dst,char *src){
int i ,j ;
char *psrc = src ;
char *pdst = dst;
char *p = psrc;
int value = 0x00;
pdst += (width * height * 4);
for(i=0;i<height;i++){
p = psrc + (i+1) * width * 3;
for(j=0;j<width;j++){
pdst -= 4;
p -= 3;
pdst[0] = p[0];
pdst[1] = p[1];
pdst[2] = p[2];
value = *((int*)pdst);
value = pdst[0];
if(value == 0x00){
pdst[3] = 0x00;
}else{
pdst[3] = 0xff;
}
}
}
return 0;
}
int show_bmp(char *path)
{
FILE *fp;
int rc;
int line_x, line_y;
long int location = 0, BytesPerLine = 0;
char *bmp_buf = NULL;
char *bmp_buf_dst = NULL;
char * buf = NULL;
int flen = 0;
int ret = -1;
int total_length = 0;
printf("into show_bmp function____________________________\n");
if(path == NULL)
{
printf("path Error,return");
return -1;
}
printf("path = %s\n", path);
fp = fopen( path, "rb" );
if(fp == NULL){
printf("load > cursor file open failed");
return -1;
}
fseek(fp,0,SEEK_SET);
fseek(fp,0,SEEK_END);
flen = ftell(fp);
printf("File size: %d\n", flen); // Debug: print file size
bmp_buf = (char*)calloc(1,flen - 54);
if(bmp_buf == NULL){
printf("load > malloc bmp out of memory!");
return -1;
}
fseek(fp,0,SEEK_SET);
rc = fread(&FileHead, sizeof(BITMAPFILEHEADER),1, fp);
if ( rc != 1)
{
printf("read header error!\n");
fclose( fp );
return( -2 );
}
// Debug: print BMP header fields
printf("BMP Header:\n");
printf("cfType: %c%c\n", FileHead.cfType[0], FileHead.cfType[1]);
printf("cfSize: %ld\n", FileHead.cfSize);
printf("cfReserved: %ld\n", FileHead.cfReserved);
printf("cfoffBits: %ld\n", FileHead.cfoffBits);
if (memcmp(FileHead.cfType, "BM", 2) != 0)
{
printf("it's not a BMP file\n");
fclose( fp );
return( -3 );
}
rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );
if ( rc != 1)
{
printf("read infoheader error!\n");
fclose( fp );
return( -4 );
}
width = InfoHead.ciWidth;
height = InfoHead.ciHeight-224;
total_length = width * height *3;
fseek(fp, FileHead.cfoffBits, SEEK_SET);
buf = bmp_buf;
while ((ret = fread(buf,1,total_length,fp)) >= 0) {
//printf("ret = %d", ret);
if (ret == 0) {
if (feof(fp)) {
printf("End of file reached.\n");
break;
}
if (ferror(fp)) {
perror("Error reading file");
break;
}
usleep(100);
continue;
}
printf("ret = %d\n", ret);
buf = ((char*) buf) + ret;
total_length = total_length - ret;
if(total_length == 0)break;
}
total_length = width * height * 4;
printf("total_length = %d\n", total_length);
bmp_buf_dst = (char*)calloc(1,total_length);
if(bmp_buf_dst == NULL){
printf("load > malloc bmp out of memory!");
return -1;
}
cursor_bitmpa_format_convert(bmp_buf_dst, bmp_buf);
memcpy(fbp,bmp_buf_dst,total_length);
printf("show logo return 0\n");
return 0;
}
int show_picture(int fd, char *path)
{
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
printf("Enter show_logo\n");
retry1:
fbfd = fd;
if (fbfd == -1)
{
printf("Error opening frame buffer errno=%d (%s)",errno, strerror(errno));
goto retry1;
}
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
{
printf("Error:reading fixed information.\n");
return -1;
}
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
{
printf("Error: reading variable information.\n");
return -1;
}
printf("R:%d,G:%d,B:%d \n", vinfo.red, vinfo.green, vinfo.blue );
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
xres = vinfo.xres;
yres = vinfo.yres;
bits_per_pixel = vinfo.bits_per_pixel;
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
printf("screensize=%d byte\n",screensize);
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if ((int)fbp == -1)
{
printf("Error: failed to map framebuffer device to memory.\n");
return -1;
}
printf("sizeof file header=%d\n", sizeof(BITMAPFILEHEADER));
show_bmp(path);
sleep(2); // 暂停2秒
fb_update(&vinfo);
munmap(fbp, screensize);
printf("Exit show_logo\n");
return 0;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s <bmp file path>\n", argv[0]);
return -1;
}
int fd = open("/dev/fb0", O_RDWR);
if (fd == -1) {
perror("Error opening framebuffer device");
return -1;
}
if (show_picture(fd, argv[1]) == -1) {
printf("Failed to display picture\n");
close(fd);
return -1;
}
close(fd);
return 0;
}
如果图片大小不一致,例如我使用的图片为:1280x1024
//这里要对图片的长宽进行校准
width = InfoHead.ciWidth;
height = InfoHead.ciHeight-224;
3.编译及远程传输
参考本人前文。