微信小程序框选截取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>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容