I'm working on a screen sharing project, and I receive a small block of images from a Socket
constantly. I need to update them on a certain initial desktop bitmap I have.
After receiving every block, it copies its pixels according to a specific position (X
and Y
parameters), which is how the initial image gets updated. But then comes the part where I need to display it on a Picturebox
. I handle the Paint
event and redrawing it all again. The entire initial image is pretty big (1920X1080 in my case).
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.
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
}
}
Because I'm aiming at high speed performance (it's kind of a real-time project), I would like to know if there's any method to draw the block itself on the picturebox instead of drawing the whole initial
bitmap again. Plus, scaling it to the Picuturebox
bounds seems too inefficient to me.
The picturebox
itself is not resizeable - it has a fixed width and height. But I need to scale the initial Bitmap
every time (after processing the blocks) so it will fit the picturbox bounds to allow the client to see the full image. Despite their screen resolution, it's lower than the shared screen resolution (the server screen which is getting captured and shared).
This is my drawing method (works extremely fast, copying block with 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);
}