我正在进行一个屏幕共享项目,我不断地从Socket
收到一小块图像,需要在我拥有的某个初始dekstop位图上更新它们。
基本上我经常从套接字读取数据(存储为jpeg图像的数据),使用Image.FromStream()
检索图像并将接收的块像素复制到完整的主位图(在特定位置{{1}我也从套接字获得的X
- 这是初始图像如何更新的原因。但接下来是我需要在Y
上显示它的部分
我处理Picturebox
事件并重新绘制它 - 整个初始图像,这是非常大的(在我的情况下是1920X1080)。
这是我的代码:
Paint
因为我的目标是高速性能(它是一种实时项目),我想知道是否有任何方法来绘制当前收到的块本身在图片框上而不是再次绘制整个 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
以下是完整主要位图的一些示例,以及我需要绘制的完整主要位图的其他小块。
小块:
我每秒获得大量的小块(30~40),其边界非常小(例如100X80像素的矩形),因此不需要重新绘制整个位图...快速刷新a全屏图像会破坏性能...
我希望我的解释清楚。
期待回答。
感谢。
答案 0 :(得分:1)
如果没有答案就离开这个问题会很遗憾。在更新图片框的一小部分时,我的测试速度大约快10倍。它的作用基本上是智能无效(仅考虑缩放的位图的更新部分无效)和智能绘画(仅绘制图片框的无效部分,采取来自e.ClipRectangle
并考虑缩放比例:
private Rectangle GetViewRect() { return pictureBox1.ClientRectangle; }
private void MainScreenThread()
{
ReadData();//reading data from socket.
initial = bufferToJpeg();//first intial full screen image.
pictureBox1.Paint += pictureBox1_Paint;//activating the paint event.
// The update action
Action<Rectangle> updateAction = imageRect =>
{
var viewRect = GetViewRect();
var scaleX = (float)viewRect.Width / initial.Width;
var scaleY = (float)viewRect.Height / initial.Height;
// Make sure the target rectangle includes the new block
var targetRect = Rectangle.FromLTRB(
(int)Math.Truncate(imageRect.X * scaleX),
(int)Math.Truncate(imageRect.Y * scaleY),
(int)Math.Ceiling(imageRect.Right * scaleX),
(int)Math.Ceiling(imageRect.Bottom * scaleY));
pictureBox1.Invalidate(targetRect);
pictureBox1.Update();
};
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.
// Invoke the update action, passing the updated block rectangle
this.Invoke(updateAction, new Rectangle(x, y, block.Width, block.Height));
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
lock (initial)
{
var viewRect = GetViewRect();
var scaleX = (float)initial.Width / viewRect.Width;
var scaleY = (float)initial.Height / viewRect.Height;
var targetRect = e.ClipRectangle;
var imageRect = new RectangleF(targetRect.X * scaleX, targetRect.Y * scaleY, targetRect.Width * scaleX, targetRect.Height * scaleY);
e.Graphics.DrawImage(initial, targetRect, imageRect, GraphicsUnit.Pixel);
}
}
唯一棘手的部分是确定缩放的矩形,特别是用于无效的矩形,因为需要浮点到int转换,所以我们确保它最终比需要的大一点,但不能少。
答案 1 :(得分:0)
如果您只需要在画布上绘图,则只需绘制一次初始图像,然后使用CreateGraphics()
和DrawImage
更新内容:< / p>
ReadData();
initial = bufferToJpeg();
pictureBox1.Image = initial;
var graphics = pictureBox1.CreateGraphics();
while (true)
{
int pos = ReadData();
Bitmap block = bufferToJpeg();
graphics.DrawImage(block, BlockX(), BlockY());
}
我会通过性能比较更新答案,因为我不相信这会带来任何重大好处;它至少会避免双重 DrawImage 。
答案 2 :(得分:0)