在 WinRT 应用程序中使用矩形几何进行裁剪

Clipping Using Rectangle Geometry in WinRT application

我以前使用 WriteableBitmapEX 库在鼠标移动的任何地方裁剪图像。好像有点慢。

我想以任意随机像素裁剪图像,我想将该裁剪区域分配给另一个图像控件。

我的问题是当我使用剪辑 属性 时,我只剩下剪辑区域,整个图像都在运行。我希望图像完全在背景中,但应将裁剪区域分配给图像控件。

这是代码。

 private void Image1_Tapped(object sender, TappedRoutedEventArgs e)
        {
            int CropArea = 50;
            int PointShift = CropArea / 2;
            var _rect = new RectangleGeometry();
            Point pt;
            pt = e.GetPosition(Image1);

            _rect.Rect = new Rect(pt.X - PointShift, pt.Y - PointShift, 100, 100);
            Image1.Clip = _rect;
            MagnifyTip.Image1.Source=Image1.clip; //This is what I want to do . Its not happenning. 
        }


<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Image x:Name="Image1" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center" Tapped="Image1_Tapped" >
            <Image.Source >
                <BitmapImage UriSource="Assets/Jellyfish.png" />
            </Image.Source>
        </Image>
    </Grid>

欢迎任何更好的解决方案,因为我必须继续在图像周围移动手指,并在我的用户控件的图像框中逐个像素地获取更新的像素裁剪图像

裁剪需要注意的几点

  1. 为图像的 Clip 属性 使用 RectangleGeometry(您已经这样做了)
  2. 调整裁剪几何图形时 - 使用它的 Transform 属性 而不是每次要重新裁剪时都创建一个新的几何图形。
  3. 更新 WriteableBitmap 相当慢,因此您可以偶尔更新一次 - 例如当您提交裁剪矩形时,但不像每个 PointerMove 事件那样实时提交。
  4. 如果你想要实时更新,你可以
    • 将另一个 Image 元素与另一个 RectangleGeometry Clip 元素一起使用,其中一个变换是原始变换的缩放版本。您也可以使用原始变换的副本并缩放整个 Image
    • 使用 DirectX 在 SwapChainPanel 中呈现转换后的输出。
  5. 对于最终的高分辨率输出,您可以使用任何方法,因为处理速度不是一个重要因素
    • 您可以使用 RenderTargetBitmap.RenderAsync() 以屏幕分辨率呈现裁剪后的图像。您可能需要将剪裁后的图像包裹在另一个元素中,例如 Grid.
    • 您可以使用 WriteableBitmap 进行处理 - 我相信 CodePlex 上的 WriteableBitmapEx project 有旋转和裁剪的方法。这是基于 CPU 的。
    • 您可以使用 DirectX,但这可能有点矫枉过正。
    • 您可以将 WIC 与 BitmapDecoder 一起使用,但旋转功能有限:How to resize Image in C# WinRT/winmd?

好吧,你不想在背景中剪裁你想要的图像,你想要两个单独的图像控件并且只剪裁你正在放大的图像,这是我如何使用 Canvas和两个图像控件。

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="canvas">
        <Image Canvas.ZIndex="0"  x:Name="Image1" ImageOpened="Image1_Opened" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center" Tapped="Image1_Tapped" >
            <Image.Source>
                <BitmapImage UriSource="Assets/JellyFish.png" />
            </Image.Source>
        </Image>
        <Image Canvas.ZIndex="1" x:Name="MagnifyTip" Visibility="Collapsed">
            <Image.Source >
                <BitmapImage UriSource="Assets/JellyFish.png" />
            </Image.Source>
        </Image>
    </Canvas>
</Grid>

加载背景图片后,您想要在 canvas 中设置图片的大小。

    double _scaleX = 5;
    double _scaleY = 5;
    double _croppedImageWidth = 100;
    double _croppedImageHeight = 100;

    private void Image1_Opened(object sender, RoutedEventArgs e)
    {
        this.Image1.MaxHeight = this.canvas.ActualHeight;
        this.Image1.MaxWidth = this.canvas.ActualWidth;
        this.MagnifyTip.MaxHeight = this.canvas.ActualHeight;
        this.MagnifyTip.MaxWidth = this.canvas.ActualWidth;
        this.MagnifyTip.RenderTransform = new ScaleTransform() 
        { 
            ScaleX = _scaleX,
            ScaleY = _scaleY
        };
    }

然后您可以在 Image1_Tapped 处理程序中设置放大图像的位置和比例。

    private void Image1_Tapped(object sender, TappedRoutedEventArgs e)
    {
        Point pt = e.GetPosition(this.canvas);
        this.MagnifyTip.Clip = new RectangleGeometry()
        {
            Rect = new Rect()
            {
                X = pt.X, 
                Y = pt.Y, 
                Width = _croppedImageWidth / _scaleX,
                Height = _croppedImageHeight / _scaleY
            }
        };
        Canvas.SetLeft(this.MagnifyTip, -pt.X * (_scaleX - 1));
        Canvas.SetTop(this.MagnifyTip, -pt.Y * (_scaleY - 1));

        this.MagnifyTip.Visibility = Visibility.Visible;
    }

重点是

  • 使用 Canvas Left, Top and ZIndex 属性将放大图像叠加在背景图像上。
  • 根据点击点和比例大小计算放大图像的剪辑大小和位置。
  • 使用ScaleTransform放大图像。