C# 抓圖服務(wù)的實(shí)現(xiàn)
C#抓圖服務(wù)首先抽象出抓圖接口,然后對接口做基于公共操作的抽象類封裝,之后針對不同的抓圖方式做差異化處理,最后根據(jù)接口實(shí)現(xiàn)抓圖服務(wù)。
注意:Win32封裝實(shí)現(xiàn)參考C#使用BitBlt進(jìn)行窗口抓圖。
Github示例工程:SimpleWindowCapture。
1、抓圖接口
using System; using Win32Proxy; namespace CaptureProxy { internal interface ICaptureHelper { bool Init(string windowName); bool Init(IntPtr handle); void Cleanup(); bool RefreshWindow(); bool ChangeWindowHandle(string windowName); bool ChangeWindowHandle(IntPtr handle); IntPtr Capture(); bool Capture(out IntPtr bitsPtr, out int bufferSize, out Win32Types.Rect rect); Win32Types.Rect WindowRect { get; } Win32Types.Rect ClientRect { get; } int BitmapDataSize { get; } IntPtr BitmapPtr { get; } Win32Types.BitmapInfo BitmapInfo { get; } } }
using System.ComponentModel; namespace CaptureProxy { public enum CaptureType { [Description("使用CreateDIBSection抓圖,速度快,但是無法抓取D3D等渲染的窗口")] CreateDibSection = 0, [Description("使用PrintWindow抓圖,速度慢(16ms左右),但是可以抓取D3D等渲染的窗口")] PrintWindow } }
2、抓圖抽象類
using System; using Win32Proxy; namespace CaptureProxy { internal abstract class AbsCaptureHelper : ICaptureHelper { public Win32Types.Rect WindowRect => _windowRect; public Win32Types.Rect ClientRect => WinClientRect; public int BitmapDataSize => _bmpDataSize; public IntPtr BitmapPtr => HBitmap; public Win32Types.BitmapInfo BitmapInfo { get; } = new Win32Types.BitmapInfo(); protected IntPtr HWnd = IntPtr.Zero; protected IntPtr HScrDc = IntPtr.Zero; protected IntPtr HMemDc = IntPtr.Zero; protected IntPtr HBitmap = IntPtr.Zero; protected IntPtr HOldBitmap = IntPtr.Zero; private Win32Types.Rect _windowRect; protected Win32Types.Rect WinClientRect; private int _bmpDataSize; protected abstract bool CommonInit(); protected abstract IntPtr DoCapture(); protected abstract bool DoCapture(out IntPtr bitsPtr); public bool Init(string windowName) { var handle = Win32Funcs.FindWindowWrapper(null, windowName); if (handle.Equals(IntPtr.Zero)) { return false; } return Init(handle); } public bool Init(IntPtr handle) { HWnd = handle; //獲取窗口大小 if (!Win32Funcs.GetWindowRectWrapper(HWnd, out _windowRect) || !Win32Funcs.GetClientRectWrapper(HWnd, out WinClientRect)) { return false; } _bmpDataSize = WinClientRect.Width * WinClientRect.Height * 3; return CommonInit(); } public void Cleanup() { if (HBitmap.Equals(IntPtr.Zero)) { return; } //刪除用過的對象 Win32Funcs.SelectObjectWrapper(HMemDc, HOldBitmap); Win32Funcs.DeleteObjectWrapper(HBitmap); Win32Funcs.DeleteDcWrapper(HMemDc); Win32Funcs.ReleaseDcWrapper(HWnd, HScrDc); HWnd = IntPtr.Zero; HScrDc = IntPtr.Zero; HMemDc = IntPtr.Zero; HBitmap = IntPtr.Zero; HOldBitmap = IntPtr.Zero; //_bitsPtr = IntPtr.Zero; } public bool RefreshWindow() { return ChangeWindowHandle(HWnd); } public bool ChangeWindowHandle(string windowName) { Cleanup(); return Init(windowName); } public bool ChangeWindowHandle(IntPtr handle) { Cleanup(); return Init(handle); } public IntPtr Capture() { if (HBitmap.Equals(IntPtr.Zero) || HMemDc.Equals(IntPtr.Zero) || HScrDc.Equals(IntPtr.Zero)) { return IntPtr.Zero; } return DoCapture(); } public bool Capture(out IntPtr bitsPtr, out int bufferSize, out Win32Types.Rect rect) { bitsPtr = IntPtr.Zero; bufferSize = _bmpDataSize; rect = WinClientRect; if (HBitmap.Equals(IntPtr.Zero) || HMemDc.Equals(IntPtr.Zero) || HScrDc.Equals(IntPtr.Zero)) { return false; } return DoCapture(out bitsPtr); } } }
3、抓圖類實(shí)現(xiàn)
using System; using Win32Proxy; namespace CaptureProxy { internal class DibCaptureHelper : AbsCaptureHelper { private Win32Types.BitmapInfo _bitmapInfo; private IntPtr _bitsPtr = IntPtr.Zero; protected override bool CommonInit() { //位圖信息 _bitmapInfo = new Win32Types.BitmapInfo {bmiHeader = new Win32Types.BitmapInfoHeader()}; _bitmapInfo.bmiHeader.Init(); _bitmapInfo.bmiHeader.biWidth = WinClientRect.Width; _bitmapInfo.bmiHeader.biHeight = WinClientRect.Height; _bitmapInfo.bmiHeader.biPlanes = 1; _bitmapInfo.bmiHeader.biBitCount = 24; _bitmapInfo.bmiHeader.biSizeImage = (uint) (WinClientRect.Width * WinClientRect.Height); _bitmapInfo.bmiHeader.biCompression = (uint) Win32Consts.BitmapCompressionMode.BI_RGB; HScrDc = Win32Funcs.GetWindowDcWrapper(HWnd); HMemDc = Win32Funcs.CreateCompatibleDcWrapper(HScrDc); HBitmap = Win32Funcs.CreateDibSectionWrapper(HMemDc, ref _bitmapInfo, (uint) Win32Consts.DibColorMode.DIB_RGB_COLORS, out _bitsPtr, IntPtr.Zero, 0); HOldBitmap = Win32Funcs.SelectObjectWrapper(HMemDc, HBitmap); return true; } protected override IntPtr DoCapture() { var ret = Win32Funcs.BitBltWrapper( HMemDc, 0, 0, WinClientRect.Width, WinClientRect.Height, HScrDc, 0, 0, (uint) Win32Consts.RasterOperationMode.SRCCOPY); return ret ? _bitsPtr : IntPtr.Zero; } protected override bool DoCapture(out IntPtr bitsPtr) { bitsPtr = _bitsPtr; var ret = Win32Funcs.BitBltWrapper( HMemDc, 0, 0, WinClientRect.Width, WinClientRect.Height, HScrDc, 0, 0, (uint) Win32Consts.RasterOperationMode.SRCCOPY); return ret; } } }
using System; using Win32Proxy; namespace CaptureProxy { internal class PrintCaptureHelper : AbsCaptureHelper { protected override bool CommonInit() { HScrDc = Win32Funcs.GetWindowDcWrapper(HWnd); HBitmap = Win32Funcs.CreateCompatibleBitmapWrapper(HScrDc, WinClientRect.Width, WinClientRect.Height); HMemDc = Win32Funcs.CreateCompatibleDcWrapper(HScrDc); HOldBitmap = Win32Funcs.SelectObjectWrapper(HMemDc, HBitmap); return true; } protected override IntPtr DoCapture() { var ret = Win32Funcs.PrintWindowWrapper(HWnd, HMemDc, (uint) Win32Consts.PrintWindowMode.PW_CLIENTONLY | (uint) Win32Consts.PrintWindowMode.PW_RENDERFULLCONTENT); return ret ? HBitmap : IntPtr.Zero; } protected override bool DoCapture(out IntPtr bitsPtr) { bitsPtr = HBitmap; var ret = Win32Funcs.PrintWindowWrapper(HWnd, HMemDc, (uint) Win32Consts.PrintWindowMode.PW_CLIENTONLY | (uint) Win32Consts.PrintWindowMode.PW_RENDERFULLCONTENT); return ret; } } }
4、抓圖服務(wù)
using System; using System.Collections.Generic; using Win32Proxy; namespace CaptureProxy { public class CaptureService { private readonly Dictionary<string, ICaptureHelper> _dicCaptureHelper; /// <summary> /// 注冊抓圖服務(wù) /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="windowName">窗口名稱</param> /// <param name="type">抓圖類型</param> /// <returns>true成功,false失敗</returns> public bool RegisterCapture(string name, string windowName, CaptureType type = CaptureType.CreateDibSection) { if (string.IsNullOrEmpty(name) || _dicCaptureHelper.ContainsKey(name)) { return false; } ICaptureHelper helper; switch (type) { case CaptureType.CreateDibSection: helper = new DibCaptureHelper(); break; case CaptureType.PrintWindow: helper = new PrintCaptureHelper(); break; default: return false; } if (!helper.Init(windowName)) { return false; } _dicCaptureHelper.Add(name, helper); return true; } /// <summary> /// 注冊抓圖服務(wù) /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="handle">窗口句柄</param> /// <param name="type">抓圖類型</param> /// <returns>true成功,false失敗</returns> public bool RegisterCapture(string name, IntPtr handle, CaptureType type = CaptureType.CreateDibSection) { if (string.IsNullOrEmpty(name) || _dicCaptureHelper.ContainsKey(name)) { return false; } ICaptureHelper helper; switch (type) { case CaptureType.CreateDibSection: helper = new DibCaptureHelper(); break; case CaptureType.PrintWindow: helper = new PrintCaptureHelper(); break; default: return false; } if (!helper.Init(handle)) { return false; } _dicCaptureHelper.Add(name, helper); return true; } /// <summary> /// 獲取是否已注冊抓圖服務(wù) /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <returns>true已注冊,false未注冊</returns> public bool IsRegister(string name) { return !string.IsNullOrEmpty(name) && _dicCaptureHelper.ContainsKey(name); } /// <summary> /// 注銷抓圖服務(wù) /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> public void UnRegisterCapture(string name) { if (string.IsNullOrEmpty(name) || !_dicCaptureHelper.ContainsKey(name)) { return; } _dicCaptureHelper[name]?.Cleanup(); _dicCaptureHelper.Remove(name); } /// <summary> /// 清理所有抓圖服務(wù) /// </summary> public void Cleanup() { foreach (var helper in _dicCaptureHelper) { helper.Value?.Cleanup(); } _dicCaptureHelper.Clear(); } public bool RefreshWindow(string name) { var ret = !string.IsNullOrEmpty(name) && _dicCaptureHelper.ContainsKey(name); if (ret) { ret = _dicCaptureHelper[name].RefreshWindow(); } return ret; } /// <summary> /// 修改窗口句柄 /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="handle">窗口句柄</param> public bool ChangeWindowHandle(string name, IntPtr handle) { return !string.IsNullOrEmpty(name) && _dicCaptureHelper.ContainsKey(name) && _dicCaptureHelper[name].ChangeWindowHandle(handle); } /// <summary> /// 修改窗口句柄 /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="windowName">窗口名稱</param> public bool ChangeWindowHandle(string name, string windowName) { return !string.IsNullOrEmpty(name) && _dicCaptureHelper.ContainsKey(name) && _dicCaptureHelper[name].ChangeWindowHandle(windowName); } /// <summary> /// 獲取窗口尺寸 /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="winRect">輸出的窗口尺寸</param> /// <returns>true成功,false失敗</returns> public bool GetWindowRect(string name, out Win32Types.Rect winRect) { var ret = !string.IsNullOrEmpty(name) && _dicCaptureHelper.ContainsKey(name); winRect = ret ? _dicCaptureHelper[name].WindowRect : new Win32Types.Rect(); return ret; } /// <summary> /// 獲取窗口客戶區(qū)尺寸 /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="clientRect">輸出的窗口客戶區(qū)尺寸</param> /// <returns>true成功,false失敗</returns> public bool GetClientRect(string name, out Win32Types.Rect clientRect) { var ret = !string.IsNullOrEmpty(name) && _dicCaptureHelper.ContainsKey(name); clientRect = ret ? _dicCaptureHelper[name].ClientRect : new Win32Types.Rect(); return ret; } /// <summary> /// 獲取抓圖數(shù)據(jù)大小 /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="bmpDataSize">抓圖數(shù)據(jù)大小</param> /// <returns>true成功,false失敗</returns> public bool GetBitmapDataSize(string name, out int bmpDataSize) { var ret = !string.IsNullOrEmpty(name) && _dicCaptureHelper.ContainsKey(name); bmpDataSize = ret ? _dicCaptureHelper[name].BitmapDataSize : 0; return ret; } public IntPtr GetBitmapPtr(string name) { if (string.IsNullOrEmpty(name) || !_dicCaptureHelper.ContainsKey(name)) { return IntPtr.Zero; } return _dicCaptureHelper[name].BitmapPtr; } public Win32Types.BitmapInfo GetBitmapInfo(string name) { if (string.IsNullOrEmpty(name) || !_dicCaptureHelper.ContainsKey(name)) { return new Win32Types.BitmapInfo(); } return _dicCaptureHelper[name].BitmapInfo; } /// <summary> /// 獲取抓圖 /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="bitsPtr">位圖指針</param> /// <returns>true成功,false失敗</returns> public bool Capture(string name, out IntPtr bitsPtr) { var ret = !string.IsNullOrEmpty(name) && _dicCaptureHelper.ContainsKey(name); bitsPtr = ret ? _dicCaptureHelper[name].Capture() : IntPtr.Zero; return ret && !bitsPtr.Equals(IntPtr.Zero); } /// <summary> /// 獲取抓圖 /// </summary> /// <param name="name">抓圖服務(wù)名稱</param> /// <param name="bitsPtr">位圖指針</param> /// <param name="bufferSize">位圖數(shù)據(jù)大小</param> /// <param name="texSize">位圖尺寸</param> /// <returns>true成功,false失敗</returns> public bool Capture(string name, out IntPtr bitsPtr, out int bufferSize, out Win32Types.Rect texSize) { if (string.IsNullOrEmpty(name) || !_dicCaptureHelper.ContainsKey(name)) { bitsPtr = IntPtr.Zero; bufferSize = 0; texSize = new Win32Types.Rect(); return false; } return _dicCaptureHelper[name].Capture(out bitsPtr, out bufferSize, out texSize); } #region 單例模式 private static CaptureService _instance; private static readonly object LockHelper = new object(); private CaptureService() { _dicCaptureHelper = new Dictionary<string, ICaptureHelper>(); } public static CaptureService Instance { get { if (_instance != null) { return _instance; } lock (LockHelper) { _instance = _instance ?? new CaptureService(); } return _instance; } } #endregion } }
5、使用示例
using System; using System.Threading; using CaptureProxy; using Win32Proxy; namespace SimpleWindowCapture { internal sealed class CaptureHelper { public event Action<string, IntPtr, Win32Types.BitmapInfo> CaptureDone = (captureName, bitmapPtr, bitmapInfo) => { }; public int Fps { get; set; } = 15; private double TimerInterval => 1000.0 / Fps; private string _captureName; private Timer _timer; public bool Start(string captureName, IntPtr handle, CaptureType type = CaptureType.CreateDibSection) { if (!CaptureService.Instance.RegisterCapture(captureName, handle, type)) { return false; } _captureName = captureName; //創(chuàng)建守護(hù)定時(shí)器,馬上執(zhí)行 _timer = new Timer(CaptureFunc, null, TimeSpan.FromMilliseconds(0), Timeout.InfiniteTimeSpan); return true; } public void Stop() { //移除定時(shí)器 _timer?.Dispose(); _timer = null; CaptureService.Instance.UnRegisterCapture(_captureName); _captureName = string.Empty; } private void CaptureFunc(object state) { Capture(); //執(zhí)行下次定時(shí)器 _timer?.Change(TimeSpan.FromMilliseconds(TimerInterval), Timeout.InfiniteTimeSpan); } private void Capture() { IntPtr bitsPtr; if (!CaptureService.Instance.Capture(_captureName, out bitsPtr)) { return; } var bitmapPtr = CaptureService.Instance.GetBitmapPtr(_captureName); var bitmapInfo = CaptureService.Instance.GetBitmapInfo(_captureName); CaptureDone.Invoke(_captureName, bitmapPtr, bitmapInfo); } } }
以上就是C# 抓圖服務(wù)的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于c# 抓圖服務(wù)的資料請關(guān)注腳本之家其它相關(guān)文章!
- C# 使用BitBlt進(jìn)行窗口抓圖的示例
- C# 實(shí)現(xiàn)SDL2進(jìn)行視頻播放窗口截圖和字幕添加
- C#實(shí)現(xiàn)QQ截圖功能及相關(guān)問題
- C#實(shí)現(xiàn)的滾動(dòng)網(wǎng)頁截圖功能示例
- C# 實(shí)現(xiàn)截圖軟件功能實(shí)例代碼
- C# 實(shí)現(xiàn)QQ式截圖功能實(shí)例代碼
- C#實(shí)現(xiàn)屬于自己的QQ截圖工具
- C#實(shí)現(xiàn)在網(wǎng)頁中根據(jù)url截圖并輸出到網(wǎng)頁的方法
- C#實(shí)現(xiàn)通過ffmpeg從flv視頻文件中截圖的方法
- C#實(shí)現(xiàn)網(wǎng)頁截圖功能
- c#實(shí)現(xiàn)winform屏幕截圖并保存的示例
相關(guān)文章
C#從數(shù)據(jù)庫讀取數(shù)據(jù)到DataSet并保存到xml文件的方法
這篇文章主要介紹了C#從數(shù)據(jù)庫讀取數(shù)據(jù)到DataSet并保存到xml文件的方法,涉及C#操作DataSet保存到XML文件的技巧,需要的朋友可以參考下2015-04-04C#連接數(shù)據(jù)庫和更新數(shù)據(jù)庫的方法
這篇文章主要介紹了C#連接數(shù)據(jù)庫和更新數(shù)據(jù)庫的方法,需要的朋友可以參考下2015-08-08區(qū)分WCF與WebService的異同、優(yōu)勢
這篇文章主要幫助大家區(qū)分WCF與WebService的異同、優(yōu)勢,分為三大方面進(jìn)行研究學(xué)習(xí),感興趣的小伙伴們可以參考一下2016-03-03C#去除DataTable重復(fù)數(shù)據(jù)的三種方法
這篇文章主要介紹了C#去除DataTable重復(fù)數(shù)據(jù)的三種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02C#給picturebox控件加圖片選中狀態(tài)的2個(gè)方法
C#給picturebox控件加圖片選中狀態(tài)的2個(gè)方法,需要的朋友可以參考一下2013-03-03