博客园头像上传源码
1、首先图片上传是一般网站都需要的,所以有必要自己整一个。
2、比较了好几个网站的图片上传功能,感觉博客园的比较好实现
3、看了下脚本,选用的是fineuploader+Jcrop,这个大家自己下吧,这里就不提供网址了。
4、效果图:



5、功能很简单,主要是预览,裁剪,保存,这样的插件有很多,但是本人没有选swf的,原因大家都知道。
6、重点和难点,由于fineuploader不兼容ie10以下版本,所以你会发现在ie8这个插件根本没办法执行,但是博客园却实现了上传功能,所以我坚信有解决办法(困扰我很久的问题)
不多说,直接上代码了。
感谢MVC版上传功能(这个版本有些问题,所以这个只能学习用。)
下面是修正的asp.net webform版本(已解决博客园在ie下重复上传出现失败的情况)
CSS
.qq-uploader {
position: relative;
width: 100%;
}
.qq-upload-button {
display: block;
/*or inline-block*/
width: 105px;
padding: 7px 0;
text-align: center;
background: #880000;
border-bottom: 1px solid #DDD;
color: #FFF;
}
.qq-upload-button-hover {
background: #CC0000;
}
.qq-upload-button-focus {
outline: 1px dotted #000000;
}
.qq-upload-drop-area, .qq-upload-extra-drop-area {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
min-height: 30px;
z-index: 2;
background: #FF9797;
text-align: center;
}
.qq-upload-drop-area span {
display: block;
position: absolute;
top: 50%;
width: 100%;
margin-top: -8px;
font-size: 16px;
}
.qq-upload-extra-drop-area {
position: relative;
margin-top: 50px;
font-size: 16px;
padding-top: 30px;
height: 20px;
min-height: 40px;
}
.qq-upload-drop-area-active {
background: #FF7171;
}
.qq-upload-list {
margin: 0;
padding: 0;
list-style: none;
}
.qq-upload-list li {
margin: 0;
padding: 9px;
line-height: 15px;
font-size: 16px;
background-color: #FFF0BD;
}
.qq-upload-file, .qq-upload-spinner, .qq-upload-size, .qq-upload-cancel, .qq-upload-retry, .qq-upload-failed-text, .qq-upload-finished {
margin-right: 12px;
}
.qq-upload-file {
}
.qq-upload-spinner {
display: inline-block;
background: url("loading.gif");
width: 15px;
height: 15px;
vertical-align: text-bottom;
}
.qq-upload-finished {
display:none;
width:15px;
height:15px;
vertical-align:text-bottom;
}
.qq-upload-retry {
display: none;
color: #000000;
}
.qq-upload-cancel {
color: #000000;
}
.qq-upload-retryable .qq-upload-retry {
display: inline;
}
.qq-upload-size, .qq-upload-cancel, .qq-upload-retry {
font-size: 12px;
font-weight: normal;
}
.qq-upload-failed-text {
display: none;
font-style: italic;
font-weight: bold;
}
.qq-upload-failed-icon {
display:none;
width:15px;
height:15px;
vertical-align:text-bottom;
}
.qq-upload-fail .qq-upload-failed-text {
display: inline;
}
.qq-upload-retrying .qq-upload-failed-text {
display: inline;
color: #D60000;
}
.qq-upload-list li.qq-upload-success {
background-color: #5DA30C;
color: #FFFFFF;
}
.qq-upload-list li.qq-upload-fail {
background-color: #D60000;
color: #FFFFFF;
}
.qq-progress-bar {
background: -moz-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(30,87,153,1)), color-stop(50%,rgba(41,137,216,1)), color-stop(51%,rgba(32,124,202,1)), color-stop(100%,rgba(125,185,232,1))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, rgba(30,87,153,1) 0%,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(30,87,153,1) 0%,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(30,87,153,1) 0%,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%); /* IE10+ */
background: linear-gradient(to bottom, rgba(30,87,153,1) 0%,rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%,rgba(125,185,232,1) 100%); /* W3C */
width: 0%;
height: 15px;
border-radius: 6px;
margin-bottom: 3px;
display: none;
}
/*自定义样式*/
body {
font-size: 12px;
font-family: Verdana,Arial,Helvetica,sans-serif;
margin: 0;
padding: 10px;
background: none repeat scroll 0 0;
}
li.alert-success {
background-color: #DFF0D8;
}
li.alert-error {
background-color: #F2DEDE;
}
[class*="span"] {
float: left;
min-height: 1px;
margin-left: 20px
}
[class^="icon-"],[class*=" icon-"] {
display: inline-block;
width: 14px;
height: 14px;
margin-top: 1px;
line-height: 14px;
vertical-align: text-top;
background-image: url("../themes/icons/glyphicons-halflings-white.png");
background-position:-144px -24px;
background-repeat: no-repeat
}
.btn {
display: inline-block;
padding: 4px 12px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
color: #333;
text-align: center;
text-shadow: 0 1px 1px rgba(255,255,255,0.75);
vertical-align: middle;
cursor: pointer;
background-color: #f5f5f5;
background-image: -moz-linear-gradient(top,#fff,#e6e6e6);
background-image: -webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));
background-image: -webkit-linear-gradient(top,#fff,#e6e6e6);
background-image: -o-linear-gradient(top,#fff,#e6e6e6);
background-image: linear-gradient(to bottom,#fff,#e6e6e6);
background-repeat: repeat-x;
border: 1px solid #bbb;
border-color: #e6e6e6 #e6e6e6 #bfbfbf;
border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
border-bottom-color: #a2a2a2;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
filter: progid: DXImageTransform.Microsoft.gradient(enabled=false);
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)
}
.btn-success {
color: #fff;
text-shadow: 0 -1px 0 rgba(0,0,0,0.25);
background-color: #5bb75b;
background-image: -moz-linear-gradient(top,#62c462,#51a351);
background-image: -webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));
background-image: -webkit-linear-gradient(top,#62c462,#51a351);
background-image: -o-linear-gradient(top,#62c462,#51a351);
background-image: linear-gradient(to bottom,#62c462,#51a351);
background-repeat: repeat-x;
border-color: #51a351 #51a351 #387038;
border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);
filter: progid: DXImageTransform.Microsoft.gradient(enabled=false)
}
.alert {
padding: 8px 35px 8px 14px;
margin-bottom: 20px;
text-shadow: 0 1px 0 rgba(255,255,255,0.5);
background-color: #fcf8e3;
border: 1px solid #fbeed5;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px
}
.container {
width: auto
}
.span12 {
width: 80%
}
HTML
<body> <div id="jquery-wrapped-fine-uploader"></div> <div style="clear:both"></div> <div id="message"></div> <div id="crop_wrap"> <div id="crop_holder"> <div id="crop_area" class="border"> <img id="crop_image" alt="" src="" class="preview-image" style="display:none" /></div> <div id="preview_area"> <div id="preview_title"> 当前头像 </div> <div id="preview_small_text" class="preview-text"> 48px × 48px </div> <div id="preview_small_wrap" class="border"> <img id="preview_small" alt="" src="../images/man.gif" class="preview-image" /> </div> <div id="preview_large_text" class="preview-text">180px × 180px </div> <div id="preview_large_wrap" class="border"> <img id="preview_large" alt="" src="../images/man.gif" class="preview-image" /> </div> </div> </div> <div id="crop_operation" style="display:none;"> <form id="form_crop" action=""> <input type="hidden" name="x" id="x" /> <input type="hidden" name="y" id="y" /> <input type="hidden" name="w" id="w" /> <input type="hidden" name="h" id="h" /> <input type="hidden" name="imgsrc" id="imgsrc" /> <input id="crop_operation_submit" type="button" value="裁切并保存" /> <span id="crop_operation_msg" style="display:none" class="green"></span> </form> </div> <div id="croped_message" class="green"></div> </div> </body>
主要JS
function updateCoords(n) { jQuery("#x").val(n.x), jQuery("#y").val(n.y), jQuery("#w").val(n.w), jQuery("#h").val(n.h) } var croper; $(function () { new Uploader($("#jquery-wrapped-fine-uploader"), function (n) { $("#preview_title").html("头像预览"), $("img.preview-image").each(function () { this.src = n }), $("#imgsrc").val(n), croper ? croper.setImage(n) : croper = new Croper($("#crop_image"), new Previewer([[$("#preview_small"), 48], [$("#preview_large"), 180]])), //防止重复添加click事件 $("#crop_operation_submit").unbind("click"); $("#crop_operation_submit").bind("click", function () { $("#crop_operation_msg").html("操作中...").show(); //保存 $.ajax({ type: "POST", url: "../JsonData/UploadHandler.aspx?action=save&" + $('#form_crop').serialize().replace(/\+/g, " "), cache: false, error: function () { alert('执行失败.', 'warning'); }, success: function (obj) { n = eval(obj); $("#crop_image").attr("src", ""); croper.setImage(""), $("#preview_small").removeAttr("style").attr("src", n.FaceSrc); $("#preview_large").removeAttr("style").attr("src", n.AvatarSrc); $("#crop_operation").hide(); $("#crop_operation_msg").html(""); $("#croped_message").html("裁切并保存成功"); $("#preview_title").html("更新后的头像"); } }); }), $("#crop_operation").show(), $("#croped_message").html("") }); }) var Uploader = function () { var n = function (n, t) { n.fineUploader({ validation: { allowedExtensions: ["png", "gif", "jpg", "jpeg"], sizeLimit: 10485760 }, request: { endpoint: "../JsonData/UploadHandler.aspx?action=upload" }, text: { uploadButton: '<i class="icon-upload icon-white"><\/i> 上传头像图片', dropProcessing: "(支持文件拖放上传,只能上传单张10M以下png、jpg、gif图片)" }, template: '<div class="qq-uploader span12"><pre class="qq-upload-drop-area span12"><span>{dragZoneText}<\/span><\/pre><div class="qq-upload-button btn btn-success" style="width: auto;">{uploadButtonText}<\/div><span class="qq-drop-processing"><span>{dropProcessingText}<\/span><span class="qq-drop-processing-spinner"><\/span><\/span><ul class="qq-upload-list" style="margin-top: 10px;overflow:hidden;"><\/ul><\/div>', classes: { success: "alert alert-success", fail: "alert alert-error" }, multiple: !1 }).on("complete", function (n, i, r, u) { if (u.success) { var f = u.message; f += "?id=" + (new Date).getTime() + Math.floor(Math.random() * 1e3); t(f); } else $("#message").html(u.message) }) }; //裁剪计算方法. return n.prototype = { constructor: n }, n} (), Previewer = function () { var n, t = function (t) { n = t }; return t.prototype = { constructor: t, showAllPreview: function (t) { var i = this.getWidgetSize(), r; width = i[0], height = i[1], r = function (n, t, i) { if (parseInt(n.w) > 0) { var r = i / n.w, u = i / n.h; t.css({ width: Math.round(r * width) + "px", height: Math.round(u * height) + "px", marginLeft: "-" + Math.round(r * n.x) + "px", marginTop: "-" + Math.round(u * n.y) + "px" }).show() } }, $.each(n, function () { r(t, this[0], this[1]) }) }, hideAllPreview: function () { $.each(n, function () { this[0].stop().fadeOut("fast") }) } }, t }(), Croper = function () { var n, t, i = function (i, r) { t = this, i.Jcrop({ onChange: r.showAllPreview, onSelect: updateCoords, aspectRatio: 1 }, function () { n = this, t.setSelect() }) }; return i.prototype = { constructor: i, setImage: function (i) { n.setImage(i, function () { t.setSelect() }) }, setSelect: function () { var t = Math.min.apply(Math, n.getWidgetSize()); n.setSelect([0, 0, t, t]) } }, i }();
一般处理程序
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.IO; using System.Drawing; public partial class JsonData_UploadHandler : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string action = Request.QueryString["action"]; switch (action) { case "upload": string qqfile = Request["qqfile"]; var inputStream = Request.InputStream; if (string.IsNullOrEmpty(qqfile)) { //ie浏览器 HttpPostedFileBase file = new HttpPostedFileWrapper(HttpContext.Current.Request.Files[0]); qqfile = file.FileName; inputStream = file.InputStream; } string uploadFolder = "../UploadFile/TempImg/" + DateTime.Now.ToString("yyyyMM") + "/"; string imgName = DateTime.Now.ToString("ddHHmmssff"); string imgType = qqfile.Substring(qqfile.LastIndexOf(".")); string uploadPath = Server.MapPath(uploadFolder); if (!Directory.Exists(uploadPath)) { Directory.CreateDirectory(uploadPath); } using (var flieStream = new FileStream(uploadPath + imgName + imgType, FileMode.Create)) { inputStream.CopyTo(flieStream); } inputStream.Dispose(); string json = "{\"success\":true,\"message\":\"" + uploadFolder + imgName + imgType + "\"}"; Response.Write(json); break; case "save": int x = Convert.ToInt32(Request["x"]); int y = Convert.ToInt32(Request["y"]); int w = Convert.ToInt32(Request["w"]); int h = Convert.ToInt32(Request["h"]); string imgsrc = Request["imgsrc"].Substring(0, Request["imgsrc"].LastIndexOf("?")); string path = "({\"FaceSrc\":\"" + CropImage.CutImage(imgsrc, x, y, w, h, 48, 48, "_1") + "\"," + "\"AvatarSrc\":\"" + CropImage.CutImage(imgsrc, x, y, w, h, 180, 180, "_2") + "\"})"; Response.Write(path); break; default: Response.Write("参数无效."); break; } Response.End(); } }
图片切割类
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Web; using System.Text.RegularExpressions; public class CropImage { /// <summary> /// 剪裁头像图片 /// </summary> /// <param name="pointX">X坐标</param> /// <param name="pointY">Y坐标</param> /// <param name="imgUrl">被截图图片地址</param> /// <param name="rlSize">截图矩形的大小</param> public static string CutImage(string imgUrl, int pointX = 0, int pointY = 0, int width = 0, int height = 0, int finalWidth = 180, int finalHeight = 180, string suffix = "") { Bitmap bitmap = null; //按截图区域生成Bitmap Image thumbImg = null; //被截图 Graphics gps = null; //存绘图对象 Image finalImg = null; //最终图片 try { if (!string.IsNullOrEmpty(imgUrl)) { bitmap = new Bitmap(width, height); thumbImg = Image.FromFile(HttpContext.Current.Server.MapPath(imgUrl)); gps = Graphics.FromImage(bitmap); //读到绘图对象 gps.DrawImage(thumbImg, new Rectangle(0, 0, width, height), new Rectangle(pointX, pointY, width, height), GraphicsUnit.Pixel); finalImg = GetThumbNailImage(bitmap, finalWidth, finalHeight); //以下代码为保存图片时,设置压缩质量 EncoderParameters ep = new EncoderParameters(); long[] qy = new long[1]; qy[0] = 80;//设置压缩的比例1-100 EncoderParameter eParam = new EncoderParameter(Encoder.Quality, qy); ep.Param[0] = eParam; ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders(); ImageCodecInfo jpegICIinfo = null; for (int x = 0; x < arrayICI.Length; x++) { if (arrayICI[x].FormatDescription.Equals("JPEG")) { jpegICIinfo = arrayICI[x]; break; } } string finalUrl = imgUrl.Replace("TempImg", "HeaderImg"); finalUrl = finalUrl.Replace(".jpg", suffix + ".jpg"); string finalPath = HttpContext.Current.Server.MapPath(finalUrl); string finalPathDir = finalPath.Substring(0, finalPath.LastIndexOf("\\")); if (!Directory.Exists(finalPathDir)) { Directory.CreateDirectory(finalPathDir); } if (jpegICIinfo != null) { finalImg.Save(finalPath, jpegICIinfo, ep); } else { finalImg.Save(finalPath); } return finalUrl; } return ""; } catch (Exception ex) { throw ex; } finally { bitmap.Dispose(); thumbImg.Dispose(); gps.Dispose(); finalImg.Dispose(); GC.Collect(); } } ///<summary> /// 对给定的一个图片(Image对象)生成一个指定大小的缩略图。 ///</summary> ///<param name="originalImage">原始图片</param> ///<param name="thumMaxWidth">缩略图的宽度</param> ///<param name="thumMaxHeight">缩略图的高度</param> ///<returns>返回缩略图的Image对象</returns> public static Image GetThumbNailImage(Image originalImage, int thumMaxWidth, int thumMaxHeight) { Size thumRealSize = Size.Empty; Image newImage = originalImage; Graphics graphics = null; try { //thumRealSize = GetNewSize(thumMaxWidth, thumMaxHeight, originalImage.Width, originalImage.Height); thumRealSize = new Size(thumMaxWidth, thumMaxHeight); newImage = new Bitmap(thumRealSize.Width, thumRealSize.Height); graphics = Graphics.FromImage(newImage); graphics.DrawImage(originalImage, new Rectangle(0, 0, thumRealSize.Width, thumRealSize.Height), new Rectangle(0, 0, originalImage.Width, originalImage.Height), GraphicsUnit.Pixel); } catch (Exception ex) { throw ex; } finally { if (graphics != null) { graphics.Dispose(); graphics = null; } } return newImage; } ///<summary> /// 获取一个图片按等比例缩小后的大小。 ///</summary> ///<param name="maxWidth">需要缩小到的宽度</param> ///<param name="maxHeight">需要缩小到的高度</param> ///<param name="imageOriginalWidth">图片的原始宽度</param> ///<param name="imageOriginalHeight">图片的原始高度</param> ///<returns>返回图片按等比例缩小后的实际大小</returns> public static Size GetNewSize(int maxWidth, int maxHeight, int imageOriginalWidth, int imageOriginalHeight) { double w = 0.0; double h = 0.0; double sw = Convert.ToDouble(imageOriginalWidth); double sh = Convert.ToDouble(imageOriginalHeight); double mw = Convert.ToDouble(maxWidth); double mh = Convert.ToDouble(maxHeight); if (sw < mw && sh < mh) { w = sw; h = sh; } else if ((sw / sh) > (mw / mh)) { w = maxWidth; h = (w * sh) / sw; } else { h = maxHeight; w = (h * sw) / sh; } return new Size(Convert.ToInt32(w), Convert.ToInt32(h)); } }
按钮图片(需要的话与本人联系,是博客园的原图)
测试环境,chrome,ie8,360
有好的建议、不明白的地方。可以联系我,在此提供qq号:512948935。目前正在找工作。

浙公网安备 33010602011771号