Jcrop插件本身并不含有图片截取功能,它仅仅是在前端层面构建一套截取动画效果并产生4个坐标点,插件使用者将这4个坐标点传回至服务器接口上进行截取操作。其优点是具有较高的通用性、浏览器兼容性(IE6+)及稳定性高,缺点是无法适用于手机H5开发(无图片缩放、拖拽效果)。
最新版的Jcrop已更新到v3.0+了,本文基于 v0.9.12,由于这版本之间API及使用方式差异非常大,故本文不具备 Jcrop v3.0+ 的使用参考价值,请读者悉知。
Jcrop V0.9+ 下载地址:http://deepliquid.com/content/Jcrop.html
Jcrop V0.9+ API中文说明:https://blog.csdn.net/xht555/article/details/43407141?utm_source=blogxgwz6
Jcrop V3.0+ 下载地址: https://github.com/tapmodo/Jcrop
html代码,这里没放出Jcrop.js、jcrop.css的引用,请读者不要漏了这关键的两步。
???<div > ???????<h3> ???????????5、上传头像实例(预览\截取) ???????</h3> ???????<!--图片上传表单,读者也可以选择其他的上传方式--> ???????<form enctype="multipart/form-data" action="./UploadPhoto" method="post"> ???????????<input name="UserPhoto" type="file" value="" /> ???????????<input type="submit" value="提交上传" ?/> ???????</form> ???????????????<!--截取主要内容区--> ???????<div > ???????????????????????<!--截取区--> ???????????<div > ???????????????<img alt="头像" style="display: none"/> ???????????</div> ???????????<!--预览区,我这里做了两个规格的预览 48*48 180*180 --> ???????????<div > ???????????????<div >当前头像</div> ???????????????<div >48px × 48px</div> ???????????????<div > ???????????????????<img alt="小预览图" src="~/Content/default_48.png"/> ???????????????</div> ???????????????<div >180px × 180px</div> ???????????????<div > ???????????????????<img alt="大预览图" src="~/Content/default_180.png"/> ???????????????</div> ???????????</div> ???????</div> ???????????????<!--截取框坐标点数据保存区,同时也是请求后台截取接口的表单--> ???????<div > ???????????<form action="./CropPhoto" method="post"> ???????????????<input type="hidden" name="url" /> ???????????????<input type="hidden" name="x" /> ???????????????<input type="hidden" name="y" /> ???????????????<input type="hidden" name="w" /> ???????????????<input type="hidden" name="h" /> ???????????????<input type="submit" value="裁剪并保存" /> ???????????</form> ???????</div> ???</div>
JS代码,所需参数
//jcrop 所需参数var jcrop_api;var boundx;var boundy;//上方是必选参数//下方是用于截取预览图的参数,可选的//我这里设置了48*48 180*180 两种规格的预览效果var $pimg_small;var $pimg_large; ????????var xsize_small = 48;var ysize_small = 48;var xsize_large = 180;var ysize_large = 180;$(function() { ???$pimg_small = $(‘#preview_small_img‘); ???$pimg_large = $(‘#preview_large_img‘);});
JS代码,主体逻辑
???//上传图片 ???$(‘#form_upload‘).ajaxForm({ ???????dataType: "json", ???????data:$(‘#form_upload‘).serialize(), ???????success: function (data, textStatus, jqXHR) { ???????????if (data.Status == ‘success‘) { ???????????????//上传成功后,为主截取区、截取预览区的img赋值 ???????????????$("#crop_img,#preview_small_img,#preview_large_img").attr(‘src‘, data.ImgUrl); ???????????????//用input hidden保存返回值,以便截取时使用 ???????????????$("#url").val(data.ImgUrl); ???????????????//if (jcrop_api != null) { ???????????????// ???jcrop_api.setImage(data.ImgUrl, function () { ???????????????// ???????var bounds = jcrop_api.getBounds(); ???????????????// ???????boundx = bounds[0]; ???????????????// ???????boundy = bounds[1]; ???????????????// ???????var size = Math.min(boundx, boundy); ???????????????// ???????jcrop_api.setSelect([0,0,size,size]); ???????????????// ???}); ???????????????//} ???????????????return; ???????????} ???????????if (data.Status == ‘error‘) { ???????????????showMessage(data.Msg); ???????????} ???????}, ???????error: function (jqXHR, textStatus, errorThrown) { ???????????showMessage(‘上传失败‘); ???????????console.error(textStatus); ???????} ???}); ???//当图片加载完毕时,调用Jcrop初始化函数 ???//因为存在多次上传图片的情况,所以此处用<img/>标签的load事件,每加载完毕一次就初始化一次 ???$("#crop_img").load(function () { ???????$("#crop_img").Jcrop({ ???????????onChange: updatePreview,//截取框变化事件,主要用于实时更新预览图 ???????????onSelect: updateCropData,//截取框选定事件,主要用于获得截取框的4个坐标点 ???????????aspectRatio: 1 //截取框的比例,1则是正方形 ???????}, function () { ???????????//$().Jcrop()初始化后的回调函数; ???????????//这里为提高用户体验而设置了一个可选范围内最大的截取框,以告诉用户“你可以进行截取了”。 ???????????jcrop_api = this; ???????????var bounds = this.getBounds();//获取图片实际尺寸,格式为:[w,h] ???????????boundx = bounds[0]; ???????????boundy = bounds[1]; ???????????var size = Math.min(boundx, boundy); ???????????jcrop_api.setSelect([0, 0, size, size]);//4个坐标点设定一个截取框 ???????}); ???});//更新预览图,这函数是官方demo给出的代码,各位可以直接copy不必深究function updatePreview(c) { ???if (parseInt(c.w) > 0) { ???????var rx_large = xsize_large / c.w; ???????var ry_large = ysize_large / c.h; ???????$pimg_large.css({ ???????????width: Math.round(rx_large * boundx) + ‘px‘, ???????????height: Math.round(ry_large * boundy) + ‘px‘, ???????????marginLeft: ‘-‘ + Math.round(rx_large * c.x) + ‘px‘, ???????????marginTop: ‘-‘ + Math.round(ry_large * c.y) + ‘px‘ ???????}); ???????var rx_small = xsize_small / c.w; ???????var ry_small = ysize_small / c.h; ???????$pimg_small.css({ ???????????width: Math.round(rx_small * boundx) + ‘px‘, ???????????height: Math.round(ry_small * boundy) + ‘px‘, ???????????marginLeft: ‘-‘ + Math.round(rx_small * c.x) + ‘px‘, ???????????marginTop: ‘-‘ + Math.round(ry_small * c.y) + ‘px‘ ???????}); ???}};//截取框选定事件的处理函数,用于实时更新4个坐标点function updateCropData(c) { ???jQuery("#x").val(c.x); ???jQuery("#y").val(c.y); ???jQuery("#w").val(c.w); ???jQuery("#h").val(c.h) ???console.group(‘updateCropData‘); ???console.info(c.x) ???console.info(c.y) ???console.info(c.w) ???console.info(c.h) ???console.groupEnd(‘updateCropData‘);} ???//请求后台接口,进行真正的图片截取 ???//因为4个坐标点是由updateCropData()函数实时更新至<form />的隐藏域里的, ???//所以这里只要提交表单即可,这里是使用了jquery.form.js插件,我上一篇文章中有提到jquery.form.js的使用 ???$(‘#form_crop‘).ajaxForm({ ???????dataType: "json", ???????success: function (data, textStatus, jqXHR) { ???????????if (data.Status == ‘success‘) { ???????????????showMessage(‘保存成功‘); ???????????????jcrop_api.destroy();//上传成功后释放jcrop ???????????????return; ???????????} ???????????if (data.Status == ‘error‘) { ???????????????showMessage(data.Msg); ???????????} ???????}, ???????error: function (jqXHR, textStatus, errorThrown) { ???????????showMessage(‘请求错误‘); ???????????console.error(textStatus); ???????} ???});
后台代码。在这里代码较长可能会造成阅读效果不佳,不过在文章末有源码下载可供阅读。
???????[HttpPost] ???????public ActionResult UploadPhoto() ???????{ ???????????HttpPostedFileBase file = Request.Files["UserPhoto"]; ???????????string contentType = file.ContentType; ???????????string extension = Path.GetExtension(file.FileName); ???????????//检查图片格式 ???????????if (!IsAllowImg(contentType, extension)) ???????????{ ???????????????return Json(new { Status = "error", Msg = "上传文件格式不符合要求。" }); ???????????} ???????????//保存形成保存路径 ???????????TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); ???????????string newFileName = Convert.ToInt64(ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) + new Random().Next(100, 999); ???????????string path = Server.MapPath("~/Upload/") + newFileName + ".jpeg"; ???????????//压缩图片、转换格式(jpeg) ???????????Image ResourceImage = Image.FromStream(file.InputStream); ???????????if(ResourceImage.Width>300) ???????????{ ???????????????int dWidth = 300; ???????????????int dHeight = 300 * ResourceImage.Height / ResourceImage.Width; ???????????????CompressPicture(file.InputStream, path, dWidth, dHeight,100); ???????????} ???????????else ???????????{ ???????????????CompressPicture(file.InputStream, path, ResourceImage.Width, ResourceImage.Height, 100); ???????????} ???????????file.InputStream.Close(); ???????????string url = Request.ApplicationPath + "Upload/" + newFileName + ".jpeg"; ???????????return Json(new { Status = "success", Msg = "上传成功",ImgUrl= url }); ???????} ???????#region 压缩图像 ???????/// <summary> ???????/// 无损压缩图片 ???????/// </summary> ???????/// <param name="inputStream">原图片</param> ???????/// <param name="dFile">压缩后保存位置</param> ???????/// <param name="dWidth">宽度</param> ???????/// <param name="dHeight">高度</param> ???????/// <param name="flag">压缩质量 1-100</param> ???????/// <returns></returns> ???????public bool CompressPicture(Stream inputStream, string dFile, ?int dWidth, int dHeight, int flag) ???????{ ???????????System.Drawing.Image iSource = System.Drawing.Image.FromStream(inputStream); ???????????ImageFormat tFormat = iSource.RawFormat; ???????????int sW = 0, sH = 0; ???????????//按比例缩放 ???????????Size tem_size = new Size(iSource.Width, iSource.Height); ???????????if (tem_size.Width > dWidth || tem_size.Height > dHeight) ???????????{ ???????????????if ((tem_size.Width * dHeight) > (tem_size.Height * dWidth)) ???????????????{ ???????????????????sW = dWidth; ???????????????????sH = (dWidth * tem_size.Height) / tem_size.Width; ???????????????} ???????????????else ???????????????{ ???????????????????sH = dHeight; ???????????????????sW = (tem_size.Width * dHeight) / tem_size.Height; ???????????????} ???????????} ???????????else ???????????{ ???????????????sW = tem_size.Width; ???????????????sH = tem_size.Height; ???????????} ???????????Bitmap ob = new Bitmap(dWidth, dHeight); ???????????Graphics g = Graphics.FromImage(ob); ???????????g.Clear(Color.WhiteSmoke); ???????????g.CompositingQuality = CompositingQuality.HighQuality; ???????????g.SmoothingMode = SmoothingMode.HighQuality; ???????????g.InterpolationMode = InterpolationMode.HighQualityBicubic; ???????????g.DrawImage(iSource, new Rectangle((dWidth - sW) / 2, (dHeight - sH) / 2, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel); ???????????g.Dispose(); ???????????//以下代码为保存图片时,设置压缩质量 ???????????EncoderParameters ep = new EncoderParameters(); ???????????long[] qy = new long[1]; ???????????qy[0] = flag;//设置压缩的比例1-100 ???????????EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy); ???????????ep.Param[0] = eParam; ???????????try ???????????{ ???????????????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; ???????????????????} ???????????????} ???????????????if (jpegICIinfo != null) ???????????????{ ???????????????????ob.Save(dFile, jpegICIinfo, ep);//dFile是压缩后的新路径 ???????????????} ???????????????else ???????????????{ ???????????????????ob.Save(dFile, tFormat); ???????????????} ???????????????return true; ???????????} ???????????catch ???????????{ ???????????????return false; ???????????} ???????????finally ???????????{ ???????????????iSource.Dispose(); ???????????????ob.Dispose(); ???????????} ???????} ???????/// <summary> ???????/// 无损压缩图片 ???????/// </summary> ???????/// <param name="sFile">原图片</param> ???????/// <param name="dFile">压缩后保存位置</param> ???????/// <param name="dWidth">宽度</param> ???????/// <param name="dHeight">高度</param> ???????/// <param name="flag">压缩质量 1-100</param> ???????/// <returns></returns> ???????public bool CompressPicture(string sFile, string dFile, int dWidth, int dHeight, int flag) ???????{ ???????????System.Drawing.Image iSource = System.Drawing.Image.FromFile(sFile); ???????????ImageFormat tFormat = iSource.RawFormat; ???????????int sW = 0, sH = 0; ???????????//按比例缩放 ???????????Size tem_size = new Size(iSource.Width, iSource.Height); ???????????if (tem_size.Width > dWidth || tem_size.Height > dHeight) ???????????{ ???????????????if ((tem_size.Width * dHeight) > (tem_size.Height * dWidth)) ???????????????{ ???????????????????sW = dWidth; ???????????????????sH = (dWidth * tem_size.Height) / tem_size.Width; ???????????????} ???????????????else ???????????????{ ???????????????????sH = dHeight; ???????????????????sW = (tem_size.Width * dHeight) / tem_size.Height; ???????????????} ???????????} ???????????else ???????????{ ???????????????sW = tem_size.Width; ???????????????sH = tem_size.Height; ???????????} ???????????Bitmap ob = new Bitmap(dWidth, dHeight); ???????????Graphics g = Graphics.FromImage(ob); ???????????g.Clear(Color.WhiteSmoke); ???????????g.CompositingQuality = CompositingQuality.HighQuality; ???????????g.SmoothingMode = SmoothingMode.HighQuality; ???????????g.InterpolationMode = InterpolationMode.HighQualityBicubic; ???????????g.DrawImage(iSource, new Rectangle((dWidth - sW) / 2, (dHeight - sH) / 2, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel); ???????????g.Dispose(); ???????????//以下代码为保存图片时,设置压缩质量 ???????????EncoderParameters ep = new EncoderParameters(); ???????????long[] qy = new long[1]; ???????????qy[0] = flag;//设置压缩的比例1-100 ???????????EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy); ???????????ep.Param[0] = eParam; ???????????try ???????????{ ???????????????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; ???????????????????} ???????????????} ???????????????if (jpegICIinfo != null) ???????????????{ ???????????????????ob.Save(dFile, jpegICIinfo, ep);//dFile是压缩后的新路径 ???????????????} ???????????????else ???????????????{ ???????????????????ob.Save(dFile, tFormat); ???????????????} ???????????????return true; ???????????} ???????????catch ???????????{ ???????????????return false; ???????????} ???????????finally ???????????{ ???????????????iSource.Dispose(); ???????????????ob.Dispose(); ???????????} ???????} ???????/// <summary> ???????/// 按指定规格裁剪图片 ???????/// </summary> ???????/// <param name="sFile">源文件路径</param> ???????/// <param name="dFile">输出文件路径</param> ???????/// <param name="originPoint">裁剪区域的起点</param> ???????/// <param name="sSize">裁剪区域的大小</param> ???????/// <param name="dSize">生成的规格</param> ???????/// <param name="flag">压缩质量 1-100</param> ???????/// <returns></returns> ???????public bool CropPicture(string sFile, string dFile, Point originPoint , Size sSize, Size dSize, int flag) ???????{ ???????????System.Drawing.Image iSource = System.Drawing.Image.FromFile(sFile); ???????????ImageFormat tFormat = iSource.RawFormat; ???????????Bitmap ob = new Bitmap(dSize.Width, dSize.Height); ???????????Graphics g = Graphics.FromImage(ob); ???????????g.Clear(Color.WhiteSmoke); ???????????g.CompositingQuality = CompositingQuality.HighQuality; ???????????g.SmoothingMode = SmoothingMode.HighQuality; ???????????g.InterpolationMode = InterpolationMode.HighQualityBicubic; ???????????g.DrawImage(iSource, new Rectangle(0, 0, dSize.Width, dSize.Height), originPoint.X, originPoint.Y, sSize.Width, sSize.Height, GraphicsUnit.Pixel); ???????????g.Dispose(); ???????????//以下代码为保存图片时,设置压缩质量 ???????????EncoderParameters ep = new EncoderParameters(); ???????????long[] qy = new long[1]; ???????????qy[0] = flag;//设置压缩的比例1-100 ???????????EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy); ???????????ep.Param[0] = eParam; ???????????try ???????????{ ???????????????ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders(); ???????????????ImageCodecInfo jpegICIinfo = null; ???????????????for (int i = 0; i < arrayICI.Length; i++) ???????????????{ ???????????????????if (arrayICI[i].FormatDescription.Equals("JPEG")) ???????????????????{ ???????????????????????jpegICIinfo = arrayICI[i]; ???????????????????????break; ???????????????????} ???????????????} ???????????????if(string.IsNullOrEmpty(dFile)) ???????????????{ ???????????????????string[] temp = sFile.Split(new char[] { ‘\\‘ }, StringSplitOptions.RemoveEmptyEntries); ???????????????????string fileName = temp[temp.Length - 1]; ???????????????????fileName = fileName.Insert(fileName.IndexOf(‘.‘), ‘_‘+ dSize.Width.ToString() + ‘_‘ + dSize.Height.ToString()); ???????????????????temp[temp.Length - 1] = fileName; ???????????????????dFile = string.Empty; ???????????????????foreach(string item in temp) ???????????????????{ ???????????????????????dFile += item + "\\"; ???????????????????} ???????????????????dFile=dFile.TrimEnd(‘\\‘); ???????????????} ???????????????if (jpegICIinfo != null) ???????????????{ ???????????????????ob.Save(dFile, jpegICIinfo, ep); ???????????????} ???????????????else ???????????????{ ???????????????????ob.Save(dFile, tFormat); ???????????????} ???????????????return true; ???????????} ???????????catch ???????????{ ???????????????return false; ???????????} ???????????finally ???????????{ ???????????????iSource.Dispose(); ???????????????ob.Dispose(); ???????????} ???????} ???????#endregion ???????#region 判断图片格式 ????????public bool IsAllowImg(string contentType, string fileExtension) ???????{ ???????????contentType = contentType.ToLower(); ???????????if(!contentType.Contains("image")) ???????????{ ???????????????return false; ???????????} ???????????fileExtension = fileExtension.ToLower(); ???????????string[] allowExtension = { ".bmp", ".gif", ".jpeg", ".jpg", ".png" }; ???????????foreach (string item in allowExtension) ???????????{ ???????????????if (fileExtension == item) ???????????????{ ???????????????????return true; ???????????????} ???????????} ???????????return false; ???????} ???????public static bool IsAllowedExtension(HttpPostedFileBase file) ???????{ ???????????System.IO.Stream stream = file.InputStream; ???????????System.IO.BinaryReader reader = new System.IO.BinaryReader(stream); ???????????string fileclass = ""; ???????????//这里的位长要具体判断. ????????????byte buffer; ???????????try ???????????{ ???????????????//buffer = r.ReadByte(); ???????????????//fileclass = buffer.ToString(); ???????????????//buffer = r.ReadByte(); ???????????????//fileclass += buffer.ToString(); ???????????????for (int i = 0; i < 2; i++) ???????????????{ ???????????????????fileclass += reader.ReadByte().ToString(); ???????????????} ???????????} ???????????catch ???????????{ ???????????} ???????????reader.Close(); ???????????stream.Close(); ???????????if (fileclass == "255216" || fileclass == "7173")//说明255216是jpg;7173是gif;6677是BMP,13780是PNG;7790是exe,8297是rar ????????????{ ???????????????return true; ???????????} ???????????else ???????????{ ???????????????return false; ???????????} ???????} ???????#endregion ???????[HttpPost] ???????public JsonResult CropPhoto(string url,int x,int y,int w,int h) ???????{ ???????????if (string.IsNullOrEmpty(url) || w == 0 || h == 0) ???????????{ ???????????????return Json(new { Status = "error", Msg = "参数错误" }); ???????????} ???????????Point origin = new Point(x, y); ???????????Size source = new Size(w, h); ???????????Size destSmall = new Size(48, 48); ???????????Size destLarge = new Size(180, 180); ???????????bool result1 =CropPicture(Server.MapPath(url), null, origin, source, destSmall, 100); ???????????bool result2 =CropPicture(Server.MapPath(url), null, origin, source, destLarge, 100); ???????????var jsonResult = result1 && result2 ???????????????? new { Status = "success", Msg = "操作成功" } ???????????????: new { Status = "error", Msg = "裁剪图片出现错误" }; ???????????return Json(jsonResult); ???????} ???}
在上传图片时,我对宽度大于300px的图片进行了等比压缩,目的是控制图片在浏览器截取区内显示的比较友好。
其实这里也可以直接返回源图,在 <img/> 标签内使用 width属性控制图片宽度,再计算出缩放比例并将此数值存储于 <form />表单内,待请求截取图片接口时将此缩放比例一并发送至后台,此时再按照缩放比例对4个坐标点做偏移计算即可截取出正确的图片。这里就提供思路,源码里我就不做这块了。
源码下载:https://pan.baidu.com/s/1eWiOzvio9EVW2WlYeaKUGA
代码是用VS2015 ASP.NET MVC5写的,我把bin目录内的dll都删了,通过还原 nuget 程序包应该就能运行了。
使用JQuery插件Jcrop进行图片截取
原文地址:https://www.cnblogs.com/xurongjian/p/9867721.html