Capture the Silverlight 4 screen through C# code and Save it to a database or send it as an email attachment by passing byte array to the WCF Service method.
Saving the captured Silverlight 4 screenshot to database or
send it as an email attachment
In this article we will see how best we can compress and
transfer WritableBitmap object to WCF services by encoding it to JPEG format.
In my previous article “Capture the screenshot of
Silverlight application in Silverlight 4”, we have seen how to capture a
Silverlight screen using WritableBitmap class.
In order to save the captured bitmap image onto the
server or to send the snapshot as an attachment in email, we first need to
convert the WritableBitmap object to byte array or binary stream and pass it to
the WCF services.
Most importantly, we need to do compression as direct
conversion of WritableBitmap object to byte array results in a very huge (more
than 5mb for any decent graphics on the screen) object, which may cause “Maximum
request length exceeded” issue with WCF services.
Here I am making use of FjCore library available on codeplex
which provides option to encode the JPEG and to a Memory Stream.
Here is the function that to convert WritableBitmap object
to JPEG and get the stream after compression.
///
/// Encodes the JPG.
///
/// "bitmap">The bitmap.
/// "destinationStream">The destination stream.
public static void EncodeJpeg(WriteableBitmap bitmap, Stream destinationStream)
{
int width = bitmap.PixelWidth;
int height = bitmap.PixelHeight;
int bands = 3; // RGB
byte[][,] raster = new byte[bands][,];
// initialise the bands
for (int i = 0; i < bands; i )
{
raster[i] = new byte[width, height];
}
// copy over the pixel data from the bitmap
for (int row = 0; row < height; row )
{
for (int column = 0; column < width; column )
{
int pixel = bitmap.Pixels[width * row column];
raster[0][column, row] = (byte)(pixel >> 16);
raster[1][column, row] = (byte)(pixel >> 8);
raster[2][column, row] = (byte)pixel;
}
}
// Use the Flux library to encode the JPG
ColorModel model = new ColorModel { colorspace = ColorSpace.RGB };
FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);
// encode it to the destination stream
JpegEncoder encoder = new JpegEncoder(img, 90, destinationStream);
encoder.Encode();
}
Here is how we can use this function to capture the
Silverlight screen and encode to JPG and then call the WCF service method to
save the image to database.
///
/// Handles the Click event of the btnCapture control.
///
/// "sender">The source of the event.
/// "e">The "System.Windows.RoutedEventArgs"/> instance containing the event data.
private void btnCapture_Click(object sender, RoutedEventArgs e)
{
// Create Bitmap image by passing UIElement to WriteableBitmap constructor
WriteableBitmap bmp = new WriteableBitmap(LayoutRoot, null);
// Display captured snapshot or can save to database
System.Windows.Controls.Image img = new System.Windows.Controls.Image();
img.Margin = new Thickness(10);
img.Source = bmp;
capturedImages.Children.Add(img);
// Encode to JPEG format
byte[] screenshot;
using (Stream pngStream = new MemoryStream())
{
EncodeJpeg(bmp, pngStream);
pngStream.Flush();
pngStream.Seek(0, SeekOrigin.Begin);
screenshot = ConvertToByteArray(pngStream);
pngStream.Close();
}
// Call service method by passing binary array as input parameter
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
client.SaveImageAsync(screenshot);
}
///
/// Converts to byte array.
///
/// "fileStream">The file stream.
///
public byte[] ConvertToByteArray(Stream fileStream)
{
if (fileStream != null)
{
int fileStreamLength = (int)fileStream.Length;
byte[] bytes = new byte[fileStreamLength];
fileStream.Read(bytes, 0, fileStreamLength);
return bytes;
}
return null;
}
You can download the sample application here.