yuezonghe | c78e2ef | 2025-02-13 17:57:46 -0800 | [diff] [blame^] | 1 | #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)
|
| 11 | typedef struct {
|
| 12 | unsigned short bfType;
|
| 13 | unsigned int bfSize;
|
| 14 | unsigned short bfReserved1;
|
| 15 | unsigned short bfReserved2;
|
| 16 | unsigned int bfOffBits;
|
| 17 | } BMPFILEHEADER;
|
| 18 |
|
| 19 | typedef 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
|
| 37 | unsigned 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 |
|
| 43 | int 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 | } |