c# – 使用directshow在桌面录制上翻转光标图标

使用Directshow.NET我开发了一个应用程序,它将记录桌面屏幕,获取我们需要用自己绘制鼠标指针的鼠标指针.所以我在BufferCB中添加了SampleGrabber adn,我写了下面的代码:

    public const Int32 CURSOR_SHOWING = 0x00000001;

    [StructLayout(LayoutKind.Sequential)]
    public struct ICONINFO
    {
        public bool fIcon;
        public Int32 xHotspot;
        public Int32 yHotspot;
        public IntPtr hbmMask;
        public IntPtr hbmColor;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public Int32 x;
        public Int32 y;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct CURSORINFO
    {
        public Int32 cbSize;
        public Int32 flags;
        public IntPtr hCursor;
        public POINT ptScreenPos;
    }

    [DllImport("user32.dll")]
    public static extern bool GetCursorInfo(out CURSORINFO pci);

    [DllImport("user32.dll")]
    public static extern IntPtr CopyIcon(IntPtr hIcon);

    [DllImport("user32.dll")]
    public static extern bool DrawIcon(IntPtr hdc, int x, int y, IntPtr hIcon);

    [DllImport("user32.dll")]
    public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);

public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
{
Graphics g;
Bitmap v;
v = new Bitmap(m_videoWidth, m_videoHeight, m_stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, pBuffer);            
g = Graphics.FromImage(v);
CURSORINFO cursorInfo;
cursorInfo.cbSize = Marshal.SizeOf(typeof(CURSORINFO));

if (GetCursorInfo(out cursorInfo))
{
    if (cursorInfo.flags == CURSOR_SHOWING)
    {
        var iconPointer = CopyIcon(cursorInfo.hCursor);
        ICONINFO iconInfo;
        int iconX, iconY;

        if (GetIconInfo(iconPointer, out iconInfo))
        {
            iconX = cursorInfo.ptScreenPos.x - ((int)iconInfo.xHotspot);
            iconY = cursorInfo.ptScreenPos.y - ((int)iconInfo.yHotspot);

            DrawIcon(g.GetHdc(), iconX, iconY, cursorInfo.hCursor);
            g.ReleaseHdc();
            g.Dispose();
            v.Dispose();                        
        }
    }
}
return 0;
}

此代码正在绘制鼠标光标,但光标在Y轴上翻转.

《c# – 使用directshow在桌面录制上翻转光标图标》

这可能是因为在BufferCB中,如果我们在Bitmap中转换pBuffer,那么该帧在Y轴上翻转.为了解决这个问题,我通过添加v.RotateFlip(RotateFlipType.RotateNoneFlipY)来在Y轴上翻转当前帧.在此更改后,BufferCB内部的鼠标指针在桌面录制视频中不可见.

我怎么能翻转鼠标指针?

更新#1

我使用Icon.ToBitmap()将图标指针转换为Icon然后转换为Bitmap,然后在Y轴上翻转,这里是代码(感谢@Roman R.):

...
iconX = cursorInfo.ptScreenPos.x - ((int)iconInfo.xHotspot);
iconY = cursorInfo.ptScreenPos.y - ((int)iconInfo.yHotspot);

Icon ic = Icon.FromHandle(iconPointer);
Bitmap icon = ic.ToBitmap();
icon.RotateFlip(RotateFlipType.RotateNoneFlipY);
g.DrawImage(icon, iconX, iconY);
g.Dispose();
v.Dispose();
icon.Dispose();
ic.Dispose();  
...

我在上面的修改中遇到的只有一个问题,有时我在行Bitmap icon = ic.ToBitmap();得到ArgumentException.

  System.ArgumentException occurred
  HResult=-2147024809
  Message=Parameter is not valid.
  Source=System.Drawing
  StackTrace:
       at System.Drawing.Bitmap.FromHicon(IntPtr hicon)
  InnerException: 

我处理了所有使用的位图,但我得到了这个例外.

最佳答案 你在这里遇到的问题是你的BufferCB实现.您创建一个临时的Graphics / Bitmap对象,以便可以使用光标覆盖更新它.你将这个位图颠倒了,图标的正常绘制将其翻转.

您需要考虑到使用BufferCB回调获得的24位RGB缓冲区的正常顺序是从下到上; Bitmap constructor行的顺序是相反的.您需要以相反的顺序将行传输到位图,然后分别将它们取回.我不确定消极的步伐是否有效,可能不会.或者只是覆盖预先翻转的光标,以补偿翻转的背景和叠加坐标.

点赞