先看效果
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title></title> <style type="text/css"> * { padding: 0; margin: 0; font-size: 14px; } #box { 400px; height: 400px; border: 1px solid red; margin: 20px auto; position: relative; } #operate { text-align: center; ; } #operate p { margin-bottom: 6px; } input[type=file] { display: none; } label { display: inline-block; cursor: pointer; background: #38f; color: #fff; 102px; height: 38px; line-height: 38px; border-radius: 4px; } #clipcanvas { position: absolute; top: 0; left: 0; z-index: 10; 100%; height: 100%; } </style> </head> <body> <div id="box"> <canvas id="canvas" width="400" height="400"></canvas> <canvas id="clipcanvas"></canvas> </div> <div id="operate"> <p><label><input type="file" name="" id="bg" value="" />选择头像</label></p> <p><label><input type="file" name="" id="flag" value="" />选择上层</label></p> <p><input type="text" name="" id="posX" value="0" />请输入上层x位置</p> <p><input type="text" name="" id="posY" value="0" />请输入上层y位置</p> <p><label id="create">直接生成</label></p> <p><label id="reset">重新截图</label></p> </div> <a href="" download="logo.png" title="点击下载" id="down"> <img src="" id="result"> </a> </body> <script type="text/javascript"> const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); const baseW = 400; const flagW = 100; let bgConfig; let flagConfig; document.getElementById("bg").onchange = async function() { const file = this.files[0]; try { const img = await getImageObj(file); const rate = compress(img, baseW); bgConfig = [img, 0, 0, img.width, img.height, 0, 0, rate.w, rate.h]; drawn(); } catch (e) { console.error(e); } }; document.getElementById("flag").onchange = async function() { const file = this.files[0]; try { const img = await getImageObj(file); const rate = compress(img, flagW); flagConfig = [img, 0, 0, img.width, img.height, 0, 0, rate.w, rate.h]; drawn(); } catch (e) { console.error(e); } }; document.getElementById("posX").onchange = function() { let val = Number(this.value) || 0; flagConfig[5] = val; drawn(); } document.getElementById("posY").onchange = function() { let val = Number(this.value) || 0; flagConfig[6] = val; drawn(); } function drawn() { ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight); if (bgConfig) { ctx.drawImage(...bgConfig); } if (flagConfig) { ctx.drawImage(...flagConfig); } } //图片压缩,获取等比缩放后的结果 function compress(img, base) { let w = img.width; let h = img.height; if (img.width > img.height) { if (img.width > base) { //要将宽度缩放 w = base; h = (w / img.width) * img.height; // 新的 宽比 高 = 旧的宽比高 h / w = img.heigth/img.width ; } } else { if (img.height > base) { h = base; w = (h / img.height) * img.width; } } return { w, h }; } function getImageObj(file) { const url = getObjectURL(file); const img = new Image(); img.src = url; return new Promise((resolve, reject) => { img.onload = function() { resolve(img); } img.onerror = function(e) { reject(e); } }); } //取得该文件的url function getObjectURL(file) { var url = null; if (window.createObjectURL != undefined) { url = window.createObjectURL(file); } else if (window.URL != undefined) { url = window.URL.createObjectURL(file); } else if (window.webkitURL != undefined) { url = window.webkitURL.createObjectURL(file); } return url; } //截图 var clipcanvas = document.getElementById("clipcanvas"); var clipctx = clipcanvas.getContext("2d"); clipcanvas.width = canvas.clientWidth; clipcanvas.height = canvas.clientHeight; var start = null; var clipArea = {}; //裁剪范围 clipcanvas.onmousedown = function(e) { start = { x: e.offsetX, y: e.offsetY }; } clipcanvas.onmousemove = function(e) { if (start) { fill(start.x, start.y, e.offsetX - start.x, e.offsetY - start.y) } } document.addEventListener("mouseup", function() { if (start) { start = null; exportImg(clipArea); } }); //重新截图 document.getElementById("reset").onclick = function(){ clipctx.clearRect(0, 0, clipcanvas.width, clipcanvas.height); } //直接生成 document.getElementById("create").onclick = function(){ exportImg({ x:0, y:0, w:canvas.clientWidth, h:canvas.clientHeight, }) } function fill(x, y, w, h) { clipctx.clearRect(0, 0, clipcanvas.width, clipcanvas.height); clipctx.beginPath(); clipctx.fillStyle = 'rgba(0,0,0,0.6)'; clipctx.strokeStyle = "green"; //遮罩层 clipctx.globalCompositeOperation = "source-over"; clipctx.fillRect(0, 0, clipcanvas.width, clipcanvas.height); //画框 clipctx.globalCompositeOperation = 'destination-out'; clipctx.fillRect(x, y, w, h); //描边 clipctx.globalCompositeOperation = "source-over"; clipctx.moveTo(x, y); clipctx.lineTo(x + w, y); clipctx.lineTo(x + w, y + h); clipctx.lineTo(x, y + h); clipctx.lineTo(x, y); clipctx.stroke(); clipctx.closePath(); clipArea = { x, y, w, h }; } function startClip(area) { var canvas = document.createElement("canvas"); canvas.width = area.w; canvas.height = area.h; var data = ctx.getImageData(area.x, area.y, area.w, area.h); var context = canvas.getContext("2d"); context.putImageData(data, 0, 0); return canvas.toDataURL("image/png"); } function exportImg(clipArea){ var url = startClip(clipArea); document.getElementById("result").src = url; document.getElementById("down").href = url; } </script> </html>