Compartir a través de


Optimización de animaciones, medios e imágenes

Crea aplicaciones para la Plataforma universal de Windows (UWP) con animaciones suaves, alta velocidad de fotogramas y captura y reproducción multimedia de alto rendimiento.

Hacer que las animaciones sean suaves

Un aspecto clave de las aplicaciones para UWP es una interacción fluida. Esto incluye interacciones táctiles que "se pegan al dedo", transiciones suaves y animaciones, y pequeños movimientos que proporcionan retroalimentación táctil. En el marco XAML hay un subproceso denominado subproceso de composición dedicado a la composición y animación de los elementos visuales de una aplicación. Dado que el subproceso de composición es independiente del subproceso de la interfaz de usuario (el subproceso que ejecuta el marco y el código de desarrollador), las aplicaciones pueden lograr una velocidad de fotogramas coherente y animaciones suaves independientemente de los pasos de diseño complicados o cálculos extendidos. En esta sección se muestra cómo usar el subproceso de composición para mantener suaves las animaciones de una aplicación. Para obtener más información sobre las animaciones, consulta Información general sobre animaciones. Para obtener información sobre cómo aumentar la capacidad de respuesta de una aplicación al realizar cálculos intensivos, consulte Mantener la capacidad de respuesta del subproceso de interfaz de usuario.

Usar animaciones independientes en lugar de animaciones dependientes

Las animaciones independientes se pueden calcular de principio a fin en el momento de la creación porque los cambios en la propiedad que se anima no afectan al resto de una escena. Por lo tanto, las animaciones independientes se pueden ejecutar en el subproceso de composición en lugar del subproceso de interfaz de usuario. Esto garantiza que se mantengan fluidos porque el subproceso de composición se actualiza a un ritmo constante.

Se garantiza que todos estos tipos de animaciones son independientes:

Las animaciones dependientes afectan al diseño, por lo que no se puede calcular sin una entrada adicional del subproceso de la interfaz de usuario. Las animaciones dependientes incluyen modificaciones en propiedades como Width y Height. De forma predeterminada, las animaciones dependientes no se ejecutan y requieren la participación del desarrollador de la aplicación. Cuando se habilita, se ejecutan sin problemas si el subproceso de la interfaz de usuario permanece desbloqueado, pero comienzan a entrecortarse si el framework o la aplicación están realizando muchas otras tareas en el subproceso de la interfaz de usuario.

Casi todas las animaciones del marco XAML son independientes de forma predeterminada, pero hay algunas acciones que puedes realizar para deshabilitar esta optimización. Tenga cuidado con estos escenarios particularmente:

  • Establecer la propiedad EnableDependentAnimation para permitir que una animación dependiente se ejecute en el subproceso de la interfaz de usuario. Convierta estas animaciones en una versión independiente. Por ejemplo, anima ScaleTransform.ScaleX y ScaleTransform.ScaleY en lugar del Ancho y Altura de un objeto. No tenga miedo de escalar objetos como imágenes y texto. El marco aplica el escalado bilineal solo mientras el ScaleTransform se está animando. La imagen o el texto se volverán a rasterizar en el tamaño final para garantizar que siempre sea nítida.
  • Realizar actualizaciones por fotograma, que son animaciones dependientes de forma eficaz. Un ejemplo de esto es aplicar transformaciones en el controlador del evento CompositonTarget.Rendering.
  • Ejecutar cualquier animación que se considere independiente en un elemento con la propiedad CacheMode configurada en BitmapCache. Esto se considera dependiente porque la memoria caché debe volver a rasterizarse para cada fotograma.

No animas un WebView ni MediaPlayerElement

El marco XAML no renderiza directamente el contenido web dentro de un control WebView y requiere trabajo adicional para integrarlo con el resto de la escena. Este trabajo adicional se agrega al animar el control alrededor de la pantalla y puede introducir problemas de sincronización (por ejemplo, es posible que el contenido HTML no se sincronice con el resto del contenido XAML de la página). Cuando necesite animar un control WebView, cámbielo con un WebViewBrush durante la animación.

Animar un MediaPlayerElement es una idea igualmente mala. Más allá del rendimiento en perjuicio del rendimiento, puede provocar el desgarro u otros artefactos en el contenido de vídeo que se está reproduciendo.

Nota Las recomendaciones de este artículo para MediaPlayerElement también se aplican a MediaElement. MediaPlayerElement solo está disponible en Windows 10, versión 1607, por lo que si estás creando una aplicación para una versión anterior de Windows, debes usar MediaElement.

Usar animaciones infinitas con moderación

La mayoría de las animaciones se ejecutan durante una cantidad de tiempo especificada, pero establecer la propiedad Timeline.Duration en Forever permite que una animación se ejecute indefinidamente. Se recomienda minimizar el uso de animaciones infinitas porque consumen continuamente recursos de CPU y pueden evitar que la CPU entre en un estado de bajo consumo o inactividad, lo que hace que se agote más rápidamente.

Agregar un controlador para CompositionTarget.Rendering es similar a ejecutar una animación infinita. Normalmente, el subproceso de la interfaz de usuario solo está activo cuando hay trabajo que hacer, pero agregar un controlador para este evento hace que se ejecute en cada fotograma. Quite el controlador cuando no haya ningún trabajo que realizar y vuelva a registrarlo cuando sea necesario de nuevo.

Uso de la biblioteca de animaciones

El espacio de nombres Windows.UI.Xaml.Media.Animation incluye una biblioteca de animaciones de alto rendimiento y suaves que tienen un aspecto y se sienten coherentes con otras animaciones de Windows. Las clases pertinentes tienen "Theme" en su nombre y se describen en información general de animaciones de . Esta biblioteca admite muchos escenarios de animación comunes, como animar la primera vista de la aplicación y crear transiciones de estado y contenido. Te recomendamos usar esta biblioteca de animaciones siempre que sea posible para aumentar el rendimiento y la coherencia de la interfaz de usuario de UWP.

Nota La biblioteca de animaciones no puede animar todas las propiedades posibles. Para escenarios XAML en los que no se aplica la biblioteca de animaciones, consulta animaciones con guion gráfico.

Animar las propiedades CompositeTransform3D de forma independiente

Puedes animar cada propiedad de un CompositeTransform3D de forma independiente, por lo que aplica solo las animaciones que necesites. Para obtener ejemplos y más información, consulta UIElement.Transform3D. Para obtener más información sobre la animación de transformaciones, consulta animaciones con storyboard y animaciones de fotograma clave y funciones de suavizado.

Optimización de recursos multimedia

Audio, vídeo e imágenes son formas atractivas de contenido que la mayoría de las aplicaciones usan. A medida que aumentan las velocidades de captura multimedia y el contenido se mueve de la definición estándar a la alta definición, aumenta la cantidad de recursos necesarios para almacenar, descodificar y reproducir este contenido. El marco XAML se basa en las características más recientes agregadas a los motores multimedia de UWP para que las aplicaciones obtengan estas mejoras de forma gratuita. Aquí explicamos algunos trucos adicionales que te permiten sacar el máximo partido a los medios de tu aplicación para UWP.

Liberar secuencias multimedia

Los archivos multimedia son algunas de las aplicaciones de recursos más comunes y costosas que suelen usar. Dado que los recursos de archivos multimedia pueden aumentar considerablemente el tamaño de la huella de memoria de la aplicación, debes recordar liberar el identificador de los recursos multimedia tan pronto como la aplicación haya terminado de usarlos.

Por ejemplo, si la aplicación trabaja con un RandomAccessStream o un objeto IInputStream, asegúrese de llamar al método close en el objeto cuando la aplicación haya terminado de usarla, para liberar el objeto subyacente.

Mostrar la reproducción de vídeo de pantalla completa siempre que sea posible

En las aplicaciones para UWP, usa siempre la propiedad IsFullWindow en la MediaPlayerElement de para habilitar y deshabilitar la representación de ventana completa. Esto garantiza que las optimizaciones de nivel del sistema se usen durante la reproducción multimedia.

El marco XAML puede optimizar la visualización del contenido de vídeo cuando es lo único que se representa, lo que da lugar a una experiencia que usa menos potencia y produce mayores velocidades de fotogramas. Para la reproducción multimedia más eficaz, establezca el tamaño de un MediaPlayerElement para que sea el ancho y alto de la pantalla y no muestre otros elementos XAML.

Hay razones legítimas para superponer elementos XAML en un MediaPlayerElement que ocupa todo el ancho y alto de la pantalla, por ejemplo, subtítulos o controles de transporte momentáneos. Asegúrese de ocultar estos elementos (establecer Visibility="Collapsed") cuando no sean necesarios para volver a poner la reproducción multimedia en su estado más eficaz.

Desactivación de la pantalla y ahorro de energía

Para evitar que la pantalla se desactive cuando la acción del usuario ya no se detecte, como cuando una aplicación está reproduciendo vídeo, puede llamar a DisplayRequest.RequestActive.

Para ahorrar energía y duración de la batería, debe llamar a DisplayRequest.RequestRelease para liberar la solicitud de visualización tan pronto como ya no sea necesario.

Estas son algunas situaciones en las que debería liberar la solicitud de visualización:

  • La reproducción de vídeo se pausa, por ejemplo, mediante la acción del usuario, el almacenamiento en búfer o el ajuste debido a un ancho de banda limitado.
  • La reproducción se detiene. Por ejemplo, el vídeo ha terminado de reproducirse o la presentación ha terminado.
  • Se ha producido un error de reproducción. Por ejemplo, problemas de conectividad de red o un archivo dañado.

Colocar otros elementos en el lado del vídeo incrustado

A menudo, las aplicaciones ofrecen una vista insertada en la que se reproduce vídeo dentro de una página. Ahora obviamente perdiste la optimización para pantalla completa porque el MediaPlayerElement no ocupa el tamaño de la página y hay otros objetos XAML renderizados. Tenga cuidado de entrar involuntariamente en este modo dibujando un borde alrededor de un MediaPlayerElement.

No dibuje elementos XAML encima del vídeo cuando esté en modo incrustado. Si lo haces, el framework se ve obligado a realizar un poco de trabajo adicional para componer la escena. Colocar controles de transporte por debajo de un elemento multimedia incrustado en lugar de en la parte superior del vídeo es un buen ejemplo de optimización para esta situación. En esta imagen, la barra roja indica un conjunto de controles de transporte (reproducir, pausar, detener, etc.).

MediaPlayerElement con elementos de superposición

No coloque estos controles encima de los medios que no estén en pantalla completa. En su lugar, coloque los controles de transporte en algún lugar fuera del área donde se renderiza el medio. En la siguiente imagen, los controles se colocan debajo del contenido multimedia.

MediaPlayerElement con elementos adyacentes

Retrasar la configuración del origen de un objeto MediaPlayerElement

Los motores multimedia son objetos costosos y el marco XAML retrasa la carga de dlls y la creación de objetos grandes siempre y cuando sea posible. El MediaPlayerElement se ve obligado a realizar este trabajo después de establecer su origen mediante la propiedad Source. Establecer esto cuando el usuario está listo para reproducir medios retrasa la mayor parte del costo asociado con el MediaPlayerElement siempre que sea posible.

Configurar MediaPlayerElement.PosterSource

Establecer MediaPlayerElement.PosterSource permite que XAML libere algunos recursos de GPU que, de lo contrario, se habrían utilizado. Esta API permite que una aplicación use la menor cantidad de memoria posible.

Mejora del limpieza de medios

La limpieza siempre es una tarea difícil para que las plataformas multimedia respondan realmente. Generalmente, las personas logran esto cambiando el valor de un control deslizante. Estos son un par de consejos sobre cómo hacer esto lo más eficiente posible:

  • Actualice el valor de Slider basado en un temporizador que consulta la Posición en el MediaPlayerElement.MediaPlayer. Asegúrese de usar una frecuencia de actualización razonable para el temporizador. La propiedad Position solo se actualiza cada 250 milisegundos durante la reproducción.
  • El tamaño del intervalo de pasos en el control deslizante debe ajustarse según la longitud del vídeo.
  • Suscríbase a los eventos PointerPressed, PointerMoved, PointerReleased en el control deslizante para establecer la propiedad PlaybackRate en 0 cuando el usuario arrastra el pulgar del control deslizante.
  • En el controlador de eventos PointerReleased, establezca manualmente la posición del medio en el valor de posición del control deslizante para lograr un ajuste de pulgar óptimo mientras se limpia.

Ajustar la resolución del vídeo a la resolución del dispositivo

El vídeo de descodificación toma mucha memoria y ciclos de GPU, por lo que elige un formato de vídeo cerca de la resolución en la que se mostrará. No tiene sentido utilizar los recursos para descodificar el vídeo 1080 si se va a escalar a un tamaño mucho más pequeño. Muchas aplicaciones no tienen el mismo vídeo codificado en diferentes resoluciones; pero si está disponible, use una codificación que esté cerca de la resolución en la que se mostrará.

La selección de formato multimedia puede ser un tema confidencial y a menudo se basa en decisiones empresariales. Desde una perspectiva de rendimiento de UWP, se recomienda vídeo H.264 como formato de vídeo principal y AAC y MP3 como formatos de audio preferidos. Para la reproducción de archivos local, MP4 es el contenedor de archivos preferido para el contenido de vídeo. La descodificación H.264 se acelera a través del hardware gráfico más reciente. Además, aunque la aceleración de hardware para la descodificación VC-1 está disponible ampliamente, para un gran conjunto de tarjetas gráficas disponibles en el mercado, la aceleración se limita en muchos casos a un nivel de aceleración parcial (o nivel IDCT), en lugar de una descarga total de hardware (es decir, modo VLD).

Si tiene control total del proceso de generación de contenido de vídeo, debe averiguar cómo mantener un buen equilibrio entre la eficiencia de compresión y la estructura GOP. El tamaño de GOP relativamente pequeño que incluye imágenes B puede aumentar el rendimiento en los modos de búsqueda o trucos.

Cuando se incluyen efectos de audio cortos y de baja latencia, por ejemplo en juegos, usa archivos WAV con datos PCM sin comprimir para reducir la sobrecarga de procesamiento que es habitual para los formatos de audio comprimidos.

Optimización de recursos de imagen

Escala las imágenes al tamaño adecuado

Las imágenes se capturan en resoluciones muy altas, lo que puede provocar que las aplicaciones usen más CPU al descodificar los datos de imagen y más memoria después de cargarse desde el disco. Pero no hay sentido descodificar y guardar una imagen de alta resolución en la memoria solo para mostrarla más pequeña que su tamaño nativo. En su lugar, cree una versión de la imagen con el tamaño exacto que se dibujará en pantalla mediante las propiedades de DecodePixelWidth y DecodePixelHeight.

No hagas esto:

<Image Source="ms-appx:///Assets/highresCar.jpg"
       Width="300" Height="200"/>    <!-- BAD CODE DO NOT USE.-->

En su lugar, haga lo siguiente:

<Image>
    <Image.Source>
    <BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
                 DecodePixelWidth="300" DecodePixelHeight="200"/>
    </Image.Source>
</Image>

Las unidades de DecodePixelWidth y DecodePixelHeight son de forma predeterminada píxeles físicos. La propiedad DecodePixelType puede usarse para cambiar este comportamiento: establecer DecodePixelType en Logical da como resultado que el tamaño de descodificación tenga en cuenta automáticamente el factor de escala actual del sistema, similar a otros contenidos XAML. Por lo tanto, sería generalmente apropiado establecer DecodePixelType en Lógico si, por ejemplo, desea que DecodePixelWidth y DecodePixelHeight coincidan con las propiedades Height y Width del control Image en el que se mostrará la imagen. Con el comportamiento predeterminado de usar píxeles físicos, debe tener en cuenta el factor de escala actual del sistema usted mismo; y debe escuchar las notificaciones de cambio de escala en caso de que el usuario cambie sus preferencias de visualización.

Si DecodePixelWidth/Height se establecen explícitamente a un tamaño mayor que el que la imagen se mostrará en pantalla, la aplicación usará innecesariamente memoria adicional (hasta 4 bytes por píxel), lo cual se torna rápidamente costoso para imágenes grandes. La imagen también se reducirá mediante el escalado bilineal, lo que podría hacer que parezca borrosa con factores de escala grandes.

Si DecodePixelWidth/DecodePixelHeight se establece explícitamente con un tamaño menor al que la imagen se mostrará en pantalla, se escalará y podría aparecer pixelada.

En algunos casos en los que no se puede determinar un tamaño de descodificación adecuado con antelación, debes aplazar la descodificación automática de tamaño correcto de XAML, lo que hará un mejor esfuerzo para descodificar la imagen en el tamaño adecuado si no se especifica un DecodePixelWidth/DecodePixelHeight explícito.

Debe establecer un tamaño de descodificación explícito si conoce el tamaño del contenido de la imagen con antelación. También debes en conjunto establecer DecodePixelType en Lógico si el tamaño de descodificación proporcionado es relativo a otros tamaños de elemento XAML. Por ejemplo, si establece explícitamente el tamaño de contenido con Image.Width e Image.Height, podría establecer DecodePixelType en DecodePixelType.Logical para usar las mismas dimensiones de píxeles lógicas que un control Image y, a continuación, usar explícitamente BitmapImage.DecodePixelWidth o BitmapImage.DecodePixelHeight para controlar el tamaño de la imagen para lograr ahorros de memoria potencialmente grandes.

Tenga en cuenta que Image.Stretch debe tenerse en cuenta al determinar el tamaño del contenido descodificado.

Descodificación de tamaño adecuado

En caso de que no establezcas un tamaño de descodificación explícito, XAML hará un mejor esfuerzo para guardar la memoria descodificando una imagen con el tamaño exacto que aparecerá en pantalla según el diseño inicial de la página contenedora. Se recomienda escribir la aplicación de forma que use esta característica siempre que sea posible. Esta característica se deshabilitará si se cumple alguna de las condiciones siguientes.

  • El BitmapImage queda conectado al árbol XAML activo mediante la configuración del contenido con SetSourceAsync o UriSource.
  • La imagen se descodifica mediante descodificación sincrónica, como SetSource.
  • La imagen se oculta estableciendo Opacidad en 0 o Visibilidad en Oculto en el elemento de imagen anfitrión, pincel o cualquier elemento primario.
  • El control o pincel de imagen usa un estiramiento de None.
  • La imagen se usa como NineGrid.
  • CacheMode="BitmapCache" se establece en el elemento imagen o en cualquier elemento padre.
  • El pincel de imagen no es rectangular (por ejemplo, cuando se aplica a una forma o al texto).

En los escenarios anteriores, establecer un tamaño de descodificación explícito es la única manera de lograr ahorros de memoria.

Siempre debe adjuntar una imagen bitmap al árbol en vivo antes de establecer el origen. Cada vez que se especifique un elemento de imagen o pincel en el marcado, esto ocurrirá automáticamente. A continuación se proporcionan ejemplos bajo el encabezado "Ejemplos de árbol activo". Siempre debe evitar usar SetSource y, en su lugar, usar SetSourceAsync al establecer un origen de flujo. Y es una buena idea evitar ocultar el contenido de la imagen (ya sea con opacidad cero o con visibilidad contraída) mientras se espera a que se genere el evento ImageOpened. Esto es una cuestión de criterio: no te beneficiarás de la descodificación de tamaño adecuado si se hace. Si la aplicación debe ocultar el contenido de la imagen inicialmente, también debe establecer explícitamente el tamaño de descodificación si es posible.

Ejemplos de árboles vivos

Ejemplo 1 (correcto): identificador uniforme de recursos (URI) especificado en el marcado.

<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>

Ejemplo 2 de marcado: URI especificado en código subyacente.

<Image x:Name="myImage"/>

Ejemplo 2 de buen código subyacente: vincular BitmapImage al árbol antes de establecer su UriSource.

var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);

Ejemplo 2 de código subyacente (incorrecto): establezca el UriSource de BitmapImage antes de conectarlo al árbol.

var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;

Optimizaciones de almacenamiento en caché

Las optimizaciones de almacenamiento en caché están en vigor para las imágenes que usan UriSource para cargar contenido desde un paquete de aplicación o desde la web. El URI se usa para identificar de forma única el contenido subyacente y, internamente, el marco XAML no descargará ni descodificará el contenido varias veces. En su lugar, usará los recursos de hardware o software almacenados en caché para mostrar el contenido varias veces.

La excepción a esta optimización es si la imagen se muestra varias veces en resoluciones diferentes (que se pueden especificar explícitamente o mediante la descodificación automática de tamaño correcto). Cada entrada de caché también almacena la resolución de la imagen y, si XAML no encuentra una imagen con un URI de origen que coincida con la resolución necesaria, descodificará una nueva versión con ese tamaño. Sin embargo, no volverá a descargar los datos de imagen codificados.

Por lo tanto, debería adoptar el uso de UriSource al cargar imágenes desde un paquete de aplicación y evitar el uso de un flujo de archivos y SetSourceAsync cuando no sea necesario.

Imágenes en paneles virtualizados (ListView, por ejemplo)

Si se quita una imagen del árbol (porque la aplicación la quitó explícitamente o porque está en un panel virtualizado moderno y se quitó implícitamente cuando se desplaza fuera de la vista), XAML optimizará el uso de memoria liberando los recursos de hardware de la imagen, ya que ya no son necesarios. La memoria no se libera inmediatamente, sino que se libera durante la actualización de fotogramas que se produce un segundo después de que el elemento de imagen ya no esté en el árbol.

Por lo tanto, debe esforzarse por usar paneles virtualizados modernos para hospedar listas de contenido de imagen.

Imágenes rasterizadas por software

Cuando se utiliza una imagen para un pincel no rectangular o para un NineGrid, la imagen seguirá una ruta de rasterización de software, lo cual no permitirá escalar las imágenes en ningún caso. Además, debe almacenar una copia de la imagen en la memoria de software y hardware. Por ejemplo, si una imagen se usa como pincel para una elipse, la imagen completa potencialmente grande se almacenará dos veces internamente. Al usar NineGrid o un pincel no rectangular, la aplicación debe escalar previamente sus imágenes a aproximadamente el tamaño en el que se representarán.

Carga de imágenes en segundo plano

XAML tiene una optimización interna que le permite descodificar el contenido de una imagen de forma asincrónica en una superficie en memoria de hardware sin necesidad de una superficie intermedia en la memoria de software. Esto reduce el uso máximo de memoria y la latencia de representación. Esta característica se deshabilitará si se cumple alguna de las condiciones siguientes.

  • La imagen se usa como NineGrid.
  • CacheMode="BitmapCache" se establece en el elemento imagen o en cualquier elemento padre.
  • El pincel de imagen no es rectangular (por ejemplo, cuando se aplica a una forma o al texto).

SoftwareBitmapSource

La clase SoftwareBitmapSource intercambia imágenes interoperables sin comprimir entre diferentes espacios de nombres WinRT, como BitmapDecoder, camera APIs y XAML. Esta clase obvia una copia adicional que normalmente sería necesaria con WriteableBitmap, y que ayuda a reducir la latencia máxima de memoria y de origen a pantalla.

El softwareBitmap de que proporciona información de origen también se puede configurar para usar un IWICBitmap personalizado para proporcionar un almacén de respaldo recargable que permita a la aplicación volver a asignar memoria a medida que se vea adecuada. Se trata de un caso de uso avanzado de C++.

La aplicación debe usar softwareBitmap y softwareBitmapSource para interoperar con otras API de WinRT que producen y consumen imágenes. Y la aplicación debe usar SoftwareBitmapSource al cargar los datos de imagen sin comprimir en lugar de usar WriteableBitmap.

Uso de GetThumbnailAsync para miniaturas

Un caso de uso para escalar imágenes es crear miniaturas. Aunque puedes usar DecodePixelWidth y DecodePixelHeight para proporcionar pequeñas versiones de imágenes, UWP proporciona API aún más eficaces para recuperar miniaturas. GetThumbnailAsync proporciona las miniaturas para imágenes que ya tienen el sistema de archivos almacenado en caché. Esto proporciona un rendimiento aún mejor que las API XAML porque no es necesario abrir ni descodificar la imagen.

FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".bmp");
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;

StorageFile file = await picker.PickSingleFileAsync();

StorageItemThumbnail fileThumbnail = await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64);

BitmapImage bmp = new BitmapImage();
bmp.SetSource(fileThumbnail);

Image img = new Image();
img.Source = bmp;
Dim picker As New FileOpenPicker()
picker.FileTypeFilter.Add(".bmp")
picker.FileTypeFilter.Add(".jpg")
picker.FileTypeFilter.Add(".jpeg")
picker.FileTypeFilter.Add(".png")
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary

Dim file As StorageFile = Await picker.PickSingleFileAsync()

Dim fileThumbnail As StorageItemThumbnail = Await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64)

Dim bmp As New BitmapImage()
bmp.SetSource(fileThumbnail)

Dim img As New Image()
img.Source = bmp

Descodificar imágenes una vez

Para evitar que las imágenes se descodifiquen más de una vez, asigne la propiedad Image.Source de un URI en lugar de usar secuencias de memoria. El marco XAML puede asociar el mismo URI en varios lugares con una imagen descodificada, pero no puede hacer lo mismo para varias secuencias de memoria que contienen los mismos datos y crea una imagen descodificada diferente para cada secuencia de memoria.