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.







