从 WPF 中提取剪辑 Canvas

Extract Clip from WPF Canvas

我在尝试不仅剪辑而且“提取”WPF 的一部分时遇到问题 Canvas。所以基本上我希望“剪辑”扩展到 window 的完整大小,或者将剪辑的项目转换为单独的 UI 元素以导出到 PNG。我写伪代码是因为真正的代码来自 Autocad 模型。

double oPrintWidth=1169;

Canvas c = new Canvas();
 
c.Width = oPrintWidth * 2.54;
c.Height = c.Width * ratio;

// Define the path to clip
string thisPathData = "M12233 M222333 M3443" // fake
c.Clip = Geometry.Parse(thisPathData);

此时我有相同的大小 canvas 但除了我的路径之外的所有内容现在都是黑色的。而且路径还在原来的位置。我现在需要将剪辑制作成整个 canvas.

我玩过 RenderTransform 但我不知道下一步该做什么,我不太擅长矩阵计算。

原创 Canvas(UI 元素的集合)

剪辑后

期望的结果

最终会打印出来,但更愿意将其保留在 WPF 中直到最后一分钟,以保留 VECTOR 属性以转换为 SVG/XPS/ETC

要制作整个 CanvasClip,然后将 Clip 应用到 Canvas,我建议您让 WPF 为您设置 ClipToBounds 属性:

Canvas c = new Canvas();
c.ClipToBounds = true;

如果这不符合您的需要,我会查看 MarginActualWidthActualHeight 属性来确定剪辑区域。然后创建一个与 Canvas.

大小匹配的 RectangleGeometry


根据您的评论进行编辑。

好吧,我还有一些时间来处理它。我能够做的是创建一个剪辑区域,然后我转换 canvas 以便剪辑区域尽可能多地填充 canvas。我想这就是你想要的...

首先我需要测量裁剪区域:

Rect bounds = canvas.Clip.Bounds;
double scaleX = c.Width / (bounds.Right - bounds.Left);
double scaleY = c.Height / (bounds.Bottom - bounds.Top);

此缩放信息用于使裁剪区域完全适合 canvas 的大小。 现在,我们需要将转换应用于 canvas:

TransformGroup group = new TransformGroup();
TranslateTransform move = new TranslateTransform(-bounds.Left, -bounds.Top);
ScaleTransform scale = new ScaleTransform(scaleX, scaleY);
group.Children.Add(move);
group.Children.Add(scale);
canvas.RenderTransform = group;

那么这里发生了什么?首先,objective 是应用几个转换。我们需要将裁剪区域居中(平移)并且我们需要使裁剪区域更大(缩放)。现在,当我说裁剪区域时,我指的是该区域的内容。实际上,我们正在移动 canvas 的渲染输出。移动区域边界不是我们想要做的。

要在 WPF 中执行此操作,我们需要将我们想要的每个转换添加到 TransformGroup 的子级。 在这种情况下,我们正在翻译 canvas 的输出,使其左上角为 (0, 0) 这是必要的,因为之后我们将缩放渲染输出。所以,现在,我们需要缩放 canvas 的输出,使图像尽可能大。为此,我们需要创建一个比率,将 canvas 大小与裁剪区域大小进行比较。

这里是缩放输出的公式:

ratio = canvasSize / clippedSize
scaledSize = clippsedSize * ratio

现在,缩放 canvas 的输出将使裁剪区域看起来尽可能大。

看看结果。以下图片展示了应用转换前后 canvas 的输出:

之前

之后

我想我不妨把我用过的所有代码都给你:

Canvas c = new Canvas();
double oPrintWidth=100;
double ratio = .89;
c.Width = oPrintWidth * 2.54;
c.Height = c.Width * ratio;
c.Background = new ImageBrush((ImageSource)FindResource("TestImage")) { Stretch = Stretch.UniformToFill };

// Define the path to clip
string newPath = "M 64,64 L 64,128 128,128, 128,64 Z";
c.Clip = Geometry.Parse(newPath);

Rect bounds = c.Clip.Bounds;
double scaleX = c.Width / (bounds.Right - bounds.Left);
double scaleY = c.Height / (bounds.Bottom - bounds.Top);
TransformGroup group = new TransformGroup();
TranslateTransform move = new TranslateTransform(-bounds.Left, -bounds.Top);
ScaleTransform scale = new ScaleTransform(scaleX, scaleY);
group.Children.Add(move);
group.Children.Add(scale);
c.RenderTransform = group;

MyBorder.Child = c;

和 XAML:

<Window.Resources>
    <BitmapImage UriSource="uvtest.jpg" x:Key="TestImage"/>
</Window.Resources>
<Grid Background="Gray">
    <Border x:Name="MyBorder" Background="White" BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>