如何将透明光标渲染到位图并保留 alpha 通道?

发布于 2024-10-07 22:43:28 字数 922 浏览 6 评论 0原文

我使用下面的代码来渲染透明图标:

    private void button1_Click(object sender, EventArgs e)
    {
        // using LoadCursorFromFile from user32.dll
        var cursor = NativeMethods.LoadCustomCursor(@"d:\Temp\Cursors\Cursors\aero_busy.ani");

        // cursor -> bitmap
        Bitmap bitmap = new Bitmap(48, 48, PixelFormat.Format32bppArgb);
        Graphics gBitmap = Graphics.FromImage(bitmap);
        cursor.DrawStretched(gBitmap, new Rectangle(0, 0, 32, 32));

        // 1. Draw bitmap on a form canvas
        Graphics gForm = Graphics.FromHwnd(this.Handle);
        gForm.DrawImage(bitmap, 50, 50);

        // 2. Draw cursor directly to a form canvas
        cursor.Draw(gForm, new Rectangle(100, 50, 32, 32));

        cursor.Dispose();
    }

不幸的是,我无法将透明光标渲染为位图!当我将光标直接绘制到表单画布时它可以工作,但是当我将光标绘制到位图时出现问题。 任何建议都将受到高度赞赏。

替代文字

I use the code below to render a transparent icon:

    private void button1_Click(object sender, EventArgs e)
    {
        // using LoadCursorFromFile from user32.dll
        var cursor = NativeMethods.LoadCustomCursor(@"d:\Temp\Cursors\Cursors\aero_busy.ani");

        // cursor -> bitmap
        Bitmap bitmap = new Bitmap(48, 48, PixelFormat.Format32bppArgb);
        Graphics gBitmap = Graphics.FromImage(bitmap);
        cursor.DrawStretched(gBitmap, new Rectangle(0, 0, 32, 32));

        // 1. Draw bitmap on a form canvas
        Graphics gForm = Graphics.FromHwnd(this.Handle);
        gForm.DrawImage(bitmap, 50, 50);

        // 2. Draw cursor directly to a form canvas
        cursor.Draw(gForm, new Rectangle(100, 50, 32, 32));

        cursor.Dispose();
    }

Unfortunately I am unable to render a transparent Cursor to Bitmap! It works when I draw Cursor directly to the form canvas, but there is a problem when I draw Cursor to bitmap.
Any advice is highly appreciated.

alt text

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凑诗 2024-10-14 22:43:28

您现在拥有的解决方案并不完全保留托管代码。您自己的评论表明您正在从 user32.dll P/Invoking LoadCursorFromFile 。无论如何,使用 Win32 API 确实没什么值得害怕的。

正如我在评论中提到的,您尝试执行的操作通常对 GDI+ 绘图函数有问题,就像 .NET Framework 提供的大多数函数一样。使用 GDI 可以使该任务变得更加容易。 您可以使用以下代码从光标(或图标,它们基本上可以互换)创建一个尊重 Alpha 通道的位图:

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

[DllImport("user32")]
private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO pIconInfo);

[DllImport("user32.dll")]
private static extern IntPtr LoadCursorFromFile(string lpFileName);

[DllImport("gdi32.dll", SetLastError = true)]
private static extern bool DeleteObject(IntPtr hObject);

private Bitmap BitmapFromCursor(Cursor cur)
{
    ICONINFO ii;
    GetIconInfo(cur.Handle, out ii);

    Bitmap bmp = Bitmap.FromHbitmap(ii.hbmColor);
    DeleteObject(ii.hbmColor);
    DeleteObject(ii.hbmMask);

    BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
    Bitmap dstBitmap = new Bitmap(bmData.Width, bmData.Height, bmData.Stride, PixelFormat.Format32bppArgb, bmData.Scan0);
    bmp.UnlockBits(bmData);

    return new Bitmap(dstBitmap);
}

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    //Using LoadCursorFromFile from user32.dll, get a handle to the icon
    IntPtr hCursor = LoadCursorFromFile("C:\\Windows\\Cursors\\Windows Aero\\aero_busy.ani");

    //Create a Cursor object from that handle
    Cursor cursor = new Cursor(hCursor);

    //Convert that cursor into a bitmap
    using (Bitmap cursorBitmap = BitmapFromCursor(cursor))
    {
        //Draw that cursor bitmap directly to the form canvas
        e.Graphics.DrawImage(cursorBitmap, 50, 50);
    }
}

如果此代码无法编译,请确保您“为 System.DrawingSystem.Drawing.ImagingSystem.Runtime.InteropServices 添加了 using 语句。另请记住将 Form1_Paint 方法连接为表单 Paint 事件的处理程序。

它经过测试可以正常工作:

cursor,从带有 alpha 通道的位图绘制

The solution you have right now doesn't stay completely with managed code. Your own comment says that you are P/Invoking LoadCursorFromFile from user32.dll. And regardless, using the Win32 API is really nothing that you should be afraid of.

As I mentioned in a comment, what you're trying to do is often problematic with GDI+ drawing functions, like most of those provided by the .NET Framework. The task is made much easier by using GDI instead. You can use the following code to create a bitmap from a cursor (or icon, they're basically interchangeable) that does respect the alpha channel:

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

[DllImport("user32")]
private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO pIconInfo);

[DllImport("user32.dll")]
private static extern IntPtr LoadCursorFromFile(string lpFileName);

[DllImport("gdi32.dll", SetLastError = true)]
private static extern bool DeleteObject(IntPtr hObject);

private Bitmap BitmapFromCursor(Cursor cur)
{
    ICONINFO ii;
    GetIconInfo(cur.Handle, out ii);

    Bitmap bmp = Bitmap.FromHbitmap(ii.hbmColor);
    DeleteObject(ii.hbmColor);
    DeleteObject(ii.hbmMask);

    BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
    Bitmap dstBitmap = new Bitmap(bmData.Width, bmData.Height, bmData.Stride, PixelFormat.Format32bppArgb, bmData.Scan0);
    bmp.UnlockBits(bmData);

    return new Bitmap(dstBitmap);
}

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    //Using LoadCursorFromFile from user32.dll, get a handle to the icon
    IntPtr hCursor = LoadCursorFromFile("C:\\Windows\\Cursors\\Windows Aero\\aero_busy.ani");

    //Create a Cursor object from that handle
    Cursor cursor = new Cursor(hCursor);

    //Convert that cursor into a bitmap
    using (Bitmap cursorBitmap = BitmapFromCursor(cursor))
    {
        //Draw that cursor bitmap directly to the form canvas
        e.Graphics.DrawImage(cursorBitmap, 50, 50);
    }
}

If this code doesn't compile, make sure that you've added using statements for System.Drawing, System.Drawing.Imaging, and System.Runtime.InteropServices. Also remember to wire up the Form1_Paint method as the handler for your form's Paint event.

It is tested to work:

cursor, drawn from bitmap complete with alpha channel

愛放△進行李 2024-10-14 22:43:28

@Cody Gray,这不适用于具有低颜色位的光标。

另一种方法是使用 Icon.ExtractAssociatedIcon 代替:

System.Drawing.Icon i = System.Drawing.Icon.ExtractAssociatedIcon(@"C:\Windows\Cursors\arrow_rl.cur");
System.Drawing.Bitmap b = i.ToBitmap();

希望能帮助某人......

@Cody Gray, That does NOT work with cursors having low color bits.

An alternative is to use Icon.ExtractAssociatedIcon instead:

System.Drawing.Icon i = System.Drawing.Icon.ExtractAssociatedIcon(@"C:\Windows\Cursors\arrow_rl.cur");
System.Drawing.Bitmap b = i.ToBitmap();

Hope that helps someone ...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文