显示任意大小的bmp图片在lcd屏幕上
本文最后更新于 165 天前,其中的信息可能已经有所发展或是发生改变。

/**
 * @filename:    showbmp.c
 * @brief:       showbmp
 * @author:      philia
 * @date:        2026/3/15
 * @version:     ver1.0
 * @note         none
 * CopyRight (c) 2026   philia  All Right Reseverd
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>

// ...(保持你的结构体定义不变)...
#pragma pack(push, 1) // 禁用内存对齐

typedef struct

{
    uint16_t bfType;      // 文件标识,必须为 "BM"(0x4D42)
    uint32_t bfSize;      // 文件总大小(字节)
    uint16_t bfReserved1; // 保留字段(必须为0)
    uint16_t bfReserved2; // 保留字段(必须为0)
    uint32_t bfOffBits;   // 像素数据偏移量(从文件头到像素数据的字节数)
} BITMAPFILEHEADER;

#pragma pack(pop)

typedef struct

{

    uint32_t biSize;         // 本结构体大小(通常为40)
    int32_t biWidth;         // 图像宽度(像素)
    int32_t biHeight;        // 图像高度(像素),正数表示从下到上存储
    uint16_t biPlanes;       // 颜色平面数(必须为1)
    uint16_t biBitCount;     // 每像素位数(1/4/8/16/24/32)
    uint32_t biCompression;  // 压缩方式(0表示不压缩)
    uint32_t biSizeImage;    // 像素数据大小(字节),压缩时需填写
    int32_t biXPelsPerMeter; // 水平分辨率(像素/米)
    int32_t biYPelsPerMeter; // 垂直分辨率(像素/米)
    uint32_t biClrUsed;      // 实际使用的调色板颜色数(0表示全部)
    uint32_t biClrImportant; // 重要颜色数(0表示所有颜色均重要)

} BITMAPINFOHEADER;

int main(int argc, const char *argv[])
{
    // 【修复1】:必须校验传入的参数个数!
    if (argc != 4) {
        printf("用法错误!正确格式: %s <bmp文件> <起始X> <起始Y>\n", argv[0]);
        return -1;
    }

    // 打开bmp文件
    FILE *bmp = fopen(argv[1], "rb");
    if (bmp == NULL) {
        printf("bmp文件打开失败\n");
        return -1;
    }

    // 读取bmp文件信息
    BITMAPFILEHEADER fileheader;
    BITMAPINFOHEADER infoheader;
    fread(&fileheader, 14, 1, bmp);
    fread(&infoheader, 40, 1, bmp);

    int bmp_width = infoheader.biWidth;
    int bmp_height = infoheader.biHeight;

    // 处理高度为负数的情况(有些BMP是从上倒下存的)
    if (bmp_height < 0) bmp_height = -bmp_height; 

    // 获取输入的起始坐标
    int x_start = atoi(argv[2]);
    int y_start = atoi(argv[3]);

    // 【修复3】:计算带补齐的行字节数,并用此大小分配内存
    int valid_bytes_per_row = bmp_width * 3;
    int total_bytes_per_row = ((valid_bytes_per_row + 3) / 4) * 4;
    int padding_bytes = total_bytes_per_row - valid_bytes_per_row;

    // 图片数据的总大小(包含废字节)
    int img_data_size = total_bytes_per_row * bmp_height;

    // 使用 malloc 在堆区分配大内存,防止栈溢出段错误
    unsigned char *bmp_buf = (unsigned char *)malloc(img_data_size);
    if (bmp_buf == NULL) {
        printf("内存分配失败\n");
        fclose(bmp);
        return -1;
    }

    // 将文件指针移动到真正的像素数据开始处(跳过中间可能的调色板等杂注)
    fseek(bmp, fileheader.bfOffBits, SEEK_SET);
    // 一次性读取包含废字节在内的所有数据
    fread(bmp_buf, img_data_size, 1, bmp);

    // 打开lcd屏幕
    int fd = open("/dev/ubuntu_lcd", O_RDWR);
    if (fd == -1) {
        printf("lcd屏幕打开失败!\n");
        free(bmp_buf);
        fclose(bmp);
        return -1;
    }

    // 申请内存空间内存映射
    int *lcd_buf = (int *)mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (lcd_buf == MAP_FAILED) {
        perror("mmap");
        free(bmp_buf);
        fclose(bmp);
        close(fd);
        return -1;
    }
    // 0xFF 也就是按字节全部填满 1,拼成 32 位就是 0xFFFFFFFF (纯白)
    memset(lcd_buf, 0xFFFF0000, 800 * 480 * 4);

    // 【修复2】:只保留一个统一的写入循环
    int i = 0; 
    int data = 0;

    // 开始映射:Y轴倒序,从图片的最后一行画到第一行
    for (int y = y_start + bmp_height - 1; y >= y_start; y--)
    {
        for (int x = x_start; x < x_start + bmp_width; x++)
        {
            // 保护伞:只有在屏幕坐标范围内的像素才允许写入显存
            if (x >= 0 && x < 800 && y >= 0 && y < 480)
            {
                data |= bmp_buf[i];           // B
                data |= bmp_buf[i + 1] << 8;  // G
                data |= bmp_buf[i + 2] << 16; // R
                lcd_buf[800 * y + x] = data;
            }

            i += 3;   // 处理完一个像素
            data = 0; 
        }

        // 一行有效数据读完了,跳过文件里的废字节对齐
        i += padding_bytes;
    }

    // 收尾工作:释放所有资源
    free(bmp_buf);
    fclose(bmp);
    close(fd);
    munmap(lcd_buf, 800 * 480 * 4);

    printf("图片显示成功!\n");
    return 0;
}

评论

  1. 6497
    Android Chrome 144.0.0.0
    5 月前
    2026-4-05 20:42:55

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇