Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Crie aplicativos da Plataforma Universal do Windows (UWP) com animações suaves, alta taxa de quadros e captura e reprodução de mídia de alto desempenho.
Tornar as animações suaves
Um aspecto fundamental dos aplicativos UWP são interações suaves. Isso inclui manipulações de toque que "grudam no dedo", transições suaves e animações, e pequenos movimentos que oferecem feedback tátil. Na estrutura XAML, há um thread chamado thread de composição dedicado à composição e animação dos elementos visuais de um aplicativo. Como o thread de composição é separado do thread de interface do usuário (o thread que executa a estrutura e o código do desenvolvedor), os aplicativos podem obter uma taxa de quadros consistente e animações suaves, independentemente de passes de layout complicados ou cálculos estendidos. Esta seção mostra como usar o thread de composição para manter sempre as animações de um aplicativo incrivelmente suaves. Para obter mais informações sobre animações, consulte a visão geral de Animações. Para saber mais sobre como aumentar a capacidade de resposta de um aplicativo ao executar cálculos intensivos, veja Manter a linha de interface do usuário responsiva.
Usar animações independentes em vez de dependentes
Animações independentes podem ser calculadas do início ao fim no momento da criação, uma vez que alterações na propriedade animada não afetam outros objetos na cena. As animações independentes podem, portanto, ser executadas no thread de composição em vez do thread da interface do usuário. Isso garante que eles permaneçam suaves porque a linha de composição é atualizada em uma cadência constante.
Todos esses tipos de animações têm a garantia de serem independentes:
Animações de objeto usando quadros-chave
Animações de duração zero
Animações para os Canvas.Left, propriedades
, e Canvas.Top, propriedades Animações para a propriedade UIElement.Opacity
Animações para propriedades do tipo Brush ao direcionar a subpropriedade SolidColorBrush.Color
Animações para as seguintes propriedades UIElement ao direcionar subpropriedades desses tipos de valor retornado:
- RenderTransform
- Transform3D
- de Projeção
- clip
As animações dependentes afetam o layout, que, portanto, não pode ser calculado sem uma entrada extra da thread da UI. Animações dependentes incluem modificações em propriedades como largura e altura. Por padrão, as animações dependentes não são executadas e exigem uma aceitação do desenvolvedor do aplicativo. Quando habilitados, eles são executados sem problemas se o thread da interface do usuário permanece desbloqueado, mas começam a gaguejar se a estrutura ou o aplicativo estiver fazendo muito outro trabalho no thread da interface do usuário.
Quase todas as animações na estrutura XAML são independentes por padrão, mas há algumas ações que você pode executar para desabilitar essa otimização. Cuidado com esses cenários particularmente:
- Definindo a propriedade EnableDependentAnimation para permitir que uma animação dependente seja executada no thread da interface do usuário. Converta essas animações em uma versão independente. Por exemplo, anime ScaleTransform.ScaleX e ScaleTransform.ScaleY em vez do Width e Height de um objeto. Não tenha medo de dimensionar objetos como imagens e texto. A estrutura aplica o dimensionamento bilinear apenas enquanto o ScaleTransform está sendo animado. A imagem/texto será rerasterizado no tamanho final para garantir que eles estejam sempre claros.
- Fazer atualizações por quadro, que são animações efetivamente dependentes. Um exemplo disso é aplicar transformações no manipulador do evento CompositonTarget.Rendering .
- Executando qualquer animação considerada independente em um elemento com a propriedade CacheMode definida como BitmapCache. Isso é considerado dependente porque o cache deve ser re-rasterizado para cada quadro.
Não anime um WebView ou MediaPlayerElement
O conteúdo da Web em um controle WebView não é renderizado diretamente pela estrutura XAML e exige trabalho extra para ser composto com o restante da cena. Esse trabalho extra se soma ao animar o controle ao redor da tela e pode potencialmente introduzir problemas de sincronização (por exemplo, o conteúdo HTML pode não se mover em sincronia com o restante do conteúdo XAML na página). Quando você precisar animar um controle WebView, troque-o por um WebViewBrush durante a animação.
Animar um MediaPlayerElement é uma ideia igualmente ruim. Além do prejuízo de desempenho, isso pode causar rasgos ou outros artefatos no conteúdo do vídeo que está sendo reproduzido.
Nota As recomendações neste artigo para MediaPlayerElement também se aplicam ao MediaElement. MediaPlayerElement só está disponível no Windows 10, versão 1607, portanto, se você estiver criando um aplicativo para uma versão anterior do Windows, precisará usar MediaElement.
Usar animações infinitas com moderação
A maioria das animações é executada por um período especificado, mas definir a propriedade Timeline.Duration como Forever permite que uma animação seja executada indefinidamente. Recomendamos minimizar o uso de animações infinitas porque elas consomem continuamente recursos de CPU e podem impedir que a CPU entre em um estado de baixa potência ou ocioso, fazendo com que ela fique sem energia mais rapidamente.
Adicionar um manipulador para CompositionTarget.Rendering é semelhante à execução de uma animação infinita. Normalmente, o thread de interface do usuário está ativo somente quando há trabalho a ser feito, mas adicionar manipulador para esse evento o força a executar todos os quadros. Remova o manipulador quando não houver trabalho a ser feito e reregistre-o quando for necessário novamente.
Usar a biblioteca de animação
O namespace Windows.UI.Xaml.Media.Animation inclui uma biblioteca de animações suaves e de alto desempenho que têm uma aparência consistente com outras animações do Windows. As classes relevantes têm "Tema" em seu nome e são descritas na visão geral Animações. Essa biblioteca dá suporte a muitos cenários comuns de animação, como animar a primeira exibição do aplicativo e criar transições de estado e conteúdo. É recomendável usar essa biblioteca de animação sempre que possível para aumentar o desempenho e a consistência da interface do usuário UWP.
Nota A biblioteca de animação não pode animar todas as propriedades possíveis. Para cenários XAML em que a biblioteca de animação não se aplica, consulte animações baseadas em storyboard.
Animar propriedades CompositeTransform3D de forma independente
Você pode animar cada propriedade de um CompositeTransform3D independentemente, portanto, aplique apenas as animações necessárias. Para obter exemplos e mais informações, consulte UIElement.Transform3D. Para obter mais informações sobre como animar transformações, consulte animações baseadas em storyboard e animações de quadro-chave e funções de suavização.
Otimizar recursos de mídia
Áudio, vídeo e imagens são formas atraentes de conteúdo que a maioria dos aplicativos usa. À medida que as taxas de captura de mídia aumentam e o conteúdo passa da definição padrão para a alta definição, a quantidade de recursos necessários para armazenar, decodificar e reproduzir esse conteúdo aumenta. A estrutura XAML se baseia nos recursos mais recentes adicionados aos mecanismos de mídia UWP para que os aplicativos obtenham esses aprimoramentos gratuitamente. Aqui, explicamos alguns truques adicionais que permitem que você obtenha o máximo de mídia em seu aplicativo UWP.
Liberar fluxos de mídia
Os arquivos de mídia são alguns dos recursos mais comuns e caros que normalmente os aplicativos usam. Como os recursos de arquivo de mídia podem aumentar consideravelmente o tamanho do volume de memória do aplicativo, você deve se lembrar de liberar o identificador para a mídia assim que o aplicativo terminar de usá-lo.
Por exemplo, se o aplicativo estiver trabalhando com um objeto RandomAccessStream ou um IInputStream, chame o método close no objeto quando seu aplicativo terminar de usá-lo, para liberar o objeto subjacente.
Exibir reprodução de vídeo em tela inteira quando possível
Em aplicativos UWP, sempre use a propriedade IsFullWindow no MediaPlayerElement para habilitar e desabilitar a renderização de janela completa. Isso garante que as otimizações de nível do sistema sejam usadas durante a reprodução de mídia.
A estrutura XAML pode otimizar a exibição de conteúdo de vídeo quando é a única coisa que está sendo renderizada, resultando em uma experiência que usa menos energia e gera taxas de quadros mais altas. Para a reprodução de mídia mais eficiente, defina o tamanho de um MediaPlayerElement para ser a largura e a altura da tela, e não exiba outros elementos XAML.
Há razões legítimas para sobrepor elementos XAML em um MediaPlayerElement que ocupa toda a largura e altura da tela, por exemplo, legendas fechadas ou controles de transporte momentâneos. Certifique-se de ocultar esses elementos (definidos Visibility="Collapsed"
) quando eles não forem necessários para colocar a reprodução de mídia de volta em seu estado mais eficiente.
Desativação do display e economia de energia
Para impedir que a exibição seja desativada quando a ação do usuário não for mais detectada, como quando um aplicativo estiver reproduzindo vídeo, você pode chamar DisplayRequest.RequestActive.
Para economizar energia e duração da bateria, você deve chamar DisplayRequest.RequestRelease para liberar a solicitação de exibição assim que ela não for mais necessária.
Aqui estão algumas situações em que você deve liberar a solicitação de exibição:
- A reprodução de vídeo é pausada, por exemplo, por ação do usuário, buffer ou ajuste devido à largura de banda limitada.
- A reprodução é interrompida. Por exemplo, o vídeo terminou ou a apresentação acabou.
- Ocorreu um erro de reprodução. Por exemplo, problemas de conectividade de rede ou um arquivo corrompido.
Colocar outros elementos no lado do vídeo inserido
Geralmente, os aplicativos oferecem uma exibição inserida em que o vídeo é reproduzido em uma página. Agora você obviamente perdeu a otimização de tela cheia porque o MediaPlayerElement não está no tamanho da página, e existem outros objetos XAML exibidos. Cuidado ao entrar involuntariamente nesse modo desenhando uma borda em torno de um MediaPlayerElement.
Não desenhe elementos XAML na parte superior do vídeo quando ele estiver no modo inserido. Se você fizer isso, a estrutura será forçada a fazer um trabalho extra para compor a cena. Colocar controles de transporte abaixo de um elemento de mídia inserida em vez de sobre o vídeo é um bom exemplo de otimização para essa situação. Nesta imagem, a barra vermelha indica um conjunto de controles de transporte (reproduzir, pausar, parar etc.).
Não coloque esses controles na parte superior da mídia que não seja tela inteira. Em vez disso, coloque os controles de transporte em algum lugar fora da área onde a mídia está sendo renderizada. Na próxima imagem, os controles são colocados abaixo da mídia.
Adiar a configuração da origem de um MediaPlayerElement
Os mecanismos de mídia são objetos caros e a estrutura XAML atrasa o carregamento de dlls e a criação de objetos grandes o máximo possível. O MediaPlayerElement é forçado a fazer esse trabalho depois que sua origem é definida por meio da propriedade Source. Definir isso quando o usuário estiver realmente pronto para reproduzir mídia atrasa a maior parte do custo associado ao MediaPlayerElement o máximo possível.
Configure a fonte do pôster no MediaPlayerElement.
Definir MediaPlayerElement.PosterSource permite que o XAML libere alguns recursos de GPU que teriam sido usados de outra forma. Essa API permite que um aplicativo use o mínimo de memória possível.
Melhorar a limpeza de mídia
Esfregar é sempre uma tarefa difícil para as plataformas de mídia se tornarem realmente responsivas. Geralmente, as pessoas fazem isso alterando o valor de uma barra deslizante. Aqui estão algumas dicas sobre como tornar isso o mais eficiente possível:
- Atualize o valor do controle deslizante com base em um temporizador que consulta a posição no MediaPlayerElement.MediaPlayer . Use uma frequência de atualização razoável para o temporizador. A propriedade Position só é atualizada a cada 250 milissegundos durante a reprodução.
- O tamanho da frequência dos passos no Controle Deslizante deve ser ajustado de acordo com o comprimento do vídeo.
- Assine os eventos
,PointerPressed ,PointerMoved eventos no controle deslizante para definir a propriedadePointerReleased PlaybackRate como 0 quando o usuário arrastar o polegar do controle deslizante. - No manipulador de eventos PointerReleased, defina manualmente a posição da mídia como o valor de posição do controle deslizante para obter o ajuste ideal do polegar durante a limpeza.
Corresponder resolução de vídeo à resolução do dispositivo
A decodificação de vídeo usa muita memória e ciclos de GPU, portanto, escolha um formato de vídeo próximo à resolução em que ele será exibido. Não vale a pena usar os recursos para decodificar o vídeo 1080 se ele for reduzido para um tamanho muito menor. Muitos aplicativos não têm o mesmo vídeo codificado em resoluções diferentes; mas, se estiver disponível, use uma codificação próxima à resolução na qual ela será exibida.
Escolher formatos recomendados
A seleção de formato de mídia pode ser um tópico sensível e geralmente é orientada por decisões de negócios. Do ponto de vista de desempenho da UWP, recomendamos o vídeo H.264 como o formato de vídeo principal e a AAC e MP3 como os formatos de áudio preferenciais. Para reprodução de arquivo local, MP4 é o contêiner de arquivo preferencial para conteúdo de vídeo. A decodificação H.264 é acelerada por meio do hardware gráfico mais recente. Além disso, embora a aceleração de hardware para decodificação VC-1 esteja amplamente disponível, para um grande conjunto de hardware gráfico no mercado, a aceleração é limitada em muitos casos a um nível de aceleração parcial (ou nível de IDCT), em vez de um descarregamento completo do hardware (ou seja, modo VLD).
Se você tiver controle total do processo de geração de conteúdo de vídeo, deverá descobrir como manter um bom equilíbrio entre a eficiência da compactação e a estrutura GOP. Um tamanho de GOP relativamente menor com imagens B pode aumentar o desempenho em modos de busca ou modos avançados.
Ao incluir efeitos de áudio curtos e de baixa latência, por exemplo, em jogos, use arquivos WAV com dados PCM descompactados para reduzir a sobrecarga de processamento que é típica para formatos de áudio compactados.
Otimizar recursos de imagem
Dimensionar imagens para o tamanho apropriado
As imagens são capturadas em resoluções muito altas, o que pode fazer com que os aplicativos usem mais CPU ao decodificar os dados da imagem e mais memória depois que eles são carregados do disco. Mas não há nenhum sentido de decodificar e salvar uma imagem de alta resolução na memória apenas para exibi-la menor do que seu tamanho nativo. Em vez disso, crie uma versão da imagem no tamanho exato em que ela será desenhada na tela usando as propriedades DecodePixelWidth e DecodePixelHeight .
Não faça isso:
<Image Source="ms-appx:///Assets/highresCar.jpg"
Width="300" Height="200"/> <!-- BAD CODE DO NOT USE.-->
Em vez disso, faça isso:
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
As unidades para DecodePixelWidth e DecodePixelHeight são por padrão pixels físicos. A propriedade DecodePixelType pode ser usada para alterar esse comportamento: definir o DecodePixelType como Logical faz com que o tamanho de decodificação contabilize automaticamente o fator de escala atual do sistema, semelhante a outros conteúdos XAML. Portanto, seria geralmente apropriado definir DecodePixelType como Lógico se, por exemplo, você deseja que DecodePixelWidth e DecodePixelHeight correspondam às propriedades de Altura e Largura do Controle de Imagem em que a imagem será exibida. Com o comportamento padrão de usar pixels físicos, você deve considerar o fator de escala atual do sistema por conta própria; e você deve escutar as notificações de alteração de escala caso o usuário altere suas preferências de exibição.
Se DecodePixelWidth/Height forem explicitamente definidos como maiores do que a imagem será exibida na tela, o aplicativo usará desnecessariamente memória extra , até 4 bytes por pixel, o que rapidamente se tornará caro para imagens grandes. A imagem também será reduzida usando o dimensionamento bilinear, o que pode fazer com que ela pareça desfocada para fatores de escala maiores.
Se DecodePixelWidth/DecodePixelHeight forem explicitamente definidos com um valor menor que o necessário para a exibição na tela, eles serão ampliados, e a imagem poderá aparecer pixelada.
Em alguns casos em que um tamanho de decodificação apropriado não pode ser determinado antecipadamente, você deve recorrer à decodificação automática no tamanho correto do XAML, que se esforçará para decodificar a imagem no tamanho apropriado se um DecodePixelWidth/DecodePixelHeight explícito não for especificado.
Você deve definir um tamanho de decodificação explícito se souber o tamanho do conteúdo da imagem antes do tempo. Você também deve, em conjunto, definir DecodePixelType para Logical se o tamanho de decodificação fornecido for relativo a outros tamanhos de elementos XAML. Por exemplo, se você definir explicitamente o tamanho do conteúdo com Image.Width e Image.Height, poderá definir DecodePixelType como DecodePixelType.Logical para usar as mesmas dimensões de pixel lógico que um controle Image e, em seguida, usar explicitamente BitmapImage.DecodePixelWidth e/ou BitmapImage.DecodePixelHeight para controlar o tamanho da imagem para obter uma economia de memória potencialmente grande.
Observe que Image.Stretch deve ser considerado ao determinar o tamanho do conteúdo decodificado.
Decodificação de tamanho adequado
Caso você não defina um tamanho de decodificado explícito, o XAML fará um melhor esforço para tentar salvar a memória decodificando uma imagem do tamanho exato em que ela aparecerá na tela de acordo com o layout inicial da página que contém. Você é aconselhado a escrever seu aplicativo de forma a usar esse recurso quando possível. Esse recurso será desabilitado se qualquer uma das condições a seguir for atendida.
- O BitmapImage é conectado à árvore XAML ao vivo depois de definir o conteúdo com SetSourceAsync ou UriSource.
- A imagem é decodificada usando decodificação síncrona, como SetSource.
- A imagem fica oculta configurando Opacidade como 0 ou Visibilidade para Recolhido no elemento de imagem do host ou pincel ou qualquer elemento pai.
- O controle de imagem ou pincel usa um Stretch de Nenhum.
- A imagem é usada como um NineGrid.
-
CacheMode="BitmapCache"
é definido no elemento de imagem ou em qualquer elemento pai. - O pincel de imagem não é retangular (como quando aplicado a uma forma ou ao texto).
A única maneira de obter economia de memória nos cenários acima é definir um tamanho de decodificação explícito.
Você sempre deve anexar um BitmapImage à árvore dinâmica antes de definir a origem. Sempre que um elemento ou pincel de imagem for especificado na marcação, esse será automaticamente o caso. Exemplos são fornecidos abaixo sob o título "Exemplos de árvore dinâmica". Você sempre deve evitar usar SetSource e, em vez disso , usar SetSourceAsync ao definir uma fonte de fluxo. E é uma boa ideia evitar ocultar o conteúdo da imagem (com opacidade zero ou com visibilidade recolhida) enquanto aguarda o evento ImageOpened ser gerado. Fazer isso é uma decisão de julgamento: você não se beneficiará de uma decodificação no tamanho certo automaticamente se isso for feito. Se o aplicativo precisar ocultar o conteúdo da imagem inicialmente, ele também deverá definir o tamanho de decodificação explicitamente, se possível.
exemplos de árvore dinâmica
Exemplo 1 (bom)— URI (Uniform Resource Identifier) especificado na marcação.
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
Exemplo 2 de marcação — URI especificado em code-behind.
<Image x:Name="myImage"/>
Exemplo 2 code-behind (bom)—conectando o BitmapImage à árvore, antes de definir seu UriSource.
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
Exemplo 2 code-behind (inválido) — definir o UriSource do BitmapImage antes de conectá-lo à árvore.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
Otimizações de cache
As otimizações de cache estão em vigor para imagens que usam UriSource para carregar conteúdo de um pacote de aplicativo ou da Web. O URI é usado para identificar exclusivamente o conteúdo subjacente e, internamente, a estrutura XAML não baixará nem decodificará o conteúdo várias vezes. Em vez disso, ele usará os recursos de hardware ou software armazenados em cache para exibir o conteúdo várias vezes.
A exceção a essa otimização será se a imagem for exibida várias vezes em resoluções diferentes (que podem ser especificadas explicitamente ou por meio da decodificação automática do tamanho direito). Cada entrada de cache também armazena a resolução da imagem e, se o XAML não conseguir encontrar uma imagem com um URI de origem que corresponda à resolução necessária, ela decodificará uma nova versão nesse tamanho. No entanto, ele não baixará os dados de imagem codificados novamente.
Como resultado, você deve adotar o uso de UriSource ao carregar imagens de um pacote de aplicativo e evitar usar um fluxo de arquivos e SetSourceAsync quando não for necessário.
Imagens em painéis virtualizados (ListView, por exemplo)
Se uma imagem for removida da árvore, porque o aplicativo a removeu explicitamente ou porque está em um painel virtualizado moderno e foi removida implicitamente quando rolada para fora da exibição, o XAML otimizará o uso da memória liberando os recursos de hardware para a imagem, pois eles não são mais necessários. A memória não é liberada imediatamente, mas sim durante a atualização de quadro que ocorre um segundo após o elemento de imagem não estar mais na árvore.
Consequentemente, você deve se esforçar para usar painéis virtualizados modernos para hospedar listas de conteúdo de imagem.
Imagens rasterizadas por software
Quando uma imagem é usada para um pincel não retangular ou para um NineGrid, a imagem usará um processo de rasterização por software, que não escalonará imagens. Além disso, ele deve armazenar uma cópia da imagem na memória de software e hardware. Por exemplo, se uma imagem for usada como um pincel para uma elipse, a imagem completa potencialmente grande será armazenada duas vezes internamente. Ao usar o NineGrid ou um pincel não retangular, o aplicativo deve dimensionar previamente suas imagens para aproximadamente o tamanho em que serão renderizadas.
Carregamento de imagens em thread de segundo plano
O XAML tem uma otimização interna que permite decodificar o conteúdo de uma imagem de forma assíncrona para uma superfície na memória de hardware sem a necessidade de uma superfície intermediária na memória de software. Isso reduz o uso de memória de pico e a latência de renderização. Esse recurso será desabilitado se qualquer uma das condições a seguir for atendida.
- A imagem é usada como um NineGrid.
-
CacheMode="BitmapCache"
é definido no elemento de imagem ou em qualquer elemento pai. - O pincel de imagem não é retangular (como quando aplicado a uma forma ou ao texto).
SoftwareBitmapSource
A classe SoftwareBitmapSource troca imagens não compactadas interoperáveis entre namespaces WinRT diferentes, como BitmapDecoder, APIs de câmera e XAML. Essa classe evita uma cópia extra que normalmente seria necessária com WriteableBitmap, ajudando assim a reduzir o pico de memória e a latência de fonte para a tela.
O
Seu aplicativo deve usar SoftwareBitmap e SoftwareBitmapSource para interoperar com outras APIs WinRT que produzem e consomem imagens. E seu aplicativo deve usar SoftwareBitmapSource ao carregar dados de imagem não compactados em vez de usar WriteableBitmap.
Utilize GetThumbnailAsync para miniaturas
Um caso de uso para dimensionar imagens é criar miniaturas. Embora você possa usar DecodePixelWidth e DecodePixelHeight para fornecer pequenas versões de imagens, a UWP fornece APIs ainda mais eficientes para recuperar miniaturas. GetThumbnailAsync fornece as miniaturas para imagens que já têm o sistema de arquivos armazenado em cache. Isso fornece um desempenho ainda melhor do que as APIs XAML porque a imagem não precisa ser aberta ou decodificada.
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
Decodificar imagens uma vez
Para impedir que as imagens sejam decodificadas mais de uma vez, atribua a propriedade Image.Source de um Uri em vez de usar fluxos de memória. A estrutura XAML pode associar o mesmo Uri em vários lugares a uma imagem decodificada, mas não pode fazer o mesmo para vários fluxos de memória que contêm os mesmos dados e cria uma imagem decodificada diferente para cada fluxo de memória.