WPF draw triangle, add right button contextmenu and menuitem method,save triangle as jpeg,via rendertargetment, DrawingContext StreamGeometry,StreamGeometryContext

private void SaveTriangleAsPicture()
{
    if (triangle == null)
    {
        MessageBox.Show("No triangle to save!");
        return;
    }

    try
    {
        SaveFileDialog dialog = new SaveFileDialog()
        {
            Filter = "PNG Image|*.png|Jpeg Image|*.jpg|BMP Image|*.bmp",
            Title = "Save Triangle as Picture",
            FileName = $"Triangle_{DateTime.Now:yyyyMMddHHmmssffff}.png"
        };

        if (dialog.ShowDialog() == true)
        {
            BitmapEncoder bmpEncoder = System.IO.Path.GetExtension(dialog.FileName).ToLower() switch
            {
                ".jpg" or ".jpeg" => new JpegBitmapEncoder(),
                ".bmp" => new BmpBitmapEncoder(),
                _ => new PngBitmapEncoder()
            };

            // Calculate the bounds of the triangle
            Rect bounds = GetTriangleBounds(triangle);

            // Add some padding around the triangle
            double padding = 10;
            bounds = new Rect(
                bounds.X - padding,
                bounds.Y - padding,
                bounds.Width + padding * 2,
                bounds.Height + padding * 2);

            // Create a visual for the triangle only
            DrawingVisual drawingVisual = new DrawingVisual();
            using (DrawingContext drawingContext = drawingVisual.RenderOpen())
            {
                // Draw white background
                drawingContext.DrawRectangle(Brushes.White, null, bounds);

                // Draw the triangle
                DrawTriangleGeometry(drawingContext, triangle, bounds);
            }

            var dpi=VisualTreeHelper.GetDpi(this);

            // Render the visual to bitmap
            RenderTargetBitmap rtb = new RenderTargetBitmap(
                (int)(bounds.Width*dpi.DpiScaleX),
                (int)(bounds.Height*dpi.DpiScaleY),
                dpi.PixelsPerInchX, 
                dpi.PixelsPerInchY,
                PixelFormats.Pbgra32);

            rtb.Render(drawingVisual);

            // Save to file
            using (FileStream fileStream = new FileStream(dialog.FileName, FileMode.Create))
            {
                bmpEncoder.Frames.Add(BitmapFrame.Create(rtb));
                bmpEncoder.Save(fileStream);
            }

            MessageBox.Show($"Triangle saved as {dialog.FileName} successfully!");
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

private Rect GetTriangleBounds(Polygon triangle)
{
    if (triangle.Points.Count == 0)
    {
        return new Rect(0, 0, sideLength, sideLength);
    }                

    double minX = triangle.Points[0].X;
    double maxX = triangle.Points[0].X;
    double minY = triangle.Points[0].Y;
    double maxY = triangle.Points[0].Y;

    foreach (Point point in triangle.Points)
    {
        if (point.X < minX)
        {
            minX = point.X;
        }
        if (point.X > maxX)
        {
            maxX = point.X;
        }
        if (point.Y < minY)
        {
            minY = point.Y;
        }
        if (point.Y > maxY)
        {
            maxY = point.Y;
        }
    }
    return new Rect(minX, minY, maxX - minX, maxY - minY);
}

private void DrawTriangleGeometry(DrawingContext drawingContext, 
    Polygon triangle, Rect bounds)
{
    // Create a stream geometry for the triangle
    StreamGeometry geometry = new StreamGeometry();
    using (StreamGeometryContext streamGeoContext = geometry.Open())
    {
        streamGeoContext.BeginFigure(triangle.Points[0], true, true);
        streamGeoContext.PolyLineTo(new List<Point>(triangle.Points), true, true);
    }

    // Apply translation to position the triangle correctly
    TransformGroup transformGroup = new TransformGroup();
    transformGroup.Children.Add(new TranslateTransform(-bounds.X, -bounds.Y));

    geometry.Transform = transformGroup;
    geometry.Freeze();

    // Draw the triangle with the same properties as the original
    drawingContext.DrawGeometry(triangle.Fill, new Pen(triangle.Stroke, 
        triangle.StrokeThickness), geometry);
}

 

 

 

 

 

 

image

 

 

 

 

 

image

 

 

 

 

 

 

 

 

image

 

 

 

 

 

 

 

 

 

 

 

 

image

 

 

 

//xaml
<Window x:Class="WpfApp15.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:WpfApp15"
        mc:Ignorable="d"
        WindowState="Maximized"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Canvas x:Name="cvs"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                Background="Transparent"/>
    </Grid>
</Window>



//cs
using Microsoft.Win32;
using System.IO;
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 WpfApp15
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private double sideLength = 100.0d;
        private Polygon triangle = null;
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            DrawTriangle();
        }

        private void DrawTriangle()
        {
            try
            {
                cvs.Children.Clear();
                double centerX = cvs.ActualWidth / 2;
                double centerY = cvs.ActualHeight / 2;

                double height = (Math.Sqrt(3) / 2) * sideLength;

                Point topPt = new Point(centerX, centerY - height / 2);
                Point leftPt = new Point(centerX - sideLength / 2, centerY + height / 2);
                Point rightPt = new Point(centerX + sideLength / 2, centerY + height / 2);

                triangle = new Polygon()
                {
                    Stroke = Brushes.Black,
                    StrokeThickness = 2,
                    Fill = Brushes.Red
                };

                triangle.Points.Add(topPt);
                triangle.Points.Add(leftPt);
                triangle.Points.Add(rightPt);
                CreateTriagnleWithContextMenu(triangle);
                cvs.Children.Add(triangle);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void CreateTriagnleWithContextMenu(Polygon triangle)
        {
            ContextMenu contextMenu = new ContextMenu();

            //Save As Picture menu item.
            MenuItem saveMenuItem = new MenuItem();
            saveMenuItem.Header = "Save As Picture";
            saveMenuItem.Click += (s, e) => SaveTriangleAsPicture();

            //Remove
            MenuItem removeItem = new MenuItem();
            removeItem.Header = "Remove Triangle";
            removeItem.Click += (s, e) => RemoveTriangle();

            contextMenu.Items.Add(saveMenuItem);
            contextMenu.Items.Add(removeItem);

            triangle.ContextMenu = contextMenu;

            triangle.MouseRightButtonDown += (s, e) =>
            {
                triangle.ContextMenu.IsOpen = true;
                e.Handled = true;
            };
        }

        private void RemoveTriangle()
        {
            try
            {
                if(triangle!=null)
                {
                    cvs.Children.Remove(triangle);
                    triangle = null;
                    MessageBox.Show("Triangle has been removed!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        private void SaveTriangleAsPicture()
        {
            if (triangle == null)
            {
                MessageBox.Show("No triangle to save!");
                return;
            }

            try
            {
                SaveFileDialog dialog = new SaveFileDialog()
                {
                    Filter = "PNG Image|*.png|Jpeg Image|*.jpg|BMP Image|*.bmp",
                    Title = "Save Triangle as Picture",
                    FileName = $"Triangle_{DateTime.Now:yyyyMMddHHmmssffff}.png"
                };

                if (dialog.ShowDialog() == true)
                {
                    BitmapEncoder bmpEncoder = System.IO.Path.GetExtension(dialog.FileName).ToLower() switch
                    {
                        ".jpg" or ".jpeg" => new JpegBitmapEncoder(),
                        ".bmp" => new BmpBitmapEncoder(),
                        _ => new PngBitmapEncoder()
                    };

                    // Calculate the bounds of the triangle
                    Rect bounds = GetTriangleBounds(triangle);

                    // Add some padding around the triangle
                    double padding = 10;
                    bounds = new Rect(
                        bounds.X - padding,
                        bounds.Y - padding,
                        bounds.Width + padding * 2,
                        bounds.Height + padding * 2);

                    // Create a visual for the triangle only
                    DrawingVisual drawingVisual = new DrawingVisual();
                    using (DrawingContext drawingContext = drawingVisual.RenderOpen())
                    {
                        // Draw white background
                        drawingContext.DrawRectangle(Brushes.White, null, bounds);

                        // Draw the triangle
                        DrawTriangleGeometry(drawingContext, triangle, bounds);
                    }

                    var dpi=VisualTreeHelper.GetDpi(this);

                    // Render the visual to bitmap
                    RenderTargetBitmap rtb = new RenderTargetBitmap(
                        (int)(bounds.Width*dpi.DpiScaleX),
                        (int)(bounds.Height*dpi.DpiScaleY),
                        dpi.PixelsPerInchX, 
                        dpi.PixelsPerInchY,
                        PixelFormats.Pbgra32);

                    rtb.Render(drawingVisual);

                    // Save to file
                    using (FileStream fileStream = new FileStream(dialog.FileName, FileMode.Create))
                    {
                        bmpEncoder.Frames.Add(BitmapFrame.Create(rtb));
                        bmpEncoder.Save(fileStream);
                    }

                    MessageBox.Show($"Triangle saved as {dialog.FileName} successfully!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private Rect GetTriangleBounds(Polygon triangle)
        {
            if (triangle.Points.Count == 0)
            {
                return new Rect(0, 0, sideLength, sideLength);
            }                

            double minX = triangle.Points[0].X;
            double maxX = triangle.Points[0].X;
            double minY = triangle.Points[0].Y;
            double maxY = triangle.Points[0].Y;

            foreach (Point point in triangle.Points)
            {
                if (point.X < minX)
                {
                    minX = point.X;
                }
                if (point.X > maxX)
                {
                    maxX = point.X;
                }
                if (point.Y < minY)
                {
                    minY = point.Y;
                }
                if (point.Y > maxY)
                {
                    maxY = point.Y;
                }
            }
            return new Rect(minX, minY, maxX - minX, maxY - minY);
        }

        private void DrawTriangleGeometry(DrawingContext drawingContext, 
            Polygon triangle, Rect bounds)
        {
            // Create a stream geometry for the triangle
            StreamGeometry geometry = new StreamGeometry();
            using (StreamGeometryContext streamGeoContext = geometry.Open())
            {
                streamGeoContext.BeginFigure(triangle.Points[0], true, true);
                streamGeoContext.PolyLineTo(new List<Point>(triangle.Points), true, true);
            }

            // Apply translation to position the triangle correctly
            TransformGroup transformGroup = new TransformGroup();
            transformGroup.Children.Add(new TranslateTransform(-bounds.X, -bounds.Y));

            geometry.Transform = transformGroup;
            geometry.Freeze();

            // Draw the triangle with the same properties as the original
            drawingContext.DrawGeometry(triangle.Fill, new Pen(triangle.Stroke, 
                triangle.StrokeThickness), geometry);
        }
    }
}

 

posted @ 2025-09-27 21:06  FredGrit  阅读(11)  评论(0)    收藏  举报