【问题标题】:Saving PNG from VB.NET Messes up Shadows从 VB.NET 保存 PNG 会弄乱阴影
【发布时间】:2014-07-20 23:44:14
【问题描述】:

我一直在尝试解决 .NET(所有版本)本身不支持 TRUE 透明度的古老问题,在阅读了数千篇文章、问题/答案、论坛、msdn 文章等之后,却一无所获除了能够通过使用整个表单来做到这一点,其中没有可见的控件(参见http://www.codeproject.com/Articles/1822/Per-Pixel-Alpha-Blend-in-C

我已经部分放弃了这种搜索,而是决定通过使用每个图形/文本直接绘制到表单上的 MDIParent/Client 情况来满足。

我遇到的问题是,当我保存透明度时,我最终会在任何阴影周围出现一个斑点,我认为(但不确定)是 PNG 正在以较低的分辨率保存或丢失Alpha 通道或其他东西,MakeTransparent(在此处插入颜色),只是不满意。如果你能说明这个过程哪里出了这么严重的错误……请告诉我。

输入图片

输出图像

我使用的代码如下:

    Imports Graphics

    Public Class PictureForm
        Private Declare Auto Function BitBlt Lib "gdi32.dll" (ByVal _
            hdcDest As IntPtr, ByVal nXDest As Integer, ByVal _
            nYDest As Integer, ByVal nWidth As Integer, ByVal _
            nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc _
            As Integer, ByVal nYSrc As Integer, ByVal dwRop As  _
            System.Int32) As Boolean
        Private Const SRCCOPY As Integer = &HCC0020

        Public Graphic As Drawing.Graphics
        Private Sub PictureForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Show()
            Graphic = Me.CreateGraphics
            Graphic.CompositingQuality = Drawing2D.CompositingQuality.HighQuality

            Graphic.DrawImage(Image.FromFile("C:\Users\Daniel\Downloads\PNG-icon.png"), 35, 22)

            Dim bmp As Bitmap = GetFormImage()
            bmp.MakeTransparent(Color.White)
            bmp.Save("test.png", System.Drawing.Imaging.ImageFormat.Png)
            bmp.Dispose()       

        End Sub

        Public Function GetFormImage() As Bitmap
            ' Get this form's Graphics object.
            Dim me_gr As Drawing.Graphics = Me.CreateGraphics

            ' Make a Bitmap to hold the image.
            Dim bm As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height, me_gr)
            Dim bm_gr As Drawing.Graphics = Drawing.Graphics.FromImage(bm)
            Dim bm_hdc As IntPtr = bm_gr.GetHdc

            ' Get the form's hDC. We must do this after 
            ' creating the new Bitmap, which uses me_gr.
            Dim me_hdc As IntPtr = me_gr.GetHdc

            ' BitBlt the form's image onto the Bitmap.
            BitBlt(bm_hdc, 0, 0, Me.ClientSize.Width, _
                Me.ClientSize.Height, _
                me_hdc, 0, 0, SRCCOPY)
            me_gr.ReleaseHdc(me_hdc)
            bm_gr.ReleaseHdc(bm_hdc)

            ' Return the result.
            Return bm
        End Function

    End Class

此外,您会注意到第一张图像中的字母在输出中没有被渲染为透明。

【问题讨论】:

  • 当您绘制到表单时,您将具有表单背景色(我猜是白色)的源图像合并到 PNG 的透明部分中,从而生成一个新图像。阴影结果不是白色或灰色,而是混合(RGB(234...239, 239, 239)),所以MakeTransparent(White) 不起作用。它确实适用于白色的字母。将 PNG 图像放入图片框并从那里编辑/保存(不需要 NativeMetods),它工作正常。保存的图像大小不同,但没有您显示的任何工件。
  • 这个想法是能够有多个层,我可以四处移动。由于无法消除的人造背景,PictureBox 不允许这样做。我确实看到了一个很好的 bitblt 工作示例,它消除了所有透明区域并使用了表单的图像区域,它显示了相反的证据,即实际上可以清除所有透明区域。此外,即使我将背景设置为蓝色,我仍然会得到那个白色的斑点。清除字母表明我没有使用通常存储在 png 中的颜色索引。我不知道怎么做。
  • 您没有使用图层 - 您将 PNG 与表单合并。 PNG 的透明度允许表单 BG 颜色成为 PNG 的一部分。 BitBlt 无法从表格中分辨出原件,因为您制作了它们。
  • 是的,最终保存的是表单内容的 BitBlt,但是这似乎是使用透明度分层多个图像的唯一方法 --- 在设计模式下,每个层都是可移动的/等(如 Photoshop)。上面的代码被缩短以演示问题。我很想问如何对无限数量的图片框进行分层,但是每个人的问题一直被标记为“已解决”,声称解决方案在这里>>stackoverflow.com/questions/395256/…
  • 让我发疯的是,我可以在 VB6 中做到这一点,但是 VS2012 仍然在伪造它 --- 人们声称使用 WPF 是多么容易,但 WPF 甚至没有一个PictureBox ...更不用说,您不能简单地双击该项目以转到它的代码...并且没有Form_Load事件等等等等。太可怕了。我正在考虑改用 Delphi。

标签: vb.net transparency gdi+ alphablending bitblt


【解决方案1】:

问题是您将图形“存储”在表单上 - 不存在 alpha。

您可以通过保留一个屏幕外位图来轻松解决此问题,您可以在该位图上进行所有绘画,并且在修改它时,您也可以将其绘制到表单中。

那么您将不再需要 GetFormImage 方法 - 您只需直接保存屏幕外位图(其中包含 alpha 信息)。

PS。您缺少几个 .Dispose() 调用。

【讨论】:

  • 问题实际上在于使用 BitBlt 捕获矩形区域的内容 - 就像屏幕截图 - 然后使一种颜色透明 - 在此过程中不保留逐像素的 alpha。图形本身实际上不在表单上,​​它位于表单上的“图形”对象内。我很快就会发布另一个确实需要解决方案的问题(上述问题已经通过不使用 BitBlt 并通过创建矩形大小的新图形对象并将图形复制到它然后保存来直接操作图形对象来解决)
  • 图形对象不能包含任何内容。它用于在 CAN 包含图形的某些东西上执行绘图。通常是位图或窗体/面板。在表单上,​​不存在 alpha 信息。
猜你喜欢
  • 2021-07-15
  • 1970-01-01
  • 1970-01-01
  • 2022-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-17
相关资源
最近更新 更多