Windows窗体:使光标位图部分透明

Ped*_*ery 8 c# gdi+ alphablending cursor winforms

我想在拖放操作中使用部分透明的图像.这一切都已设置并且工作正常,但实际转换为透明度有一个奇怪的副作用.出于某种原因,像素似乎与黑色背景混合.

下图描述了该问题:

透明度问题

图a)是原始位图.

图b)是在执行α混合之后产生的.显然,这比预期的50%α滤镜要暗很多.

图c)是所需的效果,图像a)具有50%的透明度(用绘图程序添加到组合物中).

我用来生成trasparent图像的代码如下:

Bitmap bmpNew = new Bitmap(bmpOriginal.Width, bmpOriginal.Height);
Graphics g = Graphics.FromImage(bmpNew);

// Making the bitmap 50% transparent:
float[][] ptsArray ={ 
    new float[] {1, 0, 0, 0, 0},        // Red
    new float[] {0, 1, 0, 0, 0},        // Green
    new float[] {0, 0, 1, 0, 0},        // Blue
    new float[] {0, 0, 0, 0.5f, 0},     // Alpha
    new float[] {0, 0, 0, 0, 1}         // Brightness
};
ColorMatrix clrMatrix = new ColorMatrix(ptsArray);
ImageAttributes imgAttributes = new ImageAttributes();
imgAttributes.SetColorMatrix(clrMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
g.DrawImage(bmpOriginal, new Rectangle(0, 0, bmpOriginal.Width, bmpOriginal.Height), 0, 0, bmpOriginal.Width, bmpOriginal.Height, GraphicsUnit.Pixel, imgAttributes);
Cursors.Default.Draw(g, new Rectangle(bmpOriginal.Width / 2 - 8, bmpOriginal.Height / 2 - 8, 32, 32));
g.Dispose();
imgAttributes.Dispose();
return bmpNew;
Run Code Online (Sandbox Code Playgroud)

有谁知道为什么alpha混合不起作用?

更新I:

为清楚起见,如果我在绘制表面上进行alpha混合,代码确实有效.问题是我想从现有图像创建一个完全半透明的图像,并在拖放操作期间将其用作动态光标.即使跳过上面的内容,只绘制一个颜色为88ffffff的填充矩形,也会产生深灰色.图标上出现了一些可疑的东西.

更新II:

由于我已经研究了很多并且相信这与Cursor创建有关,我也将在下面包含该代码.如果我在CreateIconIndirect调用之前对Getmap进行位图采样,则四个颜色值似乎完好无损.因此,我有一种感觉,罪魁祸首可能是IconInfo结构的hbmColor或hbmMask成员.

这是IconInfo结构:

public struct IconInfo {    // http://msdn.microsoft.com/en-us/library/ms648052(VS.85).aspx
    public bool fIcon;      // Icon or cursor. True = Icon, False = Cursor
    public int xHotspot;
    public int yHotspot;
    public IntPtr hbmMask;  // Specifies the icon bitmask bitmap. If this structure defines a black and white icon, 
                            // this bitmask is formatted so that the upper half is the icon AND bitmask and the lower 
                            // half is the icon XOR bitmask. Under this condition, the height should be an even multiple of two. 
                            // If this structure defines a color icon, this mask only defines the AND bitmask of the icon.
    public IntPtr hbmColor; // Handle to the icon color bitmap. This member can be optional if this structure defines a black 
                            // and white icon. The AND bitmask of hbmMask is applied with the SRCAND flag to the destination; 
                            // subsequently, the color bitmap is applied (using XOR) to the destination by using the SRCINVERT flag. 

}
Run Code Online (Sandbox Code Playgroud)

这是实际创建Cursor的代码:

    public static Cursor CreateCursor(Bitmap bmp, int xHotSpot, int yHotSpot) {
        IconInfo iconInfo = new IconInfo();
        GetIconInfo(bmp.GetHicon(), ref iconInfo);
        iconInfo.hbmColor = (IntPtr)0;
        iconInfo.hbmMask = bmp.GetHbitmap();
        iconInfo.xHotspot = xHotSpot;
        iconInfo.yHotspot = yHotSpot;
        iconInfo.fIcon = false;

        return new Cursor(CreateIconIndirect(ref iconInfo));
    }
Run Code Online (Sandbox Code Playgroud)

两个外部函数定义如下:

    [DllImport("user32.dll", EntryPoint = "CreateIconIndirect")]
    public static extern IntPtr CreateIconIndirect(ref IconInfo icon);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
Run Code Online (Sandbox Code Playgroud)

Chr*_*ler 6

当与GDI(和Win32)进行互操作时,GDI +有许多与alpha混合相关的问题.在这种情况下,对bmp.GetHbitmap()的调用将使您的图像与黑色背景混合.有关CodeProject文章提供了有关该问题的更多详细信息,以及用于将图像添加到图像列表的解决方案.

您应该能够使用类似的代码来获取HBITMAP用于掩码:

[DllImport("kernel32.dll")]
public static extern bool RtlMoveMemory(IntPtr dest, IntPtr source, int dwcount);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDIBSection(IntPtr hdc, [In, MarshalAs(UnmanagedType.LPStruct)]BITMAPINFO pbmi, uint iUsage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);

public static IntPtr GetBlendedHBitmap(Bitmap bitmap)
{
    BITMAPINFO bitmapInfo = new BITMAPINFO();
    bitmapInfo.biSize = 40;
    bitmapInfo.biBitCount = 32;
    bitmapInfo.biPlanes = 1;

    bitmapInfo.biWidth = bitmap.Width;
    bitmapInfo.biHeight = -bitmap.Height;

    IntPtr pixelData;
    IntPtr hBitmap = CreateDIBSection(
        IntPtr.Zero, bitmapInfo, 0, out pixelData, IntPtr.Zero, 0);

    Rectangle bounds = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
    BitmapData bitmapData = bitmap.LockBits(
        bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb );
    RtlMoveMemory(
        pixelData, bitmapData.Scan0, bitmap.Height * bitmapData.Stride);

    bitmap.UnlockBits(bitmapData);
    return hBitmap;
}
Run Code Online (Sandbox Code Playgroud)