Trabalhar com imagens no ASP.NET Core Blazor

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Este artigo descreve cenários comuns para trabalhar com imagens em aplicativos Blazor.

Definir dinamicamente uma fonte de imagem

O exemplo a seguir demonstra como definir dinamicamente a origem de uma imagem com um campo C#.

Para o exemplo nesta seção:

  • Obtenha três imagens de qualquer origem ou clique com o botão direito em cada uma das imagens a seguir para salvá-las localmente. Nomeie as imagens image1.png, image2.png e image3.png.

    Ícone do computadorÍcone de smileyÍcone da Terra

  • Coloque as imagens em uma nova pasta chamada images na raiz da Web do aplicativo (wwwroot). O uso da pasta images é apenas para fins de demonstração. Você pode organizar imagens em qualquer layout de pastas que preferir, podendo até fornecer as imagens diretamente da pasta wwwroot.

No seguinte componente ShowImage1:

  • A origem da imagem (src) é definida dinamicamente como o valor de imageSource em C#.
  • O método ShowImage atualiza o campo imageSource com base em um argumento id de imagem passado para o método .
  • Os botões renderizados chamam o método ShowImage com um argumento de imagem para cada uma das três imagens disponíveis na pasta images. O nome do arquivo é composto usando o argumento passado para o método e corresponde a uma das três imagens na pasta images.

ShowImage1.razor:

@page "/show-image-1"

<PageTitle>Show Image 1</PageTitle>

<h1>Show Image Example 1</h1>

@if (imageSource is not null)
{
    <p>
        <img src="@imageSource" />
    </p>
}

@for (var i = 1; i <= 3; i++)
{
    var imageId = i;
    <button @onclick="() => ShowImage(imageId)">
        Image @imageId
    </button>
}

@code {
    private string? imageSource;

    private void ShowImage(int id)
    {
        imageSource = $"images/image{id}.png";
    }
}
@page "/show-image-1"

<h1>Dynamic Image Source Example</h1>

@if (imageSource is not null)
{
    <p>
        <img src="@imageSource" />
    </p>
}

@for (var i = 1; i <= 3; i++)
{
    var imageId = i;
    <button @onclick="() => ShowImage(imageId)">
        Image @imageId
    </button>
}

@code {
    private string? imageSource;

    private void ShowImage(int id)
    {
        imageSource = $"images/image{id}.png";
    }
}
@page "/show-image-1"

<h1>Dynamic Image Source Example</h1>

@if (imageSource is not null)
{
    <p>
        <img src="@imageSource" />
    </p>
}

@for (var i = 1; i <= 3; i++)
{
    var imageId = i;
    <button @onclick="() => ShowImage(imageId)">
        Image @imageId
    </button>
}

@code {
    private string? imageSource;

    private void ShowImage(int id)
    {
        imageSource = $"images/image{id}.png";
    }
}

O exemplo anterior usa um campo C# para armazenar os dados de origem da imagem, mas você também pode usar uma propriedade C# para armazenar os dados.

Observação

Evite usar uma variável de loop diretamente em uma expressão lambda, como i no exemplo de loop for anterior. Caso contrário, a mesma variável será usada por todas as expressões lambda, o que resulta no uso do mesmo valor em todos os lambdas. Capture o valor da variável em uma variável local. No exemplo anterior:

  • A variável de loop i é atribuída a imageId.
  • imageId é usado na expressão lambda.

Como alternativa, use um loop foreach com Enumerable.Range, que não tem o problema anterior:

@foreach (var imageId in Enumerable.Range(1,3))
{
    <button @onclick="() => ShowImage(imageId)">
        Image @imageId
    </button>
}

Para saber mais, confira Tratamento de eventos do Blazor no ASP.NET Core.

Transmitir dados de imagem

Uma imagem pode ser enviada diretamente ao cliente usando os recursos de interoperabilidade de streaming do Blazor em vez de hospedar a imagem em uma URL pública.

O exemplo nesta seção transmite dados de origem da imagem usando a interoperabilidade de JavaScript (JS). A função setImageJS a seguir aceita a tag <img>id e o fluxo de dados da imagem. A função executa as seguintes etapas:

  • Lê o fluxo fornecido em um ArrayBuffer.
  • Cria um Blob para encapsular o ArrayBuffer.
  • Cria uma URL de objeto para servir como o endereço para a imagem a ser mostrada.
  • Atualiza o elemento <img> com o imageElementId especificado com a URL do objeto que acabou de ser criada.
  • Para evitar vazamentos de memória, a função chama revokeObjectURL para descartar a URL do objeto quando o componente terminar de trabalhar com uma imagem.
<script>
  window.setImage = async (imageElementId, imageStream) => {
    const arrayBuffer = await imageStream.arrayBuffer();
    const blob = new Blob([arrayBuffer]);
    const url = URL.createObjectURL(blob);
    const image = document.getElementById(imageElementId);
    image.onload = () => {
      URL.revokeObjectURL(url);
    }
    image.src = url;
  }
</script>

Observação

Para obter diretrizes gerais sobre a localização do JS e nossas recomendações para aplicativos de produção, confira Localização do JavaScript em aplicativos ASP.NET Core Blazor.

O seguinte componente ShowImage2:

  • Injeta serviços para um System.Net.Http.HttpClient e Microsoft.JSInterop.IJSRuntime.
  • Inclui uma tag <img> para exibir uma imagem.
  • Tem um método GetImageStreamAsync em C# para recuperar um Stream de uma imagem. Um aplicativo de produção pode gerar dinamicamente uma imagem com base no usuário específico ou recuperar uma imagem do armazenamento. O exemplo a seguir recupera o avatar do .NET para o repositório dotnet do GitHub.
  • Tem um método SetImageAsync que é disparado na seleção do botão pelo usuário. SetImageAsync executa as seguintes ações:
    • Recupera o Stream de GetImageStreamAsync.
    • Encapsula o Stream em um DotNetStreamReference, que permite transmitir os dados da imagem para o cliente.
    • Invoca a função JavaScript setImage, que aceita os dados no cliente.

Observação

Os aplicativos do lado do servidor usam um serviço HttpClient dedicado para fazer solicitações, portanto, nenhuma ação é necessária pelo desenvolvedor de um aplicativo Blazor do lado do servidor para registrar um serviço HttpClient. Os aplicativos do lado do cliente têm um registro de serviço HttpClient padrão quando o aplicativo é criado a partir de um modelo de projeto Blazor. Se um registro de serviço HttpClient não estiver presente no arquivo Program de um aplicativo do lado do cliente, forneça um regustri adicionando builder.Services.AddHttpClient();. Para saber mais, confira Fazer solicitações HTTP usando IHttpClientFactory no ASP.NET Core.

ShowImage2.razor:

@page "/show-image-2"
@inject HttpClient Http
@inject IJSRuntime JS

<PageTitle>Show Image 2</PageTitle>

<h1>Show Image Example 2</h1>

<p>
    <img id="image" />
</p>

<button @onclick="SetImageAsync">
    Set Image
</button>

@code {
    private async Task<Stream> GetImageStreamAsync()
    {
        return await Http.GetStreamAsync(
            "https://avatars.githubusercontent.com/u/9141961");
    }

    private async Task SetImageAsync()
    {
        var imageStream = await GetImageStreamAsync();
        var dotnetImageStream = new DotNetStreamReference(imageStream);
        await JS.InvokeVoidAsync("setImage", "image", dotnetImageStream);
    }
}
@page "/show-image-2"
@inject HttpClient Http
@inject IJSRuntime JS

<h1>Stream Image Data Example</h1>

<p>
    <img id="image" />
</p>

<button @onclick="SetImageAsync">
    Set Image
</button>

@code {
    private async Task<Stream> GetImageStreamAsync()
    {
        return await Http.GetStreamAsync(
            "https://avatars.githubusercontent.com/u/9141961");
    }

    private async Task SetImageAsync()
    {
        var imageStream = await GetImageStreamAsync();
        var dotnetImageStream = new DotNetStreamReference(imageStream);
        await JS.InvokeVoidAsync("setImage", "image", dotnetImageStream);
    }
}
@page "/show-image-2"
@inject HttpClient Http
@inject IJSRuntime JS

<h1>Stream Image Data Example</h1>

<p>
    <img id="image" />
</p>

<button @onclick="SetImageAsync">
    Set Image
</button>

@code {
    private async Task<Stream> GetImageStreamAsync()
    {
        return await Http.GetStreamAsync(
            "https://avatars.githubusercontent.com/u/9141961");
    }

    private async Task SetImageAsync()
    {
        var imageStream = await GetImageStreamAsync();
        var dotnetImageStream = new DotNetStreamReference(imageStream);
        await JS.InvokeVoidAsync("setImage", "image", dotnetImageStream);
    }
}

Recursos adicionais