WPF 應用程式的像素快照

更新:2007 年 11 月

WPF 圖形系統使用與裝置無關的單位以獲得解析度和裝置的獨立性。每個與裝置無關的像素都會隨系統的 Dots Per Inch (DPI) 設定自動縮放。這可以讓 WPF 應用程式在不同的 DPI 設定下適當縮放,使應用程式自動成為 DPI 感知。

不過,這個不受 DPI 影響的特性可能由於消除鋸齒而建立不規則的邊緣。這些疊影多為模糊或半透明邊緣,當邊緣的位置落在裝置像素中 (而非裝置像素之間的交界) 時出現。為解決這個問題,WPF 可以透過像素格線編排的方式,將視覺化樹狀結構中的物件邊緣對齊至 (或固定至) 裝置像素,以去除消除鋸齒功能產生的半透明邊緣。

像素格線編排是一種消除這些視覺疊影的方法,其原理是對視覺物件的幾何套用少量的位移 (Offset),以使幾何對齊至裝置像素。

這個主題包含下列章節。

  • 用於消除鋸齒功能的像素格線編排
  • 方針
  • 點陣圖影像
  • 相關主題

用於消除鋸齒功能的像素格線編排

銳利線條

如果未使用像素格線編排,而且邊緣未落在裝置像素之間,則消除鋸齒的線條可能是半透明的。下圖顯示單一像素寬度的線條落在裝置像素的中央 (左側) 和落在裝置像素之間 (右側) 時,在消除鋸齒的輸出。

消除鋸齒的線條。

消除鋸齒線條與單一像素線條比較。

使用像素格線編排時,消除鋸齒的線條會對齊至 (或固定至) 裝置像素並且呈現為銳利線條,而不是半透明線條。下列範例示範 SnapsToDevicePixels 屬性對單一像素線條的影響。緩慢調整視窗大小時會發現,隨著位置的變更,未對齊的線條 (左側) 上會有視覺疊影,而對齊的線條 (右側) 仍保持固定大小。

<Page x:Class="PixelSnapping.Lines"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Lines" Name="linesPage"
    >
  <StackPanel Width="150"  Margin="7" Orientation="Horizontal">
    <!-- Single pixel line with pixel snapping turned OFF.-->
    <Rectangle SnapsToDevicePixels="False"
       Width="45.5" Margin="10" Height="1" Fill="Red"/>
    <!-- Single pixel line with pixel snapping turned ON.-->
    <Rectangle SnapsToDevicePixels="True"
      Width="45.5" Margin="10" Height="1" Fill="Red"/>
  </StackPanel>
  <!-- Background Grid -->
  <Page.Background>
    <DrawingBrush  Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
      <DrawingBrush.Drawing>
        <DrawingGroup>
          <GeometryDrawing Brush="White">
            <GeometryDrawing.Geometry>
              <RectangleGeometry Rect="0,0,1,1" />
            </GeometryDrawing.Geometry>
          </GeometryDrawing>
          <GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z " Brush="#CCCCFF" />
          <GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="#CCCCFF" />
        </DrawingGroup>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Page.Background>
</Page>
注意事項:

SnapsToDevicePixels 只會影響透過配置階段執行的項目。您可以使用 DrawingGroup 物件的 GuidelineSet 屬性在 Drawing 上設定方針。若要手動設定 Visual 的方針,請使用 VisualYSnappingGuidelinesVisualXSnappingGuidelines 屬性建立新方針。

像素格線編排只會將水平和垂直的線條銳利化,不會影響斜線。

相鄰物件

在物件的邊緣相接,而且相接邊緣未準確對齊裝置像素之列或欄間的交界時,消除鋸齒也會造成視覺疊影。消除鋸齒的場景可能會使用基礎背景色彩柔化邊緣,而產生錯位效果 (即每個物件之間的邊緣呈現透明色彩)。下圖示範這個錯位效果。

具有錯位效果的相接物件。

相鄰物件之間露出背景。

啟用像素格線編排時,相接邊緣會對齊至裝置像素以消除錯位效果。下列範例示範 SnapsToDevicePixels 屬性對相接物件的影響。緩慢調整視窗大小時會發現,未對齊的矩形 (左側) 有錯位問題,而對齊的矩形 (右側) 仍很清楚,沒有視覺上的變化。

<Page x:Class="PixelSnapping.Seeping"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Seeping"
    >
  <StackPanel Orientation="Horizontal" Height="100">
    <Border  
      SnapsToDevicePixels="False"
      Margin="10" BorderThickness="1" BorderBrush="Black" Height="80" Background="White">
      <StackPanel Height="100.0">
        <Rectangle Width="20" Height="20" Fill="Red"/>
        <Rectangle Width="20" Height="20" Fill="Red"/>
        <Rectangle Width="20" Height="20" Fill="Red"/>
        <Rectangle Width="20" Height="20" Fill="Red"/>
      </StackPanel>
    </Border>
    <Border
      SnapsToDevicePixels="True"
        Margin="10" BorderThickness="1" BorderBrush="Black" Height="80" Background="White">
      <StackPanel Height="100.0">
        <Rectangle Width="20" Height="20" Fill="Red"/>
        <Rectangle Width="20" Height="20" Fill="Red"/>
        <Rectangle Width="20" Height="20" Fill="Red"/>
        <Rectangle Width="20" Height="20" Fill="Red"/>
      </StackPanel>
    </Border>
  </StackPanel>
  <!-- Background Grid -->
  <Page.Background>
    <DrawingBrush  Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
      <DrawingBrush.Drawing>
        <DrawingGroup>
          <GeometryDrawing Brush="White">
            <GeometryDrawing.Geometry>
              <RectangleGeometry Rect="0,0,1,1" />
            </GeometryDrawing.Geometry>
          </GeometryDrawing>
          <GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z " Brush="#CCCCFF" />
          <GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="#CCCCFF" />
        </DrawingGroup>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Page.Background>
</Page>

請注意,對齊的矩形中並沒有明確設定 SnapsToDevicePixels 屬性的值。只需要將根項目的這個屬性設為 true,就可以在所有子項目上啟用這個行為。

文字

Windows Presentation Foundation (WPF) 一律會產生消除鋸齒的文字,如果文字是靜態的,就會進行像素對齊。這有助於讓消除鋸齒的文字看起來更清晰,其原理是將圖像 (Glyph) 直接置於像素格線上,因而提供更清楚的文字。不過,當 Windows Presentation Foundation (WPF) 偵測到任何類似動畫的移動時,例如捲動、縮放或平移動畫,就會關閉像素格線編排,直到移動完成為止。等到動畫或捲動等移動完成後,像素格線編排就會慢慢以動畫方式復原。

方針

像素格線編排的核心作業是由方針控制。方針會協助將幾何調整成對齊裝置像素格線。大多數的情況下,使用 SnapsToDevicePixels 屬性進行像素格線編排可以達到想要的結果。不過,這個屬性不是永遠都可以使用,特別是在使用 Drawing 物件或直接處理 DrawingContext 時,因此您必須設定方針以達到想要讓像素格線編排提供的清晰度。

若要在 DrawingDrawingContext 物件上設定方針,您會使用 GuidelineSet 類別。這個類別讓您可以建立水平和垂直的方針,供套用至 DrawingGroup 或推入至 DrawingContext 以用於後續的繪圖命令。方針會指示繪圖哪條線應該對齊至裝置像素。如需 GuidelineSet 的詳細用法範例,請參閱 HOW TO:對圖形套用 GuidelineSet

方針也可以在 Visual 層級上設定,方法是變更水平和垂直方針集合。這些都是可以透過 VisualYSnappingGuidelinesVisualXSnappingGuidelines 屬性存取的。

點陣圖影像

因為 WPF 具有與 DPI 無關的本質,點陣圖架構的 UI 的效果可能會不佳。在消除鋸齒的場景中,影像可能因為未對齊至完整像素的問題而變得模糊。對於具有高度變化的影像更是如此,這些變化包括單一像素的線條旁有對比項目 (例如黑線和白線交替)。下圖示範對齊影像 (左側) 和未與裝置像素對齊之影像 (右側) 的影像品質差異。

裝置像素的影像對齊。

因為裝置像素非對齊而模糊的影像。

UI 中影像的常見案例是將代表圖示的影像在其他物件內置中。因為圖示通常是具有高度變化的小型影像,所以可能需要調整應用程式的配置,以避免消除鋸齒功能產生的視覺疊影。

為正確地將影像置中,如果影像的像素寬度、長度為偶數,容器 (Container) 的寬度、長度也應該為偶數。如果影像的像素寬度、長度為奇數,容器項目的寬度、長度也應該為奇數。

下列範例會建立兩個內含 ImageBorder 物件。上框線的寬度和長度為偶數,以符合影像的寬度和長度。下框線的寬度和長度則為奇數。

下圖顯示這個範例的輸出,以及容器大小對影像的影響。

在框線內部置中對齊的影像。

<Page x:Class="PixelSnapping.Images"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Images"
    >
  <StackPanel>
    <!-- Image has a pixel dimension of 144x96. -->
    <!-- Because the image has a even width and height, 
         an even border width and height allows the image to proper center. 
    -->
    <Border HorizontalAlignment="Left" VerticalAlignment="Top" Width="200" Height="100">
      <Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="sharpness.png" Stretch="None"/>
    </Border>
    <!-- Image has a pixel dimension of 144x96. -->
    <!-- Because the image has a even width and height, 
         an odd border width and height causes the image to soften. 
    -->
    <Border HorizontalAlignment="Left" VerticalAlignment="Top" Width="201" Height="101">
      <Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="sharpness.png" Stretch="None"/>
    </Border>
  </StackPanel>
  <!-- Grid Background -->
  <Page.Background>
    <DrawingBrush  Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
      <DrawingBrush.Drawing>
        <DrawingGroup>
          <GeometryDrawing Brush="White">
            <GeometryDrawing.Geometry>
              <RectangleGeometry Rect="0,0,1,1" />
            </GeometryDrawing.Geometry>
          </GeometryDrawing>
          <GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z " Brush="#CCCCFF" />
          <GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="#CCCCFF" />
        </DrawingGroup>
      </DrawingBrush.Drawing>
    </DrawingBrush>
  </Page.Background>
</Page>

可惜的是,只調整容器物件的大小並不保證能與裝置像素對齊。應用程式的整個配置會影響影像的對齊。顯示器的 Dots Per Inch (DPI) 也會影響影像對齊。在上述範例中,影像對齊只會在顯示器設為 96 Dots Per Inch (DPI) 時有作用。如果是其他設定值,就需要調整配置以符合顯示器設定。Windows Presentation Foundation (WPF) 應用程式中應盡可能避免高度變化的影像。

請參閱

概念

配置系統

參考

Image

VisualXSnappingGuidelines

VisualYSnappingGuidelines