Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>A while ago, I read this problem arises out of a requirement for pre-multiplied alpha channels in the bitmaps. I'm not sure if this was an issue with Windows cursors or GDI, and for the life of me, I cannot find documentation regarding this. So, while this explanation may or may not be correct, the following code does indeed do what you want, using a pre-multiplied alpha channel in the cursor bitmap.</p> <pre><code>public class CustomCursor { // alphaLevel is a value between 0 and 255. For 50% transparency, use 128. public Cursor CreateCursorFromBitmap(Bitmap bitmap, byte alphaLevel, Point hotSpot) { Bitmap cursorBitmap = null; External.ICONINFO iconInfo = new External.ICONINFO(); Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height); try { // Here, the premultiplied alpha channel is specified cursorBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppPArgb); // I'm assuming the source bitmap can be locked in a 24 bits per pixel format BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); BitmapData cursorBitmapData = cursorBitmap.LockBits(rectangle, ImageLockMode.WriteOnly, cursorBitmap.PixelFormat); // Use either SafeCopy() or UnsafeCopy() to set the bitmap contents SafeCopy(bitmapData, cursorBitmapData, alphaLevel); //UnsafeCopy(bitmapData, cursorBitmapData, alphaLevel); cursorBitmap.UnlockBits(cursorBitmapData); bitmap.UnlockBits(bitmapData); if (!External.GetIconInfo(cursorBitmap.GetHicon(), out iconInfo)) throw new Exception("GetIconInfo() failed."); iconInfo.xHotspot = hotSpot.X; iconInfo.yHotspot = hotSpot.Y; iconInfo.IsIcon = false; IntPtr cursorPtr = External.CreateIconIndirect(ref iconInfo); if (cursorPtr == IntPtr.Zero) throw new Exception("CreateIconIndirect() failed."); return (new Cursor(cursorPtr)); } finally { if (cursorBitmap != null) cursorBitmap.Dispose(); if (iconInfo.ColorBitmap != IntPtr.Zero) External.DeleteObject(iconInfo.ColorBitmap); if (iconInfo.MaskBitmap != IntPtr.Zero) External.DeleteObject(iconInfo.MaskBitmap); } } private void SafeCopy(BitmapData srcData, BitmapData dstData, byte alphaLevel) { for (int y = 0; y &lt; srcData.Height; y++) for (int x = 0; x &lt; srcData.Width; x++) { byte b = Marshal.ReadByte(srcData.Scan0, y * srcData.Stride + x * 3); byte g = Marshal.ReadByte(srcData.Scan0, y * srcData.Stride + x * 3 + 1); byte r = Marshal.ReadByte(srcData.Scan0, y * srcData.Stride + x * 3 + 2); Marshal.WriteByte(dstData.Scan0, y * dstData.Stride + x * 4, b); Marshal.WriteByte(dstData.Scan0, y * dstData.Stride + x * 4 + 1, g); Marshal.WriteByte(dstData.Scan0, y * dstData.Stride + x * 4 + 2, r); Marshal.WriteByte(dstData.Scan0, y * dstData.Stride + x * 4 + 3, alphaLevel); } } private unsafe void UnsafeCopy(BitmapData srcData, BitmapData dstData, byte alphaLevel) { for (int y = 0; y &lt; srcData.Height; y++) { byte* srcRow = (byte*)srcData.Scan0 + (y * srcData.Stride); byte* dstRow = (byte*)dstData.Scan0 + (y * dstData.Stride); for (int x = 0; x &lt; srcData.Width; x++) { dstRow[x * 4] = srcRow[x * 3]; dstRow[x * 4 + 1] = srcRow[x * 3 + 1]; dstRow[x * 4 + 2] = srcRow[x * 3 + 2]; dstRow[x * 4 + 3] = alphaLevel; } } } } </code></pre> <p>The pinvoke declarations are found in the External class, shown here:</p> <pre><code>public class External { [StructLayout(LayoutKind.Sequential)] public struct ICONINFO { public bool IsIcon; public int xHotspot; public int yHotspot; public IntPtr MaskBitmap; public IntPtr ColorBitmap; }; [DllImport("user32.dll")] public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo); [DllImport("user32.dll")] public static extern IntPtr CreateIconIndirect([In] ref ICONINFO piconinfo); [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); [DllImport("gdi32.dll")] public static extern IntPtr CreateBitmap(int nWidth, int nHeight, uint cPlanes, uint cBitsPerPel, IntPtr lpvBits); } </code></pre> <p>A few notes on the code:</p> <ol> <li>To use the unsafe method, UnsafeCopy(), you must compile with the /unsafe flag.</li> <li>The bitmap copying methods are ugly, especially the safe method, which uses Marshal.ReadByte()/Marshal.WriteByte() calls. There must be a faster way to copy bitmap data while also inserting alpha bytes.</li> <li>I do assume that the source bitmap is able to be locked in a 24 bits per pixel format. This should not be a problem, though.</li> </ol>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload