2010-12-15 67 views
9

J'utilise le code ci-dessous pour rendre une icône transparente:Comment rendre un curseur transparent à Bitmap préservant le canal alpha?

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(); 
    } 

Malheureusement, je suis incapable de rendre un curseur transparent pour Bitmap! Cela fonctionne quand je dessine le Curseur directement au canevas de forme, mais il y a un problème quand je dessine le Curseur au bitmap. Tout conseil est fortement apprécié.

alt text

+0

Oui, GDI + a des problèmes connus en préservant le canal alpha lors de l'élaboration des icônes. Peut-être que quelqu'un connaît une solution de contournement, mais je soupçonne que la meilleure façon d'aller ici est d'utiliser GDI à la place. –

+0

Hmm ... C'est dommage, parce que je voudrais rester avec le code managé. Savez-vous, si Windows 7 utilise encore GDI, rendre les curseurs de transparence? –

+2

semble familier. L'attribution est requise ici. Vous pourriez effectivement obtenir une meilleure réponse si vous prenez soin de cela. –

Répondre

8

La solution que vous avez en ce moment ne reste pas complètement avec le code managé. Votre propre commentaire dit que vous appelez LoadCursorFromFile depuis user32.dll. Et peu importe, en utilisant l'API Win32 est vraiment rien que vous devriez avoir peur de.

Comme je l'ai mentionné dans un commentaire, ce que vous essayez de faire est souvent problématique avec les fonctions de dessin GDI +, comme la plupart de celles fournies par le .NET Framework. La tâche est rendue beaucoup plus facile en utilisant GDI à la place. Vous pouvez utiliser le code suivant pour créer un bitmap à partir d'un curseur (ou l'icône, ils sont essentiellement interchangeables) qui ne respecte le canal 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); 
    } 
} 

Si ce code ne compile pas, assurez-vous que vous avez ajouté using instructions pour System.Drawing, System.Drawing.Imaging et System.Runtime.InteropServices. N'oubliez pas de câbler la méthode Form1_Paint en tant que gestionnaire de l'événement Paint de votre formulaire.

Il est testé pour fonctionner:

cursor, drawn from bitmap complete with alpha channel

+0

Cody, merci beaucoup! Travaillez comme un charme! –

+0

Salut génial morceau de code là-bas. Quand j'appelle BitmapFromCursor, j'obtiens une erreur "Une erreur générique s'est produite dans GDI +". sur la ligne "Bitmap bmp = Bitmap.FromHbitmap (ii.hbmColor);". Quelqu'un sait ce qui pourrait le causer et comment le réparer? – Neaox

+0

Ok, donc j'ai compris que ii.hbmColor renvoie un pointeur nul. Quelqu'un sait pourquoi cela pourrait être et comment le réparer? – Neaox

2

@Cody Gray, cela ne fonctionne pas avec les curseurs ayant de faibles bits de couleur.

Une alternative est d'utiliser à la place Icon.ExtractAssociatedIcon:

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

espoir qui aide quelqu'un ...