在進行圖片壓縮的時候。有時候會碰到要壓縮的圖片尺寸小於指定的壓縮尺寸,若直接壓縮會致使圖片失真。算法
固然。最好的方式是挑選合適尺寸圖片進行上傳。緩存
這裏給出的方法是:對不足尺寸部分進行空白填充。app
詳細參見下面代碼dom
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 ?ui
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 ?spa
".gif" : (extro == 2 ?code
".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 ""; } } } orm
調用實例:對象ImageDealLib.Resizepic( 480, 480, goodPicPath, thumbPath, CommonLib.ImageDealLib.ResizeType.X, CommonLib.ImageDealLib.ImageType.JPEG, CommonLib.ImageDealLib.FileCache.Save, out warning);