/// <summary>
 /// Dilate a <see cref="OneBppImage"/>
 /// </summary>
 public OneBppImage Dilate(OneBppImage source)
 {
     byte[,] data = new byte[source.Width, source.Height];
     
     for (int y = 0; y < source.Height; y++)
     {
         for (int x = 0; x < source.Width; x++)
         {
             byte pointValue = Constants.PIXEL_VALUE_WHITESPACE;
             foreach (Point p in StructuralElement.ExaminePoints)
             {
                 int testX = x + p.X;
                 int testY = y + p.Y;
                 if (testX < 0 || testY < 0 || testX >= source.Width || testY >= source.Height)
                 {
                     continue;
                 }
                 
                 if (source.ImageData[testX, testY] == Constants.PIXEL_VALUE_INK)
                 {
                     pointValue = Constants.PIXEL_VALUE_INK;
                     break;
                 }
             }
             
             data[x, y] = pointValue;
         }
     }
     
     return new OneBppImage(data);
 }
 /// <summary>
 /// Erode a <see cref="OneBppImage"/>
 /// </summary>
 public OneBppImage Erode(OneBppImage source)
 {
     byte[,] data = new byte[source.Width, source.Height];
     
     for (int y = 0; y < source.Height; y++)
     {
         for (int x = 0; x < source.Width; x++)
         {
             if (source.ImageData[x, y] == Constants.PIXEL_VALUE_INK)
             {
                 foreach (Point p in StructuralElement.ExaminePoints)
                 {
                     int testX = x + p.X;
                     int testY = y + p.Y;
                     if (testX < 0 || testY < 0 || testX >= source.Width || testY >= source.Height)
                     {
                         data[x, y] = Constants.PIXEL_VALUE_WHITESPACE;
                         goto NextPixel;
                     }
                     
                     if (source.ImageData[testX, testY] != Constants.PIXEL_VALUE_INK)
                     {
                         data[x, y] = Constants.PIXEL_VALUE_WHITESPACE;
                         goto NextPixel;
                     }
                 }
                 
                 data[x, y] = Constants.PIXEL_VALUE_INK;
             }
             else
             {
                 data[x, y] = Constants.PIXEL_VALUE_WHITESPACE;
             }
             
         NextPixel: ; // continue
         }
     }
     
     return new OneBppImage(data);
 }
 /// <summary>
 /// Perform a morphological closing on a <see cref="OneBppImage"/>
 /// </summary>
 public OneBppImage Close(OneBppImage source)
 {
     return Erode(Dilate(source));
 }
 /// <summary>
 /// Perform a morphological opening on a <see cref="OneBppImage"/>
 /// </summary>
 public OneBppImage Open(OneBppImage source)
 {
     return Dilate(Erode(source));
 }