基于WebImage的图片上传工具类

支持缩略图和水印。

using System;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Helpers;

namespace HZC.Util.Mvc
{
    public class MvcImageUploader
    {
        #region 字段
        private string[] _imageExts = new string[] { "jpg", "jpeg", "png", "gif", "bmp" };  // 允许上传的图片类型
        private string _basePath;
        private string _baseLocalPath;
        private int _fileLimitSize;
        #endregion

        #region 构造函数
        /// <summary>
        /// MVC图片上传工具
        /// </summary>
        public MvcImageUploader() : this(1024 * 1024 * 2, "/Upload/Pics")
        { }

        /// <summary>
        /// MVC图片上传工具
        /// </summary>
        /// <param name="fileLimitSize">图片最大限制</param>
        public MvcImageUploader(int fileLimitSize) : this(fileLimitSize, "/Upload/Pics")
        { }

        /// <summary>
        /// MVC图片上传工具
        /// </summary>
        /// <param name="fileLimitSize">图片最大限制,默认2M</param>
        /// <param name="basePath">图片上传路径,默认为 ~/Upload/Pics </param>
        public MvcImageUploader(int fileLimitSize, string basePath)
        {
            _basePath = basePath;
            _fileLimitSize = fileLimitSize;
            _baseLocalPath = GetServerPath(_basePath);
        }
        #endregion

        #region 上传
        public ImgUploadResult UploadImage(WebImage image, bool isThumb = true, bool isWater = false, 
            ThumbOption thumbOption = null, WaterOption waterOption = null)
        {
            if (image == null)
            {
                return new ImgUploadResult {
                    Code = ImgUploadResultCode.文件不存在,
                    Message = "请求中未检测到文件"
                };
            }
            else
            {
                try
                {
                    string extName = Path.GetExtension(image.FileName).ToLower();
                    int size = image.GetBytes().Length;
                    int width = image.Width;
                    int height = image.Height;

                    // 验证文件类型
                    if (!ValidFileSize(size))
                    {
                        return new ImgUploadResult
                        {
                            Code = ImgUploadResultCode.文件大小超出限制,
                            Message = "文件大小超出限制"
                        };
                    }

                    // 验证文件大小
                    if (!ValidExtName(extName))
                    {
                        return new ImgUploadResult
                        {
                            Code = ImgUploadResultCode.不受支持的文件类型,
                            Message = "不受支持的文件类型"
                        };
                    }

                    var result = new ImgUploadResult();

                    // 图片位置相关
                    var folderName = GetImageUploadFolder();                                // 图片文件夹名称
                    var newFileName = GetNewFileName(extName);                              // 随机生成的图片名称
                    var newFolderPath = Path.Combine(_baseLocalPath, folderName);           // 图片文件夹在服务器上的物理路径
                    var newFilePath = Path.Combine(newFolderPath, newFileName);             // 图片在服务器上保存的物理路径
                    var thumbFilePath = Path.Combine(_baseLocalPath,                        // 缩略图在服务器上保存的物理路径
                        folderName, "Thumbs", newFileName);

                    if (!Directory.Exists(newFolderPath))                                   // 校验|创建图片文件夹
                    {
                        Directory.CreateDirectory(newFolderPath);
                        Directory.CreateDirectory(Path.Combine(newFolderPath, "Thumbs"));
                    }

                    // 获取水印
                    if (isWater)
                    {
                        if (waterOption != null)
                        {
                            if (waterOption.Type == WaterType.图片)
                            {
                                // 图片水印
                                if (!string.IsNullOrWhiteSpace(waterOption.Content))
                                {
                                    var path = GetServerPath(waterOption.Content);
                                    if (File.Exists(path))
                                    {
                                        WebImage img = new WebImage(path);
                                        int w = waterOption.Width > 0 ? waterOption.Width : img.Width;
                                        // int h = waterOption.Height > 0 ? waterOption.Height : img.Height;
                                        var h = waterOption.Height;
                                        if (h == 0)
                                        {
                                            h = img.Height * w / img.Width;
                                        }

                                        image.AddImageWatermark(img, w, h, 
                                            waterOption.HorizontalPostion, waterOption.VerticalPostion, 
                                            waterOption.Opacity, waterOption.Padding);
                                    }                                    
                                }
                            }
                            else
                            {
                                // 文字水印
                                if (!string.IsNullOrWhiteSpace(waterOption.Content))
                                {

                                    image.AddTextWatermark(waterOption.Content, waterOption.FontColor, waterOption.FontSize, waterOption.FontStyle,
                                        waterOption.FontFamily, waterOption.HorizontalPostion, waterOption.VerticalPostion,
                                        waterOption.Opacity, waterOption.Padding);
                                }
                            }
                        }
                    }

                    image.Save(newFilePath);                                                 // 保存文件

                    result.Code = ImgUploadResultCode.上传成功;
                    result.Message = "";
                    result.ImageUrl = _basePath + "/" + folderName + "/" + newFileName;
                    result.ThumbUrl = "";
                    result.Size = size;
                    result.Width = width;
                    result.Height = height;
                    result.Ext = extName;

                    // 缩略图
                    if (isThumb)
                    {
                        var thumb = MakeThumb(image, thumbOption);
                        thumb.Save(thumbFilePath);
                        result.ThumbUrl = _basePath + "/" + folderName + "/Thumbs/" + newFileName;
                    }

                    return result;
                }
                catch (Exception ex)
                {
                    SimpleLog.WriteErrorLogAsyn("UploaderController.Image", ex.Message + ":" + ex.StackTrace);
                    return new ImgUploadResult
                    {
                        Code = ImgUploadResultCode.系统异常,
                        Message = ex.Message + "" + ex.StackTrace,
                        Size = 0,
                        Ext = "",
                        ImageUrl = "",
                        ThumbUrl = "",
                        Width = 0,
                        Height = 0
                    };
                }
            }
        }
        #endregion

        #region 生成缩略图
        private WebImage MakeThumb(WebImage source, ThumbOption option = null)
        {
            if (option == null)
            {
                option = new ThumbOption();
            }

            WebImage thumb;
            if (option.IsCrop)
            {
                if (source.Width <= option.Width || source.Height <= option.Height)
                {
                    thumb = source.Resize(option.Width, option.Height, true, true);
                }
                else
                {
                    var wScale = source.Width / option.Width;
                    var hScale = source.Height / option.Height;
                    
                    var direct = 0;     // 0:横向;1:纵向

                    var thumbWidth = 0;
                    var thumbHeight = 0;

                    if (wScale >= hScale)
                    {
                        direct = 0;
                        thumbHeight = option.Height + 2;
                        thumbWidth = option.Height * source.Width / source.Height;
                    }
                    else
                    {
                        direct = 1;
                        thumbWidth = option.Width + 2;
                        thumbHeight = option.Width * source.Height / source.Width;
                    }

                    thumb = source.Resize(thumbWidth, thumbHeight, false, false);

                    if (direct == 0)
                    {
                        var py = (thumbWidth - option.Width) / 2;
                        thumb = thumb.Crop(1, py, 1, py);
                    }
                    else
                    {
                        var py = (thumbHeight - option.Height) / 2;
                        thumb = thumb.Crop(py, 1, py, 1);
                    }
                }
            }
            else
            {
                thumb = source.Resize(option.Width, option.Height, true, true);
            }
            return thumb;
        }
        #endregion

        #region 获取图片的上传文件夹
        private string GetImageUploadFolder()
        {
            string folderName = DateTime.Today.ToString("yyyyMM");
            return folderName;
        }
        #endregion

        #region 获取文件上传后的文件名称
        private string GetNewFileName(string ext)
        {
            string fileName = Path.GetRandomFileName();
            return fileName + "." + ext;
        }
        #endregion

        #region 验证文件扩展名
        private bool ValidExtName(string ext)
        {
            return _imageExts.Contains(ext);
        }
        #endregion

        #region 验证文件大小
        private bool ValidFileSize(int size)
        {
            return size <= _fileLimitSize;
        }
        #endregion

        #region 获取指定路径在服务器上的位置
        private string GetServerPath(string url)
        {
            url = url.ToLower();
            if (url.StartsWith("http://") || url.StartsWith("https://"))
            {
                return url;
            }
            else if (HttpContext.Current != null)
            {
                return HttpContext.Current.Server.MapPath(url);
            }
            else
            {
                return string.Empty;
            }
        }
        #endregion
    }

    /// <summary>
    /// 图片上传结果
    /// </summary>
    public class ImgUploadResult
    {
        /// <summary>
        /// 结果码
        /// </summary>
        public ImgUploadResultCode Code { get; set; }

        /// <summary>
        /// 消息
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// 图片上传成功后的相对路径,如:/Upload/Pic/...
        /// </summary>
        public string ImageUrl { get; set; }

        /// <summary>
        /// 缩略图的相对路径
        /// </summary>
        public string ThumbUrl { get; set; }

        /// <summary>
        /// 图片的扩展名
        /// </summary>
        public string Ext { get; set; }

        /// <summary>
        /// 图片的大小
        /// </summary>
        public int Size { get; set; }

        /// <summary>
        /// 图片的宽度
        /// </summary>
        public int Width { get; set; }

        /// <summary>
        /// 图片的高度
        /// </summary>
        public int Height { get; set; }
    }

    /// <summary>
    /// 缩略图配置选项
    /// </summary>
    public class ThumbOption
    {
        /// <summary>
        /// 缩略图宽度
        /// </summary>
        public int Width { get; set; } = 180;

        /// <summary>
        /// 缩略图高度
        /// </summary>
        public int Height { get; set; } = 180;

        /// <summary>
        /// 是否保持图片的宽高比
        /// </summary>
        public bool IsPreserveAspectRatio { get; set; } = true;

        /// <summary>
        /// 是否阻止放大图片
        /// </summary>
        public bool IsPreventEnlarge { get; set; } = true;

        /// <summary>
        /// 是否裁剪图片,
        /// 如果裁剪,图片短边适应缩略图尺寸,自动缩放长边,并根据缩略图尺寸从中心裁剪长边
        /// 如果裁剪,图片长边适应缩略图尺寸,短边按比例缩放
        /// </summary>
        public bool IsCrop { get; set; } = false;
    }

    /// <summary>
    /// 水印配置选项
    /// </summary>
    public class WaterOption
    {
        /// <summary>
        /// 水印类型,图片|文字
        /// </summary>
        public WaterType Type { get; set; }

        /// <summary>
        /// 水印内容,
        /// 类型为图片时,传入水印图片相对根目录的路径,如:/Upload/Pics/201801/xxx.jpg
        /// 类型为文字时,传入水印的文字
        /// </summary>
        public string Content { get; set; }

        /// <summary>
        /// 水印的水平位置,
        /// 可选为 Left|Center|Right
        /// </summary>
        public string HorizontalPostion { get; set; } = "Right";

        /// <summary>
        /// 水印的垂直位置,
        /// 可选为 Top|Middle|Bottom
        /// </summary>
        public string VerticalPostion { get; set; } = "Bottom";

        /// <summary>
        /// 水印图片的宽度,仅当水印类型为图片时有效
        /// </summary>
        public int Width { get; set; } = 0;

        /// <summary>
        /// 水印图片的高度,仅当水印类型为图片时有效
        /// </summary>
        public int Height { get; set; } = 0;

        /// <summary>
        /// 水印的透明度,100为完全不透明,0为完全透明
        /// </summary>
        public int Opacity { get; set; } = 50;

        /// <summary>
        /// 边距大小
        /// </summary>
        public int Padding { get; set; } = 5;

        /// <summary>
        /// 水印文本的字体,仅当水印类型为文本时有效
        /// 注意,若指定字体在服务器上不存在,会抛出报错
        /// </summary>
        public string FontFamily { get; set; } = "Microsoft Sans Serif";

        /// <summary>
        /// 水印文本的样式,仅当水印类型为文本时有效
        /// 可选项目 Regular|Bold|Italic|Strikeout|Underline
        /// </summary>
        public string FontStyle { get; set; } = "Regular";

        /// <summary>
        /// 水印文本的文字大小,仅当水印类型为文本时有效
        /// </summary>
        public int FontSize { get; set; } = 12;

        /// <summary>
        /// 水印文本的文字颜色,仅当水印类型为文本时有效
        /// 赋值类似于 "White"、"Black" 或 "DarkBlue",或 "#RRGGBB" 或 "#RGB" 形式的十六进制值
        /// </summary>
        public string FontColor { get; set; } = "Black";
    }

    /// <summary>
    /// 图片上传结果码的枚举
    /// </summary>
    public enum ImgUploadResultCode
    {
        不受支持的文件类型 = 511,
        文件大小超出限制 = 512,
        文件不存在 = 514,
        系统异常 = 500,
        上传成功 = 200
    }

    /// <summary>
    /// 水印类型的枚举
    /// </summary>
    public enum WaterType
    {
        文字 = 1,
        图片 = 2
    }
}
View Code

 

上面是工具的代码,调用例子如下:

 1 [HttpPost]
 2         public JsonResult ImageUpload()
 3         {
 4             if (HttpContext.Request.RequestType == "GET")
 5             {
 6                 return Json(new ImgUploadResult { Code = ImgUploadResultCode.文件不存在 });
 7             }
 8 
 9             ImgUploadResult result;
10             WebImage image = WebImage.GetImageFromRequest("");
11             if (image == null)
12             {
13                 return Json(new ImgUploadResult { Code = ImgUploadResultCode.文件不存在 });
14             }
15 
16             MvcImageUploader uploader = new MvcImageUploader();
17 
18             // 文字水印
19             result = uploader.UploadImage(image, true, true,
20                 new ThumbOption { IsCrop = true },
21                 new WaterOption
22                 {
23                     Content = "这是文字水印",
24                     FontFamily = "微软雅黑",
25                     FontSize = 18,
26                     FontColor = "#FF0000",
27                     Padding = 30,
28                     HorizontalPostion = "Center",
29                     VerticalPostion = "Middle",
30                     Opacity = 80
31                 });
32 
33             // 图片水印
34             //result = uploader.UploadImage(image, true, true,
35             //    new ThumbOption { IsCrop = true },
36             //    new WaterOption
37             //    {
38             //        Type = WaterType.图片,
39             //        Content = "/Upload/Pics/201801/cctv1.jpg",
40             //        HorizontalPostion = "Center",
41             //        VerticalPostion = "Middle",
42             //        Width = 150
43             //    });
44             return Json(result);
45         }

 

posted @ 2018-01-10 22:04 没追求的码农 阅读(...) 评论(...) 编辑 收藏