【发布时间】:2016-07-16 22:13:01
【问题描述】:
我正在做一个屏幕共享项目,我经常从Socket 收到一小块图像,需要在我拥有的某个初始桌面位图上更新它们。
基本上我不断从套接字读取数据(数据存储为 jpeg 图像),使用 Image.FromStream() 检索图像并将接收到的块像素复制到完整的主位图(在特定位置 X 和 @987654332 @ 我也从套接字获得)- 这就是初始图像的更新方式。但接下来是我需要在Picturebox 上显示它的部分
我处理Paint 事件并重新绘制它——整个初始图像非常大(在我的例子中是1920X1080)。
这是我的代码:
private void MainScreenThread()
{
ReadData();//reading data from socket.
initial = bufferToJpeg();//first intial full screen image.
pictureBox1.Paint += pictureBox1_Paint;//activating the paint event.
while (true)
{
int pos = ReadData();
x = BlockX();//where to draw :X
y = BlockY();//where to draw :Y
Bitmap block = bufferToJpeg();//constantly reciving blocks.
Draw(block, new Point(x, y));//applying the changes-drawing the block on the big initial image.using native memcpy.
this.Invoke(new Action(() =>
{
pictureBox1.Refresh();//updaing the picturebox for seeing results.
// this.Text = ((pos / 1000).ToString() + "KB");
}));
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
lock (initial)
{
e.Graphics.DrawImage(initial, pictureBox1.ClientRectangle); //draws at picturebox's bounds
}
}
因为我的目标是高速性能(它是一种实时项目),我想知道是否没有任何方法可以在图片框上绘制当前收到的块本身而不是绘制整个initial 又是位图——这对我来说似乎效率很低......
这是我的绘图方法(工作得非常快,用memcpy复制块):
private unsafe void Draw(Bitmap bmp2, Point point)
{
lock (initial)
{
BitmapData bmData = initial.LockBits(new Rectangle(0, 0, initial.Width, initial.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, initial.PixelFormat);
BitmapData bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat);
IntPtr scan0 = bmData.Scan0;
IntPtr scan02 = bmData2.Scan0;
int stride = bmData.Stride;
int stride2 = bmData2.Stride;
int Width = bmp2.Width;
int Height = bmp2.Height;
int X = point.X;
int Y = point.Y;
scan0 = IntPtr.Add(scan0, stride * Y + X * 3);//setting the pointer to the requested line
for (int y = 0; y < Height; y++)
{
memcpy(scan0, scan02 ,(UIntPtr)(Width * 3));//copy one line
scan02 = IntPtr.Add(scan02, stride2);//advance pointers
scan0 = IntPtr.Add(scan0, stride);//advance pointers//
}
initial.UnlockBits(bmData);
bmp2.UnlockBits(bmData2);
}
}
这里有一些完整的主要位图示例,以及我得到的其他小块,需要在完整的位图上绘制。
小方块:
我每秒会得到大量的小块(30~40),有时它们的边界非常小(例如 100X80 像素的矩形),因此不需要再次重绘整个位图...快速刷新全屏图像会破坏性能...
我希望我的解释很清楚。
期待答案。
谢谢。
【问题讨论】:
-
我认为您可以使用
Control.CreateGraphics从图片框中获取图形,然后使用Graphics.DrawImage(image, x, y)在其上绘制,这样您就可以避免重绘初始图像。但我不知道它的效率如何,无论如何它可能会在引擎盖下运行它。可能值得做一些性能测试。 -
将图像的像素格式更改为 32bppPArgb,它的渲染速度比其他所有的快 10 倍。确保图像永远不必重新缩放以适合图片框,ClientRectangle 根本没有帮助。永远不要使用 Refresh,使用 Invalidate(Rectangle) 代替矩形是实际必须重绘的图像部分。
-
@Hans Passant 我得到的图像是 jpeg。 ..(24bpprgb)..我必须显示缩放的图像..这是为了屏幕共享目的..所以如果某人的分辨率为 1920X1080,并且他将屏幕共享给分辨率为 1600X880 的人,客户端将无法看到整个屏幕......如果图像更大,那么他的计算机分辨率将无法看到整个图像;)所以我认为必须在这里进行拉伸。为了正确显示屏幕。
-
@Hans Passant 关于您的其余答案,我明天会尝试回复。是时候睡觉了:)
-
@Slashy 你需要清除画布还是只需要在上面绘制?
标签: c# performance bitmap