XAML矢量图形模糊

4
为了使我的WPF应用程序支持高DPI,我选择使用嵌入式XAML矢量图形创建所有内部图形和图标。然而,我不明白为什么我的XAML矢量图形在渲染时会变得模糊。以下是一个示例:我使用XAML路径和矩形元素绘制了一个简单的软盘图标。下面的图像是在我的显示器的本机分辨率2048x1152下以不同大小和不同的“SnapsToDevicePixels”和“UseLayoutRounding”值呈现的相同图标。

Overall view

考虑到该图标主要由水平和垂直线条组成,它看起来有些模糊。以下是较大图标的600%缩放视图:

enter image description here

还有小图标:

enter image description here

两种尺寸下边缘都不够清晰。使用不同的SnapsToDevicePixels值,有些边缘是清晰的,但其他边缘仍然不够清晰。

如何正确绘制这样的图标,使其不会模糊呢?

以下是此窗口的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进行调整大小,但图片仍然模糊。从左到右,这是未调整大小的(画布尺寸为100x100),调整大小为50和调整大小为24:

enter image description here

还有600%的缩放视图:

enter image description here

这里是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>

我们曾经做过类似的事情,但在我们的情况下,我的一个同事使用SVG制作了图形,然后将其转换为XAML矢量图形。我不知道他是如何做到的,他是我们团队的UI专家。我只是提出这个建议,你也许可以尝试做同样的事情。 - Rod
@Rod 他很可能在Illustrator中制作了它们,并使用Mike Swanson的非常方便的AI to XAML插件,或者我认为Inkscape也可以导出到Path XAML。 - Chris W.
@ChrisW。目前我正在使用Expression Design 4进行绘图,并使用“复制到XAML”功能。将来我想用SVG绘制它们,然后从那里转换为XAML。 - tdenniston
1个回答

3
您遇到的问题是使用了VisualBrush,在绘制区域时会丢失实际矢量状态。根据您的实际需求和计划,有许多其他方法可以实现此目的,但仅根据我所看到的情况,对于您特定的实例,我建议改用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>

希望这能帮到你,祝周末愉快! :)
另外,关于调整大小,记得要考虑ViewBox,否则你需要重新设置路径而不是硬编码。如果是我,我会将连接的图标制作成一个路径(如果你使用Blend,则选择“路径”和“矩形”,右键单击->合并->联合),生成一个样式模板,省略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,就像我在开头添加的“其他方式”链接中提到的一样;

<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>

@proc-self-maps 实际上,对不起,我忽略了一些步骤,以防你想将其变成一个单一路径,并将其转换为快速样式模板。如果你愿意尝试这种方法,请告诉我,我很快就会在这里提供更详细的信息。 - Chris W.
嗯,我刚试了一下,通过将<Control>元素包装在Viewbox中进行调整大小,但渲染出的图像仍然模糊。我已经用新的截图编辑了我的问题。 - tdenniston
@proc-self-maps 不完全是这样。我曾经也这么认为,直到我被一些更有经验的人打败,比如在这个答案中。不过我们会看看能做出什么来。我只是遇到了一个忙碌的星期一,但我没有忘记这件事,尽快回来。 - Chris W.
感谢所有的建议! - tdenniston
我在使用ViewBox来托管PathIcon(UWP),将Stretch设置为Fill就解决了我的问题。不再有模糊! - user1618054
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接