开发网站几乎都做过上传图片并截图,做个无刷新Asp.Net上传并截图示例
实现功能:
1.选择文件,自动上传并生成缩放图(上传带进度条),形成预览图
2.在预览区,实现鼠标拖拽截图区,截取图片(示例截图区按缩放图小边为截图正方形长度,可扩展为截图区可变形式)
3.点击保存,截取小图,保存截取图并显示在页面上,并删除原缩略图
示例截图:
-------------------------------------------------------------------------------风骚分隔线-----------------------------------------------------------------------------------------------
第一步:准备工作,认识一些必要的东西 |
1.无刷新上传借助于Uploadify这个基于Flash的支持多文件上传的Jquery插件,很多人估计都用过了,我也在不同的项目中用过很多次,简单易用且功能强大
(美中不足,插件本身对session使用有一点BUG,不过能解决,chrome&FireFox里上传如果代码中有用Session,获取不到)
没用过这个插件的可以去它的官网认识一下这个插件
Uploadify官网:
uploadify下载: (本示例用:Uploadify-v2.1.4.zip)
http://www.uploadify.com/download/
uploady全属性、事件、方法介绍:
http://www.uploadify.com/documentation/
这里对一些常用介绍一下:
名称 | 介绍 | 类型 |
Uploadify常用属性 | ||
uploader | uploadify的swf文件的路径 | string |
cancelImg | 取消按钮图片路径 | string |
folder | 上传文件夹路径 | string |
multi | 是否多文件上传 | boolean |
script | 上传文件处理代码的文件路径 | json |
scriptData | 提交到script对应路径文件的参数 | 类型 |
method | 提交scriptData的方式(get/post) | string |
fileExt | 支持上传文件类型(格式:*.jpg;*.png) | string |
fileDesc | 提示于点击上传弹出选择文件框文件类型(自定义) | string |
sizeLimit | 上传大小限制(byte为单位) | integer |
auto | 是否选择文件后自动上传 | boolean |
Uploadify常用事件 | ||
onAllComplete | 上传完成后响应 | function |
onCancel | 取消时响应 | function |
Uploadify常用方法 | ||
.uploadify() | 初始化uploadify上传 | |
.uploadifyUpload() | 触发上传 | |
.uploadifySettings() | 更新uploadify的属性 |
2.裁剪图片使用CutPic.js (这个JS文件如果各位要用,要自己用心看看,注释很详细了)
源码太长,这里不贴出来,后面会提供下载
显示图片也用的CutPic里的方法
JS代码显示
function ShowImg(imagePath,imgWidth,imgHeight) { var imgPath = imagePath != "" ? imagePath : "!images/ef_pic.jpg"; var ic = new ImgCropper("bgDiv", "dragDiv", imgPath, imgWidth, imgHeight, null);
}
HTML显示部分布局(一个嵌套层级关系,外面是显示图片,里面dragDiv是拖拽层)
<div id="bgDiv"> <div id="dragDiv"> </div> </div>
第二步:引用资源,开始编写 |
Default.aspx页
用了三个隐藏域去存截图区的左上角X坐标,Y坐禁,以及截图框的大小;
这个要修改CutPic里设置切割要用到,CutPic.js里己经做了注释;
Uploadify中参数如果动态改变的,可以写在像我下面写的这样去更新参数
$("#uploadify").uploadifySettings('scriptData',{'LastImgUrl':$('#hidImageUrl').val()}); //更新参数
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Posrchev-裁剪头像</title> <script src="!js/jquery-1.4.1.min.js" type="text/javascript"></script> <script src="!js/cutpic.js" type="text/javascript"></script> <script src="!js/uploadify-v2.1.4/jquery.uploadify.v2.1.4.min.js" type="text/javascript"></script> <script src="!js/uploadify-v2.1.4/swfobject.js" type="text/javascript"></script> <link href="!css/Main.css" rel="stylesheet" type="text/css"/> <link href="!css/uploadify.css" rel="stylesheet" type="text/css"/> <script type="text/javascript"> var imageWidth =300; var imageHeiht =300; $(function(){ $('#uploadify').uploadify({ 'uploader': '/!js/uploadify-v2.1.4/uploadify.swf', 'script': '/Handler/UploadAvatarHandler.ashx', 'cancelImg': '/!js/uploadify-v2.1.4/cancel.png', 'folder' : '/Temp', 'queueID': 'fileQueue', 'auto': true, 'multi': false, 'method' : 'get', 'fileExt': '*.jpg;*.png', 'fileDesc': '请选择jpg , png文件...', 'scriptData': null, 'sizeLimit' : 2097152, 'onComplete': function (event, queueID, fileObj, response, data) { if (response.indexOf('Temp') !=-1) { $("#bgDiv img").remove(); //移除截图区里image标签 $("#btnSave").show(); //保存按钮显示 var result = response.split('$'); //得返回参数 var maxVal =0; if(result[1] > result[2]) { maxVal = result[2]; } else { maxVal = result[1]; } $("#maxVal").val(maxVal); //设置截图区大小 $("#hidImageUrl").val(result[0]); //上传路径存入隐藏域 ShowImg(result[0],result[1],result[2]); //在截图区显示 $("#uploadify").uploadifySettings('scriptData',{'LastImgUrl':$('#hidImageUrl').val()}); //更新参数 } else { alert(response); } } }); $("#btnSave").click(function(){ $.ajax({ type: "POST", url: "/Handler/CutAvatarHandler.ashx", data: {imgUrl:$('#hidImageUrl').val(),pointX:$("#x").val(),pointY:$("#y").val(),maxVal:$("#maxVal").val()}, success: function(msg) { if (msg.indexOf('User') !=-1) { $("#imgCut").attr("src",msg); } else { alert("error"); } }, error: function(xhr, msg, e) { alert("error"); } }); }); }); function ShowImg(imagePath,imgWidth,imgHeight) { var imgPath = imagePath !=""? imagePath : "!images/ef_pic.jpg"; var ic =new ImgCropper("bgDiv", "dragDiv", imgPath, imgWidth, imgHeight, null); } //{ Right: "rRight", Left: "rLeft", Up: "rUp", Down: "rDown", RightDown: "rRightDown", LeftDown: "rLeftDown", RightUp: "rRightUp", LeftUp: "rLeftUp"} </script> </head> <body> <form id="form1" runat="server"> <div class="fl avatarbg"> <div class="avatarboxbar"> <div id="bgDiv"> <div id="dragDiv"> </div> </div> </div> </div> <div class="avatarthumb"> <asp:Image ID="imgCut" ImageUrl="/!images/blank_pic.jpg" runat="server"/> </div> <br /> <div class="uploadimg"> <div class="upload"> <div class="uploadswf"> <input type="file" name="uploadify" id="uploadify"/> </div> <br /> <p id="fileQueue"> </p> </div> </div> <input id="btnSave" type="button" value="保存" style="display: none;"/> <input id="x" runat="server" type="hidden" value="0"/> <input id="y" runat="server" type="hidden" value="0"/> <input id="hidImageUrl" type="hidden" value=""/> <input id="maxVal" runat="server" type="hidden" value="100"/> </form> </body> </html>
上传图片Hander代码(UploadAvatarHandler.ashx)
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
<%@ WebHandler Language="C#" Class="CutAvatarHandler" %> using System; using System.Web; using System.Web.Services; using System.Web.SessionState; public class CutAvatarHandler : IHttpHandler, IRequiresSessionState { [WebMethod(EnableSession = true)] public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; context.Response.Charset = "utf-8"; System.IO.Stream stream = null; System.Drawing.Image originalImg = null; //原图 System.Drawing.Image thumbImg = null; //缩放图 try { int minWidth = 100; //最小宽度 int minHeight = 100; //最小高度 int maxWidth = 300; //最大宽度 int maxHeight = 300; //最大高度 string resultTip = string.Empty; //返回信息 HttpPostedFile file = context.Request.Files["Filedata"]; //上传文件 string uploadPath = HttpContext.Current.Server.MapPath(@context.Request["folder"]); //得到上传路径 string lastImgUrl = @context.Request.Params["LastImgUrl"]; if (!string.IsNullOrEmpty(lastImgUrl)) { PubClass.FileDel(HttpContext.Current.Server.MapPath(lastImgUrl)); } if (file != null) { if (!System.IO.Directory.Exists(uploadPath)) { System.IO.Directory.CreateDirectory(uploadPath); } string ext = System.IO.Path.GetExtension(file.FileName).ToLower(); //上传文件的后缀(小写) if (ext == ".jpg" || ext == ".png") { string flag = "ThumbNail" + DateTime.Now.ToFileTime() + ext; string uploadFilePath = uploadPath + "\\" + flag; //缩放图文件路径 stream = file.InputStream; originalImg = System.Drawing.Image.FromStream(stream); if (originalImg.Width > minWidth && originalImg.Height > minHeight) { thumbImg = PubClass.GetThumbNailImage(originalImg, maxWidth, maxHeight); //按宽、高缩放 if (thumbImg.Width > minWidth && thumbImg.Height > minWidth) { thumbImg.Save(uploadFilePath); resultTip = @context.Request["folder"] + "\\" + flag + "$" + thumbImg.Width + "$" + thumbImg.Height; } else { resultTip = "图片比例不符合要求"; } } else { resultTip = "图片尺寸必须大于" + minWidth + "*" + minHeight; } } } else { resultTip = "上传文件为空"; } context.Response.Write(resultTip); } catch (Exception) { throw; } finally { if (originalImg != null) { originalImg.Dispose(); } if (stream != null) { stream.Close(); stream.Dispose(); } if (thumbImg != null) { thumbImg.Dispose(); } GC.Collect(); } } public bool IsReusable { get { return false; } } }
切割图片Hander代码(CutAvatarHandler.ashx)
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
<%@ WebHandler Language="C#" Class="CutAvatarHandler" %> using System; using System.Web; using System.Web.SessionState; public class CutAvatarHandler : IHttpHandler, IRequiresSessionState { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; context.Response.Charset = "utf-8"; System.Drawing.Bitmap bitmap = null; //按截图区域生成Bitmap System.Drawing.Image thumbImg = null; //被截图 System.Drawing.Graphics gps = null; //存绘图对象 System.Drawing.Image finalImg = null; //最终图片 try { string pointX = context.Request.Params["pointX"]; //X坐标 string pointY = context.Request.Params["pointY"]; //Y坐标 string imgUrl = context.Request.Params["imgUrl"]; //被截图图片地址 string rlSize = context.Request.Params["maxVal"]; //截图矩形的大小 int finalWidth = 100; int finalHeight = 100; if (!string.IsNullOrEmpty(pointX) && !string.IsNullOrEmpty(pointY) && !string.IsNullOrEmpty(imgUrl)) { string ext = System.IO.Path.GetExtension(imgUrl).ToLower(); //上传文件的后缀(小写) bitmap = new System.Drawing.Bitmap(Convert.ToInt32(rlSize), Convert.ToInt32(rlSize)); thumbImg = System.Drawing.Image.FromFile(HttpContext.Current.Server.MapPath(imgUrl)); System.Drawing.Rectangle rl = new System.Drawing.Rectangle(Convert.ToInt32(pointX), Convert.ToInt32(pointY), Convert.ToInt32(rlSize), Convert.ToInt32(rlSize)); //得到截图矩形 gps = System.Drawing.Graphics.FromImage(bitmap); //读到绘图对象 gps.DrawImage(thumbImg, 0, 0, rl, System.Drawing.GraphicsUnit.Pixel); finalImg = PubClass.GetThumbNailImage(bitmap, finalWidth, finalHeight); string finalPath = "/User/final" + DateTime.Now.ToFileTime() + ext; finalImg.Save(HttpContext.Current.Server.MapPath(finalPath)); bitmap.Dispose(); thumbImg.Dispose(); gps.Dispose(); finalImg.Dispose(); GC.Collect(); PubClass.FileDel(HttpContext.Current.Server.MapPath(imgUrl)); context.Response.Write(finalPath); } } catch (Exception) { throw; } } public bool IsReusable { get { return false; } } }
这种就可以达到我文章开头的要求了
第三步:修复文件开头提到Uploadify用Session在Chrome和FireFox下的Bug (身份验证也一样有这个BUG,修复同理) |
如果UploadAvatarHandler.ashx中要用到Session那就需求些额外的配置
在Global.asax中Application_BeginRequest加入下列代码
protected void Application_BeginRequest(object sender, EventArgs e) { //为了Uploadify在谷歌和火狐下不能上传的BUG try { string session_param_name = "ASPSESSID"; string session_cookie_name = "ASP.NET_SessionId"; if (HttpContext.Current.Request.Form[session_param_name] != null) { UpdateCookie(session_cookie_name, HttpContext.Current.Request.Form[session_param_name]); } else if (HttpContext.Current.Request.QueryString[session_param_name] != null) { UpdateCookie(session_cookie_name, HttpContext.Current.Request.QueryString[session_param_name]); } } catch { } //此处是身份验证 try { string auth_param_name = "AUTHID"; string auth_cookie_name = FormsAuthentication.FormsCookieName; if (HttpContext.Current.Request.Form[auth_param_name] != null) { UpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[auth_param_name]); } else if (HttpContext.Current.Request.QueryString[auth_param_name] != null) { UpdateCookie(auth_cookie_name, HttpContext.Current.Request.QueryString[auth_param_name]); } } catch { } }
页面中加入隐藏域
<asp:HiddenField ID="hdSessionId" runat="server" />
并在页面的Load事件中,把SessionID赋给隐藏域
Uploadify()方法scriptData属性在做修改
$('#uploadify').uploadify({ //.... 'scriptData': { 'ASPSESSID': $('[id$=hdSessionId]').val() }, //..... });
以上操作,用于修改身份验证也一样。。。
第四步:一些扩展 |
CutPic.js中有一些可以扩展
比如:有人要求截图区域自己要可以拖动
把CutPic.js图片显示,截图区HTML变成这样
<div id="bgDiv"> <div id="dragDiv"> <div id="rRightDown" style="right: 0; bottom: 0;"> </div> <div id="rLeftDown" style="left: 0; bottom: 0;"> </div> <div id="rRightUp" style="right: 0; top: 0;"> </div> <div id="rLeftUp" style="left: 0; top: 0;"> </div> <div id="rRight" style="right: 0; top: 50%;"> </div> <div id="rLeft" style="left: 0; top: 50%;"> </div> <div id="rUp" style="top: 0; left: 50%;"> </div> <div id="rDown" style="bottom: 0; left: 50%;"> </div> </div> </div>
再给这些新添DIV写些样式。。。^_^! 这里自己扩展吧
显示区的JS加上最后一个参数
function ShowImg(imagePath,imgWidth,imgHeight) { var imgPath = imagePath != "" ? imagePath : "!images/ef_pic.jpg"; var ic = new ImgCropper("bgDiv", "dragDiv", imgPath, imgWidth, imgHeight, { Right: "rRight", Left: "rLeft", Up: "rUp", Down: "rDown", RightDown: "rRightDown", LeftDown: "rLeftDown", RightUp: "rRightUp", LeftUp: "rLeftUp"}); }
可能还有需求上传不要进度条,这个我没找到属性,有用过的可以指点一下,
不过这个问题没有属性也不是不可以解决的,可以在uploadify的JS文件中删除或注释掉append的这一段进度条HTML代码。
这样就做完了,Uploadify和这个CutPic.js几乎能做到所有现在能看到的上传截图功能,还有的自己扩展一下^-^!
PS:示例代码没有优化,请各位自己做做优化^_^!
Demo下载:VS08: http://files.cnblogs.com/zhongweiv/CutAvatarVS08.rar
VS10: http://files.cnblogs.com/zhongweiv/CutAvatarVS10.rar
(大家在看这个Demo时好像遇到不少问题,我帮大家转好了08和10的,各位可以下载,IIS的配置还是那样)
Demo友情提示:布署在IIS上,再看,因为示例路径全是从根目录开始
对于各位看官的疑问解答: |
-----------------------------------------------------------------------------------------------------------------------------------
1.Demo相关(因为个人习惯,写东西喜欢布暑在IIS中,路径从根目录开始,所以直接看,带来了些不便^_^!)
如果没有显示出FLash上传的,那一定是路径有问题
对于Demo再加些操作提示,可能很多人没有用过自定义端服务器:
1.布暑在IIS里,设置好端口号,如果是4.0环境,应用程序连接池选择framework4.0
2.在VS中设置,选中网站项目,右键---->属性页---->启动选项---->选择自定义服务器---->基URL填入你在IIS里设置的,比如:http://localhost:XXXX/ (XXXX代表你在IIS里设置的端口号)
3.确实,运行页面
如果用VS10转化,在IIS里布暑点击保存出来error
那有两种可能
1.连接池framework的版本你还是没选对
2,ISAPI和GCI限制里asp.net4.0没有设置为允许。。。
如果这个Demo会出错。。那你转成4.0之后编译应该就会报targetFramework的错。。。。如果实在没有什么IIS的设置经验,建议自己搜索一下或者看看IIS方面的文章
-----------------------------------------------------------------------------------------------------------------------------------
2.onComplete事件方法中几个参数的解释:
event:名字就很明显了
queueId 就是个唯一标识
fileObj 这是指那个文件
比如:fileObj.name 就是文件名
fileObj.size 是文件大小
上传文件的相关信息都可以用这个获得,还有创建时间,文件类型 等
response:这是你返回的信息
data:有四个属性
filesUploaded :上传了多少个文件
errors :出现了多少个错误
allBytesLoaded :总共上传文件的大小(因为它可以多文件上传)
speed :这是上传速度
原文链接 :http://www.cnblogs.com/zhongweiv/archive/2011/11/29/2266544.html