VNC
功能
在本机显示和控制别一台计算机的桌面,就像直接用那台计算机一样VNC的编码方式主要有
a) Raw(0):不进行编码,直接传送数据,是最慢的一种
b) Copyrect(1):对于客户端,在已经有了相同象素数据的时候比较有效,比如移动或窗口内容滚动时
c) RRE(2):将象素颜色相同的某一个矩形区域作为一个整体传输
d) Hextile(5):是RRE编码的变种,把屏幕分成16x16象素的小块,每块用Raw或RRE方式转送
e) ZRLE(16):它结合了zlib压缩
二、Hextile原理
通过解释Hextile算法,说明了简单而常用的屏幕传送和压缩算法,希望对屏幕监测、传送相关的工作有所启发
- 分割
a) 传送的图像区域被分为若干个大小为16×16象素的块,如果整个矩形不是16的倍数,则最后1行(或列)的块宽度(或高度)变小
b) 这些块按从左到右,从上到下的顺序排列,屏幕中变化的块被传送,不变的不被传送
c) 由于块大小是16x16,所以块内坐标XY可用一字节表示,WH可用一个字节表示
- 标志位:
传送每块数据的之前,先要传送一个字节的标志位,标记出该块的传送的格式,它的每一位意义如下
a) 右一:Raw数据:不压缩,直接传送,一般此位置1时其它位都置0
b) 右二:包含背景色数据:标志位之后需要接收背景色数据
c) 右三:包含前景色数据:背景色之后需要接收前景色数据
d) 右四:是否含有子块:只要该块中含有两种及两种以上颜色,则此位置1
e) 右五:子块的颜色:如果含有两种颜色,此位置0,子块颜色用前景色;若该块中含有两种以上的颜色,此位置1,子块颜色需要单独指明
- 块内部的编码:
a) 计算块内部的颜色数:一种、两种、多种,并记录出现频率最多的颜色为背景色,如果仅有两种颜色,则另一颜色记为前景色
b) 判断块内颜色数是否为一种,如果是,则先修改传送标志位,然后传送整块大小(0,0,w,h)和背景色,此块传送即完成
c) 如果不是一种,则把块拆分成颜色不同的小矩形,方法如下:
i. 先把块复制到一块内存区中,以免破坏原始数据,暂称tmpBuf
ii. 从第一个象素开始判断,该点颜色是否与背景色相同
iii. 如果不同,则分别向右和向下求得与该点颜色连续的色块
iv. 对比右色块和下色块,取出其中较大的一个,做为一个矩形色块
v. 在tmpBuf中把此矩形填成背景色,以避免重复判断
vi. 继续判断下一象素点……
d) 记录各个矩形色块的位置(x,y,w,h),如果块内含两种以上颜色,还要记录矩形色块的颜色值
e) 一边取得矩形色块,一边判断矩形色块描述数据的总长是否大于原始数据,如果大于原始数据,则放弃取色块,标志字节Raw位(右一)置1,以Raw方式直接传送原始数据,此块传送完成
f) 如果块含两种以上颜色,则将标志位的子块位(右五)置1,否则置0
g) 传送标志位,传送矩形色块个数,然后传送各矩形块数据,块中颜色数为2时不需要传送每个矩形块的颜色数据,只传位置即可
h) 注意:如果背景色或前景色与前一块(16x16块)相同,则可以不传送背景色或前景色,客户端会默认延用前一块的
三、参考实例
- 源码:
a) 源码包:tightvnc-1.2.9.orig.tar.gz
b) 编码程序:tightvnc-1.2.9.orig/Xvnc/programs/Xserver/hw/vnc/hextile.c
c) 解码程序:rightvnc-1.2.9.orig/vncviewer/hextile.c
- 参考文档
a) VNC协议简单分析-beta+4.9.pdf (优快云可下载)
b) http://blogimg.chinaunix.net/blog/upfile/070613090634.pdf
ZRLE(Zlib Run—length Encoding)压缩算法:ZRLE算法是使用Zlib压缩方式和行程编码结合起来进行数据压缩的方法。
zlib是一个执行数据压缩的库(data compression library),是使用最广泛的一套开源的通用无损压缩代码集。它是LZ77 ((Lempel-Ziv 1977)的一个变种分支。它的代码是线程安全的,数据格式可以参见RFCs(Request for Comments) 1950 到1952(www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format))。
这套源码中支持了两种压缩方法,一种就是普通的deflate/inflate,一种是gzip格式。前者更精巧,后者则增加了对目录的支持及其它一些更丰富的功能。
ZLib的是用C编写的,在VC++、BC++或C++Builder中自然很容易直接使用,对于Delphi开发者,虽然Delphi自带了ZLib的移植版本(zlib.pas),但版本为1.0.4,而且必须要使用Borland自己编译生成的zlib.dcu(当然,在完整版的光盘中包含了编译好的zlib库的.obj文件和c代码,只是缺省安装下,不过安装这些文件)。
注:
(1)编码方式:Raw,CopyRect,RRE,CoRRE,Hextile和ZRLE。常用的只有ZRLE,Hextile以及CopyRect编码,因为它们为典型的桌面提供了最好的压缩方法。
(2)行程编码又称“运行长度编码”或“游程编码”,常用RLE(Run-Length Encoding)表示是一种统计编码,该编码属于无损压缩编码。对于二值图有效。
行程编码的基本原理是:用一个符号值或串长代替具有相同值的连续符号(连续符号构成了一段连续的“行程”。行程编码因此而得名),使符号长度少于原始数据的长度。
例如:222222777771112222
行程编码为:(2,6)(7,5)(1,3)(2,4)。可见,行程编码的位数远远少于原始字符串的位数。
在对图像数据进行编码时,沿一定方向排列的具有相同灰度值的像素可看成是连续符号,用字串代替这些连续符号,可大幅度减少数据量。
行程编码分为定长行程编码和不定长行程编码两种类型。
行程编码是连续精确的编码,在传输过程中,如果其中一位符号发生错误,即可影响整个编码序列,使行程编码无法还原回原始数据。