MVC4实现图片上传,裁剪和保存到服务器

PassPhotoController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PassPhotoMVC.Helpers;
using System.Collections;

namespace PhotoDemo.Controllers
{
    public class PassPhotoController : Controller
    {
        //初始化辅助类库和局部变量
        PhotoUtils myUtils = new PhotoUtils();
        //允许上传的最大文件大小
        int maxSize = Convert.ToInt32(Settings.AppSettings.maxuploadsize);
        // all images are normalized to this height when uploaded
        //所有图像在上传时均标准化为此高度
        //它们被放大或缩小
        int hminRaw = Convert.ToInt32(Settings.AppSettings.uploadheight);

        //最终剪裁图像的所需尺寸(w,h)
        int hminCropped = Convert.ToInt32(Settings.AppSettings.passheight);
        int wminCropped = Convert.ToInt32(Settings.AppSettings.passwidth);
        int imgUploadPreview = Convert.ToInt32(Settings.AppSettings.uploadpreviewh);
        int prevw = Convert.ToInt32(Settings.AppSettings.previewwidth);
        int prevh = Convert.ToInt32(Settings.AppSettings.previewheight);

        /// <summary>
        /// 确定默认视图的参数
        /// </summary>
        /// <param name="jsfilepath">只需要覆盖预设值</param>
        /// <returns></returns>
        public ActionResult Index(String jsFilePath="")
        {            

            String RootPath = Request.Path;
            ViewBag.RootPath = RootPath;
            ViewBag.Height = prevh.ToString();
            ViewBag.Width = prevw.ToString();
            ViewBag.PreviewJSMarkup = myUtils.UpdatePreviewJs(prevw, prevh, jsFilePath);            

            return View();
        }

        /// <summary>
        ///如果最终用户尝试使用GET而不是POST调用此操作,则重定向以启动UI的界面
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult UploadImage()
        {
            return RedirectToAction("Index");
        }

        /// <summary>
        /// 处理上传文件并将上传的文件大小调整为标准大小
        /// </summary>
        /// <param name="mypostedfile"></param>
        /// <param name="targetfilename"></param>
        /// <param name="targetfolder"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult UploadImage(HttpPostedFileBase myPostedFile, String targetFilename, String targetFolder = "raw", String srcimgfolder = "", String jsFilePath = "")
        {
            // This value is sent back to the view to accomodate relative URLs when in post action
            //在POST action时,此值将发回到视图以适应相关URL
            String rootPath = Request.Path.Replace("PassPhoto/UploadImage", "");
            ViewBag.RootPath = rootPath;
            if (myPostedFile != null && myPostedFile.ContentLength > 0) 
            {
                //img文件夹的默认值取自当前服务器上下文,除非在输入参数中另有说明
                if (srcimgfolder == "")
                {
                    srcimgfolder = Server.MapPath("~/uploaded_images/" + targetFolder + "/");
                }
                else
                {
                    if (!srcimgfolder.EndsWith("\\"))
                    {
                        srcimgfolder += "\\";
                    }
                    srcimgfolder += targetFolder;
                }
                // preset name of file while testing refactor after tested
                //测试后重新测试的文件的预设名称
                targetFilename = "image_upload_test.jpg";
                ViewBag.Message = myUtils.UploadImage(myPostedFile, targetFilename, srcimgfolder, maxSize, hminRaw);
                if (ViewBag.Message == "OK: File uploaded!")
                {
                    //返回修改UI必需的值
                    ViewBag.ImageName = targetFilename;
                    ViewBag.ImageUrl = "uploaded_images/" + targetFolder + "/" + targetFilename;
                    ViewBag.Height = imgUploadPreview.ToString();
                    ViewBag.Width = myUtils.CalculateResizedWidth(targetFilename, srcimgfolder, imgUploadPreview).ToString();
                    ViewBag.PreviewDisplay = "normal";
                    int jsWidth = myUtils.CalculateResizedWidth(targetFilename, srcimgfolder, hminRaw);
                    ViewBag.PreviewJSMarkup = myUtils.UpdatePreviewJs(jsWidth, hminRaw, jsFilePath);
                }
                else
                {
                    //返回默认值并显示操作结果的错误信息
                    ViewBag.ImageName = targetFilename;
                    ViewBag.Height = prevh.ToString();
                    ViewBag.Width = prevw.ToString();
                }
            }
            else
            {
                ViewBag.Message = "错误 - 文件无效 - 上传的文件为空.";
            }
            return View("Index");              
        }

        /// <summary>
        /// 如果最终用户尝试使用GET而不是POST调用此操作,则重定向以启动UI的界面。
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult CropImage()
        {
            return RedirectToAction("Index");
        }

        /// <summary>
        /// 处理剪裁文件,保持纵横比和标准尺寸
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="folder"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        /// <param name="W"></param>
        /// <param name="H"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult CropImage(String filename, String folder, String X, String Y, String W, String H, String srcimgfolder = "", String jsFilePath = "")
        {
            String rootPath = Request.Path.Replace("PassPhoto/CropImage", "");
            ViewBag.RootPath = rootPath;
            String missingpar = "";
            //validate required post parameters and return proper error message is something is missing
            //验证必需的post参数并返回缺少参数的合适的错误消息
            if (filename == null )
            {
                missingpar = "filename";
            }
            if (folder == null)
            {
                if (missingpar != "")
                {
                    missingpar += ", ";
                }
                missingpar = "folder";
            }            
            if (missingpar.Length >0)
            {
                String ermsg1 = "Error - missing parameter";
                if (missingpar.Contains(","))
                {
                    ermsg1 += "s";
                }
                ViewBag.Message = ermsg1 + ": " + missingpar;
            }
            else
            {
                // 将post的值转换为int
                int W1 = Convert.ToInt32(W);
                int H1 = Convert.ToInt32(H);
                int X1 = Convert.ToInt32(X);
                int Y1 = Convert.ToInt32(Y);

                //srcimagefolder的默认值将在运行时从服务器上下文确定
                if (srcimgfolder == "")
                {
                    srcimgfolder = Server.MapPath("~/uploaded_images/");
                }
                else
                {
                    if (!srcimgfolder.EndsWith("\\"))
                    {
                        srcimgfolder += "\\";
                    }                   
                }
                String targetfolder = "cropped";
                ViewBag.Message = myUtils.CropImage(filename, folder, targetfolder, srcimgfolder, X1, Y1, W1, H1);
                if (ViewBag.Message == "OK - 文件裁剪完成了")
                {    
                    ViewBag.Height = imgUploadPreview.ToString();
                    ViewBag.Width = myUtils.CalculateResizedWidth(filename, srcimgfolder + targetfolder, imgUploadPreview).ToString();
                    ViewBag.ImageName = filename;
                    ViewBag.PreviewDisplay = "normal";                    
                    ViewBag.ImageUrl = "uploaded_images/cropped/" + filename;
                    ViewBag.PreviewJSMarkup = myUtils.UpdatePreviewJs(wminCropped, hminCropped, jsFilePath);
                }
            }           
            return View("Index");            
        }

    }
}

PhotoUtils.cs

using System;
using System.Web;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace PhotoDemo.Helpers
{
    /// <summary>
    /// 处理上传图像的功能(调整大小/裁剪)
    /// </summary>
    /// 

    public class PhotoUtils
    {

        /// <summary>
        /// Handle uploading of images, calls resizing for creating standard size images
        /// based on AppSettings parameters
        /// 处理图像的上传,根据AppSettings参数调用,调整大小以创建标准尺寸图像
        /// </summary>
        /// <param name="postedfile"></param>
        /// <param name="targetfilename"></param>
        /// <param name="folder"></param>
        /// <param name="maxsize"></param>
        /// <param name="hmindimension"></param>
        /// <returns></returns>
        public String UploadImage(HttpPostedFileBase postedfile, String targetfilename, String folder, int maxsize = 262144, int hmindimension = 0)
        {
            String result = "";
            // 如果hmindimension=0,则使用默认设置
            if (hmindimension == 0)
            {
                hmindimension = Convert.ToInt32(Settings.AppSettings.uploadheight);
            }                     
            Boolean fileOK = false;
            int fileSize = postedfile.ContentLength;            
            String maxk = ((int)((double)maxsize / 1024)).ToString();
            if  (fileSize > 0 & targetfilename.Length > 0)
            {
                String fileExtension = System.IO.Path.GetExtension(postedfile.FileName).ToLower();
                String[] allowedExtensions = { ".jpg", ".jpeg" };
                for (int i = 0; i <= allowedExtensions.Length - 1; i++)
                {
                    if (allowedExtensions[i].Equals(fileExtension))
                    {
                        fileOK = true;
                    }
                }
                if (fileOK)
                {
                    if (fileSize < maxsize)
                    {
                        try
                        {
                            result = ResizeImageUpload(postedfile.InputStream, targetfilename, folder, hmindimension);
                        }
                        catch(Exception ex)
                        {
                            result = "错误:无法上传文件<br>" + ex.Message;
                        }
                    }
                    else
                    {
                       result = "错误:文件大于 " + maxk + "K.请上传较小的图像";
                    }
                }
                else
                {
                    result = "错误:无法接受此类型的文件.";
                }
            }
            else
            {
                result = "错误:无法上传没有有效的目标文件名的照片.";
            }
            return result;
        }

        /// <summary>
        /// 处理上传图像的大小,使所有图像都缩放到标准高度
        /// </summary>
        /// <param name="inputfilestream"></param>
        /// <param name="finalfilename"></param>
        /// <param name="folderpath"></param>
        /// <param name="hmindimension"></param>
        /// <returns></returns>
        public String ResizeImageUpload(Stream inputfilestream, String finalfilename, String folderpath, int hmindimension)
        {
            String result = "";
            // 强制最终上传的图像以具有固定的高度
            int newStillWidth, newStillHeight;
            int ori1;
            Image originalimg;
            try
            {
                originalimg = System.Drawing.Image.FromStream(inputfilestream);
                if (originalimg.Width > originalimg.Height)
                {
                    //景观图片规则 
                    ori1 = originalimg.Height;
                    newStillHeight = hmindimension;
                    newStillWidth = (int)((double)originalimg.Width * hmindimension / ori1);
                }
                else
                {
                    //肖像图片规则
                    ori1 = originalimg.Width;
                    newStillHeight = hmindimension;
                    newStillWidth = (int)((double)newStillHeight * originalimg.Width / originalimg.Height);
                }
                Bitmap still = new Bitmap(newStillWidth, newStillHeight);
                Graphics gr_dest_still = Graphics.FromImage(still);
                SolidBrush sb = new SolidBrush(System.Drawing.Color.White);
                gr_dest_still.FillRectangle(sb, 0, 0, still.Width, still.Height);
                gr_dest_still.DrawImage(originalimg, 0, 0, still.Width, still.Height);
                try
                {
                    ImageCodecInfo codecencoder = GetEncoder("image/jpeg");
                    int quality = 90;
                    EncoderParameters encodeparams = new EncoderParameters(1);
                    EncoderParameter qualityparam = new EncoderParameter(Encoder.Quality, quality);
                    encodeparams.Param[0] = qualityparam;
                    still.SetResolution(96, 96);
                    if (!folderpath.EndsWith("\\")){
                        folderpath += "\\";
                    }
                    still.Save(folderpath  + finalfilename, codecencoder, encodeparams);
                    result = "OK: File uploaded!";
                }
                catch(Exception ex)
                {
                    result = "ERROR: 保存图像时出现问题. " + ex.Message;
                }
                if (still!=null)
                {
                    still.Dispose();                    
                }    
            }
            catch(Exception ex)
            {
                result = "ERROR: 这不是我们可以处理的图片. " + ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 处理裁剪图像,将裁剪的图像缩放到AppSettings文件中配置的标准尺寸
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="sourcefolder"></param>
        /// <param name="targetfolder"></param>
        /// <param name="imgfolder"></param>
        /// <param name="X"></param>
        /// <param name="Y"></param>
        /// <param name="W"></param>
        /// <param name="H"></param>
        /// <returns></returns>
        public String CropImage(String filename, String sourcefolder, String targetfolder, String imgfolder, int X, int Y, int W, int H)
        {
            String result = "";
            // 强制最终裁剪的图像以具有固定的尺寸
            int croppedfinalw, croppedfinalh;
            croppedfinalh = Convert.ToInt32(Settings.AppSettings.passheight);
            croppedfinalw = Convert.ToInt32(Settings.AppSettings.passwidth);
            try
            {
                if (!imgfolder.EndsWith("\\"))
                {
                    imgfolder += "\\";
                }
                String sourcepath = imgfolder + sourcefolder + "\\";
                Bitmap image1 = (Bitmap)Image.FromFile(sourcepath + filename, true);
                Rectangle rect = new Rectangle(X, Y, W, H);
                Bitmap cropped = image1.Clone(rect, image1.PixelFormat);
                // 释放原始图像,以防我们需要在下面覆盖它
                if (image1 != null)
                {
                    image1.Dispose();                    
                }    
                Bitmap finalcropped= new Bitmap(croppedfinalw, croppedfinalh);
                Graphics gr_finalcropped  = Graphics.FromImage(finalcropped);
                SolidBrush sb = new SolidBrush(System.Drawing.Color.White);
                gr_finalcropped.FillRectangle(sb, 0, 0, finalcropped.Width, finalcropped.Height);
                gr_finalcropped.DrawImage(cropped, 0, 0, finalcropped.Width, finalcropped.Height);
                try
                {
                    ImageCodecInfo codecencoder  = GetEncoder("image/jpeg");
                    int quality = 92;
                    EncoderParameters encodeparams  = new EncoderParameters(1);
                    EncoderParameter qualityparam = new EncoderParameter(Encoder.Quality, quality);
                    encodeparams.Param[0] = qualityparam;
                    finalcropped.SetResolution(240, 240);
                    sourcepath = sourcepath.Replace(sourcefolder, targetfolder);
                    finalcropped.Save(sourcepath + filename, codecencoder, encodeparams);
                    result = "OK - 文件裁剪完成了";
                }
                catch(Exception ex)
                {
                    result = "ERROR: 保存图像时出现问题。 " + ex.Message;
                }
                if (cropped != null)
                {
                    cropped.Dispose();                    
                }
                if (finalcropped != null)
                {
                    finalcropped.Dispose();                    
                }
            }
            catch(Exception ex)
            {
                result = "ERROR: 这不是我们可以处理的图片. " + ex.Message;
            }
            return result;
        }

        public ImageCodecInfo GetEncoder(String mimetype)
        {
            ImageCodecInfo result = null;
            foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders())
            {
                if (codec.MimeType == mimetype){
                    result = codec;
                }
            }
            return result;
        }

        public int CalculateResizedWidth(String filename, String folderpath, int newh)
        {
            int result = 0;
            if (!folderpath.EndsWith("\\"))
            {
                folderpath += "\\";
            }
            String fullpath = folderpath + filename;
            Bitmap image1 = (Bitmap)Image.FromFile(fullpath, true);
            if (image1 != null)
            {
                result = (int)((double)newh * image1.Width / image1.Height);
                image1.Dispose();                
            }    
            return result;
        }

        /// <summary>
        /// Updates the javascript code sent to the view to handle the cropping
        /// based on the dimensions of the source image used for cropping.
        /// 更新发送到视图的JavaScript代码,以根据用于裁剪的源图像的尺寸来处理裁剪。
        /// </summary>
        /// <param name="neww"></param>
        /// <param name="newh"></param>
        /// <param name="filepath"></param>
        /// <returns></returns>
        public String UpdatePreviewJs(int neww, int newh, String filepath="")
        {
            String result = "";
            //读取默认的js源文件
            //该结构允许通过在单元测试中传递测试文件路径进行单元测试
            if (filepath == "" || filepath==null)
            {
                HttpContext ctx = HttpContext.Current;
                if (ctx != null)
                {
                    filepath = ctx.Server.MapPath("~/js/tiffjcroppreset.js");
                }                
            }            
            result = System.IO.File.ReadAllText(filepath);
            int startselect = result.IndexOf("width: Math.round");
            int startvalue = result.IndexOf("(", startselect);
            int endvalue = result.IndexOf(")", startvalue);
            String selectvalue = result.Substring(startvalue, endvalue - startvalue + 1);
            String newvalue = "(rx*" + neww.ToString() + ")";
            result = result.Replace(selectvalue, newvalue);
            //根据源图像改变高度
            startselect = result.IndexOf("height: Math.round");
            startvalue = result.IndexOf("(", startselect);
            endvalue = result.IndexOf(")", startvalue);
            selectvalue = result.Substring(startvalue, endvalue - startvalue + 1);
            newvalue = "(ry*" + newh.ToString() + ")";
            result = result.Replace(selectvalue, newvalue);
            //配置前置宽高比
            //从设置确定固定图像比例
            String ratio = Settings.AppSettings.passwidth + "/" + Settings.AppSettings.passheight;
            startselect = result.IndexOf("aspectRatio:");
            startvalue = result.IndexOf(" ", startselect);
            endvalue = result.IndexOf(",", startvalue);
            selectvalue = result.Substring(startvalue, endvalue - startvalue + 1);
            newvalue = " " + ratio + ",";
            result = result.Replace(selectvalue, newvalue);
            //配置rx的默认值
            startselect = result.IndexOf("var rx");
            startvalue = result.IndexOf("=", startselect);
            endvalue = result.IndexOf(";", startvalue);
            selectvalue = result.Substring(startvalue, endvalue - startvalue + 1);
            newvalue = "= " + Settings.AppSettings.previewwidth + " / c.w;";
            result = result.Replace(selectvalue, newvalue);
            // 配置ry的默认值
            startselect = result.IndexOf("var ry ");
            startvalue = result.IndexOf("=", startselect);
            endvalue = result.IndexOf(";", startvalue);
            selectvalue = result.Substring(startvalue, endvalue - startvalue + 1);
            newvalue = "= " + Settings.AppSettings.previewheight + " / c.h;";
            result = result.Replace(selectvalue, newvalue);
            //Configure Explicit Resizing 
            //配置显式调整大小
            startselect = result.IndexOf("trueSize:");
            startvalue = result.IndexOf("[", startselect);
            endvalue = result.IndexOf("]", startvalue);
            selectvalue = result.Substring(startvalue, endvalue - startvalue + 1);
            newvalue = "[" + neww.ToString() + ", " + newh.ToString() + "]";
            result = result.Replace(selectvalue, newvalue);  
            return result;
        }      

    }   
}

PassPhoto视图文件夹

Index.cshtml

@{
    //从设置中读取已裁剪图像的默认值
    // 缩小到一半
    var prevw = Settings.AppSettings.previewwidth + "px";
    var prevh = Settings.AppSettings.previewheight + "px";
    //处理从控制器发回的值,以刷新UI
    ViewBag.Title = "照片上传 - MVC";
    var Image1W = prevw;
    var Image1H = prevh;
    var Image1src = "uploaded_images/raw/invalid.jpg";
    var Imagename = "invalid.jpg";
    var croppedpreviewLiteral = "";
    var previewsrc = "uploaded_images/raw/invalid.jpg";
    var displaypreview = "none";
    var message = "";
    var defaultfolder = "raw";
    var uploadaction = "PassPhoto/UploadImage";
    var cropaction = "PassPhoto/CropImage";
    //消息确定清除,否则在UI中显示错误消息
    if (ViewBag.Message != null)
    {
        message = ViewBag.Message;
        if (message.StartsWith("OK"))
        {
            message = "";
        }
    }
    if (ViewBag.Height != null)
    {
        Image1H = ViewBag.Height;
    }
    if (ViewBag.Width != null)
    {
        Image1W = ViewBag.Width;
    }
    if (ViewBag.ImageUrl != null)
    {
        Image1src = ViewBag.ImageUrl;
        previewsrc = ViewBag.ImageUrl;
    }
    if (ViewBag.ImageName != null)
    {
        Imagename = ViewBag.ImageName;
    }
    if (ViewBag.PreviewDisplay != null)
    {
        displaypreview = ViewBag.PreviewDisplay;
        if (displaypreview == "normal")
        {
            croppedpreviewLiteral = "预览图片:";
        }
    }
    if (Image1src.ToLower().Contains("cropped"))
    {
        defaultfolder = "cropped";
    }
    if (ViewBag.rootPath != null)
    {
        Image1src = ViewBag.RootPath + Image1src;
        previewsrc = ViewBag.RootPath + previewsrc;
        uploadaction = ViewBag.RootPath + uploadaction;
        cropaction = ViewBag.RootPath + cropaction;
    }

}

<div>
    <h3>概念证明 - 在线图像裁剪</h3>
    使用下面的"浏览..."按钮选择图像,并在准备好后单击"上传图像"。
    <br />
    <span id="errorLiteral" style="font-size:14px; color:Red; font-weight:bold">
        @message
    </span>
    <br />
    <form action="@uploadaction" method="post" enctype="multipart/form-data">
        <input id="fileupload" name="mypostedfile" type="file" />
        <input type="submit" id="uploadfileButton" value="上传图片" />
    </form>
    <br />
    <br />
    <table>
        <tr>
            <td style="width:400px;">
                <div id="imagenameLiteral">@Imagename</div>
                <br /><br />
                <div>
                    <img id="Image1" width="@Image1W" height="@Image1H" src="@Image1src" />
                    <br />
                </div>
            </td>
            <td style="width:400px;">
                <div id="croppedpreviewLiteral">@croppedpreviewLiteral</div>
                <div style="width:@prevw;height:@prevh;overflow:hidden;background-color:#ffffff;display:@displaypreview">
                    <img id="preview" width="@prevw" height="@prevh" src="@previewsrc" />
                </div>
            </td>
        </tr>
    </table>

    <form action="@cropaction" method="post" enctype="multipart/form-data">

        <input id="X1value" name="X" type="hidden" />
        <input id="Y1value" name="Y" type="hidden" />
        <input id="X2value" name="X2" type="hidden" />
        <input id="Y2value" name="Y2" type="hidden" />
        <input id="Wvalue" name="W" type="hidden" />
        <input id="Hvalue" name="H" type="hidden" />
        <input id="filename" name="filename" value="@Imagename" type="hidden" />
        <input id="folder" name="folder" value="@defaultfolder" type="hidden" />

        <div id="cropinstructions" style="width:400px">
            移动或重新排列原始图像内的选择工具,直到预览选项显示了你想保留的图像。准备好后,点击裁剪按钮,您的选择将会永久保存
            <br /><br />
            <input type="submit" id="cropimageButton" value="裁剪图像" />
        </div>

    </form>
</div>

@section scripts{
    <script lang="Javascript">
        @Html.Raw(ViewBag.PreviewJSMarkup)
    </script>
}     

_Layout.cshtml

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - 我的ASP.NET应用程序</title>
    @Styles.Render("~/bundles/css")  

</head>
<body>    
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - Wu</p>
        </footer>
    </div>

    @Scripts.Render("~/bundles/jcrop")    
    @RenderSection("scripts", required: false)
</body>
</html>

运行结果如图:

这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值