C# Update bitmap in picturebox

后端 未结 3 1354
再見小時候
再見小時候 2021-02-19 18:17

I\'m working on a screen sharing project ,and i recieve a small blocks of image from a Socket constantly and need to update them on a certain initial dekstop bitmap

3条回答
  •  臣服心动
    2021-02-19 18:43

    It would be shame to leave that question without some answer. The following is about 10 times faster in my tests when updating small portions of the picture box. What it does basically is smart invalidating (invalidates just the updated portion of the bitmap, considering the scaling) and smart painting (draws only the invalidated portion of the picture box, taken from e.ClipRectangle and considering the scaling):

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

    The only kind of tricky part is determining the scaled rectangles, especially the one for invalidating, due to floating point to int conversions required, so we make sure it's eventually a little bigger than needed, but not less.

提交回复
热议问题