知方号

知方号

MAUI Blazor 加载本地图片的解决方案

前言

为了解决MAUI Blazor无法加载本地图片,https://github.com/dotnet/maui/issues/2907,所以写了这篇文章。

有token大佬珠玉在前,https://www.cnblogs.com/hejiale010426/p/17073079.html ,以及微软文档的补充,https://learn.microsoft.com/zh-cn/aspnet/core/blazor/images?view=aspnetcore-7.0#stream-image-data,才能写出这篇文章,特此感谢。

解决的思路是判断路径是本机路径,如果是,调用js为它生成blob,将本机路径与blob的url对应上通过字典存储起来,主动释放时从字典移除。原理上与token大佬的文章没有什么太大区别,最主要的是增加了缓存机制

正文添加所需代码添加接口ILocalImageService//https://github.com/dotnet/maui/issues/2907 public interface ILocalImageService { // 为本地路径的图片创建blob,并返回blob的url,若不是本地路径会直接返回 Task ToUrl(string path); // 调用js,释放图片的blob Task RevokeUrl(string path); }添加实现类public class LocalImageService : ILocalImageService { private readonly IJSRuntime JS; private IJSObjectReference module = default!; //存储已生成的图片,将图片本机路径与图片blob的url联系起来 private static readonly ConcurrentDictionary urls = new(); //控制访问单个图片资源的线程数量,若图片blob在生成中,将等待 private static readonly ConcurrentDictionary semaphores = new(); public LocalImageService(IJSRuntime jS) { JS = jS; } //为本地路径的图片创建blob,并返回blob的url,若不是本地路径会直接返回 public async Task ToUrl(string path) { await InitModule(); if (!File.Exists(path)) { return path; } SemaphoreSlim semaphore = semaphores.GetOrAdd(path, _ => new SemaphoreSlim(1)); await semaphore.WaitAsync(); try { if (urls.TryGetValue(path, out string? url)) { return url; } else { string newUrl = await GenerateImageUrl(path); urls.TryAdd(path, newUrl); return newUrl; } } finally { semaphore.Release(); } } //调用js,生成图片的blob private async Task GenerateImageUrl(string path) { using var imageStream = File.OpenRead(path); var dotnetImageStream = new DotNetStreamReference(imageStream); var url = await module.InvokeAsync("streamToUrl", new object[1] { dotnetImageStream }); return url; } //调用js,释放图片的blob public async Task RevokeUrl(string path) { await InitModule(); if(string.IsNullOrWhiteSpace(path)) { return; } if (urls.ContainsKey(path)) { urls.TryRemove(path, out string? url); await module.InvokeVoidAsync("revokeUrl", new object[1] { url! }); } } //初始化JS模块 private async Task InitModule() { module ??= await JS!.InvokeAsync("import", "./js/getLocalImage.js"); } }在wwwroot/js中添加getLocalImage.js/*出自 https://www.cnblogs.com/hejiale010426/p/17073079.html,有修改*//** 将stream转url对象 */export async function streamToUrl(imageStream) { // 适配webview和web const arrayBuffer = await imageStream.arrayBuffer(); const blob = new Blob([arrayBuffer]); return (window.URL || window.webkitURL || window || {}).createObjectURL(blob);}/*** 释放url对象,因为createObjectURL创建的对象一直会存在可能会占用过多的内存,请注意释放*/export function revokeUrl(url) { (window.URL || window.webkitURL || window || {}).revokeObjectURL(url);}在MauiProgram.cs中添加以下代码builder.Services.AddScoped();注意事项

使用时一定要注意释放,当你不需要这个图片时主动释放它。如果它需要经常显示,那么不必释放,因为生成比较大的图片在安卓上是比较慢的。

最终效果源码

源码放在GitHub上了,https://github.com/Yu-Core/MAUIBlazorLoadLocalImage

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。