**css **
.container {
position: relative;
width: 100%;
height: 100%;
background: #000;
}
.img {
position: absolute;
top: 5%;
left: 50%;
transform: translateX(-50%);
overflow: hidden;
background: #eee;
}
.img image {
height:400px;
}
.imgcrop {
position: absolute;
left: -50000rpx;
top: -500000rpx;
}
.footer {
position: fixed;
width: 100%;
height: 110rpx;
color: red;
background: #000;
bottom: 1;
display: flex;
align-items: center;
justify-content: space-around;
margin-top: 130%;
}
.footer view {
width: 30%;
text-align: center;
}
.background {
width: 100%;
height: 100%;
position: absolute;
top: 0;
z-index: -1;
}
HTML
<view class="container">
<!-- 剪裁框与初始图片,剪裁框监听用户手势,获取移动缩放旋转值,images通过css样式显示变化 -->
<view class="img" style="width:{{ width }}px; height:{{height}}px" catchtouchstart="touchstartCallback" catchtouchmove="touchmoveCallback" catchtouchend="touchendCallback" >
<image style="transform: translate({{stv.offsetX}}px, {{stv.offsetY}}px) scale({{stv.scale}}) rotate({{ stv.rotate }}deg);width:{{originImg.width}}px; height: {{originImg.height}}px" src="{{ originImg.url }}"></image>
</view>
<view class='footer'>
<view bindtap='uploadTap'>选择图片</view>
<view bindtap='rotate'>旋转</view>
<view bindtap='cropperImg'>打印</view>
</view>
<!-- canvas长宽设为初始图片设置的长款的两倍,使剪裁得到的图片更清晰,也不至于过大 -->
<canvas class='imgcrop' style="width:{{canvasWidth}}px; height: {{canvasHeight}}px" canvas-id='imgcrop'></canvas>
</view>
JS
注:77.png或者66.png更改成自己的图片URL,如果只需要一张图片去掉77.png或者66.png这段代码
const device = wx.getSystemInfoSync();
const app = getApp();
var mun = -1;
var initImgPaht='';
var widthRadio = '';
var heightRadio = '';
var twoPoint = {
x1: 0,
y1: 0,
x2: 0,
y2: 0
}
Component({
/**
* 组件的属性列表
*/
properties: {
ratio: {
type: Number,
observer: function (newVal, oldVal) {
this.setData({
width: device.windowWidth * 0.8,
height: device.windowWidth * 0.8 / newVal
})
}
},
url: {
type: String,
observer ( newVal, oldVal ) {
this.initImg( newVal )
}
}
},
/**
* 组件的初始数据
*/
data: {
width: device.windowWidth * 0.8, //剪裁框的宽度
height: device.windowWidth * 0.8 / (102 / 152), //剪裁框的长度
originImg: null, //存放原图信息
canvasWidth: device.windowWidth,
canvasHeight: device.windowWidth,
stv: {
offsetX: 0, //剪裁图片左上角坐标x
offsetY: 0, //剪裁图片左上角坐标y
zoom: false, //是否缩放状态
distance: 0, //两指距离
scale: 1, //缩放倍数
rotate: 0 //旋转角度
},
},
/**
* 组件的方法列表
*/
methods: {
uploadTap() {
let _this = this
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success(res) {
_this.initImg( res.tempFilePaths[0]);
}
})
},
rotate() {
let _this = this;
_this.setData({
'stv.rotate': _this.data.stv.rotate % 90 == 0 ? _this.data.stv.rotate = _this.data.stv.rotate + 90 : _this.data.stv.rotate = 0
})
if (_this.data.stv.rotate == 360) {
_this.data.stv.rotate = 0;
}
},
// canvas剪裁图片
cropperImg() {
wx.showLoading({
title: 'loading',
mask: true
})
let _this = this;
let ctx = wx.createCanvasContext('imgcrop',this);//创建画布
//原始图片
var imgWidth
var imgHeight
//放大缩小后的图片
var zoomWidth
var zoomHeight
//等比例图片
var originalWidth
var originalHeight
var proportion//放大缩小倍数
var str//临时值
var zoomJudge = true;
if (_this.data.originImg.judge) {//宽度大于高度图片
imgWidth = _this.data.height * heightRadio;
imgHeight = _this.data.width * widthRadio;
} else {//高度大于宽度图片
imgWidth = _this.data.width * widthRadio;
imgHeight = _this.data.height * heightRadio;
}
//保存六寸图片默认1440分辨率,进行等比例缩放,默认刚刚大于1440分辨率
if (imgHeight > 1440) {//缩小
for (var i = 1; i < 10; i = i + 0.1) {
str = imgHeight / i;
if (str < 1440) {
proportion = i + 0.1;
break;
}
}
} else {//放大
for (var i = 1; i < 10; i = i + 0.1) {
str = imgHeight * i;
if (str > 1440) {
proportion = i;
zoomJudge = false;
break;
}
}
}
//等比例缩放高度宽度(任务需求只有六寸图片),宽度图片长宽相互替换避免画布大小变化(裁剪画布大小图片)
if (zoomJudge){
originalWidth = imgWidth / proportion;
originalHeight = imgHeight / proportion;
}else {
originalWidth = imgWidth * proportion;
originalHeight = imgHeight * proportion;
}
//画布高宽赋值
_this.setData({
canvasWidth: originalWidth,
canvasHeight: originalHeight
})
//获取图片赋值信息
let cropData = _this.data.stv;
ctx.save();// 保存当前的绘图状态
//放大缩小后的图片(双指缩放)
zoomWidth = originalWidth * cropData.scale;
zoomHeight = originalHeight * cropData.scale;
//等待处理
console.info(cropData.rotate);
//以画布原点为中心
if (_this.data.originImg.judge) {//由于旋转高宽位置替换
if (cropData.rotate == 90){//默认旋转90
ctx.translate(originalWidth + (zoomWidth - originalWidth) / 2, -(zoomHeight - originalHeight) / 2);
ctx.rotate(cropData.rotate * Math.PI / 180);
ctx.drawImage(_this.data.originImg.url, 0, 0, zoomHeight, zoomWidth);
ctx.drawImage('66.png', (zoomHeight - originalHeight) / 2, (zoomWidth - originalWidth) / 2, originalHeight, originalWidth);
} else if (cropData.rotate == 180) {
ctx.translate(zoomHeight + (originalWidth - zoomHeight) / 2, zoomWidth + (originalHeight - zoomWidth) / 2);
ctx.rotate(cropData.rotate * Math.PI / 180);
ctx.drawImage(_this.data.originImg.url, 0, 0, zoomHeight, zoomWidth);
ctx.drawImage('66.png', -(originalWidth - zoomHeight) / 2, -(originalHeight - zoomWidth) / 2, originalWidth, originalHeight);
} else if (cropData.rotate == 270) {
ctx.translate(-(zoomWidth - originalWidth) / 2, originalHeight + (zoomHeight - originalHeight) / 2);
ctx.rotate(cropData.rotate * Math.PI / 180);
ctx.drawImage(_this.data.originImg.url, 0, 0, zoomHeight, zoomWidth);
ctx.drawImage('66.png', (zoomHeight - originalHeight) / 2, (zoomWidth - originalWidth) / 2, originalHeight, originalWidth);
} else {//没有选择的图片
ctx.translate((originalWidth - zoomHeight) / 2, (originalHeight - zoomWidth) / 2);
ctx.rotate(cropData.rotate * Math.PI / 180);
ctx.drawImage(_this.data.originImg.url, 0, 0, zoomHeight, zoomWidth);
ctx.drawImage('66.png', (originalWidth + zoomHeight) / 2 - originalWidth, (zoomWidth + originalHeight) / 2 - originalHeight, originalWidth, originalHeight);
}
} else {//正常图片
if (cropData.rotate == 0) {
ctx.translate((originalWidth - zoomWidth) / 2, (originalHeight - zoomHeight) /2);
ctx.rotate(cropData.rotate * Math.PI / 180);
ctx.drawImage(_this.data.originImg.url, 0, 0, zoomWidth, zoomHeight);
ctx.drawImage('77.png', (zoomWidth - originalWidth) / 2, (zoomHeight -originalHeight) / 2, originalWidth, originalHeight);
} else if (cropData.rotate == 90){
ctx.translate((originalWidth + zoomHeight)/2, (originalHeight - zoomWidth )/2);
ctx.rotate(cropData.rotate * Math.PI / 180);
ctx.drawImage(_this.data.originImg.url, 0, 0, zoomWidth, zoomHeight);
ctx.drawImage('77.png', -(originalHeight - zoomWidth) / 2, -(originalWidth - zoomHeight) / 2, originalHeight, originalWidth);
} else if (cropData.rotate == 180){
ctx.translate(originalWidth - (originalWidth - zoomWidth) / 2, originalHeight - (originalHeight - zoomHeight) / 2);
ctx.rotate(cropData.rotate * Math.PI / 180);
ctx.drawImage(_this.data.originImg.url, 0, 0, zoomWidth, zoomHeight);
ctx.drawImage('77.png', -(originalWidth - zoomWidth) / 2, -(originalHeight - zoomHeight) / 2, originalWidth, originalHeight);
} else if(cropData.rotate == 270) {
ctx.translate((originalWidth - zoomHeight) / 2, (originalHeight + zoomWidth) / 2);
ctx.rotate(cropData.rotate * Math.PI / 180);
ctx.drawImage(_this.data.originImg.url, 0, 0, zoomWidth, zoomHeight);
ctx.drawImage('77.png', -(originalHeight - zoomWidth) / 2, -(originalWidth - zoomHeight) / 2, originalHeight, originalWidth);
}
}
ctx.restore();//恢复之前保存的绘图状态。
wx.showToast({
title: '图片正在生成中.....',
icon: 'loading',
duration: 2200
});
ctx.draw(false, () => {//延迟2.2秒,防止画布加载过快无法正常裁剪。异步加载
setTimeout(() => {
wx.canvasToTempFilePath({
canvasId: 'imgcrop',
success(response) {
mun++;
console.log(response.tempFilePath);
var list = {
url: response.tempFilePath,
id: mun
}
_this.triggerEvent("getCropperImg", { list: list })
wx.hideLoading();
wx.saveImageToPhotosAlbum({
filePath: response.tempFilePath,
success(res) {
wx.showModal({//保存相册,不需要保存相册的上传服务器自己写
content: '图片已保存到相册了',
showCancel: false,
confirmText: '知道啦',
confirmColor: '#72B9C3',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
}
}
})
}
})
},
fail(e) {
console.log(e);
wx.hideLoading();
wx.showToast({
title: '生成图片失败',
icon: 'none'
})
}
}, this)
}, 2200);
});
},
//选择相片后初始化图片信息
initImg(url) {
let _this = this;
wx.getSystemInfo({//获取手机信息
success(res) {
_this.setData({//默认设置手机屏幕百分之八十
width: res.windowWidth * 0.8,
height: res.windowHeight * 0.8
})
}
})
wx.getImageInfo({//图片信息
src: url,
success(resopne) {
var imgWidth = resopne.width;
var imgHeight = resopne.height;
//根据屏幕缩小图片
widthRadio = imgWidth / _this.data.width;
heightRadio = imgHeight / _this.data.height;
if (imgWidth > imgHeight) {//宽大于高 图片处理
_this.setData({//初始化测试图片信息
originImg: {
url: url,
width: imgHeight / heightRadio,
height: imgWidth / widthRadio ,
judge:true//判断图片类型,
},
stv: {//初始化画布信息,旋转90度后 X,Y位置发生变化
offsetX: -70 - widthRadio,
offsetY: 70 + widthRadio,
zoom: false, //是否缩放状态
distance: 0, //两指距离
scale: 1, //缩放倍数
rotate: 90 //旋转角度
}
})
} else {
_this.setData({
originImg: {
url: url,
width: imgWidth / widthRadio,
height: imgHeight / heightRadio,
judge:false
},
stv: {
offsetX: 0,
offsetY: 0,
zoom: false, //是否缩放状态
distance: 0, //两指距离
scale: 1, //缩放倍数
rotate: 0
},
})
}
}
})
},
//事件处理函数
touchstartCallback: function (e) {
if (e.touches.length === 1) {
let { clientX, clientY } = e.touches[0];
this.startX = clientX;
this.startY = clientY;
this.touchStartEvent = e.touches;
} else {
let xMove = e.touches[1].clientX - e.touches[0].clientX;
let yMove = e.touches[1].clientY - e.touches[0].clientY;
let distance = Math.sqrt(xMove * xMove + yMove * yMove);
twoPoint.x1 = e.touches[0].pageX * 2
twoPoint.y1 = e.touches[0].pageY * 2
twoPoint.x2 = e.touches[1].pageX * 2
twoPoint.y2 = e.touches[1].pageY * 2
this.setData({
'stv.distance': distance,
'stv.zoom': true, //缩放状态
})
}
},
//图片手势动态缩放
touchmoveCallback: function (e) {
let _this = this
fn(_this, e)
},
touchendCallback: function (e) {
//触摸结束
if (e.touches.length === 0) {
this.setData({
'stv.zoom': false, //重置缩放状态
})
}
}
}
})
/**
* fn:延时调用函数
* delay:延迟多长时间
* mustRun:至少多长时间触发一次
*/
var throttle = function (fn, delay, mustRun) {
var timer = null,
previous = null;
return function () {
var now = +new Date(),
context = this,
args = arguments;
if (!previous) previous = now;
var remaining = now - previous;
if (mustRun && remaining >= mustRun) {
fn.apply(context, args);
previous = now;
} else {
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
}
}
}
var touchMove = function (_this, e) {
//触摸移动中
if (e.touches.length === 1) {
//单指移动
if (_this.data.stv.zoom) {
//缩放状态,不处理单指
return;
}
} else if (e.touches.length === 2) {
//双指缩放
let xMove = e.touches[1].clientX - e.touches[0].clientX;
let yMove = e.touches[1].clientY - e.touches[0].clientY;
let distance = Math.sqrt(xMove * xMove + yMove * yMove);
let distanceDiff = distance - _this.data.stv.distance;
let newScale = _this.data.stv.scale + 0.005 * distanceDiff;
if (newScale < 0.2 || newScale > 2.5) {
return;
}
_this.setData({
'stv.distance': distance,
'stv.scale': newScale,
})
} else {
return;
}
}
//为touchMove函数节流
const fn = throttle(touchMove, 10, 10);
效果图