Form的TransparencyKey留下可怕的边缘

问题描述 投票:0回答:1

[当使用TransparencyKey制作透明表格并将带有透明像素的PNG放置为背景图像时,PNG图像在其大部分图像轮廓上都有难看的彩色边缘(尤其是用于设置表格的颜色透明度键...在我的情况下(洋红色)。

我也尝试了好几个小时,但也没有找到解决方案。几乎起作用的是使用具有不同TransparencyKey颜色的多个窗体,并且如果该像素与其他窗体之一中的颜色或位置不匹配,则逐个像素地匹配窗体,如果存在匹配则将其排除在外而将其写入像素在新表格上按像素排列。

这不是完美的,但是非常接近。但是,此方法花费了2.5个小时,对于处理一个小的徽标来说,这太长了。

如何解决此问题?

vb.net winforms transparency
1个回答
2
投票
此代码是此处找到的代码的翻译版本(带有少量解释):Windows Form Transparent Background Image。最初来自Microsoft示例代码库(至少在他们杀死它之前)。


将窗体呈现为透明时,请将其

TransparencyKey设置为与BackGroundColor相同的颜色,然后在窗体的透明表面上绘制半透明的位图,位图的锯齿部分不会与Form后面的任何内容混合。用作TransparencyKey的颜色可能会影响渲染结果,但是半透明像素(尤其是位图边缘附近的像素)将始终在不同背景上可见,因为没有blending。

要解决该问题,我们可以构建一个Layered Window

系统会自动组成和重新绘制分层的窗口,基础应用程序的窗口。结果,分层的窗口是平滑呈现,没有复杂窗口典型的闪烁地区。此外,分层窗口可以是部分半透明的,也就是alpha混合。

要创建分层表单,我们可以设置WS_EX_LAYERED扩展样式来覆盖表单的WS_EX_LAYERED属性:

CreateParams

Windows 8+:顶层窗口和子窗口支持Protected Overrides ReadOnly Property CreateParams As CreateParams Get Dim parms As CreateParams = MyBase.CreateParams parms.ExStyle = parms.ExStyle Or WS_EX_LAYERED Return parms End Get End Property 样式。以前的Windows版本仅对顶级窗口支持此样式。

要绘制可以与背景混合的位图,我们在窗口设备上下文中选择一个位图,然后调用WS_EX_LAYERED,并使用UpdateLayeredWindow结构指定渲染的类型。此结构允许定义(

[BLENDFUNCTION)源位图和目标位图如何混合(实际上,唯一可能的操作是Source Over,BLENDFUNCTION),即应用于源的不透明度级别位图(BlendOpAC_SRC_OVER =不透明,SourceConstantAlpha =完全透明)以及如何解释源位图和目标位图的颜色(255)。

[这里,我们要混合具有Alpha通道(按像素alpha)的源位图,因此它是半透明的:我们将

0

指定为AlphaFormat(请参阅有关颜色如何显示的文档混合将根据源bItmap的“颜色”类型进行解释。 就这些。

[要构建分层表单,将新表单添加到项目,更改构造器,如下所示,添加AC_SRC_ALPHA替代,如果可以移动拖动表单,则添加AlphaFormat替代,并

CreateParams

方法调用,该方法激活源位图(在构造函数中传递)和窗体的DC的Alpha混合。另外,将WndProc支持类添加到项目中:►可以像往常一样创建Form,在这种情况下,将Bitmap对象传递给其构造函数:(位图格式必须为32位SelectBitmap()-具有alpha通道的NativeMethods可以))

ARGB

PNG

[Dim layeredForm As New PerPixelAlphaLayeredForm(bitmap) layeredForm.Show()

支持类别:
Public Class PerPixelAlphaLayeredForm Public Sub New() Me.New(Nothing) End Sub Public Sub New(bitmap As Bitmap) InitializeComponent() Me.LayerBitmap = bitmap End Sub Private ReadOnly Property LayerBitmap As Bitmap Protected Overrides Sub OnLoad(e As EventArgs) MyBase.OnLoad(e) If Me.LayerBitmap IsNot Nothing Then Me.ClientSize = Me.LayerBitmap.Size Dim screenSize = Screen.FromHandle(Me.Handle).Bounds.Size Me.Location = New Point((screenSize.Width - Me.Width) \ 2, (screenSize.Height - Me.Height) \ 2) SelectBitmap(Me.LayerBitmap) ' Or, call the SelectBitmapFadeOut() method ' Task.Run(Function() SelectBitmapFadeOut(Me.LayerBitmap)) End If Me.TopMost = True End Sub Private Sub SelectBitmap(bitmap As Bitmap) NativeMethods.SelectBitmapToLayeredWindow(Me, bitmap, 255) End Sub Private Async Function SelectBitmapFadeOut(bitmap As Bitmap) As Task Dim fadeProgress As Integer = 255 For i = fadeProgress To 1 Step -1 BeginInvoke(New MethodInvoker(Sub() NativeMethods.SelectBitmapToLayeredWindow(Me, bitmap, fadeProgress))) fadeProgress -= 1 Await Task.Delay(10) Next End Function Protected Overrides ReadOnly Property CreateParams As CreateParams Get Dim parms As CreateParams = MyBase.CreateParams If Not DesignMode Then parms.ExStyle = parms.ExStyle Or NativeMethods.WS_EX_LAYERED Return parms End Get End Property Protected Overrides Sub WndProc(ByRef m As Message) If m.Msg = NativeMethods.WM_NCHITTEST Then m.Result = New IntPtr(NativeMethods.HTCAPTION) Else MyBase.WndProc(m) End If End Sub End Class

您可以从Google云端硬盘下载NativeMethods

内置.Net Framework 4.7.2-其他任何4.5.2+框架都可以使用

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.