/*********************************************************************************
* @Description : 在LCD屏的任意位置展示一张任意大小的bmp图片,其余位置用纯色填充
* @Author : ice_cui
* @Date : 2025-04-28 22:53:46
* @Email : Lazypanda_ice@163.com
* @LastEditTime : 2025-04-29 14:52:09
* @Version : V1.0.3
* @Copyright : Copyright (c) 2025 Lazypanda_ice@163.com All rights reserved.
**********************************************************************************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#define FILL_COLOR 0xFFFFFF
//屏幕的物理尺寸
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
//想要显示图片的起始位置
#define X 100
#define Y 100
//取消字节对齐
#pragma pack(1)
//文件头结构体
typedef struct BITMAP_FILE_HEADER
{
short bfType;//文件标识
int bfSize;//文件大小
short bfReserved1;//保留字
short bfReserved2;//保留字
int bfOffBits;//文件指示器偏移量相较于文件开头
} bpFile_Header, *PbpFile_Header;
//信息头结构体
typedef struct BITMAP_INFO_HEADER
{
int bpSize;//图像描述信息块的大小
int bpWidth;//图像宽度
int bpHeight;//图像高度
short bpPlanes;//图像的plane总数(恒为1)
short bpBitCount;//记录颜色的位数取值1(双色),4,6,24,32
int bpCompression;//数据压缩方式(0:不压缩;1:8位压缩;2:4位压缩)
int bpSizeImage;//图像区数据的大小,必须是4的倍数
int bpXPelsPerMeter;//水平每米有多少像素,在设备无关位图中,填写00H
int bpYPelsPerMeter;//垂直每米有多少像素,在设备无关位图中,填写00H
int bpClrUsed;// 此图像所有的颜色数,不用,固定为0
int bpClrImportant;// 重要颜色数,不用,固定为0
} bpInfo_Header, *PbpInfo_Header;
#pragma pack()
int main(int argc, char const *argv[])
{
//1,打开待显示的bmp图像
FILE *bmp_fp = fopen("2.bmp","rb");
if (NULL == bmp_fp)
{
perror("无法打开BMP文件");
return -1;
}
//2,读取bmp文件的图像信息,获取bmp的宽和高
bpInfo_Header headerinfo;
fseek(bmp_fp,14,SEEK_SET);
fread(&headerinfo,1,40,bmp_fp);
if (headerinfo.bpBitCount != 24) {
printf("the bmp is not 24bit\n");
fclose(bmp_fp);
return -1;
}
printf("bmp width = %d,height = %d,bit = %d\n",headerinfo.bpWidth,
headerinfo.bpHeight,
headerinfo.bpBitCount);
// 计算每行字节数(考虑字节对齐)
int rowSize = ((headerinfo.bpWidth * headerinfo.bpBitCount + 31) / 32) * 4;
// 3,动态分配内存读取bmp文件的颜色分量
char *bmp_buf = (char *)malloc(rowSize * headerinfo.bpHeight);
if (bmp_buf == NULL)
{
perror("内存分配失败");
fclose(bmp_fp);
return -1;
}
fseek(bmp_fp, 54, SEEK_SET); // 跳过文件头和信息头
fread(bmp_buf, 1, rowSize * headerinfo.bpHeight, bmp_fp);
//4,关闭bmp
fclose(bmp_fp);
//5,打开LCD
int lcd_fd = open ("/dev/fb0",O_RDWR);
if (-1 == lcd_fd)
{
perror("open lcd error");
free(bmp_buf);
return -1;
}
//6,对LCD屏进行内容映射 mmap函数
int *lcd_mp = (int*)mmap(NULL,
LCD_WIDTH * LCD_HEIGHT * 4,
PROT_READ|PROT_WRITE,
MAP_SHARED,
lcd_fd,
0);
if (MAP_FAILED == lcd_mp)
{
printf("mmap for lcd is error\n");
return -1;
}
// 先填充纯色
for (int i = 0; i < LCD_HEIGHT; i++)
{
for (int j = 0; j < LCD_WIDTH; j++)
{
lcd_mp[i * LCD_WIDTH + j] = FILL_COLOR;
}
}
// 显示BMP图片
for (int i = 0; i < headerinfo.bpHeight; i++)
{
for (int j = 0; j < headerinfo.bpWidth; j++)
{
int srcIndex = ((headerinfo.bpHeight - i - 1) * rowSize + j * 3);
int dstX = X + j;
int dstY = Y + i;
if (dstX >= 0 && dstX < LCD_WIDTH && dstY >= 0 && dstY < LCD_HEIGHT)
{
unsigned char b = bmp_buf[srcIndex];
unsigned char g = bmp_buf[srcIndex + 1];
unsigned char r = bmp_buf[srcIndex + 2];
lcd_mp[dstY * LCD_WIDTH + dstX] = (r << 16) | (g << 8) | b;
}
}
}
//8,解除映射并关闭LCD
munmap(lcd_mp,LCD_WIDTH * LCD_HEIGHT * 4);
close(lcd_fd);
return 0;
}