使用ubuntu的lcd显示模拟器出现的问题 图片是bmp 24位 运行后图片发黄
BMP是一种与硬件设备无关的图像文件格式,是Windows环境中交换与图有关的数据的一种标准,在Windows环境中运行的图形图像软件都支持BMP图像格式。BMP格式的图片存放的就是原始的RGB数据,一般没有做压缩,也就是图片的画质是最原始的,也导致BMP图片占用的内存非常大。现在常用的jpg、jpeg格式都是压缩格式,保存的时候通过算法编码压缩,显示的时候再解压成RGB数据渲染显示。
BMP格式在嵌入式设备里用的还是较多的,BMP虽然占用内存大,优点是显示速度快,因为不需要解码,在性能一般,不是很强的设备上使用BMP显示效率较高。
为了解BMP格式,这篇文章就采用Linux开发板作为实验平台,在LCD屏上读取BMP图片,完成绘制,不需要借助任何第三方库,全部由纯C语言代码一行一行敲出来,深入理解Linux下帧缓冲编程框架、BMP图片的存储结构原理。
一般BMP图片由以下4个部分组成:
1:文件头
2:图像参数
3:调色板
4:位图数据
现在一般采用的图片都是RGB888,24位真彩色,就没有调色板,只有3个部分组成。
其中文件头存放图片的属性,位图数据偏移量。图像参数存放图片的宽高、像素位数等信息。位图数据就是存储的原始RGB数据,可以直接在LCD屏上显示。
下面列出BMP图片的结构:
位图数据存储规则:
(1)每行的字节数必须是4的倍数,如果不是,则需要用0补齐。
(2)BMP位图数据的存放是从下到上,从左到右的。先读最后一行,读完后在读倒数第二行。
按照上面的介绍,就可以定义一个BMP解码专用的结构体,对应文件里每个字节数据,结构体成员变量必须按照上面截图里的说明定义。整个结构体还需要进行强制1个字节对齐,不然每个编译器对结构体的空间开辟规则有差异,会导致数据错位。
#pragma pack(1) //强制1个字节对齐
//BMP的文件头
struct _BMP_HEAD
{
char type[2]; //图片的类型 "BM"
unsigned int size; //文件大小
unsigned short r1; //保留1
unsigned short r2; //保留2
unsigned int seek; //数据偏移字节(真实像素点数据)
};
//BMP的参数信息
struct _BMP_INFO
{
unsigned int size; //当前结构体大小
unsigned int w; //宽度
unsigned int h; //高度
unsigned short flag; //固定为1
unsigned short bit; //像素点的位数
unsigned int r1; //压缩方式 0
unsigned int r2; //水平分辨率
unsigned int r3; //垂直分辨率
unsigned int r4; //垂直分辨率
unsigned int r5; //引用色彩
unsigned int r6; //关键色彩
};
问题原因: 你遇到LCD模拟显示器图片发黄的问题是因为在显示BMP图片的过程中,RGB数据没有正确解码并渲染显示。
解决方法:
// 定义BMP的文件头
struct _BMP_HEAD
{
char type[2]; //图片的类型 "BM"
unsigned int size; //文件大小
unsigned short r1; //保留1
unsigned short r2; //保留2
unsigned int seek; //数据偏移字节(真实像素点数据)
};
// 定义BMP的参数信息
struct _BMP_INFO
{
unsigned int size; //当前结构体大小
unsigned int w; //宽度
unsigned int h; //高度
unsigned short flag; //固定为1
unsigned short bit; //像素点的位数
unsigned int r1; //压缩方式 0
unsigned int r2; //水平分辨率
unsigned int r3; //垂直分辨率
unsigned int r4; //垂直分辨率
unsigned int r5; //引用色彩
unsigned int r6; //关键色彩
};
// 读取BMP图片的文件头和参数信息
void read_bmp_info(const char* file_path, struct _BMP_HEAD* bmp_head, struct _BMP_INFO* bmp_info) {
FILE* file = fopen(file_path, "rb");
if (file == NULL) {
printf("打开BMP文件失败\n");
return;
}
fread(bmp_head, sizeof(struct _BMP_HEAD), 1, file);
fread(bmp_info, sizeof(struct _BMP_INFO), 1, file);
fclose(file);
}
#include <linux/fb.h>
#include <sys/mman.h>
#include <stdio.h>
unsigned char *fb_mem;
struct fb_var_screeninfo var; // 可变参数
struct fb_fix_screeninfo fix; // 固定参数
// 画点
void show_pixel(int x, int y, int color)
{
unsigned long *show32 = NULL;
// 定位到LCD屏上的位置
show32 = (unsigned long *)(fb_mem + y * var.xres * var.bits_per_pixel / 8 + x * var.bits_per_pixel / 8);
*show32 = color; // 向指向的LCD地址赋数据
}
int main()
{
int fb;
fb = open("/dev/fb0", 2);
if (fb < 0)
{
printf("fb0打开失败!\n");
return -1;
}
// 获取可变参数
ioctl(fb, FBIOGET_VSCREENINFO, &var);
printf("x=%d\n", var.xres);
printf("y=%d\n", var.yres);
printf("bit=%d\n", var.bits_per_pixel);
// 获取固定参数
ioctl(fb, FBIOGET_FSCREENINFO, &fix);
printf("line_byte=%d\n", fix.line_length);
printf("smem_len=%d\n", fix.smem_len);
// 映射LCD地址
fb_mem = (unsigned char *)mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
struct _BMP_HEAD bmp_head;
struct _BMP_INFO bmp_info;
read_bmp_info("path_to_bmp_file", &bmp_head, &bmp_info); // 替换成你的BMP图片路径
// 读取BMP位图数据并渲染显示
unsigned int data_offset = bmp_head.seek;
unsigned char* bmp_data = (unsigned char*)malloc(bmp_info.size - bmp_head.seek);
FILE* file = fopen("path_to_bmp_file", "rb");
fseek(file, data_offset, SEEK_SET);
fread(bmp_data, 1, bmp_info.size - bmp_head.seek, file);
fclose(file);
int x, y;
unsigned int data_index = 0;
for (y = bmp_info.h - 1; y >= 0; y--)
{
for (x = 0; x < bmp_info.w; x++)
{
unsigned char b = bmp_data[data_index++];
unsigned char g = bmp_data[data_index++];
unsigned char r = bmp_data[data_index++];
int color = (r << 16) | (g << 8) | b; // 将RGB三个分量合并成一个颜色值
show_pixel(x, y, color);
}
// 判断是否需要用0进行字节对齐
int remainder = (bmp_info.w * bmp_info.bit) % 8;
if (remainder != 0) {
data_index += (8 - remainder) / 8;
}
}
free(bmp_data);
return 0;
}
请将上面的代码替换到你的项目中,并根据需要替换path_to_bmp_file
为你的BMP图片路径。运行代码后,BMP图片的RGB数据将正确解码并显示在LCD屏幕上,解决了图片呈现黄色的问题。
如果你的LCD显示模拟器中没有提供像素点渲染的接口,或者你的代码与你的LCD屏幕不兼容,那么我无法提供更具体的解决方案。