7.微信小程序做按比例截取图片

项目需求是需要做一个上传图片按1:1,16:9 ,3:4一个图片截取,网上查了好久,找到一个cropper截取组件 ,现在把接入以及修改步骤记录一下
截取组件原地址找不到了,贴一下代码吧(谢谢大佬分享了!!!)
wxml

<view class="wx-cropper-info" wx:if="{{isShowCropper}}">
    <view class='cropper-content'>
        <view class="wx-corpper" style="width:{{cropperInitW}}rpx;height:{{cropperInitH}}rpx;background:#000">
            <view class="wx-corpper-content" style="width:{{cropperW}}rpx;height:{{cropperH}}rpx;left:{{cropperL}}rpx;top:{{cropperT}}rpx">
                <image class="img" src="{{imageSrc}}" style="width:{{cropperW}}rpx;height:{{cropperH}}rpx"></image>
                <view class="wx-corpper-crop-box" bindtouchstart="contentStartMove" bindtouchmove="contentMoveing"
                    bindtouchend="contentTouchEnd" style="left:{{cutL}}rpx;top:{{cutT}}rpx;right:{{cutR}}rpx;bottom:{{cutB}}rpx">
                    <view class="wx-cropper-view-box">
                        <view class="wx-cropper-dashed-h"></view>
                        <view class="wx-cropper-dashed-v"></view>
                        <!-- catchtouchmove="dragMove" -->
                        <view class="wx-cropper-line-t" data-drag="top" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
                        <view class="wx-cropper-line-r" data-drag="right" catchtouchstart="dragStart"
                            catchtouchmove="dragMove"></view>
                        <view class="wx-cropper-line-b" data-drag="bottom" catchtouchstart="dragStart"
                            catchtouchmove="dragMove"></view>
                        <view class="wx-cropper-line-l" data-drag="left" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
                        <view class="wx-cropper-point point-t" data-drag="top" catchtouchstart="dragStart"
                            catchtouchmove="dragMove"></view>
                        <view class="wx-cropper-point point-tr" data-drag="topTight"></view>
                        <view class="wx-cropper-point point-r" data-drag="right" catchtouchstart="dragStart"
                            catchtouchmove="dragMove"></view>
                        <view class="wx-cropper-point point-rb" data-drag="rightBottom" catchtouchstart="dragStart"
                            catchtouchmove="dragMove"></view>
                        <view class="wx-cropper-point point-b" data-drag="bottom" catchtouchstart="dragStart"
                            catchtouchmove="dragMove" catchtouchend="dragEnd"></view>
                        <view class="wx-cropper-point point-bl" data-drag="bottomLeft"></view>
                        <view class="wx-cropper-point point-l" data-drag="left" catchtouchstart="dragStart"
                            catchtouchmove="dragMove"></view>
                        <view class="wx-cropper-point point-lt" data-drag="leftTop"></view>
                    </view>
                </view>
            </view>
        </view>
    </view>
    <view class="cropper-configs" wx:if="{{!isDefault}}">
        <button type="primary reverse" class="btn" bindtap="changeSome" data-index="1" style='margin-top: 30rpx;'> 1:1 </button>
        <button type="primary reverse" class="btn" bindtap="changeSome" data-index="0.75"style='margin-top: 30rpx;'> 3:4 </button>
        <button type="primary reverse" class="btn" bindtap="changeSome" data-index="0.5625" style='margin-top: 30rpx;'> 9:16 </button>
    </view>
    <view class='cropper-config'>
        <button type="primary reverse" class="btn" bindtap="cancelCropper" style='margin-top: 30rpx;'> 取消 </button>
        <button type="primary" class="cropper-confirm btn" bindtap="confirmCropper" style='margin-top: 30rpx;'>  确认 </button>
    </view>
    <canvas wx:if="{{!isCircleCrop}}" canvas-id="cropper" style="position:absolute;border: 1px solid red; width:{{qualityWidth}}px;height:{{qualityWidth/innerAspectRadio}}px;top:-9999px;left:-9999px;"></canvas>
    <canvas wx:else canvas-id="cropper" style="position:absolute;border: 1px solid red; width:{{canvasW}}px;height:{{canvasH}}px;top:-9999px;left:-9999px;"></canvas>
</view>


js

const defaultData = {
    isShowCropper:false,
    // 初始化的宽高
    cropperInitW: 750,
    cropperInitH: 750,
    // 动态的宽高
    cropperW: 750,
    cropperH: 750,
    // 动态的left top值
    cropperL: 0,
    cropperT: 0,

    transL: 0,
    transT: 0,

    // 图片缩放值
    scaleP: 0,
    imageW: 0,
    imageH: 0,

    // 裁剪框 宽高
    cutL: 0,
    cutT: 0,
    cutB: 0,
    cutR: 0,

    qualityWidth: '',
    innerAspectRadio: 750 / wx.getSystemInfoSync().windowWidth,
    
    C_CONSTANTS:{
        SCREEN_WIDTH : 750,
        PAGE_X:0, // 手按下的x位置
        PAGE_Y:0, // 手按下y的位置
        PR : wx.getSystemInfoSync().pixelRatio, // dpi
        T_PAGE_X:{}, // 手移动的时候x的位置
        T_PAGE_Y:{}, // 手移动的时候Y的位置
        CUT_L:0, // 初始化拖拽元素的left值
        CUT_T:0, // 初始化拖拽元素的top值
        CUT_R:0, // 初始化拖拽元素的
        CUT_B:0, // 初始化拖拽元素的
        CUT_W:0, // 初始化拖拽元素的宽度
        CUT_H:0, //  初始化拖拽元素的高度
        IMG_RATIO:0, // 图片比例
        IMG_REAL_W:0, // 图片实际的宽度
        IMG_REAL_H:0, // 图片实际的高度
        IMG_TYPE:'',//图片的格式
        DRAFG_MOVE_RATIO : 750 / wx.getSystemInfoSync().windowWidth //移动时候的比例
    }
};
let data = {};

try{
    data = JSON.parse(JSON.stringify(defaultData));
}catch(e){console.log(e)};

Component({
    properties: {
        imageSrc:{
            type:String,
            value:'',
            observer(newVal, oldVal) {
                if(newVal !== oldVal){
                    this.setData({
                        isShowCropper:true
                    },() => {
                        this.loadImage();
                    })
                }
                
            }
        },
        isCircleCrop:{
            type:Boolean,
            value:false
        },
        isDefault: {
            type: Boolean,
            value: false
        },
        enableScale:{
            type:Boolean,
            value:false
        },
        ratio:{
            type:Number,
            value:1,
        }
    },
    observers:{
        ratio(val) {
            let that = this;
            console.log(val,'1111')
            that.loadImage()
        }
    },
    data,
    ready(){
        if(this.data.isCircleCrop){
            //圆形裁剪 强制比例为1
            this.setData({
                ratio:1
            })
        }
    },
    methods: {
        // 修改裁剪比例
        changeSome(e){
            let that = this;
            // console.log(e.currentTarget.dataset.index)
            that.triggerEvent('changeScale', {
                'scale': e.currentTarget.dataset.index
              })
            // that.setData({
            //     ratio:e.currentTarget.dataset.index,
            // })
        },
        loadImage() {
            let {ratio,imageSrc} = this.data;
            let {IMG_REAL_W,IMG_REAL_H,IMG_RATIO,SCREEN_WIDTH,IMG_TYPE} = this.data.C_CONSTANTS;
            wx.getImageInfo({
                src: imageSrc,
                success: res => {
                    IMG_REAL_W = res.width;
                    IMG_REAL_H = res.height;
                    IMG_RATIO = IMG_REAL_W / IMG_REAL_H;
                    IMG_TYPE = res.type === 'png' ? 'png' : 'jpg';
                    // 根据图片的宽高显示不同的效果   保证图片可以正常显示
                    let temp = {};
                    let cropperData = {};
                    if (IMG_RATIO >= 1) {
                        cropperData = {
                            cropperW: SCREEN_WIDTH,
                            cropperH: SCREEN_WIDTH / IMG_RATIO,
                            // 初始化left right
                            cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
                            cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2)
                        }
                        if(ratio > 1){
                            temp = {
                                cutL: (SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2,
                                cutT: (SCREEN_WIDTH / IMG_RATIO - SCREEN_WIDTH / IMG_RATIO / ratio ) / 2,
                                cutR: SCREEN_WIDTH - (SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2 - SCREEN_WIDTH / IMG_RATIO,
                                cutB: SCREEN_WIDTH / IMG_RATIO - (SCREEN_WIDTH / IMG_RATIO - SCREEN_WIDTH / IMG_RATIO / ratio ) / 2 - SCREEN_WIDTH / IMG_RATIO / ratio
                            }
                        }else{
                            temp = {
                                cutT:0,
                                cutB:0,
                                cutL:(SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO * ratio) / 2,
                                cutR: SCREEN_WIDTH - (SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO * ratio) / 2 - SCREEN_WIDTH / IMG_RATIO * ratio
                            }
                        }
                    } else {
                        cropperData = {
                            cropperW: SCREEN_WIDTH * IMG_RATIO,
                            cropperH: SCREEN_WIDTH,
                            // 初始化left right
                            cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2),
                            cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2)
                        }
                        if(ratio > 1){
                            temp = {
                                cutL:0,
                                cutR:0,
                                cutT: (SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO / ratio) / 2,
                                cutB: SCREEN_WIDTH - (SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO / ratio) / 2 - SCREEN_WIDTH * IMG_RATIO / ratio
                            }
                        }else{
                            temp = {
                                cutL: (SCREEN_WIDTH * IMG_RATIO - SCREEN_WIDTH * IMG_RATIO * ratio) / 2,
                                cutR: SCREEN_WIDTH * IMG_RATIO - (SCREEN_WIDTH * IMG_RATIO - SCREEN_WIDTH * IMG_RATIO * ratio) / 2 - SCREEN_WIDTH * IMG_RATIO * ratio,
                                cutT: (SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2,
                                cutB: SCREEN_WIDTH - (SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2 - SCREEN_WIDTH * IMG_RATIO
                            }
    
                        }
                    }
                    this.setData({
                        C_CONSTANTS:Object.assign({},this.data.C_CONSTANTS,{
                            IMG_REAL_W,
                            IMG_REAL_H,
                            IMG_RATIO,
                            IMG_TYPE
                        }),
                        isShowCropper: true,
                        // 图片缩放值
                        scaleP: IMG_REAL_W / SCREEN_WIDTH,
                        qualityWidth: IMG_REAL_W,
                        innerAspectRadio: IMG_RATIO,
                        ...temp,
                        ...cropperData
                    })
                }
            });
            
        },
        contentStartMove(e) {
            this.setData({
                'C_CONSTANTS.PAGE_X':e.touches[0].pageX,
                'C_CONSTANTS.PAGE_Y':e.touches[0].pageY
            })
        },
        // 拖动时候触发的touchMove事件
        contentMoveing(e) {
            let {PAGE_X,PAGE_Y,DRAFG_MOVE_RATIO} = this.data.C_CONSTANTS;
            let {cutL,cutR,cutT,cutB} = this.data;
            let dragLengthX = (PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
            let dragLengthY = (PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
            // 左移
            if (dragLengthX > 0) {
                if (cutL - dragLengthX < 0) dragLengthX = cutL
            } else {
                if (cutR + dragLengthX < 0) dragLengthX = -cutR
            }
    
            if (dragLengthY > 0) {
                if (cutT - dragLengthY < 0) dragLengthY = cutT
            } else {
                if (cutB + dragLengthY < 0) dragLengthY = -cutB
            }
            this.setData({
                cutL: cutL - dragLengthX,
                cutT: cutT - dragLengthY,
                cutR: cutR + dragLengthX,
                cutB: cutB + dragLengthY,
                'C_CONSTANTS.PAGE_X':e.touches[0].pageX,
                'C_CONSTANTS.PAGE_Y':e.touches[0].pageY
            });
        },
        // 设置大小的时候触发的touchStart事件
        dragStart(e) {
            let {cutL,cutR,cutT,cutB} = this.data;
            this.setData({
                C_CONSTANTS:Object.assign({},this.data.C_CONSTANTS,{
                    T_PAGE_X : e.touches[0].pageX,
                    T_PAGE_Y : e.touches[0].pageY,
                    CUT_L : cutL,
                    CUT_R : cutR,
                    CUT_B : cutB,
                    CUT_T : cutT
                })
            })
            
        },
        // 设置大小的时候触发的touchMove事件
        dragMove(e) {
            let dragType = e.target.dataset.drag
            let {ratio,cropperW,cropperH,cutL,cutT,cutR,cutB,enableScale} = this.data;
            let {CUT_R,CUT_L,CUT_T,CUT_B,T_PAGE_X,T_PAGE_Y,DRAFG_MOVE_RATIO} = this.data.C_CONSTANTS;
            let dragLength;
            switch (dragType) {
                case 'right':
                    dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
                    if (CUT_R + dragLength < 0) dragLength = -CUT_R
                    cutR = CUT_R + dragLength;
                    if(enableScale){
                        cutT = CUT_T + dragLength / ratio;
                    }
                    if(cutR < 0 || cutT < 0 || cutT > cropperH || cutR > cropperW) return;
                    break;
                case 'left':
                    dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
                    if (CUT_L - dragLength < 0) dragLength = CUT_L
                    if ((CUT_L - dragLength) > (this.data.cropperW - this.data.cutR)) dragLength = CUT_L - (this.data.cropperW - this.data.cutR)
                    cutL = CUT_L - dragLength;
                    if(enableScale){
                        cutT = CUT_T - dragLength / ratio;
                    }
                    if(cutL < 0 || cutT < 0 || cutT > cropperH || cutL > cropperW) return;
                    break;
                case 'top':
                    dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
                    if (CUT_T - dragLength < 0) dragLength = CUT_T
                    if ((CUT_T - dragLength) > (this.data.cropperH - this.data.cutB)) dragLength = CUT_T - (this.data.cropperH - this.data.cutB)
                    cutT = CUT_T - dragLength;
                    if(enableScale){
                        cutR = CUT_R - dragLength * ratio;
                    }
                    break;
                case 'bottom':
                    dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
                    if (CUT_B + dragLength < 0) dragLength = -CUT_B
                    cutB = CUT_B + dragLength;
                    if(enableScale){
                        cutR = CUT_R + dragLength * ratio;
                    }
                    if(cutR < 0 || cutT < 0 || cutT > cropperH || cutR > cropperW) return;
                    break;
                default:'';
            }
            this.setData({
                cutL,
                cutT,
                cutR,
                cutB
            });
        },
        contentTouchEnd(){},  
        // 获取图片
        confirmCropper() {
            const isCircleCrop = this.data.isCircleCrop;
            if(isCircleCrop){
                this.circleCrop()
            }else{
                this.normalCropper();
            }
        },

        normalCropper(){
            let {imageSrc,cropperW,cropperH,cutL,cutT,cutR,cutB} = this.data;
            let {IMG_REAL_W,IMG_REAL_H,IMG_TYPE} = this.data.C_CONSTANTS;
            // 将图片写入画布
            const ctx = wx.createCanvasContext('cropper',this)
            ctx.drawImage(imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H);
            ctx.draw(true, () => {
                // 获取画布要裁剪的位置和宽度   均为百分比 * 画布中图片的宽度    保证了在微信小程序中裁剪的图片模糊  位置不对的问题 canvasT = (_this.data.cutT / _this.data.cropperH) * (_this.data.imageH / pixelRatio)
                let canvasW = ((cropperW - cutL - cutR) / cropperW) * IMG_REAL_W
                let canvasH = ((cropperH - cutT - cutB) / cropperH) * IMG_REAL_H
                let canvasL = (cutL / cropperW) * IMG_REAL_W
                let canvasT = (cutT / cropperH) * IMG_REAL_H
                wx.canvasToTempFilePath({
                    x: canvasL,
                    y: canvasT,
                    width: canvasW,
                    height: canvasH,
                    destWidth: canvasW,
                    destHeight: canvasH,
                    fileType:IMG_TYPE || 'jpg',
                    canvasId: 'cropper',
                    success: (res) => {
                        //图片裁剪成功
                        this.cancelCropper();
                        this.triggerEvent('cropperDone', {
                            src:res.tempFilePath,
                            cropperData:{
                                x: canvasL,
                                y: canvasT,
                                width: canvasW,
                                height: canvasH
                            }
                        })
                    },
                    fail:err =>{
                        this.triggerEvent('cropperFail',err)
                    }
                },this);
            })
        },

        circleCrop(){
            console.log('圆角切割')
            let {imageSrc,cropperW,cropperH,cutL,cutT,cutR,cutB} = this.data;
            let {IMG_REAL_W,IMG_REAL_H,IMG_TYPE} = this.data.C_CONSTANTS;
            // 将图片写入画布
            const ctx = wx.createCanvasContext('cropper',this)
            let canvasW = ((cropperW - cutL - cutR) / cropperW) * IMG_REAL_W
            let canvasL = (cutL / cropperW) * IMG_REAL_W
            let canvasT = (cutT / cropperH) * IMG_REAL_H
            this.setData({
                canvasW:canvasW,
                canvasH:canvasW
            },() => {
                ctx.arc(canvasW / 2,canvasW / 2,canvasW / 2,0,2 * Math.PI);
                ctx.clip();
                ctx.drawImage(imageSrc, canvasL, canvasT, canvasW, canvasW,0,0,canvasW,canvasW);
                ctx.draw(true, () => {
                    wx.canvasToTempFilePath({
                        fileType:IMG_TYPE || 'jpg',
                        canvasId: 'cropper',
                        success: (res) => {
                            //图片裁剪成功
                            this.cancelCropper();
                            this.triggerEvent('cropperDone', {
                                src:res.tempFilePath,
                                cropperData:{
                                    x: canvasL,
                                    y: canvasT,
                                    width: canvasW,
                                    height: canvasW
                                }
                            })
                        },
                        fail:err =>{
                            this.triggerEvent('cropperFail',err)
                        }
                    },this);
                })
            })
        },

        cancelCropper(){
            let originData = {}
            try{
                originData = JSON.parse(JSON.stringify(defaultData))
            }catch(e){};

            this.setData({
                ...originData
            });
            this.triggerEvent('cropperCancel')
        }
    }
})

1.引入组件

//.json文件
"usingComponents": {
    "cropper":"../../components/cropper"
  }
//.wxml文件
<!-- 图片截取 -->
<view class="btn" bindtap="choiceImageCropper">冲冲冲</view>
<cropper imageSrc="{{imageSrc}}" enableScale="{{true}}" isDefault="{{}}" isCircleCrop="{{false}}"
  ratio="{{proportion}}" bind:changeScale='changeScale' bind:cropperDone="cropperDone"
  bind:cropperCancel="cropperCancel" bind:cropperFail="cropperFail"></cropper>
  <!-- 
  imageSrc:需要截取的图片地址
  enableScale:是否限制比例,true为用户不能随意调整比例 
  isDefault:是否限定默认尺寸为1:1且不显示其他比例选项 默认flase
  isCircleCrop:是否显示圆角切割 (用于切割头像)
  ratio:为传入截取比例尺(组件默认为1) 
  changeScale:组件传递比例事件
  cropperDone:用户确认截取图片事件
  cropperCancel:用户取消截取 
  cropperFail:截取报错
  -->
//

2.js事件

  //组件触发取消截取方法
  cropperCancel(e){
    console.log('用户截取取消了')
  },
  // 组件触发截取确认方法
  cropperDone(e) {
    console.log(e);
    let that = this;
    that.setData({
      src:e.detail.src
    })
  },
  // 修改比例
  changeScale(e) {
    let that = this;
    that.setData({
      proportion: e.detail.scale,
    })
  },
  // 上传需要裁剪图片
  choiceImageCropper(){
    let that = this;
    wx.chooseImage({
      count: 1,
      sourceType: ['album', 'camera'],
      sizeType: ['compressed'],
      success(res) {
        console.log(res);
        that.setData({
          imageSrc:res.tempFilePaths[0]
        })
      },
      fail(err) {}
    })
  },

以上代码贴下来可以直接使用,也可根据自身需求去添加功能及修改,组件有一点问题就是切圆形头像的时候截取框还是矩形不是圆形,但是截取出来的还是圆形的图片的,因为项目不需要截取圆形图片就没做修改,代码也添加了项目需求的一部分功能,总的来说这个组件还是挺好的。

希望能帮到大家,也便于自己记录(如果有帮助到大家可以点下赞哦~)!!!
如有疑问或者不对的地方可以下方评论留言讨论哦~会积极回复大家的!!!
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值