本文实例为大家分享了微信小程序实现照片裁剪的具体代码,供大家参考,具体内容如下
前段时间用小程序的canvas、movable-area、movable-view封装了一个按比例裁剪照片的组件,无需引用任何插件。废话不多说,直接贴代码:
组件代码
1.cut_photo.json
{
"component": true
}
2.cut_photo.wxml
<view>
<canvas class="fyj_canvas" canvas-id="myCanvas" style="width:100%;height:{{canvasHeight}}px">
<movable-area class="fyj_movable_area text-center hidden" style="width:100%;height:{{canvasHeight}}px;">
<movable-view wx:if="{{src}}" style="width:{{cutWidth}}px;height:{{cutHeight}}px" class="fyj_movable_view"
x="{{x}}"
y="{{y}}"
direction="all"
bindchange="movableChange"
></movable-view>
<image class="fyj_photo" id="fyj_photo" src="{{src}}" mode="widthFix"></image>
</movable-area>
</canvas>
<view style="margin-top:20rpx;padding:0 20rpx;">
<button class="pull-left" type="warn" size="mini" bindtap="getPhoto">选择照片/拍照</button>
<button class="pull-right" type="primary" size="mini" bindtap="cut">裁剪</button>
<view class="clearfix"></view>
</view>
</view>
3.cut_photo.js
const app = getApp()
Component({
options: {
//multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
properties: {
// 这里定义了innerText属性,属性值可以在组件使用时指定
//宽高比
aspectRatio: {
type: Number,
value: 5/7,
}
},
data: {
screenWidth: wx.getSystemInfoSync().windowWidth,
canvasHeight: 300,
x: 0,
y: 0,
src: '',
cut_src: '',
cutWidth: 0,
cutHeight: 0
},
attached: function () {
},
methods: {
// 这里是一个自定义方法
//选择照片
getPhoto: function () {
const $this = this;
const ctx = wx.createCanvasContext('myCanvas',this)
var obj = wx.createSelectorQuery();
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
//清空之前的剪切图
$this.triggerEvent('getTempFilePath', { cut_src: '', cutWidth: $this.data.cutWidth, cutHeight: $this.data.cutHeight })
// tempFilePath可以作为img标签的src属性显示图片
const tempFilePaths = res.tempFilePaths[0];
$this.setData({
src: tempFilePaths,
cut_src: '',
});
setTimeout(function () {
wx.createSelectorQuery().in($this).select('#fyj_photo').boundingClientRect(function (rect) {
console.log(rect);
console.log(rect.height);
$this.setData({
canvasHeight: rect.height
})
ctx.drawImage(tempFilePaths, 0, 0, $this.data.screenWidth, $this.data.canvasHeight)
ctx.draw();
$this.setCut();
//确保不同大小的图片,切图不会变形
$this.setData({
x: 0,
y: 0
});
}).exec()
}, 100)
}
})
},
//获取图片高度
// getHeight:function(){
// const query = wx.createSelectorQuery().in(this)
// query.selectAll('#fyj_photo').boundingClientRect()
// query.exec(function (rect) {
// console.log(rect);
// console.log(rect[0].height);
// $this.setData({
// canvasHeight: rect[0].height
// })
// ctx.drawImage(tempFilePaths[0], 0, 0, $this.data.screenWidth, $this.data.canvasHeight)
// ctx.draw();
// $this.setCut();
// })
// },
//裁剪框移动事件
movableChange: function (e) {
console.log(e.detail);
this.setData({
x: e.detail.x,
y: e.detail.y
})
},
//截图
cut: function () {
const $this = this;
console.log($this.data.cutHeight);
wx.canvasToTempFilePath({
x: $this.data.x,
y: $this.data.y,
width: $this.data.cutWidth,
height: $this.data.cutHeight,
destWidth: $this.data.cutWidth,
destHeight: $this.data.cutHeight,
canvasId: 'myCanvas',
success(res) {
console.log(res.tempFilePath);
$this.setData({
cut_src: res.tempFilePath
})
$this.triggerEvent('getTempFilePath', { cut_src: $this.data.cut_src, cutWidth: $this.data.cutWidth, cutHeight: $this.data.cutHeight})
}
},this)
},
//动态设置裁剪框大小,确定高度不得超过canvas的高度
setCut: function () {
const $this = this;
this.setData({
cutWidth: wx.getSystemInfoSync().windowWidth * 0.8,
cutHeight: wx.getSystemInfoSync().windowWidth * 0.8/this.data.aspectRatio
})
if (this.data.cutHeight - 4 > this.data.canvasHeight) {
console.log($this.data.cutHeight);
console.log($this.data.canvasHeight);
this.setData({
cutHeight: this.data.canvasHeight - 4,
cutWidth: (this.data.canvasHeight - 4)*this.data.aspectRatio
})
} else {
this.setData({
cutWidth: wx.getSystemInfoSync().windowWidth * 0.8,
cutHeight: wx.getSystemInfoSync().windowWidth * 0.8/this.data.aspectRatio
})
}
console.log($this.data.cutWidth);
console.log($this.data.cutHeight);
},
}
})
4.cut_photo.wxss
.fyj_movable_area{width:100%;height:auto;position: relative;background:rgba(0,0,0,0.3)}
.fyj_movable_view{border:2px dashed #fff}
.fyj_photo{width:100%;}
.fyj_footer{margin-top:20rpx 0;}
.fyj_footerBtn{width:100%;display: inline-block;color:#fff;border-radius: 0;font-size:32rpx;}
.fyj_sure{background: #fc6b47;}
.pull-left{float:left;}
.pull-right{float:right}
.clearfix{clear:both}
.text-center{text-align: center}
引用页代码
1.page.json
{
"navigationBarTitleText": "选择照片",
"usingComponents": {
"cut-photo": "/pages/cut_photo/cut_photo"
}
}
2.page.wxml
<view>
<!-- aspectRatio 剪裁图片的宽高比 -->
<cut-photo aspectRatio="0.5" bindgetTempFilePath="getCutsrc"></cut-photo>
<view wx:if="{{cut_src}}" class="fyj_cutDiv text-center">
<image style="width:{{cutWidth}}px;height:{{cutHeight}}px" class="fyj_cut_photo" src="{{cut_src}}" mode="widthFix"></image>
</view>
<view wx:if="{{cut_src}}" class="fyj_footer text-center">
<button class="fyj_footerBtn fyj_sure" bindtap='sure'>确定</button>
</view>
</view>
3.page.js
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
cut_src:'',
cutWidth:0,
cutHeight:0,
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
getCutsrc:function(e){
console.log(e);
this.setData({
cut_src: e.detail.cut_src,
cutWidth: e.detail.cutWidth,
cutHeight: e.detail.cutHeight
})
}
})
4.page.wxss
.fyj_footer{margin-top:20rpx 0;}
.fyj_footerBtn{width:100%;display: inline-block;color:#fff;border-radius: 0;font-size:32rpx;}
.fyj_sure{background: #fc6b47;}
.fyj_cutDiv{margin:20rpx 0;}
大概思路
将canvas跟movable-area重合,通过movable-view来确定裁剪区域。为了确保图片加载不变形,选择完图片后,需要动态设置canvas、movable-area的高度及movable-view的宽高。