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