• 基于.NetCore开发博客项目 StarBlog - (20) 图片显示优化


    前言

    我的服务器带宽比较高,博客部署在上面访问的时候几乎没感觉有加载延迟,就没做图片这块的优化,不过最近有小伙伴说博客的图片加载比较慢,那就来把图片优化完善一下吧~

    目前有两个地方需要完善

    • 图片瀑布流
    • 图片缩略图

    图片瀑布流

    关于瀑布流之前的文章有介绍: 基于.NetCore开发博客项目 StarBlog - (10) 图片瀑布流

    不过当时直接套用的 Bootstrap5 例子代码,有偶尔显示错位的bug

    我又去看了一下 masonry-layout 的官网,找到这个bug的原因:瀑布流在图片还没加载完成就渲染好了,而图片的大小不一,造成了最终显示错位。

    解决方法也很简单,用 imagesLoaded 这个库,它有个事件,在全部图片加载完成后触发,在事件响应里面再渲染一次瀑布流,就搞定了~

    masonry-layout 这个库里面不附带 imagesLoaded ,要用必须自己安装。

    我用的版本是 5.0.0

    yarn add imagesloaded
    

    在 StarBlog.Web 的 gulpfile.js 里配置一下路径

    1. // 使用 npm 下载的前端组件,自定义存放位置
    2. const customLibs = [
    3. // ...
    4. {name: 'imagesloaded', dist: './node_modules/imagesloaded/*.js'},
    5. ]

    然后执行 gulp move

    接着,修改一下图片页面 StarBlog.Web/Views/Photography/Index.cshtml

    引入 js 依赖,我这里还用了 environment tag helper,可以根据不同的环境引入不同的文件。在开发环境引入完整 js 文件,生产环境引入 ``*.min` 文件。

    1. @section bottom {
    2. <environment include="Development">
    3. <script src="~/lib/jquery/dist/jquery.js"></script>
    4. <script src="~/lib/masonry-layout/dist/masonry.pkgd.js"></script>
    5. <script src="~/lib/imagesloaded/imagesloaded.pkgd.js"></script>
    6. </environment>
    7. <environment exclude="Development">
    8. <script src="~/lib/jquery/dist/jquery.min.js"></script>
    9. <script src="~/lib/masonry-layout/dist/masonry.pkgd.min.js"></script>
    10. <script src="~/lib/imagesloaded/imagesloaded.pkgd.min.js"></script>
    11. </environment>
    12. <script src="~/js/photo.js"></script>
    13. }

    把图片列表部分的代码改一下

    1. <div id="photo-grid" class="row">
    2. @foreach (var photo in Model.Photos) {
    3. <div class="col-sm-6 col-lg-4 mb-4 grid-item">
    4. <partial name="Widgets/PhotoCard" model="photo"/>
    5. </div>
    6. }
    7. </div>

    然后是 js/photo.js里的 js 代码

    1. // init Masonry
    2. let $grid = $('#photo-grid').masonry({
    3. itemSelector: '.grid-item',
    4. percentPosition: true,
    5. })
    6. // layout Masonry after each image loads
    7. $grid.imagesLoaded().progress( function() {
    8. $grid.masonry('layout');
    9. });

    搞定~

    图片缩略图

    一开始我用的是 SixLabors.ImageSharp.Web 这个库

    挺方便的,以中间件的形式使用

    通过 Nuget 安装之后,在 program.cs 里配置一下

    1. // 注册服务
    2. builder.Services.AddImageSharp();
    3. // 添加中间件
    4. app.UseImageSharp();

    之后就可以在任意图片文件的地址后面加上 width=xxx&format=xxx 这样的参数来实现调整大小和转换格式了~

    图片列表的每个图片我做成了一个 partial view 组件,在 StarBlog.Web/Views/Shared/Widgets/PhotoCard.cshtml 这个文件

    要把这个改成缩略图,只需要修改一下 img 元素

    现在每个图片缩略图宽度300(宽度自适应),格式转换成 webp

    <img class="bd-placeholder-img card-img-top" src="/media/@Model.FilePath?width=300&format=webp" alt="">
    

    这个中间件还有很多其他参数可以设置,我只用到两个,详情可以看文档: Processing Commands

    Progressive JPEG

    本来用 ImageSharp.Web 中间件已经够好了

    但还有一点美中不足,就是它不支持生成 progressive JPEG 图片,这样就没办法在加载图片的时候先显示一个模糊的轮廓,再逐渐变清晰,而是从上到下一行一行加载,不好看~

    所以,我用了 Magick.NET 这个库来实现生成 progressive JPEG 格式的图片。

    这个库有三种版本:Q8, Q16, Q16-HDRI

    根据官网文档,我选择了它推荐的 Q8 版本,性能最好 (图片质量无所谓了)

    使用 nuget 安装 Magick.NET-Q8-AnyCPU 这个库

    修改 StarBlog.Web/Services/PhotoService.cs

    现在我要来写一个生成缩略图的方法

    1. /// <summary>
    2. /// 生成Progressive JPEG缩略图 (使用 MagickImage)
    3. /// </summary>
    4. public async Task<byte[]> GetThumb(string id, int width=300) {
    5. var photo = await _photoRepo.Where(a => a.Id == id).FirstAsync();
    6. using (var image = new MagickImage(GetPhotoFilePath(photo))) {
    7. image.Format = MagickFormat.Pjpeg;
    8. image.Resize(width,0);
    9. return image.ToByteArray();
    10. }
    11. }

    接着再写个接口

    编辑 StarBlog.Web/Apis/PhotoController.cs

    1. [HttpGet("{id}/Thumb")]
    2. public async Task GetThumb(string id, [FromQuery] int width = 300) {
    3. var data = await _photoService.GetThumb(id, width);
    4. return new FileContentResult(data, "image/jpeg");
    5. }

    搞定。

    现在只需要访问 /Api/Photo/{图片ID}/Thumb?width=300 这个地址,就可以生成 progressive JPEG 格式的缩略图了~

    最后再来改造一下 StarBlog.Web/Views/Shared/Widgets/PhotoCard.cshtml 组件

    1. <img class="bd-placeholder-img card-img-top" alt=""
    2. src="@Url.Action("GetThumb", "Photo", new {id = Model.Id, width = 300})">

    okk~

    小结

    相比起 ImageSharp.Web 中间件自带缓存的特性,我这个自己写的缩略图方法是比较粗糙的,而且每次请求都是动态生成,会给服务器带来一定压力。

    不过它没有 Progressive JPEG 呀,这个功能缺失真的太难受了,只能期待它早日实现这个功能吧~

    不然就只能我自己来实现缓存功能提高性能了~

  • 相关阅读:
    msf后渗透之文件交互指令、上传下载文件、屏幕截图、键盘记录、创建账户、音频录像和提权(上)
    基于SSM实现智慧幼儿园信息管理系统
    SSM框架-Spring(二)
    涨薪了!原来这才是性能优化的正确打开方式
    一些逻辑漏洞案例
    高考志愿填报和未来的职业规划
    【23种设计模式】享元模式【⭐】
    Halcon 第一章『Halcon语言』◆第5节:读取图像
    【力扣】292. Nim 游戏
    JavaFX Scene Builder Miscellaneous 控件详解
  • 原文地址:https://blog.csdn.net/jh035512/article/details/128109821