Windows窗体:使光标位图部分透明 [英] Windows Forms: Making a cursor bitmap partially transparent

查看:290
本文介绍了Windows窗体:使光标位图部分透明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用拖/放操作部分透明​​的图像。这是所有的设置和工作正常,但实际转换透明度有一个奇怪的副作用。由于某些原因,象素似乎在黑色背景被混合。



下图说明了问题:





图一)是原始位图。



图b)是已执行alpha混合后生产什么。显然,这是比预期的预期50%的α-滤波器变暗了许多。



图c)为所期望的效果,图像),用50%的透明度(加入到组合物与绘图程序)



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

 位图bmpNew =新位图(bmpOriginal.Width,bmpOriginal.Height); 
图形G = Graphics.FromImage(bmpNew);

//使得位50%透明:
浮法[] [] = ptsArray {
新的浮动[] {1,0,0,0,0},/ /红
新的浮动[] {0,1,0,0,0},//绿
新的浮动[] {0,0,1,0,0},//蓝
新浮[] {0,0,0,0.5F,0},//阿尔法
新的浮动[] {0,0,0,0,1} //亮度
};
嘉洛斯clrMatrix =新嘉洛斯(ptsArray);
ImageAttributes imgAttributes =新ImageAttributes();
imgAttributes.SetColorMatrix(clrMatrix,ColorMatrixFlag.Default,ColorAdjustType.Bitmap);
g.DrawImage(bmpOriginal,新矩形(0,0,bmpOriginal.Width,bmpOriginal.Height),0,0,bmpOriginal.Width,bmpOriginal.Height,GraphicsUnit.Pixel,imgAttributes);
Cursors.Default.Draw(G,新的Rectangle(bmpOriginal.Width / 2 - 8 bmpOriginal.Height / 2 - 8,32,32));
g.Dispose();
imgAttributes.Dispose();
返回bmpNew;



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



更新我:



为了清楚起见,该代码没有工作,如果我alphablending在绘制表面的顶部。问题是,我想从现有图像创建完全半透明图像,并以此作为在拖/放操作动态游标。甚至跳过上述和只画色填充矩形88ffffff产生暗灰色颜色。 。有鬼是怎么回事的图标



更新二:



由于我reseached一大堆,相信这一定是与光标创作,我会在下面包含太多的代码。如果只有CreateIconIndirect调用之前我GetPixel样品位图,四个颜色值似乎是完整的。因此我有一种感觉,匪徒可能是hbmColor或ICONINFO结构的hbmMask成员



这里的ICONINFO结构:

 公共结构ICONINFO {// http://msdn.microsoft.com/en-us/library/ms648052(VS.85).aspx 
公共BOOL FICON; //图标或光标。真=图标,假=光标
公众诠释xHotspot;
公众诠释yhotspot光标;
公众的IntPtr hbmMask; //指定图标掩码位图。如果该结构限定了黑色和白色的图标,
//这个掩码被格式化,使得上半部是图标和掩码和下部
//一半是图标的XOR位掩码。在此条件下,该高度应该是偶数倍的两项。
//如果这个结构定义了一个色图标,这个面具只定义图标的AND位掩码。
公众的IntPtr hbmColor; //处理的图标颜色位图。如果这个结构定义了一个黑色的
//白色图标这个成员可以是可选的。 hbmMask的AND掩码施加与SRCAND标志到目的地; //随后,彩色位图是通过使用SRCINVERT标志施加(使用异或)到目的地


}

这是实际创建光标的代码:

 公共静态光标CreateCursor(BMP位图,诠释xHotSpot,诠释yhotspot光标){
ICONINFO ICONINFO =新ICONINFO();
的GetIconInfo(bmp.GetHicon(),REF ICONINFO);
iconInfo.hbmColor =(IntPtr的)0;
iconInfo.hbmMask = bmp.GetHbitmap();
iconInfo.xHotspot = xHotSpot;
iconInfo.yHotspot = yhotspot光标;
iconInfo.fIcon = FALSE;

返回新光标(CreateIconIndirect(REF ICONINFO));
}



两个外部函数定义如下:



 函数[DllImport(user32.dll中,入口点=CreateIconIndirect)] 
公共静态外部的IntPtr CreateIconIndirect(REF ICONINFO图标);

函数[DllImport(user32.dll中)]
[返回:的MarshalAs(UnmanagedType.Bool)
公共静态外部布尔的GetIconInfo(IntPtr的惠康,楼盘ICONINFO pIconInfo);


解决方案

GDI +有许多相关的alpha混合时的问题与GDI(和Win32)互操作做。在这种情况下,调用bmp.GetHbitmap()将与黑色背景融为一体你的形象。在CodeProject 的文章对这个问题更多的细节,以及用于将图像添加到一个解决方案。图像列表



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

 函数[DllImport(KERNEL32.DLL)] 
公共静态外部布尔RtlMoveMemory(IntPtr的DEST,IntPtr的来源,INT dwcount);
函数[DllImport(GDI32.DLL)]
公共静态外部的IntPtr CreateDIBSection(IntPtr的HDC,[在,的MarshalAs(UnmanagedType.LPStruct)BITMAPINFO PBMI,UINT iUsage,出的IntPtr ppvBits,IntPtr的hSection, UINT dwOffset);

公共静态的IntPtr GetBlendedHBitmap(位图位图)
{
BITMAPINFO BITMAPINFO =新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,出PixelData取出,IntPtr.Zero,0);

矩形范围=新的Rectangle(0,0,bitmap.Width,bitmap.Height);
的BitmapData位图数据= bitmap.LockBits(
界,ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);
RtlMoveMemory(
PixelData取出,bitmapData.Scan0,bitmap.Height * bitmapData.Stride);

bitmap.UnlockBits(位图数据);
返回HBITMAP;
}


I want to use partially transparent images in drag/drop operations. This is all set up and works fine, but the actual transformation to transparency has a weird side effect. For some reason, the pixels seem to be blended against a black background.

The following image describes the problem:

Figure a) is the original bitmap.

Figure b) is what is produced after alpha blending has been performed. Obviously this is a lot darker than the intended 50% alpha filter intended.

Figure c) is the desired effect, image a) with 50% transparency (added to the composition with a drawing program).

The code I use to produce the trasparent image is the following:

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;

Does anyone know why the alpha blending does not work?

Update I:

For clarity, the code does work if I'm alphablending on top of a drawn surface. The problem is that I want to create a completely semitransparent image from an existing image and use this as a dynamic cursor during drag/drop operations. Even skipping the above and only painting a filled rectangle of color 88ffffff yields a dark grey color. Something fishy is going on with the icon.

Update II:

Since I've reseached a whole lot and believe this has got something to do with the Cursor creation, I'm gonna include that code below too. If I GetPixel-sample the bitmap just before the CreateIconIndirect call, the four color values seem to be intact. Thus I have a feeling the culprits might be the hbmColor or the hbmMask members of the IconInfo structure.

Here's the IconInfo structure:

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. 

}

And here is the code that actually creates the 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));
    }

The two external functions are defined as follows:

    [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);

解决方案

GDI+ has a number of problems related to alpha blending when doing interop with GDI (and Win32). In this case, the call to bmp.GetHbitmap() will blend your image with a black background. An article on CodeProject gives more detail on the problem, and a solution that was used for adding images to an image list.

You should be able to use similar code to get the HBITMAP to use for the mask:

[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;
}

这篇关于Windows窗体:使光标位图部分透明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆