OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 438|回复: 4

求助: 请问 BMP图片显示错位是什么原因?

[复制链接]

1

主题

3

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2024-6-12
在线时间
2 小时
发表于 2024-7-9 17:38:00 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 kuraky 于 2024-7-10 16:16 编辑


硬件环境: I.MX6ULL alpha 开发板, 7寸 1024 * 600
软件环境是:  操作系统开发出厂自带linux系统  +  <<【正点原子】I.MX6U嵌入式Linux C应用编程指南V1.4 >> 是 第19章的示例代码19.5.1 显示BMP图像
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
/**** BMP 文件头数据结构 ****/
typedef struct {
    unsigned char type[2];
    //文件类型
    unsigned int size;
    //文件大小
    unsigned short reserved1; //保留字段 1
    unsigned short reserved2;
    //保留字段 2
    unsigned int offset;
    //到位图数据的偏移量
} __attribute__ ((packed)) bmp_file_header;

/**** 位图信息头数据结构 ****/
typedef struct {
    unsigned int size;
    //位图信息头大小
    int width;
    //图像宽度
    int height;
    //图像高度
    unsigned short planes;
    //位面数
    unsigned short bpp;
    //像素深度
    unsigned int compression; //压缩方式
    unsigned int image_size;
    //图像大小
    int x_pels_per_meter;
    //像素/米
    int y_pels_per_meter;
    //像素/米
    unsigned int clr_used;
    unsigned int clr_omportant;
} __attribute__ ((packed)) bmp_info_header;

/**** 静态全局变量 ****/
static int width;
//LCD X 分辨率
static int height;
//LCD Y 分辨率
static unsigned short *screen_base = NULL;
//映射后的显存基地址
static unsigned long line_length;
//LCD 一行的长度(字节为单位)

static int show_bmp_image(const char *path)
{
    bmp_file_header file_h;
    bmp_info_header info_h;
    unsigned short *line_buf = NULL;
    //行缓冲区
    unsigned long line_bytes; //BMP 图像一行的字节的大小
    unsigned int min_h, min_bytes;
    int fd = -1;
    int j;
    /* 打开文件 */
    if (0 > (fd = open(path, O_RDONLY))) {
        perror("open error");
        return -1;
    }
    /* 读取 BMP 文件头 */
    if (sizeof(bmp_file_header) !=
        read(fd, &file_h, sizeof(bmp_file_header))) {
        perror("read error");
        close(fd);
        return -1;
    }
    if (0 != memcmp(file_h.type, "BM", 2)) {
        fprintf(stderr, "it's not a BMP file\n");
        close(fd);
        return -1;
    }

    /* 读取位图信息头 */
    if (sizeof(bmp_info_header) !=
        read(fd, &info_h, sizeof(bmp_info_header))) {
        perror("read error");
        close(fd);
        return -1;
    }
        /* 打印信息 */
    printf("文件大小: %d\n"
            "位图数据的偏移量: %d\n"
            "位图信息头大小: %d\n"
            "图像分辨率: %d*%d\n"
            "像素深度: %d\n", file_h.size, file_h.offset,
            info_h.size, info_h.width, info_h.height,
            info_h.bpp);

    /* 将文件读写位置移动到图像数据开始处 */
    if (-1 == lseek(fd, file_h.offset, SEEK_SET)) {
        perror("lseek error");
        close(fd);
        return -1;
    }

    /* 申请一个 buf、暂存 bmp 图像的一行数据 */
    line_bytes = info_h.width * info_h.bpp / 8;
    line_buf = malloc(line_bytes);
    if (NULL == line_buf) {
        fprintf(stderr, "malloc error\n");
        close(fd);
        return -1;
    }
    if (line_length > line_bytes)
        min_bytes = line_bytes;
    else
        min_bytes = line_length;

    if (0 < info_h.height) {//倒向位图
        if (info_h.height > height) {
            min_h = height;
            lseek(fd, (info_h.height - height) * line_bytes, SEEK_CUR);
            screen_base += width * (height - 1); //定位到屏幕左下角位置
        }
        else {
            min_h = info_h.height;
            screen_base += width * (info_h.height - 1); //定位到....不知怎么描述 懂的人自然懂!
        }
        for (j = min_h; j > 0; screen_base -= width, j--) {
            read(fd, line_buf, line_bytes); //读取出图像数据
            memcpy(screen_base, line_buf, min_bytes);//刷入 LCD 显存
        }
    } else { //正向位图
        int temp = 0 - info_h.height;
        if (temp > height)
            min_h = height;
        else
            min_h = temp;
        for (j = 0; j < min_h; j++, screen_base += width) {
            read(fd, line_buf, line_bytes);
            memcpy(screen_base, line_buf, min_bytes);
        }
    }
    /* 关闭文件、函数返回 */
    close(fd);
    free(line_buf);
    return 0;
}


int main(int argc, char *argv[])
{
    struct fb_fix_screeninfo fb_fix;
    struct fb_var_screeninfo fb_var;
    unsigned int screen_size;
    int fd;
    /* 传参校验 */
    if (2 != argc) {
        fprintf(stderr, "usage: %s <bmp_file>\n", argv[0]);
        exit(-1);
    }
    /* 打开 framebuffer 设备 */
    if (0 > (fd = open("/dev/fb0", O_RDWR))) {
        perror("open error");
        exit(EXIT_FAILURE);
    }

    /* 获取参数信息 */
    ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
    ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);
    screen_size = fb_fix.line_length * fb_var.yres;
    line_length = fb_fix.line_length;
    width = fb_var.xres;
    height = fb_var.yres;

    /* 将显示缓冲区映射到进程地址空间 */
    screen_base = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == (void *)screen_base) {
        perror("mmap error");
        close(fd);
        exit(EXIT_FAILURE);
    }
    /* 显示 BMP 图片 */
    memset(screen_base, 0xFF, screen_size);
    show_bmp_image(argv[1]);
    /* 退出 */
    munmap(screen_base, screen_size); //取消映射
    close(fd); //关闭文件
    exit(EXIT_SUCCESS);
    //退出进程
}


原图片

原图片

开发显示的图片

开发显示的图片
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

10

主题

3281

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8205
金钱
8205
注册时间
2020-5-11
在线时间
3700 小时
发表于 2024-7-10 10:02:37 | 显示全部楼层
从显示看,多半是宽度有差异,比如图像宽度是100,但你把它当作101的宽度来显示。
还有起始位置可能有偏差,意思就是第一个点的位置不对。
专治疑难杂症
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2024-6-12
在线时间
2 小时
 楼主| 发表于 2024-7-10 10:15:00 来自手机 | 显示全部楼层
我是用的imx6ULL alpha开发板 7寸1024*600 , 开发版出厂Linux系统, 教程中的示例代码
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2024-6-12
在线时间
2 小时
 楼主| 发表于 2024-7-10 16:38:09 | 显示全部楼层
经过多次测试, 发现和图片的横向分辨率有关. 如果是单数,比如 901 , 就会显示错位.
把图片的横向分辨率改为902, 就能正常显示.

不知道和LCD底层驱动有没有关系.
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2024-7-14 22:19:37 | 显示全部楼层
帮顶
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 15:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表