如何在c#中创建多个图像的透明背景

我有一个窗体forms的图像集合,并希望使它们’非矩形’ – 即透明背景。

但是,使用transparencyKey ,是的都会松开它们的背景颜色。 但是,我任何时候都只能看到一个而不是另一个(取决于哪个是“带来了前方”)。

有没有办法在表格上显示两个图像,都是“非矩形”,两者都有透明背景?

请注意:我设法让背景变得透明( TransparencyKey设置为gray (RGB of 66,66,66) ,两个图像都具有相同的背景。

我听说过“ regions ”一词,但从我所知道的情况来看,这通常是CPU上非常“重”的方式。

任何建议都非常感谢并乐于回答任何澄清问题(因为我不善于解释自己)。

注意。 我试图实现的“效果”类似于项目启动时开启的X战警门 – 我的桌面就在后面。

“leftDoor”向左移动,“rightDoor”向右移动

此尝试使用UpdateLayeredWindow API: http : //msdn.microsoft.com/en-us/library/ms997507.aspx#layerwin_topic2a

我从Corylulu激发了我的实现: https ://stackoverflow.com/a/8809657/1812199

这两个位图是动态创建的,但您可以从文件系统或其他任何位置加载它们。

叠加窗口当前遍布整个主屏幕,但您也可以选择将表单的位置和大小设置为您需要的任何内容(例如,在另一个表单的顶部)。

我为两个位图实现了一个非常基本的动画,但是你要比我更有创意:)

 using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Windows.Forms; namespace StackOverflow25400312 { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); var bounds = Screen.PrimaryScreen.Bounds; var imagesSize = new Size(bounds.Width * 2 / 3, bounds.Height); var left = LoadLeftDoorTransparentPng(imagesSize); var right = LoadRightDoorTransparentPng(imagesSize); // Create a form with same dimension as the screen. var form = new OverlayForm(left, right, bounds); Application.Run(form); } private static Image GenerateImage(GraphicsPath path, Size sz) { var bitmap = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb); var graphics = Graphics.FromImage(bitmap); graphics.Clear(Color.Transparent); graphics.FillPath(Brushes.Red, path); return bitmap; } private static Image LoadRightDoorTransparentPng(Size sz) { int w = sz.Width; int h = sz.Height; var path = new GraphicsPath(); path.AddLines(new[] { new Point(w / 2, 0), new Point(w, 0), new Point(w, h), new Point(w / 2, h), new Point(0, h / 2), }); // I will generate it by code but you should use Bitmap.FromFile(...) return GenerateImage(path, sz); } private static Image LoadLeftDoorTransparentPng(Size sz) { int w = sz.Width; int h = sz.Height; var path = new GraphicsPath(); path.AddLines(new[] { new Point(0, 0), new Point(w, 0), new Point(w / 2, h / 2), new Point(w, h), new Point(0, h), }); // I will generate it by code but you should use Bitmap.FromFile(...) return GenerateImage(path, sz); } } public class OverlayForm : Form { public const int WS_EX_NOACTIVATE = 0x08000000; public const int WS_EX_TOOLWINDOW = 0x00000080; public const int WS_EX_TOPMOST = 0x00000008; public const int WS_EX_LAYERED = 0x00080000; public const int WS_EX_TRANSPARENT = 0x00000020; [DllImport("gdi32.dll")] public static extern bool DeleteDC(IntPtr hdc); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetDC(IntPtr hWnd); [DllImport("gdi32.dll", SetLastError = true)] public static extern IntPtr CreateCompatibleDC(IntPtr hdc); [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); [DllImport("user32.dll")] public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); [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 pptSrc, uint crKey, [In] ref BLENDFUNCTION pblend, uint dwFlags); public const int ULW_ALPHA = 2; [StructLayout(LayoutKind.Sequential)] public struct SIZE { public int cx; public int cy; public SIZE(int cx, int cy) { this.cx = cx; this.cy = cy; } } [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; public POINT(int x, int y) { this.X = x; this.Y = y; } public POINT(System.Drawing.Point pt) : this(pt.X, pt.Y) { } public static implicit operator System.Drawing.Point(POINT p) { return new System.Drawing.Point(pX, pY); } public static implicit operator POINT(System.Drawing.Point p) { return new POINT(pX, pY); } } [StructLayout(LayoutKind.Sequential)] public struct BLENDFUNCTION { public byte BlendOp; public byte BlendFlags; public byte SourceConstantAlpha; public byte AlphaFormat; public BLENDFUNCTION(byte op, byte flags, byte alpha, byte format) { BlendOp = op; BlendFlags = flags; SourceConstantAlpha = alpha; AlphaFormat = format; } } public const int AC_SRC_OVER = 0x00; public const int AC_SRC_ALPHA = 0x01; private readonly Image _left; private readonly Image _right; private readonly Bitmap _backBuffer; private readonly Timer _timer; private int _offset; public OverlayForm(Image left, Image right, Rectangle bounds) { _left = left; _right = right; _backBuffer = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); _timer = new Timer(); _offset = 0; Bounds = bounds; FormBorderStyle = FormBorderStyle.None; StartPosition = FormStartPosition.Manual; ShowInTaskbar = false; } protected override bool ShowWithoutActivation { get { return true; } } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= WS_EX_LAYERED; // This form has to have the WS_EX_LAYERED extended style cp.ExStyle |= WS_EX_TRANSPARENT; // Click through. cp.ExStyle |= WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST; return cp; } } protected override void OnLoad(EventArgs e) { base.OnLoad(e); _timer.Interval = 16; _timer.Tick += _timer_Tick; _timer.Start(); } private void UpdateLayeredWindow() { using (Graphics g = Graphics.FromImage(_backBuffer)) { g.Clear(Color.Transparent); g.DrawImage(_left, 0 - _offset, 0); g.DrawImage(_right, Width - _right.Width + _offset, 0); SetBitmap(_backBuffer); } } private void SetBitmap(Bitmap bitmap) { // 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 = GetDC(IntPtr.Zero); IntPtr memDc = 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 = SelectObject(memDc, hBitmap); SIZE size = new SIZE(bitmap.Width, bitmap.Height); POINT pointSource = new POINT(0, 0); POINT topPos = new POINT(Left, Top); BLENDFUNCTION blend = new BLENDFUNCTION(); blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; blend.SourceConstantAlpha = 255; blend.AlphaFormat = AC_SRC_ALPHA; bool fail = UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, ULW_ALPHA); } finally { ReleaseDC(IntPtr.Zero, screenDc); if (hBitmap != IntPtr.Zero) { SelectObject(memDc, oldBitmap); DeleteObject(hBitmap); } DeleteDC(memDc); } } void _timer_Tick(object sender, EventArgs e) { int distance = _left.Width - _offset; // Is animation done? if (distance == 0) { _timer.Stop(); Close(); return; } // Step forward. // You can replace with any easing function of your choice, // but this one works well usually. int step = distance / 9; // Help it a little when the animation is about to end. if (step == 0) step = distance; _offset += step; UpdateLayeredWindow(); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { _left.Dispose(); _right.Dispose(); _backBuffer.Dispose(); _timer.Dispose(); } } } } 

看看这个 ! 这是一个不同的问题,但在那里张贴的图像上,你可以看到三个不同的图像,所有图像之间以及背景之间都是透明的。

您可以通过覆盖面板的某些方法来解决它,如下所示:

 abstract public class DrawingArea : Panel { protected Graphics graphics; abstract protected void OnDraw(); protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x00000020; return cp; } } protected override void OnPaintBackground(PaintEventArgs pevent) { } protected override void OnPaint(PaintEventArgs e) { this.graphics = e.Graphics; this.graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; this.graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear; this.graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; this.graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; OnDraw(); } } 

并且您可以重复使用此“DrawingArea”类将其扩展到您的门或您想要的任何类型的透明图像,例如以下示例:

 public class TransparentImage : DrawingArea { private bool draw = false; private Image Imagem; public Image imagem { get { return Imagem; } set { Imagem = value; draw = true; this.Size = Imagem.Size; } } protected override void InitLayout() { this.BringToFront(); } public TransparentImage() { } protected override void OnDraw() { if (draw) { Rectangle location = new Rectangle(0, 0, Imagem.Width, Imagem.Height); this.graphics.DrawImage(Imagem, location); } } } 

此“transparentImage”将作为组件显示在工具箱窗口中,以便您可以从那里实例化它。

在门打开/关闭动画时,您可能会发现一些闪烁,因此,建议使用双缓冲来平滑动画。

绝对winforms不是最好的做法,我可以通过我自己的错误说:)

看起来你正在寻找一个简单的解决方案。

看一下这个post: C#WinForms的透明图像

为了以“简单”的方式达到最终效果,我想你应该做到以下几点

1 – 您需要制作一个加载全屏的新的启动画面。 在您的主窗体上,在加载表单时,您可以将此启动画面窗体显示为“模态”窗体。

2 – 尝试覆盖OnPaintBackground以便不为背景绘制任何内容。

  protected override void OnPaintBackground(PaintEventArgs e) { //Do not paint background } 

3 – 放置图像并随着时间的推移产生效果。 看看我在顶部发布的链接。 它可能有助于制作透明图像,如果它是你的烦恼。

4 – 在动画结束时,启动画面会自动卸载。