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

如何在XCB中绘制不同颜色的点(Rust xcb crate实现)

问题解答

一、简化x::Point切片的获取方式

你的代码可以通过两种方式简化:

方式1:利用Vec自动解引用

Vec<T>可自动解引用为[T],无需显式调用as_slice(),直接传递&Vec<_>即可:

fn set_pixels(&mut self, pixels: Vec<(usize, usize, u32)>) {
    self.connection.send_request(
        &x::PolyPoint {
            coordinate_mode: x::CoordMode::Origin,
            drawable: x::Drawable::Window(self.handle.unwrap()),
            gc: self.gc.unwrap(),
            points: &pixels.into_iter()
                .map(|(x, y, _)| x::Point { x: x as i16, y: y as i16 })
                .collect::<Vec<_>>(),
        }
    );
}

方式2:临时变量提升可读性

若链式调用不够清晰,可先将转换后的点存入临时变量,再传递引用:

fn set_pixels(&mut self, pixels: Vec<(usize, usize, u32)>) {
    let points: Vec<x::Point> = pixels.into_iter()
        .map(|(x, y, _)| x::Point { x: x as i16, y: y as i16 })
        .collect();
    
    self.connection.send_request(
        &x::PolyPoint {
            coordinate_mode: x::CoordMode::Origin,
            drawable: x::Drawable::Window(self.handle.unwrap()),
            gc: self.gc.unwrap(),
            points: &points,
        }
    );
}

二、高效绘制不同颜色的点(避免逐点调用ChangeGc)

PolyPoint依赖GC前景色绘制所有点,无法为单个点指定颜色。要高效实现多颜色点绘制,推荐以下两种方案:

方案1:用PutImage批量写入像素

这是X11中批量像素操作的最优方式,仅需几次系统调用即可完成所有点的绘制:

操作步骤

  1. 创建临时Pixmap作为像素缓冲区;
  2. 将所有带颜色的点转换为RGBA格式的像素数组;
  3. 通过PutImage将像素数组一次性写入Pixmap;
  4. 用CopyArea将Pixmap内容复制到目标窗口;
  5. 销毁临时Pixmap释放资源。

示例代码

use xcb::x;

fn set_colored_pixels(&mut self, pixels: Vec<(usize, usize, u32)>, width: u16, height: u16) {
    let conn = &self.connection;
    let window = self.handle.unwrap();
    let root_window = conn.get_setup().roots().next().unwrap().root();
    
    // 获取默认视觉格式,创建临时Pixmap(尺寸与窗口一致)
    let visual = conn.get_setup().roots().next().unwrap().root_visual();
    let pixmap = conn.generate_id();
    conn.send_request(&x::CreatePixmap {
        depth: 24, // 根据窗口实际深度调整,通常为24或32
        pixmap,
        drawable: x::Drawable::Window(root_window),
        width,
        height,
    });

    // 初始化RGBA像素缓冲区,默认填充黑色,再覆盖目标点颜色
    let mut buffer = vec![0u8; (width as usize) * (height as usize) * 4];
    for (x, y, color) in pixels {
        let index = (y as usize) * width as usize * 4 + (x as usize) * 4;
        // 将0xRRGGBB格式的颜色转换为RGBA字节
        buffer[index] = ((color >> 16) & 0xFF) as u8;
        buffer[index + 1] = ((color >> 8) & 0xFF) as u8;
        buffer[index + 2] = (color & 0xFF) as u8;
        buffer[index + 3] = 0xFF; // 不透明通道
    }

    // 将像素缓冲区写入Pixmap
    conn.send_request(&x::PutImage {
        format: x::ImageFormat::ZPixmap,
        drawable: x::Drawable::Pixmap(pixmap),
        gc: self.gc.unwrap(),
        width,
        height,
        dst_x: 0,
        dst_y: 0,
        left_pad: 0,
        depth: 24,
        data: &buffer,
    });

    // 复制Pixmap内容到目标窗口
    conn.send_request(&x::CopyArea {
        src_drawable: x::Drawable::Pixmap(pixmap),
        dst_drawable: x::Drawable::Window(window),
        gc: self.gc.unwrap(),
        src_x: 0,
        src_y: 0,
        dst_x: 0,
        dst_y: 0,
        width,
        height,
    });

    // 销毁临时Pixmap并刷新请求
    conn.send_request(&x::FreePixmap { pixmap });
    conn.flush();
}

方案2:按颜色分组绘制

若不想使用PutImage,可将相同颜色的点分组,每组仅调用一次ChangeGc再批量绘制,大幅减少系统调用次数:

use std::collections::HashMap;
use xcb::x;

fn set_colored_pixels_by_group(&mut self, pixels: Vec<(usize, usize, u32)>) {
    let conn = &self.connection;
    let window = self.handle.unwrap();
    let gc = self.gc.unwrap();

    // 按颜色分组存储点
    let mut color_groups: HashMap<u32, Vec<x::Point>> = HashMap::new();
    for (x, y, color) in pixels {
        color_groups.entry(color)
            .or_default()
            .push(x::Point { x: x as i16, y: y as i16 });
    }

    // 遍历每组,设置颜色后批量绘制同色点
    for (color, points) in color_groups {
        conn.send_request(&x::ChangeGc {
            gc,
            value_list: &[x::Gc::Foreground(color)],
        });
        conn.send_request(&x::PolyPoint {
            coordinate_mode: x::CoordMode::Origin,
            drawable: x::Drawable::Window(window),
            gc,
            points: &points,
        });
    }
    conn.flush();
}

该方案效率远高于逐点绘制,颜色种类越少,性能提升越明显。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:35:18