简体   繁体   English

如何从 ScrollViewer 中的图像捕获画布区域

[英]How can I capture the canvas area from the Image in the ScrollViewer

I use the scrollviewer to zoom in or out of the picture, and it has been successful.我用scrollviewer放大或缩小图片,已经成功了。 Now I hope to draw an area on the picture and capture the area to an image.现在我希望在图片上绘制一个区域并将该区域捕获为图像。 But the image I get is blank except the border.但是我得到的图像除了边框是空白的。 Here is my code.这是我的代码。

XAML: XAML:

<Window x:Class="Capture.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:Capture"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Slider Grid.Column="0" Orientation="Vertical" 
                HorizontalAlignment="Left" Minimum="1" x:Name="slider"/>
        
        
        <ScrollViewer Name="scrollViewer" Grid.Column="1" 
                      VerticalScrollBarVisibility="Visible" 
                      HorizontalScrollBarVisibility="Visible" Margin="0,0,0,40">

            <Grid Name="grid" Width="400" Height="400" >
                <Grid.LayoutTransform>
                    <TransformGroup x:Name="TfGroup">
                        <ScaleTransform x:Name="scaleTransform"/>
                    </TransformGroup>
                </Grid.LayoutTransform>
                <Viewbox Grid.Column="0" Grid.Row="0">
                    <Image x:Name="img" Source="C:\Users\citic\Desktop\微信截图_20200728104010.png" />
                </Viewbox>
                <Canvas x:Name="canvas" MouseDown="Canvas_MouseDown" MouseMove="Canvas_MouseMove" MouseUp="Canvas_MouseUp" Background="Transparent"/>
            </Grid>

        </ScrollViewer>
        <Button Grid.Column="1" Content="Capture" Margin="338,381,337.333,9.667" Click="Button_Click"/>
    </Grid>
</Window>

public partial class MainWindow : Window
    {
        Point? lastCenterPositionOnTarget;
        Point? lastMousePositionOnTarget;
        Point? lastDragPoint;

        private System.Windows.Point startPoint;
        private System.Windows.Shapes.Rectangle rect;

        private int w1;
        private int h1;

        public MainWindow()
        {
            InitializeComponent();

            scrollViewer.ScrollChanged += OnScrollViewerScrollChanged;

            scrollViewer.PreviewMouseLeftButtonUp += OnMouseLeftButtonUp;
            scrollViewer.PreviewMouseWheel += OnPreviewMouseWheel;

            slider.ValueChanged += OnSliderValueChanged;
        }

        void OnScrollViewerScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.ExtentHeightChange != 0 || e.ExtentWidthChange != 0)
            {
                Point? targetBefore = null;
                Point? targetNow = null;

                if (!lastMousePositionOnTarget.HasValue)
                {
                    if (lastCenterPositionOnTarget.HasValue)
                    {
                        var centerOfViewport = new Point(scrollViewer.ViewportWidth / 2,
                                                         scrollViewer.ViewportHeight / 2);
                        Point centerOfTargetNow =
                              scrollViewer.TranslatePoint(centerOfViewport, grid);

                        targetBefore = lastCenterPositionOnTarget;
                        targetNow = centerOfTargetNow;
                    }
                }
                else
                {
                    targetBefore = lastMousePositionOnTarget;
                    targetNow = Mouse.GetPosition(grid);

                    lastMousePositionOnTarget = null;
                }

                if (targetBefore.HasValue)
                {
                    double dXInTargetPixels = targetNow.Value.X - targetBefore.Value.X;
                    double dYInTargetPixels = targetNow.Value.Y - targetBefore.Value.Y;

                    double multiplicatorX = e.ExtentWidth / grid.Width;
                    double multiplicatorY = e.ExtentHeight / grid.Height;

                    double newOffsetX = scrollViewer.HorizontalOffset -
                                        dXInTargetPixels * multiplicatorX;
                    double newOffsetY = scrollViewer.VerticalOffset -
                                        dYInTargetPixels * multiplicatorY;

                    if (double.IsNaN(newOffsetX) || double.IsNaN(newOffsetY))
                    {
                        return;
                    }

                    scrollViewer.ScrollToHorizontalOffset(newOffsetX);
                    scrollViewer.ScrollToVerticalOffset(newOffsetY);
                }
            }
        }

        private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            scrollViewer.Cursor = Cursors.Arrow;
            scrollViewer.ReleaseMouseCapture();
            lastDragPoint = null;
        }

        private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            lastMousePositionOnTarget = Mouse.GetPosition(grid);

            System.Windows.Point centerPoint = e.GetPosition(img);

            var val = e.Delta * 0.01;   //描述鼠标滑轮滚动

            if (scaleTransform.ScaleX + val < 0.1) return;
            if (scaleTransform.ScaleX + val > 100) return;

            scaleTransform.CenterX = centerPoint.X;
            scaleTransform.CenterY = centerPoint.Y;

            scaleTransform.ScaleX += val;
            scaleTransform.ScaleY += val;


            if (e.Delta > 0)
            {
                slider.Value += 1;
            }
            if (e.Delta < 0)
            {
                slider.Value -= 1;
            }

            e.Handled = true;
        }

        private void OnSliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            scaleTransform.ScaleX = e.NewValue;
            scaleTransform.ScaleY = e.NewValue;

            var centerOfViewport = new System.Windows.Point(scrollViewer.ViewportWidth / 2, scrollViewer.ViewportHeight / 2);

            lastCenterPositionOnTarget = scrollViewer.TranslatePoint(centerOfViewport, grid);
        }

        private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            canvas.Children.Clear();

            startPoint = e.GetPosition(canvas);

            rect = new System.Windows.Shapes.Rectangle
            {
                Stroke = System.Windows.Media.Brushes.IndianRed,
                StrokeThickness = 0.2,
                StrokeDashArray = new DoubleCollection { 2 }
            };
            Canvas.SetLeft(rect, startPoint.X);
            Canvas.SetTop(rect, startPoint.Y);
            canvas.Children.Add(rect);
        }

        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Released || rect == null)
                return;

            var pos = e.GetPosition(canvas);

            var x = Math.Min(pos.X, startPoint.X);
            var y = Math.Min(pos.Y, startPoint.Y);

            var w = Math.Max(pos.X, startPoint.X) - x;
            var h = Math.Max(pos.Y, startPoint.Y) - y;

            w1 = (int)w;
            h1 = (int)h;

            rect.Width = w;
            rect.Height = h;

            Canvas.SetLeft(rect, x);
            Canvas.SetTop(rect, y);
        }

        private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {

        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var rect = new Rect(canvas.RenderSize);
            var visual = new DrawingVisual();

            using (var dc = visual.RenderOpen())
            {
                dc.DrawRectangle(new VisualBrush(canvas), null, rect);
            }

            var bitmap = new RenderTargetBitmap(
                (int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Default);
            bitmap.Render(visual);

            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(bitmap));

            using (var file = File.OpenWrite(@"C:\Users\citic\Desktop\test.jpg"))
            {
                encoder.Save(file);
            }
        }
    }

I am a WPF novice, and many contents are still learning.我是WPF新手,很多内容还在学习中。 Please help me, thank you!请帮帮我,谢谢!

The reason why it isn't working is because you're only capturing the Canvas and converting it to a bitmap.它不起作用的原因是因为您只是捕获 Canvas 并将其转换为位图。 If you look at your layout the Image is on another layer.如果您查看布局,则图像位于另一层。 It is not placed on the Canvas.它没有放置在画布上。

<Grid>
    <Viewbox>
        <Image /> <!-- This is on a separate layer of the layout -->
    </Viewbox>
    <Canvas /> <!-- You're only capturing this -->
</Grid>

Instead of capturing the Canvas, maybe you should try the Grid instead.与其捕获 Canvas,不如尝试使用 Grid。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM