图片缩放的相关处理
图片缩放的相关处理
最近自己做的点东西上用到了图片的处理,不过没有找到合适的图片处理相关算法,倒是找到了几个获取缩略图的算法。代码不长,简单看了看原理也比较简单(其实不是简单是C#的封装的太多了,所以显得比较简单)。既然没有相关的统一调用的代码,索性,我来整理一套相关的处理代码然后公开出来吧。
图片处理的相关分析
其实我要用的图片处理非常简单,就是简单的压缩一下图片。然后把图片设置到对应大小而已。但是对于设置的方式,C#基础的函数中使用的Rect范围设置。这个范围设置计算起来可能相对头疼一些。所以我在考虑要不要让调用者在忽略Rect这个参数的情况愉快的调用接口呢?于是乎,我定义了几个图片缩放类型(Full、Zoom、Overflow、Original)。然后默认的让原始图片的中心点与输出图片的中心点对齐。然后根据缩放类型来对图片进行不同的缩放模式。
缩放模式
- Full:让图片放弃原来的比例,直接按照目标数据进行拉伸
- Zoom:让图片保持原有比例,并且保证原始图片在目标图片的正中央,没有图片的位置保留米白色
- Original:让图片保持原来的大小,输出图片类似于裁剪中间位置某个范围的图片
- Overflow:让图片保持原来的比例,并且保证输目标是被图片填满的不留空白
调用的范例
ImageHelper.GetInstance().ImageCompress(InputFile, Path.Combine(OutPutPath, item_file), new System.Drawing.Size(500, 300), ImageZoomType.Full, 50);
样品展示
原始图片
Full 300*500
Full 500 * 300
Original 300 * 500
Original 500 * 300
Overflow 300 * 500
Overflow 500 * 300
Zoom 300 * 500
Zoom 500 * 300
存在的不足
- 压缩没有独到的技术
- 目前只支持JPEG格式的图片
- 部分图片进行缩放之后会留下一个1像素浅浅的边
后续的内容
图片处理不光是缩放,还有其他的很多东西比较实用(截图、压缩、按高缩放、按宽缩放、添加水印、添加隐藏水印),我准备把图片常用的相关处理。整理成一个帮助类,方便迁入到各个项目中去。
所以我建立了一个专门的图片处理的开源项目方便后续功能加入,地址如下:http://git.oschina.net/anxin1225/ImageCompress
压缩相关的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ImageCompress { public struct AnchorPoint { //public AnchorPoint() : this(0, 0) { } public AnchorPoint( double x, double y) { X = x; Y = y; } public double X, Y; } public enum ImageZoomType { Full, Zoom, Overflow, Original, } public delegate void ImageHandle(Image image, Bitmap bitmap); public class ImageHelper { private ImageHelper() { } private static ImageHelper _image_helper = null ; private Dictionary<ImageZoomType, ImageHandle> _name_to_handle = new Dictionary<ImageZoomType, ImageHandle>(); public static ImageHelper GetInstance() { if (_image_helper == null ) { _image_helper = new ImageHelper(); //填满 _image_helper._name_to_handle[ImageZoomType.Full] = (image, bitmap) => { _image_helper.DrawImage(image, bitmap, new Rectangle( new Point(0, 0), bitmap.Size)); }; //原始 _image_helper._name_to_handle[ImageZoomType.Original] = (image, bitmap) => { _image_helper.DrawImage(image, bitmap, 1, new AnchorPoint(0.5, 0.5), new AnchorPoint(0.5, 0.5)); }; //溢出 _image_helper._name_to_handle[ImageZoomType.Overflow] = (image, bitmap) => { float proportion_x = ( float )bitmap.Width / image.Width; float proportion_y = ( float )bitmap.Height / image.Height; _image_helper.DrawImage(image, bitmap, proportion_x > proportion_y ? proportion_x : proportion_y, new AnchorPoint(0.5, 0.5), new AnchorPoint(0.5, 0.5)); }; //缩放 _image_helper._name_to_handle[ImageZoomType.Zoom] = (image, bitmap) => { float proportion_x = ( float )bitmap.Width / image.Width; float proportion_y = ( float )bitmap.Height / image.Height; _image_helper.DrawImage(image, bitmap, proportion_x < proportion_y ? proportion_x : proportion_y, new AnchorPoint(0.5, 0.5), new AnchorPoint(0.5, 0.5)); }; } return _image_helper; } /// <summary> /// 压缩图片 /// </summary> /// <param name="source_path">源数据位置</param> /// <param name="save_path">保存数据位置</param> /// <param name="save_size">保存图片大小</param> /// <param name="ztype">缩放模式</param> /// <param name="flag">图片保存品质</param> /// <returns>是否完成压缩</returns> public bool ImageCompress( string source_path, string save_path, Size save_size, ImageZoomType ztype, int flag) { bool success = false ; Image source = null ; while ( true ) { source = LoadImage(source_path); if (source == null ) break ; Bitmap bitmap = new Bitmap(save_size.Width, save_size.Height); if (_name_to_handle.ContainsKey(ztype)) { _name_to_handle[ztype](source, bitmap); } else { break ; } success = SaveImage(bitmap, save_path, source.RawFormat, flag); break ; } if (source != null ) source.Dispose(); return success; } public Image LoadImage( string source_path) { Image image = null ; while ( true ) { if (!File.Exists(source_path)) break ; try { image = Image.FromFile(source_path); } catch { break ; } break ; } return image; } /// <summary> /// 将BitMap保存到磁盘上 /// </summary> /// <param name="image">需要保存的图片</param> /// <param name="save_path">保存的路径</param> /// <param name="format">保存格式</param> /// <param name="flag">保存质量</param> /// <returns></returns> public bool SaveImage(Bitmap image, string save_path, ImageFormat format, int flag) { //以下代码为保存图片时,设置压缩质量 EncoderParameters ep = new EncoderParameters(); long [] qy = new long [1]; qy[0] = flag; //设置压缩的比例1-100 EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy); ep.Param[0] = eParam; try { ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders(); ImageCodecInfo jpegICIinfo = null ; for ( int x = 0; x < arrayICI.Length; x++) { if (arrayICI[x].FormatDescription.Equals( "JPEG" )) { jpegICIinfo = arrayICI[x]; break ; } } if (jpegICIinfo != null ) { image.Save(save_path, jpegICIinfo, ep); //dFile是压缩后的新路径 } else { image.Save(save_path, format); } return true ; } catch { return false ; } finally { image.Dispose(); } } /// <summary> /// 画图 /// </summary> /// <param name="source">原始图像</param> /// <param name="output">输出图像</param> /// <param name="souce_scale">原始图像的缩放值</param> /// <param name="souce_anchor"></param> /// <param name="graphics_anchor"></param> public void DrawImage(Image source, Bitmap output, float souce_scale, AnchorPoint souce_anchor, AnchorPoint graphics_anchor) { DrawImage(source, output, souce_scale, souce_anchor, new Point(( int )(output.Width * graphics_anchor.X), ( int )(output.Height * graphics_anchor.Y))); } /// <summary> /// 画图 /// </summary> /// <param name="source">原始图像</param> /// <param name="output">输出凸显</param> /// <param name="source_scale">图像的所放值</param> /// <param name="source_anchor">源图像锚点</param> /// <param name="souce_point">图像位置</param> public void DrawImage(Image source, Bitmap output, float source_scale, AnchorPoint source_anchor, Point souce_point) { var pic_po = new Point(( int )(souce_point.X - source.Size.Width * source_scale * source_anchor.X), ( int )(souce_point.Y - source.Size.Height * source_scale * source_anchor.Y)); DrawImage(source, output, new Rectangle(pic_po, new Size(( int )(source.Width * source_scale), ( int )(source.Height * source_scale)))); } /// <summary> /// 画图 /// </summary> /// <param name="source"></param> /// <param name="output"></param> /// <param name="rect"></param> public void DrawImage(Image source, Bitmap output, Rectangle rect) { Graphics g = Graphics.FromImage(output); g.Clear(Color.WhiteSmoke); g.CompositingQuality = CompositingQuality.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(source, rect, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel); g.Dispose(); } } } |
PS:为了美观本文中的原始图片并不是原始图片,因为原始图片太大了。会造成页面滑动,所以我上传了一张较小的图片。Git的图片则是原始的图片
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?