图片压缩之处理小图片压缩策略
在进行图片压缩的时候。有时候会碰到要压缩的图片尺寸小于指定的压缩尺寸,若直接压缩会导致图片失真。
当然。最好的方式是挑选合适尺寸图片进行上传。
这里给出的方法是:对不足尺寸部分进行空白填充。
详细參见下面代码
using System; using System.Drawing.Drawing2D; using System.Drawing; using System.IO; using System.Drawing.Imaging; namespace CommonLib { public class ImageUtils { /// <summary> /// 创建缩略图像,缩略图是一个正方型的小图片 /// </summary> /// <param name="thumbnilWidth">缩略图的宽度</param> /// <param name="inputFileName">原始图像文件名称</param> /// <param name="outputFileName">输出的所略图文件名称</param> public static void Thumbnil(int thumbnilWidth, string inputFileName, string outputFileName) { Image src = Image.FromFile(inputFileName); Image pThumbnail = Thumbnil(thumbnilWidth, src); pThumbnail.Save(outputFileName); } public static void Thumbnil(int thumbnilWidth, string inputFileName, string outputFileName, ImageFormat format) { Image src = Image.FromFile(inputFileName); Image pThumbnail = Thumbnil(thumbnilWidth, src); SaveImage(outputFileName, format, pThumbnail, (long)98); } /// <summary> /// 创建缩略图像,缩略图是一个正方型的小图片 /// </summary> /// <param name="thumbnilWidth"></param> /// <param name="inputStream"></param> /// <param name="outputFileName"></param> /// <param name="format"></param> public static void Thumbnil(int thumbnilWidth, Stream inputStream, string outputFileName, ImageFormat format) { Image src = Image.FromStream(inputStream); Image pThumbnail = Thumbnil(thumbnilWidth, src); SaveImage(outputFileName, format, pThumbnail, (long)98); } /// <summary> /// 创建缩略图像,缩略图是一个正方型的小图片 /// </summary> /// <param name="thumbnilWidth"></param> /// <param name="inputStream"></param> /// <param name="outputFileName"></param> public static void Thumbnil(int thumbnilWidth, Stream inputStream, string outputFileName) { Image src = Image.FromStream(inputStream); Image pThumbnail = Thumbnil(thumbnilWidth, src); pThumbnail.Save(outputFileName); src.Dispose(); pThumbnail.Dispose(); } /// <summary> /// 缩略图 /// </summary> /// <param name="maxWidth">最大宽度</param> /// <param name="maxHeight">最大的高度</param> /// <param name="inputStream">图片流</param> /// <param name="outputFileName">输出路径</param> public static void Thumbnil(int maxWidth, int maxHeight, Stream inputStream, string outputFileName) { string fileDirectory = Path.GetDirectoryName(outputFileName); if (!Directory.Exists(fileDirectory)) { DirectoryInfo di = Directory.CreateDirectory(fileDirectory);//创建一个文件 } System.Drawing.Image img = System.Drawing.Image.FromStream(inputStream); if (img.Width > maxWidth || img.Height > maxHeight) { int pwidth = 0; if (img.Height / maxHeight > img.Width / maxWidth) { pwidth = Convert.ToInt16(((decimal)img.Width) * maxHeight / img.Height); } else { pwidth = maxWidth; } Thumbnil(pwidth, inputStream, outputFileName); } else { Thumbnil(img.Width, inputStream, outputFileName); } img.Dispose(); } public static void Thumbnil(int thumbnilWidth, Stream inputStream, Stream outputStream, ImageFormat format) { Image src = Image.FromStream(inputStream); Image pThumbnail = Thumbnil(thumbnilWidth, src); SaveImage(outputStream, format, pThumbnail, (long)98); } public static Image Thumbnil(int thumbnilWidth, Image src) { int width_heigh = src.Width; if (src.Height < src.Width) width_heigh = src.Height; RectangleF sourceRect = new RectangleF((src.Width - width_heigh) / 2, (src.Height - width_heigh) / 2, width_heigh, width_heigh); RectangleF destinationRect = new RectangleF(0, 0, thumbnilWidth, thumbnilWidth); Image pThumbnail = new Bitmap(thumbnilWidth, thumbnilWidth); Graphics g = Graphics.FromImage(pThumbnail); g.InterpolationMode = InterpolationMode.High; g.DrawImage(src, destinationRect, sourceRect, GraphicsUnit.Pixel); return pThumbnail; } private static void SaveImage(string outputFileName, ImageFormat format, Image image) { SaveImage(outputFileName, format, image, (long)95); } private static void SaveImage(string outputFileName, ImageFormat format, Image image, long qualityValue) { if (format == ImageFormat.Jpeg) { EncoderParameters ep = new EncoderParameters(); ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityValue); ImageCodecInfo ici = null; ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.MimeType == "image/jpeg") { ici = codec; break; } } if (ici != null) image.Save(outputFileName, ici, ep); else image.Save(outputFileName, format); } else image.Save(outputFileName, format); } private static void SaveImage(Stream outputStream, ImageFormat format, Image image) { SaveImage(outputStream, format, image, (long)95); } private static void SaveImage(Stream outputStream, ImageFormat format, Image image, long qualityValue) { if (format == ImageFormat.Jpeg) { EncoderParameters ep = new EncoderParameters(); ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityValue); ImageCodecInfo ici = null; ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.MimeType == "image/jpeg") { ici = codec; break; } } if (ici != null) image.Save(outputStream, ici, ep); else image.Save(outputStream, format); } else image.Save(outputStream, format); } /// <summary> /// 按图片原始比例创建缩略图像 /// </summary> public static void ScaleImage(int maxPixel, string inputFileName, string outputFileName, string waterMarkText, InterpolationMode interpolationMode, ImageFormat imageFormat) { Image src = Image.FromFile(inputFileName); int src_height = src.Height; int src_width = src.Width; int destW = maxPixel; int destH = maxPixel; double wh_Ratio = src_width * 1.0 / src_height * 1.0; if (src_height <= maxPixel && src_width <= maxPixel) { File.Copy(inputFileName, outputFileName); src.Dispose(); return; } else if (wh_Ratio <= 1) { destW = (int)Math.Round(destH * wh_Ratio); if (destW == 0) destW = 1; } else if (wh_Ratio > 1) { destH = (int)Math.Round(destW / wh_Ratio); if (destH == 0) destH = 1; } RectangleF sourceRect = new RectangleF(0, 0, src_width, src_height); RectangleF destinationRect = new RectangleF(0, 0, destW, destH); Image destImg = new Bitmap(destW, destH); Graphics g = Graphics.FromImage(destImg); if (interpolationMode == InterpolationMode.Bilinear) interpolationMode = InterpolationMode.High; g.InterpolationMode = interpolationMode; g.DrawImage(src, destinationRect, sourceRect, GraphicsUnit.Pixel); #region 增加水印的算法 //WaterMark(destImg, GetWaterMarkImage()); WaterMarkText(destImg, waterMarkText); #endregion long qulityValue = 95; if (destW < 200 || destH < 200) qulityValue = 98; //destImg.Save(outputFileName, imageFormat); SaveImage(outputFileName, imageFormat, destImg, qulityValue); destImg.Dispose(); src.Dispose(); g.Dispose(); return; } /// <summary> /// 按图片原始比例创建缩略图像 /// </summary> public static void ScaleImage(int maxPixel, Stream inputStream, string outputFileName, string waterMarkText, InterpolationMode interpolationMode, ImageFormat imageFormat) { Image src = Image.FromStream(inputStream); int src_height = src.Height; int src_width = src.Width; int destW = maxPixel; int destH = maxPixel; double wh_Ratio = src_width * 1.0 / src_height * 1.0; if (src_height <= maxPixel && src_width <= maxPixel) { src.Save(outputFileName, imageFormat); src.Dispose(); return; } else if (wh_Ratio <= 1) { destW = (int)Math.Round(destH * wh_Ratio); } else if (wh_Ratio > 1) { destH = (int)Math.Round(destW / wh_Ratio); } RectangleF sourceRect = new RectangleF(0, 0, src_width, src_height); RectangleF destinationRect = new RectangleF(0, 0, destW, destH); Image destImg = new Bitmap(destW, destH); Graphics g = Graphics.FromImage(destImg); if (interpolationMode == InterpolationMode.Bilinear) interpolationMode = InterpolationMode.High; g.InterpolationMode = interpolationMode; g.DrawImage(src, destinationRect, sourceRect, GraphicsUnit.Pixel); #region 增加水印的算法 //WaterMark(destImg, GetWaterMarkImage()); WaterMarkText(destImg, waterMarkText); #endregion //默认处理。大图片就减少一些画质 long qulityValue = 95; if (destW < 200 || destH < 200) qulityValue = 98; //destImg.Save(outputFileName, imageFormat); SaveImage(outputFileName, imageFormat, destImg, qulityValue); destImg.Dispose(); src.Dispose(); g.Dispose(); return; } /// <summary> /// 图片压缩 /// </summary> /// <param name="maxWidth">最大宽度</param> /// <param name="maxHeight">最大高度</param> /// <param name="inputStream">图片流</param> /// <param name="outputFileName">输出路径</param> /// <param name="waterMarkText">水印文字</param> /// <param name="interpolationMode">生成格式</param> /// <param name="imageFormat">图片格式化</param> public static void ScaleImage(int maxWidth, int maxHeight, Stream inputStream, string outputFileName, string waterMarkText, InterpolationMode interpolationMode, ImageFormat imageFormat) { string fileDirectory = Path.GetDirectoryName(outputFileName); if (!Directory.Exists(fileDirectory)) { DirectoryInfo di = Directory.CreateDirectory(fileDirectory);//创建一个文件 } System.Drawing.Image img = System.Drawing.Image.FromStream(inputStream); if (img.Width > 770 || img.Height > 560) { int pwidth = 0; if (img.Height / maxHeight > img.Width / maxWidth) { pwidth = Convert.ToInt16(((decimal)img.Width) * maxHeight / img.Height); } else { pwidth = maxWidth; } ScaleImage(pwidth, inputStream, outputFileName, waterMarkText, interpolationMode, imageFormat); } else { ScaleImage(img.Width, inputStream, outputFileName, waterMarkText, interpolationMode, imageFormat); } img.Dispose(); } public static void WaterMarkText(Image srcImg, string waterMarkText) { try { if (string.IsNullOrEmpty(waterMarkText)) return; if (srcImg.Width <= 100) return; int waterMarkWidth = srcImg.Width; int waterMarkHeight = 20; //px; WaterMarkText(srcImg, waterMarkText, 0, srcImg.Height - waterMarkHeight, waterMarkHeight, waterMarkWidth, new Font("微软雅黑", 12, GraphicsUnit.Pixel)); } catch { throw; } } public static void WaterMarkText(Image srcImg, string waterMarkText, int left, int top, int waterMarkHeight, int waterMarkWidth, Font font) { try { Graphics g = Graphics.FromImage(srcImg); Rectangle rect = new Rectangle(left, top, waterMarkWidth, waterMarkHeight); //画半透明确色底色 Brush brush = new SolidBrush(Color.FromArgb(99, Color.White)); g.FillRectangle(brush, rect); //画文字 rect.Width = rect.Width - 10; rect.Y = rect.Y + 2; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Far; g.DrawString(waterMarkText, font, Brushes.Black, rect, sf); //存盘 g.Save(); #region 释放此函数创建的GDI+资源 brush.Dispose(); font.Dispose(); sf.Dispose(); g.Dispose(); #endregion } catch { throw; } } private static void WaterMark(Image srcImg, Image waterMarkImage) { if (waterMarkImage == null) return; if (waterMarkImage.Width > (srcImg.Width - 20)) return; if (waterMarkImage.Height > (srcImg.Height - 20)) return; //水印在右下角。距离边6px位置 Rectangle rect = new Rectangle(0, 0, waterMarkImage.Width, waterMarkImage.Height); #region 生成一个暂时Image Image tempImage = new Bitmap(waterMarkImage.Width, waterMarkImage.Height); float[][] ptsArray ={ new float[] {1, 0, 0, 0, 0}, new float[] {0, 1, 0, 0, 0}, new float[] {0, 0, 1, 0, 0}, new float[] {0, 0, 0, 0.5f, 0}, //注意:此处为0.5f,图像为半透明 new float[] {0, 0, 0, 0, 1}}; ColorMatrix clrMatrix = new ColorMatrix(ptsArray); Graphics tempGraphics = Graphics.FromImage(tempImage); //将原图的要被水印覆盖的位置copy到暂时Image Rectangle srcRect = new Rectangle(srcImg.Width - waterMarkImage.Width - 6, srcImg.Height - waterMarkImage.Height - 6, waterMarkImage.Width, waterMarkImage.Height); tempGraphics.DrawImage(srcImg, rect, srcRect, GraphicsUnit.Pixel); ImageAttributes tempImgAttributes = new ImageAttributes(); tempImgAttributes.SetColorMatrix(clrMatrix, ColorMatrixFlag.SkipGrays, ColorAdjustType.Bitmap); //将水印图片贴到暂时区,跳过gray颜色。白色也是一种gray。将是透明色 tempGraphics.DrawImage(waterMarkImage, rect, 0, 0, waterMarkImage.Width, waterMarkImage.Height, GraphicsUnit.Pixel, tempImgAttributes); tempGraphics.Save(); #endregion #region 将暂时Image以透明贴图的方式绘至原图 ImageAttributes imgAttributes = new ImageAttributes(); imgAttributes.SetColorKey(Color.White, Color.White); //绘图像 Graphics g = Graphics.FromImage(srcImg); //srcRect 是原图要覆盖的区域,此时作为目标区域 g.DrawImage(tempImage, srcRect, 0, 0, tempImage.Width, tempImage.Height, GraphicsUnit.Pixel, imgAttributes); g.Save(); #endregion #region 释放此函数创建的资源 g.Dispose(); tempGraphics.Dispose(); tempImage.Dispose(); #endregion } private static Image waterMarkImage = null; public static Image GetWaterMarkImage() { return waterMarkImage; } public static void SetWaterMarkImage(Image image) { waterMarkImage = image; } } /// <summary> /// 图片处理:缩略图片 /// </summary> public class ImageDealLib { /// <summary> /// 图片保存类型 /// JPEG:.jpg格式; /// GIF:.gif格式; /// PNG:.png格式; /// </summary> public enum ImageType { JPEG, GIF, PNG } /// <summary> /// 水印模式 /// Center:中间; /// CenterUp:中上; /// CenterDown:中下; /// LeftUp:左上; /// LeftDown:左下; /// RightUp:右上; /// RightDown:右下; /// Random:随机; /// </summary> public enum WaterType { Center, CenterUp, CenterDown, LeftUp, LeftDown, RightUp, RightDown, Random } /// <summary> /// 缩略模式 /// X--按宽度缩放,高着宽比例; /// Y--按高度缩放,宽着宽比例; /// XY--按给定mwidth,mheight(此模式mwidth,mheight为必须值)进行缩略; /// </summary> public enum ResizeType { X, Y, XY } /// <summary> /// 文件检測模式 /// M:不检測文件是否存在,返回ServerMapPath; /// C:检測文件是否存在,返回ServerMapPath; /// </summary> public enum FileCheckModel { M, C } /// <summary> /// 原图文件是否保存 /// Delete:保存 /// Save:不保存,删除 /// </summary> public enum FileCache { Save, Delete } /// <summary> /// 依据指定:缩略宽、高,缩略图片并保存 /// 返回图片虚拟路径,和一个警告信息,可依据此信息获取图片合成信息 /// </summary> /// <param name="picpath">原图路径</param> /// <param name="model">缩略模式[X,Y,XY](默认XY模式)</param> /// <param name="spath">文件保存路径(默认跟路径)</param> /// <param name="imgtype">图片保存类型</param> /// <param name="mwidth">缩略宽度(默认原图高度)</param> /// <param name="mheight">缩略高度(默认原图高度)</param> /// <param name="filecache">原文件处理方式</param> /// <param name="warning">处理警告信息</param> /// <returns>错误,返回错误信息;成功,返回图片路径</returns> public static string Resizepic(double? mwidth, double?
mheight, string picpath, string spath, ResizeType model, ImageType imgtype, FileCache filecache, out string warning) { //反馈信息 System.Text.StringBuilder checkmessage = new System.Text.StringBuilder(); //原图路径 if (string.IsNullOrWhiteSpace(picpath)) { checkmessage.Append("请输入原图路径。"); warning = checkmessage.ToString().TrimEnd(';'); return string.Empty; } //文件保存路径 if (string.IsNullOrWhiteSpace(spath)) { checkmessage.Append("请输入保存路径。"); warning = checkmessage.ToString().TrimEnd(';'); return string.Empty; } else { string fileDirectory = Path.GetDirectoryName(spath); if (!Directory.Exists(fileDirectory)) { DirectoryInfo di = Directory.CreateDirectory(fileDirectory);//创建一个文件 } } //缩略宽度 double swidth = mwidth.HasValue ?
double.Parse(mwidth.ToString()) : 0; //缩略高度 double sheight = mheight.HasValue ? double.Parse(mheight.ToString()) : 0; //从指定源图片,创建image对象 string _sourceimg_common_mappath = ""; //检測源文件 bool checkfile = false; checkfile = System.IO.File.Exists(picpath);//FileExistMapPath(picpath, FileCheckModel.C, out _sourceimg_common_mappath); System.Drawing.Image _sourceimg_common = null; System.Drawing.Bitmap _currimg_common = null; System.Drawing.Graphics _g_common = null; if (checkfile) { //从源文件创建imgage _sourceimg_common = System.Drawing.Image.FromFile(picpath); #region 缩略模式 //缩略模式 switch (model) { case ResizeType.X: #region X模式 //依据给定尺寸,获取绘制比例 double _width_scale = swidth / _sourceimg_common.Width; //高着比例 sheight = _sourceimg_common.Height * _width_scale; #endregion ; break; case ResizeType.Y: #region Y模式 //依据给定尺寸,获取绘制比例 double _height_scale = sheight / _sourceimg_common.Height; //宽着比例 swidth = _sourceimg_common.Width * _height_scale; #endregion ; break; case ResizeType.XY: #region XY模式 //当选择XY模式时,mwidth,mheight为必须值 if (swidth < 0 || sheight < 0) { checkmessage.Append("error:XY模式,mwidth,mheight为必须值;"); } #endregion ; break; default: #region 默认XY模式 //当默认XY模式时,mwidth,mheight为必须值 if (swidth < 0 || sheight < 0) { checkmessage.Append("error:你当前未选择缩略模式,系统默认XY模式,mwidth,mheight为必须值;"); } ; break; #endregion } #endregion } else { checkmessage.Append("error:未能找到缩略原图片," + picpath + ";"); } if (string.IsNullOrEmpty(checkmessage.ToString())) { //创建bitmap对象 _currimg_common = new System.Drawing.Bitmap((int)swidth, (int)sheight); _g_common = Graphics.FromImage(_currimg_common); //画半透明确色底色 Brush brush = new SolidBrush(Color.FromArgb(99, Color.White)); _g_common.FillRectangle(brush, 0, 0, (float)swidth, (float)sheight); //设置画笔 _g_common.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver; _g_common.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; _g_common.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; int left = Math.Max(0, ((int)swidth - _sourceimg_common.Width) / 2);//图片左距离 int top = Math.Max(0, ((int)sheight - _sourceimg_common.Height) / 2);//图片上距离 int des_width = (int)swidth; int des_height = (int)sheight; int s_width = _sourceimg_common.Width; int s_height = _sourceimg_common.Height; if (des_width < s_width) { des_width = s_width; } if (des_height < s_height) { des_height = s_height; } //绘制图片 _g_common.DrawImage(_sourceimg_common, new Rectangle(left, top, Math.Min(_sourceimg_common.Width, (int)swidth), Math.Min(_sourceimg_common.Height, (int)sheight)), new Rectangle(0, 0, _sourceimg_common.Width, _sourceimg_common.Height), GraphicsUnit.Pixel); //保存图片 string _spath_common_mappath = ""; //获取图片类型的hashcode值,生成图片后缀名 int extro = imgtype.GetHashCode(); string extend = extro == 0 ? ".jpg" : (extro == 1 ?
".gif" : (extro == 2 ?
".png" : ".jpg")); //全局文件名称 // spath = spath + Guid.NewGuid().ToString() + extend; // FileExistMapPath(spath, FileCheckModel.M, out _spath_common_mappath); switch (imgtype) { case ImageType.JPEG: _currimg_common.Save(spath, System.Drawing.Imaging.ImageFormat.Jpeg); break; case ImageType.GIF: _currimg_common.Save(spath, System.Drawing.Imaging.ImageFormat.Gif); break; case ImageType.PNG: _currimg_common.Save(spath, System.Drawing.Imaging.ImageFormat.Png); break; } //释放 _sourceimg_common.Dispose(); _currimg_common.Dispose(); _g_common.Dispose(); //处理原文件 int filecachecode = filecache.GetHashCode(); //文件缓存方式:Delete,删除原文件 if (filecachecode == 1) { System.IO.File.Delete(picpath); } //返回相对虚拟路径 warning = ""; return spath; } //释放 if (_sourceimg_common != null) { _sourceimg_common.Dispose(); } if (_currimg_common != null) { _currimg_common.Dispose(); } if (_g_common != null) { _g_common.Dispose(); } warning = checkmessage.ToString().TrimEnd(';'); return ""; } } }
调用实例:ImageDealLib.Resizepic( 480, 480, goodPicPath, thumbPath, CommonLib.ImageDealLib.ResizeType.X, CommonLib.ImageDealLib.ImageType.JPEG, CommonLib.ImageDealLib.FileCache.Save, out warning);