MVC 采用 HttpPostedFileBase 压缩保存图片
一、帮助类库
using System; using System.IO; namespace Utity.ImgHelper { /// <summary> /// Path utility functions<br/> /// 路径的工具函数<br/> /// </summary> public static class PathUtils { /// <summary> /// Secure path combining<br/> /// Throw exception if any part contains ".." or other invalid value<br/> /// 安全的合并路径<br/> /// 如果路径中有..或其他不合法的值则抛出例外<br/> /// </summary> /// <param name="paths">Path parts</param> /// <returns></returns> /// <example> /// <code language="cs"> /// PathUtils.SecureCombine("a", "b", "c") == Path.Combine("a", "b", "c") /// PathUtils.SecureCombine("a", "/b", "c") throws exception /// PathUtils.SecureCombine("a", "\\b", "c") throws exception /// PathUtils.SecureCombine("a", "", "c") throws exception /// PathUtils.SecureCombine("a", "..", "c") throws exception /// PathUtils.SecureCombine("a/../b", "c") throws exception /// </code> /// </example> public static string SecureCombine(params string[] paths) { for (var i = 0; i < paths.Length; ++i) { var path = paths[i]; if (i > 0 && path.StartsWith("/")) { throw new ArgumentException($"path startswith '/'"); } else if (path.StartsWith("\\")) { throw new ArgumentException($"path startswith '\'"); } else if (string.IsNullOrEmpty(path)) { throw new ArgumentException($"path {path} is null or empty"); } else if (path.Contains("..")) { throw new ArgumentException($"path {path} contains '..'"); } } return Path.Combine(paths); } /// <summary> /// Ensure parent directories are exist<br/> /// 确保路径的上级文件夹存在<br/> /// </summary> /// <param name="path">Path</param> /// <example> /// <code language="cs"> /// PathUtils.EnsureParentDirectory("c:\abc\123.txt"); /// // will create c:\abc if not exist /// </code> /// </example> public static void EnsureParentDirectory(string path) { var parentDirectory = Path.GetDirectoryName(path); if (!Directory.Exists(parentDirectory)) { Directory.CreateDirectory(parentDirectory); } } } }
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Linq; namespace Utity.ImgHelper { public static class ImageExtensions { /// <summary> /// Resize image /// </summary> /// <param name="image">Original image</param> /// <param name="width">Width</param> /// <param name="height">height</param> /// <param name="mode">Resize mode</param> /// <param name="background">Background default is transparent</param> /// <returns></returns> public static Image Resize(this Image image, int width, int height, ImageResizeMode mode, Color? background = null) { var src = new Rectangle(0, 0, image.Width, image.Height); var dst = new Rectangle(0, 0, width, height); // Calculate destination rectangle by resize mode if (mode == ImageResizeMode.Fixed) { } else if (mode == ImageResizeMode.ByWidth) { height = (int)((decimal)src.Height / src.Width * dst.Width); dst.Height = height; } else if (mode == ImageResizeMode.ByHeight) { width = (int)((decimal)src.Width / src.Height * dst.Height); dst.Width = width; } else if (mode == ImageResizeMode.Cut) { if ((decimal)src.Width / src.Height > (decimal)dst.Width / dst.Height) { src.Width = (int)((decimal)dst.Width / dst.Height * src.Height); src.X = (image.Width - src.Width) / 2; // Cut left and right } else { src.Height = (int)((decimal)dst.Height / dst.Width * src.Width); src.Y = (image.Height - src.Height) / 2; // Cut top and bottom } } else if (mode == ImageResizeMode.Padding) { if ((decimal)src.Width / src.Height > (decimal)dst.Width / dst.Height) { dst.Height = (int)((decimal)src.Height / src.Width * dst.Width); dst.Y = (height - dst.Height) / 2; // Padding left and right } else { dst.Width = (int)((decimal)src.Width / src.Height * dst.Height); dst.X = (width - dst.Width) / 2; // Padding top and bottom } } // Draw new image var newImage = new Bitmap(width, height); using (var graphics = Graphics.FromImage(newImage)) { // Set smoothing mode graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.SmoothingMode = SmoothingMode.HighQuality; // Set background color graphics.Clear(background ?? Color.Transparent); // Render original image with the calculated rectangle graphics.DrawImage(image, dst, src, GraphicsUnit.Pixel); } return newImage; } /// <summary> /// Save to jpeg with specified quality /// </summary> /// <param name="image">Image object</param> /// <param name="filename">File path, will automatic create parent directories</param> /// <param name="quality">Compress quality, 1~100</param> public static void SaveJpeg(this Image image, string filename, long quality) { PathUtils.EnsureParentDirectory(filename); var encoder = ImageCodecInfo.GetImageEncoders().First( c => c.FormatID == ImageFormat.Jpeg.Guid); var parameters = new EncoderParameters(); parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality); image.Save(filename, encoder, parameters); } /// <summary> /// Save to icon, see /// http://stackoverflow.com/questions/11434673/bitmap-save-to-save-an-icon-actually-saves-a-png /// </summary> /// <param name="image">Image object</param> /// <param name="filename">File path, will automatic create parent directories</param> public static void SaveIcon(this Image image, string filename) { PathUtils.EnsureParentDirectory(filename); using (var stream = new FileStream(filename, FileMode.Create)) { // Header (ico, 1 photo) stream.Write(new byte[] { 0, 0, 1, 0, 1, 0 }, 0, 6); // Size stream.WriteByte(checked((byte)image.Width)); stream.WriteByte(checked((byte)image.Height)); // No palette stream.WriteByte(0); // Reserved stream.WriteByte(0); // No color planes stream.Write(new byte[] { 0, 0 }, 0, 2); // 32 bpp stream.Write(new byte[] { 32, 0 }, 0, 2); // Image data length, set later stream.Write(new byte[] { 0, 0, 0, 0 }, 0, 4); // Image data offset, fixed 22 here stream.Write(new byte[] { 22, 0, 0, 0 }, 0, 4); // Write png data image.Save(stream, ImageFormat.Png); // Write image data length long imageSize = stream.Length - 22; stream.Seek(14, SeekOrigin.Begin); stream.WriteByte((byte)(imageSize)); stream.WriteByte((byte)(imageSize >> 8)); stream.WriteByte((byte)(imageSize >> 16)); stream.WriteByte((byte)(imageSize >> 24)); } } /// <summary> /// Save image by it's file extension /// Quality parameter only available for jpeg /// </summary> /// <param name="image">Image object</param> /// <param name="filename">File path, will automatic create parent directories</param> /// <param name="quality">Compress quality, 1~100</param> public static void SaveAuto(this Image image, string filename, long quality) { PathUtils.EnsureParentDirectory(filename); var extension = Path.GetExtension(filename).ToLower(); if (extension == ".jpg" || extension == ".jpeg") { image.SaveJpeg(filename, quality); } else if (extension == ".bmp") { image.Save(filename, ImageFormat.Bmp); } else if (extension == ".gif") { image.Save(filename, ImageFormat.Gif); } else if (extension == ".ico") { image.SaveIcon(filename); } else if (extension == ".png") { image.Save(filename, ImageFormat.Png); } else if (extension == ".tiff") { image.Save(filename, ImageFormat.Tiff); } else if (extension == ".exif") { image.Save(filename, ImageFormat.Exif); } else { throw new NotSupportedException( string.Format("unsupport image extension {0}", extension)); } } } /// <summary> /// Image resize mode /// </summary> public enum ImageResizeMode { /// <summary> /// Resize to the specified size, allow aspect ratio change /// </summary> Fixed, /// <summary> /// Resize to the specified width, height is calculated by the aspect ratio /// </summary> ByWidth, /// <summary> /// Resize to the specified height, width is calculated by the aspect ratio /// </summary> ByHeight, /// <summary> /// Resize to the specified size, keep aspect ratio and cut the overflow part /// </summary> Cut, /// <summary> /// Resize to the specified size, keep aspect ratio and padding the insufficient part /// </summary> Padding } }
using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace Utity.ImgHelper { /// <summary> /// 图片压缩类 /// </summary> public class ImageHttpPostedFileBase : HttpPostedFileBase { Stream stream; string contentType; string fileName; public int ImageQuality { get; set; } public Size ImageThumbnailSize { get; set; } public ImageResizeMode ImageResizeMode { get; set; } public ImageHttpPostedFileBase(Stream stream, string contentType, string fileName, Size imageThumbnailSize, int ImageQuality, ImageResizeMode imageResizeMode) { this.stream = stream; this.contentType = contentType; this.fileName = fileName; this.ImageQuality = ImageQuality; this.ImageThumbnailSize = imageThumbnailSize; this.ImageResizeMode = imageResizeMode; } public override int ContentLength { get { return (int)stream.Length; } } public override string ContentType { get { return contentType; } } public override string FileName { get { return fileName; } } public override Stream InputStream { get { return stream; } } public override void SaveAs(string filename) { var image = Image.FromStream(stream); using (var thumbnailImage = image.Resize(ImageThumbnailSize.Width, ImageThumbnailSize.Height, ImageResizeMode, Color.White)) thumbnailImage.SaveAuto(filename, ImageQuality); } } }
使用:
ImageHttpPostedFileBase fileBase = new ImageHttpPostedFileBase(formFile.InputStream, formFile.ContentType, formFile.FileName, new Size(240, 200), 90, ImageResizeMode.ByWidth); fileBase.SaveAs(sSavedPath);
例子:
/// <summary> /// 上传图片 /// </summary> /// <param name="formFile"></param> /// <returns></returns> [HttpPost] public JsonResult UpLoadImg(HttpPostedFileBase formFile) { var data = new MessageModel<string>(); if (formFile == null) { data.success = false; data.msg = "图片保存失败"; return Json(data); } string _path = "_FileUpLoad"; //文件名 var currentPictureWithoutExtension = Path.GetFileNameWithoutExtension(formFile.FileName); //扩展名 var currentPictureExtension = Path.GetExtension(formFile.FileName).ToUpper(); string savePath = Server.MapPath("~/" + _path) + "/" + DateTime.Now.ToString("yyyyMMdd") + "/"; if (LimitPictureType.Contains(currentPictureExtension)) { if (!Directory.Exists(savePath)) { Directory.CreateDirectory(savePath); } string _name = DateTime.Now.ToString("yyyyMMddHHmmss"); #region 保存缩略图 string sname = _name + "_thumb" + currentPictureExtension.ToLower(); string sSavedPath = savePath + sname; ImageHttpPostedFileBase fileBase = new ImageHttpPostedFileBase(formFile.InputStream, formFile.ContentType, formFile.FileName, new Size(240, 200), 90, ImageResizeMode.ByWidth); fileBase.SaveAs(sSavedPath); #endregion string name = _name + currentPictureExtension.ToLower(); string bSavePaht = savePath + name; formFile.SaveAs(bSavePaht); data.success = true; data.msg = "图片保存成功"; //返回路径 data.response = "/" + _path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + name; } else { data.success = false; data.msg = "图片保存失败"; } return Json(data); }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Model { /// <summary> /// 通用返回信息类 /// </summary> public class MessageModel<T> { /// <summary> /// 操作是否成功 /// </summary> public bool success { get; set; } = false; /// <summary> /// 返回信息 /// </summary> public string msg { get; set; } = "服务器异常"; /// <summary> /// 返回数据集合 /// </summary> public T response { get; set; } } }