using System; using System.Diagnostics; using System.Drawing; using System.Windows.Forms; using xServer.Core.Utilities; namespace xServer.Controls { public interface IRapidPictureBox { bool Running { get; set; } Image GetImageSafe { get; set; } void Start(); void Stop(); void UpdateImage(Bitmap bmp, bool cloneBitmap = false); } /// /// Custom PictureBox Control designed for rapidly-changing images. /// public class RapidPictureBox : PictureBox, IRapidPictureBox { /// /// True if the PictureBox is currently streaming images, else False. /// public bool Running { get; set; } /// /// Returns the width of the original screen. /// public int ScreenWidth { get; private set; } /// /// Returns the height of the original screen. /// public int ScreenHeight { get; private set; } /// /// Provides thread-safe access to the Image of this Picturebox. /// public Image GetImageSafe { get { return Image; } set { lock (_imageLock) { Image = value; } } } /// /// The lock object for the Picturebox's image. /// private readonly object _imageLock = new object(); /// /// The Stopwatch for internal FPS measuring. /// private Stopwatch _sWatch; /// /// The internal class for FPS measuring. /// private FrameCounter _frameCounter; /// /// Subscribes an Eventhandler to the FrameUpdated event. /// /// The Eventhandler to set. public void SetFrameUpdatedEvent(FrameUpdatedEventHandler e) { _frameCounter.FrameUpdated += e; } /// /// Unsubscribes an Eventhandler from the FrameUpdated event. /// /// The Eventhandler to remove. public void UnsetFrameUpdatedEvent(FrameUpdatedEventHandler e) { _frameCounter.FrameUpdated -= e; } /// /// Starts the internal FPS measuring. /// public void Start() { _frameCounter = new FrameCounter(); _sWatch = Stopwatch.StartNew(); Running = true; } /// /// Stops the internal FPS measuring. /// public void Stop() { if (_sWatch != null) _sWatch.Stop(); Running = false; } /// /// Updates the Image of this Picturebox. /// /// The new bitmap to use. /// If True the bitmap will be cloned, else it uses the original bitmap. public void UpdateImage(Bitmap bmp, bool cloneBitmap) { try { CountFps(); if ((ScreenWidth != bmp.Width) && (ScreenHeight != bmp.Height)) UpdateScreenSize(bmp.Width, bmp.Height); lock (_imageLock) { // get old image to dispose it correctly var oldImage = GetImageSafe; SuspendLayout(); GetImageSafe = cloneBitmap ? new Bitmap(bmp, Width, Height) /*resize bitmap*/ : bmp; ResumeLayout(); if (oldImage != null) oldImage.Dispose(); } } catch (InvalidOperationException) { } catch (Exception) { } } /// /// Constructor, sets Picturebox double-buffered and initializes the Framecounter. /// public RapidPictureBox() { this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED return cp; } } protected override void OnPaint(PaintEventArgs pe) { lock (_imageLock) { if (GetImageSafe != null) { pe.Graphics.DrawImage(GetImageSafe, Location); } } } private void UpdateScreenSize(int newWidth, int newHeight) { ScreenWidth = newWidth; ScreenHeight = newHeight; } private void CountFps() { var deltaTime = (float)_sWatch.Elapsed.TotalSeconds; _sWatch = Stopwatch.StartNew(); _frameCounter.Update(deltaTime); } } }