在没有任何事情之前,我会注意到我接受了C#或VB.Net解决方案。用Lockbits替换图像的颜色
我有这样的老代码,我试图重构避免使用GetPixel
/SetPixel
方法的坏习惯所和性能效率低下:
<Extension>
Public Function ChangeColor(ByVal sender As Image,
ByVal oldColor As Color,
ByVal newColor As Color) As Image
Dim bmp As New Bitmap(sender.Width, sender.Height, sender.PixelFormat)
Dim x As Integer = 0
Dim y As Integer = 0
While (x < bmp.Width)
y = 0
While y < bmp.Height
If DirectCast(sender, Bitmap).GetPixel(x, y) = oldColor Then
bmp.SetPixel(x, y, newColor)
End If
Math.Max(Threading.Interlocked.Increment(y), y - 1)
End While
Math.Max(Threading.Interlocked.Increment(x), x - 1)
End While
Return bmp
End Function
因此,使用阅读的是投票的解决方案here后LockBits
的做法,我想代码适应我的需要,使用Color
作为参数,而不是一个字节序列(因为在本质上是相同的):
<Extension>
Public Function ChangeColor(ByVal sender As Image,
ByVal oldColor As Color,
ByVal newColor As Color) As Image
Dim bmp As Bitmap = DirectCast(sender.Clone, Bitmap)
' Lock the bitmap's bits.
Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height)
Dim bmpData As BitmapData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat)
' Get the address of the first line.
Dim ptr As IntPtr = bmpData.Scan0
' Declare an array to hold the bytes of the bitmap.
Dim numBytes As Integer = (bmpData.Stride * bmp.Height)
Dim rgbValues As Byte() = New Byte(numBytes - 1) {}
' Copy the RGB values into the array.
Marshal.Copy(ptr, rgbValues, 0, numBytes)
' Manipulate the bitmap.
For i As Integer = 0 To rgbValues.Length - 1 Step 3
If (Color.FromArgb(rgbValues(i), rgbValues(i + 1), rgbValues(i + 2)) = oldColor) Then
rgbValues(i) = newColor.R
rgbValues(i + 1) = newColor.G
rgbValues(i + 2) = newColor.B
End If
Next i
' Copy the RGB values back to the bitmap.
Marshal.Copy(rgbValues, 0, ptr, numBytes)
' Unlock the bits.
bmp.UnlockBits(bmpData)
Return bmp
End Function
我有两个扩展方法的问题,首先是,如果像素格式不是Format24bppRgb
作为原始示例,然后全部出错,在循环中引发IndexOutOfRange
异常,我想这是因为我正在读取3个字节( RGB)而不是4(ARGB),但我不知道如何适应它可以传递给函数的任何源像素格式。
Secondlly的是,如果我使用Format24bppRgb
为原来的C#示例,颜色变为黑色。
请注意,我不知道,如果在C#中的问题给出的原始的解决方案,我联系是错误的,因为按他们的意见似乎是错误的某种方式。
这是我想要使用它的方式:
' This function creates a bitmap of a solid color.
Dim srcImg As Bitmap = ImageUtil.CreateSolidcolorBitmap(New Size(256, 256), Color.Red)
Dim modImg As Image = srcImg.ChangeColor(Color.Red, Color.Blue)
PictureBox1.BackgroundImage = srcImg
PictureBox2.BackgroundImage = modImg
所以我添加了1,4,8,24和32 bpp像素格式的示例。当然,您也可以计算15/16/64和其他格式的颜色。我在这里使用了不安全的方法,但是您可以使用'Marshal.Copy'通过使用托管数组来复制数据。 – taffer