模糊 XAML 矢量图形

Blurry XAML vector graphics

为了使我的 WPF 应用程序具有高 DPI 感知能力,我选择使用嵌入式 XAML 矢量图形创建所有内部图形和图标。

但是,我不明白为什么我的 XAML 矢量图在渲染时很模糊。这是一个例子。我使用 XAML 路径和矩形元素绘制了一个简单的软盘图标。下图是同一图标以两种不同的大小呈现,并具有不同的 SnapsToDevicePixelsUseLayoutRounding 值(这是在 Windows 7 中我显示器的原始分辨率 2048x1152)。

鉴于图标主要是水平和垂直线,所以看起来奇怪地模糊。这是较大图标的 600% 缩放视图:

以及较小的图标:

两种尺寸的边缘都不清晰。并且随着 SnapsToDevicePixels 的不同值,一些边缘是清晰的,但其他边缘仍然不是。

绘制这样的图标才不会模糊不清的正确方法是什么?

这里是这个window的XAML,包括路径数据:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="XAML Path Test" Height="175" Width="525">
    <Window.Resources>
        <ResourceDictionary>
            <Canvas x:Key="icon">
                <Path Width="84" Height="83" Canvas.Left="6.5" Canvas.Top="9.5" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FFFFFFFF" Data="F1 M 9,12L 68.9914,12L 88,31.0086L 88,90L 9,90L 9,12 Z "/>
                <Rectangle Width="43" Height="41" Canvas.Left="23.5" Canvas.Top="9.5" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FF000000"/>
                <Rectangle Width="23" Height="31" Canvas.Left="38.5" Canvas.Top="11.25" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FFFFFFFF"/>
            </Canvas>
        </ResourceDictionary>
    </Window.Resources>
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Rectangle Width="50" Height="50" Margin="10">
                <Rectangle.Fill>
                    <VisualBrush Visual="{StaticResource icon}"/>
                </Rectangle.Fill>
            </Rectangle>

            <Rectangle Width="50" Height="50" Margin="10" SnapsToDevicePixels="True">
                <Rectangle.Fill>
                    <VisualBrush Visual="{StaticResource icon}"/>
                </Rectangle.Fill>
            </Rectangle>

            <Rectangle Width="50" Height="50" Margin="10" UseLayoutRounding="True" SnapsToDevicePixels="True">
                <Rectangle.Fill>
                    <VisualBrush Visual="{StaticResource icon}"/>
                </Rectangle.Fill>
            </Rectangle>
        </StackPanel>

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Rectangle Width="24" Height="24" Margin="10">
                <Rectangle.Fill>
                    <VisualBrush Visual="{StaticResource icon}"/>
                </Rectangle.Fill>
            </Rectangle>

            <Rectangle Width="24" Height="24" Margin="10" SnapsToDevicePixels="True">
                <Rectangle.Fill>
                    <VisualBrush Visual="{StaticResource icon}"/>
                </Rectangle.Fill>
            </Rectangle>

            <Rectangle Width="24" Height="24" Margin="10" UseLayoutRounding="True" SnapsToDevicePixels="True">
                <Rectangle.Fill>
                    <VisualBrush Visual="{StaticResource icon}"/>
                </Rectangle.Fill>
            </Rectangle>
        </StackPanel>
    </StackPanel>
</Window>

编辑:

按照 Chris W. 的建议将路径+矩形包裹在 ControlTemplate 中,并使用 Viewbox 调整大小,图像仍然模糊。从左到右,这是未调整大小(canvas 大小为 100x100)、调整大小为 50 和调整大小为 24:

以及 600% 缩放视图:

这是 ControlTemplate:

<ControlTemplate x:Key="icon">
    <Canvas Width="100" Height="100">
        <Path Width="84" Height="83" Canvas.Left="6.5" Canvas.Top="9.5" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FFFFFFFF" Data="F1 M 9,12L 68.9914,12L 88,31.0086L 88,90L 9,90L 9,12 Z "/>
        <Rectangle Width="43" Height="41" Canvas.Left="23.5" Canvas.Top="9.5" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FF000000"/>
        <Rectangle Width="23" Height="31" Canvas.Left="38.5" Canvas.Top="11.25" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FFFFFFFF"/>
    </Canvas>
</ControlTemplate>

以及用法:

<Control Template="{StaticResource icon}"/>
<Viewbox Height="50">
    <Control Template="{StaticResource icon}"/>
</Viewbox>
<Viewbox Height="24">
    <Control Template="{StaticResource icon}"/>
</Viewbox>

您的问题是您正在使用 VisualBrush 在其中绘制一个区域并且您失去了实际矢量状态。

有很多 other ways 可以根据您的实际需要和您打算用它做什么来完成这个,但是对于您的特定实例,仅根据我所看到的,我会把它切换成这样的而不是只使用 ControlTemplate

<Window>
    <Window.Resources>      
        <ControlTemplate x:Key="icon">
            <Canvas>
               <Path Width="84" Height="83" Canvas.Left="6.5" Canvas.Top="9.5" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FFFFFFFF" Data="F1 M 9,12L 68.9914,12L 88,31.0086L 88,90L 9,90L 9,12 Z "/>
                <Rectangle Width="43" Height="41" Canvas.Left="23.5" Canvas.Top="9.5" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FF000000"/>
                <Rectangle Width="23" Height="31" Canvas.Left="38.5" Canvas.Top="11.25" Stretch="Fill" StrokeThickness="5" StrokeMiterLimit="2.75" Stroke="#FF000000" Fill="#FFFFFFFF"/>
             </Canvas>
        </ControlTemplate>
    </Window.Resources>

    <Grid>

        <Control Template="{StaticResource icon}"/>

    </Grid>
</Window>

希望这对您有所帮助,祝您周末愉快! :)

On 和 PS - 要调整大小,请牢记 ViewBox 否则您将需要重新设置路径以使其不被硬设置。如果是我,我会在一条路径中创建一个像这样的连接图标(如果您使用混合,select 路径和矩形并右键单击 -> 组合 -> 联合)为一条路径数据,然后将其转换为 Style 模板,并放弃 ViewBox 和其他内容。

附加信息:

您也可以像这样模板化路径,这将是真正的向量;

<StackPanel>
    <StackPanel.Resources>

        <Style TargetType="Path" x:Key="DiskIcon">
            <Setter Property="Data" Value="F1 M 88.813,81.850 L 2.000,81.850 L 2.000,2.000 L 17.070,2.000 L 17.070,35.930 L 63.417,35.930 L 63.417,2.299 L 88.813,27.379 L 88.813,81.850 Z M 55.800,2.825 L 55.800,26.341 L 39.818,26.341 L 39.818,2.825 L 55.800,2.825 Z M 63.935,0.000 L 0.000,0.000 L 0.000,83.850 L 90.813,83.850 L 90.813,26.543 L 63.935,0.000 Z"/>
            <Setter Property="Fill" Value="Black"/>
            <Setter Property="Margin" Value="10"/>
            <Setter Property="Height" Value="100"/>
            <Setter Property="Width" Value="100"/>
        </Style>

    </StackPanel.Resources>

    <Path Style="{StaticResource DiskIcon}"/>

    <Path Style="{StaticResource DiskIcon}" Fill="Red"/>

    <Path Style="{StaticResource DiskIcon}" Fill="Blue"/>

</StackPanel>

根据情况和需要,尽管我经常将其构建到 ContentControl 中以托管嵌入式 CLR ViewBox,如 "other ways" link 中所述,我在开头喜欢;

<StackPanel>
        <StackPanel.Resources>
            <Style x:Key="TheAwesomeXAMLimage" TargetType="ContentControl">
                <Setter Property="Background" Value="Black"/>
                <Setter Property="Height" Value="90"/>
                <Setter Property="Width" Value="100"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ContentControl">

                            <Viewbox Stretch="Fill">

                                <Path Fill="{TemplateBinding Background}" 
                                          Data="F1 M 88.813,81.850 L 2.000,81.850 L 2.000,2.000 L 17.070,2.000 L 17.070,35.930 L 63.417,35.930 L 63.417,2.299 L 88.813,27.379 L 88.813,81.850 Z M 55.800,2.825 L 55.800,26.341 L 39.818,26.341 L 39.818,2.825 L 55.800,2.825 Z M 63.935,0.000 L 0.000,0.000 L 0.000,83.850 L 90.813,83.850 L 90.813,26.543 L 63.935,0.000 Z"/>

                            </Viewbox>

                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </StackPanel.Resources>

        <ContentControl Style="{StaticResource TheAwesomeXAMLimage}"/>
        <ContentControl Style="{StaticResource TheAwesomeXAMLimage}"
                        Background="Red" Height="50" Width="60" Margin="10"/>

    </StackPanel>