将 WPF 画布保存到文件而不损失质量(不使用位图作为中介)

Posted

技术标签:

【中文标题】将 WPF 画布保存到文件而不损失质量(不使用位图作为中介)【英文标题】:Saving WPF Canvas to file without losing quality (Without using Bitmap as intermediary) 【发布时间】:2019-05-18 08:57:07 【问题描述】:

我的任务是为一些动态制冷剂特性创建列线图。 (Nomograph Examples)。具体来说,我必须创建一个程序,该程序接受用户输入,然后生成可打印的列线图图形。我必须与几个外部黑盒 .dll 交互才能获取一些数据,所以我认为 .NET 是我使用的最佳平台。鉴于没有现成的工具可以轻松创建所有 4 个轴都基于用户输入的非常复杂的图形,因此我将其构建为仅在 WPF 画布上绘制线条和文本。一切都很好;缩放,平移,所有这些。不过我有一个问题。

我找到的将 WPF 画布保存到文件(例如 png)的每个答案都使用位图作为到达那里的路径。这个问题,我已经尝试过并让它工作,是生成的图像失去了所有的可伸缩性,并且取决于画布的大小,很多质量。 XAML 应该是全矢量图形,因为这是一个将大量信息打包到一个小区域中的图形,所以我需要一个可扩展的结果。

注意:这不是所有其他“如何将 WPF 画布保存到文件”问题的副本。

我尝试过的事情:

    所有其他“如何将 WPF 画布保存到文件”的答案。 增加RenderTargetBitmap() 方法中的dpi 输入。 (注意:这只是放大左上角的图像,使其无法使用)

想法

我想也许如果没有办法按照我的要求做,也可以在保存之前将画布及其所有子元素缩放到非常大的东西,也许制作一个副本,然后保存它?事实是,我完全不知道该怎么做,我宁愿看看有没有办法先保存到矢量图形。

这是我的 XAML:

<Window x:Class="RefGraph.Graph"
    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:RefGraph"
    mc:Ignorable="d"
    Title="Graph" Height="1081" Width="1400">
<Grid>
    <Viewbox>
        <Canvas Height="Binding Path=CanvasHeight" Width="Binding Path=CanvasWidth" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,20,0,0" MouseWheel="Canvas_MouseWheel" MouseMove="Canvas_MouseMove" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseLeftButtonUp="Canvas_MouseLeftButtonUp">
            <Canvas.RenderTransform>
                <TransformGroup>
                    <TranslateTransform/>
                    <MatrixTransform/>
                </TransformGroup>
            </Canvas.RenderTransform>
            <ContentPresenter Content="Binding Canvas"></ContentPresenter>
        </Canvas>
    </Viewbox>
    <Menu x:Name="Menu_Main" Width="Binding ActualWidth, ElementName=DockPanel_Menu" Height="20" VerticalAlignment="Top">
        <MenuItem x:Name="Menu_File" Header="_File">
            <MenuItem x:Name="MenuItem_Save" Header="_Save" InputGestureText="Ctrl+S" VerticalAlignment="Top" HorizontalAlignment="Left" Click="MenuItem_Save_Click"/>
            <MenuItem x:Name="MenuItem_SaveAs" Header="_Save As" InputGestureText="Ctrl+Shift+S" VerticalAlignment="Top" HorizontalAlignment="Left" />
            <MenuItem x:Name="MenuItem_Print" Header="_Print" InputGestureText="Ctrl+P" VerticalAlignment="Top" HorizontalAlignment="Left" />
            <MenuItem x:Name="MenuItem_PrintPreview" Header="_Print Preview" InputGestureText="Ctrl+Shift+P" VerticalAlignment="Top" HorizontalAlignment="Left"/>
            <Separator />
            <MenuItem Header="_Exit" InputGestureText="Ctrl+X" VerticalAlignment="Top" HorizontalAlignment="Left" />
            </MenuItem>
    </Menu>
</Grid>
</Window>

我应该注意到,在保存之前有许多子元素会动态添加到画布中。

另一个说明:出于某种原因,我认为 PNG 是矢量图形。老实说,我不知道为什么。我想这个问题不是专门关于 PNG 的,而是更多关于保存质量不差的画布,这是通过使用本网站上现有的答案所必需的。我已经编辑了这个问题以反映这一点,并且我也发布了一个答案。

【问题讨论】:

没有必要大喊 :) 我已经为你修好了帖子 @CamiloTerevinto 谢谢 :) 我的建议是研究 PDF 或 OpenXPS 等矢量文件格式,这两种格式都可以处理缩放、字体、旋转等。两者都是极其复杂的格式,我不知道有什么简单的方法可以从 XAML 中获取。 @DourHighArch 我想出了一个关于如何在不损失质量的情况下将其保存为 PDF 的答案,但严格来说,这不是对所述问题的答案。我想正确地做到这一点。我应该编辑帖子吗?写我自己的答案?两者都有? 【参考方案1】:

要将 Canvas 或大多数其他 XAML 元素保存到 PDF,您需要引用 PresentationFramework 和 System.Printing。

然后,您可以创建一个 PrintDialog,设置您想要的任何首选项,然后使用它保存到 PDF。

void SaveCanvasToPDF(Canvas myCanvas)
    PrintDialog pd = new PrintDialog();
    pd.PrintQueue = new PrintQueue(new PrintServer(), "Microsoft Print to PDF");
    pd.PrintTicket.PageOrientation = PageOrientation.Landscape;
    pd.PrintTicket.PageScalingFactor = 100;
    pd.PrintVisual(myCanvas, "Nomograph");

【讨论】:

【参考方案2】:

既然您在谈论图像的清晰度。您能否尝试将现有的 WPF 画布转换为 SVG(可缩放矢量图形)文件。我还没有尝试过。希望以下链接对您有所帮助。

https://archive.codeplex.com/?p=svg

https://github.com/vvvv/SVG

【讨论】:

以上是关于将 WPF 画布保存到文件而不损失质量(不使用位图作为中介)的主要内容,如果未能解决你的问题,请参考以下文章

拍照并保存到 SD 而不损失质量

在 android 中减小图像大小而不损失其质量

将剪贴板中的位图保存到 wpf 应用程序中的 png

如何在 Android 上旋转 JPEG 文件而不损失质量和增加文件大小?

如何在不损失图像质量的情况下调整图像大小以适合小型 HTML5 画布? [复制]

Wpf:从 zip 加载图像源而不保存文件