遠程幀緩衝協議,即RFB(Remote Frame Buffer)協議是 VNC(Virtual Network Computing)軟件所使用的通訊協議,用於客戶端向服務器傳送控制命令以及服務器向客戶端發送其操作畫面,藉此,遠程桌面共享軟件(不涉及Windows自帶的桌面共享)得以實現。
本文僅對bill在開發過程中遇到的鼠標形狀解析問題作簡要記錄。
RFB協議規定,鼠標形狀在僞編碼範疇,協議原文如下:
A client which requests the Cursor pseudo-encoding is declaring that it is capable of
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 with
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 the
width and height of the cursor in pixels. The data consists of width × height pixel
values followed by a bitmask. The bitmask consists of left-to-right, top-to-bottom
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
這樣一來,便可以使程序“分辨“出上述圖像中哪些像素纔是真正的指針,而哪些像素是可以設爲透明值加以忽略的。根據位掩碼最終得到了如下的鼠標指針:
現在便可放心的將指針繪製到客戶端任何區域,而不用擔心指針在白色區域無法識別的問題了。