4 Replies - 316 Views - Last Post: 06 January 2012 - 05:34 PM Rate Topic: -----

#1 shadowevil  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 48
  • Joined: 12-August 10

Form background with per-pixel alpha?

Posted 06 January 2012 - 09:42 AM

Is it possible to create an irregular window with per pixel alpha so that it
blends in to the desktop at the edges? I've managed to create an irregular
from using the colour-keyed TransparentColour property, but this leaves it
with a hard aliased edge.

I found something, but this is what I get:

Posted Image

Of course I have buttons, and other things behind what you see there. But It doesn't want to show correctly. Any fix for this, would be amazing. I think it's because I'm only alpha'ing the background image, which loads it ontop of everything. But again, I have no clue on how to alpha JUST the background, and keep it as a background.

My code for Per-Pixel-Alpha:

        class Win32
        {
            public enum Bool
            {
                False = 0,
                True
            };


            [StructLayout(LayoutKind.Sequential)]
            public struct Point
            {
                public Int32 x;
                public Int32 y;

                public Point(Int32 x, Int32 y) { this.x = x; this.y = y; }
            }


            [StructLayout(LayoutKind.Sequential)]
            public struct Size
            {
                public Int32 cx;
                public Int32 cy;

                public Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; }
            }


            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            struct ARGB
            {
                public byte Blue;
                public byte Green;
                public byte Red;
                public byte Alpha;
            }


            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct BLENDFUNCTION
            {
                public byte BlendOp;
                public byte BlendFlags;
                public byte SourceConstantAlpha;
                public byte AlphaFormat;
            }

            public const Int32 WS_EX_LAYERED = 0x80000;
            public const Int32 ULW_COLORKEY = 0x00000001;
            public const Int32 ULW_ALPHA = 0x00000002;
            public const Int32 ULW_OPAQUE = 0x00000004;

            public const byte AC_SRC_OVER = 0x00;
            public const byte AC_SRC_ALPHA = 0x01;


            [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

            [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern IntPtr GetDC(IntPtr hWnd);

            [DllImport("user32.dll", ExactSpelling = true)]
            public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool DeleteDC(IntPtr hdc);

            [DllImport("gdi32.dll", ExactSpelling = true)]
            public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

            [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
            public static extern Bool DeleteObject(IntPtr hObject);
        }

        protected void OnPaintBackground(Bitmap bitmap, byte opacity)
        {
            if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
                throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");

            // The ideia of this is very simple,
            // 1. Create a compatible DC with screen;
            // 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
            // 3. Call the UpdateLayeredwindow.

            IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
            IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
            IntPtr hBitmap = IntPtr.Zero;
            IntPtr oldBitmap = IntPtr.Zero;

            try
            {
                hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));  // grab a GDI handle from this GDI+ bitmap
                oldBitmap = Win32.SelectObject(memDc, hBitmap);

                Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
                Win32.Point pointSource = new Win32.Point(0, 0);
                Win32.Point topPos = new Win32.Point(Left, Top);
                Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
                blend.BlendOp = Win32.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = opacity;
                blend.AlphaFormat = Win32.AC_SRC_ALPHA;

                Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);
            }
            finally
            {
                Win32.ReleaseDC(IntPtr.Zero, screenDc);
                if (hBitmap != IntPtr.Zero)
                {
                    Win32.SelectObject(memDc, oldBitmap);
                    //Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak.
                    Win32.DeleteObject(hBitmap);
                }
                Win32.DeleteDC(memDc);
            }
        }

        protected override CreateParams CreateParams
        {
            get
            {
                // Add the layered extended style (WS_EX_LAYERED) to this window
                CreateParams createParams = base.CreateParams;
                createParams.ExStyle |= Win32.WS_EX_LAYERED;
                return createParams;
            }
        }

        private void main_Load(object sender, EventArgs e)
        {
            OnPaintBackground(Properties.Resources.Background, 255);
        }




Is This A Good Question/Topic? 0
  • +

Replies To: Form background with per-pixel alpha?

#2 ragingben  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 170
  • View blog
  • Posts: 637
  • Joined: 07-October 08

Re: Form background with per-pixel alpha?

Posted 06 January 2012 - 09:44 AM

This is do-able in WPF, I'm really not sure how easy with WinForms though as I have never used WinForms much. Is WPF an option?
Was This Post Helpful? 0
  • +
  • -

#3 RexGrammer  Icon User is offline

  • Coding Dynamo
  • member icon

Reputation: 182
  • View blog
  • Posts: 783
  • Joined: 27-October 11

Re: Form background with per-pixel alpha?

Posted 06 January 2012 - 10:46 AM

Sure you can. You can set the TransparencyKey property of the form to a color you want, and then create a image with that color in PS (or your image editor of choice). Then set that image as the background image of the form.
Was This Post Helpful? -1
  • +
  • -

#4 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4531
  • View blog
  • Posts: 7,903
  • Joined: 08-June 10

Re: Form background with per-pixel alpha?

Posted 06 January 2012 - 01:26 PM

Rex, did you even bother reading the second sentence of the question?
Was This Post Helpful? 0
  • +
  • -

#5 shadowevil  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 48
  • Joined: 12-August 10

Re: Form background with per-pixel alpha?

Posted 06 January 2012 - 05:34 PM

Yeah. I think it's a later thing. It's rendering the background image above everything. :/

The above code works flawlessly. Does what I want it to do. But it renders the background above everything. Even though I can still click the buttons under it.

This post has been edited by shadowevil: 06 January 2012 - 05:40 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1