Asp.Net DDD架构浅谈——图片上传、缩略裁剪

本系列目录

Asp.Net DDD架构浅谈——整体框架说明
Asp.Net DDD架构浅谈——领域划分、仓储应用、Services层定义
Asp.Net DDD架构浅谈——图片上传、缩略裁剪
Asp.Net DDD架构浅谈——依赖注入Autofac
Asp.Net DDD架构浅谈——网站配置

任何一个网站都离不开图片上传、缩略裁剪,可以想到的场景就很多:

  • 用户头像
  • 文章封面图,富文本图片
  • 广告图片,幻灯片图片
    等等,能用到的实在是太多了,所以一个好的图片处理流程是很重要的,它适用于几乎所有的网站。

图片上传

图片上传的插件已经很成熟,能找到的就很多,比如说webuploaderuploadifyfileupload等。我们要对这些插件进行筛选,就要先确定我们的要求:

  • 支持Html5,支持移动端,因此不能是Flash。
  • 有上传进度回调函数,这样可以显示进度条,用户友好度提高。
  • 免费
    综合考虑,我在项目中选中了fileupload。看下项目中的代码:
@using System.Web.Mvc
@using Steven.Domain.Enums
@using Steven.Web.Framework.Extensions
@helper SingleUpload(WebViewPage wvp, TableSource src, string btnId, string imgId, string hdId, long imgAttaId = 0, int width = 100, int height = 100)
{
    
上传图片
}

在add函数里面,我们添加了预览,并且把进度条设为0.
在progress函数里面,我们实时更新上传进度。
在done函数里面,更新图片链接,以及附件的id值,并且隐藏进度条,看下实际效果:


Asp.Net DDD架构浅谈——图片上传、缩略裁剪_第1张图片
上传图片.gif

图片裁剪

在项目中,在UI设计师设计好的页面中,会对图片的大小尺寸有要求,而后台编辑人员上传图片的时候,不可能先按规定裁剪好再上传图片,这样会导致大量的工作量,所以裁剪的过程就需要程序来处理。稍微总结了下优点如下:

  • 图片统一尺寸,保持页面整齐。
  • 控制图片大小,图片太大时网页加载会很慢。

图片裁剪有很多种形式,最常用的是一下三种:

  • Crop,根据缩略图的尺寸截取原图
  • Fit,按比例缩放,自动调整尺寸
  • Pad,按比例缩放,保持尺寸,不足部分填白
    假设我们要上传一张图片,尺寸是1920x640的图片,如下图所示:


    Asp.Net DDD架构浅谈——图片上传、缩略裁剪_第2张图片
    少年营.jpg

    现在有一个业务是需要在前台展示500x500的图片,那么三种裁剪方式就不一样了,而具体要那种效果,需要和设计师讨论下。


    Asp.Net DDD架构浅谈——图片上传、缩略裁剪_第3张图片
    少年营-500x500-Crop

    Asp.Net DDD架构浅谈——图片上传、缩略裁剪_第4张图片
    少年营-500x167-Fit

    Asp.Net DDD架构浅谈——图片上传、缩略裁剪_第5张图片
    少年营-500x500-Pad

图片链接 & 生成缩略图时机

一开始我是这么处理的,把图片的物理路径做Base64处理,然后加上参数:裁剪方式,大小等,生成一个图片路劲,如:
http://img.hielites.com//Thumbnail/ZGVmYXVsdFwyMDE3XzA0XDE4XDE2MTYzMTMwNzU3NDM3LmpwZw2/Crop/1920x640
其中ZGVmYXVsdFwyMDE3XzA0XDE4XDE2MTYzMTMwNzU3NDM3LmpwZw2是图片路劲的Base64编码,Crop是裁剪方式,1920x640是缩略图的尺寸。
然后在用户打开网页,访问这个链接的时候,会判断,是否已经存在缩略图,如果不存在,则创建缩略图;如果已经存在,则返回图片,代码如下:

        [OutputCache(CacheProfile = "FileCache")]
        public ActionResult Thumb(string size, ThumbnailMethod mode, int q, string fn, WaterMarkingPosition? position)
        {
            Response.Cache.SetOmitVaryStar(true);
            //Base64解码
            var filePath = StringUtility.XBase64Decode(fn);
            var arrSize = size.ToLower().Split('x');
            var dirRoot = _attSvc.GetFullPath($@"thumb\{mode}-{size}-{position}");
            //拼接缩略图路径
            var filePathAbs = Path.Combine(dirRoot, filePath);
            var dirPath = Path.GetDirectoryName(filePathAbs);
            if (string.IsNullOrEmpty(dirPath))
            {
                return HttpNotFound("-File Not Found-");
            }
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }
            var fileExt = Path.GetExtension(filePathAbs);
            //判断缩略图片是否存在
            if (!System.IO.File.Exists(filePathAbs))
            {
                var iThumb = new ImgThumbUtillity()
                {
                    QualityLevel = q
                };
                var filePathSrc = _attSvc.GetFullPath(filePath);
                iThumb.MakeThumbnail(filePathSrc, filePathAbs, fileExt, StringUtility.ConvertToInt(arrSize[0]), StringUtility.ConvertToInt(arrSize[1]), mode, position, _configRep.WaterMarkingPath);
            }

            var fileContentType = _attSvc.GetFileContentType(fileExt);
            return File(filePathAbs, fileContentType);
        }

再用了一段时间后,发现会出一些问题:

  • 图片链接并不是以.jpg/.png等图片扩展名结尾的,对浏览器来说并不友好。
  • 用户访问时再去生成缩略图,第一个打开的用户会很慢。
  • 图片是放在OutputCache缓存中的,导致服务器的图片站点占用内存偏大。

为了解决这些问题,改进流程,做了如下处理

  • 先生成缩略图,再给链接,解决了第一个用户打开慢的问题。
  • 直接给静态图片路劲,解决了图片地址不以.jpg/.png结尾,以及图片站内存占用偏大的问题。
    改进后的图片路径变为http://www.beilinsoft.com/UploadFiles/Thumb/Crop_540x360/default/2017_09/6/1607471540151200.jpg
    其中,Crop表示裁剪方式,540x360表示缩略图尺寸。
    代码如下:
        public string GetPicUrl(long attaId, int width = 100, int height = 100, ThumMode mode = ThumMode.Crop, int quality = 100, WaterMarkingPosition? waterPosition = null)
        {
            var atta = AttachmentRepository.Get(attaId);
            if (atta == null)
            {
                return null;
            }
            //图片路径
            var thumbPath = Path.Combine(SysConfigRepository.UploadThumbDirectory,
                $"{mode}_{width}x{height}",
                atta.FilePath);
            var thumbFullPath = GetFullPath(thumbPath);
            //判断图片是否存在
            if (!File.Exists(thumbFullPath))
            {
                var originalFullPath = GetFullPath(atta.FilePath);
                if (!File.Exists(originalFullPath))
                {
                    return null;
                }
                using (var originalImage = new ImageFactory(true))
                {
                    ResizeMode resizeMode = GetRezieMode(mode);
                    var resizeLayer = new ResizeLayer(new Size(width, height), resizeMode);
                    originalImage.Load(originalFullPath)
                        .Resize(resizeLayer);
                    AddWatermark(waterPosition, originalImage);
                    originalImage.BackgroundColor(Color.White)
                        .Quality(quality)
                        .Save(thumbFullPath);
                }
            }


            return GetFileUrl(Path.Combine(SysConfigRepository.UploadRootDirectory, thumbPath));
        }

还有一个需要补充的是,需要在图片站创建一个虚拟目录,指向图片实际存储的地址:


Asp.Net DDD架构浅谈——图片上传、缩略裁剪_第6张图片
虚拟目录

Asp.Net DDD架构浅谈——图片上传、缩略裁剪_第7张图片
虚拟目录编辑

这样我们可以建立多个图片站,来分撒服务器压力。

你可能感兴趣的:(Asp.Net DDD架构浅谈——图片上传、缩略裁剪)