一、通過小程序API:裁剪圖片接口wx.cropImage
媒體 / 圖片 / wx.cropImage (qq.com)
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album', 'camera'],
success: (res) => {
var tempFiles = res.tempFiles;
var pathList = that.data.pathList;
wx.cropImage({
src: tempFiles[0].tempFilePath, // 圖片路徑
cropScale: '1:1', // 裁剪比例
success: function (res) {
if (!/(\.jpg|\.png|\.jpeg)$/.test(res.tempFilePath.toLowerCase())) {
wx.showToast({
title: '請上傳jpg、png或jpeg格式的圖片',
icon: 'none',
});
return;
}
var tempFilePaths = res.tempFilePath;
console.log('裁剪圖',tempFilePaths)
}
})
}
})
二、通過小程序圖片裁剪插件 image-cropper
小程序圖片裁剪插件 image-cropper | 微信開放社區(qū) (qq.com)
1、將插件項目中image-cropper文件內(nèi)容復(fù)制到本地項目中的compoent中
wxml:
<view class='image-cropper' catchtouchmove='_preventTouchMove'>
<view class='main' bindtouchend="_cutTouchEnd" bindtouchstart="_cutTouchStart" bindtouchmove="_cutTouchMove" bindtap="_click">
<view class='content'>
<view class='content_top bg_gray {{_flag_bright?"":"bg_black"}}' style="height:{{cut_top}}px;transition-property:{{_cut_animation?'':'background'}}"></view>
<view class='content_middle' style="height:{{height}}px;">
<view class='content_middle_left bg_gray {{_flag_bright?"":"bg_black"}}' style="width:{{cut_left}}px;transition-property:{{_cut_animation?'':'background'}}"></view>
<view class='content_middle_middle' style="width:{{width}}px;height:{{height}}px;transition-duration: .3s;transition-property:{{_cut_animation?'':'background'}};">
<view class="border border-top-left"></view>
<view class="border border-top-right"></view>
<view class="border border-right-top"></view>
<view class="border border-right-bottom"></view>
<view class="border border-bottom-right"></view>
<view class="border border-bottom-left"></view>
<view class="border border-left-bottom"></view>
<view class="border border-left-top"></view>
</view>
<view class='content_middle_right bg_gray {{_flag_bright?"":"bg_black"}}' style="transition-property:{{_cut_animation?'':'background'}}"></view>
</view>
<view class='content_bottom bg_gray {{_flag_bright?"":"bg_black"}}' style="transition-property:{{_cut_animation?'':'background'}}"></view>
</view>
<image bindload="imageLoad" bindtouchstart="_start" bindtouchmove="_move" bindtouchend="_end" style="width:{{img_width ? img_width + 'px' : 'auto'}};height:{{img_height ? img_height + 'px' : 'auto'}};transform:translate3d({{_img_left-img_width/2}}px,{{_img_top-img_height/2}}px,0) scale({{scale}}) rotate({{angle}}deg);transition-duration:{{_cut_animation?.4:0}}s;" class='img' src='{{imgSrc}}'></image>
</view>
<canvas canvas-id='image-cropper' disable-scroll="true" style="width:{{_canvas_width * export_scale}}px;height:{{_canvas_height * export_scale}}px;left:{{canvas_left}}px;top:{{canvas_top}}px" class='image-cropper-canvas'></canvas>
</view>
js:
Component({
properties: {
/**
* 圖片路徑
*/
'imgSrc': {
type: String
},
/**
* 裁剪框高度
*/
'height': {
type: Number,
value: 200
},
/**
* 裁剪框?qū)挾? */
'width': {
type: Number,
value: 200
},
/**
* 裁剪框最小尺寸
*/
'min_width': {
type: Number,
value: 100
},
'min_height': {
type: Number,
value: 100
},
/**
* 裁剪框最大尺寸
*/
'max_width': {
type: Number,
value: 300
},
'max_height': {
type: Number,
value: 300
},
/**
* 裁剪框禁止拖動
*/
'disable_width': {
type: Boolean,
value: false
},
'disable_height': {
type: Boolean,
value: false
},
/**
* 鎖定裁剪框比例
*/
'disable_ratio': {
type: Boolean,
value: false
},
/**
* 生成的圖片尺寸相對剪裁框的比例
*/
'export_scale': {
type: Number,
value: 3
},
/**
* 生成的圖片質(zhì)量0-1
*/
'quality': {
type: Number,
value: 1
},
'cut_top': {
type: Number,
value: null
},
'cut_left': {
type: Number,
value: null
},
/**
* canvas上邊距(不設(shè)置默認不顯示)
*/
'canvas_top': {
type: Number,
value: null
},
/**
* canvas左邊距(不設(shè)置默認不顯示)
*/
'canvas_left': {
type: Number,
value: null
},
/**
* 圖片寬度
*/
'img_width': {
type: null,
value: null
},
/**
* 圖片高度
*/
'img_height': {
type: null,
value: null
},
/**
* 圖片縮放比
*/
'scale': {
type: Number,
value: 1
},
/**
* 圖片旋轉(zhuǎn)角度
*/
'angle': {
type: Number,
value: 0
},
/**
* 最小縮放比
*/
'min_scale': {
type: Number,
value: 0.5
},
/**
* 最大縮放比
*/
'max_scale': {
type: Number,
value: 2
},
/**
* 是否禁用旋轉(zhuǎn)
*/
'disable_rotate': {
type: Boolean,
value: false
},
/**
* 是否限制移動范圍(剪裁框只能在圖片內(nèi))
*/
'limit_move': {
type: Boolean,
value: false
}
},
data: {
el: 'image-cropper', //暫時無用
info: wx.getSystemInfoSync(),
MOVE_THROTTLE: null, //觸摸移動節(jié)流settimeout
MOVE_THROTTLE_FLAG: true, //節(jié)流標識
INIT_IMGWIDTH: 0, //圖片設(shè)置尺寸,此值不變(記錄最初設(shè)定的尺寸)
INIT_IMGHEIGHT: 0, //圖片設(shè)置尺寸,此值不變(記錄最初設(shè)定的尺寸)
TIME_BG: null, //背景變暗延時函數(shù)
TIME_CUT_CENTER: null,
_touch_img_relative: [{
x: 0,
y: 0
}], //鼠標和圖片中心的相對位置
_flag_cut_touch: false, //是否是拖動裁剪框
_hypotenuse_length: 0, //雙指觸摸時斜邊長度
_flag_img_endtouch: false, //是否結(jié)束觸摸
_flag_bright: true, //背景是否亮
_canvas_overflow: true, //canvas縮略圖是否在屏幕外面
_canvas_width: 200,
_canvas_height: 200,
origin_x: 0.5, //圖片旋轉(zhuǎn)中心
origin_y: 0.5, //圖片旋轉(zhuǎn)中心
_cut_animation: false, //是否開啟圖片和裁剪框過渡
_img_top: wx.getSystemInfoSync().windowHeight / 2, //圖片上邊距
_img_left: wx.getSystemInfoSync().windowWidth / 2, //圖片左邊距
watch: {
//監(jiān)聽截取框?qū)捀咦兓? width(value, that) {
if (value < that.data.min_width) {
that.setData({
width: that.data.min_width
});
}
that._computeCutSize();
},
height(value, that) {
if (value < that.data.min_height) {
that.setData({
height: that.data.min_height
});
}
that._computeCutSize();
},
angle(value, that) {
//停止居中裁剪框,繼續(xù)修改圖片位置
that._moveStop();
if (that.data.limit_move) {
if (that.data.angle % 90) {
that.setData({
angle: Math.round(that.data.angle / 90) * 90
});
return;
}
}
},
_cut_animation(value, that) {
//開啟過渡300毫秒之后自動關(guān)閉
clearTimeout(that.data._cut_animation_time);
if (value) {
that.data._cut_animation_time = setTimeout(() => {
that.setData({
_cut_animation: false
});
}, 300)
}
},
limit_move(value, that) {
if (value) {
if (that.data.angle % 90) {
that.setData({
angle: Math.round(that.data.angle / 90) * 90
});
}
that._imgMarginDetectionScale();
!that.data._canvas_overflow && that._draw();
}
},
canvas_top(value, that) {
that._canvasDetectionPosition();
},
canvas_left(value, that) {
that._canvasDetectionPosition();
},
imgSrc(value, that) {
that.pushImg();
},
cut_top(value, that) {
that._cutDetectionPosition();
if (that.data.limit_move) {
!that.data._canvas_overflow && that._draw();
}
},
cut_left(value, that) {
that._cutDetectionPosition();
if (that.data.limit_move) {
!that.data._canvas_overflow && that._draw();
}
}
}
},
attached() {
this.data.info = wx.getSystemInfoSync();
//啟用數(shù)據(jù)監(jiān)聽
this._watcher();
this.data.INIT_IMGWIDTH = this.data.img_width;
this.data.INIT_IMGHEIGHT = this.data.img_height;
this.setData({
_canvas_height: this.data.height,
_canvas_width: this.data.width,
});
this._initCanvas();
this.data.imgSrc && (this.data.imgSrc = this.data.imgSrc);
//根據(jù)開發(fā)者設(shè)置的圖片目標尺寸計算實際尺寸
this._initImageSize();
//設(shè)置裁剪框大小>設(shè)置圖片尺寸>繪制canvas
this._computeCutSize();
//檢查裁剪框是否在范圍內(nèi)
this._cutDetectionPosition();
//檢查canvas是否在范圍內(nèi)
this._canvasDetectionPosition();
//初始化完成
this.triggerEvent('load', {
cropper: this
});
},
methods: {
/**
* 上傳圖片
*/
upload() {
let that = this;
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0];
that.pushImg(tempFilePaths);
wx.showLoading({
title: '加載中...'
})
}
})
},
/**
* 返回圖片信息
*/
getImg(getCallback) {
this._draw(() => {
wx.canvasToTempFilePath({
width: this.data.width * this.data.export_scale,
height: Math.round(this.data.height * this.data.export_scale),
destWidth: this.data.width * this.data.export_scale,
destHeight: Math.round(this.data.height) * this.data.export_scale,
fileType: 'png',
quality: this.data.quality,
canvasId: this.data.el,
success: (res) => {
getCallback({
url: res.tempFilePath,
width: this.data.width * this.data.export_scale,
height: this.data.height * this.data.export_scale
});
}
}, this)
});
},
/**
* 設(shè)置圖片動畫
* {
* x:10,//圖片在原有基礎(chǔ)上向下移動10px
* y:10,//圖片在原有基礎(chǔ)上向右移動10px
* angle:10,//圖片在原有基礎(chǔ)上旋轉(zhuǎn)10deg
* scale:0.5,//圖片在原有基礎(chǔ)上增加0.5倍
* }
*/
setTransform(transform) {
if (!transform) return;
if (!this.data.disable_rotate) {
this.setData({
angle: transform.angle ? this.data.angle + transform.angle : this.data.angle
});
}
var scale = this.data.scale;
if (transform.scale) {
scale = this.data.scale + transform.scale;
scale = scale <= this.data.min_scale ? this.data.min_scale : scale;
scale = scale >= this.data.max_scale ? this.data.max_scale : scale;
}
this.data.scale = scale;
let cutX = this.data.cut_left;
let cutY = this.data.cut_top;
if (transform.cutX) {
this.setData({
cut_left: cutX + transform.cutX
});
this.data.watch.cut_left(null, this);
}
if (transform.cutY) {
this.setData({
cut_top: cutY + transform.cutY
});
this.data.watch.cut_top(null, this);
}
this.data._img_top = transform.y ? this.data._img_top + transform.y : this.data._img_top;
this.data._img_left = transform.x ? this.data._img_left + transform.x : this.data._img_left;
//圖像邊緣檢測,防止截取到空白
this._imgMarginDetectionScale();
//停止居中裁剪框,繼續(xù)修改圖片位置
this._moveDuring();
this.setData({
scale: this.data.scale,
_img_top: this.data._img_top,
_img_left: this.data._img_left
});
!this.data._canvas_overflow && this._draw();
//可以居中裁剪框了
this._moveStop(); //結(jié)束操作
},
/**
* 設(shè)置剪裁框位置
*/
setCutXY(x, y) {
this.setData({
cut_top: y,
cut_left: x
});
},
/**
* 設(shè)置剪裁框尺寸
*/
setCutSize(w, h) {
this.setData({
width: w,
height: h
});
this._computeCutSize();
},
/**
* 設(shè)置剪裁框和圖片居中
*/
setCutCenter() {
let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;
let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;
//順序不能變
this.setData({
_img_top: this.data._img_top - this.data.cut_top + cut_top,
cut_top: cut_top, //截取的框上邊距
_img_left: this.data._img_left - this.data.cut_left + cut_left,
cut_left: cut_left, //截取的框左邊距
});
},
_setCutCenter() {
let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;
let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;
this.setData({
cut_top: cut_top, //截取的框上邊距
cut_left: cut_left, //截取的框左邊距
});
},
/**
* 設(shè)置剪裁框?qū)挾?即將廢棄
*/
setWidth(width) {
this.setData({
width: width
});
this._computeCutSize();
},
/**
* 設(shè)置剪裁框高度-即將廢棄
*/
setHeight(height) {
this.setData({
height: height
});
this._computeCutSize();
},
/**
* 是否鎖定旋轉(zhuǎn)
*/
setDisableRotate(value) {
this.data.disable_rotate = value;
},
/**
* 是否限制移動
*/
setLimitMove(value) {
this.setData({
_cut_animation: true,
limit_move: !!value
});
},
/**
* 初始化圖片,包括位置、大小、旋轉(zhuǎn)角度
*/
imgReset() {
this.setData({
scale: 1,
angle: 0,
_img_top: wx.getSystemInfoSync().windowHeight / 2,
_img_left: wx.getSystemInfoSync().windowWidth / 2,
})
},
/**
* 加載(更換)圖片
*/
pushImg(src) {
if (src) {
this.setData({
imgSrc: src
});
//發(fā)現(xiàn)是手動賦值直接返回,交給watch處理
return;
}
// getImageInfo接口傳入 src: '' 會導(dǎo)致內(nèi)存泄漏
if (!this.data.imgSrc) return;
wx.getImageInfo({
src: this.data.imgSrc,
success: (res) => {
this.data.imageObject = res;
//圖片非本地路徑需要換成本地路徑
if (this.data.imgSrc.search(/tmp/) == -1) {
this.setData({
imgSrc: res.path
});
}
//計算最后圖片尺寸
this._imgComputeSize();
if (this.data.limit_move) {
//限制移動,不留空白處理
this._imgMarginDetectionScale();
}
this._draw();
},
fail: (err) => {
this.setData({
imgSrc: ''
});
}
});
},
imageLoad(e) {
setTimeout(() => {
this.triggerEvent('imageload', this.data.imageObject);
}, 1000)
},
/**
* 設(shè)置圖片放大縮小
*/
setScale(scale) {
if (!scale) return;
this.setData({
scale: scale
});
!this.data._canvas_overflow && this._draw();
},
/**
* 設(shè)置圖片旋轉(zhuǎn)角度
*/
setAngle(angle) {
if (!angle) return;
this.setData({
_cut_animation: true,
angle: angle
});
this._imgMarginDetectionScale();
!this.data._canvas_overflow && this._draw();
},
_initCanvas() {
//初始化canvas
if (!this.data.ctx) {
this.data.ctx = wx.createCanvasContext("image-cropper", this);
}
},
/**
* 根據(jù)開發(fā)者設(shè)置的圖片目標尺寸計算實際尺寸
*/
_initImageSize() {
//處理寬高特殊單位 %>px
if (this.data.INIT_IMGWIDTH && typeof this.data.INIT_IMGWIDTH == "string" && this.data.INIT_IMGWIDTH.indexOf("%") != -1) {
let width = this.data.INIT_IMGWIDTH.replace("%", "");
this.data.INIT_IMGWIDTH = this.data.img_width = this.data.info.windowWidth / 100 * width;
}
if (this.data.INIT_IMGHEIGHT && typeof this.data.INIT_IMGHEIGHT == "string" && this.data.INIT_IMGHEIGHT.indexOf("%") != -1) {
let height = this.data.img_height.replace("%", "");
this.data.INIT_IMGHEIGHT = this.data.img_height = this.data.info.windowHeight / 100 * height;
}
},
/**
* 檢測剪裁框位置是否在允許的范圍內(nèi)(屏幕內(nèi))
*/
_cutDetectionPosition() {
let _cutDetectionPositionTop = () => {
//檢測上邊距是否在范圍內(nèi)
if (this.data.cut_top < 0) {
this.setData({
cut_top: 0
});
}
if (this.data.cut_top > this.data.info.windowHeight - this.data.height) {
this.setData({
cut_top: this.data.info.windowHeight - this.data.height
});
}
},
_cutDetectionPositionLeft = () => {
//檢測左邊距是否在范圍內(nèi)
if (this.data.cut_left < 0) {
this.setData({
cut_left: 0
});
}
if (this.data.cut_left > this.data.info.windowWidth - this.data.width) {
this.setData({
cut_left: this.data.info.windowWidth - this.data.width
});
}
};
//裁剪框坐標處理(如果只寫一個參數(shù)則另一個默認為0,都不寫默認居中)
if (this.data.cut_top == null && this.data.cut_left == null) {
this._setCutCenter();
} else if (this.data.cut_top != null && this.data.cut_left != null) {
_cutDetectionPositionTop();
_cutDetectionPositionLeft();
} else if (this.data.cut_top != null && this.data.cut_left == null) {
_cutDetectionPositionTop();
this.setData({
cut_left: (this.data.info.windowWidth - this.data.width) / 2
});
} else if (this.data.cut_top == null && this.data.cut_left != null) {
_cutDetectionPositionLeft();
this.setData({
cut_top: (this.data.info.windowHeight - this.data.height) / 2
});
}
},
/**
* 檢測canvas位置是否在允許的范圍內(nèi)(屏幕內(nèi))如果在屏幕外則不開啟實時渲染
* 如果只寫一個參數(shù)則另一個默認為0,都不寫默認超出屏幕外
*/
_canvasDetectionPosition() {
if (this.data.canvas_top == null && this.data.canvas_left == null) {
this.data._canvas_overflow = false;
this.setData({
canvas_top: -5000,
canvas_left: -5000
});
} else if (this.data.canvas_top != null && this.data.canvas_left != null) {
if (this.data.canvas_top < -this.data.height || this.data.canvas_top > this.data.info.windowHeight) {
this.data._canvas_overflow = true;
} else {
this.data._canvas_overflow = false;
}
} else if (this.data.canvas_top != null && this.data.canvas_left == null) {
this.setData({
canvas_left: 0
});
} else if (this.data.canvas_top == null && this.data.canvas_left != null) {
this.setData({
canvas_top: 0
});
if (this.data.canvas_left < -this.data.width || this.data.canvas_left > this.data.info.windowWidth) {
this.data._canvas_overflow = true;
} else {
this.data._canvas_overflow = false;
}
}
},
/**
* 圖片邊緣檢測-位置
*/
_imgMarginDetectionPosition(scale) {
if (!this.data.limit_move) return;
let left = this.data._img_left;
let top = this.data._img_top;
var scale = scale || this.data.scale;
let img_width = this.data.img_width;
let img_height = this.data.img_height;
if (this.data.angle / 90 % 2) {
img_width = this.data.img_height;
img_height = this.data.img_width;
}
left = this.data.cut_left + img_width * scale / 2 >= left ? left : this.data.cut_left + img_width * scale / 2;
left = this.data.cut_left + this.data.width - img_width * scale / 2 <= left ? left : this.data.cut_left + this.data.width - img_width * scale / 2;
top = this.data.cut_top + img_height * scale / 2 >= top ? top : this.data.cut_top + img_height * scale / 2;
top = this.data.cut_top + this.data.height - img_height * scale / 2 <= top ? top : this.data.cut_top + this.data.height - img_height * scale / 2;
this.setData({
_img_left: left,
_img_top: top,
scale: scale
})
},
/**
* 圖片邊緣檢測-縮放
*/
_imgMarginDetectionScale() {
if (!this.data.limit_move) return;
let scale = this.data.scale;
let img_width = this.data.img_width;
let img_height = this.data.img_height;
if (this.data.angle / 90 % 2) {
img_width = this.data.img_height;
img_height = this.data.img_width;
}
if (img_width * scale < this.data.width) {
scale = this.data.width / img_width;
}
if (img_height * scale < this.data.height) {
scale = Math.max(scale, this.data.height / img_height);
}
this._imgMarginDetectionPosition(scale);
},
_setData(obj) {
let data = {};
for (var key in obj) {
if (this.data[key] != obj[key]) {
data[key] = obj[key];
}
}
this.setData(data);
return data;
},
/**
* 計算圖片尺寸
*/
_imgComputeSize() {
let img_width = this.data.img_width,
img_height = this.data.img_height;
if (!this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {
//默認按圖片最小邊 = 對應(yīng)裁剪框尺寸
img_width = this.data.imageObject.width;
img_height = this.data.imageObject.height;
if (img_width / img_height > this.data.width / this.data.height) {
img_height = this.data.height;
img_width = this.data.imageObject.width / this.data.imageObject.height * img_height;
} else {
img_width = this.data.width;
img_height = this.data.imageObject.height / this.data.imageObject.width * img_width;
}
} else if (this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {
img_width = this.data.imageObject.width / this.data.imageObject.height * this.data.INIT_IMGHEIGHT;
} else if (!this.data.INIT_IMGHEIGHT && this.data.INIT_IMGWIDTH) {
img_height = this.data.imageObject.height / this.data.imageObject.width * this.data.INIT_IMGWIDTH;
}
this.setData({
img_width: img_width,
img_height: img_height
});
},
//改變截取框大小
_computeCutSize() {
if (this.data.width > this.data.info.windowWidth) {
this.setData({
width: this.data.info.windowWidth,
});
} else if (this.data.width + this.data.cut_left > this.data.info.windowWidth) {
this.setData({
cut_left: this.data.info.windowWidth - this.data.cut_left,
});
};
if (this.data.height > this.data.info.windowHeight) {
this.setData({
height: this.data.info.windowHeight,
});
} else if (this.data.height + this.data.cut_top > this.data.info.windowHeight) {
this.setData({
cut_top: this.data.info.windowHeight - this.data.cut_top,
});
}!this.data._canvas_overflow && this._draw();
},
//開始觸摸
_start(event) {
this.data._flag_img_endtouch = false;
if (event.touches.length == 1) {
//單指拖動
this.data._touch_img_relative[0] = {
x: (event.touches[0].clientX - this.data._img_left),
y: (event.touches[0].clientY - this.data._img_top)
}
} else {
//雙指放大
let width = Math.abs(event.touches[0].clientX - event.touches[1].clientX);
let height = Math.abs(event.touches[0].clientY - event.touches[1].clientY);
this.data._touch_img_relative = [{
x: (event.touches[0].clientX - this.data._img_left),
y: (event.touches[0].clientY - this.data._img_top)
}, {
x: (event.touches[1].clientX - this.data._img_left),
y: (event.touches[1].clientY - this.data._img_top)
}];
this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
}!this.data._canvas_overflow && this._draw();
},
_move_throttle() {
//安卓需要節(jié)流
if (this.data.info.platform == 'android') {
clearTimeout(this.data.MOVE_THROTTLE);
this.data.MOVE_THROTTLE = setTimeout(() => {
this.data.MOVE_THROTTLE_FLAG = true;
}, 1000 / 40)
return this.data.MOVE_THROTTLE_FLAG;
} else {
this.data.MOVE_THROTTLE_FLAG = true;
}
},
_move(event) {
if (this.data._flag_img_endtouch || !this.data.MOVE_THROTTLE_FLAG) return;
this.data.MOVE_THROTTLE_FLAG = false;
this._move_throttle();
this._moveDuring();
if (event.touches.length == 1) {
//單指拖動
let left = (event.touches[0].clientX - this.data._touch_img_relative[0].x),
top = (event.touches[0].clientY - this.data._touch_img_relative[0].y);
//圖像邊緣檢測,防止截取到空白
this.data._img_left = left;
this.data._img_top = top;
this._imgMarginDetectionPosition();
this.setData({
_img_left: this.data._img_left,
_img_top: this.data._img_top
});
} else {
//雙指放大
let width = (Math.abs(event.touches[0].clientX - event.touches[1].clientX)),
height = (Math.abs(event.touches[0].clientY - event.touches[1].clientY)),
hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)),
scale = this.data.scale * (hypotenuse / this.data._hypotenuse_length),
current_deg = 0;
scale = scale <= this.data.min_scale ? this.data.min_scale : scale;
scale = scale >= this.data.max_scale ? this.data.max_scale : scale;
//圖像邊緣檢測,防止截取到空白
this.data.scale = scale;
this._imgMarginDetectionScale();
//雙指旋轉(zhuǎn)(如果沒禁用旋轉(zhuǎn))
let _touch_img_relative = [{
x: (event.touches[0].clientX - this.data._img_left),
y: (event.touches[0].clientY - this.data._img_top)
}, {
x: (event.touches[1].clientX - this.data._img_left),
y: (event.touches[1].clientY - this.data._img_top)
}];
if (!this.data.disable_rotate) {
let first_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[0].y, _touch_img_relative[0].x);
let first_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[0].y, this.data._touch_img_relative[0].x);
let second_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[1].y, _touch_img_relative[1].x);
let second_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[1].y, this.data._touch_img_relative[1].x);
//當前旋轉(zhuǎn)的角度
let first_deg = first_atan - first_atan_old,
second_deg = second_atan - second_atan_old;
if (first_deg != 0) {
current_deg = first_deg;
} else if (second_deg != 0) {
current_deg = second_deg;
}
}
this.data._touch_img_relative = _touch_img_relative;
this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
//更新視圖
this.setData({
angle: this.data.angle + current_deg,
scale: this.data.scale
});
}!this.data._canvas_overflow && this._draw();
},
//結(jié)束操作
_end(event) {
this.data._flag_img_endtouch = true;
this._moveStop();
},
//點擊中間剪裁框處理
_click(event) {
if (!this.data.imgSrc) {
//調(diào)起上傳
this.upload();
return;
}
this._draw(() => {
let x = event.detail ? event.detail.x : event.touches[0].clientX;
let y = event.detail ? event.detail.y : event.touches[0].clientY;
if ((x >= this.data.cut_left && x <= (this.data.cut_left + this.data.width)) && (y >= this.data.cut_top && y <= (this.data.cut_top + this.data.height))) {
//生成圖片并回調(diào)
wx.canvasToTempFilePath({
width: this.data.width * this.data.export_scale,
height: Math.round(this.data.height * this.data.export_scale),
destWidth: this.data.width * this.data.export_scale,
destHeight: Math.round(this.data.height) * this.data.export_scale,
fileType: 'png',
quality: this.data.quality,
canvasId: this.data.el,
success: (res) => {
this.triggerEvent('tapcut', {
url: res.tempFilePath,
width: this.data.width * this.data.export_scale,
height: this.data.height * this.data.export_scale
});
}
}, this)
}
});
},
//渲染
_draw(callback) {
if (!this.data.imgSrc) return;
let draw = () => {
//圖片實際大小
let img_width = this.data.img_width * this.data.scale * this.data.export_scale;
let img_height = this.data.img_height * this.data.scale * this.data.export_scale;
//canvas和圖片的相對距離
var xpos = this.data._img_left - this.data.cut_left;
var ypos = this.data._img_top - this.data.cut_top;
//旋轉(zhuǎn)畫布
this.data.ctx.translate(xpos * this.data.export_scale, ypos * this.data.export_scale);
this.data.ctx.rotate(this.data.angle * Math.PI / 180);
this.data.ctx.drawImage(this.data.imgSrc, -img_width / 2, -img_height / 2, img_width, img_height);
this.data.ctx.draw(false, () => {
callback && callback();
});
}
if (this.data.ctx.width != this.data.width || this.data.ctx.height != this.data.height) {
//優(yōu)化拖動裁剪框,所以必須把寬高設(shè)置放在離用戶觸發(fā)渲染最近的地方
this.setData({
_canvas_height: this.data.height,
_canvas_width: this.data.width,
}, () => {
//延遲40毫秒防止點擊過快出現(xiàn)拉伸或裁剪過多
setTimeout(() => {
draw();
}, 40);
});
} else {
draw();
}
},
//裁剪框處理
_cutTouchMove(e) {
if (this.data._flag_cut_touch && this.data.MOVE_THROTTLE_FLAG) {
if (this.data.disable_ratio && (this.data.disable_width || this.data.disable_height)) return;
//節(jié)流
this.data.MOVE_THROTTLE_FLAG = false;
this._move_throttle();
let width = this.data.width,
height = this.data.height,
cut_top = this.data.cut_top,
cut_left = this.data.cut_left,
size_correct = () => {
width = width <= this.data.max_width ? width >= this.data.min_width ? width : this.data.min_width : this.data.max_width;
height = height <= this.data.max_height ? height >= this.data.min_height ? height : this.data.min_height : this.data.max_height;
},
size_inspect = () => {
if ((width > this.data.max_width || width < this.data.min_width || height > this.data.max_height || height < this.data.min_height) && this.data.disable_ratio) {
size_correct();
return false;
} else {
size_correct();
return true;
}
};
height = this.data.CUT_START.height + ((this.data.CUT_START.corner > 1 && this.data.CUT_START.corner < 4 ? 1 : -1) * (this.data.CUT_START.y - e.touches[0].clientY));
switch (this.data.CUT_START.corner) {
case 1:
width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;
if (this.data.disable_ratio) {
height = width / (this.data.width / this.data.height)
}
if (!size_inspect()) return;
cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width);
break
case 2:
width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;
if (this.data.disable_ratio) {
height = width / (this.data.width / this.data.height)
}
if (!size_inspect()) return;
cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height)
cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width)
break
case 3:
width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;
if (this.data.disable_ratio) {
height = width / (this.data.width / this.data.height)
}
if (!size_inspect()) return;
cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height);
break
case 4:
width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;
if (this.data.disable_ratio) {
height = width / (this.data.width / this.data.height)
}
if (!size_inspect()) return;
break
}
if (!this.data.disable_width && !this.data.disable_height) {
this.setData({
width: width,
cut_left: cut_left,
height: height,
cut_top: cut_top,
})
} else if (!this.data.disable_width) {
this.setData({
width: width,
cut_left: cut_left
})
} else if (!this.data.disable_height) {
this.setData({
height: height,
cut_top: cut_top
})
}
this._imgMarginDetectionScale();
}
},
_cutTouchStart(e) {
let currentX = e.touches[0].clientX;
let currentY = e.touches[0].clientY;
let cutbox_top4 = this.data.cut_top + this.data.height - 30;
let cutbox_bottom4 = this.data.cut_top + this.data.height + 20;
let cutbox_left4 = this.data.cut_left + this.data.width - 30;
let cutbox_right4 = this.data.cut_left + this.data.width + 30;
let cutbox_top3 = this.data.cut_top - 30;
let cutbox_bottom3 = this.data.cut_top + 30;
let cutbox_left3 = this.data.cut_left + this.data.width - 30;
let cutbox_right3 = this.data.cut_left + this.data.width + 30;
let cutbox_top2 = this.data.cut_top - 30;
let cutbox_bottom2 = this.data.cut_top + 30;
let cutbox_left2 = this.data.cut_left - 30;
let cutbox_right2 = this.data.cut_left + 30;
let cutbox_top1 = this.data.cut_top + this.data.height - 30;
let cutbox_bottom1 = this.data.cut_top + this.data.height + 30;
let cutbox_left1 = this.data.cut_left - 30;
let cutbox_right1 = this.data.cut_left + 30;
if (currentX > cutbox_left4 && currentX < cutbox_right4 && currentY > cutbox_top4 && currentY < cutbox_bottom4) {
this._moveDuring();
this.data._flag_cut_touch = true;
this.data._flag_img_endtouch = true;
this.data.CUT_START = {
width: this.data.width,
height: this.data.height,
x: currentX,
y: currentY,
corner: 4
}
} else if (currentX > cutbox_left3 && currentX < cutbox_right3 && currentY > cutbox_top3 && currentY < cutbox_bottom3) {
this._moveDuring();
this.data._flag_cut_touch = true;
this.data._flag_img_endtouch = true;
this.data.CUT_START = {
width: this.data.width,
height: this.data.height,
x: currentX,
y: currentY,
cut_top: this.data.cut_top,
cut_left: this.data.cut_left,
corner: 3
}
} else if (currentX > cutbox_left2 && currentX < cutbox_right2 && currentY > cutbox_top2 && currentY < cutbox_bottom2) {
this._moveDuring();
this.data._flag_cut_touch = true;
this.data._flag_img_endtouch = true;
this.data.CUT_START = {
width: this.data.width,
height: this.data.height,
cut_top: this.data.cut_top,
cut_left: this.data.cut_left,
x: currentX,
y: currentY,
corner: 2
}
} else if (currentX > cutbox_left1 && currentX < cutbox_right1 && currentY > cutbox_top1 && currentY < cutbox_bottom1) {
this._moveDuring();
this.data._flag_cut_touch = true;
this.data._flag_img_endtouch = true;
this.data.CUT_START = {
width: this.data.width,
height: this.data.height,
cut_top: this.data.cut_top,
cut_left: this.data.cut_left,
x: currentX,
y: currentY,
corner: 1
}
}
},
_cutTouchEnd(e) {
this._moveStop();
this.data._flag_cut_touch = false;
},
//停止移動時需要做的操作
_moveStop() {
//清空之前的自動居中延遲函數(shù)并添加最新的
clearTimeout(this.data.TIME_CUT_CENTER);
this.data.TIME_CUT_CENTER = setTimeout(() => {
//動畫啟動
if (!this.data._cut_animation) {
this.setData({
_cut_animation: true
});
}
this.setCutCenter();
}, 1000)
//清空之前的背景變化延遲函數(shù)并添加最新的
clearTimeout(this.data.TIME_BG);
this.data.TIME_BG = setTimeout(() => {
if (this.data._flag_bright) {
this.setData({
_flag_bright: false
});
}
}, 2000)
},
//移動中
_moveDuring() {
//清空之前的自動居中延遲函數(shù)
clearTimeout(this.data.TIME_CUT_CENTER);
//清空之前的背景變化延遲函數(shù)
clearTimeout(this.data.TIME_BG);
//高亮背景
if (!this.data._flag_bright) {
this.setData({
_flag_bright: true
});
}
},
//監(jiān)聽器
_watcher() {
Object.keys(this.data).forEach(v => {
this._observe(this.data, v, this.data.watch[v]);
})
},
_observe(obj, key, watchFun) {
var val = obj[key];
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
set: (value) => {
val = value;
watchFun && watchFun(val, this);
},
get() {
if (val && '_img_top|img_left||width|height|min_width|max_width|min_height|max_height|export_scale|cut_top|cut_left|canvas_top|canvas_left|img_width|img_height|scale|angle|min_scale|max_scale'.indexOf(key) != -1) {
let ret = parseFloat(parseFloat(val).toFixed(3));
if (typeof val == "string" && val.indexOf("%") != -1) {
ret += '%';
}
return ret;
}
return val;
}
})
},
_preventTouchMove() {}
}
})
?json:
{
"component": true,
"usingComponents": {}
}
wxss:根據(jù)自己需求調(diào)整
.image-cropper {
background: rgba(14, 13, 13, .8);
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 999;
}
.image-cropper .main {
position: absolute;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.image-cropper .content {
z-index: 9;
position: absolute;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
pointer-events: none;
}
.image-cropper .bg_black {
background: rgba(0, 0, 0, 0.8) !important;
}
.image-cropper .bg_gray {
background: rgba(0, 0, 0, 0.45);
transition-duration: .35s;
}
.image-cropper .content>.content_top {
pointer-events: none;
}
.image-cropper .content>.content_middle {
display: flex;
height: 200px;
width: 100%;
}
.image-cropper .content_middle_middle {
width: 200px;
box-sizing: border-box;
position: relative;
transition-duration: .3s;
}
.image-cropper .content_middle_right {
flex: auto;
}
.image-cropper .content>.content_bottom {
flex: auto;
}
.image-cropper .img {
z-index: 2;
top: 0;
left: 0;
position: absolute;
border: none;
width: 100%;
backface-visibility: hidden;
transform-origin: center;
}
.image-cropper .image-cropper-canvas {
position: fixed;
background: white;
width: 150px;
height: 150px;
z-index: 10;
top: -200%;
pointer-events: none;
}
.image-cropper .border {
background: white;
pointer-events: auto;
position: absolute;
}
.image-cropper .border-top-left {
left: -2.5px;
top: -2.5px;
height: 2.5px;
width: 33rpx;
}
.image-cropper .border-top-right {
right: -2.5px;
top: -2.5px;
height: 2.5px;
width: 33rpx;
}
.image-cropper .border-right-top {
top: -1px;
width: 2.5px;
height: 30rpx;
right: -2.5px;
}
.image-cropper .border-right-bottom {
width: 2.5px;
height: 30rpx;
right: -2.5px;
bottom: -1px;
}
.image-cropper .border-bottom-left {
height: 2.5px;
width: 33rpx;
bottom: -2.5px;
left: -2.5px;
}
.image-cropper .border-bottom-right {
height: 2.5px;
width: 33rpx;
bottom: -2.5px;
right: -2.5px;
}
.image-cropper .border-left-top {
top: -1px;
width: 2.5px;
height: 30rpx;
left: -2.5px;
}
.image-cropper .border-left-bottom {
width: 2.5px;
height: 30rpx;
left: -2.5px;
bottom: -1px;
}
?
?2、然后在要引用插件的頁面json文件中添加image-cropper
"usingComponents": {
"image-cropper": "../image-cropper/image-cropper"
},
3、在引用插件的wxml文件中引用組件,根據(jù)自己的需求更改要的效果
<image-cropper
id="image-cropper"
limit_move="{{true}}"
disable_rotate="{{true}}"
width="{{width}}"
height="{{height}}"
imgSrc="{{src}}"
bindload="cropperload"
bindimageload="loadimage"
bindtapcut="clickcut">
</image-cropper>
<view class='bottom'>
<button catchtap='updateImage'>更換照片</button>
<button type="primary" bindtap='submit'>確定裁剪</button>
</view>
4、在引用插件的js中獲取處理的圖片
Page({
data: {
src:'',
width:250,//寬度
height: 250,//高度
},
onLoad(options) {
//獲取到image-cropper實例
this.cropper = this.selectComponent("#image-cropper");
//開始裁剪
this.setData({
src:"xxx.jpg",//要裁剪的圖片
});
wx.showLoading({
title: '加載中'
})
},
cropperload(e){
console.log("cropper初始化完成");
},
loadimage(e){
console.log("圖片加載完成",e.detail);
wx.hideLoading();
//重置圖片角度、縮放、位置
this.cropper.imgReset();
},
clickcut(e) {
wx.previewImage({
current: e.detail.url,
urls: [e.detail.url]
})
},
//更換圖片
updateImage: function (e) {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album', 'camera'],
success: (res) => {
var tempFiles = res.tempFiles[0].tempFilePath;
console.log('圖片路徑',tempFiles)
}
})
},
submit() {
this.cropper.getImg((obj) => {
console.log('裁剪后的圖片',obj.url)
});
},
onShow: function() {
},
onHide: function() {
},
onUnload: function() {
},
})
基本就是這樣,可以看看下面這幾個大佬的文章,更為詳細:
微信小程序中裁剪圖片以及壓縮到指定尺寸并上傳_小程序裁剪圖片-CSDN博客
小程序圖片裁剪組件基于image-cropper(修改版)_艾路菲爾的博客-CSDN博客文章來源:http://www.zghlxwxcb.cn/news/detail-853302.html
微信小程序圖片裁剪image-cropper插件使用_微信小程序圖片裁剪插件_曉未蘇的博客-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-853302.html
到了這里,關(guān)于微信小程序?qū)ι蟼鲌D片進行裁剪實現(xiàn)記錄的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!