using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Media.Imaging; using System.Windows; using System.Windows.Media; using System.IO; using System.Diagnostics; using System.Windows.Threading; using System.Windows.Shapes; namespace Microsoft.Research.DynamicDataDisplay.Common.Auxiliary { internal static class ScreenshotHelper { /// Gets the encoder by extension /// The extension /// BitmapEncoder object internal static BitmapEncoder GetEncoderByExtension(string extension) { switch (extension) { case "bmp": return new BmpBitmapEncoder(); case "jpg": return new JpegBitmapEncoder(); case "gif": return new GifBitmapEncoder(); case "png": return new PngBitmapEncoder(); case "tiff": return new TiffBitmapEncoder(); case "wmp": return new WmpBitmapEncoder(); default: throw new ArgumentException(Strings.Exceptions.CannotDetermineImageTypeByExtension, "extension"); } } /// Creates the screenshot of entire plotter element /// internal static BitmapSource CreateScreenshot(UIElement uiElement, Int32Rect screenshotSource) { Window window = Window.GetWindow(uiElement); if (window == null) { return CreateElementScreenshot(uiElement); } Size size = window.RenderSize; //double dpiCoeff = 32 / SystemParameters.CursorWidth; //int dpi = (int)(dpiCoeff * 96); double dpiCoeff = 1; int dpi = 96; RenderTargetBitmap bmp = new RenderTargetBitmap( (int)(size.Width * dpiCoeff), (int)(size.Height * dpiCoeff), dpi, dpi, PixelFormats.Default); // white background Rectangle whiteRect = new Rectangle { Width = size.Width, Height = size.Height, Fill = Brushes.White }; whiteRect.Measure(size); whiteRect.Arrange(new Rect(size)); bmp.Render(whiteRect); // the very element bmp.Render(uiElement); CroppedBitmap croppedBmp = new CroppedBitmap(bmp, screenshotSource); return croppedBmp; } private static BitmapSource CreateElementScreenshot(UIElement uiElement) { bool measureValid = uiElement.IsMeasureValid; if (!measureValid) { double width = 300; double height = 300; FrameworkElement frElement = uiElement as FrameworkElement; if (frElement != null) { if (!Double.IsNaN(frElement.Width)) width = frElement.Width; if (!Double.IsNaN(frElement.Height)) height = frElement.Height; } Size size = new Size(width, height); uiElement.Measure(size); uiElement.Arrange(new Rect(size)); } RenderTargetBitmap bmp = new RenderTargetBitmap( (int)uiElement.RenderSize.Width, (int)uiElement.RenderSize.Height, 96, 96, PixelFormats.Default); // this is waiting for dispatcher to perform measure, arrange and render passes uiElement.Dispatcher.Invoke(((Action)(() => { })), DispatcherPriority.Background); Size elementSize = uiElement.DesiredSize; // white background Rectangle whiteRect = new Rectangle { Width = elementSize.Width, Height = elementSize.Height, Fill = Brushes.White }; whiteRect.Measure(elementSize); whiteRect.Arrange(new Rect(elementSize)); bmp.Render(whiteRect); bmp.Render(uiElement); return bmp; } private static Dictionary pendingBitmaps = new Dictionary(); internal static void SaveBitmapToStream(BitmapSource bitmap, Stream stream, string fileExtension) { if (bitmap == null) throw new ArgumentNullException("bitmap"); if (stream == null) throw new ArgumentNullException("stream"); if (String.IsNullOrEmpty(fileExtension)) throw new ArgumentException(Strings.Exceptions.ExtensionCannotBeNullOrEmpty, fileExtension); BitmapEncoder encoder = ScreenshotHelper.GetEncoderByExtension(fileExtension); encoder.Frames.Add(BitmapFrame.Create(bitmap, null, new BitmapMetadata(fileExtension.Trim('.')), null)); encoder.Save(stream); } internal static void SaveBitmapToFile(BitmapSource bitmap, string filePath) { if (String.IsNullOrEmpty(filePath)) throw new ArgumentException(Strings.Exceptions.FilePathCannotbeNullOrEmpty, "filePath"); if (bitmap.IsDownloading) { pendingBitmaps[bitmap] = filePath; bitmap.DownloadCompleted += OnBitmapDownloadCompleted; return; } string dirPath = System.IO.Path.GetDirectoryName(filePath); if (!String.IsNullOrEmpty(dirPath) && !Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } bool fileExistedBefore = File.Exists(filePath); try { using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { string extension = System.IO.Path.GetExtension(filePath).TrimStart('.'); SaveBitmapToStream(bitmap, fs, extension); } } catch (ArgumentException) { if (!fileExistedBefore && File.Exists(filePath)) { try { File.Delete(filePath); } catch { } } } catch (IOException exc) { Debug.WriteLine("Exception while saving bitmap to file: " + exc.Message); } } public static void SaveStreamToFile(Stream stream, string filePath) { string dirPath = System.IO.Path.GetDirectoryName(filePath); if (!String.IsNullOrEmpty(dirPath) && !Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { string extension = System.IO.Path.GetExtension(filePath).TrimStart('.'); if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin); stream.CopyTo(fs); } stream.Dispose(); } private static void OnBitmapDownloadCompleted(object sender, EventArgs e) { BitmapSource bmp = (BitmapSource)sender; bmp.DownloadCompleted -= OnBitmapDownloadCompleted; string filePath = pendingBitmaps[bmp]; pendingBitmaps.Remove(bmp); SaveBitmapToFile(bmp, filePath); } } }