Alignement des pixels dans les applications WPF

Mise à jour : novembre 2007

Le système graphique WPF utilise des unités indépendantes du périphérique pour garantir l'indépendance vis-à-vis du périphérique et de la résolution. Chaque pixel indépendant du périphérique s'ajuste automatiquement au paramètre points par pouce (ppp) du système. Cela fournit aux applications WPF la mise à l'échelle appropriée pour différents paramètres ppp et rend l'application capable de prendre automatiquement en compte le paramètre ppp.

Cependant, cette indépendance ppp peut générer un rendu irrégulier des bords en raison de l'anticrénelage. Ces artefacts, apparaissant généralement avec des bords flous ou semi-transparents, peuvent se produire lorsque l'emplacement d'un bord tombe au milieu d'un pixel de périphérique au lieu d'être entre des pixels de périphériques. Pour résoudre ce problème, WPF permet d'aligner les bords d'un objet d'une arborescence visuelle aux pixels de périphériques, ou de les fixer, grâce à l'alignement de pixels, éliminant ainsi les bords semi-transparents produits par l'anticrénelage.

L'alignement de pixels est un moyen de supprimer ces artefacts visuels en appliquant de petits offsets à la géométrie visuelle pour aligner la géométrie aux pixels de périphériques.

Cette rubrique comprend les sections suivantes.

  • Alignement de pixels pour un rendu anticrénelage
  • Indications
  • Images bitmap
  • Rubriques connexes

Alignement de pixels pour un rendu anticrénelage

Lignes nettes

Sans l'alignement de pixels, les lignes avec un rendu anticrénelage peuvent apparaître semi-transparentes si le bord ne tombe pas entre des pixels de périphériques. L'illustration suivante montre le résultat d'une ligne avec anticrénelage et largeur à pixel unique qui tombe au milieu d'un pixel de périphérique (image de gauche) et une ligne qui tombe entre des pixels de périphériques (image de droite).

Rendu de ligne avec anticrénelage.

Ligne avec anticrénelage comparée avec une ligne d'un pixel.

Avec l'alignement de pixels, les lignes avec anticrénelage sont alignées aux pixels de périphériques, ou deviennent fixes, et elles apparaissent de façon très nettes et les bords ne sont pas semi-transparents. L'exemple suivant montre l'influence de la propriété SnapsToDevicePixels sur une ligne à pixel unique. Si vous redimensionnez lentement la fenêtre, vous voyez les artefacts visuels sur une ligne non alignée (à gauche) et la taille fixe de la ligne alignée (à droite) lorsque leur position change.

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

SnapsToDevicePixels affecte uniquement les éléments qui s'exécutent par l'intermédiaire de la passe de disposition. Vous pouvez fournir des indications sur un Drawing à l'aide de la propriété GuidelineSet de l'objet DrawingGroup. Pour définir manuellement les indications d'un Visual, créez de nouvelles indications en utilisant les propriétés VisualYSnappingGuidelines et VisualXSnappingGuidelines.

L'alignement de pixels rend plus nettes uniquement les lignes horizontale et verticale et n'affecte pas les lignes diagonales.

Objets adjacents

L'anticrénelage peut également provoquer des artefacts visuels lorsque les bords entre des objets sont contigus et que le bord adjacent n'est pas exactement aligné entre une ligne ou une colonne de pixels de périphériques. Il peut arriver que l'anticrénelage atténue le bord avec la couleur d'arrière-plan sous-jacente, ce qui produit un effet « d'infiltration », c'est-à-dire que le bord entre chaque objet apparaît avec une couleur transparente. L'illustration suivante montre cet effet.

Objets contigus avec effet « d'infiltration ».

Fusion de l'arrière-plan entre objets attenants

Lorsque l'alignement de pixels est activé, les bords contigus sont alignés sur les pixels de périphériques afin de supprimer l'effet « d'infiltration ». L'exemple suivant montre l'effet de la propriété SnapsToDevicePixels sur les objets contigus. Si vous redimensionnez lentement la fenêtre, vous voyez le problème « d'infiltration » sur les rectangles non alignés (à gauche) alors que les rectangles alignés (à droite) restent groupés sans aucune irrégularité visuelle.

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

Notez que les rectangles alignés ne définissent pas explicitement une valeur pour la propriété SnapsToDevicePixels. La propriété doit simplement avoir la valeur true sur la racine afin d'activer le comportement pour tous les éléments enfants.

Texte

Windows Presentation Foundation (WPF) génère toujours du texte avec anticrénelage et si le texte est statique, il sera aligné sur les pixels. Cela permet au texte avec anticrénelage d'avoir une apparence plus nette puisque les glyphes sont placés directement sur la grille de pixels, garantissant ainsi une plus grande clarté du texte. Toutefois, lorsque Windows Presentation Foundation (WPF) détecte un mouvement semblable à une animation, tel qu'un défilement, une mise à l'échelle ou une translation animée, l'alignement de pixels est désactivé tant que le mouvement n'est pas terminé. Dès que l'animation ou le défilement est terminé, l'alignement de pixels est peu à peu réactivé.

Indications

Fondamentalement, l'alignement de pixels est contrôlé par des indications. Elles facilitent en effet l'ajustement des géométries sur une grille de pixels de périphériques. Dans la plupart des cas, l'alignement de pixels basé sur la propriété SnapsToDevicePixels fournira le résultat voulu. Cependant, cette propriété n'est pas toujours disponible surtout lorsque vous utilisez des objets Drawing ou lorsque vous utilisez directement DrawingContext, donc des indications doivent être définies pour obtenir la même netteté qu'avec l'alignement de pixels.

Pour définir des indications concernant les objets Drawing et DrawingContext, la classe GuidelineSet est utilisée. Cette classe vous permet de créer des indications horizontales et verticales qui peuvent être appliquées à un DrawingGroup ou faire l'objet d'un push dans un DrawingContext pour les commandes de dessin suivantes. Le dessin respecte les indications pour déterminer les lignes qui doivent être alignées sur un pixel de périphérique. Pour un exemple détaillé de l'utilisation de GuidelineSet, consultez Comment : appliquer un GuidelineSet à un dessin.

Les indications peuvent également être définies au niveau Visual en modifiant les collections d'indications horizontales et verticales. Celles-ci sont accessibles via les propriétés VisualYSnappingGuidelines et VisualXSnappingGuidelines.

Images bitmap

En raison de la nature indépendante de ppp dans WPF, l'interface utilisateur basée sur les bitmaps peut avoir des résultats de présentation non souhaitables. Les scènes avec anticrénelage peuvent rendre une image floue à cause des problèmes d'alignement de pixels fractionnaires. Cela est particulièrement vrai pour les images qui contiennent des modifications à haute fréquence, par exemple des lignes à pixel unique avec des éléments contrastés adjacents (tels que des lignes alternativement blanches et noires). L'illustration suivante montre les différences de qualité entre une image alignée (à gauche) et un offset d'image sans alignement sur les pixels de périphériques (à droite).

Alignement d'image sur les pixels de périphériques.

Image floue en raison de l'absence d'alignement des pixels du périphérique.

Un scénario courant pour les images dans interface utilisateur consiste à centrer une image représentant une icône dans un autre objet. Comme les icônes sont généralement de petites images avec des modifications à haute fréquence, il sera peut-être nécessaire d'ajuster la disposition de l'application afin de supprimer les artefacts visuels produits par l'anticrénelage.

Pour centrer correctement une image, le conteneur doit avoir une largeur et une hauteur paires si la largeur et la hauteur de pixels de l'image sont paires. Si l'image a une largeur et une hauteur de pixels impaires, l'élément conteneur doit également avoir une largeur et une hauteur impaires.

L'exemple suivant crée deux objets Border qui contiennent un Image. La bordure supérieure a une largeur et une hauteur paires pour correspondre à celles de l'image. La bordure inférieure a une largeur et une hauteur impaires.

L'image suivante montre le résultat de l'exemple et l'influence de la taille du conteneur sur l'image.

Images centrées dans les bordures.

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

Malheureusement, il ne suffit pas d'ajuster la taille de l'objet conteneur pour garantir l'alignement de pixels. Toute la disposition d'une application peut avoir une influence sur l'alignement de l'image. L'affichage points par pouce (ppp) affecte également l'alignement de l'image. Dans l'exemple ci-dessus, l'alignement de l'image sera obtenu uniquement si l'affichage a la valeur 96 points par pouce (ppp). Avec un autre réglage, la disposition devra être ajustée pour tenir compte des paramètres de l'affichage. Si possible, les images à haute fréquence doivent être évitées dans les applications Windows Presentation Foundation (WPF).

Voir aussi

Concepts

Système de disposition

Référence

Image

VisualXSnappingGuidelines

VisualYSnappingGuidelines