微信小程序框选截取2寸照片

vue3+uniapp实现微信小程序框选截取2寸照片功能

image.png

image.png

1.组件代码
src/components下面创建capturePhotos.vue文件 内容如下

<template>
    <view class="picture-tailor" :class="{ 'picture-tailor-show': isShow }">
        <movable-area class="picture-area">
            <movable-view
                class="picture-view"
                :style="{ width: img_width / img_scaling + 'px', height: img_height / img_scaling + 'px' }"
                direction="all"
                :x="offsetX"
                :y="offsetY"
                scale="true"
                :scale-min="scaleMin"
                @change="movableChange"
                @scale="movableScale">
                <image :style="{ width: img_width / img_scaling + 'px', height: img_height / img_scaling + 'px' }" :src="pictureSrc"></image>
            </movable-view>
        </movable-area>
        <view class="select-box"></view>
        <button class="button-ok" @click="createImg">完成</button>
        <button class="button-no" @click="hide">取消</button>
        <canvas type="2d" id="picture-canvas" class="canvas-view"></canvas>
    </view>
</template>

<script>
    // rpx转px
    function rpxToPx(rpx) {
        const screenWidth = uni.getSystemInfoSync().screenWidth
        return (screenWidth * Number.parseInt(rpx)) / 750
    }
    
    // 480rpx 转px
    let tailorSizeX = rpxToPx(350);
    let tailorSizeY = rpxToPx(530);// 需要截取的尺寸350rpx x 530rpx,此变量要和样式中的350rpx,175rpx相对应,175rpx为此变量的一半,若要修改成其他值一定要一一对应
    let newOffsetX = 0; // 拖动缩放完成后的X轴偏移量
    let newOffsetY = 0; // 拖动缩放完成后的Y轴偏移量

    export default {
        name: "lv-clip",
        data() {
            return {
                pictureSrc:'',// 图片
                offsetX: 0, // 图像初始化的X轴偏移量
                offsetY: 0, // 图像初始化的Y轴偏移量
                img_width: 0, // 图片真实宽度
                img_height: 0, // 图片真实高度
                img_scaling: 1, //图片初始化缩放比例
                scale: 1, // 拖动缩放完成后的图片缩放比例
                scaleMin: 0.5, // 最小缩放值
                isShow: false
            };
        },
        methods: {
            // 显示组件
            show(img) {
                this.pictureSrc = img; // 赋值图片
                this.getImgInfo(); // 初始化图片
                this.isShow = true; // 显示组件
            },
            // 隐藏组件
            hide() {
                this.isShow = false;
            },
            // 初始化图片
            getImgInfo() {
                uni.getImageInfo({
                    src: this.pictureSrc,
                    success: res => {
                        // 图片宽高
                        this.img_width = res.width;
                        this.img_height = res.height;

                        // 把最小的边撑满
                        // let count = this.img_width <= this.img_height ? this.img_width : this.img_height;
                        let count = this.img_height;
                        this.img_scaling = count / tailorSizeY;
                        this.scaleMin = 1;

                        // 计算图片居中显示时的偏移量
                        this.offsetX = -(this.img_width / this.img_scaling / 2 - tailorSizeX / 2);
                        this.offsetY = -(this.img_height / this.img_scaling / 2 - tailorSizeY / 2);

                        // 获取新的偏移量
                        newOffsetX = this.offsetX;
                        newOffsetY = this.offsetY;
                    }
                });
            },
            // 计算拖动偏移量
            movableChange(e) {
                newOffsetX = e.detail.x;
                newOffsetY = e.detail.y;
            },
            // 计算缩放比例和偏移量
            movableScale(e) {
                newOffsetX = e.detail.x;
                newOffsetY = e.detail.y;
                this.scale = e.detail.scale;
            },
            // 截取图片
            createImg() {
                
                // #ifdef MP-WEIXIN
                uni.createSelectorQuery().in(this).select('#picture-canvas').fields({ node: true, size: true })
                    .exec((res) => {
                        const canvas = res[0].node;
                        canvas.width = tailorSizeX;
                        canvas.height = tailorSizeY;
                        
                        const ctx = canvas.getContext('2d')
                        
                        let headerImg = canvas.createImage();   //创建iamge实例
                        headerImg.src = this.pictureSrc;    //临时图片路径
                        headerImg.onload = () => {
                            ctx.drawImage(
                                headerImg,
                                newOffsetX,//起点 X 坐标
                                newOffsetY,//起点 Y 坐标
                                (this.img_width / this.img_scaling) * this.scale,//终点 X 坐标
                                (this.img_height / this.img_scaling) * this.scale//终点 Y 坐标
                            );
                            ctx.restore();  //保存上下文 
                            uni.canvasToTempFilePath({
                                quality: 1,// 图片质量0-1
                                canvas:canvas,
                                fileType: 'png',
                                success: res => {
                                    // 在H5平台下,tempFilePath 为 base64
                                    this.hide(); // 关闭
                                    this.$emit("createImg", res.tempFilePath);
                                },
                                fail: function (res) {
                                    this.hide(); // 关闭
                                }
                            },this);
                        };
                    })
                // #endif
                
                
                // #ifdef MP-DINGTALK
                let ctx = uni.createCanvasContext("picture-canvas", this);
                ctx.drawImage(
                    this.pictureSrc,
                    newOffsetX,//起点 X 坐标
                    newOffsetY,//起点 Y 坐标
                    (this.img_width / this.img_scaling) * this.scale,//终点 X 坐标
                    (this.img_height / this.img_scaling) * this.scale//终点 Y 坐标
                );
                ctx.draw(false, () => {
                    uni.canvasToTempFilePath(
                        {
                            quality: 1,// 图片质量0-1
                            canvasId: "picture-canvas",// 画布标识,传入 <canvas/> 的 canvas-id(支付宝小程序是id、其他平台是canvas-id)
                            success: res => {
                                this.hide(); // 关闭
                                this.$emit("createImg", res.tempFilePath);
                            },
                            fail: function (res) {
                                this.hide(); // 关闭
                            }
                        },
                        this
                    );
                });
                // #endif
                
                
            }
        }
    };
</script>

<style scoped>
    .picture-tailor {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        width: 100%;
        height: 100%;
        background-color: #000000;
        z-index:100;
        transform: translateX(100%);
        transition: all 200ms ease;
        overflow: hidden;
        visibility: hidden;
    }

    .picture-tailor-show {
        transform: translateY(0) !important;
        visibility: visible;
    }

    /* 拖动域的位置和大小 */
    .picture-tailor .picture-area {
        width: 350rpx;
        height: 530rpx;
        position: absolute;
        /* 使其居中定位 */
        top: calc(50% - 265rpx);
        left: calc(50% - 175rpx);
    }

    /* 拖动控件的大小 */
    .picture-area .picture-view {
        min-width: 350rpx;
        min-height: 530rpx;
    }

    /* 中间选择框的大小,本意是视觉上模拟拖动域 */
    .select-box {
        position: absolute;
        top: calc(50% - 265rpx);
        left: calc(50% - 175rpx);
        width: 350rpx;
        height: 530rpx;
        box-sizing: border-box;
        /* border-radius: 50%; */
        border: red 5rpx solid;
        pointer-events: none;
    }

    .button-ok {
        position: absolute;
        bottom: 40rpx;
        right: 40rpx;
        width: 120rpx;
        background-color: #007aff;
        font-size: 28rpx;
        color: #ffffff;
    }
    .button-no {
        position: absolute;
        bottom: 40rpx;
        left: 40rpx;
        width: 120rpx;
        background-color: #007aff;
        font-size: 28rpx;
        color: #ffffff;
    }

    /* 画布大小,画布大小就是截取的原始大小 */
    .canvas-view {
        width: 350rpx;
        height: 530rpx;
        position: relative;
        left: -9999rpx;
        visibility: hidden;
    }
</style>

2.vue3页面使用

<u-form-item label="上传头像" required :borderBottom="true">
    <view class="page">
         <image class="iii" :src="tailorPath"  ></image>
        <capture-photos ref="capturePhotosDom" @createImg="createImg"></capture-photos>
        <button type="primary" size="mini" @click="choosePhoto">选择图片</button>
    </view>
</u-form-item>

<script setup>
import capturePhotos from "@/components/capturePhotos.vue";
const capturePhotosDom = ref(null);
    const tailorPath = ref('')
    const choosePhoto = ()=>{
        uni.chooseImage({
            count: 1,
            sizeType: ["compressed"],
            success: res => {
                if(res.tempFilePaths[0]){
                // 传入临时路径
                    capturePhotosDom.value.show(res.tempFilePaths[0]);
                }
            }
        });
    }
    // 拿到临时路径
    async function createImg(e){
        console.log(e)
        tailorPath.value = e;
        await upload(e)
    }
    
    function upload(e) {
        // 调用uni.uploadFile将文件上传至服务器
        uni.showLoading()
        uni.uploadFile({
            url: qlm_gateway_url + '/public/filemanage/upload', // 设置上传接口地址
            filePath: e, // 需要上传的文件路径
            name: 'file', // 后台接收文件时对应的字段名称
            header: {
                // "Content-Type": "multipart/form-data",
            },
            success(response) {
                // TODO: 处理上传成功后的操作
                console.log('文件上传成功');
                uni.hideLoading()
                const data = JSON.parse(response.data)
                formData.value.photo = data.data.url
                tailorPath.value=file_server_url + data.data.url
                photourl.value = [{
                    name: "photo",
                    url: file_server_url + data.data.url
                }]
                // uni.hideLoading()
                return
            },
            fail(error) {
                console.log('文件上传失败');
                console.log(error);
                uni.hideLoading()
                // uni.hideLoading()
                // TODO: 处理上传失败后的操作
            }
        });
    }
    //查询
    async function findPlayerInfo(id) {
        uni.showLoading()
        const res = await findPlayerInfoBO(id)
        console.log('res',res.data)
        uni.hideLoading()
        if(res.retCode==88888888){
            uni.showToast({
                title: res.msg,
                duration: 2000
            });
            formData.value=res.data
            // getImageUrl(res.data.photo)
            if (res.data.photo != null) {
                tailorPath.value=file_server_url + res.data.photo
            }
        }else{
            uni.showToast({
                title: res.msg,
                 icon:'error',
                duration: 2000
            });
            return false
        }
    }
</script>

<style lang="scss" scoped>
    .iii{
        width: 70px;
        height: 106px;
        border: 2rpx solid red;
        image{
            width: 100%;
            height: 100%;
        }
    }
</style>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容