blob: b46a1974a774c74fa6f43da3ab986195307796eb [file] [log] [blame]
yuezonghec78e2ef2025-02-13 17:57:46 -08001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <fcntl.h>
5#include <unistd.h>
6#include <sys/mman.h>
7#include <sys/ioctl.h>
8#include <linux/fb.h>
9
10#pragma pack(1)
11typedef struct {
12 unsigned short bfType;
13 unsigned int bfSize;
14 unsigned short bfReserved1;
15 unsigned short bfReserved2;
16 unsigned int bfOffBits;
17} BMPFILEHEADER;
18
19typedef struct {
20 unsigned int biSize;
21 int biWidth;
22 int biHeight;
23 unsigned short biPlanes;
24 unsigned short biBitCount;
25 unsigned int biCompression;
26 unsigned int biSizeImage;
27 int biXPelsPerMeter;
28 int biYPelsPerMeter;
29 unsigned int biClrUsed;
30 unsigned int biClrImportant;
31} BMPINFOHEADER;
32#pragma pack()
33
34#define SWAP_ENDIAN_USHORT(value) ((unsigned short)((((unsigned short)(value) & 0xFF) << 8) | (((unsigned short)(value) & 0xFF00) >> 8)))
35
36// Convert 24-bit RGB to 16-bit RGB565
37unsigned short rgb24_to_rgb565(unsigned char r, unsigned char g, unsigned char b) {
38 unsigned short color = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
39 unsigned short swapped = SWAP_ENDIAN_USHORT(color);
40 return swapped;
41}
42
43int main(int argc, char *argv[]) {
44 FILE *fp = NULL;
45 unsigned char *line = NULL;
46 BMPFILEHEADER fileHeader;
47 BMPINFOHEADER infoHeader;
48
49 if (argc < 2) {
50 printf("No para. Please input bmp filepath.\n");
51 return;
52 }
53
54 // Open BMP file
55 fp = fopen(argv[1], "rb");
56 if (!fp) {
57 perror("Cannot open BMP file");
58 return -1;
59 }
60
61 // Read BMP headers
62 if (fread(&fileHeader, sizeof(BMPFILEHEADER), 1, fp) != 1) {
63 perror("Failed to read file header");
64 fclose(fp);
65 return -1;
66 }
67 printf("fileHeader: bfType=%x, bfSize=%u, bfOffBits=%u\n",
68 fileHeader.bfType, fileHeader.bfSize, fileHeader.bfOffBits);
69
70 if (fread(&infoHeader, sizeof(BMPINFOHEADER), 1, fp) != 1) {
71 perror("Failed to read info header");
72 fclose(fp);
73 return -1;
74 }
75 printf("infoHeader: biSize=%u, biWidth=%d, biHeight=%d\n",
76 infoHeader.biSize, infoHeader.biWidth, infoHeader.biHeight);
77 printf("infoHeader: biPlanes=%u, biBitCount=%u, biCompression=%u\n",
78 infoHeader.biPlanes, infoHeader.biBitCount, infoHeader.biCompression);
79 printf("infoHeader: biSizeImage=%u, biXPelsPerMeter=%d, biYPelsPerMeter=%d\n",
80 infoHeader.biSizeImage, infoHeader.biXPelsPerMeter, infoHeader.biYPelsPerMeter);
81 printf("infoHeader: biClrUsed=%u, biClrImportant=%d\n",
82 infoHeader.biClrUsed, infoHeader.biClrImportant);
83
84 // Check BMP format
85 if (fileHeader.bfType != 0x4D42) { // ASCII code for "BM"
86 printf("Not a valid BMP file\n");
87 fclose(fp);
88 return -1;
89 }
90
91 // Check bit depth
92 if (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 16) {
93 printf("Only 16-bit or 24-bit BMP supported, current image is %d-bit\n", infoHeader.biBitCount);
94 fclose(fp);
95 return -1;
96 }
97
98 // Open framebuffer device
99 int fbfd = open("/dev/fb0", O_RDWR);
100 if (fbfd < 0) {
101 perror("Cannot open framebuffer device");
102 fclose(fp);
103 return -1;
104 }
105
106 // Get screen information
107 struct fb_var_screeninfo vinfo;
108 if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
109 perror("Cannot get screen info");
110 close(fbfd);
111 fclose(fp);
112 return -1;
113 }
114
115 // Check screen color depth
116 if (vinfo.bits_per_pixel != 16) {
117 printf("This program only supports 16-bit color depth display\n");
118 close(fbfd);
119 fclose(fp);
120 return -1;
121 }
122
123 // Calculate screen size and map framebuffer
124 long screensize = vinfo.xres * vinfo.yres * 2; // 16-bit = 2 bytes
125 unsigned char *fbp = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
126 if (fbp == MAP_FAILED) {
127 perror("Cannot map framebuffer");
128 close(fbfd);
129 fclose(fp);
130 return -1;
131 }
132
133 // Move file pointer to image data
134 fseek(fp, fileHeader.bfOffBits, SEEK_SET);
135
136 // Prepare to read image data
137 unsigned short *fb16 = (unsigned short *)fbp;
138 int bytes_per_pixel = infoHeader.biBitCount / 8;
139 int padding = (4 - (infoHeader.biWidth * bytes_per_pixel) % 4) % 4;
140 line = malloc(infoHeader.biWidth * bytes_per_pixel + padding);
141
142 if (line == NULL) {
143 perror("Memory allocation failed");
144 munmap(fbp, screensize);
145 close(fbfd);
146 fclose(fp);
147 return -1;
148 }
149
150 // Read and display image data
151 int y = 0;
152 for (y = infoHeader.biHeight - 1; y >= 0; y--) {
153 if (fread(line, infoHeader.biWidth * bytes_per_pixel + padding, 1, fp) != 1) {
154 printf("Failed to read image data\n");
155 free(line);
156 munmap(fbp, screensize);
157 close(fbfd);
158 fclose(fp);
159 return -1;
160 }
161 int x = 0;
162 for (x = 0; x < infoHeader.biWidth; x++) {
163 unsigned short pixel;
164 int location = x + y * vinfo.xres;
165
166 if (infoHeader.biBitCount == 24) {
167 // 24-bit BMP (BGR format)
168 unsigned char b = line[x * 3];
169 unsigned char g = line[x * 3 + 1];
170 unsigned char r = line[x * 3 + 2];
171 pixel = rgb24_to_rgb565(r, g, b);
172 } else {
173 // 16-bit BMP (already in RGB565 format)
174 pixel = *(unsigned short*)&line[x * 2];
175 }
176
177 // Check if within display bounds
178 if (x < vinfo.xres && y < vinfo.yres) {
179 fb16[location] = pixel;
180 }
181 }
182 }
183
184 // To display
185 write(fbfd, "1", 1);
186 usleep(1000*100);
187
188 // Cleanup resources
189 free(line);
190 fclose(fp);
191 munmap(fbp, screensize);
192 close(fbfd);
193
194 printf("Image display completed\n");
195 return 0;
196}