ubuntu lcd模拟显示器 图片发黄问题

使用ubuntu的lcd显示模拟器出现的问题 图片是bmp 24位 运行后图片发黄

img

  • 这篇博客: Linux应用开发-LCD显示BMP图片中的 1. 前言 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 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图片的结构:

    image-20220124001914847

    image-20220124001941914

    位图数据存储规则:

    (1)每行的字节数必须是4的倍数,如果不是,则需要用0补齐。
    (2)BMP位图数据的存放是从下到上,从左到右的。先读最后一行,读完后在读倒数第二行。

    image-20220124002345869

    按照上面的介绍,就可以定义一个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; //关键色彩
    };
    
  • 以下回答由chatgpt基于相关博客总结生成:

    问题原因: 你遇到LCD模拟显示器图片发黄的问题是因为在显示BMP图片的过程中,RGB数据没有正确解码并渲染显示。

    解决方法:

    1. 首先,需要读取BMP图片的文件头和参数信息。下面是一个解析BMP图片的C语言代码示例:
    // 定义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);
    }
    
    1. 接下来,根据读取到的BMP参数信息,确定每个像素点的颜色数据的存储方式,并渲染到LCD屏幕上。根据参考资料中介绍的BMP位图数据存储规则,从最后一行开始读取每一行的像素点数据,逐个显示在LCD屏幕上。下面是一个示例代码:
    #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屏幕不兼容,那么我无法提供更具体的解决方案。