'i00 .Net Image Filters
'©i00 Productions All rights reserved
'Created by Kris Bennett
'----------------------------------------------------------------------------------------------------
'All property in this file is and remains the property of i00 Productions, regardless of its usage,
'unless stated otherwise in writing from i00 Productions.
'
'i00 is not and shall not be held accountable for any damages directly or indirectly caused by the
'use or miss-use of this product. This product is only a component and thus is intended to be used
'as part of other software, it is not a complete software package, thus i00 Productions is not
'responsible for any legal ramifications that software using this product breaches.
Public Module ext_ImageFilters
<System.Runtime.CompilerServices.Extension()> _
Public Function Filters(ByVal b As Bitmap) As ImageFilter
Return New ImageFilter(b)
End Function
Public Class ImageFilter
Dim b As Bitmap
Public Sub New(ByVal b As Bitmap)
Me.b = b
End Sub
Public Shared Sub ConvertToSupportLockBits(ByRef b As Bitmap)
Dim bClone As New Bitmap(b.Width, b.Height, Imaging.PixelFormat.Format32bppArgb)
Using g = Graphics.FromImage(bClone)
b.SetResolution(96, 96)
g.DrawImage(b, Point.Empty)
End Using
b.Dispose()
b = bClone
End Sub
Public Shared Function SupportsLockBits(ByVal b As Bitmap) As Boolean
Return Bitmap.GetPixelFormatSize(b.PixelFormat) = 32 AndAlso b.PixelFormat <> Imaging.PixelFormat.Indexed
End Function
#Region "Bitmap Data"
Private Class BitmapData
Public Bitmap As Bitmap
Public ByteData As Byte()
Public BitmapData As Imaging.BitmapData
Private Sub New()
End Sub
Public Shared Function LockBits(ByVal b As Bitmap) As BitmapData
If SupportsLockBits(b) = False Then
Throw New Exception("Your bitmap must be 32bit non-indexed in order to apply filters")
End If
LockBits = New BitmapData
LockBits.Bitmap = b
Dim bmpRect As New Rectangle(0, 0, b.Width, b.Height)
ReDim LockBits.ByteData(b.Width * b.Height * 4 - 1)
LockBits.BitmapData = b.LockBits(bmpRect, Imaging.ImageLockMode.ReadWrite, b.PixelFormat)
System.Runtime.InteropServices.Marshal.Copy(LockBits.BitmapData.Scan0, LockBits.ByteData, 0, LockBits.ByteData.Length)
End Function
Public Sub UnlockBits()
System.Runtime.InteropServices.Marshal.Copy(Me.ByteData, 0, Me.BitmapData.Scan0, Me.ByteData.Length)
Me.Bitmap.UnlockBits(Me.BitmapData)
End Sub
Public Function YFromOffset(ByVal Offset As Integer) As Integer
Return CInt(Int(Offset / (Bitmap.Width * 4)))
End Function
Public Function StartOfLineFromOffset(ByVal Offset As Integer) As Integer
Return Offset - (Offset Mod (Bitmap.Width * 4))
End Function
End Class
#End Region
Public Sub Invert()
Dim bData = BitmapData.LockBits(b)
For i = LBound(bData.ByteData) To UBound(bData.ByteData)
Select Case i Mod 4
Case 0, 1, 2 'blue, green, red
bData.ByteData(i) = CByte(255 - bData.ByteData(i))
Case 3 'alpha
End Select
Next
bData.UnlockBits()
End Sub
Public Sub GausianBlur(Optional ByVal Amount As Integer = 4)
Dim bData = BitmapData.LockBits(b)
Dim OutBytes As Byte()
ReDim OutBytes(bData.ByteData.Count - 1)
For ii = LBound(bData.ByteData) To UBound(bData.ByteData) Step 4
'find the average color of the area around the pixel...
Dim cR As Integer = 0
Dim cG As Integer = 0
Dim cB As Integer = 0
Dim cA As Integer = 0
Dim PixelCounter As Integer = 0
Dim YLine = bData.YFromOffset(ii)
For iY = Math.Max(YLine - Int(Amount / 2), 0) To Math.Min(YLine + Int(Amount / 2), bData.Bitmap.Height - 1)
Dim StartOfLine As Integer = bData.StartOfLineFromOffset(CInt(iY * (bData.Bitmap.Width * 4)))
Dim EndOfLine As Integer = StartOfLine + ((bData.Bitmap.Width * 4) - 1)
Dim ThisX = ii + ((iY - YLine) * (bData.Bitmap.Width * 4))
For iX As Integer = CInt(Math.Max(ThisX - (Int(Amount / 2) * 4), StartOfLine)) To CInt(Math.Min((ThisX + (Int(Amount / 2) * 4)) - 1, EndOfLine))
Select Case iX Mod 4
Case 0 'blue
cB += bData.ByteData(iX)
Case 1 'green
cG += bData.ByteData(iX)
Case 2 'red
cR += bData.ByteData(iX)
Case 3 'alpha
cA += bData.ByteData(iX)
PixelCounter += 1
End Select
Next
Next
OutBytes(ii) = CByte(cB / PixelCounter) 'blue
OutBytes(ii + 1) = CByte(cG / PixelCounter) 'green
OutBytes(ii + 2) = CByte(cR / PixelCounter) 'red
OutBytes(ii + 3) = CByte(cA / PixelCounter) 'alpha
Next
bData.ByteData = OutBytes
bData.UnlockBits()
End Sub
Public Sub Alpha(Optional ByVal Alpha As Byte = 127)
Dim cm As New System.Drawing.Imaging.ColorMatrix
cm.Matrix33 = CSng(Alpha / 255)
Using ia As New System.Drawing.Imaging.ImageAttributes
ia.SetColorMatrix(cm)
Dim rc As New Rectangle(0, 0, b.Width, b.Height)
Using bClone As Bitmap = DirectCast(b.Clone, Bitmap)
Using g As Graphics = Graphics.FromImage(b)
g.Clear(Color.Transparent)
g.DrawImage(bClone, rc, 0, 0, bClone.Width, bClone.Height, GraphicsUnit.Pixel, ia)
End Using
End Using
End Using
End Sub
Public Sub GrayScale()
Dim cm As New System.Drawing.Imaging.ColorMatrix(New Single()() _
{New Single() {0.299, 0.299, 0.299, 0, 0}, _
New Single() {0.587, 0.587, 0.587, 0, 0}, _
New Single() {0.114, 0.114, 0.114, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
Using ia As New System.Drawing.Imaging.ImageAttributes
ia.SetColorMatrix(cm)
Dim rc As New Rectangle(0, 0, b.Width, b.Height)
Using bClone As Bitmap = DirectCast(b.Clone, Bitmap)
Using g As Graphics = Graphics.FromImage(b)
g.Clear(Color.Transparent)
g.DrawImage(bClone, rc, 0, 0, bClone.Width, bClone.Height, GraphicsUnit.Pixel, ia)
End Using
End Using
End Using
End Sub
Private Function BlendByte(ByVal From As Byte, ByVal [To] As Byte, ByVal Amount As Byte) As Byte
Return CByte(((CInt([To]) - [From]) * (Amount / 255)) + [From])
End Function
Public Sub AlphaMask(ByVal AlphaColor As Color, ByVal SolidColor As Color)
Dim bData = BitmapData.LockBits(b)
For i = LBound(bData.ByteData) To UBound(bData.ByteData) Step 4
Dim AlphaByte = bData.ByteData(i + 3)
bData.ByteData(i) = BlendByte(AlphaColor.B, SolidColor.B, AlphaByte) 'blue
bData.ByteData(i + 1) = BlendByte(AlphaColor.G, SolidColor.G, AlphaByte) 'green
bData.ByteData(i + 2) = BlendByte(AlphaColor.R, SolidColor.R, AlphaByte) 'red
bData.ByteData(i + 3) = BlendByte(AlphaColor.A, SolidColor.A, AlphaByte) 'alpha
Next
bData.UnlockBits()
End Sub
Public Sub Brightness(Optional ByVal amount As Single = 0)
If amount = 0 Then Return
Dim bData = BitmapData.LockBits(b)
If amount > 0 Then
For i = LBound(bData.ByteData) To UBound(bData.ByteData) Step 4
bData.ByteData(i) = CByte(bData.ByteData(i) + (amount * (255 - bData.ByteData(i)))) 'blue
bData.ByteData(i + 1) = CByte(bData.ByteData(i + 1) + (amount * (255 - bData.ByteData(i + 1)))) 'green
bData.ByteData(i + 2) = CByte(bData.ByteData(i + 2) + (amount * (255 - bData.ByteData(i + 2)))) 'red
Next
Else
For i = LBound(bData.ByteData) To UBound(bData.ByteData) Step 4
bData.ByteData(i) = CByte(bData.ByteData(i) - (Math.Abs(amount) * bData.ByteData(i))) 'blue
bData.ByteData(i + 1) = CByte(bData.ByteData(i + 1) - (Math.Abs(amount) * bData.ByteData(i + 1))) 'green
bData.ByteData(i + 2) = CByte(bData.ByteData(i + 2) - (Math.Abs(amount) * bData.ByteData(i + 2))) 'red
Next
End If
bData.UnlockBits()
End Sub
Public Sub [Static](Optional ByVal Amount As Integer = 4)
Dim bData = BitmapData.LockBits(b)
'create a random order that we will use to step through the pixels...
'this is used to prevent image "shifting"
Randomize()
Dim RndPixelOrder = (From xItem In Enumerable.Range(0, CInt(UBound(bData.ByteData) / 4)) Select xItem * 4 Order By Rnd()).ToArray
For Each item In RndPixelOrder
'get a random pixel around the area specified from the pixel and swap it...
Dim iY = bData.YFromOffset(item)
Dim rY = (iY - CInt(Amount / 2)) + Int((Amount + 1) * Rnd())
rY = Math.Max(0, rY)
rY = Math.Min(bData.Bitmap.Height - 1, rY)
'rX is the real offset where as Y is the nice offset
Dim rX As Integer = CInt((Int((Rnd() * (Amount + 1 + (Amount Mod 2)))) * 4) - (CInt(Amount + (Amount Mod 2)) * 2))
rX = item + rX
Dim StartOfLine As Integer = bData.StartOfLineFromOffset(item)
Dim EndOfLine As Integer = StartOfLine + ((bData.Bitmap.Width - 1) * 4)
rX = Math.Max(StartOfLine, rX)
rX = Math.Min(EndOfLine, rX)
rX += CInt((bData.Bitmap.Width * 4) * (rY - iY))
Dim Hold As Byte
'b
Hold = bData.ByteData(item)
bData.ByteData(item) = bData.ByteData(rX)
bData.ByteData(rX) = Hold
'g
Hold = bData.ByteData(item + 1)
bData.ByteData(item + 1) = bData.ByteData(rX + 1)
bData.ByteData(rX + 1) = Hold
'r
Hold = bData.ByteData(item + 2)
bData.ByteData(item + 2) = bData.ByteData(rX + 2)
bData.ByteData(rX + 2) = Hold
'a
Hold = bData.ByteData(item + 3)
bData.ByteData(item + 3) = bData.ByteData(rX + 3)
bData.ByteData(rX + 3) = Hold
Next
bData.UnlockBits()
End Sub
Private Sub Clear()
Dim bData = BitmapData.LockBits(b)
Dim OutBytes As Byte()
ReDim OutBytes(bData.ByteData.Count - 1)
bData.ByteData = OutBytes
bData.UnlockBits()
End Sub
Public Sub DropShadow(ByVal ShadowColor As Color, ByVal Depth As Point, Optional ByVal BlurAmount As Integer = 4)
'copy the origional image...
Using bCloneShadow = DirectCast(b.Clone, Bitmap)
Using bImage = DirectCast(b.Clone, Bitmap)
'clear image
Clear()
'draw the shadow
Using g = Graphics.FromImage(b)
bCloneShadow.Filters.AlphaMask(Color.Transparent, ShadowColor)
bCloneShadow.Filters.GausianBlur(BlurAmount)
g.DrawImage(bCloneShadow, Depth)
End Using
'draw the item
Using g = Graphics.FromImage(b)
g.DrawImage(bImage, Point.Empty)
End Using
End Using
End Using
End Sub
Public Sub Emboss()
Dim bData = BitmapData.LockBits(b)
Const Level1 As Byte = 127
Const Level2 As Byte = 255
For ii = LBound(bData.ByteData) To UBound(bData.ByteData) Step 4
If (ii + 4) Mod (bData.Bitmap.Width * 4) = 0 Then
'right line - make gray
bData.ByteData(ii) = Level1 'b
bData.ByteData(ii + 1) = Level1 'g
bData.ByteData(ii + 2) = Level1 'r
Continue For
End If
Dim iY = bData.YFromOffset(ii)
If iY = bData.Bitmap.Height - 1 Then
'bottom line - make gray
bData.ByteData(ii) = Level1 'b
bData.ByteData(ii + 1) = Level1 'g
bData.ByteData(ii + 2) = Level1 'r
Continue For
End If
Dim OffsetPixelPointer = ii + ((bData.Bitmap.Width + 1) * 4)
bData.ByteData(ii) = CByte(Math.Min(Math.Abs(CInt(bData.ByteData(ii)) - CInt(bData.ByteData(OffsetPixelPointer))) + Level1, Level2)) 'b
bData.ByteData(ii + 1) = CByte(Math.Min(Math.Abs(CInt(bData.ByteData(ii + 1)) - CInt(bData.ByteData(OffsetPixelPointer + 1))) + Level1, Level2)) 'g
bData.ByteData(ii + 2) = CByte(Math.Min(Math.Abs(CInt(bData.ByteData(ii + 2)) - CInt(bData.ByteData(OffsetPixelPointer + 2))) + Level1, Level2)) 'r
'bData.ByteData(ii + 3) = 255 'a
Next
bData.UnlockBits()
End Sub
'This code for HSL is an adaptation of "Hue Saturation Lightness Filter" by Miran.Uhan
'The origional project can be found @ http://www.codeproject.com/KB/graphics/HSL_Filter.aspx
Public Sub HSL(Optional ByVal hue As Single = 0, Optional ByVal sat As Single = 0, Optional ByVal lum As Single = 0)
Const c1o60 As Double = 1 / 60
Const c1o255 As Double = 1 / 255
If hue < 0 Then
hue = (hue + ((Int(Math.Abs(hue) / 360) + 1) * 360)) Mod 360
Else
hue = hue Mod 360
End If
sat = sat * 255
lum = lum * 255
Dim bData = BitmapData.LockBits(Me.b)
Dim f1, f2 As Double
Dim R, G, B As Double
Dim H, S, L, H1 As Double
Dim v1, v2, v3 As Double
Dim dif, min, sum As Double
For ii = LBound(bData.ByteData) To UBound(bData.ByteData) Step 4
R = bData.ByteData(ii + 2)
G = bData.ByteData(ii + 1)
B = bData.ByteData(ii)
min = R
If (G < min) Then min = G
If (B < min) Then min = B
Dim max As Double = R : f1 = 0.0 : f2 = G - B
If (G > max) Then
max = G : f1 = 120.0 : f2 = B - R
End If
If (B > max) Then
max = B : f1 = 240.0 : f2 = R - G
End If
dif = max - min
sum = max + min
L = 0.5 * sum
If (dif = 0) Then
H = 0.0 : S = 0.0
Else
If (L < 127.5) Then
S = 255.0 * dif / sum
Else
S = 255.0 * dif / (510.0 - sum)
End If
H = (f1 + 60.0 * f2 / dif)
If H < 0.0 Then H += 360.0
If H >= 360.0 Then H -= 360.0
End If
'transformation
H = H + hue
If H >= 360.0 Then H = H - 360.0
S = S + sat
If S < 0.0 Then S = 0.0
If S > 255.0 Then S = 255.0
L = L + lum
If L < 0.0 Then L = 0.0
If L > 255.0 Then L = 255.0
'back to RGB
If (S = 0) Then
R = L : G = L : B = L
Else
If (L < 127.5) Then
v2 = c1o255 * L * (255 + S)
Else
v2 = L + S - c1o255 * S * L
End If
v1 = 2 * L - v2
v3 = v2 - v1
H1 = H + 120.0
If (H1 >= 360.0) Then H1 -= 360.0
If (H1 < 60.0) Then
R = v1 + v3 * H1 * c1o60
ElseIf (H1 < 180.0) Then
R = v2
ElseIf (H1 < 240.0) Then
R = v1 + v3 * (4 - H1 * c1o60)
Else
R = v1
End If
H1 = H
If (H1 < 60.0) Then
G = v1 + v3 * H1 * c1o60
ElseIf (H1 < 180.0) Then
G = v2
ElseIf (H1 < 240.0) Then
G = v1 + v3 * (4 - H1 * c1o60)
Else
G = v1
End If
H1 = H - 120.0
If (H1 < 0.0) Then H1 += 360.0
If (H1 < 60.0) Then
B = v1 + v3 * H1 * c1o60
ElseIf (H1 < 180.0) Then
B = v2
ElseIf (H1 < 240.0) Then
B = v1 + v3 * (4 - H1 * c1o60)
Else
B = v1
End If
End If
'set new colors
bData.ByteData(ii + 2) = CByte(R)
bData.ByteData(ii + 1) = CByte(G)
bData.ByteData(ii) = CByte(B)
Next
bData.UnlockBits()
End Sub
End Class
End Module