直接上程式碼,其中上傳功能需要自己配置允許跨域的檔案伺服器地址~
或者將html檔案貼到您的站點下同源上傳也OK。
支援:
不同尺寸圖片獲取、
原圖縮小放大、
原圖移動、
選擇框大小改變、
下載選中的區域、
上傳選中的區域、
幾種簡單的濾鏡(自己新增濾鏡函式即可新增濾鏡效果)
移動端適配要點:
① 替換事件名稱
if(/^.*(Android|iPad|iPhone){1}.*$/.test(navigator.userAgent)){ eventName={down:"touchstart",move:"touchmove",up:"touchend",click:"tap"}; }
② 移動端touch事件e沒有clientX屬性,需要做如下處理
//處理事件,支援移動端 //e.originalEvent.targetTouches[0].pageX function dealE(e){ e.clientX= e.clientX || e.originalEvent.targetTouches[0].clientX; e.clientY= e.clientY || e.originalEvent.targetTouches[0].clientY; }
③ 移動端瀏覽器展示網頁在手指拖動的過程中是會左右晃悠的,體驗十分不好。
給所有事件都加上
e.preventDefault();
④ 移動端瀏覽器對File上傳支援不好,微信甚至乾脆遮蔽了File上傳請求
我的做法是:
獲取圖片檔案的base64字串:
var imgData = $("#res1")[0].toDataURL("png"); imgData = imgData.replace(/^data:image\/(png|jpg);base64,/, "");
然後自己在後端實現一個檔案上傳代理,接收base64字串,拼接body:
proxyRequest.ContentType = "multipart/form-data; boundary=----WebKitFormBoundaryqwqoxnDz0J0XB2Ti"; StreamReader reader = new StreamReader(_context.Request.InputStream); string base64=reader.ReadToEnd(); string divider = "----WebKitFormBoundaryqwqoxnDz0J0XB2Ti"; string content = ""; content += "--"+divider; content += "\r\n"; content += "Content-Disposition: form-data; name=\"userlogo\"; filename=\"userlogo.png\""; content += "\r\n"; content += "Content-Type: image/png"; content += "\r\n\r\n"; byte[] bytes1 = Encoding.UTF8.GetBytes(content); byte[] bytes2 = Convert.FromBase64String(base64); byte[] bytes3 = Encoding.UTF8.GetBytes("\r\n" + "--" + divider + "--\r\n"); byte[] bytes = new byte[bytes1.Length+bytes2.Length+bytes3.Length]; bytes1.CopyTo(bytes,0); bytes2.CopyTo(bytes, bytes1.Length); bytes3.CopyTo(bytes, bytes1.Length + bytes2.Length); proxyRequest.ContentLength = bytes.Length;
這樣對於移動端瀏覽器來說這就是一個普通的請求。
至此,移動端完美支援!
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>get image</title> <style> canvas{ border:solid thin #ccc; cursor:pointer; } #canvasContainer{ position:relative; } #picker{ position:absolute; border:solid thin #ccc; cursor: move; overflow:hidden; z-index:2; } #resize{ width: 0; height: 0; border-bottom: 15px solid rgba(200,200,200,0.8); border-left: 15px solid transparent; right: 0; bottom: 0; position: absolute; cursor: se-resize; z-index:3; } </style> <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script> <script> $(function(){ var canvas=document.getElementById("container"), context=canvas.getContext("2d"), //檔案伺服器地址 fileServer=null, //適配環境,隨時修改事件名稱 eventName={down:"mousedown",move:"mousemove",up:"mouseup",click:"click"}; //////////canvas尺寸配置 var canvasConfig={ //容器canvas尺寸 width:500, height:300, //原圖放大/縮小 zoom:1, //圖片物件 img:null, //圖片完整顯示在canvas容器內的尺寸 size:null, //圖片繪製偏移,為了原圖不移出框外,這個只能是負值or 0 offset:{x:0,y:0}, //當前應用的濾鏡 filter:null } canvas.width=canvasConfig.width; canvas.height=canvasConfig.height; ///////////設定選擇工具配置 var config={ //圖片選擇框當前大小、最大大小、最小大小 pickerSize:100, minSize:50, maxSize:200, x:canvas.width/2-100/2, y:canvas.height/2-100/2 } /////////////結果canvas配置 var resCanvas=[$("#res1")[0].getContext("2d"),$("#res2")[0].getContext("2d"),$("#res3")[0].getContext("2d")]; //結果canvas尺寸配置 var resSize=[100,50,32] resSize.forEach(function(size,i){ $("#res"+(i+1))[0].width=size; $("#res"+(i+1))[0].height=size; }); //////// 濾鏡配置 var filters=[]; filters.push({name:"灰度",func:function(pixelData){ //r、g、b、a //灰度濾鏡公式: gray=r*0.3+g*0.59+b*0.11 var gray; for(var i=0;i<canvasConfig.width*canvasConfig.height;i++){ gray=pixelData[4*i+0]*0.3+pixelData[4*i+1]*0.59+pixelData[4*i+2]*0.11; pixelData[4*i+0]=gray; pixelData[4*i+1]=gray; pixelData[4*i+2]=gray; } }}); filters.push({name:"黑白",func:function(pixelData){ //r、g、b、a //黑白濾鏡公式: 0 or 255 var gray; for(var i=0;i<canvasConfig.width*canvasConfig.height;i++){ gray=pixelData[4*i+0]*0.3+pixelData[4*i+1]*0.59+pixelData[4*i+2]*0.11; if(gray>255/2){ gray=255; } else{ gray=0; } pixelData[4*i+0]=gray; pixelData[4*i+1]=gray; pixelData[4*i+2]=gray; } }}); filters.push({name:"反色",func:function(pixelData){ for(var i=0;i<canvasConfig.width*canvasConfig.height;i++){ pixelData[i*4+0]=255-pixelData[i*4+0]; pixelData[i*4+1]=255-pixelData[i*4+1]; pixelData[i*4+2]=255-pixelData[i*4+2]; } }}); filters.push({name:"無",func:null}); // 新增濾鏡按鈕 filters.forEach(function(filter){ var button=$("<button>"+filter.name+"</button>"); button.on(eventName.click,function(){ canvasConfig.filter=filter.func; //重繪 draw(context,canvasConfig.img,canvasConfig.size); }) $("#filters").append(button); }); //下載生成的圖片(只下載第一張) $("#download").on(eventName.click,function(){ //將mime-type改為image/octet-stream,強制讓瀏覽器直接download var _fixType = function(type) { type = type.toLowerCase().replace(/jpg/i, 'jpeg'); var r = type.match(/png|jpeg|bmp|gif/)[0]; return 'image/' + r; }; var saveFile = function(data, filename){ var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a'); save_link.href = data; save_link.download = filename; var event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); save_link.dispatchEvent(event); }; var imgData = $("#res1")[0].toDataURL("png"); imgData = imgData.replace(_fixType("png"),'image/octet-stream');//base64 saveFile(imgData,"頭像created on"+new Date().getTime()+"."+"png"); }); //上傳圖片 $("#upload").on(eventName.click,function(){ var imgData = $("#res1")[0].toDataURL("png"); imgData = imgData.replace(/^data:image\/(png|jpg);base64,/, ""); if(!fileServer){ alert("請配置檔案伺服器地址"); return; } var blobBin = atob(imgData); var array = []; for(var i = 0; i < blobBin.length; i++) { array.push(blobBin.charCodeAt(i)); } var blob=new Blob([new Uint8Array(array)], {type: 'image/png'}); var file=new File([blob],"userlogo.png", {type: 'image/png'}); var formdata=new FormData(); formdata.append("userlogo",file); $.ajax({ type: 'POST', url: fileServer, data: formdata, processData: false, contentType: false, success: function (msg) { $("#uploadres").text(JSON.stringify(msg)); } }); }); //繫結選擇圖片事件 $("#fileinput").change(function(){ var file=this.files[0], URL = (window.webkitURL || window.URL), url = URL.createObjectURL(file), img=new Image(); img.src=url; img.onload=function(){ canvasConfig.img=img; canvasConfig.size=getFixedSize(img,canvas); draw(context,img,canvasConfig.size); setPicker(); } }); //移動選擇框 //繫結滑鼠在選擇工具上按下的事件 $("#picker").on(eventName.down,function(e){ e.stopPropagation(); var start={x:e.clientX,y:e.clientY,initX:config.x,initY:config.y}; $("#canvasContainer").on(eventName.move,function(e){ // 將x、y限制在框內 config.x=Math.min(Math.max(start.initX+e.clientX-start.x,0),canvasConfig.width-config.pickerSize); config.y=Math.min(Math.max(start.initY+e.clientY-start.y,0),canvasConfig.height-config.pickerSize); setPicker(); }) }); //原圖移動事件 $("#container").on(eventName.down,function(e){ e.stopPropagation(); var start={x:e.clientX,y:e.clientY,initX:canvasConfig.offset.x,initY:canvasConfig.offset.y}; var size=canvasConfig.size; $("#canvasContainer").on(eventName.move,function(e){ // 將x、y限制在框內 // 座標<0 當圖片大於容器 座標>容器-圖片 否則不能移動 canvasConfig.offset.x=Math.max(Math.min(start.initX+e.clientX-start.x,0),Math.min(canvasConfig.width-size.width*canvasConfig.zoom,0)); canvasConfig.offset.y=Math.max(Math.min(start.initY+e.clientY-start.y,0),Math.min(canvasConfig.height-size.height*canvasConfig.zoom,0)); //重繪蒙版 draw(context,canvasConfig.img,canvasConfig.size); }) }); //改變選擇框大小事件 $("#resize").on(eventName.down,function(e){ e.stopPropagation(); var start={x:e.clientX,init:config.pickerSize}; $("#canvasContainer").on(eventName.move,function(e){ config.pickerSize= Math.min(Math.max(start.init+e.clientX-start.x,config.minSize),config.maxSize); $("#picker").css({width:config.pickerSize,height:config.pickerSize}); draw(context,canvasConfig.img,canvasConfig.size); }) }); $(document).on(eventName.up,function(e){ $("#canvasContainer").unbind(eventName.move); }) //原圖放大、縮小 $("#bigger").on(eventName.click,function(){ canvasConfig.zoom=Math.min(3,canvasConfig.zoom+0.1); //重繪蒙版 draw(context,canvasConfig.img,canvasConfig.size); }) $("#smaller").on(eventName.click,function(){ canvasConfig.zoom=Math.max(0.4,canvasConfig.zoom-0.1); //重繪蒙版 draw(context,canvasConfig.img,canvasConfig.size); }) // 定位選擇工具 function setPicker(){ $("#picker").css({width:config.pickerSize+"px",height:config.pickerSize+"px", top:config.y,left:config.x}); //重繪蒙版 draw(context,canvasConfig.img,canvasConfig.size); } //繪製canvas中的圖片和蒙版 function draw(context,img,size){ var pickerSize=config.pickerSize, zoom=canvasConfig.zoom, offset=canvasConfig.offset; context.clearRect(0,0,canvas.width,canvas.height); context.drawImage(img,0,0,img.width,img.height,offset.x,offset.y,size.width*zoom,size.height*zoom); //繪製挖洞後的蒙版 context.save(); context.beginPath(); pathRect(context,config.x,config.y,pickerSize,pickerSize); context.rect(0,0,canvas.width,canvas.height); context.closePath(); context.fillStyle="rgba(255,255,255,0.9)"; context.fill(); context.restore(); //繪製結果 var imageData=context.getImageData(config.x,config.y,pickerSize,pickerSize) resCanvas.forEach(function(resContext,i){ resContext.clearRect(0,0,resSize[i],resSize[i]); resContext.drawImage(canvas,config.x,config.y,pickerSize,pickerSize,0,0,resSize[i],resSize[i]); //新增濾鏡效果 if(canvasConfig.filter){ var imageData=resContext.getImageData(0,0,resSize[i],resSize[i]); var temp=resContext.getImageData(0,0,resSize[i],resSize[i]);// 有的濾鏡實現需要temp資料 canvasConfig.filter(imageData.data,temp); resContext.putImageData(imageData,0,0,0,0,resSize[i],resSize[i]); } }); } //逆時針用路徑自己來繪製矩形,這樣可以控制方向,以便挖洞 // 起點x,起點y,寬度,高度 function pathRect(context,x,y,width,height){ context.moveTo(x,y); context.lineTo(x,y+height); context.lineTo(x+width,y+height); context.lineTo(x+width,y); context.lineTo(x,y); } // 根據圖片和canvas的尺寸,確定圖片顯示在canvas中的尺寸 function getFixedSize(img,canvas){ var cancasRate=canvas.width/canvas.height, imgRate=img.width/img.height,width=img.width,height=img.height; if(cancasRate>=imgRate && img.height>canvas.height){ height=canvas.height; width=imgRate*height; } else if(cancasRate<imgRate && img.width>canvas.width){ width=canvas.width; height=width/imgRate; } return {width:width,height,height} } }); </script> </head> <body> <input id="fileinput" type="file" /><br/><br/> <div id="canvasContainer"> <canvas id="container"></canvas> <div id="picker"> <div id="resize"></div> </div> </div><br/> <button id="bigger">原圖放大</button><button id="smaller">原圖縮小</button> <p>結果:</p> <div> <canvas id="res1"></canvas> <canvas id="res2"></canvas> <canvas id="res3"></canvas> <button id="download"> 下載 </button> <button id="upload"> 上傳 </button>(demo只上傳/下載第一張圖片) <div id="uploadres"></div> </div> <p>濾鏡:</p> <div id="filters"></div> </body> </html>
原文地址:http://www.cnblogs.com/tzyy/p/4830439.html
轉載請註明。