[英]C# Update bitmap in picturebox
我正在進行一個屏幕共享項目,我不斷收到來自Socket
一小塊圖像,需要在我擁有的某個初始dekstop位圖上更新它們。
基本上我經常從套接字讀取數據(數據存儲為jpeg圖像),使用Image.FromStream()
檢索圖像並將接收到的塊像素復制到完整的主位圖(在特定位置X
和Y
,我也得到從套接字) - 這是初始圖像更新的方式。 但接下來是我需要在Picturebox
上顯示它的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像素的矩形),因此不需要重新繪制整個位圖...快速刷新全屏圖像會殺死表現......
我希望我的解釋清楚。
期待一個答案。
謝謝。
如果沒有一些答案就離開那個問題會很遺憾。 在更新圖片框的一小部分時,我的測試速度大約快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轉換,所以我們確保它最終比需要的大一點,但不能少。
如果您只需要在畫布上繪制,只需繪制一次初始圖像,然后使用CreateGraphics()
和DrawImage
更新內容:
ReadData();
initial = bufferToJpeg();
pictureBox1.Image = initial;
var graphics = pictureBox1.CreateGraphics();
while (true)
{
int pos = ReadData();
Bitmap block = bufferToJpeg();
graphics.DrawImage(block, BlockX(), BlockY());
}
我將通過性能比較更新答案,因為我不相信這會帶來任何重大好處; 它至少會避免雙重DrawImage 。
請仔細閱讀以下文件:
http://www.cs.columbia.edu/~lennox/draft-lennox-avt-app-sharing-00.html
我閱讀它,它對桌面共享應用程序的理解有很大幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.