WPF Save ItemsControl canvas as jpg via RenderTargetBitmap,DrawingVisual,DrawingContext,VisualBrush, DrawRectangle,JpegBitmapEncoder

 <ItemsControl ItemsSource="{Binding ElpsCollection}">
     <ItemsControl.ItemsPanel>
         <ItemsPanelTemplate>
             <Canvas Background="White"/>
         </ItemsPanelTemplate>
     </ItemsControl.ItemsPanel>
     <ItemsControl.ItemContainerStyle>
         <Style>
             <Setter Property="Canvas.Left" Value="{Binding X}"/>
             <Setter Property="Canvas.Top" Value="{Binding Y}"/>
         </Style>
     </ItemsControl.ItemContainerStyle>
     <ItemsControl.ItemTemplate>
         <DataTemplate>
             <Ellipse Width="{Binding Width}"
                      Height="{Binding Height}"
                      Fill="{Binding ElpColor}"/>
         </DataTemplate>
     </ItemsControl.ItemTemplate>
     <ItemsControl.ContextMenu>
         <ContextMenu>
             <MenuItem Header="ReGenerate Ellipses"
                       Command="{Binding ReGenerateEllipsesCommand}"/>
             <MenuItem Header="Save As Jpg"
                       Command="{Binding SaveAsJpgCommand}"
                       CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ContextMenu}},
                 Path=PlacementTarget}"/>
         </ContextMenu>
     </ItemsControl.ContextMenu>
 </ItemsControl>


 private void SaveFrameworkElementAsPicture(FrameworkElement fe,string jpgFile,int dpi=96)
 {
     Size size = new Size(fe.ActualWidth, fe.ActualHeight);

     RenderTargetBitmap rtb=new RenderTargetBitmap(
         (int)(size.Width * dpiFactor), 
         (int)(size.Height * dpiFactor),
         dpi*dpiFactor,
         dpi*dpiFactor,
         PixelFormats.Pbgra32);

     DrawingVisual drawingVisual=new DrawingVisual();
     using (DrawingContext drawingContext = drawingVisual.RenderOpen())
     {
         VisualBrush visualBrush = new VisualBrush(fe);
         drawingContext.DrawRectangle(visualBrush,
             null,
             new Rect(new Point(0,0),new Point(size.Width,size.Height)));
     }

     rtb.Render(drawingVisual);

     var jpgEncoder = new JpegBitmapEncoder();
     jpgEncoder.Frames.Add(BitmapFrame.Create(rtb));
     using(FileStream fs=new FileStream(jpgFile,FileMode.Create))
     {
         jpgEncoder.Save(fs);
         MessageBox.Show($"Saved in {System.IO.Path.GetFullPath(jpgFile)}");
         OpenJpgFileViaProcess(jpgFile);
     }
 }

 

 

 

image

 

 

 

 

image

 

 

image

 

 

 

//xaml
<Window x:Class="WpfApp40.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp40"
        mc:Ignorable="d"
        WindowState="Maximized"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ItemsControl ItemsSource="{Binding ElpsCollection}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Background="White"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style>
                    <Setter Property="Canvas.Left" Value="{Binding X}"/>
                    <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Ellipse Width="{Binding Width}"
                             Height="{Binding Height}"
                             Fill="{Binding ElpColor}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="ReGenerate Ellipses"
                              Command="{Binding ReGenerateEllipsesCommand}"/>
                    <MenuItem Header="Save As Jpg"
                              Command="{Binding SaveAsJpgCommand}"
                              CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ContextMenu}},
                        Path=PlacementTarget}"/>
                </ContextMenu>
            </ItemsControl.ContextMenu>
        </ItemsControl>
    </Grid>
</Window>



//cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp40
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var vm = new MainVM();
            this.DataContext=vm;
        }
    }

    public class MainVM : INotifyPropertyChanged
    {
        private int dpiFactor = 2;
        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler!=null)
            {
                handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private ObservableCollection<ElpModel> elpsCollection;
        public ObservableCollection<ElpModel> ElpsCollection
        {
            get
            {
                return elpsCollection;
            }
            set
            {
                if (value!=elpsCollection)
                {
                    elpsCollection=value;
                    OnPropertyChanged(nameof(ElpsCollection));
                }
            }
        }
        public MainVM()
        {
            InitData();
        }

        private void InitData()
        {
            double maxWidth = SystemParameters.FullPrimaryScreenWidth-100;
            double maxHeight = SystemParameters.FullPrimaryScreenHeight-100;
            Random rnd = new Random();
            ElpsCollection=new ObservableCollection<ElpModel>();
            List<Color> colorsList = new List<Color>();
            colorsList.Add(Colors.Red);
            colorsList.Add(Colors.Green);
            colorsList.Add(Colors.Blue);
            colorsList.Add(Colors.Yellow);
            colorsList.Add(Colors.Black);
            colorsList.Add(Colors.Gray);
            colorsList.Add(Colors.Gold);
            colorsList.Add(Colors.Cyan);
            colorsList.Add(Colors.Magenta);
            colorsList.Add(Colors.DarkBlue);
            colorsList.Add(Colors.Purple);

            int colorsCount = colorsList.Count;

            for (int i = 0; i<20; i++)
            {
                ElpsCollection.Add(new ElpModel()
                {
                    Width=100,
                    Height=100,
                    X=rnd.Next(50, (int)maxWidth),
                    Y=rnd.Next(50, (int)maxHeight),
                    ElpColor=new SolidColorBrush(colorsList[i%colorsCount])
                });
            }
        }


        private ICommand saveAsJpgCommand;
        public ICommand SaveAsJpgCommand
        {
            get
            {
                if (saveAsJpgCommand==null)
                {
                    saveAsJpgCommand = new DelCommand(SaveAsJpgCommandExecuted);
                }
                return saveAsJpgCommand;
            }
        }

        private void SaveAsJpgCommandExecuted(object? obj)
        {
            var fe = obj as FrameworkElement;
            if(fe==null)
            {
                return;
            }

            string jpgFile = $"ItemsControl_{DateTime.Now.ToString("yyyyMMddmmHHssffff")}.jpg";
            SaveFrameworkElementAsPicture(fe, jpgFile);
        }

        private void SaveFrameworkElementAsPicture(FrameworkElement fe,string jpgFile,int dpi=96)
        {
            Size size = new Size(fe.ActualWidth, fe.ActualHeight);

            RenderTargetBitmap rtb=new RenderTargetBitmap(
                (int)(size.Width * dpiFactor), 
                (int)(size.Height * dpiFactor),
                dpi*dpiFactor,
                dpi*dpiFactor,
                PixelFormats.Pbgra32);

            DrawingVisual drawingVisual=new DrawingVisual();
            using (DrawingContext drawingContext = drawingVisual.RenderOpen())
            {
                VisualBrush visualBrush = new VisualBrush(fe);
                drawingContext.DrawRectangle(visualBrush,
                    null,
                    new Rect(new Point(0,0),new Point(size.Width,size.Height)));
            }

            rtb.Render(drawingVisual);

            var jpgEncoder = new JpegBitmapEncoder();
            jpgEncoder.Frames.Add(BitmapFrame.Create(rtb));
            using(FileStream fs=new FileStream(jpgFile,FileMode.Create))
            {
                jpgEncoder.Save(fs);
                MessageBox.Show($"Saved in {System.IO.Path.GetFullPath(jpgFile)}");
                OpenJpgFileViaProcess(jpgFile);
            }
        }

        private void OpenJpgFileViaProcess(string jpgFile)
        {
            Process.Start(new ProcessStartInfo
            {
                FileName= jpgFile,
                UseShellExecute=true
            });
        }

        private ICommand reGenerateEllipsesCommand;
        public ICommand ReGenerateEllipsesCommand
        {
            get
            {
                if(reGenerateEllipsesCommand == null)
                {
                    reGenerateEllipsesCommand=new DelCommand(ReGenerateEllipsesCommandExecuted);
                }
                return reGenerateEllipsesCommand;
            }
        }

        private void ReGenerateEllipsesCommandExecuted(object? obj)
        {
            InitData();
        }
    }
   

    public class ElpModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
        public void OnPropertyChanged([CallerMemberName] string propName = "")
        {
            var handler = PropertyChanged;
            if (handler!=null)
            {
                handler?.Invoke(this, new PropertyChangedEventArgs(propName));
            }
        }


        private double width;
        public double Width
        {
            get
            {
                return width;
            }
            set
            {
                if (value!=width)
                {
                    width=value;
                    OnPropertyChanged(nameof(Width));
                }
            }
        }


        private double height;
        public double Height
        {
            get
            {
                return width;
            }
            set
            {
                if (value!=height)
                {
                    height=value;
                    OnPropertyChanged(nameof(Height));
                }
            }
        }

        private double x;
        public double X
        {
            get
            {
                return x;
            }
            set
            {
                if (value!=x)
                {
                    x=value;
                    OnPropertyChanged(nameof(X));
                }
            }
        }

        private double y;
        public double Y
        {
            get
            {
                return y;
            }
            set
            {
                if (value!=y)
                {
                    y=value;
                    OnPropertyChanged(nameof(Y));
                }
            }
        }

        private SolidColorBrush elpColor;
        public SolidColorBrush ElpColor
        {
            get
            {
                return elpColor;
            }
            set
            {
                if (value!=elpColor)
                {
                    elpColor=value;
                    OnPropertyChanged(nameof(ElpColor));
                }
            }
        }
    }

    public class DelCommand : ICommand
    {
        private readonly Action<object?> execute;
        private readonly Predicate<object?> canExecute;

        public DelCommand(Action<object?> executeValue, Predicate<object?> canExecuteValue = null)
        {
            execute=executeValue;
            canExecute=canExecuteValue;
        }


        public event EventHandler? CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested+=value;
            }
            remove
            {
                CommandManager.RequerySuggested-=value;
            }
        }

        public bool CanExecute(object? parameter)
        {
            return canExecute==null ? true : canExecute(parameter);
        }

        public void Execute(object? parameter)
        {
            execute(parameter);
        }
    }
}

 

posted @ 2025-08-15 22:41  FredGrit  阅读(12)  评论(0)    收藏  举报