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<string> 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<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");
}
}
- 在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<ILocalImageService, LocalImageService>();
注意事项
使用时一定要注意释放,当你不需要这个图片时主动释放它。如果它需要经常显示,那么不必释放,因为生成比较大的图片在安卓上是比较慢的。
最终效果
源码
源码放在GitHub上了,https://github.com/Yu-Core/MAUIBlazorLoadLocalImage
MAUI Blazor 加载本地图片的解决方案的更多相关文章
- android ImageLoader加载本地图片的工具类
import android.widget.ImageView; import com.nostra13.universalimageloader.core.ImageLoader; /** * 异步 ...
- UIWebView如何加载本地图片
UIWebView如何加载本地图片 UIWebView加载本地图片是有实用价值的.比方说,有时候我们需要本地加载静态页来显示相关帮助信息,而这些帮助信息当中含有很多很多的富文本,用代码实现难度较大,这 ...
- angular 图片加载失败 情况处理? 如何在ionic中加载本地图片 ?
1.angular 图片加载失败 情况处理 在directive中定义组件,在ng-src错误时,调用err-src app.directive('errSrc',function(){ return ...
- Flutter学习笔记(19)--加载本地图片
如需转载,请注明出处:Flutter学习笔记(19)--加载本地图片 上一篇博客正好用到了本地的图片,记录一下用法: 首先新建一个文件夹,这个文件夹要跟目录下 然后在pubspec.yaml里面声明出 ...
- !!!myeclipse 上加载本地图片问题,无法加载问题
出现无法加载本地图片的问题, 原因就是把图片放到了本地项目中的image了,但是myeclipse上没有刷新 这样以后 本地的图片比在线的要快 低级错误,诶!
- 用UIWebView加载本地图片和gif图
加载gif图: NSData *gif = [NSData dataWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@" ...
- vue如何动态加载本地图片
大家好,我是前端队长Daotin,想要获取更多前端精彩内容,关注我(全网同名),解锁前端成长新姿势. 以下正文: 今天遇到一个在vue文件中引入本地图片的问题,于是有了这篇文章. 通常,我们的一个im ...
- UIImage加载本地图片的两种方式
UIImage加载图片方式一般有两种: (1)imagedNamed初始化:默认加载图片成功后会内存中缓存图片,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象.如果缓存中没有找到相应的图片 ...
- Unity加载本地图片的2种方式
1. 使用 WWW 加载,详细查看 unity3d 官方文档. 2. 使用 System.IO 加载,lua 代码如下: local File = luanet.import_type("S ...
- fresco加载本地图片、gif资源
首先 来看看fresco 是个神马东西 https://github.com/facebook/fresco 这个是fresco的一个官方gifhub 官网为http://frescolib.org/ ...
随机推荐
- Vue项目的网络请求代理到封装详细步骤
1.创建vue项目 vue create demo demo是项目名称 2.安装axios 进入demo里面打开终端(黑窗口),执行 npm install axios 3.进行config.js配置 ...
- [Pytorch框架] 2.5 循环神经网络
文章目录 2.5 循环神经网络 2.5.1 RNN简介 RNN的起因 为什么需要RNN RNN都能做什么 2.5.2 RNN的网络结构及原理 RNN LSTM GRU 2.5.3 循环网络的向后传播( ...
- 继承 extends
首先是基础的继承关系,用extend就可以继承. 再者是继承的东西,包括:变量(也包括类变量).全部非私有的属性和方法(除了父类的构造方法) 注:构造方法 class C{ public C() { ...
- 2021-02-03:手写代码:KMP算法。
福哥答案2021-02-03: Knuth-Morris-Pratt 字符串查找算法,简称为 KMP算法,常用于在一个文本串 S 内查找一个模式串 P 的出现位置.这个算法由 Donald Knuth ...
- ABP - 初识 ABP
ABP框架 ABP是用于创建现代化Web应用程序的完整体系结构和强大的基础架构,以模块化的方式进行开发,所有模块以nuget包的方式提供,开箱即用,遵循最佳实践和约定,提供SOLID开发经验. 缩写 ...
- vue全家桶进阶之路14:常用属性和方法
Vue2中常用的属性和方法: 属性 el:用于指定Vue实例挂载的元素,可以是CSS选择器.HTML元素或Vue组件. data:用于存储Vue实例的响应式数据,也可以是一个函数,返回一个对象,用于提 ...
- ESLint: Expected a space before ‘/>;‘, but not found. (vue/html-closing-bracket-spacing)
文件->设置->编辑器->代码样式->HTML->其他-->在空的标签(打钩)
- k8s资源对象(二)
Configmap和Secret资源介绍 secret和configmap资源都是通过挂载的方式将对应数据挂载到容器内部环境中去使用,两者的使用没有太多的不同 ,configmap资源通常用于为pod ...
- springboot 整合druid和mybatis
Shrio+Mybatis+Druid 1.导入相关依赖包 2.在配置文件配置数据源 3.pojo对应实体类和mapper目录下的接口UserMapper (3.使用注解版) package com. ...
- 主流原型设计工具-Axure
原型设计工具是一种用于设计和验证用户界面的软件工具,它可以帮助用户将界面设计想法转化为可交互的原型.以下是几种常见的原型设计工具: Axure:Axure是一款强大的原型设计工具,可以创建高保真的原型 ...