如何在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中批量像素操作的最优方式,仅需几次系统调用即可完成所有点的绘制:
操作步骤
- 创建临时
Pixmap作为像素缓冲区; - 将所有带颜色的点转换为RGBA格式的像素数组;
- 通过
PutImage将像素数组一次性写入Pixmap; - 用
CopyArea将Pixmap内容复制到目标窗口; - 销毁临时
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
相关产品推荐
相关产品推荐

