You may use a WriteableBitmap instead of (or actually in addition to) a BitmapImage. First create your BitmapImage as usual (but with less code):
var selectedFileName = dlg.FileName;
var bitmap = new BitmapImage(new Uri(selectedFileName));
Then create a WritableBitmap from the BitmapImage and assign that to the Image control:
var writeableBitmap = new WriteableBitmap(bitmap);
image.Source = writeableBitmap;
Now you may modify the WriteableBitmap in order to draw your overlay data. The following code snippet shows how to get and modify a pixel in the bitmap:
if (writeableBitmap.Format.BitsPerPixel == 32)
{
var x = 10;
var y = 20;
var pixelRect = new Int32Rect(x, y, 1, 1);
var pixelBuffer = new byte[4];
writeableBitmap.CopyPixels(pixelRect, pixelBuffer, 4, 0);
// modify pixelBuffer and write it back
writeableBitmap.WritePixels(pixelRect, pixelBuffer, 4, 0);
}
EDIT: A suggestion for a SetPixel method that takes the overlay color alpha value into account. Please note that this method assumes that the bitmap's pixel format is Bgr32.
public void SetPixel(WriteableBitmap wb, int x, int y, Color color)
{
var pixelRect = new Int32Rect(x, y, 1, 1);
var pixelBuffer = new byte[4];
wb.CopyPixels(pixelRect, pixelBuffer, 4, 0);
pixelBuffer[0] = (byte)(pixelBuffer[0] * (1F - color.ScA) + color.B * color.ScA);
pixelBuffer[1] = (byte)(pixelBuffer[1] * (1F - color.ScA) + color.G * color.ScA);
pixelBuffer[2] = (byte)(pixelBuffer[2] * (1F - color.ScA) + color.R * color.ScA);
wb.WritePixels(pixelRect, pixelBuffer, 4, 0);
}
Please note also that it is a lot more efficient to set a larger number of pixels in one go. Ideally you would set all overlay pixels at once. You would copy all pixel values into one large array, calculate their new RGB values as shown above, and then write them all back at once.