ASP.NET 中使用 Plupload 上传图片
最近弄项目需要一个异步的图片上传图片组件,首先选择了 swfupload,但是在使用中发现火狐下莫名其妙的会丢失 Session(不使用 global.asax 的情况下,没有找到完美的解决方案),后来找到了 Plupload,便去了解了一下。
Plupload官网:http://www.plupload.com
它是一个开源组件!功能的确很强大!
它主要功能是多文件上传,并提供图片客户端尺寸压缩。主要的特色是可以使用 Flash Gears HTML 5 Silverlight BrowserPlus HTML 4 等多项技术实现!
官网上的实例是用php写的,后来在http://www.cnblogs.com/zjfree/archive/2010/12/27/1918400.html找到了.net版的,我根据自己的需求做了些调整,美化了一下界面样式,调整了js代码,自己写了后台代码。
这是我参考了swfupload上传之后在页面上显示缩略图的效果图。
HTML代码:
<!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"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>\</title> <script language="javascript" type="text/javascript" src="/Static/Script/plupload/jquery.plupload.queue.min.js"></script> <script language="javascript" type="text/javascript" src="/Static/Script/plupload/plupload.min.js"></script> <script language="javascript" type="text/javascript" src="/Static/Script/plupload/plupload.flash.min.js"></script> </head> <body> <div id="flash_uploader" style="width: 600px; height: 330px;"> 请检查您的Flash插件是否正确安装!</div> <div id="thumbnails"> </div> <script type="text/javascript"> $(function () { // 初始化Flash上传插件 $("#flash_uploader").pluploadQueue({ runtimes: 'flash', //使用Flash插件 url: '/Services.aspx?act=Upload', //服务器端响应页面 max_file_size: '10mb', //最大文件限制 file_size: '1mb', //一次上传数据大小 unique_names: true, //是否自动生成唯一名称 filters: [ //文件类型限制 {title: "图片文件", extensions: "jpg,gif,png" }, { title: "压缩文件", extensions: "zip,rar" } ], // 缩放图片 // resize: { width: 320, height: 240, quality: 80 }, // SWF文件位置 flash_swf_url: '/Static/Script/plupload/plupload.flash.swf', init: { FileUploaded: function (up, file, info) { if (info.response != null) { var jsonstr = eval("(" + info.response + ")"); var thumbnailUrl = jsonstr[0].thumbnailUrl; var originalUrl = jsonstr[0].originalUrl; var name = jsonstr[0].name; //一个文件上传成功 addImage(name, originalUrl, thumbnailUrl); } }, Error: function (up, args) { //发生错误 if (args.file) { alert('[error] File:' + args.file); } else { alert('[error]' + args); } } } }); }); </script> </body> </html>
后台代码:
HttpContext context = HttpContext.Current; string savePath = PathConfig.UploadPath(); //上传文件的路径 string uploadFileUrl = PathConfig.UploadUrl(); //上传文件的URL HttpPostedFile uploadFile = context.Request.Files["file"]; try { //验证文件夹是否存在 if (!Directory.Exists(savePath)) { Directory.CreateDirectory(savePath); } string fileName = uploadFile.FileName; string name = DateTime.Now.ToString("yyyyMMddHHmmssfff"); if (fileName.LastIndexOf(".") > -1) { string fileExt = fileName.Substring(fileName.LastIndexOf(".")); string saveName = name + fileExt; uploadFile.SaveAs(savePath + saveName); string originalUrl = uploadFileUrl + saveName; Image original_image = Image.FromStream(uploadFile.InputStream); string thumbnail_id = name; MemoryStream ms = new MemoryStream(); ms = ImageProcess.MakeThumbnail(original_image, 100, 100); Image thumbnail = Image.FromStream(ms); string imagePath = savePath + name + "-Thumbnail" + fileExt; thumbnail.Save(imagePath, System.Drawing.Imaging.ImageFormat.Jpeg); ThumbnailInfo thumb = new ThumbnailInfo(thumbnail_id, ms.GetBuffer()); string thumbnailUrl = uploadFileUrl + name + "-Thumbnail" + fileExt; List<ThumbnailInfo> thumbnails = context.Session["file_info"] as List<ThumbnailInfo>; if (thumbnails == null) { thumbnails = new List<ThumbnailInfo>(); context.Session["file_info"] = thumbnails; } thumbnails.Add(thumb); context.Response.StatusCode = 200; context.Response.Write("[{'name':'" + name + "','originalUrl':'" + originalUrl + "','thumbnailUrl':'" + thumbnailUrl + "'}]"); } else { context.Response.StatusCode = 500; context.Response.Write("error"); context.Response.End(); }
jquery.plupload.queue.min.js代码:
(function (c) { var d = {}; function a(e) { return plupload.translate(e) || e } function b(f, e) { e.contents().each(function (g, h) { h = c(h); if (!h.is(".plupload")) { h.remove() } }); e .prepend('<div class="plupload_wrapper plupload_scroll"><div id="' + f + '_container" class="plupload_container"><div class="plupload"><div class="plupload_content"><div class="plupload_filelist_header"><div class="plupload_file_name">' + a("文件名称") + '</div><div class="plupload_file_action"> </div><div class="plupload_file_status"><span>' + a("文件状态") + '</span></div><div class="plupload_file_size">' + a("文件大小") + '</div><div class="plupload_clearer"> </div></div><ul id="' + f + '_filelist" class="plupload_filelist"></ul><div class="plupload_filelist_footer"><div class="plupload_file_name"><div class="plupload_buttons"><a href="#" class="plupload_button plupload_add">' + a("添加文件") + '</a><a href="#" class="plupload_button plupload_start">' + a("开始上传") + '</a></div><span class="plupload_upload_status"></span><div class="plupload_progress"><div class="plupload_progress_container"><div class="plupload_progress_bar"></div></div></div></div><div class="plupload_file_action"></div><div class="plupload_file_status"><span class="plupload_total_status">0%</span></div><div class="plupload_file_size"><span class="plupload_total_file_size">0 b</span></div><div class="plupload_clearer"> </div></div></div></div></div><input type="hidden" id="' + f + '_count" name="' + f + '_count" value="0" /></div>') } c.fn.pluploadQueue = function (e) { if (e) { this.each(function () { var j, i, k; i = c(this); k = i.attr("id"); if (!k) { k = plupload.guid(); i.attr("id", k) } j = new plupload.Uploader(c.extend({ dragdrop: true, container: k }, e)); d[k] = j; function h(l) { var m; if (l.status == plupload.DONE) { m = "plupload_done" } if (l.status == plupload.FAILED) { m = "plupload_failed" } if (l.status == plupload.QUEUED) { m = "plupload_delete" } if (l.status == plupload.UPLOADING) { m = "plupload_uploading" } c("#" + l.id).attr("class", m).find("a").css("display", "block") } function f() { c("span.plupload_total_status", i).html(j.total.percent + "%"); c("div.plupload_progress_bar", i).css("width", j.total.percent + "%"); c("span.plupload_upload_status", i).text("已上传 " + j.total.uploaded + "/" + j.files.length + " 文件。") } function g() { var m = c("ul.plupload_filelist", i).html(""), n = 0, l; c.each(j.files, function (p, o) { l = ""; if (o.status == plupload.DONE) { if (o.target_name) { l += '<input type="hidden" name="' + k + "_" + n + '_tmpname" value="' + plupload.xmlEncode(o.target_name) + '" />' } l += '<input type="hidden" name="' + k + "_" + n + '_name" value="' + plupload.xmlEncode(o.name) + '" />'; l += '<input type="hidden" name="' + k + "_" + n + '_status" value="' + (o.status == plupload.DONE ? "done" : "failed") + '" />'; n++; c("#" + k + "_count").val(n) } m .append('<li id="' + o.id + '"><div class="plupload_file_name"><span>' + o.name + '</span></div><div class="plupload_file_action"><a href="#"></a></div><div class="plupload_file_status">' + o.percent + '%</div><div class="plupload_file_size">' + plupload.formatSize(o.size) + '</div><div class="plupload_clearer"> </div>' + l + "</li>"); h(o); c("#" + o.id + ".plupload_delete a").click(function (q) { c("#" + o.id).remove(); j.removeFile(o); q.preventDefault() }) }); c("span.plupload_total_file_size", i).html(plupload .formatSize(j.total.size)); if (j.total.queued === 0) { c("span.plupload_add_text", i).text(a("Add files.")) } else { c("span.plupload_add_text", i).text(j.total.queued + " files queued.") } c("a.plupload_start", i) .toggleClass( "plupload_disabled", j.files.length == (j.total.uploaded + j.total.failed)); m[0].scrollTop = m[0].scrollHeight; f(); if (!j.files.length && j.features.dragdrop && j.settings.dragdrop) { c("#" + k + "_filelist") .append('<li class="plupload_droptext">' + a("Drag files here.") + "</li>") } } j.bind("UploadFile", function (l, m) { c("#" + m.id).addClass("plupload_current_file") }); j.bind("Init", function (l, m) { b(k, i); if (!e.unique_names && e.rename) { c("#" + k + "_filelist div.plupload_file_name span", i) .live("click", function (s) { var q = c(s.target), o, r, n, p = ""; o = l .getFile(q.parents("li")[0].id); n = o.name; r = /^(.+)(\.[^.]+)$/.exec(n); if (r) { n = r[1]; p = r[2] } q .hide() .after('<input type="text" />'); q.next().val(n).focus().blur( function () { q.show().next() .remove() }).keydown(function (u) { var t = c(this); if (u.keyCode == 13) { u.preventDefault(); o.name = t.val() + p; q.text(o.name); t.blur() } }) }) } c("a.plupload_add", i).attr("id", k + "_browse"); l.settings.browse_button = k + "_browse"; if (l.features.dragdrop && l.settings.dragdrop) { l.settings.drop_element = k + "_filelist"; c("#" + k + "_filelist") .append('<li class="plupload_droptext">' + a("Drag files here.") + "</li>") } c("#" + k + "_container").attr("title", ""); c("a.plupload_start", i).click(function (n) { if (!c(this).hasClass("plupload_disabled")) { j.start() } n.preventDefault() }); c("a.plupload_stop", i).click(function (n) { n.preventDefault(); j.stop() }); c("a.plupload_start", i).addClass("plupload_disabled") }); j.init(); j.bind("Error", function (l, o) { var m = o.file, n; if (m) { n = o.message; if (o.details) { n += " (" + o.details + ")" } if (o.code == plupload.FILE_SIZE_ERROR) { alert(a("Error: File to large: ") + m.name) } if (o.code == plupload.FILE_EXTENSION_ERROR) { alert(a("Error: Invalid file extension: ") + m.name) } c("#" + m.id).attr("class", "plupload_failed") .find("a").css("display", "block").attr( "title", n) } }); j.bind("StateChanged", function () { if (j.state === plupload.STARTED) { c("li.plupload_delete a,div.plupload_buttons", i) .hide(); c( "span.plupload_upload_status,div.plupload_progress,a.plupload_stop", i).css("display", "block"); c("span.plupload_upload_status", i).text("已上传 " + j.total.uploaded + "/" + j.files.length + " 文件"); if (e.multiple_queues) { c( "span.plupload_total_status,span.plupload_total_file_size", i).show() } } else { g(); c("a.plupload_stop,div.plupload_progress", i).hide(); c("a.plupload_delete", i).css("display", "block") } }); j.bind("QueueChanged", g); j.bind("FileUploaded", function (l, m) { h(m) }); j.bind("UploadProgress", function (l, m) { c("#" + m.id + " div.plupload_file_status", i) .html(m.percent + "%"); h(m); f(); if (e.multiple_queues && j.total.uploaded + j.total.failed == j.files.length) { c(".plupload_buttons,.plupload_upload_status", i).css( "display", "inline"); c(".plupload_start", i).addClass("plupload_disabled"); c( "span.plupload_total_status,span.plupload_total_file_size", i).hide() } }); if (e.setup) { e.setup(j) } }); return this } else { return d[c(this[0]).attr("id")] } } })(jQuery); function addImage(name,originalUrl, thumbnailUrl) { var newImg = document.createElement("img"); newImg.style.margin = "5px"; newImg.setAttribute("class", "thumbnail"); newImg.setAttribute("onclick", "InsertImages('" + name + "','" + originalUrl + "', '" + thumbnailUrl + "')"); document.getElementById("thumbnails").appendChild(newImg); if (newImg.filters) { try { newImg.filters.item("DXImageTransform.Microsoft.Alpha").opacity = 0; } catch (e) { // If it is not set initially, the browser will throw an error. This will set it if it is not set yet. newImg.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + 0 + ')'; } } else { newImg.style.opacity = 0; } newImg.onload = function () { fadeIn(newImg, 0); }; newImg.src = thumbnailUrl; // alert(src); } function fadeIn(element, opacity) { var reduceOpacityBy = 5; var rate = 30; // 15 fps if (opacity < 100) { opacity += reduceOpacityBy; if (opacity > 100) { opacity = 100; } if (element.filters) { try { element.filters.item("DXImageTransform.Microsoft.Alpha").opacity = opacity; } catch (e) { // If it is not set initially, the browser will throw an error. This will set it if it is not set yet. element.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + opacity + ')'; } } else { element.style.opacity = opacity / 100; } } if (opacity < 100) { setTimeout(function () { fadeIn(element, opacity); }, rate); } } function uploadError(file, errorCode, message) { var imageName = "error.gif"; var progress; try { switch (errorCode) { case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED: try { progress = new FileProgress(file, this.customSettings.upload_target); progress.setCancelled(); progress.setStatus("Cancelled"); progress.toggleCancel(false); } catch (ex1) { this.debug(ex1); } break; case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED: try { progress = new FileProgress(file, this.customSettings.upload_target); progress.setCancelled(); progress.setStatus("Stopped"); progress.toggleCancel(true); } catch (ex2) { this.debug(ex2); } case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED: imageName = "uploadlimit.gif"; break; default: alert(message); break; } addImage("/Static/Images/swfupload/" + imageName); } catch (ex3) { this.debug(ex3); } }
这是我用的样式代码:
/* Plupload ------------------------------------------------------------------- */ .plupload_button { display: -moz-inline-box; /* FF < 3*/ display: inline-block; font: normal 12px sans-serif; text-decoration: none; color: #42454a; border: 1px solid #bababa; padding: 2px 8px 3px 20px; margin-right: 4px; background: #f3f3f3 url('/Static/Images/plupload/buttons.png') no-repeat 0 center; outline: 0; /* Optional rounded corners for browsers that support it */ -moz-border-radius: 3px; -khtml-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; } .plupload_button:hover { color: #000; text-decoration: none; } .plupload_disabled, a.plupload_disabled:hover { color: #737373; border-color: #c5c5c5; background: #ededed url('/Static/Images/plupload/buttons-disabled.png') no-repeat 0 center; cursor: default; } .plupload_add { background-position: -181px center; } .plupload_wrapper { font: normal 12px Verdana,sans-serif; width: 100%; } .plupload_container { padding: 8px 0px; background: url('/Static/Images/plupload/transp50.png'); /*-moz-border-radius: 5px;*/ } .plupload_container input { border: 1px solid #DDD; font: normal 11px Verdana,sans-serif; width: 98%; } .plupload_header { background: #2A2C2E url('/Static/Images/plupload/backgrounds.gif') repeat-x; } .plupload_header_content { background: url('/Static/Images/plupload/backgrounds.gif') no-repeat 0 -317px; min-height: 56px; padding-left: 60px; color: #FFF; } .plupload_header_title { font: normal 18px sans-serif; padding: 6px 0 3px; } .plupload_header_text { font: normal 12px sans-serif; } .plupload_filelist { margin: 0; padding: 0; list-style: none; border-left: 1px solid #99BBE8; border-right: 1px solid #99BBE8; } .plupload_scroll .plupload_filelist { height: 240px; background: #F5F5F5; overflow-y: scroll; } .plupload_filelist li { padding: 10px 8px; background: #F5F5F5 url('/Static/Images/plupload/backgrounds.gif') repeat-x 0 -156px; border-bottom: 1px solid #DDD; } .plupload_filelist_footer { background: #DFDFDF; padding: 8px 8px; color: #42454A; } .plupload_filelist_header { background: url("/Static/Images/plupload/grid3-hrow.gif") repeat-x scroll left bottom #F9F9F9; border-right: 1px solid #99BBE8; cursor: default; white-space: nowrap; padding: 8px; border-left: 1px solid #99BBE8; border-top: 1px solid #99BBE8; } #thumbnails { width: 700px; float: left; } .thumbnail { float: left; } .plupload_filelist_footer { background: url("/Static/Images/plupload/bg.gif") repeat-x scroll left top #D0DEF0; height: 22px; line-height: 20px; vertical-align: middle; border: 1px solid #99BBE8; } .plupload_file_name { float: left; overflow: hidden; width: 60%; } .plupload_upload_status { float:left;} .plupload_file_status { color: #777; } .plupload_file_status span { color: #42454A; } .plupload_file_size, .plupload_file_status, .plupload_progress { float: right; width: 15%; } .plupload_file_size, .plupload_file_status, .plupload_file_action { text-align: right; } .plupload_filelist .plupload_file_name { width: 60%; } .plupload_file_action { float: right; width: 16px; height: 16px; margin-left: 15px; } .plupload_file_action * { display: none; width: 16px; height: 16px; } li.plupload_uploading { background: #ECF3DC url('/Static/Images/plupload/backgrounds.gif') repeat-x 0 -238px; } li.plupload_done { color: #AAA; } li.plupload_delete a { background: url('/Static/Images/plupload/delete.gif'); } li.plupload_failed a { background: url('/Static/Images/plupload/error.gif'); cursor: default; } li.plupload_done a { background: url('/Static/Images/plupload/done.gif'); cursor: default; } .plupload_progress, .plupload_upload_status { display: none; } .plupload_progress_container { margin-top: 3px; border: 1px solid #CCC; background: #FFF; padding: 1px; } .plupload_progress_bar { width: 0px; height: 7px; background: #CDEB8B; } .plupload_file_action, .plupload_scroll .plupload_filelist_footer .plupload_file_action { margin-right: 17px; } /* Floats */ .plupload_clear, .plupload_clearer { clear: both; } .plupload_clearer, .plupload_progress_bar { display: block; font-size: 0; line-height: 0; } li.plupload_droptext { background: transparent; text-align: center; vertical-align: middle; border: 0; line-height: 165px; }
addImage和uploadError 方法是我从swfupload中提取出来的,用于上传成功后自动显示缩略图的,
newImg.setAttribute("onclick", "InsertImages('" + name + "','" + originalUrl + "', '" + thumbnailUrl + "')");是我想点击图片后插入到编辑器中用的。
这应该算一个不完整的程序吧,因为上传失败的方法还没有进行处理,等过段时间我好好整理一下再发布上来,另外我没有上传附件,其他代码可以去xiao张兄那里去下载,然后用我的代码替换相应的部分即可,水平有限让各位高手见笑了。