不确定我尝试做的事情是否会成功,或者甚至是可能的。基本上我正在创建一个远程桌面类型的应用程序,它将屏幕捕获为jpeg图像并将其发送到客户端应用程序进行显示。
我希望通过将图像与旧图像进行比较并仅发送差异来减少每次发送的数据量。例如:
var bitmap = new Bitmap(1024, 720);
string oldBase = "";
using (var stream = new MemoryStream())
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size);
bitmap.Save(stream, ImageFormat.Jpeg);
string newBase = Convert.ToBase64String(stream.ToArray());
// ! Do compare/replace stuff here with newBase and oldBase !
// Store the old image as a base64 string.
oldBase = newBase;
}
使用这样的东西我可以比较两个base64字符串并替换任何匹配。匹配的文本可以替换为:
[替换的字符数]
这样,在客户端,我知道在哪里替换旧数据并添加新数据。再说一遍,我不确定这是否会起作用所以任何人对此的想法都会非常感激。 :)如果有可能,你能指出我正确的方向吗?感谢。
答案 0 :(得分:1)
我们目前正在研究一些非常相似的东西 - 基本上,你要实现的是视频编解码器(非常简单的运动jpeg)。有一些简单的方法,有些非常复杂。
答案 1 :(得分:1)
您可以通过直接比较位图位来实现。查看Bitmap.LockBits,它将为您提供BitmapData
指针,您可以从中获取像素数据。然后,您可以比较每条扫描线的像素,并将它们编码为您想要用于传输的任何格式。
请注意,扫描线的长度(以字节为单位)始终是4的倍数。因此,除非您使用32位颜色,否则必须考虑可能在末尾的填充。扫描线。这就是Stride
结构中BitmapData
属性的含义。
基于每个扫描线进行操作更容易,但可能不如将位图视为一个连续的数据块那样有效(在减少发送的数据量方面)。您的传输格式应如下所示:
<start marker>
// for each scan line
<scan line marker><scan line number>
<pixel position><number of pixels><pixel data>
<pixel position><number of pixels><pixel data>
...
// next scan line
<scan line marker><scan line number>
...
<end marker>
每个<pixel position><number of pixels><pixel data>
条目都是一组经过更改的像素。如果扫描线没有更改像素,您可以选择不发送它。或者您可以发送扫描线标记和数字,然后立即发送下一条扫描线。
对于<pixel position>
字段和<number of pixels>
字段,两个字节就足够了。因此,每个块的开销为4个字节。在最简单的版本工作之后,您可能感兴趣的优化是,如果存在小的运行,则组合已更改/未更改的像素块。例如,如果您有uucucuc
,其中u
是未更改的像素而c
是更改的像素,则您可能希望将cucuc
编码为一个运行五个改变像素。这将减少您必须传输的数据量。
请注意,这不是最佳方式,但它简单,有效且相对容易实现。
在任何情况下,一旦你编码了东西,你就可以通过内置的GZip
压缩器来运行数据(尽管这样做可能没什么用处),然后将它推到管道上客户端,它会解压缩并解释结果。
最简单的方法是在一台机器上构建它,使用两个窗口来验证结果。一旦它正常工作,您就可以连接网络传输部分。通过在中间进行传输步骤来调试初始切割可能会非常令人沮丧。
答案 2 :(得分:0)
这不适用于JPEG。您需要使用BMP或可能未压缩的TIFF。
我认为如果是我,我会使用BMP,扫描像素以进行更改并构建一个PNG,除了更改之外的所有内容都是透明的。
首先,这会降低您的传输大小,因为PNG压缩非常好,特别是对于重复像素。
其次,它可以很容易地在接收端进行显示,因为您可以简单地将新图像绘制在旧图像的上方。