blob: b46a1974a774c74fa6f43da3ab986195307796eb [file] [log] [blame]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#pragma pack(1)
typedef struct {
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
} BMPFILEHEADER;
typedef struct {
unsigned int biSize;
int biWidth;
int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} BMPINFOHEADER;
#pragma pack()
#define SWAP_ENDIAN_USHORT(value) ((unsigned short)((((unsigned short)(value) & 0xFF) << 8) | (((unsigned short)(value) & 0xFF00) >> 8)))
// Convert 24-bit RGB to 16-bit RGB565
unsigned short rgb24_to_rgb565(unsigned char r, unsigned char g, unsigned char b) {
unsigned short color = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
unsigned short swapped = SWAP_ENDIAN_USHORT(color);
return swapped;
}
int main(int argc, char *argv[]) {
FILE *fp = NULL;
unsigned char *line = NULL;
BMPFILEHEADER fileHeader;
BMPINFOHEADER infoHeader;
if (argc < 2) {
printf("No para. Please input bmp filepath.\n");
return;
}
// Open BMP file
fp = fopen(argv[1], "rb");
if (!fp) {
perror("Cannot open BMP file");
return -1;
}
// Read BMP headers
if (fread(&fileHeader, sizeof(BMPFILEHEADER), 1, fp) != 1) {
perror("Failed to read file header");
fclose(fp);
return -1;
}
printf("fileHeader: bfType=%x, bfSize=%u, bfOffBits=%u\n",
fileHeader.bfType, fileHeader.bfSize, fileHeader.bfOffBits);
if (fread(&infoHeader, sizeof(BMPINFOHEADER), 1, fp) != 1) {
perror("Failed to read info header");
fclose(fp);
return -1;
}
printf("infoHeader: biSize=%u, biWidth=%d, biHeight=%d\n",
infoHeader.biSize, infoHeader.biWidth, infoHeader.biHeight);
printf("infoHeader: biPlanes=%u, biBitCount=%u, biCompression=%u\n",
infoHeader.biPlanes, infoHeader.biBitCount, infoHeader.biCompression);
printf("infoHeader: biSizeImage=%u, biXPelsPerMeter=%d, biYPelsPerMeter=%d\n",
infoHeader.biSizeImage, infoHeader.biXPelsPerMeter, infoHeader.biYPelsPerMeter);
printf("infoHeader: biClrUsed=%u, biClrImportant=%d\n",
infoHeader.biClrUsed, infoHeader.biClrImportant);
// Check BMP format
if (fileHeader.bfType != 0x4D42) { // ASCII code for "BM"
printf("Not a valid BMP file\n");
fclose(fp);
return -1;
}
// Check bit depth
if (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 16) {
printf("Only 16-bit or 24-bit BMP supported, current image is %d-bit\n", infoHeader.biBitCount);
fclose(fp);
return -1;
}
// Open framebuffer device
int fbfd = open("/dev/fb0", O_RDWR);
if (fbfd < 0) {
perror("Cannot open framebuffer device");
fclose(fp);
return -1;
}
// Get screen information
struct fb_var_screeninfo vinfo;
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
perror("Cannot get screen info");
close(fbfd);
fclose(fp);
return -1;
}
// Check screen color depth
if (vinfo.bits_per_pixel != 16) {
printf("This program only supports 16-bit color depth display\n");
close(fbfd);
fclose(fp);
return -1;
}
// Calculate screen size and map framebuffer
long screensize = vinfo.xres * vinfo.yres * 2; // 16-bit = 2 bytes
unsigned char *fbp = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if (fbp == MAP_FAILED) {
perror("Cannot map framebuffer");
close(fbfd);
fclose(fp);
return -1;
}
// Move file pointer to image data
fseek(fp, fileHeader.bfOffBits, SEEK_SET);
// Prepare to read image data
unsigned short *fb16 = (unsigned short *)fbp;
int bytes_per_pixel = infoHeader.biBitCount / 8;
int padding = (4 - (infoHeader.biWidth * bytes_per_pixel) % 4) % 4;
line = malloc(infoHeader.biWidth * bytes_per_pixel + padding);
if (line == NULL) {
perror("Memory allocation failed");
munmap(fbp, screensize);
close(fbfd);
fclose(fp);
return -1;
}
// Read and display image data
int y = 0;
for (y = infoHeader.biHeight - 1; y >= 0; y--) {
if (fread(line, infoHeader.biWidth * bytes_per_pixel + padding, 1, fp) != 1) {
printf("Failed to read image data\n");
free(line);
munmap(fbp, screensize);
close(fbfd);
fclose(fp);
return -1;
}
int x = 0;
for (x = 0; x < infoHeader.biWidth; x++) {
unsigned short pixel;
int location = x + y * vinfo.xres;
if (infoHeader.biBitCount == 24) {
// 24-bit BMP (BGR format)
unsigned char b = line[x * 3];
unsigned char g = line[x * 3 + 1];
unsigned char r = line[x * 3 + 2];
pixel = rgb24_to_rgb565(r, g, b);
} else {
// 16-bit BMP (already in RGB565 format)
pixel = *(unsigned short*)&line[x * 2];
}
// Check if within display bounds
if (x < vinfo.xres && y < vinfo.yres) {
fb16[location] = pixel;
}
}
}
// To display
write(fbfd, "1", 1);
usleep(1000*100);
// Cleanup resources
free(line);
fclose(fp);
munmap(fbp, screensize);
close(fbfd);
printf("Image display completed\n");
return 0;
}