啊... ...

一通操作下来感觉就是两个字 折磨

跨平台有跨平台的好处 但框架本身支持的有限 很多东西做起来很曲折 哎

这里总结一下笔者为了折腾本地图片显示的尝试

为什么要做本地图片展示呢 如果是做需要网络连接的app 这个一般是不需要的(要做上传前预览/编辑的话还是要的)

但对于离线的app肯定是要的 总会有场景用户导入图片/文件之类的吧

笔者只测试了windows和安卓这两个平台,mac和iOS因为没有设备和开发者账号所以调试不了

复制到wwwroot

这是最简单直接的方法,什么都不用改,把图片复制到wwwroot下然后直接使用图片地址就行了

代码如下:

    public async Task PickAndShow(PickOptions options)
{
try
{
var result = await FilePicker.Default.PickAsync(options);
if (result != null)
{
await using var stream = await result.OpenReadAsync();
var originalFileName = result.FileName;
var extension = Path.GetExtension(originalFileName);
var targetFileName = Guid.NewGuid() + extension; var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", "images", targetFileName);
Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", "images"));
await using var targetStream = new FileStream(path, FileMode.Create);
Debug.WriteLine($"copy path:{path}");
await stream.CopyToAsync(targetStream);
_objUrl = $"images/{targetFileName}";
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}

这个的优点就是简单直接

缺点就是安卓不支持... 安卓的wwwroot在app bundle里 只能读不能写

适合只需要windows的使用

但你只需要windows 还用maui是不是有

base64/objectURL

这两个我一起说 因为原理是一样的

存在sqlite appdata或者其他什么地方

需要用的时候读取转化为base64和objectURL

但是使用base64的时候我发现了很严重的内存泄漏,传了很多图片测试之后应用的内存直接炸了.

见: https://stackoverflow.com/questions/77513507/how-to-avoid-memory-leaks-when-using-base64-images-in-blazor

可能是我用的png有关,但他的确会造成内存较大的消耗,并且有不必要的开销,你转成base64,浏览器还得给他转回来.

用objectURL是个更好的选择

在index.html中放入这段代码:

<script>
window.createObjectURL = async (imageStream) => {
const arrayBuffer = await imageStream.arrayBuffer();
const blob = new Blob([arrayBuffer]);
return URL.createObjectURL(blob);
} window.revokeObjectURL = (url) => {
URL.revokeObjectURL(url);
}
</script>

扩展一下IJSRuntime,这是为了方便使用,也可以直接调,都是一样的:

public static class IJSRuntimeExtensions
{
public static ValueTask<string> CreateObjectUrl(this IJSRuntime js, Stream stream, bool leaveOpen = false)
{
var dotNetStreamReference = new DotNetStreamReference(stream, leaveOpen);
return js.InvokeAsync<string>("createObjectURL", dotNetStreamReference);
} public static async Task RevokeObjectUrl(this IJSRuntime js, string? url)
{
Debug.WriteLine($"Revoke call url {url}");
if (url is not null)
{
await js.InvokeVoidAsync("revokeObjectURL", url);
}
}
}

哪里需要用调用一下获得objectURL即可

复制到appdata下 覆盖CreateFileProvider

从爆栈上发现的,测试了下windows和安卓上都可用,意外的简单直接.

见:

https://stackoverflow.com/a/75282680/2078863

public class CustomFilesBlazorWebView : BlazorWebView
{
public override IFileProvider CreateFileProvider(string contentRootDir)
{
var lPhysicalFiles = new PhysicalFileProvider(FileSystem.Current.AppDataDirectory);
return new CompositeFileProvider(lPhysicalFiles, base.CreateFileProvider(contentRootDir));
}
}

然后用这个替换原本的BlazorWebView即可.

之后就将文件复制到Appdata下:

    public static readonly string ImageDir = "image";

    public async Task<string> CopyToImageDir(byte[] bytes, string originalFileName)
{
var appFilePath = Path.Combine(GetImageDirPath(), CreateNewName(originalFileName));
Directory.CreateDirectory(GetImageDirPath());
await using var fileStream = File.Create(appFilePath);
await fileStream.WriteAsync(bytes);
return appFilePath;
} public string GetImageDirPath()
{
return Path.Combine(FileSystem.AppDataDirectory, ImageDir);
} private string CreateNewName(string originalFileName)
{
var extension = Path.GetExtension(originalFileName);
var uuid = Guid.NewGuid().ToString();
var newFileName = $"{Path.GetFileNameWithoutExtension(originalFileName)}_{uuid}{extension}";
return newFileName;
}

url使用image/filename即可


这些方案都不可避免要将文件复制都某个地方.

其实优化下可以直接读原始文件, 但是不同平台限制不太一样, 比如在安卓上FilePicker返回的fullPath是cache地址不是实际地址, 需要自己写native代码用安卓原生的文件选择.

其他还有不少大佬的方案,这里只做几个实现比较简单的总结.

市面上有许多由资深开发者提出的复杂方案,但在这里,我只总结了几个实现起来相对简单的方法.

唉,MAUI本身的使用确实颇具挑战性.虽然将Blazor集成进UI在某种程度上缓解了这一问题,但由于其跨平台的特性,很多功能似乎都不尽如人意.

初看上去,基础的使用似乎没什么问题,但一旦动手实现更复杂的功能,就会发现受到了各种限制.想要突破这些限制,就必须编写与平台相关的代码,而这又要求你必须深入了解Windows、安卓和iOS等系统的原生代码是如何编写的.

这种局面确实令人尴尬,这或许也是跨平台框架普遍存在的问题.

微软的努力将决定未来的发展,但从他们那边来看,情况似乎并不乐观.

就以本文读取本地图片的问题为例:

https://github.com/dotnet/maui/issues/2907

https://github.com/dotnet/aspnetcore/issues/25274

早在2021年甚至2020年,就有人提出了这个问题.

经过多个相关问题的讨论,认为在.NET 7中实现这一功能风险太大,决定推迟到.NET 8.

mkArtakMSFT modified the milestones: Backlog, .NET 7 Planning on Nov 6, 2021

danroth27 modified the milestones: .NET 7 Planning, .NET 8 Planning on Aug 24, 2022

While we have made progress on this feature, at this point we think the risk is too high to include this in the .NET 7 release. Moving to .NET 8.

2023-06-30 bot: We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

然而,即便.NET 8已经发布,这个功能依旧没有得到官方的实现, 只有各种workaround……这实在令人沮丧.

MAUI给人的感觉好像是一个被遗弃的项目.随着.NET 9或.NET 10的推出,微软可能会宣布停止支持MAUI,并推出另一个全新的框架.

毕竟微软的作风一贯如此.

相关参考链接:

Work with images in ASP.NET Core Blazor

[Bug] Not allowed to load local resource for Android

Blazor Image component to display images that are not accessible through HTTP endpoints

How to display local image as well as resources image in .Net MAUI Blazor

Overriding CreateFileProvider for BlazorWebView throws exception

博客: blazor maui hybrid app显示本地图片

blazor maui hybrid app显示本地图片的更多相关文章

  1. Android ImageView显示本地图片

    Android ImageView 显示本地图片 布局文件 <?xml version="1.0" encoding="utf-8"?> <R ...

  2. Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果

    版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/1873 ...

  3. Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果

    大家好!过完年回来到现在差不多一个月没写文章了,一是觉得不知道写哪些方面的文章,没有好的题材来写,二是因为自己的一些私事给耽误了,所以过完年的第一篇文章到现在才发表出来,2014年我还是会继续在CSD ...

  4. Slog71_选取、上传和显示本地图片GET !(微信小程序之云开发-全栈时代3)

    ArthurSlog SLog-71 Year·1 Guangzhou·China Sep 12th 2018 ArthurSlog Page GitHub NPM Package Page 掘金主页 ...

  5. Atitit. html 使用js显示本地图片的设计方案.doc

    Atitit. html 使用js显示本地图片的设计方案.doc 1.  Local mode  是可以的..web模式走有的不能兰.1 2. IE8.0 显示本地图片 img.src=本地图片路径无 ...

  6. Atitit. IE8.0 显示本地图片预览解决方案 img.src=本地图片路径无效的解决方案

    Atitit. IE8.0 显示本地图片预览解决方案 img.src=本地图片路径无效的解决方案 1. IE8.0 显示本地图片 img.src=本地图片路径无效的解决方案1 1.1. div来完成  ...

  7. 在InternetExplorer.Application中显示本地图片

    忘记了,喜欢一个人的感觉 Demon's Blog  »  程序设计  »  在InternetExplorer.Application中显示本地图片 « 对VBS效率的再思考——处理二进制数据 Wo ...

  8. tomcat中显示本地图片①(未解决)

    <本模块文仅作为学习过程中的自我总结,有需要可参看,欢迎指导与提出建议,很多地方可能断章取义,理解不到位,虚心求学.谢谢!> 资料查阅原因:2018/7/10(做项目中显示详情页面,从数据 ...

  9. SpringBoot之显示本地图片范例

    controller // 扫描指定目录下的图片进行展示 @RequestMapping("/showPics") public ModelAndView showPics(Mod ...

  10. HTML5 Canvas显示本地图片实例1、Canvas预览图片实例1

    1.前台代码: <input id="fileOne" type="file" /> <canvas id="canvasOne&q ...

随机推荐

  1. #1198:Farm Irrigation(DFS + 并查集)

    Farm Irrigation **Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) T ...

  2. L2-007 家庭房产 (25 分) (并查集)

    给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数.人均房产面积及房产套数. 输入格式: 输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产: 编号 父 ...

  3. ngix反向代理服务器

    Nginx ("engine x") 是一个高性能的HTTP 和反向代理 服务器,在大负载的情况下表现十分优秀. 1.正向代理 正向代理也是大家最常接触的到的代理模式.正向代理最大 ...

  4. ifelse优化方案

    优化 if else:https://blog.csdn.net/FBB360JAVA/article/details/103832405 利用java8特性优化: https://blog.csdn ...

  5. 改变函数内this指向方法——call、apply、bind

    javascript为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部this的指向问题,常用的有bind( ).call( ).apply( )三种方法. 相同点: 都可以改变函数内部的thi ...

  6. java基础-idea的使用-day07

    目录 1. idea的获取 2. 已经安装的idea 如何卸载 3. idea的安装与破解 3. 设置 4. 写代码常用快捷建的使用 1. idea的获取 链接:https://pan.baidu.c ...

  7. langchain中的Document类

      在Langchain-Chatchat的上传文档接口(upload_docs)中有个自定义的docs字段,用到了Document类.根据发现指的是from langchain.docstore.d ...

  8. 基于html5+javascript技术开发的房贷利率计算器,买房的码农们戳进来

    房贷计算器是一款专为购房者设计的实用工具应用,其主要功能是帮助用户详细计算房贷的还款金额.利息以及还款计划等.通过这款软件,用户可以更加便捷地了解到自己的还款情况和计划,从而更好地规划自己的财务.下面 ...

  9. AHB Matrix

    常用的AHB Bus结构 AHB Matrix AHB Bus Matrix,即总线矩阵,其实际上就是一个互连(Interconnect).用于连接满足该总线协议的外设,包括Master和Slave. ...

  10. MyBatis——第一个程序

    MyBatis1:初识 MyBatis第一个程序 流程:搭建环境–>导入MyBatis–>编写代码–>测试 1.创建一张User表. 关键字id.username.pwd 2.导入相 ...