Ajuste de píxeles en aplicaciones de WPF

Actualización: noviembre 2007

El sistema de gráficos de WPF utiliza unidades independientes del dispositivo para que sean independientes de la resolución y del dispositivo. Cada píxel independiente del dispositivo ajusta su escala automáticamente al valor de puntos por pulgada (dpi) del sistema. Esto proporciona a las aplicaciones de WPF un ajuste de escala correcto para las distintas configuraciones de dpi y hace que la aplicación detecte este valor de dpi automáticamente.

Sin embargo, esta independencia de dpi puede crear representaciones de bordes irregulares debido al suavizado (anti-aliasing). Estas anomalías de la imagen, que suelen aparecer como bordes borrosos o semitransparentes, pueden producirse cuando un borde se encuentra en medio de un píxel de dispositivo en vez de situarse entre píxeles de dispositivo. Para solucionar este problema, WPF proporciona una manera de ajustar (o fijar) los bordes de los objetos en un árbol visual a los píxeles de dispositivo a través del ajuste de píxeles, lo que elimina los bordes semitransparentes generados por el suavizado (anti-aliasing).

El ajuste de píxeles es un medio para suprimir estas anomalías visuales aplicando pequeños desplazamientos a la geometría del objeto visual a fin de alinearla con los píxeles del dispositivo.

Este tema contiene las secciones siguientes.

  • Ajuste de píxeles para representación con suavizado (anti-aliasing)
  • Líneas de guía
  • Imágenes de mapa de bits
  • Temas relacionados

Ajuste de píxeles para representación con suavizado (anti-aliasing)

Líneas nítidas

Sin el ajuste de píxeles, las líneas representadas con suavizado (anti-aliasing) pueden parecer semitransparentes si el borde no se encuentra entre los píxeles del dispositivo. En la ilustración siguiente se muestra el resultado de representar con suavizado una línea con un grosor de un solo píxel cuando se encuentra en medio de un píxel del dispositivo (izquierda) y cuando se encuentra entre píxeles del dispositivo (derecha).

Representación de línea con suavizado.

Línea alisada comparada con línea de un solo pixel.

Con el ajuste de píxeles, las líneas suavizadas se ajusta, o fijan, a los píxeles del dispositivo y parecen nítidas, con lo que se elimina la representación de líneas semitransparentes. En el ejemplo siguiente se muestra el efecto de la propiedad SnapsToDevicePixels en una línea con un grosor de un solo píxel. Al cambiar lentamente el tamaño de la ventana, se muestran las anomalías que aparecen en una línea no ajustada (izquierda) y el tamaño fijo de la línea que sí se ha ajustado (derecho) a medida que cambia su posición.

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

Nota

SnapsToDevicePixels únicamente afecta a los elementos que se encuentran en el recorrido de la pasada de diseño. Pueden establecerse líneas de guía en un objeto Drawing mediante la propiedad GuidelineSet del objeto DrawingGroup. Para establecer manualmente las líneas de guía de un objeto Visual, cree nuevas líneas de guía mediante las propiedades VisualYSnappingGuidelines y VisualXSnappingGuidelines.

El ajuste de píxeles únicamente afecta a la nitidez de las líneas horizontales y verticales, no afecta a las líneas diagonales.

Objetos adyacentes

El suavizado (anti-aliasing) también puede producir anomalías visuales cuando los bordes entre los objetos son colindantes y el borde adyacente no queda alineado exactamente entre una fila o una columna de píxeles del dispositivo. La escena con suavizado puede suavizar el borde utilizando el color de fondo subyacente, lo que genera un efecto de permeabilidad en que el borde entre los objetos parece de color transparente. En la ilustración siguiente se muestra este efecto de permeabilidad.

Objetos colindantes con efecto de permeabilidad.

Fondo que penetra entre objetos contiguos.

Con el ajuste de píxeles habilitado, los bordes colindantes se ajustan a los píxeles del dispositivo para quitar el efecto de permeabilidad. En el ejemplo siguiente se muestra el efecto de la propiedad SnapsToDevicePixels en objetos colindantes. Al cambiar lentamente el tamaño de la ventana, se presenta el problema de permeabilidad en los rectángulos sin ajustar (izquierda), mientras que en los rectángulos ajustados (derecha) permanecen unidos sin irregularidades visuales.

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

Observe que en los rectángulos ajustados no se estable explícitamente un valor para la propiedad SnapsToDevicePixels. Únicamente se necesita establecer la propiedad en true en la raíz para habilitar el comportamiento en todos los elementos secundarios.

Texto

Windows Presentation Foundation (WPF) siempre genera el texto con suavizado (anti-aliasing) y, si es estático, se le aplica ajuste de píxeles. Esto ayuda a dar un aspecto más nítido al texto con suavizado, al situar los glifos directamente en la cuadrícula de píxeles, lo que proporciona un texto más claro. Sin embargo, cuando Windows Presentation Foundation (WPF) detecta cualquier movimiento similar a una animación, como un desplazamiento, un ajuste de escala o una conversión animada, el ajuste de píxeles se desactiva hasta que se completa el movimiento. Cuando la animación o el movimiento de desplazamiento termina, se vuelve a animar lentamente el ajuste de píxeles.

Líneas de guía

Básicamente, el ajuste de píxeles se controla mediante líneas de guía. Las líneas de guía ayudan a ajustar las geometrías a una cuadrícula de píxeles del dispositivo. En la mayoría de los casos, el ajuste de píxeles mediante la propiedad SnapsToDevicePixels da lugar al resultado deseado. Sin embargo, esta propiedad no siempre está disponible, sobre todo cuando se utilizan objetos Drawing o se trata directamente con un DrawingContext; en estos casos es preciso establecer líneas de guía para lograr la nitidez deseada que el ajuste de píxeles proporciona.

Para establecer las líneas de guía en los objetos Drawing y DrawingContext, se utiliza la clase GuidelineSet. Esta clase permite crear líneas de guía horizontales y verticales que se pueden aplicar a DrawingGroup o se puedan insertar en DrawingContext para los comandos de dibujo subsiguientes. Las líneas de guía indican al dibujo qué líneas se deben ajustar a un píxel del dispositivo. Para obtener un ejemplo detallado del uso de GuidelineSet, consulte Cómo: Aplicar un objeto GuidelineSet a un dibujo.

Las líneas de guía también se pueden establecer en el nivel de los objetos Visual cambiando las colecciones de líneas de guía horizontales y verticales. Se tiene acceso a ellas a través de las propiedades VisualYSnappingGuidelines y VisualXSnappingGuidelines.

Imágenes de mapa de bits

Debido al carácter independiente de dpi de WPF, las interfaz de usuario basadas en mapas de bits pueden dar lugar a resultados de presentación no deseados. Las escenas con suavizado (anti-aliasing) pueden emborronar una imagen a causa de los problemas de alineación de los píxeles fraccionarios. Esto se cumple en particular para las imágenes que contienen cambios de alta frecuencia, tales como las líneas de un solo píxel con elementos adyacentes en contraste (como líneas negras y blancas alternas). En la ilustración siguiente se muestran las diferencias de calidad de imagen de una imagen alineada (izquierda) y una imagen desplazada de modo que no esté alineada con los píxeles del dispositivo (derecho).

Alineación de la imagen con los píxeles del dispositivo.

Imagen difuminada por alineación incorrecta de píxeles de dispositivo.

Un escenario común para las imágenes de una interfaz de usuario es centrar una imagen que representa un icono dentro de otro objeto. Dado que los iconos suelen ser imágenes pequeñas con cambios de alta frecuencia, puede ser preciso ajustar el diseño de la aplicación para evitar las anomalías visuales generadas por el suavizado (anti-aliasing).

Para centrar correctamente una imagen, el contenedor debe tener un ancho y un alto pares si el ancho y el alto en píxeles de la imagen son pares. Si el ancho y el alto de la imagen son impares, el ancho y el alto del elemento contenedor también deberán ser impares.

En el ejemplo siguiente se crean dos objetos Border que contienen una Image. El borde superior tiene un ancho y un alto pares, para coincidir con los de la imagen. El borde inferior tiene un ancho y un alto impares.

En la ilustración siguiente se muestra el resultado del ejemplo y el efecto que tiene el tamaño del contenedor en la imagen.

Imágenes centradas dentro de los bordes.

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

Por desgracia, la alineación con los píxeles del dispositivo no se garantiza con sólo ajustar el tamaño del objeto contenedor. El diseño de la aplicación en su conjunto puede afectar a la alineación de la imagen. El valor de puntos por pulgada (dpi) de pantalla también afecta a la alineación de las imágenes. En el ejemplo anterior, la alineación de la imagen funcionará únicamente si la pantalla está establecida en 96 puntos por pulgada (dpi). Con cualquier otra configuración, deberá ajustarse el diseño a fin de alojar la configuración de pantalla. Siempre que sea posible, deben evitarse las imágenes de alta frecuencia en las aplicaciones de Windows Presentation Foundation (WPF).

Vea también

Conceptos

Sistema de diseño

Referencia

Image

VisualXSnappingGuidelines

VisualYSnappingGuidelines