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/ ...
随机推荐
- JavaScript基础语法-变量
JavaScript JavaScript - 变量 1. 概念 变量是用于存放数据的容器 通过变量名可以获取数据 并且数据是可修改的 2. 使用 声明变量 只声明不赋值 直接调用 程序会输出unde ...
- SkyWalking的学习之一
SkyWalking的学习之一 前言 最近在学习应用调优诊断等内容. 现在实际工作中实质上的拆分和微服务在售前阶段 所以真正用到链路的地方比较少. 但是人生都是要向前看的. 想着一方面提高自己. 一方 ...
- Torchvision datasets中的经典数据集梳理(以及与OCR相关的常用数据集整理)
这篇文章是在上班摸鱼的时候随手整理的一些常用CV数据集(文末附带我处理好的数据的下载资源) 众所周知,通过使用Torchvision,可以方便快捷地加载一些较为常用的数据集.但是(敲黑板!)如果本地没 ...
- Django框架——静态文件配置、form表单、request对象、连接数据库、ORM简介、ORM基本操作和语句
配置文件介绍 SECRET_KEY = '0yge9t5m9&%=of**qk2m9z^7-gp2db)g!*5dzb136ys0#)*%*a' # 盐 DEBUG = True # 调试模式 ...
- 云原生时代崛起的编程语言Go常用标准库实战
@ 目录 基础标准库 简述 字符串-string 底层结构 函数 长度 格式化输出 模版-template text/template html/template 正则表达式-regexp 编码-en ...
- 2023-04-27:用go语言重写ffmpeg的remuxing.c示例。
2023-04-27:用go语言重写ffmpeg的remuxing.c示例. 答案2023-04-27: ffmpeg的remuxing.c是一个用于将多媒体文件从一种容器格式转换为另一种容器格式的命 ...
- 2022-07-02:以下go语言代码输出什么?A:编译错误;B:Panic;C:NaN。 package main import “fmt“ func main() { var a =
2022-07-02:以下go语言代码输出什么?A:编译错误:B:Panic:C:NaN. package main import "fmt" func main() { var ...
- 2022-05-30:给定一个n*2的二维数组,表示有n个任务。 一个信息是任务能够开始做的时间,另一个信息是任务的结束期限,后者一定大于前者,且数值上都是正数, 你作为单线程的人,不能并行处理任务,
2022-05-30:给定一个n*2的二维数组,表示有n个任务. 一个信息是任务能够开始做的时间,另一个信息是任务的结束期限,后者一定大于前者,且数值上都是正数, 你作为单线程的人,不能并行处理任务, ...
- 2023.5.16 总结 AT_abc260_g
atcoder AT_abc260_g 题意 一个点 O 可以影响到其它点,能影响到的点的坐标满足:(\((u, v)\) 为当前点的坐标,\((x, y) 为能影响到的点的坐标\)) \(u\le ...
- 深入理解 python 虚拟机:破解核心魔法——反序列化 pyc 文件
深入理解 python 虚拟机:破解核心魔法--反序列化 pyc 文件 在前面的文章当中我们详细的对于 pyc 文件的结构进行了分析,pyc 文件主要有下面的四个部分组成:魔术. Bite Filed ...