最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

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大佬的文章没有什么太大区别,最主要的是增加了缓存机制

正文

添加所需代码

  1. 添加接口ILocalImageService
//https://github.com/dotnet/maui/issues/2907    public interface ILocalImageService    {        // 为本地路径的图片创建blob,并返回blob的url,若不是本地路径会直接返回        Task ToUrl(string path);        // 调用js,释放图片的blob        Task RevokeUrl(string path);    }
  1. 添加实现类
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");        }    }
  1. 在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);}
  1. 在MauiProgram.cs中添加以下代码
builder.Services.AddScoped();

注意事项

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

最终效果

源码

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

关键词: