基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片
系列文章
- 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客?
- 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目
- 基于.NetCore开发博客项目 StarBlog - (3) 模型设计
- 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入
- 基于.NetCore开发博客项目 StarBlog - (5) 开始搭建Web项目
- 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表
- 基于.NetCore开发博客项目 StarBlog - (7) 页面开发之文章详情页面
- 基于.NetCore开发博客项目 StarBlog - (8) 分类层级结构展示
- 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入
- 基于.NetCore开发博客项目 StarBlog - (10) 图片瀑布流
- 基于.NetCore开发博客项目 StarBlog - (11) 实现访问统计
- 基于.NetCore开发博客项目 StarBlog - (12) Razor页面动态编译
- 基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能
- 基于.NetCore开发博客项目 StarBlog - (14) 实现主题切换功能
- 基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片
- ...
前言
之前我写了一篇 .NetCore实现图片缩放与裁剪 - 基于ImageSharp,里面有生成尺寸随机图片的算法,同时也是StarBlog博客中原有的实现方式,不过偶尔刷新页面的时候我注意到有些图片加载不出来,调试了一下发现原来是报错了,原本这个算法有bug。于是利用周末时间重新实现了一遍,这下可以说是完美了~
生成随机尺寸图片的功能目前用在文章卡片上,原本使用的是LoremPicsum提供的服务,但它的服务器在国外,上线之后发现加载太慢了,经常加载不出来,于是决定自己实现一版。功能基础是上文提到的文章中的ImageSharp。

思路
先理一下需求
- 指定一个目录作为图片库位置,把之前搜集的壁纸图片放进去,大概放个几百张就行了吧
- 遍历获取到库中的图片列表
- 随机取出一张图片
- 根据指定的尺寸缩放或裁剪图片
其他的还有诸如指定随机seed、将seed与图片进行静态映射等扩展功能的实现。
关键功能
关键功能在于「根据指定的尺寸缩放或裁剪图片」
难点在于裁剪和缩放图片要保证:
- 不改变图片原有的比例
- 尽量保持图片原有的内容元素
第一版我是将横屏和竖屏的图片分开处理,(在输入尺寸不超过原图尺寸的情况下)先把比例接近的边调整成一样的大小,再裁剪中间部分,不过问题也很明显,如果调整大小之后另一条边的长度小于输入长度,那就会拉伸图片,导致比例改变。
在参考几个类似的MATLAB和Python项目之后,我换了别的思路:
- 在输入尺寸不超过原图尺寸的情况下,先按输入的尺寸比例裁剪、再调整尺寸
- 如果超出原图尺寸,则先按比例调整原图的大小,再重复第一步
举个例子
比如原图是 1080 x 2340 的尺寸,输入的图片是 400 x 200 尺寸
那第一步判断尺寸不超过原图,不需要缩放
然后是「按输入的尺寸比例裁剪」,把 400 x 200 化简成 2 : 1 的比例
在原图中截取 2 : 1 的大小,即 1080 x 540
然后再把截取的图片调整到 400 x 200,搞定!
看下效果
| 原图 | 输出(400x200) | 输出(200x300) |
|---|---|---|
![]() |
![]() |
![]() |
虽然比一开始的方案更费一丢丢内存,但却实实在在提升了出图成功率,nice~
代码实现
直接上代码好了,根据上面提到的思路,分两步走,代码也比一开始的方案更整洁
async Task<(Image, IImageFormat)> GenerateSizedImageAsync(string imagePath, int width, int height) {
await using var fileStream = new FileStream(imagePath, FileMode.Open);
var (image, format) = await Image.LoadWithFormatAsync(fileStream);
// 输出尺寸超出原图片尺寸,放大
if (width > image.Width && height > image.Height) {
image.Mutate(a => a.Resize(width, height));
}
else if (width > image.Width || height > image.Height) {
// 改变比例大的边
if (width / image.Width < height / image.Height)
image.Mutate(a => a.Resize(0, height));
else
image.Mutate(a => a.Resize(width, 0));
}
// 将输入的尺寸作为裁剪比例
var (scaleWidth, scaleHeight) = GetPhotoScale(width, height);
var cropWidth = image.Width;
var cropHeight = (int) (image.Width / scaleWidth * scaleHeight);
if (cropHeight > image.Height) {
cropHeight = image.Height;
cropWidth = (int) (image.Height / scaleHeight * scaleWidth);
}
var cropRect = new Rectangle((image.Width - cropWidth) / 2, (image.Height - cropHeight) / 2, cropWidth, cropHeight);
image.Mutate(a => a.Crop(cropRect));
image.Mutate(a => a.Resize(width, height));
return (image, format);
}
里面还用到了计算图片比例,很简单,先算出图片宽度和高度的最大公约数,然后宽高分别除以这个最大公约数,就是比例了(也就是化简分数)
计算最大公约数代码
private static int GetGreatestCommonDivisor(int m, int n) {
if (m < n) (n, m) = (m, n);
while (n != 0) {
var r = m % n;
m = n;
n = r;
}
return m;
}
计算图片比例代码
private static (double, double) GetPhotoScale(int width, int height) {
if (width == height) return (1, 1);
var gcd = GetGreatestCommonDivisor(width, height);
return ((double)width / gcd, (double)height / gcd);
}
参考资料
- Python PIL图片按比例裁剪:https://blog.csdn.net/lly1122334/article/details/122365539
- python 等比例裁剪图片:https://blog.csdn.net/chenping1993/article/details/110088858
- C#基础练习之求两个数的最大公约数与最小公倍数:https://blog.csdn.net/maybe_ice/article/details/104328202
基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片的更多相关文章
- 基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (17) 自动下载文章里的外部图片
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (18) 实现本地Typora文章打包上传
前言 九月太忙,只更新了三篇文章,本来这个功能是从九月初就开始做的,结果一直拖到现在国庆假期才有时间完善并且写文章~ 之前我更新了几篇关于 Python 的文章,有朋友留言问是不是不更新 .Net 了 ...
- 基于.NetCore开发博客项目 StarBlog - (19) Markdown渲染方案探索
前言 笔者认为,一个博客网站,最核心的是阅读体验. 在开发StarBlog的过程中,最耗时的恰恰也是文章的展示部分功能. 最开始还没研究出来如何很好的使用后端渲染,所以只能先用Editor.md组件做 ...
- 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 ... 基于. ...
- 基于.NetCore开发博客项目 StarBlog - (3) 模型设计
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (5) 开始搭建Web项目
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
随机推荐
- k8s入门之Ingress(七)
Ingress 的功能其实很容易理解:所谓 Ingress,就是 Service 的"Service",代理不同后端 Service 而设置的负载均衡服务. 一.安装ingress ...
- 技术管理进阶——一线Leader与大Leader的差异是什么?
原创不易,求分享.求一键三连 前几年,因为下属的一些骚操作,Leader对我产生了误会,这导致了一些"不信任",这种不信任在短时间会让人丧失安全感,很多人会因此患得患失. 这种 ...
- tuandui last
组长博客链接### 组长博客 参考邹欣老师的问题模板进行总结思考### 设想和目标(2分)#### 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 解决的问题 ...
- 利用腾讯云函数部署.Net 5米游社原神每日签到功能
自从GitHub批量禁止滥用Action功能后,项目不得不考虑另外方案执行应用.其中腾讯云函数被大家作为不错的选择(虽然马上也要收费了). 但对于.Net的部署目前资源很少,而且我也没学过bash.在 ...
- Java中的JVM和Redis,你了解的透彻么?
招聘在前不久已经渐渐拉下帷幕了,看到最近技术群一个问题,引起了我的思考:"今年面试为什么那么难?" 想必大家都知道程序员要涨薪主要靠跳槽来完成!但是无论是考试,还是求职,这个难度, ...
- 想学会SOLID原则,看这一篇文章就够了!
背景 在我们日常工作中,代码写着写着就出现下列的一些臭味.但是还好我们有SOLID这把'尺子', 可以拿着它不断去衡量我们写的代码,除去代码臭味.这就是我们要学习SOLID原则的原因所在. 设计的臭味 ...
- 《你不知道的JS》上
- java_简单学习笔记
java_study笔记 前言: 所有笔记均总结自狂神的java基础视频 https://www.bilibili.com/video/BV12J41137hu?p=1 idea小技巧 psvm+回车 ...
- 好客租房1-React基础目标
学习目标 能够说出React是什么 掌握react的特点 掌握react的基本使用 能够使用react脚手架 学习目录 react概述 react基本使用 react脚手架
- 如何在 pyqt 中自定义工具提示 ToolTip
前言 Qt 自带的工具提示样式不太好看,就算加了样式表也时不时会失效,同时工具提示没有阴影,看起来就更难受了.所以本篇博客将会介绍自定义工具提示的方法,效果如下图所示: 实现过程 工具提示其实就是一个 ...


