2012年1月21日 星期六

圖片裁剪大頭貼功能 - ASP.NET WebForm + jQuery + imgAreaSelect


前一篇文章「圖片裁剪大頭貼功能 - ASP.NET MVC + jQuery + imgAreaSelect」是說明在ASP.NET MVC架構下去使用 imgAreaSelect 來達成裁剪圖片的功能需求,而其實客戶的專案架構是使用ASP.NET WebForm,而這篇文章就來說明如何在ASP.NET WebForm架構下使用 imgAreaSelect。


系統操作環境:

  • ASP.NET WebForm
  • .NET Framework 4.0 (C#)
  • jQuery 1.7.1
  • imgAreaSelect 0.9.8

 

目錄結構:

image

與之前使用ASP.NET MVC的目錄結構相比,其實差異性不是很大,同樣的主要操作頁面都是有三個:

  • Default 主頁面
  • Upload 上傳頁
  • Crop 裁剪圖片頁


前端頁面的程式設定與使用

Crop頁面:

<form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="回到首頁" onclick="Button1_Click" />
        <asp:Button ID="Button2" runat="server" Text="裁剪相片" onclick="Button2_Click" />
        <asp:Panel ID="Panel1" runat="server" Visible="false">
            <asp:Image ID="Image3" runat="server" />
            <hr />
        </asp:Panel>
        <div align="center">
            <img id="Image1" runat="server" style="float: left; margin-right: 10px;" alt="Create Thumbnail" />
            <div style="float: left; position: relative; overflow: hidden; width: 100px; height: 100px;">
                <img id="Image2" runat="server" style="position: relative;" alt="Thumbnail Preview" />
            </div>
        </div>
        <input type="hidden" id="x1" name="x1" value="" runat="server" />
        <input type="hidden" id="y1" name="y1" value="" runat="server" />
        <input type="Hidden" id="x2" name="x2" value="" runat="server" />
        <input type="hidden" id="y2" name="y2" value="" runat="server" />
    </div>
</form>

基本上頁面的elements設置都大同小異,與MVC的部份都是一樣的,差別就在於我所設計的這個WebForm頁面並不會有太多的AJAX功能與效果,私心而論,WebForm也是可以達成AJAX功能與效果,但與MVC相比就不是那樣靈活與自由,因為WebForm有太多需要與Server端元件牽扯在一起,而本人我比較不喜歡使用 AJAX.NET,UpdatePanel的使用要考慮到太多的問題,尤其是WebForm必須注意的網頁生命週期事件。

並不是說使用了UpdatePanel就無法jQuery做結合,而是為了要與jQuery來做整合就還要多花許多的時間與工夫,所以成本與效益的考量下,這個ASP.NET WebForm的裁剪圖面功能就完全不做AJAX的功能與效果,每一次的操作完成就會有一次的PostBack。

 

下圖為一張尚未進行裁剪操作的原始圖片資料

image

下圖為已經有操作過裁剪圖片的顯示

image

 

來看看Crop頁面的前端程式的內容:

        <script type="text/javascript" src="Scripts/jquery-1.7.1.min.js"></script>
        <script type="text/javascript" src="Scripts/jquery.imgareaselect.pack.js"></script>
        <script type="text/javascript">
            $(document).ready(function ()
            {
                $('img#Image1').imgAreaSelect(
                {
                    handles: 'corners',
                    aspectRatio: '1:1',
                    x1: 0, y1: 0, x2: 100, y2: 100,
                    onSelectChange: preview
                });
            });
            function preview(img, selection)
            {
                var scaleX = 100 / selection.width;
                var scaleY = 100 / selection.height;
                var img = new Image();
                img.src = $('#Image1').attr('src');
                var pic_real_width = img.width;
                var pic_real_height = img.height;
                $('#Image1 + div > img').css({
                    width: Math.round(scaleX * pic_real_width) + 'px',
                    height: Math.round(scaleY * pic_real_height) + 'px',
                    marginLeft: '-' + Math.round(scaleX * selection.x1) + 'px',
                    marginTop: '-' + Math.round(scaleY * selection.y1) + 'px'
                });
                $('input[name="x1"]').val(selection.x1);
                $('input[name="y1"]').val(selection.y1);
                $('input[name="x2"]').val(selection.x2);
                $('input[name="y2"]').val(selection.y2);
            } 
        </script>

這邊imgAreaSelect使用設定與ASP.NET MVC的使用設定是大致相同的,不過這邊要補充說明一下「handles」這個設定參數,

handles

當imgAreaSelect沒有設定這個參數時,預設為「false」也就是裁剪選取框不會出現這角落與各邊的小方框,當設定為「handles: ture」時,裁剪選取框的各個角落與四個邊中間就會出現小方框,而當設定為「handles: ‘corners’」時,只會在四個角落出現小方框,而四個邊中間則不會出現,如下圖所示,

image

 



後端:Code behind的內容

因為前面有說過這個WebForm的範例不會有AJAX的效果與功能,所以每一個完成送出的操作都是一個PostBack,所以當選取完裁剪區域後按下「裁剪圖片」Button就是整頁再PostBack回後端,

image

而我們是把選擇裁剪區域框的座標值一樣是存放到Hidden Field中,所以當頁面PostBack回到後端,後端程式也同樣是可以得到座標值,不過記得的就是要將Hidden Field增加「runat = “server”」(因為並非使用伺服器控制項的HiddenField),

看看後端裁剪圖片的程式:

#region -- SaveCropImage --
/// <summary>
/// Saves the crop image.
/// </summary>
private void SaveCropImage()
{
    bool isNullOfsectionValue = this.x1.Value == null
        && this.x2.Value == null
        && this.y1.Value == null
        && this.y2.Value == null;
    if (isNullOfsectionValue)
    {
        ClientScriptHelper.ShowMessage(this.Page, "請選擇相片裁剪區域", RegisterScriptType.Start);
    }
    else
    {
        CropImageUtility cropUtils = new CropImageUtility(this.UploadPath, this.OriginalPath, this.CropPath);
        Dictionary<string, string> result = cropUtils.ProcessImageCrop
        (
            this.CurrentImage,
            new int[]
            { 
                this.x1.Value.ConvertToInt(),
                this.x2.Value.ConvertToInt(),
                this.y1.Value.ConvertToInt(),
                this.y2.Value.ConvertToInt()
            }
        );
        if (!result["result"].Equals("Success", StringComparison.OrdinalIgnoreCase))
        {
            ClientScriptHelper.ShowMessage(this.Page, result["msg"], RegisterScriptType.Start);
        }
        else
        {
            //裁剪圖片檔名儲存到資料庫
            service.Update(this.ImageID, result["CropImage"]);
            //如果有之前的裁剪圖片,則刪除
            if (!string.IsNullOrWhiteSpace(result["OldCropImage"]))
            {
                cropUtils.DeleteCropImage(result["OldCropImage"]);
            }
            //載入裁剪圖片檔
            LoadCropImage();
            ClientScriptHelper.ShowMessage(this.Page, "相片裁剪完成", RegisterScriptType.Start);
        }
    }
} 
#endregion


後端:圖片上傳的處理

為什麼特別提出說明這一段呢?

以往在WebFrom中對於頁面的檔案上傳欄位,在Code Behid的處理都是對應使用「HttpPostedFile」,但因為ASP.NET MVC對於檔案上傳欄位的處理所對應的是「HttpPostedFileBase」,

 

MSDN - HttpPostedFile 類別

MSDN - HttpPostedFileBase 類別

兩個類別的結構內容差不多,但兩者間是沒有關連性,除了同在一個Namespace「System.Web」下,

而在.NET Framework 3.5之後就有提供一個 HttpPostedFileWrapper 類別可以來幫助我們解決這個問題,

image

MSDN - HttpPostedFileWrapper 類別

「HttpPostedFileWrapper 類別衍生自 HttpPostedFileBase 類別,而且可做為 HttpPostedFile 類別的包裝函式。 這個類別會公開 (Expose) HttpPostedFile 類別的功能,同時也會公開 HttpPostedFileBase 型別。 HttpPostedFileBase 類別可讓您以自訂實作取代應用程式中 HttpPostedFile 類別的原始實作,例如當您從 ASP.NET 管線外部執行單元測試時。」

HttpPostedFileWrapper是繼承自HttpPostedFileBase,而其建構式為接受HttpPostedFile類別的參數,

public HttpPostedFileWrapper
(
    HttpPostedFile httpPostedFile
)

 

因為我不希望兩個網站專案都各自造輪子,只要使用一個處理上傳檔案的Method就好了,所以WebForm對於這個地方就需要做點小小的處理,

直接看看程式的內容:

#region -- ProcessUpload --
/// <summary>
/// Processes the upload.
/// </summary>
private void ProcessUpload()
{
    string fileName = string.Empty;
    if (FileUpload1.HasFile)
    {
        HttpPostedFileBase uploadFile = new HttpPostedFileWrapper(FileUpload1.PostedFile);
        CropImageUtility cropUtils = new CropImageUtility(this.UploadPath, this.OriginalPath, "");
        Dictionary<string, string> result = cropUtils.ProcessUploadImage(uploadFile);
        if (!result["result"].Equals("Success", StringComparison.OrdinalIgnoreCase))
        {
            Session["Upload_File"] = null;
            ClientScriptHelper.ShowMessage(this.Page, result["msg"], RegisterScriptType.Start);
        }
        else
        {
            Session["Upload_File"] = result["msg"];
        }
    }
}
#endregion


操作流程示意

Step 1:首頁,列出所有圖片資料並可以做刪除資料的操作

image


Step 2:上傳圖片頁

image

選擇並上傳圖片,上傳圖片暫存至/Temp目錄下,當按下「儲存圖片」Button在將圖片移到/Original目錄下,如果按下「取消儲存」則將圖片自/Temp目錄中刪除,並清空頁面的資料以做重新上傳。

image

按下「儲存圖片」Button在將圖片移到/Original目錄下,並且顯示「裁剪圖片」Button,按下此Button就會移到裁剪圖片頁。

image


Step 3:裁剪圖片頁

新上傳或未進行過裁剪圖片操作的資料並不會有裁剪圖片的圖檔,

image

選擇裁剪圖片的區域,並在右方即時預覽

image

按下「裁剪圖片」Button後,頁面資料PostBack到後端進行圖片裁剪的操作,完成後就會顯示完成裁剪圖片的結果並顯示裁剪後的圖檔內容。

image



因為大部分的功能都與前一篇ASP.NET MVC架構的功能是雷同的,所以就沒有太多的內容描述, 除了特別提出的「HttpPostedFile」與「HttpPostedFileBase」的差異與如何使用「HttpPostedFileWrapper」將HttpPostedFile類別的物件轉換為HttpPostedFileBase類別的物件,而下一篇文章除了把使用imgAreaSelect的ASP.NET MVC網站與ASP.NET WebForm網站原始碼提出來之外,也會簡單說明一下如何將共用功能的部份給提取出來到另一個類別庫專案中,讓兩種不同架構的網站可以共用。

 

參考連結:

imgAreaSelect Documentation
http://odyniec.net/projects/imgareaselect/usage.html


以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。