blob: 281e9ab8a26325ca4b01f429d249dec4ae9b788c [file] [log] [blame]
liubin281ac462023-07-19 14:22:54 +08001#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;
16typedef unsigned short color_t;
17/**< \brief 定义每个像素点对应的位数,如果是565的屏则为16,如果是888的屏则为32 */
18// #define BITS_PER_PIXEL 32
19#define BITS_PER_PIXEL 16
20
21static struct fb_var_screeninfo __g_vinfo; /* 显示信息 */
22color_t *__gp_frame; /* 虚拟屏幕首地址 */
23
24#pragma pack(2)
25typedef unsigned short WORD;
26typedef unsigned char BYTE;
27typedef unsigned int DWORD;
28typedef int LONG;
29
30typedef 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
40typedef 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
58typedef WORD (*bmp_xx_to_16)(char *);
59
60//画点
61void 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
69WORD 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
89WORD 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图像
104void 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 */
200void 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 */
213void clear()
214{
215 full_screen(0);
216}
217
218/* framebuffer初始化 */
219int 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
255int 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}