Open DJm00n opened 8 months ago
@Olina-Zhang can your team please verify the issue in later versions?
This issue reproes on .NET 9.0 latest build: 9.0.100-alpha.1.23564.26. Also, as customer said, this is a not regression issue, it reproes both from .NET 5.0 ~ 9.0 and .NET Framework 4.6.2 ~ 4.8.1.
Thanks, I was wondering if we had managed to fix it in recent versions. Looks like not.
This is similar to #9421, where we had issues scaling the icon.
After going over the code, this is by design. GDI+ DrawIcon
handles transparency using a single color marked as transparent.
What is weird is this works:
Cursor cursor = Cursors.AppStarting;
Icon icon = Icon.FromHandle((IntPtr)cursor.Handle);
Bitmap bitmap = new Bitmap(cursor.Size.Width, cursor.Size.Height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bitmap);
g.DrawIcon(icon, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
bitmap.Save(Path.Combine(Directory.GetCurrentDirectory(), "cursor2.png"), ImageFormat.Png);
Icon
uses IntersectClipRect
and DrawIconEx
Cursor
uses DrawIcon
in simple cases and then falls back to IntersectClipRect
and DrawIconEx
.I'll need to debug/investigate more but that is what I have found so far.
@elachlan Graphics.DrawIcon
is clearly contains some kind of workaround (with use of Icon.ToBitmap()
under the hood) for this issue:
It looks like Graphics.FromImage(bitmap);
sets the _backingImage
which is then used in the code you linked.
I can't see an obvious solution in Cursor
because we don't know how Graphics
was created. Graphics g = Graphics.FromImage(bitmap);
basically sets that context.
I guess we could just call the graphics.drawicon
from cursor? or expose a bool indicating if _backingImage
is being used, which we can use to call DrawImage
?
Kind of related: #9879 and #10293
@DJm00n would a new API Cursor.ToBitmap
be a good solution?
Cursors.AppStarting.ToBitmap().Save(Path.Combine(Directory.GetCurrentDirectory(), "cursor2.png"), ImageFormat.Png);
@elachlan I think adding Cursor.ToBitmap
(and fixing Cursor.Draw
?) would be a good solution. Actually most of the cursor and icon code could be merged into one base class since they are working on the same Win32 APIs under the hood. Looks like they are separated by historical reasons.
Adding a Cursor.ToBitmap
seems to fit with the existing Icon.ToBitmap
.
Looking at it a bit it appears DrawIconEx
might do the right thing? DrawIcon
basically does this: DrawIconEx(hdc, x, y, hicon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE );
. DI_COMPAT prevents alpha channel support I believe.
@JeremyKuhne AFAIK DI_COMPAT
does nothing. It was a thing in pre-Windows NT era.
@JeremyKuhne Icon.ToBitmap
is crazy stuff:
I think it implementation could be merged with future Cursor.ToBitmap
.
AFAIK DI_COMPAT does nothing. It was a thing in pre-Windows NT era.
Yeah, I read the code wrong, I don't see it doing anything.
I think it implementation could be merged with future Cursor.ToBitmap.
I wonder if all of that is actually necessary or if there are alternative APIs we can be using. In general, of course, we should not duplicate code.
.NET version
7.0.400
Did it work in .NET Framework?
No
Did it work in any of the earlier releases of .NET Core or .NET 5+?
No response
Issue description
Curosor.Draw
draws with broken alpha channel: Result: Expected:Also reported here more that 10 years ago: https://stackoverflow.com/questions/4451839/how-to-render-a-transparent-cursor-to-bitmap-preserving-alpha-channel
Steps to reproduce
This code with
Icon.FromHandle
andIcon.ToBitmap
works as expected: