Canvas实现图像裁剪保存(含demo)
打算用canvas实现一个简单的图片裁剪的功能 (类似于上传头像并裁剪)
先分析一下需求点:
- 上传一张图片(图片来源会实现两种途径:1、本地上传 2、服务器获取)
- 将上传的图片先进行预处理(进行缩放)
- 拖动滑动条缩放图像
- 裁剪图片并输出结果(两种途径:1、提供下载链接保存至本地 2、上传oss)
- 项目github:https://github.com/mikoRen/picture-cropper
步骤
- 展示
- Start!
- 第一部分:初始部分:设置缩放参数,图片初始位置,图像绘制
- 第二部分:canvas位置拖动
- 第三部分:图像缩放
- 第四部分:预览—-绘制结果图像
- 第五部分:导出文件
- 第五部分:补充>获取图片途径:本地上传
展示
Start!
html中主要使用的元素:
第一个canvas:用于绘制,操作 原图片
第二个canvas:用于输出裁剪之后的图片
一个input type=range ,缩放时使用的滑动条
第一个button:裁剪图片
第二个button:导出图片
html:
<!DOCTYPE html>
<html lang="en">
<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">
<link href="./index.css" rel="stylesheet" type="text/css">
<title>Document</title>
</head>
<body>
<input id="img-input" type="file"/>
<div class="pic-cropper">
<input id="slider" type="range"/>
<canvas id="image-canvas" width="300" height="300"></canvas>
<button id="submit">预览</button>
<canvas id="result-canvas" width="200" height="200"></canvas>
<button id="export">导出</button>
</div>
<script src="./index.js"></script>
</body>
</html>
第一部分:初始部分:设置缩放参数,图片初始位置,图像绘制
图片来源:服务器获取(本地上传会在后面补充)
思路要点:
- 获取一张图片,对图像尺寸进行处理之后,绘制在 源图像canvas 里 (我这里设置的源图像缩放范围是200~500,源图像初始状态:长或者宽为200)
- 拖动滑动条进行缩放,也就是拖动滑动条的过程中修改【当前缩放值:currentFactor】
- 滑动条的缩放范围:获取图像之后,判断图像是一个“竖长图像(width
=height)”,如果是“竖长图像(width =height)”则按照height来确定缩放范围 - 缩放和拖动过程中,要注意检测图片不要“出界”
“竖长图像”和“扁图像” 缩放参数的计算不一样
使用到的变量
//第一个canvas 源图像canvas
var imgCanvas = document.getElementById("image-canvas"); //源图像canvas的尺寸为300*300
var imgCxt = imgCanvas.getContext("2d");
//第二个canvas 结果图像canvas
var resultCanvas = document.getElementById("result-canvas"); //目标canvas的尺寸为200*200
var resultCxt = resultCanvas.getContext("2d");
var currentFactor = 1; //当前的放缩倍数
var minFactor = 1; //最小放缩倍数
var maxFactor = 1; //最大放缩倍数
var img = new Image();
img.setAttribute('crossOrigin', 'anonymous'); //解决跨域问题
确定图像的放缩范围
(里面的200是目标图的尺寸,500是放缩的最大尺寸,可以根据需求调整)
// 计算初始Factor
calculateFactor = function() {
//竖长图片
if(img.width<img.height) {
minFactor = 200/img.width;//初始状态
currentFactor = 200/img.width;
maxFactor = 500/img.width;
} else {
//扁图片
minFactor = 200/img.height;
currentFactor = 200/img.height;
maxFactor = 500/img.height;
}
initSlider(); //初始化滑动条的min和max
}
确定图片在canvas里的初始绘制位置
//计算初始画布位置
canvasOriginPosition = function() {
calculateFactor();
var positionX;
var positionY;
if(img.width<img.height) {
positionX = 50;
positionY = 50 - (img.height*currentFactor - 200) /2;
} else {
positionX = 50 - (img.width*currentFactor - 200) /2;
positionY = 50;
}
lastImgX = positionX;
lastImgY = positionY;
return({ "positionX":positionX,"positionY":positionY});
}
画蒙版
//画蒙版和截取范围
drawMask = function() {
imgCxt.fillStyle = "rgba(0,0,0,0.5)";
imgCxt.fillRect(0,0,300,300);
imgCxt.fillStyle = "rgba(0,0,0,1)";
imgCxt.globalCompositeOperation = "destination-out"; //globalCompositeOperation提供canvas里图像的组合方式
imgCxt.fillRect(50,50,200,200);
}
获取图像绘进行初始绘制
//获取图像并画出来
//参数里的imgUrl是在从服务器中获取到的图像的url
getImage = function(imgUrl) {
img.src=imgUrl;
img.onload = function() {
calculateFactor(); //绘制图像前 先初始化缩放参数
var originPosition = canvasOriginPosition(); //绘制图像前 获取图像的初始位置
imgCxt.globalCompositeOperation = "destination-over";
imgCxt.drawImage(img,originPosition.positionX,originPosition.positionY,img.width*currentFactor,img.height*currentFactor);
}
}
调用
drawMask();//这里必须先绘制蒙版再绘制图片,原因是 设置的 globalCompositeOperation 的参数 ,可修改
getImage();
到这里就可以实现一个初始的界面了
每次拖动,或者缩放,canvas都要重新绘制图像
pX,pY是图像的位移,没有发生位移,则参数为0
redrawImg = function(pX,pY) {
//每次绘图前检查position是否没有超出区域
var newPosition = checkPosition(pX,pY)
imgCanvas.setAttribute('height', 300);
drawMask();
imgCxt.globalCompositeOperation = "destination-over";
imgCxt.drawImage(img,newPosition.X,newPosition.Y,img.width*currentFactor,img.height*currentFactor);
}
第二部分:canvas位置拖动
思路:
- 再canvas范围里,鼠标按下onmousedown:开始进入可拖动状态
- 可拖动状态下,鼠标移动onmousemove:获取移动位移(pX,pY),和上次移动后的作图位置(lastImageX,lastImageY)组成新的作图位置
- 鼠标抬起onmouseup:结束拖动状态,并取消可拖动状态
//控制canvas拖动
var moving = false;
var lastmouseX = null;
var lastmouseY = null;
//上次移动结束,canvas画图的位置
var lastImgX = 0;
var lastImgY = 0;
imgCanvas.onmousedown=function(e) {
moving = true;
lastmouseX = e.clientX;
lastmouseY = e.clientY;
}
window.onmouseup = function(e) {
if(moving === true) {
moving = false;
var newPosition = checkPosition(e.clientX - lastmouseX,e.clientY - lastmouseY)
//每次移动完成都要改变一下上次图片绘制位置
lastImgX = newPosition.X;
lastImgY = newPosition.Y;
}
window.onmousemove = function(e) {
if(moving) {
pX=e.clientX - lastmouseX;
pY=e.clientY - lastmouseY;
redrawImg(pX,pY); //移动的时候要重新绘制图像
}
}
}
第三部分:图像缩放
每次图像缩放都要重新位置图像
//初始滑动条
initSlider = function() {
mySlider.min = minFactor;
mySlider.max = maxFactor;
mySlider.step = 0.01;
}
mySlider.oninput = function() {
currentFactor = mySlider.value;
//每次缩放完也都要修改图片的绘制位置,缩放不改变绘制位置,所以参数置为0
redrawImg(0,0);
}
第四部分:预览—绘制结果图像
按照当前的缩放系数(currentFactor),使用 五参数 drawImage()
五个参数的意义:drawImage(img,绘图位置X,绘图位置Y,缩放图像width,缩放图像height )
var submitBtn = document.getElementById("submit");
submitBtn.onclick = function() {
resultCxt.drawImage(img,lastImgX-50,lastImgY-50,img.width*currentFactor,img.height*currentFactor)
}
第五部分:导出文件
这里使用了html a 标签
canvas.toDataURL()
var exportBtn = document.getElementById("export");
exportBtn.onclick = function() {
var url = resultCanvas.toDataURL('image/png', 0.92);
var resultLink = document.createElement("a");
resultLink.download = "裁剪结果";
resultLink.href = url;
document.body.appendChild(resultLink);
resultLink.click();
resultLink.remove();
}
第五部分:补充>获取图片途径:本地上传
var imgInput = document.getElementById("img-input");
imgInput.onchange = function() {
var imgUrl = URL.createObjectURL(imgInput.files[0]);
imgCanvas.setAttribute('height', 300);
resultCanvas.setAttribute('height',200);
drawMask();
getImage(imgUrl);
}
还没有评论,来说两句吧...