wxml
<canvas canvas-id="myCanvas" style="position:absolute;border: 1px solid red; width:{{imageW}}rpx;height:{{imageH}}rpx;top:-9999px;left:-9999px;"></canvas>
<view style="text-align: center;"><image style="width: 192rpx;height: 192rpx;border-radius: 500rpx !important;overflow: hidden; margin-top: 30rpx;margin-bottom: 30rpx;" src="{{returnImage}}"></image></view>
<view style="display: flex;">
<button type="primary" bindtap="getImageInfo">头像预览</button>
<button type="primary" bindtap="upload" loading="{{isdisabled}}" disabled="{{isdisabled}}">上传头像</button>
</view>
js
const app = getApp();
// 手机的宽度
var windowWRPX = 750
var pixelRatio = wx.getSystemInfoSync().pixelRatio
Page({
/**
* 页面的初始数据
*/
data: {
topLabel: '头像上传', //顶部栏
triggered: false, //模块是否刷新中
isdisabled: false, //是否提交
showmodel: false, //是否编辑模式
imageSrc: '',
returnImage: '',
isShowImg: false,
// 初始化的宽高
cropperInitW: windowWRPX,
cropperInitH: windowWRPX,
// 动态的宽高
cropperW: windowWRPX,
cropperH: windowWRPX,
// 动态的left top值
cropperL: 0,
cropperT: 0,
// 图片缩放值
scaleP: 0,
imageW: 0,
imageH: 0,
// 裁剪框 宽高
cutW: 0,
cutH: 0,
cutL: 0,
cutT: 0,
},
upload(e) { //头像上传
wx.showLoading({
title: '头像上传中...',
})
this.setData({isdisabled:true})
const userinfo = wx.getStorageSync('userinfo')
let encryptor = new Encrypt.JSEncrypt()
encryptor.setPublicKey(publicKey);
let requestkey = encryptor.encrypt(userinfo.YHBH + ',' + userinfo.OPENID + ',' + userinfo.BH + ',' + new Date().getTime()) // 加密
// 将图片写入画布
const ctx = wx.createCanvasContext('myCanvas')
ctx.drawImage(this.data.imageSrc)
ctx.draw(true, () => {
// 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题
let canvasW = (this.data.cutW / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasH = (this.data.cutH / this.data.cropperH) * (this.data.imageH / pixelRatio)
let canvasL = (this.data.cutL / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasT = (this.data.cutT / this.data.cropperH) * (this.data.imageH / pixelRatio)
setTimeout(() => {
wx.canvasToTempFilePath({
x: canvasL,
y: canvasT,
width: canvasW,
height: canvasH,
destWidth: canvasW * 0.35,//设置压缩百分比,如果写100就是分辨率
destHeight: canvasH * 0.35,//设置压缩百分比,如果写100就是分辨率
canvasId: 'myCanvas',
fileType: 'jpg',
success: res => {
wx.uploadFile({
url: App.uploads + '/weixin/upload/img/upload/cover',
filePath: res.tempFilePath,
name: 'file',
header: {
token: requestkey
},
formData: {
BH: wx.getStorageSync('userinfo').BH
},
success:res=>{
res.data = JSON.parse(res.data)
let pages = getCurrentPages();
let previousPage = pages[pages.length - 2]; //上一个页面
previousPage.setData({
avatarUrl: res.data.data.filePath
})
const userinfo = wx.getStorageSync('userinfo')
userinfo.TX = res.data.data.filePath
wx.setStorageSync('userinfo', userinfo)
wx.hideLoading()
wx.showToast({
title: '上传成功',
icon: "succes",
duration: 1500
})
this.setData({isdisabled:false})
},
fail:res=>{
this.setData({isdisabled:false})
wx.hideLoading()
wx.showToast({
title: '上传失败',
icon: "error",
duration: 1500
})
}
})
}
})
}, 500);
})
},
// 获取图片
getImageInfo() {
wx.showLoading({
title: '图片生成中...',
})
wx.downloadFile({
url: this.data.imageSrc, //仅为示例,并非真实的资源
success: res=>{
// 将图片写入画布
const ctx = wx.createCanvasContext('myCanvas')
ctx.drawImage(res.tempFilePath)
ctx.draw(true, () => {
// 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题
let canvasW = (this.data.cutW / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasH = (this.data.cutH / this.data.cropperH) * (this.data.imageH / pixelRatio)
let canvasL = (this.data.cutL / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasT = (this.data.cutT / this.data.cropperH) * (this.data.imageH / pixelRatio)
setTimeout(() => {
wx.canvasToTempFilePath({
x: canvasL,
y: canvasT,
width: canvasW,
height: canvasH,
destWidth: canvasW * 0.35,//设置压缩百分比,如果写100就是分辨率
destHeight: canvasH * 0.35,//设置压缩百分比,如果写100就是分辨率
canvasId: 'myCanvas',
fileType: 'jpg',
success: res=>{
wx.hideLoading()
// wx.getImageInfo({
// src: res.tempFilePath,
// success (res) {
// console.log(res.width)//图片宽
// console.log(res.height)//图片高
// }
// })
// 成功获得地址的地方
wx.previewImage({
current: '', // 当前显示图片的http链接
urls: [res.tempFilePath] // 需要预览的图片http链接列表
})
this.setData({
returnImage:res.tempFilePath
})
}
})
}, 200);
})
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.setData({
imageSrc: 'https://wx3.sinaimg.cn/orj360/6b03f0e6gy1h6c1mivf4lj20u01400wu.jpg'
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
wx.showLoading({
title: '图片加载中...',
})
wx.getImageInfo({
src: this.data.imageSrc,
success: res=>{
var innerAspectRadio = res.width / res.height;
// 根据图片的宽高显示不同的效果 保证图片可以正常显示
if (innerAspectRadio >= 1) {
this.setData({
cropperW: windowWRPX,
cropperH: windowWRPX / innerAspectRadio,
// 初始化left right
cropperL: Math.ceil((windowWRPX - windowWRPX) / 2),
cropperT: Math.ceil((windowWRPX - windowWRPX / innerAspectRadio) / 2),
// 裁剪框 宽高
cutW: windowWRPX,
cutH: windowWRPX / innerAspectRadio,
cutL: 0,
cutT: 0,
// 图片缩放值
scaleP: res.width * pixelRatio / windowWRPX,
// 图片原始宽度 rpx
imageW: res.width * pixelRatio,
imageH: res.height * pixelRatio
})
} else {
this.setData({
cropperW: windowWRPX * innerAspectRadio,
cropperH: windowWRPX,
// 初始化left right
cropperL: Math.ceil((windowWRPX - windowWRPX * innerAspectRadio) / 2),
cropperT: Math.ceil((windowWRPX - windowWRPX) / 2),
// 裁剪框的宽高
cutW: windowWRPX * innerAspectRadio,
cutH: windowWRPX,
cutL: 0,
cutT: 0,
// 图片缩放值
scaleP: res.width * pixelRatio / windowWRPX,
// 图片原始宽度 rpx
imageW: res.width * pixelRatio,
imageH: res.height * pixelRatio
})
}
this.setData({
isShowImg: true
})
wx.hideLoading()
}
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
实际应用场景
wxml
<canvas canvas-id="myCanvas" style="position:absolute;border: 1px solid red; width:{{imageW}}rpx;height:{{imageH}}rpx;top:-9999px;left:-9999px;"></canvas>
<button class="round cu-avatar" plain="true" open-type="chooseAvatar" bind:chooseavatar="getimginfo" style="border: 0;width: 158rpx;height: 158rpx;">
<image class="round" src="https://wx3.sinaimg.cn/orj360/6b03f0e6gy1h6c1mivf4lj20u01400wu.jpg" style="width: 158rpx;height: 158rpx;"></image>
</button>
js
const app = getApp();
// 手机的宽度
var windowWRPX = 750
var pixelRatio = wx.getSystemInfoSync().pixelRatio
Page({
/**
* 页面的初始数据
*/
data: {
topLabel: '头像上传', //顶部栏
// 初始化的宽高
cropperInitW: windowWRPX,
cropperInitH: windowWRPX,
// 动态的宽高
cropperW: windowWRPX,
cropperH: windowWRPX,
// 动态的left top值
cropperL: 0,
cropperT: 0,
// 图片缩放值
scaleP: 0,
imageW: 0,
imageH: 0,
// 裁剪框 宽高
cutW: 0,
cutH: 0,
cutL: 0,
cutT: 0,
},
getimginfo(e) { //获取图片信息
wx.getImageInfo({
src: e.detail.avatarUrl,
success: res => {
var innerAspectRadio = res.width / res.height;
// 根据图片的宽高显示不同的效果 保证图片可以正常显示
if (innerAspectRadio >= 1) {
this.setData({
cropperW: windowWRPX,
cropperH: windowWRPX / innerAspectRadio,
// 初始化left right
cropperL: Math.ceil((windowWRPX - windowWRPX) / 2),
cropperT: Math.ceil((windowWRPX - windowWRPX / innerAspectRadio) / 2),
// 裁剪框 宽高
cutW: windowWRPX,
cutH: windowWRPX / innerAspectRadio,
cutL: 0,
cutT: 0,
// 图片缩放值
scaleP: res.width * pixelRatio / windowWRPX,
// 图片原始宽度 rpx
imageW: res.width * pixelRatio,
imageH: res.height * pixelRatio
})
} else {
this.setData({
cropperW: windowWRPX * innerAspectRadio,
cropperH: windowWRPX,
// 初始化left right
cropperL: Math.ceil((windowWRPX - windowWRPX * innerAspectRadio) / 2),
cropperT: Math.ceil((windowWRPX - windowWRPX) / 2),
// 裁剪框的宽高
cutW: windowWRPX * innerAspectRadio,
cutH: windowWRPX,
cutL: 0,
cutT: 0,
// 图片缩放值
scaleP: res.width * pixelRatio / windowWRPX,
// 图片原始宽度 rpx
imageW: res.width * pixelRatio,
imageH: res.height * pixelRatio
})
}
this.upfile(e.detail.avatarUrl)
}
})
},
upfile(url) { //上传图片
wx.getFileInfo({
filePath: url,
success: res => {
if (res.size > 10000) { //大于10KB就压缩
const ctx = wx.createCanvasContext('myCanvas')
ctx.drawImage(url)
ctx.draw(true, () => {
// 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题
let canvasW = (this.data.cutW / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasH = (this.data.cutH / this.data.cropperH) * (this.data.imageH / pixelRatio)
let canvasL = (this.data.cutL / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasT = (this.data.cutT / this.data.cropperH) * (this.data.imageH / pixelRatio)
setTimeout(() => {
wx.canvasToTempFilePath({
x: canvasL,
y: canvasT,
width: canvasW,
height: canvasH,
destWidth: canvasW * 0.35, //设置压缩百分比,如果写100就是分辨率
destHeight: canvasH * 0.35, //设置压缩百分比,如果写100就是分辨率
canvasId: 'myCanvas',
fileType: 'jpg',
success: res => {
wx.uploadFile({
url: App.uploads + '/file/api/upload',
filePath: res.tempFilePath,
name: 'file',
header: {
authToken: wx.getStorageSync('token'),
},
success: res => {
res.data = JSON.parse(res.data)
this.data.tx = res.data.data.filePath
this.batchmodify()
},
fail: res => {
wx.hideLoading()
wx.showToast({
title: '上传失败',
icon: "error",
duration: 1500
})
}
})
}
})
}, 500);
})
} else {
wx.uploadFile({
url: App.uploads + '/file/api/upload',
filePath: url,
name: 'file',
header: {
authToken: wx.getStorageSync('token'),
},
success: res => {
res.data = JSON.parse(res.data)
this.data.tx = res.data.data.filePath
this.batchmodify()
},
fail: res => {
wx.hideLoading()
wx.showToast({
title: '上传失败',
icon: "error",
duration: 1500
})
}
})
}
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
css
.round {
border-radius: 5000rpx !important;
overflow: hidden;
}
.cu-avatar {
font-variant: small-caps;
margin: 0;
padding: 0;
display: inline-flex;
text-align: center;
justify-content: center;
align-items: center;
background-color: #ccc;
color: var(--white);
white-space: nowrap;
position: relative;
width: 64rpx;
height: 64rpx;
background-size: cover;
background-position: center;
vertical-align: middle;
font-size: 1.5em;
}