昨天又使用了某个多年以前写的,或者说是“收集”而来的方法。这个方法的作用是根据一幅图片(一般是幅大图)生成它的缩略图。这个方法用了许多年了,一直没有去怀疑过它的正确性,但是昨天忽然发现它一直以来都存在一个问题,虽然可能不是那么明显,而且也不会造成太大问题(否则早就发现了)——但是,这的确是个不妥的地方。这个问题在我看来也有一定借鉴意义,因此我打算把它展示出来。那么,您能否看出它究竟是错在什么地方了呢?

生成缩略图的规则很简单,概括地说有三点:

  1. 包含图片完整内容,以及长宽比不变。
  2. 尺寸尽可能大,但如果图片本身很小,也不做拉伸。
  3. 不超过指定的width * height的范围内。

这个规则其实就是最传统的缩略图生成方式,使用如Windows照片浏览器等软件打开图片后,一般来说默认都会如此调整图片尺寸。而我们如果需要写一段代码来实现这一点也并不困难,以下便是我用了许多年的方法:

/// <summary>
/// Creates a thumbnail from an existing image. Sets the biggest dimension of the
/// thumbnail to either desiredWidth or Height and scales the other dimension down
/// to preserve the aspect ratio
/// </summary>
/// <param name="imageStream">stream to create thumbnail for</param>
/// <param name="desiredWidth">maximum desired width of thumbnail</param>
/// <param name="desiredHeight">maximum desired height of thumbnail</param>
/// <returns>Bitmap thumbnail</returns>
public Bitmap CreateThumbnail(Bitmap originalBmp, int desiredWidth, int desiredHeight)
{// If the image is smaller than a thumbnail just return itif (originalBmp.Width <= desiredWidth && originalBmp.Height <= desiredHeight){return originalBmp;}int newWidth, newHeight;// scale down the smaller dimensionif ((decimal)desiredWidth / originalBmp.Width < (decimal)desiredHeight / originalBmp.Height){decimal desiredRatio = (decimal)desiredWidth / originalBmp.Width;newWidth = desiredWidth;newHeight = (int)(originalBmp.Height * desiredRatio);}else{decimal desiredRatio = (decimal)desiredHeight / originalBmp.Height;newHeight = desiredHeight;newWidth = (int)(originalBmp.Width * desiredRatio);}// This code creates cleaner (though bigger) thumbnails and properly// and handles GIF files better by generating a white background for// transparent images (as opposed to black)// This is preferred to calling Bitmap.GetThumbnailImage()Bitmap bmpOut = new Bitmap(newWidth, newHeight);using (Graphics graphics = Graphics.FromImage(bmpOut)){graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;graphics.FillRectangle(Brushes.White, 0, 0, newWidth, newHeight);graphics.DrawImage(originalBmp, 0, 0, newWidth, newHeight);}return bmpOut;
}

它的具体来源我已经记不得了,不过从英文注释上来看这应该是个老外写的代码,那么我们现在就来解释一番。首先,这个方法会先判断源图片的大小是否已经可以放入目标区域(desiredWidth * desiredHeight)中了,如果是,则直接返回源图片。如果不满足第一个判断,则说明宽和高之中至少有一个超出了目标尺寸,而我们要对源图片进行等比例缩放。

那么缩放的“比例”又是多少呢?自然是“宽”或“高”中缩放“程度大”的那个。因为如果按照缩放程度小的那条边的比例来改变图片尺寸,那么另一条边势必会超出范围。因此,我们接下来便是比较desiredWidth与originalBmp.Width之比,以及desiredHeight与originalBmp.Height之比孰大孰小。哪个小,则意味着我们要把它作为缩放依据,因为它对图片尺寸的限制要比另一条边来的严格。于是乎,再第二个条件判断的任意一个分支中,我们都可以计算出缩放的比例(desiredRatio),然后把作为“依据”的那条边设为desiredWidth/Height,将另一条边根据缩放比例进行调整。在计算和比较过程中我们都使用了decimal数据类型,因为它是.NET中精度最高的浮点数类型,我们以此减少计算过程中所带来的误差。

至于得到了newWidth和newHeight之后,我们便只要根据这个尺寸生成目标图片即可,它便是源图片的缩略图,符合我们之前提出的三个要求。

听起来很简单,看上去也没有什么问题,不是吗?不过,其实这个实现中有一个不那么明显的问题,您发现了吗?(答案)

您能看出这个生成缩略图的方法有什么问题吗?相关推荐

  1. php 缩略图不失真,c#生成缩略图不失真的方法实例分享

    c#生成缩略图不失真的方法实例分享/// /// 获得缩微图 /// /// public bool GetThumbImg() { try { string imgpath; //原始路径 if(i ...

  2. php 生成等比例缩略图,PHP实现原比例生成缩略图的方法

    PHP实现原比例生成缩略图的方法 发布于 2016-02-17 05:18:30 | 107 次阅读 | 评论: 0 | 来源: 网友投递 PHP开源脚本语言PHP(外文名: Hypertext Pr ...

  3. php图片生成缩略图_php实现根据url自动生成缩略图的方法

    本文实例讲述了php实现根据url自动生成缩略图的方法,是非常实用的功能.分享给大家供大家参考.具体方法如下: 原理:设置apache rewrite ,当图片不存在时,调用php创建图片. 例如: ...

  4. php 图片生成视频,PHP基于ffmpeg实现转换视频,截图及生成缩略图的方法

    本文实例讲述了PHP基于ffmpeg实现转换视频,截图及生成缩略图的方法.分享给大家供大家参考,具体如下: 这里把ffmpeg 和  生成缩略图整合了一下: include("ImageRe ...

  5. java生成缩略图例子_具体介绍java生成缩略图的方法示例代码

    这篇文章主要介绍了java生成缩略图的方法,结合具体实例形式分析了java生成缩略图过程中所涉及的各种常见的图形处理技巧,需要的朋友可以参考下 本文实例讲述了java生成缩略图的方法.分享给大家供大家 ...

  6. Android生成缩略图的方法

    Android9.0 之前,使用BitmapFactory生成缩略图. 举例:使用ThumbnailTask生成缩略图,GridViewAdapter显示缩略图 static class Thumbn ...

  7. PS如何批量生成缩略图(方法可以通用其他重复劳动)

    原图 缩略 进入正题,学生时代玩过脚本精灵的应该一点就通 原理就是:录制一系列动作,然后生成脚本,并执行(经常PS水印代码的一个可以用程序实现,一个就可以用PS脚本) 新建一个组 新建一个动作 进行你 ...

  8. C#中不失真生成缩略图

    C#中不失真生成缩略图- - 使用.net的方法GetThumbnailImage生成的缩略图失真严重,这里推荐一种不失真生成缩略图的方法,供参考. /// <summary>   /// ...

  9. java 生成缩略图并返回字节数组_关于提取后台图片数据时自动生成缩略图程序...

    调用图片的页面: require_once('thumbs.php');//调用缩略图的类文件 //3 手机推荐 $nestedRows= $Download->getDownotherList ...

最新文章

  1. 【转】modulenotfounderror: no module named ‘matplotlib._path‘问题的解决
  2. Arm v9的牙膏挤出来了,超大核机器学习性能x2,小核4年来终于更新
  3. javascript基础(第一天)
  4. CC2541对AT24CXX系列存储器的支持
  5. 什么叫返回路径平面上的间隙_信号完整性:关于走线的参考平面问题探讨
  6. CGTN专访第四范式裴沵思 阐释数字化转型背后的驱动力
  7. Weka java.lang.reflect.InvocationTargetException
  8. 基于HTML5 的人脸识别活体认证
  9. 2016陕西省ACM省赛 HE 字符串处理 删除注释
  10. ruhe anzjhuang mysql_Mysql配置安装过程
  11. Codeforces Round #535 (Div. 3)
  12. 怎么把vivo强行刷入鸿蒙系统,vivo手机如何强制刷机
  13. caj转换成word方法免费
  14. 对数(log)的换算公式
  15. 设计窗口模拟教室座位表java,基于web的考研自习教室座位管理(完整源码+论文全套+教学视频)...
  16. pytorch.chunk
  17. 怎样屏蔽浏览器关闭按钮及ALT+F4 快捷键
  18. 直播系统解决方案-搭建你自己的直播平台
  19. Mac Edge 浏览器开启几秒后自动关闭问题
  20. html使用thymeleaf模板时,获取数据库中字符串值,拆分为list根据下标获取对应的值的方法

热门文章

  1. Docker Review - dockerfile 实战_给基础镜像增加功能
  2. 深入理解分布式技术 - 分布式调用跟踪
  3. MySQL - 并发事务问题及解决方案
  4. xamarin.android蓝牙,在Android上连接Xamarin的配对蓝牙设备
  5. mysql中的钱null,mysql 中null总结
  6. 学习笔记Hadoop(十一)—— Hadoop基础操作(3)—— MapReduce常用Shell操作、MapReduce任务管理
  7. python协程实时输出_python协程
  8. android view setx,Android的setX()和setY()表现不可思议
  9. leetcode 刷题 118. 杨辉三角解题思路
  10. java虚拟机所支持的指令_JVM虚拟机指令