嵌入式开发板屏幕显示图片(bmp)

0.framebuffer简介

帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,把显存抽象后的一种设备,他允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。framebuffer是LCD对应的一中HAL(硬件抽象层),提供抽象的,统一的接口操作,用户不必关心硬件层是怎么实施的。这些都是由Framebuffer设备驱动来完成的。

1.图片

图片

下载图片的大小应该和显示屏大小一致

显示屏大小可以通过代码来查看,参考:什么是framebuffer,怎么应用(一)————如何画点、线、矩形、圆

2.代码

参考:Linux framebuffer显示bmp图片

2.1位图文件头

位图文件头(BITMAPFILEHEADER)是BMP位图文件的一个重要组成部分,主要用于识别文件是否为位图文件,并提供文件大小和位图数据的位置等信息。以下是位图文件头的详细结构和说明:

  1. 结构定义

    • 位图文件头通常占据14个字节,其结构定义如下:
      typedef struct tagBITMAPFILEHEADER {
          WORD  bfType;       // 2字节,位图文件类型,必须为'BM'(0x4D42)
          DWORD bfSize;       // 4字节,文件大小(以字节为单位)
          WORD  bfReserved1;  // 2字节,保留字段,通常为0
          WORD  bfReserved2;  // 2字节,保留字段,通常为0
          DWORD bfOffBits;    // 4字节,从文件头到实际位图数据的偏移量(以字节为单位)
      } BITMAPFILEHEADER;
      
  2. 字段解释

    • bfType:该字段用于标识文件类型,对于BMP文件,这个值必须是’BM’(即0x4D42)。这是识别文件是否为位图文件的关键。
    • bfSize:该字段表示整个文件的大小,以字节为单位。这有助于确定文件是否已完整下载或传输。
    • bfReserved1bfReserved2:这两个字段是保留字段,通常设置为0。在某些情况下,这些字段可能被用于特定的用途,但在标准的BMP文件中,它们不被使用。
    • bfOffBits:该字段表示从文件头到实际位图数据的偏移量,以字节为单位。通过这个字段,程序可以快速地定位到位图数据的起始位置。
  3. 作用

    • 位图文件头的主要作用是标识文件类型,确保程序能够正确地解析文件。同时,它还提供了关于文件大小和位图数据位置的信息,这些信息对于读取和解析位图文件至关重要。

在解析BMP文件时,程序首先会读取文件头,并检查bfType字段的值是否为’BM’。如果不是,则该文件不是有效的BMP文件。然后,程序会根据bfSizebfOffBits字段的值来读取和解析文件的其余部分。

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.编译及远程传输

参考本人前文。

4.输出到开发板的效果图

效果图

  • 29
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值