在 ASP.NET Core Blazor 中处理图像

注意

此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

对于当前版本,请参阅此文的 .NET 8 版本

本文介绍在 Blazor 应用中处理图像的常见情况。

动态设置图像源

下面的示例演示如何使用 C# 字段动态设置图像的源。

对于本部分中的示例:

  • 从任何源获取三个图像,或右键单击以下每个图像以在本地保存它们。 对 image1.pngimage2.pngimage3.png 命名。

    计算机图标笑脸图标地球图标

  • 将图像放置在应用的 Web 根目录 (wwwroot) 中名为 images 的新文件夹中。 images 文件夹的使用仅用于演示目的。 可以在喜欢的任何文件夹布局中组织图像,包括直接从 wwwroot 文件夹中提供图像。

在下面的 ShowImage1 组件中:

  • 图像中的源 (src) 动态设置为 C# 中的值 imageSource
  • ShowImage 方法基于传递到方法的图像 id 参数更新 imageSource 字段。
  • 呈现的按钮使用 images 文件夹中每个可用图像(共三个)的图像参数调用 ShowImage 方法。 文件名使用传递给该方法的参数组成,并匹配 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";
    }
}

前面的示例使用 C# 字段来保存图像的源数据,但也可使用 C# 属性来保存数据。

注意

避免直接在 Lambda 表达式中使用循环变量,如前面的 for 循环示例中的 i。 否则,所有 Lambda 表达式将使用相同的变量,这将导致在所有 Lambda 中使用相同的值。 在局部变量中捕获该变量的值。 在上面的示例中:

  • 将循环变量 i 分配到 imageId
  • imageId 用于 lambda 表达式。

或者,将 foreach 循环与 Enumerable.Range 结合使用,这样就能避开上述问题:

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

有关详细信息,请参阅 ASP.NET Core Blazor 事件处理

流式传输图像数据

可以使用 Blazor 的流式处理互操作功能将图像直接发送到客户端,而不是在公共 URL 托管图像。

本部分中的示例使用 JavaScript (JS) 互操作流式传输图像源数据。 以下 setImageJS 函数接受图像的 <img> 标记 id 和数据流。 该函数执行以下步骤:

  • 将提供的流读入 ArrayBuffer
  • 创建 Blob 以包装 ArrayBuffer
  • 创建一个对象 URL,用作要显示的图像的地址。
  • 通过刚创建的对象 URL 使用指定的 imageElementId 更新 <img> 元素。
  • 若要防止内存泄漏,该函数要在组件处理完图像时调用 revokeObjectURL 以释放对象 URL。
<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>

注意

有关生产应用的 JS 位置和建议的一般指南,请参阅 “ASP.NET CoreBlazor 应用中的 JavaScript 位置”。

以下 ShowImage2 组件:

  • System.Net.Http.HttpClientMicrosoft.JSInterop.IJSRuntime 注入服务。
  • 包含用于显示图像的标记 <img>
  • 拥有用于检索图像的 StreamGetImageStreamAsync C# 方法。 生产应用可以基于特定用户动态生成图像,或者从存储中检索图像。 以下示例检索 dotnet GitHub 存储库的 .NET 头像。
  • 拥有在用户选择按钮时触发的 SetImageAsync 方法。 SetImageAsync 执行下列步骤:
    • GetImageStreamAsync 检索 Stream
    • Stream 包装在 DotNetStreamReference 中,这允许将图像数据流式传输到客户端。
    • 调用 setImage JavaScript 函数,该函数接受客户端上的数据。

注意

服务器端应用使用专用的 HttpClient 服务发出请求,因此服务器端 Blazor 应用的开发人员无需执行任何操作即可注册 HttpClient 服务。 根据 Blazor 项目模板创建应用时,客户端应用提供默认的 HttpClient 服务注册。 如果客户端应用的 Program 文件中不存在 HttpClient 服务注册,请通过添加 builder.Services.AddHttpClient(); 来提供。 有关详细信息,请参阅在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求

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);
    }
}

其他资源