功能

在嵌入式linux上, 通过操作framebuffer, 直接在显示屏上显示bmp图片
之前网上找的一些类似功能的都不靠谱, 于是自己写了一个测试程序

使用方法

编译后拷贝进开发板即可使用

./fb_show_bmp test.bmp

显示的图片由参数指定,上面指令中test.bmp为测试用的bmp格式的图片

效果

源码说明

代码说明

有部分代码需要注意一下

  1. 显示屏设备节点

    默认使用的是/dev/fb0这个节点,如果开发板的不是这个,需要改动

  2. 显示屏显示一行像素的数据长度
    显示屏一行的数据长度由 struce fb_fix_screeninfo 中的 line_length 字段决定, 而通过屏幕的分辨率计算得到的一行的数据量不一定准确.
    例如一个显示屏是 800x480, bpp为32, 直接计算一行的数据长度为: 800 * (32 / 8) 个字节
    但是这样计算不一定准确, 还与驱动的实现方式有关, 所以最好还是直接使用 line_length 字段

  3. bmp格式问题
    bmp图片的数据对于显示屏来说像是上下左右颠倒了, 所以进行转换时需要处理一下
    函数 cursor_bitmap_format_convert()进行了一行显示数据的左右处理
    上下方向上的数据我没有进行处理, 所以最终效果看起来是上下颠倒的

  4. 显示屏bpp
    我只测试了bpp为24/32的板子, 对于bpp为16的如果测试有问题, 可能还需要在修改下代码

源码

源码与一些测试用的bmp图片可在这里下载: https://download.csdn.net/download/bruno_mars/11267270

  • fb_show_bmp.c
#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>//14byte文件头
typedef struct
{char cfType[2];  //文件类型,"BM"(0x4D42)int  cfSize;     //文件大小(字节)int  cfReserved; //保留,值为0int  cfoffBits;  //数据区相对于文件头的偏移量(字节)
}__attribute__((packed)) BITMAPFILEHEADER;
//__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐//40byte信息头
typedef struct
{char ciSize[4];          //BITMAPFILEHEADER所占的字节数int  ciWidth;            //宽度int  ciHeight;           //高度char ciPlanes[2];        //目标设备的位平面数,值为1int  ciBitCount;         //每个像素的位数char ciCompress[4];      //压缩说明char ciSizeImage[4];     //用字节表示的图像大小,该数据必须是4的倍数char ciXPelsPerMeter[4]; //目标设备的水平像素数/米char ciYPelsPerMeter[4]; //目标设备的垂直像素数/米char ciClrUsed[4];       //位图使用调色板的颜色数char ciClrImportant[4];  //指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要
}__attribute__((packed)) BITMAPINFOHEADER;typedef struct
{unsigned char blue;unsigned char green;unsigned char red;unsigned char reserved;
}__attribute__((packed)) PIXEL; //颜色模式RGBtypedef struct
{int          fbfd;char         *fbp;unsigned int xres;unsigned int yres;unsigned int xres_virtual;unsigned int yres_virtual;unsigned int xoffset;unsigned int yoffset;unsigned int bpp;unsigned long line_length;unsigned long size;struct fb_bitfield red;struct fb_bitfield green;struct fb_bitfield blue;
} FB_INFO;typedef struct
{unsigned int width;unsigned int height;unsigned int bpp;unsigned long size;unsigned int data_offset;
} IMG_INFO;FB_INFO fb_info;
IMG_INFO img_info;int show_bmp(char *img_name);static int cursor_bitmap_format_convert(char *dst,char *src, unsigned long img_len_one_line)
{int img_len ,fb_len ;char *p;__u32 val;PIXEL pix;p = (char *)&val;img_len = img_info.width; /*一行图片的长度*/fb_len = fb_info.xres; /*一行显示屏的长度*//*进行x轴的偏移*/dst += fb_info.xoffset * (fb_info.bpp / 8);fb_len -= fb_info.xoffset;/*bmp 数据是上下左右颠倒的,这里只进行左右的处理*//*先定位到图片的最后一个像素的地址,然后往第一个像素的方向处理,进行左右颠倒的处理*/src += img_len_one_line - 1;/*处理一行要显示的数据*/while(1) {if (img_info.bpp == 32)pix.reserved = *(src--);pix.red   = *(src--);pix.green = *(src--);pix.blue  = *(src--);val = 0x00;val |= (pix.red >> (8 - fb_info.red.length)) << fb_info.red.offset;val |= (pix.green >> (8 - fb_info.green.length)) << fb_info.green.offset;val |= (pix.blue >> (8 - fb_info.blue.length)) << fb_info.blue.offset;if (fb_info.bpp == 16) {*(dst++) = *(p + 0);*(dst++) = *(p + 1);}else if (fb_info.bpp == 24) {*(dst++) = *(p + 0);*(dst++) = *(p + 1);*(dst++) = *(p + 2);}else if (fb_info.bpp == 32) {*(dst++) = *(p + 0);*(dst++) = *(p + 1);*(dst++) = *(p + 2);*(dst++) = *(p + 3);}/*超过图片长度或显示屏长度认为一行处理完了*/img_len--;fb_len--;if (img_len <= 0 || fb_len <= 0)break;}
#if 0printf("r = %d\n", pix.red);printf("g = %d\n", pix.green);printf("b = %d\n", pix.blue);
#endifreturn 0;
}int show_bmp(char *img_name)
{FILE *fp;int ret = 0;BITMAPFILEHEADER FileHead;BITMAPINFOHEADER InfoHead;if(img_name == NULL) {printf("img_name is null\n");return -1;}fp = fopen( img_name, "rb" );if(fp == NULL) {printf("img[%s] open failed\n", img_name);ret = -1;goto err_showbmp;}/* 移位到文件头部 */fseek(fp, 0, SEEK_SET);ret = fread(&FileHead, sizeof(BITMAPFILEHEADER), 1, fp);if ( ret != 1) {printf("img read failed\n");ret = -1;goto err_showbmp;}//检测是否是bmp图像if (memcmp(FileHead.cfType, "BM", 2) != 0) {printf("it's not a BMP file[%c%c]\n", FileHead.cfType[0], FileHead.cfType[1]);ret = -1;goto err_showbmp;}ret = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );if ( ret != 1) {printf("read infoheader error!\n");ret = -1;goto err_showbmp;}img_info.width       = InfoHead.ciWidth;img_info.height      = InfoHead.ciHeight;img_info.bpp         = InfoHead.ciBitCount;img_info.size        = FileHead.cfSize;img_info.data_offset = FileHead.cfoffBits;printf("img info w[%d] h[%d] bpp[%d] size[%ld] offset[%d]\n", img_info.width, img_info.height, img_info.bpp, img_info.size, img_info.data_offset);if (img_info.bpp != 24 && img_info.bpp != 32) {printf("img bpp is not 24 or 32\n");ret = -1;goto err_showbmp;}/**一行行处理*/char *buf_img_one_line;char *buf_fb_one_line;char *p;int fb_height;long img_len_one_line = img_info.width * (img_info.bpp / 8);long fb_len_one_line = fb_info.line_length;printf("img_len_one_line = %d\n", img_len_one_line);printf("fb_len_one_line = %d\n", fb_info.line_length);buf_img_one_line = (char *)calloc(1, img_len_one_line + 256);if(buf_img_one_line == NULL) {printf("alloc failed\n");ret = -1;goto err_showbmp;}buf_fb_one_line = (char *)calloc(1, fb_len_one_line + 256);if(buf_fb_one_line == NULL) {printf("alloc failed\n");ret = -1;goto err_showbmp;}fseek(fp, img_info.data_offset, SEEK_SET);p = fb_info.fbp + fb_info.yoffset * fb_info.line_length; /*进行y轴的偏移*/fb_height = fb_info.yres;while (1) {memset(buf_img_one_line, 0, img_len_one_line);memset(buf_fb_one_line, 0, fb_len_one_line);ret = fread(buf_img_one_line, 1, img_len_one_line, fp);if (ret < img_len_one_line) {/*图片读取完成,则图片显示完成*/printf("read to end of img file\n");cursor_bitmap_format_convert(buf_fb_one_line, buf_img_one_line, img_len_one_line); /*数据转换*/memcpy(fb_info.fbp, buf_fb_one_line, fb_len_one_line);break;}cursor_bitmap_format_convert(buf_fb_one_line, buf_img_one_line, img_len_one_line); /*数据转换*/memcpy(p, buf_fb_one_line, fb_len_one_line); /*显示一行*/p += fb_len_one_line;/*超过显示屏宽度认为图片显示完成*/fb_height--;if (fb_height <= 0)break;}free(buf_img_one_line);free(buf_fb_one_line);fclose(fp);return ret;
err_showbmp:if (fp)fclose(fp);return ret;
}int show_picture(char *img_name)
{struct fb_var_screeninfo vinfo;struct fb_fix_screeninfo finfo;if (fb_info.fbfd <= -1) {printf("fb open fialed\n");return -1;}if (ioctl(fb_info.fbfd, FBIOGET_FSCREENINFO, &finfo)) {printf("fb ioctl fialed\n");return -1;}if (ioctl(fb_info.fbfd, FBIOGET_VSCREENINFO, &vinfo)) {printf("fb ioctl fialed\n");return -1;}fb_info.xres = vinfo.xres;fb_info.yres = vinfo.yres;fb_info.xres_virtual = vinfo.xres_virtual;fb_info.yres_virtual = vinfo.yres_virtual;fb_info.xoffset = vinfo.xoffset;fb_info.yoffset = vinfo.yoffset;fb_info.bpp  = vinfo.bits_per_pixel;fb_info.line_length = finfo.line_length;fb_info.size = finfo.smem_len;memcpy(&fb_info.red, &vinfo.red, sizeof(struct fb_bitfield));memcpy(&fb_info.green, &vinfo.green, sizeof(struct fb_bitfield));memcpy(&fb_info.blue, &vinfo.blue, sizeof(struct fb_bitfield));printf("fb info x[%d] y[%d] x_v[%d] y_v[%d] xoffset[%d] yoffset[%d] bpp[%d] line_length[%ld] size[%ld]\n", fb_info.xres, fb_info.yres, fb_info.xres_virtual, fb_info.yres_virtual, fb_info.xoffset, fb_info.yoffset, fb_info.bpp, fb_info.line_length, fb_info.size);printf("fb info red off[%d] len[%d] msb[%d]\n", fb_info.red.offset, fb_info.red.length, fb_info.red.msb_right);printf("fb info green off[%d] len[%d] msb[%d]\n", fb_info.green.offset, fb_info.green.length, fb_info.green.msb_right);printf("fb info blue off[%d] len[%d] msb[%d]\n", fb_info.blue.offset, fb_info.blue.length, fb_info.blue.msb_right);if (fb_info.bpp != 16 && fb_info.bpp != 24 && fb_info.bpp != 32) {printf("fb bpp is not 16,24 or 32\n");return -1;}if (fb_info.red.length > 8 || fb_info.green.length > 8 || fb_info.blue.length > 8) {printf("fb red|green|blue length is invalid\n");return -1;}// 内存映射fb_info.fbp = (char *)mmap(0, fb_info.size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_info.fbfd, 0);if (fb_info.fbp == (char *)-1) {printf("mmap fialed\n");return -1;}show_bmp(img_name);//删除映射munmap(fb_info.fbp, fb_info.size);return 0;
}int main(int argc, char **argv)
{char img_name[64];if (argc != 2) {printf("arg error\n");return 0;}snprintf(img_name, sizeof(img_name), "%s", argv[1]);printf("img_name = %s\n", img_name);fb_info.fbfd = open("/dev/fb0", O_RDWR);if (!fb_info.fbfd) {printf("Error: cannot open framebuffer device(/dev/fb0).\n");return -1;}show_picture(img_name);close(fb_info.fbfd);return 0;
}

嵌入式linux操作framebuffer显示bmp图片相关推荐

  1. linux开发板显示百叶窗图片,03Linux命令操作2

    第一天 第一个小时嵌入式介绍,何为嵌入式,为什么学习嵌入式,嵌入式的发展前景,嵌入式的具体工作岗位以及薪资待遇如何. 第二个小时项目介绍 1.为什么需要项目的的沉淀,企业需要什么样的嵌入式开发人才 2 ...

  2. framebuffer显示JPEG图片

    framebuffer显示JPEG图片 2011-05-03 20:14:45 分类: 嵌入式 转自http://www.linuxsense.org/archives/281.html http:/ ...

  3. 基于嵌入式linux 的蓝牙通信系统设计与实现的研究意义,嵌入式Linux操作系统通信管理机的设计研究...

    摘 要 随着信息技术的发展,各种操作技术.操作系统不断更新,而通信管理机是自动化系统的数据枢纽,在自动化系统中担任重要角色,在本文中我们对嵌入式Linux操作系统的特点.通信管理机制等方面进行研究分析 ...

  4. s3c2440a如何保证嵌入式linux对于虚拟内存的支持?,基于S3C2440的嵌入式LINUX操作系统内核研究【资料学习】.doc...

    学校代码: 11059 学 号:0805070285 Hefei University 毕业论文(设计) BACHELOR DISSERTATION 论文题目: 基于S3C2440的嵌入式 LINUX ...

  5. C语言用句柄显示bmp图片,VC编程之VC MFC界面上显示BMP图片

    本文主要向大家介绍了VC编程之VC MFC界面上显示BMP图片,通过具体的内容向大家展示,希望对大家学习VC编程有所帮助. 1.通过点击界面浏览按钮选择BMP图像文件. 点击浏览按钮打开文件对话框选择 ...

  6. Linux应用开发-LCD显示BMP图片

    1. 前言 BMP是一种与硬件设备无关的图像文件格式,是Windows环境中交换与图有关的数据的一种标准,在Windows环境中运行的图形图像软件都支持BMP图像格式.BMP格式的图片存放的就是原始的 ...

  7. framebuffer 保存 bmp图片格式

    最近需要完成一个从framebuffer中进行读取,然后将内存的东西保存为bmp图片格式,我的其他博客内容对framebuffer进行详细的讲解,以及bmp的格式进行详细的讲解. 之前从网上看到了一些 ...

  8. UEFI显示BMP图片

    两种方式 :一种为按像素点画图:另一种为将图片转换到GOP blt缓冲区中,允许用户调用blt将其显示出来. 画像素点方式极慢,可以看到一行一行的绘画过程:而使用缓冲区则会立刻显示出一张图片. 先了解 ...

  9. 在6818开发板上显示bmp图片的基本步骤

    我总结为以下四步: 1)打开液晶屏文件.打开bmp图片文件.完成液晶屏内存映射 2)读取bmp图片文件到临时数组temp,等待处理数组里面的数据. 3)处理数据.映射到液晶屏上,此处是bmp图片算法: ...

  10. VC MFC界面上显示BMP图片

    1.通过点击界面浏览按钮选择BMP图像文件. 点击浏览按钮打开文件对话框选择BMP图像文件,得到文件所在的路径目录.关键代码如下: void ShowBMPDlg::OnButtonSelectiam ...

最新文章

  1. wince5使用access数据库_关于wince系统支持什么数据库的阿里云论坛用户知识和技术交流...
  2. SUSE Linux ntp 升级报错(MAKE [1]:*** 【all】Error 2)
  3. XamarinSQLite教程在Xamarin.Android项目中定位数据库文件
  4. fftw_plan_dft_2d优化
  5. openstack万兆交换机设置mtu值
  6. SQLite AND/OR 运算符(http://www.w3cschool.cc/sqlite/sqlite-and-or-clauses.html)
  7. EhCache的配置
  8. 2019ICPC(上海) - Spanning Tree Removal(构造)
  9. 迭代开发需要一种不同的观点[4]
  10. TensorFlow函数(十)tf.global_variables_initializer()
  11. 自定义CardView
  12. python的集合是什么_Python集合的概念是什么?Python集合的介绍
  13. 98% after emitting CopyPlugin
  14. [机器学习] SSE,MSE,RMSE,R-square指标讲解
  15. 龙测独家AI全新功能上线,手机无感录制,AI自动生成测试用例
  16. 原型设计 + 用户规格说明书
  17. 5.3 闪电网络的设计
  18. 【待更新】感知视频编码中的感知检测技术(显著性物体检测向)
  19. 改编电影:《蒙提·派森之火腿骑士》 Monty Python‘s Spamalot
  20. UML总结—包图(Package Diagram)

热门文章

  1. 面试题汇总2(吐血整理)
  2. N1 armbian cups安装hp m126a打印机
  3. 什么是简单边界点(Simple border points)
  4. 在Excel中批量生成二维码标签,标签中可添加二维码或者条形码
  5. 解决私服jar包[WARNING] The POM for xxx is missing, no dependency information available
  6. 安装mosek并配置到matlab
  7. html下拉框选择日期,javascript实现日期三级联动下拉框选择菜单
  8. Excel远程连接Oracle,excel连接数据库_怎么用oracle命令连接远程数据库�9�3
  9. ESD静电二极管封装规格,详细介绍
  10. 项目管理 : 需求管理的6个流程