I'm fairly new to C# and WPF programming. I am currently trying to figure out how to modify a JPG image using WriteableBitmap. I think I get the general gist of whats going on, but I'm observing a strange behavior that I just don't understand.
Here's the situation based on the sample code below: If I declare the WriteableBitmap using the constructor that is currently commented out (on line 29), I can modify the pixels and draw a black region with a red square in it using the code shown. This is my working test case for setting and writing pixels.
However, if I comment out line 29 and create a WriteableBitmap using a JPG image instead (as it's currently coded -- see line 31), the image itself loads fine, but the red square and black square that I try to overwrite (and which worked previously), no longer appear.
Can anyone explain why this is happening? In the second method, I am not declaring values for the dPiX and dPiY parameters, nor am I able to specify the PixelFormat of BGRA32 anywhere. Since these are read only, I'm not able to modify them. Is this the source of my problem? And if so, is there a way to fix this?
I sense this is something very fundamental that I am just overlooking. Any guidance would be greatly appreciated. Thanks in advance for your time.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Drawing;
using System.IO;
namespace AsciiArt
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//Test code to load a JPG and then write over top of it using writeable bitmaps
private void SampleWriteableBitmap()
{
// Create a writeable bitmap (which is a valid WPF image source
//WriteableBitmap wbmap = new WriteableBitmap(100, 100, 96, 96, PixelFormats.Bgra32, null);
WriteableBitmap wbmap = ConvertToBitmap("../../photos/Image1.JPG");
// Overwriting the image by making all pixels black -- a silly test I know.
for (int x = 0; x < wbmap.PixelWidth; ++x)
{
for (int y = 0; y < wbmap.PixelHeight; ++y)
{
// apply pixels to bitmap
//Colors are A, Red, Green, Blue. A must be 255 to be opaque
// A R G B
SetPixel(wbmap, x, y, System.Drawing.Color.FromArgb(255, 0, 0, 0));
}
}
// and then creating a smaller block of a different color -- again as a test.
for (int x = 0; x < 20; ++x)
{
for (int y = 0; y < 20; ++y)
{
// apply pixels to bitmap
//Colors are A, Red, Green, Blue. A must be 255 to be opaque
// A R G B
SetPixel(wbmap, x, y, System.Drawing.Color.FromArgb(255, 255, 0, 0));
}
}
// Display some parameters for debugging...
ByteReadData.Text = "wbmap.PixelHeight: " + wbmap.PixelHeight + " wbmap.PixelWidth: " +
wbmap.PixelWidth + " wbmap.Format: " + wbmap.Format.BitsPerPixel + " ---> " +
wbmap.PixelHeight * wbmap.PixelWidth * wbmap.Format.BitsPerPixel / 8 + " wbmap.dpix: " + wbmap.DpiX + " wbmap.dpiy: " + wbmap.DpiY;
// set image source to the new bitmap
convertedPhoto.Source = wbmap;
}
// function to convert a JPG or other file type to a Bitmap
public WriteableBitmap ConvertToBitmap(string fileName)
{
BitmapImage bitmap = new BitmapImage(new Uri(fileName, UriKind.Relative));
WriteableBitmap newbitmap = new WriteableBitmap(bitmap);
return newbitmap;
}
public void SetPixel(WriteableBitmap wbm, int x, int y, System.Drawing.Color c)
{
if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1) return;
if (y < 0 || x < 0) return;
if (!wbm.Format.Equals(PixelFormats.Bgra32)) return;
wbm.Lock();
IntPtr buff = wbm.BackBuffer;
int Stride = wbm.BackBufferStride;
unsafe
{
byte* pbuff = (byte*)buff.ToPointer();
int loc = y * Stride + x * 4;
pbuff[loc] = c.B;
pbuff[loc + 1] = c.G;
pbuff[loc + 2] = c.R;
pbuff[loc + 3] = c.A;
}
wbm.AddDirtyRect(new Int32Rect(x, y, 1, 1));
wbm.Unlock();
}
public MainWindow()
{
InitializeComponent();
SampleWriteableBitmap();
}
}
} }