美文网首页Asp.net开发.NET.NET
Asp.Net DDD架构浅谈——图片上传、缩略裁剪

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

作者: Steven_7 | 来源:发表于2018-01-23 11:35 被阅读111次

本系列目录

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)
{
    <div class="row" id="row_upload_@btnId">
        <input type="hidden" name="@hdId" id="@hdId" value="@imgAttaId" />
        <div class="col-md-4">
            <span class="btn btn-success fileinput-button">
                <span>上传图片</span>
                <input type="file" accept="image/*" name="Filedata" id="@btnId">
            </span>
        </div>
        <div class="col-md-6">
            <div class="text-center">
                <span class="thumbnail">
                    <img id="@imgId" src="@wvp.Url.ThumbUrl(imgAttaId,width,height,"/Res/shop/img/img_icon.png")" width="@width" height="@height" alt="" />
                </span>
            </div>
            <div class="progress mt10" @(imgAttaId == 0 ? "" : "hidden")>
                <div style="width: 00%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" role="progressbar" class="progress-bar">
                </div>
            </div>
        </div>
    </div>
    <script>
        $(function () {
            var $row = $('#row_upload_@btnId');

            $('#@btnId').fileupload({
                url: '@wvp.Html.Raw(wvp.Url.Action("BatchUpload", "Attachment", new { src, width, height }))',
                dataType: 'json',
                add: function (e, data) {
                    //判断文件类型
                    var acceptFileTypes = /^image\/(gif|jpe?g|png)$/i;
                    //文件类型判断
                    if (data.files[0]['type'].length && !acceptFileTypes.test(data.files[0]['type'])) {
                        showErrorMsg('请上传图片!');
                        return;
                    }

                    $row.find('.progress-bar').css('width', '0%');
                    $row.find('.progress').show();
                    //预览
                    if (data.files && data.files[0]) {
                        var reader = new FileReader();
                        reader.onload = function (e) {
                            $('#@imgId').attr('src', e.target.result);
                        }
                        reader.readAsDataURL(data.files[0]);
                    }

                    data.submit();
                },
                progress: function (e, data) {
                    var progress = parseInt(data.loaded / data.total * 100, 10);
                    $row.find('.progress-bar').css('width', progress + '%');
                },
                done: function (e, data) {
                    var json = data.result;
                    $('#@imgId').attr('src', json.imgPath);
                    $('#@hdId').val(json.id);
                    $row.find('.progress').hide();
                }
            });
        });
    </script>
}

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


上传图片.gif

图片裁剪

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

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

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

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


    少年营.jpg

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


    少年营-500x500-Crop
    少年营-500x167-Fit
    少年营-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缓存中的,导致服务器的图片站点占用内存偏大。

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

        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架构浅谈——图片上传、缩略裁剪

    本文链接:https://www.haomeiwen.com/subject/djojaxtx.html