显示bmp图片的程序之前已经写过了,只是没有单独拿出来,这次单独把显示bmp图片的程序拿出来并简单讲解一下。

直接上代码:

  1 /**
  2  * filename: jpg.c
  3  * author: Suzkfly
  4  * date: 2021-07-28
  5  * platform: S3C6410或Ubuntu
  6  */
  7 #include <stdio.h>
  8 #include <linux/fb.h>
  9 #include <sys/types.h>
 10 #include <sys/stat.h>
 11 #include <fcntl.h>
 12 #include <sys/mman.h>
 13 #include <math.h>
 14 #include <string.h>
 15 #include <stdlib.h>
 16 
 17 /**< \brief 根据实际情况修改,此处为unsigned short是565的屏,根据程序打印出的
 18     bits_per_pixel的值可以判断出输出格式是565还是888 */
 19 typedef unsigned int color_t;
 20 //typedef unsigned short color_t;
 21 /**< \brief 定义每个像素点对应的位数,如果是565的屏则为16,如果是888的屏则为32 */
 22 #define BITS_PER_PIXEL    32
 23 //#define BITS_PER_PIXEL    16
 24 
 25 static struct fb_var_screeninfo __g_vinfo;    /* 显示信息 */
 26 color_t *__gp_frame;                    /* 虚拟屏幕首地址 */
 27 
 28 #pragma pack(2)
 29 typedef unsigned short WORD; 
 30 typedef unsigned char BYTE; 
 31 typedef unsigned int DWORD; 
 32 typedef int LONG; 
 33 
 34 typedef struct tagBITMAPFILEHEADER
 35 {
 36     WORD bfType;        // 位图文件的类型,必须为BM
 37     DWORD bfSize;       // 位图文件的大小,以字节为单位 
 38     WORD bfReserved1;   // 位图文件保留字,必须为0
 39     WORD bfReserved2;   // 位图文件保留字,必须为0
 40     DWORD bfOffBits;    // 位图数据的起始位置,以相对于位图
 41     // 文件头的偏移量表示,以字节为单位
 42 } BITMAPFILEHEADER;
 43 
 44 typedef struct tagBITMAPINFOHEADER
 45 {
 46     DWORD biSize; // 本结构所占用字节数
 47     LONG biWidth; // 位图的宽度,以像素为单位
 48     LONG biHeight; // 位图的高度,以像素为单位
 49     WORD biPlanes; // 目标设备的级别,必须为1
 50     WORD biBitCount;// 每个像素所需的位数,必须是1(双色),
 51          // 4(16色),8(256色)或24(真彩色)之一
 52     DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
 53         // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
 54     DWORD biSizeImage; // 位图的大小,以字节为单位
 55     LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数
 56     LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数
 57     DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数
 58     DWORD biClrImportant;// 位图显示过程中重要的颜色数
 59 } BITMAPINFOHEADER;
 60 #pragma pack(0)
 61 
 62 
 63 //画点
 64 void draw_point(int x, int y, color_t color)
 65 {
 66     color_t *p = __gp_frame;
 67 
 68     p += __g_vinfo.xres * y + x;
 69     *p = color;
 70 }
 71 
 72 //功能:在指定坐标显示指定BPM24位图
 73 //参数:(x , y)坐标
 74 //        pic:24位BMP图像
 75 void Show_BMP(int x , int y , char *pic)
 76 {
 77     int fd = 0;
 78     color_t c;
 79     BITMAPFILEHEADER filehead;
 80     BITMAPINFOHEADER infohead;
 81     int i,j;
 82     unsigned char *p = NULL , *p_data = NULL;
 83     int width_error = 0;
 84 
 85     fd = open(pic , O_RDONLY);
 86     if(fd == -1) {
 87         printf("fail to open\n");
 88         return;
 89     }
 90 
 91     read(fd , &filehead , sizeof(filehead));
 92     read(fd , &infohead , sizeof(infohead));
 93 
 94     width_error = (4-infohead.biWidth*3%4)%4;
 95 
 96     p_data = malloc(infohead.biSizeImage);
 97     if(p_data == NULL) {
 98         perror("fail to malloc");
 99     }
100     
101     read(fd , p_data , infohead.biSizeImage);
102     p = p_data;
103     
104     for(j = infohead.biHeight - 1; j >= 0; j--) {
105         for(i = 0; i < infohead.biWidth; i++) {
106 #if (BITS_PER_PIXEL == 16)          
107             /* 如果使用的bmp图片的颜色深度是24位,适用于888的屏,但如果一定要在565的屏
108                上显示,则取红色的高5位,绿色的高6位和蓝色的高5位,拼成16位的数据
109                进行显示。这样做并不是最好的办法,更好的方法是将需要丢失的部分数
110                据进行进位或舍去。 */             
111             char b, g, r;
112             r = *p >> 3;
113             p++;
114             g = *p >> 2;
115             p++;
116             b = *p >> 3;
117             p++; 
118 
119             c = (b << 11) | (g << 5) | r;
120 #elif (BITS_PER_PIXEL == 32) 
121             c = *p;
122             p++;
123             c |= (*p << 8);
124             p++;
125             c |= (*p << 16);
126             p++;
127 #endif
128             draw_point(x + i, y + j, c);
129         }
130         p += width_error;
131     }
132     free(p_data);
133     close(fd);
134 }
135 
136 /**
137  * \brief 填充整屏
138  */
139 void full_screen (color_t color)
140 {
141     int i;
142     color_t *p = __gp_frame;
143 
144     for (i = 0; i < __g_vinfo.xres_virtual * __g_vinfo.yres_virtual; i++) {
145         *p++ = color;
146     }
147 }
148 
149 /**
150  * \brief 清屏
151  */
152 void clear()
153 {
154     full_screen(0);
155 }
156 
157 /* framebuffer初始化 */
158 int framebuffer_init (void)
159 {
160     int fd = 0;
161 
162     fd = open("/dev/fb0", O_RDWR);
163     if (fd == -1) {
164         perror("fail to open /dev/fb0\n");
165         return -1;
166     }
167 
168     /* 获取显示信息 */
169     ioctl(fd, FBIOGET_VSCREENINFO, &__g_vinfo);                     /* 获取显示信息 */
170     printf("bits_per_pixel = %d\n", __g_vinfo.bits_per_pixel);      /* 得到一个像素点对应的位数 */
171     printf("xres_virtual = %d\n", __g_vinfo.xres_virtual);            /* 打印虚拟屏幕列数 */
172     printf("yres_virtual = %d\n", __g_vinfo.yres_virtual);            /* 打印虚拟屏幕行数 */
173     printf("xres = %d\n", __g_vinfo.xres);                            /* 打印屏幕列数 */
174     printf("yres = %d\n", __g_vinfo.yres);                            /* 打印屏幕行数 */
175 
176     /* 设置显示信息 */
177     /*
178     __g_vinfo.xres_virtual = 2048;
179     __g_vinfo.yres_virtual = 1920;
180     __g_vinfo.xres = 800;
181     __g_vinfo.yres = 600;
182     if (ioctl(fd, FBIOPUT_VSCREENINFO, &__g_vinfo)) {
183         perror ("Get VScreen Info Error\n");
184            exit (1); 
185     }
186     */
187     
188     
189     /* 获取显示信息 */
190     ioctl(fd, FBIOGET_VSCREENINFO, &__g_vinfo);                     /* 获取显示信息 */
191     printf("bits_per_pixel = %d\n", __g_vinfo.bits_per_pixel);      /* 得到一个像素点对应的位数 */
192     printf("xres_virtual = %d\n", __g_vinfo.xres_virtual);            /* 打印虚拟屏幕列数 */
193     printf("yres_virtual = %d\n", __g_vinfo.yres_virtual);            /* 打印虚拟屏幕行数 */
194     printf("xres = %d\n", __g_vinfo.xres);                            /* 打印屏幕列数 */
195     printf("yres = %d\n", __g_vinfo.yres);                            /* 打印屏幕行数 */
196 
197     __gp_frame = mmap(NULL,                             /* 映射区的开始地址,为NULL表示由系统决定映射区的起始地址 */
198                       __g_vinfo.xres_virtual * __g_vinfo.yres_virtual * __g_vinfo.bits_per_pixel / 8,    /* 映射区大小 */
199                       PROT_WRITE | PROT_READ,            /* 内存保护标志(可读可写) */
200                       MAP_SHARED,                        /* 映射对象类型(与其他进程共享) */
201                       fd,                                /* 有效的文件描述符 */
202                       0);                                /* 被映射内容的偏移量 */
203     if (__gp_frame == NULL) {
204         perror("fail to mmap\n");
205         return -1;
206     }
207 
208     return 0;
209 }
210 
211 
212 int main(int argc, const char *argv[])
213 {
214     if (framebuffer_init()) {
215         return 0;
216     }
217 
218     /* 清屏 */
219     clear();
220 
221     Show_BMP(0 , 0 , "banana.bmp");
222 
223     return 0;
224 }

注意:

banana.bmp这张图片需要自己准备。

该程序是将BMP显示的部分单独拿出来了,并且解决了一些bug,因此以后bmp显示图片的程序都应用该程序。