[ASP.net MVC 4] 使用jQuery imgAreaSelect實現facebook的大頭照圖片剪裁功能

[ASP.net MVC 4] 使用jQuery imgAreaSelect實現facebook的大頭照圖片剪裁功能

image

前言

圖片剪裁功能,使用者拖拉縮放一個選擇區域(selection area)

按下確定鈕,將該選擇區域給裁剪下來

基本原理:

先上傳一張原始圖片

jQuery Plugin幫忙弄出selection area效果,並回傳selection area的座標和寬高

然後我們可以用hidden欄位記下座標值和寬高,把資料送到Server端,Server端再用System.Drawing.Graphics的DrawImage()方法對原始圖檔把selection area裁切下來存檔即可。

以上動作可以在同一頁面完成,不過實際運用在專案上發現,很多地方都要加這種裁切功能的話,最好還是另外抽出一個頁面

然後再用window.open()或jQuery fancybox還是jQuery colorbox去開啟該頁面來處理圖片

 

實作

第一步先引用jQuery核心函式庫

再去imgAreaSelect - image selection-cropping jQuery plugin - odyniec.net官網 下載.zip壓縮檔

解壓後把裡面css資料夾的.gif圖檔和imgareaselect-default.css還有scripts資料夾的jquery.imgareaselect.min.js引入專案

以下代碼已整理過,說明都在註解裡

ImgAreaSelectController.cs


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplicationImgAreaSelect.Controllers
{
    public class ImgAreaSelectController : Controller
    {
        //裁剪圖片的View
        [HttpGet]
        public ActionResult Index()
        {
            ViewData["openerFieldId"] = Request.QueryString["openerFieldId"];
            ViewData["openerSrcId"] = Request.QueryString["openerSrcId"];
            return View();
        }

        /// <summary>
        /// 上傳原始檔案
        /// </summary>
        /// <param name="myFile"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Upload(HttpPostedFileBase myFile, FormCollection form)
        {
            ModelState.Clear();//上傳檔案無須驗證
            //有選擇檔案
            if (myFile != null && myFile.ContentLength > 0)
            {
                //新的檔名
                string newName = Guid.NewGuid().ToString() + Path.GetExtension(myFile.FileName);
                //暫存圖檔
                myFile.SaveAs(Server.MapPath("~/TempFiles/" + newName));
                ViewData["sourceImgName"] = newName;
            }
            ViewData["openerFieldId"] = form["openerFieldId"];
            ViewData["openerSrcId"] = form["openerSrcId"];
            return View("Index");
        }

        //裁剪圖片
        [HttpPost]
        public ActionResult CropImage(FormCollection form)
        {
            //selection area的左上座標和寬高
            int x1 = Convert.ToInt32(form["x1"]);
            int y1 = Convert.ToInt32(form["y1"]);
            int width = Convert.ToInt32(form["width"]);
            int height = Convert.ToInt32(form["height"]);
            string sourceImgName = form["sourceImgName"];
            string sourceImgPath = Server.MapPath("~/TempFiles/" + sourceImgName);
            string targetImgName = Guid.NewGuid().ToString() + ".jpg";
            string targetImgPath = Server.MapPath("~/TempFiles/" + targetImgName);
            #region 裁剪圖片
            //有先做過上傳圖檔
            if (!string.IsNullOrEmpty(sourceImgName))
            {

                //原始圖片
                System.Drawing.Image sourceImage = Image.FromFile(sourceImgPath);

                //裁剪的區域
                Rectangle fromR = new Rectangle(x1, y1, width, height);
                //裁剪出來的圖要放在畫布的哪個位置
                Rectangle toR = new Rectangle(0, 0, width, height);



                //要當畫布的Bitmap物件
                System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(width, height);
                //產生畫布
                System.Drawing.Graphics g = Graphics.FromImage(bitmap);
                //清空畫布,背景白色
                g.Clear(Color.White);

                //以像素做為測量單位
                GraphicsUnit units = GraphicsUnit.Pixel;
                //剪裁
                g.DrawImage(sourceImage, toR, fromR, units);



                //裁剪完成,存檔
                bitmap.Save(targetImgPath, ImageFormat.Jpeg);
                //釋放資源
                g.Dispose();
                bitmap.Dispose();
                sourceImage.Dispose();

                System.IO.File.Delete(sourceImgPath);//把原始檔刪除

            }
            #endregion 

            
            string js = "<script>" +
                                "window.opener.document.getElementById('" + form["openerFieldId"] + "').value='" + targetImgName + "';" +
                                "window.opener.document.getElementById('" + form["openerSrcId"] + "').src='" + Url.Content("~/TempFiles/" + targetImgName) + "';" +
                                "window.opener=null; " +//關閉子視窗
                                "window.open('','_self');" +
                                "window.close();" +
                "</script>";

            return Content(js);
        }

    }
}

ImgAreaSelect的View(Index.cshtml)


<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>裁剪圖片</title>
    @*引用jQuery核心函式庫*@
    <script src="~/Scripts/jquery-2.0.2.min.js"></script>
    
    @*引用jQuery imageAreaSelect的相關檔案*@
    <script src="~/Scripts/jquery.imgareaselect.min.js"></script>
    <link href="~/Content/css/imgareaselect-default.css" rel="stylesheet" />
    
    <script type="text/javascript">
        $(document).ready(init);
        function init() {
            //上傳圖片
            $("input[name='myFile']").change(function () {
                //改變表單post的action
                var action = "@Url.Action("Upload","ImgAreaSelect")";
                $("form").attr("action", action);
                $("form").submit();
            });

            var sourceImgName = $("input[name='sourceImgName']").val();
            //已上傳過圖檔
            if (sourceImgName != "") {
                
                //對原始圖檔呼叫 imgAreaSelect()
                $('#sourceImage').imgAreaSelect({
                    resizable: false,//使用者不可縮放selection area
                    persistent: true,//使用者click selection area之外的地方不會重新開始一個新的selection area
                    aspectRatio: '1:1', x1: 0, y1: 0, x2: 120, y2: 120,//selection area的寬高比例和預設寬高
                    onSelectEnd: function (img, selection) {  //當使用者拖放結束時,儲存selection area的左上座標和寬高給hidden
                        $('input[name="x1"]').val(selection.x1);
                        $('input[name="y1"]').val(selection.y1);
                        $("input[name='width']").val(selection.width);
                        $("input[name='height']").val(selection.height);

                    }
                });
            }



        }


    </script>


</head>
<body>



    @using (Html.BeginForm("CropImage", "ImgAreaSelect", FormMethod.Post,new {enctype= "multipart/form-data"}))
    {
        //要裁剪的座標和寬高
        @Html.Hidden("x1",0)
        @Html.Hidden("y1",0)
        @Html.Hidden("width",120)
        @Html.Hidden("height",120)
        //原始圖檔名稱
        @Html.Hidden("sourceImgName", ViewData["sourceImgName"])
        //要置換window.opener的欄位
        @Html.Hidden("openerFieldId",ViewData["openerFieldId"])
        @Html.Hidden("openerSrcId",ViewData["openerSrcId"])

        
        <span>請選擇檔案</span>
        <input type="file" name="myFile" /> 
        <hr />
      
        if (ViewData["sourceImgName"]!=null)
        {
            <span style="color:red;">請選擇要裁剪的區域</span><br />
        }
        //img必須指定src,有圖的話jQuery Plugin才有效
       <img id="sourceImage"   src="@Url.Content("~/TempFiles/" + ViewData["sourceImgName"])" />
        <br />
       <input type="submit" value="確定" />
        
        
    }
</body>
</html>

 

一般要使用的話…

HomeController.cs


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

namespace MvcApplicationImgAreaSelect.Controllers
{
    public class HomeController : Controller
    {
        
        [HttpGet]
        public ActionResult Form()
        {
            return View();
        }

        //儲存
        [HttpPost]
        public ActionResult Form(FormCollection form)
        {
            //裁圖檔名
            string imageFileName = form["imageFileName"];
            //裁圖Url
            string imgUrl = Url.Content("~/TempFiles/" + imageFileName);
            //裁圖路徑
            string imgPath = Server.MapPath("~/TempFiles/" + imageFileName);

            //把資料儲存DB或搬移檔案等等,剩下的自行料理....

            return View();
        }

    }
}

HomeController的View(Form.cshtml)


<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Form</title>
    <script src="~/Scripts/jquery-2.0.2.min.js"></script>
    <script type="text/javascript">
        $(document).ready(init);
        function init() {
            //註冊button按下後事件,開啟imgAreaSelect頁面
            $("#btnOpenImgAreaSelect").click(function () {

                //一裁剪完,此頁的圖片要顯示裁剪圖片而hidden欄位要記下裁剪後圖片的檔名
                var url = "@Url.Action("Index", "ImgAreaSelect")" + "?" + "openerFieldId=imageFileName" + "&" + "openerSrcId=imgDemo";
                window.open(url, '', 'width=1024,height=768');//覺得window.open()太醜的話,再自行用fancybox或colorbox美化
            });


        }
    </script>
</head>
<body>
    <div>
        @using (Html.BeginForm("Form", "Home", FormMethod.Post, new { @class = "form-horizontal", enctype = "multipart/form-data" }))
        {
                         

            @Html.Hidden("imageFileName")
            <img id="imgDemo" src=""> 
            <br />
            <input type="button" id="btnOpenImgAreaSelect" value="另開視窗" />
            <br />
            <input type="submit" value="儲存" />
                        
        }
    </div>
</body>
</html>

 

執行結果:

demo

 

範例檔下載

 

 

結語

此Plugin還有一些參數不錯用,可以自行參考官網看看

 

 

參考文章:

jQuery+Asp.net结合实现图片截图