Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Drawing.Imaging
Public NotInheritable Class EACImage
Public Shared Sub FromBitmap(ByVal b As Bitmap, ByVal output As String, Optional ByVal threshold As Integer = 0)
Dim r As New Rectangle(0, 0, b.Width, b.Height)
Using fs As New FileStream(output, FileMode.Create, FileAccess.Write)
Using bw As New BinaryWriter(fs)
Dim bd As BitmapData = b.LockBits(r, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
Dim arr(bd.Width * bd.Height - 1) As Integer
Marshal.Copy(bd.Scan0, arr, 0, arr.Length)
'Prepare information
Dim dictionary As New List(Of Integer)
Dim data As New List(Of Integer)
For i As Integer = 0 To arr.Length - 1
While GetAComp(arr(i)) <= threshold
i += 1
If i = arr.Length Then Exit For
End While
data.Add(0) 'Begin a new group
data.Add(i Mod bd.Width) 'Width
data.Add(i \ bd.Width) 'Height
While (i < arr.Length) AndAlso (GetAComp(arr(i)) > threshold)
data.Add(arr(i))
i += 1
End While
Next
'Compress the list
CompressList(data, dictionary)
'Write header information
For Each item As Integer In dictionary
bw.Write(item)
MsgBox("Wrote " & item)
Next
bw.Write(0I)
bw.Write(bd.Width)
bw.Write(bd.Height)
'Write data
For Each item As Integer In data
bw.Write(item)
Next
'Unlock the bitmap
b.UnlockBits(bd)
'Close the streams.
bw.Close()
fs.Close()
End Using
End Using
End Sub
Public Shared Function FromFile(ByVal f As String) As Bitmap
Dim r As Bitmap = Nothing
Using fs As New FileStream(f, FileMode.Open, FileAccess.Read)
Using br As New BinaryReader(fs)
Dim dict As New List(Of Integer)
Do
Dim itm As Integer = br.ReadInt32()
If itm = 0 Then Exit Do
dict.Add(itm)
Loop
r = New Bitmap(br.ReadInt32(), br.ReadInt32(), PixelFormat.Format32bppArgb)
Dim bd As BitmapData = r.LockBits(New Rectangle(0, 0, r.Width, r.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb)
Dim arr(bd.Width * bd.Height - 1) As Integer
Dim x As Integer = 0, y As Integer = 0
Do
If br.BaseStream.Position = br.BaseStream.Length Then Exit Do
Dim n_int As Integer = br.ReadInt32()
If n_int = 0 Then 'next group
x = br.ReadInt32()
y = br.ReadInt32()
End If
If GetAComp(n_int) = 0 Then 'It's compressed
For j As Integer = 1 To GetRepetition(n_int)
arr(y * bd.Width + x) = dict(GetIndex(n_int))
x += 1
If x >= bd.Width Then
y += 1
x = x Mod bd.Width
End If
Next
Else 'Not compressed
arr(y * bd.Width + x) = n_int
End If
x += 1
If x >= bd.Width Then
y += 1
x = x Mod bd.Width
End If
Loop
'Copy back and unlock
Marshal.Copy(arr, 0, bd.Scan0, arr.Length)
r.UnlockBits(bd)
'Close the streams.
br.Close()
fs.Close()
End Using
End Using
Return r
End Function
#Region "GetXXX"
Friend Shared Function GetAComp(ByVal i As Integer) As Integer
Dim sh24 As Integer = 255I << 24
Dim res As Integer = i And sh24
Return res >> 24
End Function
Friend Shared Function GetRepetition(ByVal i As Integer) As Integer
Dim sh16 As Integer = 255 << 16
Dim sh8 As Integer = 255 << 8
Dim res As Integer = i And (sh16 Or sh8)
Return res >> 8
End Function
Friend Shared Function GetIndex(ByVal i As Integer) As Integer
Return (i And 255)
End Function
Friend Shared Function GetInt(ByVal count As Integer, ByVal index As Integer) As Integer
If count > Short.MaxValue OrElse index > 255 Then Throw New ArgumentException()
Return index Or (count << 8)
End Function
#End Region
Private Shared Sub CompressList(ByRef l As List(Of Integer), ByRef dict As List(Of Integer), Optional ByVal minrep As Integer = 30)
dict.Clear()
Dim nl As New List(Of Integer)
Dim l_itm As Integer = -1
Dim count As Integer = 0
For i As Integer = 0 To l.Count - 1
Dim itm As Integer = l(i)
If itm = 0 Then
i += 2
If i >= l.Count Then Exit For
itm = l(i)
End If
If count = 0 Then
count = 1
l_itm = itm
Else
If l_itm = itm Then
count += 1
If (count < UInt16.MaxValue) AndAlso (dict.Count < 255) Then Continue For
End If
If count <= minrep Then
nl.Add(itm)
Else
Dim idx As Integer = dict.Count
If Not dict.Contains(itm) Then
dict.Add(itm)
Else
idx = dict.IndexOf(itm)
End If
nl.Add(GetInt(count, idx))
End If
l_itm = itm
count = 1
End If
Next
l = nl
End Sub
End Class