显示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显示图片的程序都应用该程序。