gpt4 book ai didi

C#更新图片框中的位图

转载 作者:可可西里 更新时间:2023-11-01 08:29:25 24 4
gpt4 key购买 nike

我正在做一个屏幕共享项目,我不断从 Socket 接收一小块图像,需要在我拥有的某个初始 dekstop 位图上更新它们。

基本上我不断地从套接字中读取数据(存储为 jpeg 图像的数据),使用 Image.FromStream() 检索图像并将接收到的 block 像素复制到完整的主位图(在一个特定的位置 XY 我也从套接字中获得)- 这就是初始图像更新的方式。但是接下来是我需要在 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
}
}

因为我的目标是高速性能(这是一个实时项目),我想知道是否没有任何方法可以在图片框上绘制当前接收到的 block 本身而不是绘制整个initial bitmap again - 这对我来说似乎效率很低......这是我的绘图方法(速度极快,使用 memcpy 复制 block ):

     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);
}
}

这里有一些完整的主位图示例,以及我得到的其他小块,需要在完整的位图上绘制。

完整位图: full bitmap小块:

enter image description here小块:

enter image description here

小块:

enter image description here

我每秒得到大量的小块(30~40)有时它们的边界真的很小(例如 100X80 像素的矩形)所以没有必要再次重绘整个位图......快速刷新全屏图像会破坏性能...

我希望我的解释很清楚。

期待答案。

谢谢。

最佳答案

如果不回答这个问题,那将是一种耻辱。在更新图片框的一小部分时,以下内容在我的测试中快了大约 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);
}
}

唯一棘手的部分是确定缩放的矩形,尤其是用于无效的矩形,因为需要将 float 转换为 int,因此我们确保它最终比需要的大一点,但不少。

关于C#更新图片框中的位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38416132/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com