使所有渐变为白色渐变为透明

时间:2014-09-10 20:44:54

标签: transparency gdi+ system.drawing colormatrix

我试图获得一个打开现有图像并使其透明的高效代码。问题是,我希望所有可能的颜色都是渐变到白色的渐变到透明。我已经和Color Matrix玩了一下但是失败了......所以我做了很多可能完全不必要的东西。我的解决方案如下。

1)打开现有文件。

2)从源

创建一个灰度的新图像

3)反转灰度

4)将红色值应用于反转灰度图像中的alpha,每像素一个像素到新图像。其他RGB值将从原始文件中释放出来。 (对不起我的草率功能......只需要做一个快速测试,看看是否可能)

这在某种程度上很好用,除了处理更大的图像(大约3500x2000像素)需要很多时间它是否可以用ColorMatrix直接执行此操作以跳过每像素进程的像素?还是有其他方法吗?我一直在考虑屏蔽等,但没有任何经验。

由于使用灰度作为输入,当前代码也会使其他颜色比黑色略微透明(不太强烈)。

'VB.NET
Imports System.Drawing
Imports System.Drawing.Imaging

Module Module1

Sub Main()
    Dim args() As String = Environment.GetCommandLineArgs
    Dim Path As String = String.Empty

    If args.Count = 2 Then
        Path = args(1)
    End If

    Try
        Dim image1 As Bitmap = CType(Image.FromFile(Path, True), Bitmap)
        Dim image2 As New Bitmap(image1.Width, image1.Height)

        Dim g As Graphics = Graphics.FromImage(image2)

        Dim myColorMatrix As New ColorMatrix
        Dim invColor As New ColorMatrix

        Dim imageAttr As New ImageAttributes

        myColorMatrix.Matrix00 = 0.3F
        myColorMatrix.Matrix01 = 0.3F
        myColorMatrix.Matrix02 = 0.3F

        myColorMatrix.Matrix10 = 0.59F
        myColorMatrix.Matrix11 = 0.59F
        myColorMatrix.Matrix12 = 0.59F

        myColorMatrix.Matrix20 = 0.11F
        myColorMatrix.Matrix21 = 0.11F
        myColorMatrix.Matrix22 = 0.11F

        myColorMatrix.Matrix33 = 1.0
        myColorMatrix.Matrix44 = 1.0

        imageAttr.SetColorMatrix(myColorMatrix, ColorAdjustType.Default, ColorAdjustType.Default)
        g.DrawImage(image1, New Rectangle(0, 0, image1.Width, image1.Height), 0, 0, image1.Width, image1.Height, GraphicsUnit.Pixel, imageAttr)

        invColor.Matrix00 = -1
        invColor.Matrix11 = -1
        invColor.Matrix22 = -1
        invColor.Matrix33 = 1
        invColor.Matrix44 = 1
        invColor.Matrix40 = 1
        invColor.Matrix41 = 1
        invColor.Matrix42 = 1

        imageAttr.SetColorMatrix(invColor, ColorAdjustType.Default, ColorAdjustType.Default)
        g.DrawImage(image2, New Rectangle(0, 0, image1.Width, image1.Height), 0, 0, image1.Width, image1.Height, GraphicsUnit.Pixel, imageAttr)

        Dim myColor As New Color
        Dim x As Integer = 0
        Dim y As Integer = 0
        Dim myAlpha As Integer = 0
        Dim orgColor(2) As Integer

        Do Until y = image1.Height
            Do Until x = image1.Width
                'Get alpha
                myAlpha = toRGB(image2.GetPixel(x, y))

                orgColor = currentRGB(image1.GetPixel(x, y))

                myColor = Color.FromArgb(myAlpha, orgColor(0), orgColor(1), orgColor(2))

                image2.SetPixel(x, y, myColor)
                x = x + 1
            Loop
            x = 0
            y = y + 1
        Loop

        image2.Save("C:\test\transparent.png", ImageFormat.Png)

        image1.Dispose()
        image2.Dispose()
        g.Dispose()

    Catch ex As System.IO.FileNotFoundException
        MsgBox(ex.ToString & vbNewLine & " There was an error opening the bitmap." _
            & "Please check the path.")
    End Try

End Sub
Private Function toRGB(ByVal Color As Color) As Integer
    Dim r As Integer
    r = Color.R
    Return r
End Function
Private Function currentRGB(ByRef color As Color) As Array
    Dim currRGB(2) As Integer
    currRGB(0) = color.R
    currRGB(1) = color.G
    currRGB(2) = color.B
    Return currRGB
End Function
End Module

2 个答案:

答案 0 :(得分:1)

您可以使用system()让ImageMagick为您执行此操作。它是免费的here

它还提供Windows .NET绑定 - 请参阅here,这样您就可以直接从程序中调用ImageMagick的库函数,而无需system()

我认为您尝试做的事情可以在命令行中完成:

convert input.bmp \( +clone -colorspace gray \) -alpha off -compose copy_opacity -composite output.png

我在图像3500x2000上对上面进行了基准测试,需要0.8秒 - 不知道与你的代码相比是否有任何好处!

答案 1 :(得分:1)

这是完全未经测试的代码(我甚至不知道它是否正确编译),但它应该让你知道如何尽可能快地完成它(当然不使用GPU):< / p>

public static void AlphaGray(
    Bitmap bmp,
    int threshold )
{
    Rectangle r = new Rectangle( Point.Empty, bmp.Size );
    BitmapData bd = bmp.LockBits( r, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb );
    unsafe
    {
        byte* p = (byte*)bd.Scan0.ToPointer();
        for ( int i = r.Height * r.Width; i > 0; i--, p +=4 )
        {
            var avg = (p[0] + p[1] + p[2]) /3;
            var bx = p[0] - avg; 
            var gx = p[1] - avg; 
            var rx = p[2] - avg; 
            if( bx*bx + gx*gx + rx*rx < threshold )
                p[3] = (byte)avg;
        }
    }
    bmp.UnlockBits( bd );
}