private void RenderToBitmapButton_OnClick(object sender, RoutedEventArgs e) { var renderedBitmap = _selectedCamera.RenderToBitmap(customWidth: 400, customHeight: 300, antialiasingLevel: 4, backgroundBrush: Brushes.White, dpi: 96); var window = new Window() { Title = "Bitmap created with RenderToBitmap method", SizeToContent = SizeToContent.WidthAndHeight }; var image = new Image() { Source = renderedBitmap, Width = renderedBitmap.Width, Height = renderedBitmap.Height }; window.Content = image; window.ShowDialog(); }
private BitmapSource RenderToBitmap(BaseCamera cameraToRender) { var selectedAntialiasingLevel = GetSelectedAntialiasingLevel(); var selectedDpi = GetSelectedDpi(); int customWidth, customHeight; GetCustomBitmapSize(out customWidth, out customHeight); Brush backgroundBrush; if (BackgroundBrushCheckBox.IsChecked ?? false) { backgroundBrush = ViewportBorder.Background; // Use current background gradient, but we could also specify any other brush that will be used as background on the bitmap } else { backgroundBrush = null; // Transparent background } BitmapSource bitmap; try { Mouse.OverrideCursor = Cursors.Wait; // This can take some time // For demonstration purposes we use call two different overloads of RenderToBitmap method // The the simple RenderToBitmap method is called when no custom size or antialiasing is required (this method uses a simpler and faster rendering methods) // We could call only the second method (internally that method checks for custom size or antialiasing and if they are not required calls the first method). // But for this demonstration I wanted to show you that you have two options if (customWidth == 0 && customHeight == 0 && selectedAntialiasingLevel < 1) { // Note that backgroundBrush and dpi parameters are optional (backgroundBrush = null, dpi = 96) // so if you want to get a bitmap of the current Viewport3D, you can simply call RenderToBitmap without any parameters bitmap = cameraToRender.RenderToBitmap(backgroundBrush, selectedDpi); } else { // When using customWidth and customHeight and the aspect ratio (= width / height) of the Viewport3D is not the same as // the aspect ratio of the target bitmap, the Viewport3D is uniformly scaled to fill the target bitmap. bitmap = cameraToRender.RenderToBitmap(customWidth, customHeight, selectedAntialiasingLevel, backgroundBrush, selectedDpi); } // RenderToBitmap is internally using Ab3d.Utilities.BitmapRendering.RenderToBitmap method. // You can use it to render any other FrameworkElement (instead of Viewport3D) to bitmap. // You can also use it to set the scaleToFill to false. // IMPORTANT: // If you will be calling RenderToBitmap ofter, then please note that there can be some problems when RenderTargetBitmap is used very ofter in WPF. // You can get "Out of memory" exceptions because garbage collector is not aware of the native bitmaps behind the RenderTargetBitmap. // A common workaround for that is to manually trigger garbage collection after some created RenderTargetBitmap objects - this can be done with the following 3 lines: // GC.Collect(); // GC.WaitForPendingFinalizers(); // GC.Collect(); // // This is also used after saving the bitmap a few lines below. // // Another workaround is to reuse the RenderTargetBitmap instances. // To do this you will need to change the source code for the RenderToBitmap method. // In this case please buy a Ab3d.PowerToys source code. You can also send me an email and I will provide you the original source code for the method. // // If RenderToBitmap is used very ofter, then please check the internet for more information about that. } catch (Exception ex) { Mouse.OverrideCursor = null; // This can happen when to big image is rendered (with combination of big antialiasing and DPI) MessageBox.Show("Error rendering bitmap:\r\n" + ex.Message); bitmap = null; } finally { Mouse.OverrideCursor = null; } return(bitmap); }