天天看點

【如何正确解析通過 RFB 協定發送的滑鼠形狀】

   本文僅對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.

<a href="http://s3.51cto.com/wyfs02/M01/22/E0/wKioL1MqaPORcO4TAACzYNERVrQ350.jpg" target="_blank"></a>

   協定規定滑鼠指針僞編碼格式為兩個連續的數組,第一個數組用來儲存指針形狀的像素點,第二個數組則儲存了一個位掩碼,用來反映上述像素點的有效性。

   剛開始看這段描述,實在是沒了解這個位掩碼的功能,便直接忽略位掩碼,得到了下圖所示的指針原始RGB資料:

   乍看上去好像已經達到目的了,直到在用戶端進行繪制才發現問題 —— 我們肉眼能夠分辨出圖中的指針,可是如何利用程式得到一個幹淨(沒有黑色背景)的指針呢?貌似我們可以将該數組中所有黑色像素設為透明值來得到指針,但另一個問題又來了 —— 所有黑色像素透明後,白色指針便沒有了邊框,一旦VNC用戶端顯示背景為白色,滑鼠就“消失”了。

   是以忽略位掩碼的嘗試是失敗的。不得不再次認真了解 bitmask 的意義,才發現位掩碼的真正用途:

   bitmask中每一個 bit 對應指針像素數組中的一個像素點(通常為 4bytes),以從左到右、自上而下的順序反映對應像素點的有效性,若某 bit 為 1,則表示它對應的是有效的滑鼠指針像素點,應予以保留。否則便可以将該像素點設為透明值。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<code>bitmask_len 位掩碼數組長度</code>

<code>bitmask 位掩碼數組</code>

<code>cursor 滑鼠指針像素數組</code>

<code>bytes_per_pixel 每個像素點位元組數,通常為4</code>

<code>int</code> <code>cursor_pixel_idx = 0;</code>

<code>for</code> <code>(</code><code>int</code> <code>i = 0; i &lt; bitmask_len; ++i) {</code>

<code>  </code><code>uint8_t mask = bitmask[i];</code>

<code>  </code><code>for</code> <code>(</code><code>int</code> <code>j = 0; j &lt; 8; ++j) {</code>

<code>    </code><code>bool</code> <code>is_pixel_valid = mask &amp; 128;</code>

<code>    </code><code>mask &lt;&lt;= 1;</code>

<code>      </code> 

<code>    </code><code>if</code> <code>(!is_pixel_valid) {</code>

<code>      </code><code>for</code> <code>(</code><code>int</code> <code>k = 0; k != bytes_per_pixel; ++k) {</code>

<code>        </code><code>cursor[cursor_pixel_idx + k] = 0xFF;</code>

<code>      </code><code>}</code>

<code>    </code><code>}</code>

<code>                   </code> 

<code>    </code><code>cursor_pixel_idx += bytes_per_pixel;</code>

<code>  </code><code>}</code>

<code>} </code><code>// for</code>

   這樣一來,便可以使程式“分辨“出上述圖像中哪些像素才是真正的指針,而哪些像素是可以設為透明值加以忽略的。根據位掩碼最終得到了如下的滑鼠指針:

   現在便可放心的将指針繪制到用戶端任何區域,而不用擔心指針在白色區域無法識别的問題了。

     本文轉自Bill_Hoo 51CTO部落格,原文連結:http://blog.51cto.com/billhoo/1380289,如需轉載請自行聯系原作者

繼續閱讀