栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片

 优质资源分享 
学习路线指引(点击解锁)知识定位人群定位
李 Python实战微信订餐小程序 李进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
Python量化交易实战入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统
系列文章
  • 基于.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项目之后,我换了别的思路:

  1. 在输入尺寸不超过原图尺寸的情况下,先按输入的尺寸比例裁剪、再调整尺寸
  2. 如果超出原图尺寸,则先按比例调整原图的大小,再重复第一步
举个例子

比如原图是 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

    • 系列文章
  • 前言

  • 思路

  • 先理一下需求

  • 关键功能

  • 举个例子

  • 代码实现

  • 参考资料

    __EOF__

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wP0MxvME-1657255562035)(https://blog.csdn.net/deali)]程序设计实验室 - 本文链接: https://blog.csdn.net/deali/p/16457314.html

  • 关于博主: 公众号:程序设计实验室,欢迎交流~
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角**【[推荐](javascript:void(0)】**一下。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1008829.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号