远程帧缓冲协议,即RFB(Remote Frame Buffer)协议是 VNC(Virtual Network Computing)软件所使用的通信协议,用于客户端向服务器传送控制命令以及服务器向客户端发送其操做画面,借此,远程桌面共享软件(不涉及Windows自带的桌面共享)得以实现。数组
本文仅对bill在开发过程当中遇到的鼠标形状解析问题做简要记录。
服务器
RFB协议规定,鼠标形状在伪编码范畴,协议原文以下:ide
A client which requests the Cursor pseudo-encoding is declaring that it is capable ofui
drawing a mouse cursor locally. This can signicantly improve perceived performance编码
over slow links. The server sets the cursor shape by sending a pseudo-rectangle withspa
the Cursor pseudo-encoding as part of an update. The pseudo-rectangle’s x-position指针
and y-position indicate the hotspot of the cursor, and width and height indicate thecode
width and height of the cursor in pixels. The data consists of width × height pixelorm
values followed by a bitmask. The bitmask consists of left-to-right, top-to-bottomserver
scanlines, where each scanline is padded to a whole number of bytes floor((width +
7)/8). Within each byte the most signicant bit represents the leftmost pixel, with a
1-bit meaning the corresponding pixel in the cursor is valid.
协议规定鼠标指针伪编码格式为两个连续的数组,第一个数组用来保存指针形状的像素点,第二个数组则保存了一个位掩码,用来反映上述像素点的有效性。
刚开始看这段描述,实在是没理解这个位掩码的功能,便直接忽略位掩码,获得了下图所示的指针原始RGB数据:
乍看上去好像已经达到目的了,直到在客户端进行绘制才发现问题 —— 咱们肉眼可以分辨出图中的指针,但是如何利用程序获得一个干净(没有黑色背景)的指针呢?貌似咱们能够将该数组中全部黑色像素设为透明值来获得指针,但另外一个问题又来了 —— 全部黑色像素透明后,白色指针便没有了边框,一旦VNC客户端显示背景为白色,鼠标就“消失”了。
所以忽略位掩码的尝试是失败的。不得再也不次认真理解 bitmask 的意义,才发现位掩码的真正用途:
bitmask中每个 bit 对应指针像素数组中的一个像素点(一般为 4bytes),以从左到右、自上而下的顺序反映对应像素点的有效性,若某 bit 为 1,则表示它对应的是有效的鼠标指针像素点,应予以保留。不然即可以将该像素点设为透明值。
bitmask_len 位掩码数组长度 bitmask 位掩码数组 cursor 鼠标指针像素数组 bytes_per_pixel 每一个像素点字节数,一般为4 int cursor_pixel_idx = 0; for (int i = 0; i < bitmask_len; ++i) { uint8_t mask = bitmask[i]; for (int j = 0; j < 8; ++j) { bool is_pixel_valid = mask & 128; mask <<= 1; if (!is_pixel_valid) { for (int k = 0; k != bytes_per_pixel; ++k) { cursor[cursor_pixel_idx + k] = 0xFF; } } cursor_pixel_idx += bytes_per_pixel; } } // for
这样一来,即可以使程序“分辨“出上述图像中哪些像素才是真正的指针,而哪些像素是能够设为透明值加以忽略的。根据位掩码最终获得了以下的鼠标指针:
如今即可放心的将指针绘制到客户端任何区域,而不用担忧指针在白色区域没法识别的问题了。