少俠學截圖-C#螢幕捕捉的方式
本篇主要介紹如何通過C#程式碼來獲得Windows作業系統的桌面點陣圖。
當然,不僅僅是截圖。主要是受園子裡的朋友我不是聖人的激發,勾起了繼續探究一下Windows螢幕捕捉和網路傳輸的慾望。
以前也搞過一陣子,不過都是淺嘗一下。最近幾天搞了點眉目出來,這裡就先發第一塊出來分享一下。
後續的還要等我除錯完成,想清楚了再發。
截圖的結果就是要獲得一個點陣圖
主要方式有兩個:
1、C#類庫
2、Windows32API
先介紹使用C#類庫的方式
主要使用Screen類
http://msdn.microsoft.com/zh-cn/library/system.windows.forms.screen.aspx
表示單個系統上的一個或多個顯示裝置。
名稱空間: System.Windows.Forms
程式集: System.Windows.Forms(在 System.Windows.Forms.dll 中)
程式碼:
Image img = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics g = Graphics.FromImage(img);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.PrimaryScreen.Bounds.Size);
通過這3行,img已經獲得了對一個點陣圖的引用了。
簡單得很哦
第二種:使用Win32API
主要參考這個版本的程式碼
http://www.csharphelp.com/2006/11/capturing-the-screen-image-using-c/
具體不想多做介紹了
簡單說明,Windows作業系統本身擁有豐富的程式碼,能完成很多系統級功能,並且非常高效。
而C#以及各種.net程式,以及其他高階語言完成類似功能時都需要程式設計師為之編碼,且執行效率多數是不行的。
所以幹嗎要重複造輪子呢
在.net這裡可以使用上述的方式來引用Windows的系統函式來完成我們需要的功能
探討的部分是,在很多Win32呼叫的程式中,釋放控制程式碼一直是非常要緊的一件事
但是在我實際使用中發現不是必須如此的
原始程式碼:
public static Bitmap GetDesktopImage()
{
//Variable to keep the handle of the btimap.
IntPtr m_HBitmap=null;
//Variable to keep the refrence to the desktop bitmap.
System.Drawing.Bitmap bmp=null;
//In size variable we shall keep the size of the screen.
SIZE size;
//Here we get the handle to the desktop device context.
IntPtr hDC = PlatformInvokeUSER32.GetDC(PlatformInvokeUSER32.GetDesktopWindow());
//Here we make a compatible device context in memory for screen device context.
IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);
//We pass SM_CXSCREEN constant to GetSystemMetrics to get the X coordinates of screen.
size.cx = PlatformInvokeUSER32.GetSystemMetrics (PlatformInvokeUSER32.SM_CXSCREEN);
//We pass SM_CYSCREEN constant to GetSystemMetrics to get the Y coordinates of screen.
size.cy = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CYSCREEN);
//We create a compatible bitmap of screen size and using screen device context.
m_HBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, size.cx, size.cy);
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (m_HBitmap!=IntPtr.Zero)
{
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0,PlatformInvokeGDI32.SRCCOPY);
//We select the old bitmap back to the memory device context.
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
//We delete the memory device context.
PlatformInvokeGDI32.DeleteDC(hMemDC);
//We release the screen device context.
PlatformInvokeUSER32.ReleaseDC(PlatformInvokeUSER32.GetDesktopWindow(), hDC);
//Image is created by Image bitmap handle and assigned to Bitmap variable.
bmp=System.Drawing.Image.FromHbitmap(m_HBitmap);
//Delete the compatible bitmap object.
PlatformInvokeGDI32.DeleteObject(m_HBitmap);
return bmp;
}
//If m_HBitmap is null retunrn null.
return null;
}
對比程式碼:
public static Bitmap GetDesktopImage()
{
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (m_HBitmap!=IntPtr.Zero)
{
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);
//We select the old bitmap back to the memory device context.
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
//老外的原始程式碼中,靜態構造裡是沒東西的。所有那些都是在本函式中宣告、使用並且銷燬的。
//如果有喜歡銷燬東西癖好的,可以在這裡銷燬hDC、hMemDC以及m_HBitmap
//不過我覺得沒有這個必要,並且不銷燬能提高點點速度
return System.Drawing.Image.FromHbitmap(m_HBitmap);
}
//If m_HBitmap is null retunrn null.
return null;
}
因為我覺得hDC在本程式使用中永遠是指向桌面視窗的控制程式碼,簡單說這個指標的值是永遠不變的。除非桌面視窗被釋放、重建。
同理hMemDC也是一樣和桌面視窗關聯的
m_HBitmap則是一個點陣圖物件的引用,也就是申請了一塊記憶體。
反覆多次對同一片記憶體寫入資料是不會有問題的
因此我在程式碼中把這幾個的初始化都轉移到了靜態構造裡,只執行一次。實際看速度是快了一點的。
由於對C/C++的理解不是很深(本人本質是VB5.0+VBA office程式設計師出身),希望有關達人能指點一下上述理由是否成立。
小結:
C#類庫方式:程式碼簡潔、學習代價低
Win32API方式:程式碼複雜、學習難度高
一般而言用C#方式,並且執行效率上看,在我的機器上兩者區別不大。Win32API方式略有優勢。
關鍵點:滑鼠呢?
上面兩個程式碼其實都沒有捕捉到滑鼠,很不爽的一個地方
通過網路搜尋和試驗,在Win32API方式下我完成了對滑鼠形狀及位置的捕獲。Win32API在win平臺上應該是萬能的,呵呵。
總體思路是在捕獲全屏後,單獨獲取滑鼠位置及形狀。然後“畫”到先前捕獲的點陣圖上
public static Bitmap GetDesktopImage()
{
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (m_HBitmap!=IntPtr.Zero)
{
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);
#region 繪製滑鼠
PlatformInvokeUSER32.CURSORINFO pci = new PlatformInvokeUSER32.CURSORINFO();
pci.cbSize = Marshal.SizeOf(pci);
PlatformInvokeUSER32.GetCursorInfo(out pci);
IntPtr dc = hMemDC;
//這個偏移量是我在使用時發現的問題,不一定是10,沒有精確論證過。只是目前看起來位置正確。
PlatformInvokeUSER32.DrawIconEx(dc, pci.ptScreenPos.X-10, pci.ptScreenPos.Y-10, pci.hCursor, 32, 32, 1, IntPtr.Zero, PlatformInvokeUSER32.DI_NORMAL);
#endregion
//We select the old bitmap back to the memory device context.
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
//老外的原始程式碼中,靜態構造裡是沒東西的。所有那些都是在本函式中宣告、使用並且銷燬的。
//如果有喜歡銷燬東西癖好的,可以在這裡銷燬hDC、hMemDC以及m_HBitmap
//不過我覺得沒有這個必要,並且不銷燬能提高點點速度
return System.Drawing.Image.FromHbitmap(m_HBitmap);
}
//If m_HBitmap is null retunrn null.
return null;
}
經使用,完美解決問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-622490/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android螢幕截圖方式總結Android
- iOS螢幕截圖的方法iOS
- Flutter學習 —- 螢幕截圖和高斯模糊Flutter
- Flutter學習 ---- 螢幕截圖和高斯模糊Flutter
- SPX螢幕截圖軟體
- .NET 視窗/螢幕截圖
- selenium實現螢幕截圖
- iSnapshot for Mac螢幕截圖工具Mac
- android 螢幕截圖原始碼Android原始碼
- mac蘋果螢幕截圖快捷鍵Mac蘋果
- Python網頁截圖/螢幕截圖/截長圖如何實現?Python網頁
- 微軟稱win10系統將棄用截圖工具:由螢幕捕捉應用取而代之微軟Win10
- Mac螢幕截圖工具——iSnapshot for MacMac
- Android 5.0 螢幕錄製/截圖Android
- Windows 8.1怎麼給螢幕截圖Windows
- Ubuntu螢幕截圖快捷鍵知多少Ubuntu
- 釋出一個螢幕捕捉類
- 直播平臺軟體開發,完整擷取整個螢幕的截圖方式
- C#軟體開發例項.私人訂製自己的螢幕截圖工具(四)基本截圖功能實現C#
- iOS-圖片水印,圖片裁剪和螢幕截圖iOS
- 最強大的螢幕截圖軟體:Snagit for macGitMac
- Android獲取當前Activity的螢幕截圖Android
- 高畫質螢幕截圖工具GrabIt ,體驗不一樣的截圖感受
- win10中怎麼拍攝螢幕截圖 在win10系統中拍攝螢幕截圖的步驟Win10
- 螢幕截圖工具Snagit 2022 macGitMac
- TechSmith Snagit 2022螢幕截圖工具MITGit
- Snagit 2022 for Mac(螢幕截圖工具)GitMac
- web端螢幕截圖,生成自定義海報!Web
- TechSmith Snagit mac最強大的螢幕截圖軟體MITGitMac
- CleanShot X:螢幕截圖、錄屏、滾動截圖、標註一個都不少
- 用electron開發了一個螢幕截圖工具
- Snagit 2023 for Mac(螢幕截圖軟體)GitMac
- Matplotlib 中文使用者指南 8.1 螢幕截圖
- 簡單好用的螢幕截圖工具:Screen Timelapse for MacMac
- 自己寫遠端控制軟體之捕捉螢幕
- 向React Native應用新增螢幕捕捉功能React Native
- C#軟體開發例項.私人訂製自己的螢幕截圖工具(一)功能概覽C#
- Flutter 簽字畫板及螢幕或Widget截圖Flutter