using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Tango.ScreenCapture { public class ScreenCaptureEngine : IDisposable { private bool _isDisposed; private Thread _captureThread; private Bitmap _previousBitmap; private ImageComparer _comparer; public event EventHandler ScreenFrameReceived; public IScreenCaptureMethod CaptureMethod { get; set; } public CaptureRegion CaptureRegion { get; set; } public bool IsStarted { get; set; } public TimeSpan Interval { get; set; } public bool CaptureCursor { get; set; } public bool EnableImageComparison { get; set; } public ScreenCaptureEngine() { Interval = TimeSpan.FromMilliseconds(100); CaptureMethod = new GdiScreenCapture(); CaptureRegion = new CaptureRegion(System.Windows.Forms.Screen.PrimaryScreen.Bounds); _comparer = new ImageComparer(); EnableImageComparison = true; } public void Start() { if (_isDisposed) { throw new ObjectDisposedException("Screen capture engine cannot be started after disposed."); } if (!IsStarted) { IsStarted = true; _captureThread = new Thread(CaptureThreadMethod); _captureThread.IsBackground = true; _captureThread.Name = "Screen Capture Thread"; _captureThread.Start(); } } public void Stop() { if (IsStarted) { IsStarted = false; } } private void CaptureThreadMethod() { while (IsStarted) { var bitmap = CaptureMethod.GetDesktopBitmap(CaptureRegion); if (CaptureCursor) { using (Graphics g = Graphics.FromImage(bitmap)) { CursorUtils.ApplyCursor(g, bitmap, CaptureRegion.Left, CaptureRegion.Top); } } if (EnableImageComparison) { if (_previousBitmap == null) { _previousBitmap = bitmap.Clone() as Bitmap; OnScreenFrameReceived(new ScreenCaptureFrame(bitmap, null)); } else { var diffBitmap = _comparer.CreateDifferenceBitmap(_previousBitmap, bitmap, Color.Transparent); _previousBitmap.Dispose(); _previousBitmap = bitmap.Clone() as Bitmap; OnScreenFrameReceived(new ScreenCaptureFrame(bitmap, diffBitmap)); } } else { OnScreenFrameReceived(new ScreenCaptureFrame(bitmap, null)); } Thread.Sleep(Interval); } } public void Dispose() { if (!_isDisposed) { _isDisposed = true; Stop(); CaptureMethod?.Dispose(); } } protected virtual void OnScreenFrameReceived(ScreenCaptureFrame frame) { ScreenFrameReceived?.Invoke(this, new ScreenCaptureFrameReceivedEventArgs() { Frame = frame, }); } } }