I'm making my own new image format where any pixel with an alpha less than a specific amount is dropped, and up to 255 colors are stored in a dictionary for additional compression. The format is like this:

Not one of the 255 colors in the dictionary: Argb representation
In dictionary: 0 for the alpha byte, number of repetitions in the R and G bytes, and index in the B byte.

Each group is stored like so:
0 x y colors.

I'm getting an IndexOutOfRangeException because the dictionary never has anything in it, and I can't figure out why. I have no idea what's going wrong! Here's my code:
vb.net Code:
  1. Imports System.IO
  2. Imports System.Runtime.InteropServices
  3. Imports System.Drawing.Imaging
  4. Public NotInheritable Class EACImage
  5.  
  6.     Public Shared Sub FromBitmap(ByVal b As Bitmap, ByVal output As String, Optional ByVal threshold As Integer = 0)
  7.         Dim r As New Rectangle(0, 0, b.Width, b.Height)
  8.         Using fs As New FileStream(output, FileMode.Create, FileAccess.Write)
  9.             Using bw As New BinaryWriter(fs)
  10.                 Dim bd As BitmapData = b.LockBits(r, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
  11.                 Dim arr(bd.Width * bd.Height - 1) As Integer
  12.                 Marshal.Copy(bd.Scan0, arr, 0, arr.Length)
  13.  
  14.                 'Prepare information
  15.                 Dim dictionary As New List(Of Integer)
  16.                 Dim data As New List(Of Integer)
  17.                 For i As Integer = 0 To arr.Length - 1
  18.                     While GetAComp(arr(i)) <= threshold
  19.                         i += 1
  20.                         If i = arr.Length Then Exit For
  21.                     End While
  22.                     data.Add(0) 'Begin a new group
  23.                     data.Add(i Mod bd.Width) 'Width
  24.                     data.Add(i \ bd.Width) 'Height
  25.                     While (i < arr.Length) AndAlso (GetAComp(arr(i)) > threshold)
  26.                         data.Add(arr(i))
  27.                         i += 1
  28.                     End While
  29.                 Next
  30.  
  31.                 'Compress the list
  32.                 CompressList(data, dictionary)
  33.  
  34.                 'Write header information
  35.                 For Each item As Integer In dictionary
  36.                     bw.Write(item)
  37.                     MsgBox("Wrote " & item)
  38.                 Next
  39.                 bw.Write(0I)
  40.                 bw.Write(bd.Width)
  41.                 bw.Write(bd.Height)
  42.  
  43.                 'Write data
  44.                 For Each item As Integer In data
  45.                     bw.Write(item)
  46.                 Next
  47.  
  48.                 'Unlock the bitmap
  49.                 b.UnlockBits(bd)
  50.  
  51.                 'Close the streams.
  52.                 bw.Close()
  53.                 fs.Close()
  54.             End Using
  55.         End Using
  56.     End Sub
  57.  
  58.     Public Shared Function FromFile(ByVal f As String) As Bitmap
  59.         Dim r As Bitmap = Nothing
  60.  
  61.         Using fs As New FileStream(f, FileMode.Open, FileAccess.Read)
  62.             Using br As New BinaryReader(fs)
  63.                 Dim dict As New List(Of Integer)
  64.                 Do
  65.                     Dim itm As Integer = br.ReadInt32()
  66.                     If itm = 0 Then Exit Do
  67.                     dict.Add(itm)
  68.                 Loop
  69.                 r = New Bitmap(br.ReadInt32(), br.ReadInt32(), PixelFormat.Format32bppArgb)
  70.                 Dim bd As BitmapData = r.LockBits(New Rectangle(0, 0, r.Width, r.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb)
  71.                 Dim arr(bd.Width * bd.Height - 1) As Integer
  72.                 Dim x As Integer = 0, y As Integer = 0
  73.                 Do
  74.                     If br.BaseStream.Position = br.BaseStream.Length Then Exit Do
  75.                     Dim n_int As Integer = br.ReadInt32()
  76.                     If n_int = 0 Then 'next group
  77.                         x = br.ReadInt32()
  78.                         y = br.ReadInt32()
  79.                     End If
  80.                     If GetAComp(n_int) = 0 Then 'It's compressed
  81.                         For j As Integer = 1 To GetRepetition(n_int)
  82.                             arr(y * bd.Width + x) = dict(GetIndex(n_int))
  83.                             x += 1
  84.                             If x >= bd.Width Then
  85.                                 y += 1
  86.                                 x = x Mod bd.Width
  87.                             End If
  88.                         Next
  89.                     Else 'Not compressed
  90.                         arr(y * bd.Width + x) = n_int
  91.                     End If
  92.                     x += 1
  93.                     If x >= bd.Width Then
  94.                         y += 1
  95.                         x = x Mod bd.Width
  96.                     End If
  97.                 Loop
  98.  
  99.                 'Copy back and unlock
  100.                 Marshal.Copy(arr, 0, bd.Scan0, arr.Length)
  101.                 r.UnlockBits(bd)
  102.  
  103.                 'Close the streams.
  104.                 br.Close()
  105.                 fs.Close()
  106.             End Using
  107.         End Using
  108.  
  109.         Return r
  110.     End Function
  111.  
  112. #Region "GetXXX"
  113.     Friend Shared Function GetAComp(ByVal i As Integer) As Integer
  114.         Dim sh24 As Integer = 255I << 24
  115.         Dim res As Integer = i And sh24
  116.         Return res >> 24
  117.     End Function
  118.  
  119.     Friend Shared Function GetRepetition(ByVal i As Integer) As Integer
  120.         Dim sh16 As Integer = 255 << 16
  121.         Dim sh8 As Integer = 255 << 8
  122.         Dim res As Integer = i And (sh16 Or sh8)
  123.         Return res >> 8
  124.     End Function
  125.  
  126.     Friend Shared Function GetIndex(ByVal i As Integer) As Integer
  127.         Return (i And 255)
  128.     End Function
  129.  
  130.     Friend Shared Function GetInt(ByVal count As Integer, ByVal index As Integer) As Integer
  131.         If count > Short.MaxValue OrElse index > 255 Then Throw New ArgumentException()
  132.         Return index Or (count << 8)
  133.     End Function
  134. #End Region
  135.  
  136.  
  137.     Private Shared Sub CompressList(ByRef l As List(Of Integer), ByRef dict As List(Of Integer), Optional ByVal minrep As Integer = 30)
  138.         dict.Clear()
  139.         Dim nl As New List(Of Integer)
  140.         Dim l_itm As Integer = -1
  141.         Dim count As Integer = 0
  142.         For i As Integer = 0 To l.Count - 1
  143.             Dim itm As Integer = l(i)
  144.             If itm = 0 Then
  145.                 i += 2
  146.                 If i >= l.Count Then Exit For
  147.                 itm = l(i)
  148.             End If
  149.             If count = 0 Then
  150.                 count = 1
  151.                 l_itm = itm
  152.             Else
  153.                 If l_itm = itm Then
  154.                     count += 1
  155.                     If (count < UInt16.MaxValue) AndAlso (dict.Count < 255) Then Continue For
  156.                 End If
  157.                 If count <= minrep Then
  158.                     nl.Add(itm)
  159.                 Else
  160.                     Dim idx As Integer = dict.Count
  161.                     If Not dict.Contains(itm) Then
  162.                         dict.Add(itm)
  163.                     Else
  164.                         idx = dict.IndexOf(itm)
  165.                     End If
  166.                     nl.Add(GetInt(count, idx))
  167.                 End If
  168.                 l_itm = itm
  169.                 count = 1
  170.             End If
  171.         Next
  172.         l = nl
  173.     End Sub
  174.  
  175. End Class