遠程幀緩衝協議,即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
這樣一來,即可以使程序「分辨「出上述圖像中哪些像素纔是真正的指針,而哪些像素是能夠設爲透明值加以忽略的。根據位掩碼最終獲得了以下的鼠標指針:
如今即可放心的將指針繪製到客戶端任何區域,而不用擔憂指針在白色區域沒法識別的問題了。