窗体的TransparencyKey留下令人难以置信的彩色边缘

当使用TransparencyKey制作透明表格并将带有透明像素的PNG放置为背景图像时,PNG图像的大部分图像轮廓上的色边不雅观(尤其是用于还要设置表单透明度键...就我而言(洋红色)。

我已经尝试了几个小时了,但也找不到解决方法。
几乎起作用的是使用具有不同TransparencyKey颜色的多个Forms,并且如果该像素与另一种Forms中的颜色或位置不匹配,则逐像素匹配Forms,如果存在匹配项,则将其排除在外。在新表格上逐像素写入。

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

如何解决此问题?

shaouwu 回答:窗体的TransparencyKey留下令人难以置信的彩色边缘

此代码是对此处找到的代码的翻译(略有解释):
Windows Form Transparent Background Image
最初来自Microsoft示例代码库(至少在他们杀死它之前)。


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

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

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

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

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 8+:顶级窗口和子窗口支持WS_EX_LAYERED样式。以前的Windows版本仅在顶级窗口中支持此样式。

要绘制可以与背景混合的位图,请在“窗口设备上下文”中选择一个位图,然后调用UpdateLayeredWindow,并使用BLENDFUNCTION结构指定渲染的类型。
此结构允许定义( BlendOp )源位图和目标位图的混合方式(实际上,唯一可能的操作是Source Over, AC_SRC_OVER ),应用于源位图的不透明度级别( SourceConstantAlpha 255 =不透明,0 =完全透明)以及源的颜色和颜色目标位图被解释( AlphaFormat )。

在这里,我们要混合具有Alpha通道(每个像素alpha)的源位图,因此它是半透明的:我们将 AC_SRC_ALPHA 指定为{{1} }(请参阅有关基于源bItmap的颜色类型如何解释颜色融合的文档)。

仅此而已。

要构建分层表单,请向项目中添加新表单,如此处所示更改构造方法,添加AlphaFormat替代,如果可以移动表单并将其拖动,请添加CreateParams替代。 WndProc 方法调用,该方法将激活源位图(在构造函数中传递)和窗体的DC的Alpha混合。
另外,将SelectBitmap()支持类添加到项目中:

►可以像往常一样创建Form,在这种情况下,将Bitmap对象传递给其构造函数:
(位图格式必须为32位NativeMethods-具有{alpha通道的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,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 支持类别:

NativeMethods

您可以从Google云端硬盘下载Sample Project
内置.Net Framework 4.7.2-其他任何4.5.2+框架都可以实现

本文链接:https://www.f2er.com/2646434.html

大家都在问