You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用XLib将Windows格式Bitmap文件读取为Pixmap对象

实现方案总览

整个操作分为BMP文件解析、像素格式适配、XLib Pixmap创建三个核心阶段,不需要引入额外重型依赖,以下是具体实现步骤和示例代码:


1 前置依赖说明
  • 仅依赖X11核心库即可实现,编译时添加-lX11参数链接X11库
  • 以下示例为原生实现BMP解析,也可以使用libbmp等轻量库简化解析逻辑

2 具体实现步骤

2.1 解析BMP文件头与像素数据

Windows BMP的核心结构包含两个固定头:

  • BITMAPFILEHEADER:14字节,包含文件标识(固定为0x4D42,对应字符串"BM")、文件总大小、像素数据的偏移地址
  • BITMAPINFOHEADER:常用版本为40字节,包含位图宽高、位深、压缩方式、像素数据总大小等信息

注意:BMP像素存储为行倒序,文件里的第一行像素对应位图最底部的内容;每行像素数据按4字节对齐,不足的位置用0填充。24位BMP像素顺序为BGR无Alpha通道,32位BMP像素顺序为BGRA。

2.2 适配X11像素格式

X11 Pixmap的像素格式和当前显示设备的Visual强绑定,默认24位真彩模式下像素顺序为RGB,32位带Alpha模式下为ARGB,需要对BMP读取到的像素做顺序转换:

  • 24位BMP:交换每个像素的B和R分量位置
  • 32位BMP:交换每个像素的B和R分量位置,同时调整Alpha通道位置适配当前Visual的要求

2.3 创建Pixmap并写入像素数据

调用XLib的XCreatePixmap接口创建对应尺寸的Pixmap对象,再通过XPutImage把转换完成的像素数据写入Pixmap即可。


3 完整代码示例
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

// BMP头结构定义,禁用结构体对齐
typedef struct {
    uint16_t type;
    uint32_t size;
    uint16_t reserved1;
    uint16_t reserved2;
    uint32_t off_bits;
} __attribute__((packed)) BitMapFileHeader;

typedef struct {
    uint32_t size;
    int32_t  width;
    int32_t  height;
    uint16_t planes;
    uint16_t bit_count;
    uint32_t compression;
    uint32_t size_image;
    int32_t  x_pels_per_meter;
    int32_t  y_pels_per_meter;
    uint32_t clr_used;
    uint32_t clr_important;
} __attribute__((packed)) BitMapInfoHeader;

/**
 * @param dpy X11 Display连接句柄
 * @param root 根窗口句柄
 * @param bmp_path BMP文件路径
 * @return 转换完成的Pixmap对象,创建失败返回0
 */
Pixmap bmp_to_pixmap(Display *dpy, Window root, const char *bmp_path) {
    FILE *fp = fopen(bmp_path, "rb");
    if (!fp) return 0;

    BitMapFileHeader file_hdr;
    BitMapInfoHeader info_hdr;
    // 读取BMP文件头
    fread(&file_hdr, sizeof(BitMapFileHeader), 1, fp);
    if (file_hdr.type != 0x4D42) {
        fclose(fp);
        return 0;
    }
    // 读取BMP信息头
    fread(&info_hdr, sizeof(BitMapInfoHeader), 1, fp);
    // 示例仅支持无压缩的24/32位BMP
    if ((info_hdr.bit_count != 24 && info_hdr.bit_count != 32) || info_hdr.compression != 0) {
        fclose(fp);
        return 0;
    }

    int width = info_hdr.width;
    int height = abs(info_hdr.height);
    // 计算BMP行步长(4字节对齐)
    int stride = (width * info_hdr.bit_count / 8 + 3) & ~3;
    uint8_t *bmp_data = malloc(stride * height);
    fseek(fp, file_hdr.off_bits, SEEK_SET);
    fread(bmp_data, stride * height, 1, fp);
    fclose(fp);

    // 获取X11默认24位真彩视觉信息
    XVisualInfo vinfo;
    XMatchVisualInfo(dpy, DefaultScreen(dpy), 24, TrueColor, &vinfo);
    XImage *img = XCreateImage(dpy, vinfo.visual, 24, ZPixmap, 0, 
                               malloc(width * height * 4), width, height, 32, 0);

    // 转换像素格式,处理BMP行倒序
    for (int y = 0; y < height; y++) {
        int bmp_y = info_hdr.height > 0 ? (height - 1 - y) : y;
        uint8_t *bmp_row = bmp_data + bmp_y * stride;
        for (int x = 0; x < width; x++) {
            uint8_t b = bmp_row[x * info_hdr.bit_count/8 + 0];
            uint8_t g = bmp_row[x * info_hdr.bit_count/8 + 1];
            uint8_t r = bmp_row[x * info_hdr.bit_count/8 + 2];
            uint32_t pixel = (r << 16) | (g << 8) | b;
            XPutPixel(img, x, y, pixel);
        }
    }

    // 创建Pixmap并写入像素数据
    Pixmap pix = XCreatePixmap(dpy, root, width, height, 24);
    GC gc = XCreateGC(dpy, pix, 0, NULL);
    XPutImage(dpy, pix, gc, img, 0, 0, 0, 0, width, height);

    // 释放临时资源
    XFreeGC(dpy, gc);
    XDestroyImage(img);
    free(bmp_data);

    return pix;
}

// 编译命令:gcc 源文件名.c -o 输出文件名 -lX11

4 注意事项
  • 上述代码默认适配24位真彩X11显示,如需支持32位带Alpha通道的Pixmap,调整XMatchVisualInfo的位深参数和像素转换逻辑即可
  • 示例仅支持无压缩BMP,如需支持RLE压缩的BMP需要额外实现压缩解码逻辑
  • Pixmap使用完成后需要调用XFreePixmap释放X服务器端的资源

内容的提问来源于stack exchange,提问作者Stewart Tunbridge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 08:57:01