现在做的项目需要做一些图片处理,由于时间赶急,之前我便没有处理图片,直接将图片放在input[type=file]里面,以文件的形式提交给后台,这样做简直就是最低级的做法,之后各种问题便出来了,人物头像需要正方形,这样做难免出现异性,显示的时候便是各种丑。
项目赶完之后这两天优化本想在网上找一个现成的图片裁剪插件使用,但是在百度上面和jq22上面找了半天找到的都是一些服务器裁剪的事例,加上看别人的代码各种麻烦,简直头大,最后发现一个本地图片处理的插件,便想着不如自己写一个,虽然代码写着乱,但是自己乱写的也比别人好好写的更容易懂不是。哈哈
cropper插件详细api可参考以下链接 jQuery.cropper中文API详解
html
@*定义一个上传的按钮*@
<div class="row" id="bootst">
<label for="" class="lab"><span style="color:red;">*</span>首图上传:</label>
<button id="fileImgs">上传图片</button>
<b>(您可以上传一张首图)</b>
<div class="wap_tol" style="margin-top:10px;">
<ul></ul>
</div>
</div>
@*图片裁剪框弹出层*@
<div id="crop-avatar" class="pop pub_suc_pop" style="display:none">
<div class="pop_tit">
<h4 class="pop_hd">编辑图像</h4>
</div>
<div class="pop_bd" style="text-align:center">
<div class="modal fade" id="avatar-modal" aria-hidden="true" aria-labelledby="avatar-modal-label" role="dialog" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form class="avatar-form" action="/TechShare/SaveCutImg" enctype="multipart/form-data" method="post">
<div class="modal-body">
<div class="avatar-body">
<div class="avatar-upload">
<input class="avatar-src" name="avatar_src" type="hidden">
<input class="avatar-data" name="avatar_data" type="hidden">
<span style="float:left;display:block">请选择图片:</span>
<a class="up-btn" data-bind="TechShare">选择图片</a>
<input type="file" class="fileinput avatar-input" id="avatarInput" name="avatar_file" style="margin-left:0px">
@*accept="image/*"*@
</div>
<div class="row uplow">
<div style="width:75%;float:left;padding:10px;box-sizing: border-box;">
<div class="avatar-wrapper"></div>
</div>
<div style="width: 25%;float: left;padding:10px;box-sizing: border-box;" class="previw-box">
<div class="avatar-preview preview-lg"></div>
<div class="avatar-preview preview-md"></div>
<div class="avatar-preview preview-sm"></div>
</div>
</div>
<div class="btnright">
<a href="javascript:" class="conmit">确定</a>
<a href="javascript:" class="cancel">取消</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="loading" aria-label="Loading" role="img" tabindex="-1"></div>
</div>
<span href="javascript:void(0);" class="a_close" οnclick="$.unblockUI();" name="close_all" id="domMessage2_close"></span>
</div>
上边的是剪裁弹出div,然后引用css样式
<link href="~/Content/Styles/cropper/cropper.min.css" rel="stylesheet" />
<link href="~/Content/Styles/cropper/main.css" rel="stylesheet" />
(找不到样式直接在网上搜索cropper,)
cropper.min.css(http://pan.baidu.com/s/1c2hDBAo)
main.css(http://pan.baidu.com/s/1eRK9b7k)
点击上传图片
jQuery
$("#fileImgs").click(function () {
$.blockUI({
message: $('#crop-avatar'),
css: {
top: '30%',
left: '25%',
textAlign: 'left',
width: '1020px',
background: '#fff'
},
centerX: true,
centerY: true,
});
});
最后是这样的
下班开始引用js,这种js网上也比较过。我的就直接吧最主要的贴出来,直接拿出去拷贝就行
JS
(function (window, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as anonymous module.
define(['jquery', 'bootstrap'], factory);
} else if (typeof exports === 'object') {
// Node / CommonJS
factory(require('jquery'), require('bootstrap'));
} else {
// Browser globals.
window.crop = window.crop || {};
window.crop.CropAvatar = factory($);
}
})(this, function ($) {
'use strict';
var console = window.console || { log: function () { } };
function CropAvatar(options) {
var defaults = {
el: null,
width: 340,
heigth: 340,
mName: '',
uploadbefore: null,
success: null,
error: null
};
var opts = $.extend(defaults, options);
this.$container = $(opts.el);
//this.$avatarView = this.$container.find('.avatar-view');
this.$avatarView = $('#imgUpload');
this.$avatar = this.$avatarView.find('img');
this.$avatarModal = this.$container.find('#avatar-modal');
this.$loading = this.$container.find('.loading');
this.$avatarForm = this.$avatarModal.find('.avatar-form');
this.$avatarUpload = this.$avatarForm.find('.avatar-upload');
this.$avatarSrc = this.$avatarForm.find('.avatar-src');
this.$avatarData = this.$avatarForm.find('.avatar-data');
this.$avatarInput = this.$avatarForm.find('.avatar-input');
this.$avatarWrapper = this.$avatarModal.find('.avatar-wrapper');
this.$avatarPreview = this.$avatarModal.find('.avatar-preview');
this.$avatarSubmit = this.$avatarForm.find('#submit');
this.init();
this.opts = opts;
}
CropAvatar.prototype = {
constructor: CropAvatar,
support: {
fileList: !!$('<input type="file">').prop('files'),
blobURLs: !!window.URL && URL.createObjectURL,
removeURLs: !!window.URL && URL.revokeObjectURL,
formData: !!window.FormData
},
init: function () {
this.support.datauri = this.support.fileList && this.support.blobURLs; this.initModal();
this.addListener();
},
//初始化给按钮绑定事件
addListener: function () {
this.$avatarView.on('click', $.proxy(this.click, this));
this.$avatarInput.on('change', $.proxy(this.change, this));
this.$avatarSubmit.on('click', $.proxy(this.submit, this));
},
//默认不现实上传框
initModal: function () {
this.$avatarModal.modal({
show: false
});
},
//点击事件显示出弹出框
click: function () {
if (this.opts.uploadbefore && typeof this.opts.uploadbefore == "function")
{
if (!this.opts.uploadbefore()) {
return false;
}
}
this.$avatarModal.modal('show');
//this.initPreview();
},
//选中图片,更改图片事件
change: function () {
var files;
var file;
if (this.support.datauri) {
$("div.avatar-body div.alert").remove();
files = this.$avatarInput.prop('files');
if (files.length > 0) {
file = files[0];
if (this.isImageFile(file)) {
if (this.url) {
this.support.removeURLs(this.url); // Revoke the old one
}
this.url = this.support.blobURLs(file);//URL.createObjectURL(file);
this.startCropper();
}
else {
this.alert('请上传图片!');
}
}
} else {
file = this.$avatarInput.val();
if (this.isImageFile(file)) {
this.syncUpload();
}
}
},
//提交开始上传
submit: function () {
$("div.avatar-body div.alert").remove();
if (!this.$avatarSrc.val() && !this.$avatarInput.val()) {
this.alert('请上传图片!');
return false;
}
if (this.support.formData) {
this.ajaxUpload();
return false;
}
},
isImageFile: function (file) {
if (file.type) {
return /^image\/\w+$/.test(file.type);
} else {
return /\.(jpg|jpeg|png|gif)$/.test(file);
}
},
startCropper: function () {
var _this = this;
if (this.active) {
this.$img.cropper('replace', this.url);
} else {
this.$img = $('<img src="' + this.url + '">');
this.$avatarWrapper.empty().html(this.$img);
this.$img.cropper({
aspectRatio: 1,
preview: this.$avatarPreview.selector,
//autoCropArea: 0.8,
crop: function (e) {
var json = [
'{"x":' + e.x,
'"y":' + e.y,
'"height":' + e.height,
'"width":' + e.width,
'"rotate":' + e.rotate + '}'
].join();
_this.$avatarData.val(json);
}
});
this.active = true;
}
this.$avatarModal.one('hidden.bs.modal', function () {
_this.$avatarPreview.empty();
_this.stopCropper();
});
},
stopCropper: function () {
if (this.active) {
this.$img.cropper('destroy');
this.$img.remove();
this.active = false;
}
},
ajaxUpload: function () {
//var cropBoxData = this.$img.cropper('getCropBoxData');//截取后的文件
//var imageRate = 1;//图片保存的缩放比例
//var width = cropBoxData.width * imageRate;
//var height = cropBoxData.height * imageRate;
//alert(this.opts.width);
//var moduleName = this.$avatarView.attr("data-bind");
//var width = 340;
//var height = 340;
//if (moduleName == "TechShare") {
// width = 341;
// height = 321;
//} else if (moduleName == "BrandProduct") {
// width = 350;
// height = 300;
//} else if (moduleName == "ProductCase") {
// width = 136;
// height = 175;
//} else if (moduleName == "News") {
// width = 175;
// height = 136;
//}
//生成结果canvas,这里决定图片保存的高宽
var croppedCanvas = this.$img.cropper('getCroppedCanvas', {
width: this.opts.width,
height: this.opts.height
});
var result = null;//要返回的最后结果
var encoderOptions = 0.8;//图片保存质量
//如果是base64格式,那么获取源文件类型进行保存,否则图片默认保存为jpeg
result = croppedCanvas.toDataURL('image/png', encoderOptions);
//url可以写死,也可以自己定义
var url = this.$avatarForm.attr('action');
var data = new FormData(this.$avatarForm[0]);
var _this = this;
data.append("imgBase64", result);
data.append("moduleName", this.opts.mName);
//自己上传阿里云 或者本地服务器
$.ajax(url, {
type: 'post',
data: data,
dataType: 'json',
processData: false,
contentType: false,
beforeSend: function () {
_this.submitStart();
},
//上传成功后,返回的data就是成功后的地址,可以根据data调用的事件再前台显示出来
success: function (data) {
_this.submitDone(data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
_this.submitFail(textStatus || errorThrown);
},
complete: function () {
_this.submitEnd();
}
});
},
syncUpload: function () {
this.$avatarSubmit.click();
},
submitStart: function () {
this.$loading.fadeIn();
},
//成功后调用的事件
//这边可以直接把成功后的图片显示,
submitDone: function (data) {
if (data) {
if (this.opts.success && typeof this.opts.success == "function")
{
this.url = data;
if (this.support.datauri || this.uploaded) {
this.uploaded = false;
if (this.url) {
this.opts.success(this.url);
}
this.cropDone();
}
else {
this.uploaded = true;
this.$avatarSrc.val(this.url);
this.startCropper();
}
this.$avatarInput.val('');
}
else {
this.alert('请写回调函数!');
}
}
else {
this.alert('上传失败!');
}
},
submitFail: function (msg) {
if (this.opts.error && typeof this.opts.error == "function") {
this.opts.error();
} else {
this.alert(msg);
}
},
submitEnd: function () {
this.$loading.fadeOut();
},
cropDone: function () {
this.$avatarForm.get(0).reset();
this.$avatar.attr('src', this.url);
this.stopCropper();
this.$avatarModal.modal('hide');
},
alert: function (msg) {
var $alert = [
'<div class="alert alert-danger avatar-alert alert-dismissable">',
'<button type="button" class="close" data-dismiss="alert">×</button>',
msg,
'</div>'
].join('');
this.$avatarUpload.after($alert);
}
};
return CropAvatar;
//这段是初始化,前边再页面jQuery已经写过上传,这句话就不需要了,没写的话可以直接初始化调用
//$(function () {
// return new CropAvatar($('#crop-avatar'));
//});
});
C#后台上传本地
这个上传是根据日期来的,不同存放到一个文件件 ,图片多了就卡死,所以会根据日期创建多个文件夹,也便于后期好查询
public ActionResult SaveCutImg(string imgBase64)
{
String fileName = imgBase64;
String fileExt = ".png";//扩展名
string savePath = "/Attachment/images/";//存放项目的地址
string dirPath = Server.MapPath(savePath);
string Thumbname = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", DateTimeFormatInfo.InvariantInfo);
String newFileName = Thumbname + fileExt;
//判断是否有这个地址文件夹,没有就创建一个
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
dirPath += DateTime.Now.ToString("yyyy-MM") + "/";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
String filePath = dirPath + newFileName;
try
{
//图片保存格式
//fileFullPath = fileFullPath + guid + ".png";
//将二进制图片保存到服务器
byte[] arr = Convert.FromBase64String(imgBase64.Substring(22));
System.IO.MemoryStream ms = new System.IO.MemoryStream(arr);
System.Drawing.Image img = System.Drawing.Image.FromStream(ms);
img.Save(Path.Combine(dirPath, newFileName), System.Drawing.Imaging.ImageFormat.Png);
//暂且不需要保留三个业所图片,服务器压力大,留着备用
//下边是为了用不同环境,头像图片和显示图片像素不一样大才做的,这边不考虑。
//大图,中图,小图压缩好的
//string fullFilePath = savePath + DateTime.Now.ToString("yyyy-MM") + "/" + newFileName;
// var path2 = fullFilePath.Substring(0, fullFilePath.LastIndexOf('/') + 1) + Thumbname + "_360_360" + fileExt;
// ThumbnailHelper.MakeThumbnail(Path.Combine(dirPath, newFileName), this.Server.MapPath(path2), 360, 360, "HW");//切图
// var path3 = fullFilePath.Substring(0, fullFilePath.LastIndexOf('/') + 1) + Thumbname + "_65_65" + fileExt;
// ThumbnailHelper.MakeThumbnail(Path.Combine(dirPath, newFileName), this.Server.MapPath(path3), 65, 65, "HW");//切图
// var path4 = fullFilePath.Substring(0, fullFilePath.LastIndexOf('/') + 1) + Thumbname + "_160_180" + fileExt;
// ThumbnailHelper.MakeThumbnail(Path.Combine(dirPath, newFileName), this.Server.MapPath(path4), 160, 180, "HW");//切图
return Json(savePath + DateTime.Now.ToString("yyyy-MM") + "/" + newFileName);
}
catch (Exception ex)
{
ModelState.AddModelError("", "保存文件时发生异常,异常信息:" + ex.Message + "");
return Json("ex.Message ");
}
}