One of the high-profile missing features in Silverlight has been Printing support. If you have ever tried to print a web page containing Silverlight content, what you saw on the printed page may be skewed or even missing altogether! So, what if you wanted to print a portion of your Silverlight screen, or take a “snapshot” image of the Silverlight UI to include in a report or other printable format?
WriteableBitmap bitmap = new WriteableBitmap(cnvSource, new TranslateTransform());2. Convert the WriteableBitmap pixels to a PNG using Joe Stegman's PNG encoder .
EditableImage imageData = new EditableImage(bitmap.PixelWidth, bitmap.PixelHeight); for (int y = 0; y < bitmap.PixelHeight; ++y) { for (int x = 0; x < bitmap.PixelWidth; ++x) { int pixel = bitmap.Pixels[bitmap.PixelWidth * y + x]; imageData.SetPixel(x, y, (byte)((pixel >> 16) & 0xFF), (byte)((pixel >> 8) & 0xFF), (byte)(pixel & 0xFF), (byte)((pixel >> 24) & 0xFF) ); } } Stream pngStream = imageData.GetStream();NOTE that this PNG encoder does NOT include compression! This would be a good optimization to add, but also note that the GZipStream class is not present in Silverlight, so you would need to use an outside compression library such as SharpZipLib .
3.At this point, we have the PNG bytes in a stream, and you could take several approaches to get these bytes up to the server – such as using an Http Handler (ASHX). In this demo, we’ll place the bytes into a hidden field on the ASPX page and post the page back to the server for inclusion in a report. To do this, we’ll translate the PNG bytes into a string using Base64 encoding:
byte[] binaryData = new Byte[pngStream.Length]; long bytesRead = pngStream.Read(binaryData, 0, (int)pngStream.Length); string base64String = System.Convert.ToBase64String(binaryData, 0, binaryData.Length); // save the encoded PNG bytes to the page HtmlDocument document = HtmlPage.Document; HtmlElement txtPNGBytes = document.GetElementById("txtPNGBytes"); txtPNGBytes.SetProperty("value", base64String); // this calls a js function "postBackPrint" which will cause a postback HtmlPage.Window.CreateInstance("postBackPrint", new string[] { });
4.Now that we have our bytes up on the server, we can decode them and feed them to a ReportViewer (RDLC) report. This will give us a nicely printed format and the ability to export to PDF:
string bytes64 = Request["txtPNGBytes"]; byte[] imageBytes = System.Convert.FromBase64String(bytes64); DSReportPrintImage ds = new DSReportPrintImage(); DataRow drImage = ds.Tables[0].NewRow(); drImage["ImageBytes"] = imageBytes; ds.Tables[0].Rows.Add(drImage); ReportViewer1.LocalReport.ReportPath = "ReportPrintSilverlight.rdlc"; ReportDataSource src = new ReportDataSource("DSReportPrintImage_ImageData", ds.Tables[0]); ReportViewer1.LocalReport.DataSources.Add(src); ReportViewer1.LocalReport.Refresh();
That’s it! I really think this use of WriteableBitmap as a snapshot/print function will be useful in some of my projects that need to capture the current view of the Silverlight application.