I thought the answer might be also useful for others. Furthermore I will provide ready to use code for JPEG encoding and decoding of the WriteableBitmap.
Byte array conversion
Copy WriteableBitmap to ARGB byte array
public static byte[] ToByteArray(this WriteableBitmap bmp) { int[] p = bmp.Pixels; int len = p.Length * 4; byte[] result = new byte[len]; // ARGB Buffer.BlockCopy(p, 0, result, 0, len); return result; }
Copy ARGB byte array into WriteableBitmap
public static void FromByteArray(this WriteableBitmap bmp, byte[] buffer) { Buffer.BlockCopy(buffer, 0, bmp.Pixels, 0, buffer.Length); }
Usage
// Render UIElement into WriteableBitmap WriteableBitmap bmp = new WriteableBitmap(UIElement, null); // Copy WriteableBitmap.Pixels into byte array (format ARGB) byte[] buffer = bmp.ToByteArray(); // Create a new WriteableBitmap with the size of the original image WriteableBitmap bmp = new WriteableBitmap(width, height); // Fill WriteableBitmap from byte array (format ARGB) bmp.FromByteArray(buffer);
I will include the two methods in my WriteableBitmap extensions that I'm going to put up on Codeplex soon.
JPEG encoding and decoding
If you want to store many images or transport them over a network the needed storage size could quickly become a big problem. For example an image with the size 512 x 512 needs 1 Megabyte storage space and a 1024 x 768 image even 3 MB. A solution could be image compression using JPEG encoding and decoding. To accomplish this I've used the open source FJCore JPEG library which is distributed under the MIT License and works nicely with Silverlight.
Encode WriteableBitmap as JPEG stream
public static void EncodeJpeg(WriteableBitmap bmp, Stream destinationStream) { // Init buffer in FluxJpeg format int w = bmp.PixelWidth; int h = bmp.PixelHeight; int[] p = bmp.Pixels; byte[][,] pixelsForJpeg = new byte[3][,]; // RGB colors pixelsForJpeg[0] = new byte[w, h]; pixelsForJpeg[1] = new byte[w, h]; pixelsForJpeg[2] = new byte[w, h]; // Copy WriteableBitmap data into buffer for FluxJpeg int i = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int color = p[i++]; pixelsForJpeg[0][x, y] = (byte)(color >> 16); // R pixelsForJpeg[1][x, y] = (byte)(color >> 8); // G pixelsForJpeg[2][x, y] = (byte)(color); // B } } // Encode Image as JPEG using the FluxJpeg library // and write to destination stream ColorModel cm = new ColorModel { colorspace = ColorSpace.RGB }; FluxJpeg.Core.Image jpegImage = new FluxJpeg.Core.Image(cm, pixelsForJpeg); JpegEncoder encoder = new JpegEncoder(jpegImage, 95, destinationStream); encoder.Encode(); }
Decode WriteableBitmap from JPEG stream
public static WriteableBitmap DecodeJpeg(Stream sourceStream) { // Decode JPEG from stream var decoder = new FluxJpeg.Core.Decoder.JpegDecoder(sourceStream); var jpegDecoded = decoder.Decode(); var img = jpegDecoded.Image; img.ChangeColorSpace(ColorSpace.RGB); // Init Buffer int w = img.Width; int h = img.Height; var result = new WriteableBitmap(w, h); int[] p = result.Pixels; byte[][,] pixelsFromJpeg = img.Raster; // Copy FluxJpeg buffer into WriteableBitmap int i = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { p[i++] = (0xFF << 24) // A | (pixelsFromJpeg[0][x, y] << 16) // R | (pixelsFromJpeg[1][x, y] << 8) // G | pixelsFromJpeg[2][x, y]; // B } } return result; }
Usage
// Save rendered UIElement as JPEG file private void BtnSaveFile_Click(object sender, RoutedEventArgs e) { if (saveFileDlg.ShowDialog().Value) { using (Stream dstStream = saveFileDlg.OpenFile()) { // Render to WriteableBitmap WriteableBitmap bmp = new WriteableBitmap(UIElement, null); // Encode JPEG and write to FileStream EncodeJpeg(bmp, dstStream); } } } // Open JPEG file and read into a WriteableBitmap private void BtnLoadFile_Click(object sender, RoutedEventArgs e) { if (openFileDialog.ShowDialog().Value) { using (System.IO.Stream srcStream = openFileDialog.File.OpenRead()) { // Read JPEG file and decode it WriteableBitmap bmp = DecodeJpeg(srcStream); } } }
Keep in mind that the standard JPEG format doesn't support alpha values (transparency) and that the compression is lossy. So don't encode and decode images subsequently with JPEG.
It is also possible to use the built-in Silverlight class BitmapSource and its SetSource method to decode an JPEG stream.
public static WriteableBitmap DecodeJpegWithBitmapSource(Stream sourceStream) { // Decode JPEG from stream var bitmapSource = new BitmapSource(); bitmapSource.SetSource(sourceStream); return new WriteableBitmap(bitmapSource); }
Source code
Check out my Codeplex project WriteableBitmapEx for an up to date version of the byte array conversion methods.