博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 全屏坐标及区域坐标获取。自定义光标及系统光标描边捕捉显示。
阅读量:5238 次
发布时间:2019-06-14

本文共 25972 字,大约阅读时间需要 86 分钟。

   最近手头工作比较轻松了一点就继续研究和完善之前的录屏软件,使用AForge最大的问题在于:最原始的只能够录全屏,而自定义的录屏需要更改非常多的细节:like follows:

1、需要支持区域化录屏;

2、需要支持麦克风录音,并且混音在视频中,同步;

3、需要支持系统声音录取、并且需要混音在视频中,同步;

4、需要支持捕获光标,并且自定义颜色、描边,最重要的是你需要在区域录屏的时候支持坐标位置更新(相对比较难);

   前面3个已经在前面的文章介绍了,这里不再赘述。着重列出第4点的内容以及如何解决。如果正在研究录屏这块的朋友们,千万别去copy那什么网上有限制时间录制和收费的录制,特别是有些很恶心的还发表长篇大论写的如何如何实现(的确技术不可否认是实现了),其实最后还是要你付费才能完全使用,就问你恶不恶心!

   好了,废话不多说,我们来一一解决;

首先获取系统光标有两种方式,第一种是直接通过系统API进行获取光标,这个是完全记录系统光标在做什么。随着系统光标变化而变化的。这边有用到的是几个类:

第一种方式:【CursorHelper.cs】、【GDIStuff.cs】、【Win32Stuff.cs】相对复杂一些;我就在代码中直接显示就好了,不需要引用任何其他的东西;

///     ///     The rt global cursor.    ///     public class CursorHelper    {        #region Constants        ///         ///     The curso r_ showing.        ///         private const int CURSOR_SHOWING = 1;        #endregion        #region Public Methods and Operators        ///         /// The capture cursor.        ///         ///         /// The x.        ///         ///         /// The y.        ///         /// 
/// The
. ///
public static Bitmap CaptureCursor(ref int x, ref int y) { Win32Stuff.CURSORINFO cursorInfo = new Win32Stuff.CURSORINFO(); cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); if (!Win32Stuff.GetCursorInfo(out cursorInfo)) { return null; } if (cursorInfo.flags != Win32Stuff.CURSOR_SHOWING) { return null; } IntPtr hicon = Win32Stuff.CopyIcon(cursorInfo.hCursor); if (hicon == IntPtr.Zero) { return null; } Win32Stuff.ICONINFO iconInfo; if (!Win32Stuff.GetIconInfo(hicon, out iconInfo)) { return null; } x = cursorInfo.ptScreenPos.x - ((int)iconInfo.xHotspot); y = cursorInfo.ptScreenPos.y - ((int)iconInfo.yHotspot); using (Bitmap maskBitmap = Bitmap.FromHbitmap(iconInfo.hbmMask)) { // Is this a monochrome cursor? if (maskBitmap.Height == maskBitmap.Width * 2) { Bitmap resultBitmap = new Bitmap(maskBitmap.Width, maskBitmap.Width); using (Graphics desktopGraphics = Graphics.FromHwnd(Win32Stuff.GetDesktopWindow())) { IntPtr desktopHdc = desktopGraphics.GetHdc(); IntPtr maskHdc = GDIStuff.CreateCompatibleDC(desktopHdc); IntPtr oldPtr = GDIStuff.SelectObject(maskHdc, maskBitmap.GetHbitmap()); using (Graphics resultGraphics = Graphics.FromImage(resultBitmap)) { IntPtr resultHdc = resultGraphics.GetHdc(); // These two operation will result in a black cursor over a white background. // Later in the code, a call to MakeTransparent() will get rid of the white background. GDIStuff.BitBlt( resultHdc, 0, 0, 32, 32, maskHdc, 0, 32, (int)GDIStuff.TernaryRasterOperations.SRCCOPY); GDIStuff.BitBlt( resultHdc, 0, 0, 32, 32, maskHdc, 0, 0, (int)GDIStuff.TernaryRasterOperations.SRCINVERT); resultGraphics.ReleaseHdc(resultHdc); GDIStuff.DeleteDC(resultHdc); GDIStuff.DeleteObject(resultHdc); } IntPtr newPtr = GDIStuff.SelectObject(maskHdc, oldPtr); GDIStuff.DeleteObject(oldPtr); GDIStuff.DeleteObject(newPtr); GDIStuff.DeleteDC(maskHdc); desktopGraphics.ReleaseHdc(desktopHdc); GDIStuff.DeleteDC(desktopHdc); } // Remove the white background from the BitBlt calls, // resulting in a black cursor over a transparent background. resultBitmap.MakeTransparent(Color.White); return resultBitmap; } } //// Delete the mask, if present. // if (iconInfo.hbmMask != IntPtr.Zero) // { // DeleteObject(iconInfo.hbmMask); // } //// Delete the color bitmap, if present. // if (iconInfo.hbmColor != IntPtr.Zero) // { // DeleteObject(iconInfo.hbmColor); // } using (Icon icon = Icon.FromHandle(hicon)) { return icon.ToBitmap(); } } #endregion #region Methods /// /// The copy icon. /// /// /// The h icon. /// ///
/// The
. ///
[DllImport("user32.dll")] private static extern IntPtr CopyIcon(IntPtr hIcon); /// /// The delete object. /// /// /// The h dc. /// ///
/// The
. ///
[DllImport("gdi32.dll")] private static extern IntPtr DeleteObject(IntPtr hDc); /// /// The destroy icon. /// /// /// The h icon. /// ///
/// The
. ///
[DllImport("user32.dll")] private static extern bool DestroyIcon(IntPtr hIcon); /// /// The get cursor info. /// /// /// The pci. /// ///
/// The
. ///
[DllImport("user32.dll")] private static extern bool GetCursorInfo(out CURSORINFO pci); /// /// The get gdi handle count. /// ///
/// The
. ///
private static int GetGDIHandleCount() { return GetGuiResources(Process.GetCurrentProcess().Handle, 0); } /// /// The get gui resources. /// /// /// The h process. /// /// /// The ui flags. /// ///
/// The
. ///
[DllImport("user32.dll")] private static extern int GetGuiResources(IntPtr hProcess, int uiFlags); /// /// The get icon info. /// /// /// The h icon. /// /// /// The piconinfo. /// ///
/// The
. ///
[DllImport("user32.dll")] private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo); /// /// The get user handle count. /// ///
/// The
. ///
private static int GetUserHandleCount() { return GetGuiResources(Process.GetCurrentProcess().Handle, 1); } /// /// The handle message. /// /// /// The message. /// private static void HandleMessage(string message) { Debug.WriteLine("HC: " + message + ": GDI: " + GetGDIHandleCount() + ": User: " + GetUserHandleCount()); } #endregion /// /// The cursorinfo. /// [StructLayout(LayoutKind.Sequential)] private struct CURSORINFO { // Fields /// /// The cb size. /// [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."), SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] public int cbSize; /// /// The flags. /// [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."), SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] public int flags; /// /// The h cursor. /// [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."), SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] public IntPtr hCursor; /// /// The pt screen pos. /// [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."), SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")] public POINT ptScreenPos; } /// /// The iconinfo. /// [StructLayout(LayoutKind.Sequential)] private struct ICONINFO { // Fields /// /// The f icon. /// public bool fIcon; /// /// The x hotspot. /// public int xHotspot; /// /// The y hotspot. /// public int yHotspot; // Handle of the icon’s bitmask bitmap. /// /// The hbm mask. /// public IntPtr hbmMask; // Handle of the icon’s color bitmap. Optional for monochrome icons. /// /// The hbm color. /// public IntPtr hbmColor; } /// /// The point. /// [StructLayout(LayoutKind.Sequential)] private struct POINT { // Fields /// /// The x. /// public int x; /// /// The y. /// public int y; } ///// ///// The capture cursor. ///// ///// ///// The x. ///// ///// ///// The y. ///// /////
///// The
. /////
// public static Bitmap CaptureCursor(ref int x, ref int y) // { // try // { // // Return value initially nothing // Bitmap bmp = null; // CURSORINFO curInfo = new CURSORINFO(); // curInfo.cbSize = Marshal.SizeOf(curInfo); // // HandleMessage("Start") // if (GetCursorInfo(ref curInfo)) // { // if (curInfo.flags == CURSOR_SHOWING) // { // IntPtr hicon = CopyIcon(curInfo.hCursor); // if (hicon != IntPtr.Zero) // { // ICONINFO icoInfo = default(ICONINFO); // if (GetIconInfo(hicon, ref icoInfo)) // { // // Delete the mask, if present. // if (icoInfo.hbmMask != IntPtr.Zero) // { // DeleteObject(icoInfo.hbmMask); // } // // Delete the color bitmap, if present. // if (icoInfo.hbmColor != IntPtr.Zero) // { // DeleteObject(icoInfo.hbmColor); // } // x = curInfo.ptScreenPos.x - icoInfo.xHotspot; // y = curInfo.ptScreenPos.y - icoInfo.yHotspot; // } // Icon ic = Icon.FromHandle(hicon); // bmp = ic.ToBitmap(); // // Must destroy the icon object we got from CopyIcon // DestroyIcon(hicon); // } // } // } // // HandleMessage("End") // return bmp; // } // catch // { // return null; // } // } }
CursorHelper.cs
///     ///     The gdi stuff.    ///     internal class GDIStuff    {        #region Constants        ///         ///     The srccopy.        ///         public const int SRCCOPY = 13369376;        #endregion        #region Enums        ///         ///     Specifies a raster-operation code. These codes define how the color data for the        ///     source rectangle is to be combined with the color data for the destination        ///     rectangle to achieve the final color.        ///         public enum TernaryRasterOperations        {            /// dest = source            SRCCOPY = 0x00CC0020,             /// dest = source OR dest            SRCPAINT = 0x00EE0086,             /// dest = source AND dest            SRCAND = 0x008800C6,             /// dest = source XOR dest            SRCINVERT = 0x00660046,             /// dest = source AND (NOT dest)            SRCERASE = 0x00440328,             /// dest = (NOT source)            NOTSRCCOPY = 0x00330008,             /// dest = (NOT src) AND (NOT dest)            NOTSRCERASE = 0x001100A6,             /// dest = (source AND pattern)            MERGECOPY = 0x00C000CA,             /// dest = (NOT source) OR dest            MERGEPAINT = 0x00BB0226,             /// dest = pattern            PATCOPY = 0x00F00021,             /// dest = DPSnoo            PATPAINT = 0x00FB0A09,             /// dest = pattern XOR dest            PATINVERT = 0x005A0049,             /// dest = (NOT dest)            DSTINVERT = 0x00550009,             /// dest = BLACK            BLACKNESS = 0x00000042,             /// dest = WHITE            WHITENESS = 0x00FF0062,             ///             ///     Capture window as seen on screen.  This includes layered windows            ///     such as WPF windows with AllowsTransparency="true"            ///             CAPTUREBLT = 0x40000000        }        #endregion        #region Public Methods and Operators        ///         /// The bit blt.        ///         ///         /// The hdc dest.        ///         ///         /// The x dest.        ///         ///         /// The y dest.        ///         ///         /// The w dest.        ///         ///         /// The h dest.        ///         ///         /// The hdc source.        ///         ///         /// The x src.        ///         ///         /// The y src.        ///         ///         /// The raster op.        ///         /// 
/// The
. ///
[DllImport("gdi32.dll", EntryPoint = "BitBlt")] [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here.")] [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "Reviewed. Suppression is OK here.")] public static extern bool BitBlt( IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, int RasterOp); /// /// The create compatible bitmap. /// /// /// The hdc. /// /// /// The n width. /// /// /// The n height. /// ///
/// The
. ///
[DllImport("gdi32.dll", EntryPoint = "CreateCompatibleBitmap")] [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here.")] public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight); /// /// The create compatible dc. /// /// /// The hdc. /// ///
/// The
. ///
[DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC")] public static extern IntPtr CreateCompatibleDC(IntPtr hdc); /// /// The create dc. /// /// /// The lpsz driver. /// /// /// The lpsz device. /// /// /// The lpsz output. /// /// /// The lp init data. /// ///
/// The
. ///
[DllImport("gdi32.dll", EntryPoint = "CreateDC")] public static extern IntPtr CreateDC(IntPtr lpszDriver, string lpszDevice, IntPtr lpszOutput, IntPtr lpInitData); /// /// The delete dc. /// /// /// The h dc. /// ///
/// The
. ///
[DllImport("gdi32.dll", EntryPoint = "DeleteDC")] public static extern IntPtr DeleteDC(IntPtr hDc); /// /// The delete object. /// /// /// The h dc. /// ///
/// The
. ///
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")] public static extern IntPtr DeleteObject(IntPtr hDc); /// /// The select object. /// /// /// The hdc. /// /// /// The bmp. /// ///
/// The
. ///
[DllImport("gdi32.dll", EntryPoint = "SelectObject")] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp); #endregion }
GDIStuff.cs
///     ///     The win 32 stuff.    ///     internal class Win32Stuff    {        #region Constants        ///         ///     The curso r_ showing.        ///         public const int CURSOR_SHOWING = 0x00000001;        ///         ///     The s m_ cxscreen.        ///         public const int SM_CXSCREEN = 0;        ///         ///     The s m_ cyscreen.        ///         public const int SM_CYSCREEN = 1;        #endregion        #region Public Methods and Operators        ///         /// The copy icon.        ///         ///         /// The h icon.        ///         /// 
/// The
. ///
[DllImport("user32.dll", EntryPoint = "CopyIcon")] public static extern IntPtr CopyIcon(IntPtr hIcon); /// /// The get cursor info. /// /// /// The pci. /// ///
/// The
. ///
[DllImport("user32.dll", EntryPoint = "GetCursorInfo")] public static extern bool GetCursorInfo(out CURSORINFO pci); /// /// The get dc. /// /// /// The ptr. /// ///
/// The
. ///
[DllImport("user32.dll", EntryPoint = "GetDC")] public static extern IntPtr GetDC(IntPtr ptr); /// /// The get desktop window. /// ///
/// The
. ///
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")] public static extern IntPtr GetDesktopWindow(); /// /// The get icon info. /// /// /// The h icon. /// /// /// The piconinfo. /// ///
/// The
. ///
[DllImport("user32.dll", EntryPoint = "GetIconInfo")] public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo); /// /// The get system metrics. /// /// /// The abc. /// ///
/// The
. ///
[DllImport("user32.dll", EntryPoint = "GetSystemMetrics")] public static extern int GetSystemMetrics(int abc); /// /// The get window dc. /// /// /// The ptr. /// ///
/// The
. ///
[DllImport("user32.dll", EntryPoint = "GetWindowDC")] public static extern IntPtr GetWindowDC(int ptr); /// /// The release dc. /// /// /// The h wnd. /// /// /// The h dc. /// ///
/// The
. ///
[DllImport("user32.dll", EntryPoint = "ReleaseDC")] public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc); #endregion /// /// The cursorinfo. /// [StructLayout(LayoutKind.Sequential)] public struct CURSORINFO { /// /// The cb size. /// public int cbSize; // Specifies the size, in bytes, of the structure. /// /// The flags. /// public int flags; // Specifies the cursor state. This parameter can be one of the following values: /// /// The h cursor. /// public IntPtr hCursor; // Handle to the cursor. /// /// The pt screen pos. /// public POINT ptScreenPos; // A POINT structure that receives the screen coordinates of the cursor. } /// /// The iconinfo. /// [StructLayout(LayoutKind.Sequential)] public struct ICONINFO { /// /// The f icon. /// public bool fIcon; // Specifies whether this structure defines an icon or a cursor. A value of TRUE specifies /// /// The x hotspot. /// public int xHotspot; // Specifies the x-coordinate of a cursor's hot spot. If this structure defines an icon, the hot /// /// The y hotspot. /// public int yHotspot; // Specifies the y-coordinate of the cursor's hot spot. If this structure defines an icon, the hot /// /// The hbm mask. /// public IntPtr hbmMask; // (HBITMAP) Specifies the icon bitmask bitmap. If this structure defines a black and white icon, /// /// The hbm color. /// public IntPtr hbmColor; // (HBITMAP) Handle to the icon color bitmap. This member can be optional if this } /// /// The point. /// [StructLayout(LayoutKind.Sequential)] public struct POINT { /// /// The x. /// public int x; /// /// The y. /// public int y; } }
Win32Stuff.cs

OK,类已经铺垫好了,接下来就在你的视频捕获方法中放入:关键方法--CursorHelper.CaptureCursor(ref x,ref y);

1                                        Graphics g = Graphics.FromImage(bitmap);//编辑原始视频帧 2                                        g.SmoothingMode = SmoothingMode.AntiAlias;//设置鼠标质量 3                                        g.InterpolationMode = InterpolationMode.HighQualityBicubic; 4                                        g.PixelOffsetMode = PixelOffsetMode.HighQuality; 5                                        var x = _currentPoint.X; 6                                        var y = _currentPoint.Y; 7                                        var cursorBmp = CursorHelper.CaptureCursor(ref x, ref y); 8                                        if (cursorBmp != null) 9                                        {10                                            g.DrawImage(cursorBmp, _currentPoint);11                                        }12                                        cursorBmp.Dispose();

**注释说明:其中_currentPoint 是相对于屏幕的坐标Point** 获取方法是--

_currentPoint = System.Windows.Forms.Cursor.Position;//(大屏坐标)

**注释说明:其中bitmap是当前获取的最原始的视频帧(不包含任何的例如光标-声音-什么锤子之类的哈哈哈)**,此类方法就是把原始视频帧重新编辑!

第二种方式:相对简单一点,获取光标_currentPoint还是使用上面的方法,但是不同的地方是我要自定义光标icon,这个又有一点难点就是如何画怎么画;---项目中采用的是外圈描边,内边填充方式;

1  SolidBrush myBrush = new SolidBrush(System.Drawing.Color.FromArgb(50, ColorTranslator.FromHtml("#你的填充颜色")));//设置透明度跟填充颜色 2                                        System.Drawing.Pen p = new System.Drawing.Pen(ColorTranslator.FromHtml("#你的描边颜色"));//设置透明度跟描边颜色 3                                        Graphics g = Graphics.FromImage(bitmap);//编辑原始视频帧 4                                        g.SmoothingMode = SmoothingMode.AntiAlias;//设置鼠标质量 5                                        g.InterpolationMode = InterpolationMode.HighQualityBicubic; 6                                        g.PixelOffsetMode = PixelOffsetMode.HighQuality; 7                                        g.DrawEllipse(p, new Rectangle(_currentPoint.X - this.screenArea.Left, _currentPoint.Y - this.screenArea.Top, 25, 25));//描边 8                                        g.FillEllipse(myBrush, new Rectangle(_currentPoint.X - this.screenArea.Left, _currentPoint.Y - this.screenArea.Top, 25, 25));//填充圆形区域 9                                        myBrush.Dispose();10                                        p.Dispose();11                                        g.Flush();

**注释:在上述这种方式中特别注意,原始的方法比如你是全屏录制则采用以下方式即可,还有自定义笔刷的画法,我想做完给大家分享。**

1                                        g.DrawEllipse(p, new Rectangle(_currentPoint.X , _currentPoint.Y, 25, 25));//描边2                                        g.FillEllipse(myBrush, new Rectangle(_currentPoint.X , _currentPoint.Y, 25, 25));//填充圆形区域

**注释:如果你的录屏方式也存在区域模式,那么就采用 当前光标位置X轴减去你录屏区域的左坐标,当前光标位置Y轴减去你录屏的顶坐标即可获取,这种方式自适应任何区域**

以上是个人在完善时候研究的成果,在此希望把它们分享给更多正在研究的伙伴们,因为研究的时候的确遇到了非常多的问题,我希望这些文章能够给你们一些方向研究,加快你们的开发进度。

 

转载于:https://www.cnblogs.com/BarryJames/p/6950813.html

你可能感兴趣的文章
SQL Server 如何查询表定义的列和索引信息
查看>>
GCD 之线程死锁
查看>>
NoSQL数据库常见分类
查看>>
一题多解 之 Bat
查看>>
Java 内部类
查看>>
{面试题7: 使用两个队列实现一个栈}
查看>>
【练习】使用事务和锁定语句
查看>>
centos7升级firefox的flash插件
查看>>
Apache Common-IO 使用
查看>>
评价意见整合
查看>>
二、create-react-app自定义配置
查看>>
Android PullToRefreshExpandableListView的点击事件
查看>>
系统的横向结构(AOP)
查看>>
linux常用命令
查看>>
NHibernate.3.0.Cookbook第四章第6节的翻译
查看>>
使用shared memory 计算矩阵乘法 (其实并没有加速多少)
查看>>
Django 相关
查看>>
git init
查看>>
训练记录
查看>>
IList和DataSet性能差别 转自 http://blog.csdn.net/ilovemsdn/article/details/2954335
查看>>