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

如何使用xcb在纯C语言中实现截图?

嘿,我之前也为了追求截图速度放弃过Cairo,转而用XCB实现,完全懂你找不到示例的痛苦!下面直接上纯C的实现方案,从核心逻辑到完整代码都给你理清楚:

纯XCB截图的核心逻辑

XCB的截图本质是借助X服务器的像素复制能力,流程非常直接:

  1. 建立与X服务器的连接
  2. 获取目标屏幕的根窗口和尺寸信息
  3. 创建一个Pixmap(X服务器端的像素缓冲区)
  4. 将根窗口的像素数据复制到Pixmap中
  5. 从Pixmap读取原始像素数据到客户端内存
  6. 清理资源

这个流程全程是X服务器端操作+直接内存读取,比Cairo的客户端渲染快不少,完全能满足高性能需求。

完整代码示例

下面是可直接运行的纯C代码,包含基础错误处理和可选的PNG保存逻辑:

#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
// 如果需要保存PNG,取消下面的注释并链接libpng
// #include <png.h>

int main() {
    // 1. 连接到X服务器
    xcb_connection_t *conn = xcb_connect(NULL, NULL);
    if (xcb_connection_has_error(conn)) {
        fprintf(stderr, "无法连接到X服务器\n");
        return 1;
    }

    // 2. 获取默认屏幕、根窗口和屏幕尺寸
    const xcb_setup_t *setup = xcb_get_setup(conn);
    xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(setup);
    xcb_screen_t *screen = screen_iter.data;
    xcb_window_t root_window = screen->root;
    uint16_t screen_width = screen->width_in_pixels;
    uint16_t screen_height = screen->height_in_pixels;

    // 3. 创建用于存储截图的Pixmap
    xcb_pixmap_t screenshot_pixmap = xcb_create_pixmap(
        conn,
        screen->root_depth,
        root_window,
        screen_width,
        screen_height
    );

    // 4. 将根窗口的像素复制到Pixmap(X服务器端操作,速度极快)
    xcb_copy_area(
        conn,
        root_window,          // 源窗口
        screenshot_pixmap,    // 目标Pixmap
        screen->root_visual,  // 视觉格式
        0, 0,                 // 源窗口起始坐标
        0, 0,                 // 目标Pixmap起始坐标
        screen_width, screen_height  // 复制区域尺寸
    );
    // 强制发送请求并等待X服务器处理完成
    xcb_flush(conn);

    // 5. 从Pixmap读取像素数据到客户端内存(ZPixmap格式,像素连续存储)
    xcb_get_image_cookie_t image_cookie = xcb_get_image(
        conn,
        XCB_IMAGE_FORMAT_Z_PIXMAP,
        screenshot_pixmap,
        0, 0,
        screen_width, screen_height,
        ~0  // 获取所有颜色位
    );

    xcb_get_image_reply_t *image_reply = xcb_get_image_reply(conn, image_cookie, NULL);
    if (!image_reply) {
        fprintf(stderr, "获取图像数据失败\n");
        xcb_free_pixmap(conn, screenshot_pixmap);
        xcb_disconnect(conn);
        return 1;
    }

    // 原始像素数据指针(紧跟在image_reply结构体之后)
    uint8_t *pixel_data = xcb_get_image_data(image_reply);
    int bytes_per_pixel = image_reply->depth / 8;
    printf("截图成功:%dx%d,每个像素占用%d字节\n", screen_width, screen_height, bytes_per_pixel);

    // --- 可选:将像素数据保存为PNG ---
    // 注意:XCB的ZPixmap默认是BGR/BGRA顺序,需要转换为RGB/RGBA才能正确显示
    /*
    FILE *png_file = fopen("screenshot.png", "wb");
    if (png_file) {
        png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
        png_infop info_ptr = png_create_info_struct(png_ptr);
        png_init_io(png_ptr, png_file);

        // 设置PNG图像信息
        png_set_IHDR(png_ptr, info_ptr, screen_width, screen_height, 8,
                     bytes_per_pixel == 4 ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
                     PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
        png_write_info(png_ptr, info_ptr);

        // 逐行转换并写入PNG
        for (int y = 0; y < screen_height; y++) {
            uint8_t *row = pixel_data + y * image_reply->stride;
            // 转换BGR到RGB,BGRA到RGBA
            for (int x = 0; x < screen_width; x++) {
                uint8_t temp = row[x * bytes_per_pixel];
                row[x * bytes_per_pixel] = row[x * bytes_per_pixel + 2];
                row[x * bytes_per_pixel + 2] = temp;
            }
            png_write_row(png_ptr, row);
        }

        // 完成PNG写入并清理
        png_write_end(png_ptr, NULL);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        fclose(png_file);
        printf("截图已保存为screenshot.png\n");
    }
    */

    // 6. 清理所有资源
    free(image_reply);
    xcb_free_pixmap(conn, screenshot_pixmap);
    xcb_disconnect(conn);

    return 0;
}
编译与运行
  • 如果不需要保存PNG,编译命令:
    gcc xcb_screenshot.c -o xcb_screenshot -lxcb
    
  • 如果需要保存PNG,先确保安装了libpng开发库,然后编译:
    gcc xcb_screenshot.c -o xcb_screenshot -lxcb -lpng
    

运行后会在控制台输出截图信息,若启用PNG保存则会生成screenshot.png。

关键注意点
  1. 像素格式转换:XCB的ZPixmap默认采用BGR/BGRA顺序(与大多数图像库的RGB/RGBA相反),如果需要和其他工具兼容,必须手动转换颜色通道,代码中已经给出示例。
  2. 性能优化:如果只需要截取屏幕的一部分,只需修改xcb_copy_area和xcb_get_image中的坐标与尺寸参数,不用截取整个屏幕,能进一步提升速度。
  3. 多屏幕支持:如果是多显示器环境,需要通过Xinerama或RandR扩展获取每个屏幕的独立根窗口和尺寸,基础代码仅支持单屏幕,扩展逻辑可以基于现有代码修改。
  4. 错误处理:代码中加入了基础的错误检查,实际项目中可以用xcb_request_check来验证每个XCB请求的执行结果,避免潜在的崩溃。

内容的提问来源于stack exchange,提问作者Alessandro Sangiuliano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 16:32:54