前言

为了解决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<string> 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<string, string> urls = new();
//控制访问单个图片资源的线程数量,若图片blob在生成中,将等待
private static readonly ConcurrentDictionary<string, SemaphoreSlim> semaphores = new(); public LocalImageService(IJSRuntime jS)
{
JS = jS;
} //为本地路径的图片创建blob,并返回blob的url,若不是本地路径会直接返回
public async Task<string> 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<string> GenerateImageUrl(string path)
{
using var imageStream = File.OpenRead(path);
var dotnetImageStream = new DotNetStreamReference(imageStream);
var url = await module.InvokeAsync<string>("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<IJSObjectReference>("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<ILocalImageService, LocalImageService>();

注意事项

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

最终效果


源码

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

MAUI Blazor 加载本地图片的解决方案的更多相关文章

  1. android ImageLoader加载本地图片的工具类

    import android.widget.ImageView; import com.nostra13.universalimageloader.core.ImageLoader; /** * 异步 ...

  2. UIWebView如何加载本地图片

    UIWebView如何加载本地图片 UIWebView加载本地图片是有实用价值的.比方说,有时候我们需要本地加载静态页来显示相关帮助信息,而这些帮助信息当中含有很多很多的富文本,用代码实现难度较大,这 ...

  3. angular 图片加载失败 情况处理? 如何在ionic中加载本地图片 ?

    1.angular 图片加载失败 情况处理 在directive中定义组件,在ng-src错误时,调用err-src app.directive('errSrc',function(){ return ...

  4. Flutter学习笔记(19)--加载本地图片

    如需转载,请注明出处:Flutter学习笔记(19)--加载本地图片 上一篇博客正好用到了本地的图片,记录一下用法: 首先新建一个文件夹,这个文件夹要跟目录下 然后在pubspec.yaml里面声明出 ...

  5. !!!myeclipse 上加载本地图片问题,无法加载问题

    出现无法加载本地图片的问题, 原因就是把图片放到了本地项目中的image了,但是myeclipse上没有刷新 这样以后 本地的图片比在线的要快 低级错误,诶!

  6. 用UIWebView加载本地图片和gif图

    加载gif图: NSData *gif = [NSData dataWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@" ...

  7. vue如何动态加载本地图片

    大家好,我是前端队长Daotin,想要获取更多前端精彩内容,关注我(全网同名),解锁前端成长新姿势. 以下正文: 今天遇到一个在vue文件中引入本地图片的问题,于是有了这篇文章. 通常,我们的一个im ...

  8. UIImage加载本地图片的两种方式

    UIImage加载图片方式一般有两种: (1)imagedNamed初始化:默认加载图片成功后会内存中缓存图片,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象.如果缓存中没有找到相应的图片 ...

  9. Unity加载本地图片的2种方式

    1. 使用 WWW 加载,详细查看 unity3d 官方文档. 2. 使用 System.IO 加载,lua 代码如下: local File = luanet.import_type("S ...

  10. fresco加载本地图片、gif资源

    首先 来看看fresco 是个神马东西 https://github.com/facebook/fresco 这个是fresco的一个官方gifhub 官网为http://frescolib.org/ ...

随机推荐

  1. Java:Should I use a `HashSet` or a `TreeSet` for a very large dataset?

    这是StackOverflow上一个有意思的提问,记录一下. 原地址在这 翻译: 对于大型数据集,应该使用"哈希集"还是"树集"? (因为HashTable有着 ...

  2. 第三方接口调用httpUtils

    1.GET 请求 public static JSONObject getHttpGetResp(String url, String authorization, String title) { H ...

  3. Linux 根据名称自动kill掉当前相关进程

    ps aux | grep app | grep -v "grep" | awk '{print $2}' | xargs -r kill

  4. 2020-12-13:用最少数量的线程,每个线程执行for的空循环,把cpu打满了。如果在for的空循环里添加打印输出函数,会把cpu打满吗?为什么?

    福哥答案2020-12-13:不会.输出会进行io操作,相对于CPU的速度,这是一个非常缓慢的过程,所以CPU会有机会空闲下来.***[评论](https://user.qzone.qq.com/31 ...

  5. AcWing 1209. 带分数

    题目描述: 分析: 题意就是说给定一个整数N,求给定a,b,c,求a+b/c==N且a,b,c恰好包括0-9的答案的个数,需要注意的是,b/c可能得到的是小数,所以要尽量避免除法,将等式转换为乘法格式 ...

  6. drf——5个视图扩展类、9个视图子类、视图集、drf之路由

    5个视图扩展类 # 写5个类(不叫视图类 视图拓展类 需要配合GenericAPIView一起用) 每个类有一个方法 以后想写哪个接口 就继承哪个类即可 from rest_framework.res ...

  7. kafka集群是如何选择leader,你知道吗?

    前言 kafka集群是由多个broker节点组成,这里面包含了许多的知识点,以下的这些问题你都知道吗? 你知道topic的分区leader是怎么选举的吗? 你知道zookeeper中存储了kafka的 ...

  8. 文心一言 VS 讯飞星火 VS chatgpt (28)-- 算法导论5.1 3题

    三.假设你希望以1/2的概率输出0与 1.你可以自由使用一个输出0或1的过程 BIASED-RANDOM.它以某概率 p 输出1,概率 1-p 输出0,其中 0<p<1 ,但是 p 的值未 ...

  9. Kubernetes(k8s)定时任务:CronJob

    目录 一.系统环境 二.前言 三.Kubernetes CronJob简介 四.kubernetes CronJob和Linux crontab对比 五.CronJob表达式语法 六.创建CronJo ...

  10. R 语言中常见的 10 个错误,看到第 7 个会不会感觉很神奇?

    翻译:BioIT 爱好者(部分内容有调整)原文:The top 10 R errors, the 7th one will surprise you 就像你学习走路时遇到了一些问题,你在学习 R 的过 ...