uniapp APP端水印相機實現


  使用插件https://ext.dcloud.net.cn/plugin?id=4892

 在插件功能上增加定位,定時功能,水印相機頁面每十秒重新獲取一次地址,時間,增加水印生canvas文本多行換行功能

 

 由於相機組件app不支持,所以插件使用 live-pusher 直播推流 組件實現的自定義相機功能。

 拍照頁面使用nvue,可以實現應用內拍照以及拍照畫面自定義元素等功能。

水印相機頁watermarkCamera.nvue

<template>
    <view class="live-camera" :style="{ width: windowWidth, height: windowHeight }">
        <view class="preview" :style="{ width: windowWidth, height: windowHeight}">
            <live-pusher id="livePusher" ref="livePusher" class="livePusher" mode="FHD" beauty="0" whiteness="0"
                :aspect="aspect" min-bitrate="1000" audio-quality="16KHz" device-position="back" auto-focus="false"
                muted="true" :enable-camera="true" :enable-mic="false" :zoom="false" @statechange="statechange"
                :style="{ width: windowWidth, height: windowHeight }"></live-pusher>
            <!--提示語-->
            <cover-view class="remind">
                <text class="remind-text remind-name" style="">{{ username }}</text>
                <text class="remind-text remind-address" style="">{{ address }}</text>
                <text class="remind-text remind-time" style="">{{ time }}</text>
            </cover-view>
        </view>
        <view class="menu">
            <!--底部菜單區域背景-->
            <cover-image class="menu-mask" src="@/static/camera/bar.png"></cover-image>

            <!--返回鍵-->
            <cover-image class="menu-back" @tap="back" src="@/static/camera/back.png"></cover-image>

            <!--快門鍵-->
            <cover-image class="menu-snapshot" @tap="snapshot" src="@/static/camera/shutter.png"></cover-image>

            <!--反轉鍵-->
            <cover-image class="menu-flip" @tap="flip" src="@/static/camera/flip.png"></cover-image>
        </view>
    </view>
</template>

<script>
    let _this = null;
    export default {
        data() {
            return {
                dotype: 'watermark',
                message: 'live-camer', //水印內容
                username: uni.getStorageSync('loginUserName'),
                address: '無法獲取地址',
                time: '2022-2-14 10:23',
                poenCarmeInterval: null, //打開相機的輪詢
                aspect: '2:3', //比例
                windowWidth: '', //屏幕可用寬度
                windowHeight: '', //屏幕可用高度
                camerastate: false, //相機准備好了
                livePusher: null, //流視頻對象
                snapshotsrc: null ,//快照,
                timer:null,//定時器
            };
        },
        onLoad(e) {
            _this = this;
            if (e.dotype != undefined) this.dotype = e.dotype;
            this.initCamera();
        },
        onReady() {
            this.getAddress();
            let date = new Date()
            this.time= this.dateFormat("YYYY-mm-dd HH:MM", date);
            this.livePusher = uni.createLivePusherContext('livePusher', this);
            this.startPreview(); //開啟預覽並設置攝像頭
            this.poenCarme();
        },
        onShow() {
            clearInterval(this.timer)
            // 每隔10秒刷新地址和時間
            this.timer = setInterval(()=>{
                this.getAddress();
                let date = new Date()
                this.time= this.dateFormat("YYYY-mm-dd HH:MM", date);
            },10000);
        },
        onUnload(){
            clearInterval(this.timer)
        },
        methods: {
            getAddress(){
                uni.getLocation({
                    type: 'gcj02',
                        geocode: true,
                        isHighAccuracy:true,
                    success:(res) => {
                                this.address = res.address.province+res.address.city+res.address.district+res.address.street+res.address.streetNum+res.address.poiName;
                        console.log('當前位置:' , this.address);
                                console.log('當前位置的經度:' + res.longitude);
                        console.log('當前位置的緯度:' + res.latitude);
                    }
                });
            },
            //輪詢打開
            poenCarme() {
                //#ifdef APP-PLUS
                if (plus.os.name == 'Android') {
                    this.poenCarmeInterval = setInterval(function() {
                        console.log(_this.camerastate);
                        if (!_this.camerastate) _this.startPreview();
                    }, 2500);
                }
                //#endif
            },
            //初始化相機
            initCamera() {
                uni.getSystemInfo({
                    success: function(res) {
                        _this.windowWidth = res.windowWidth;
                        _this.windowHeight = res.windowHeight;
                        let zcs = _this.aliquot(_this.windowWidth, _this.windowHeight);
                        _this.aspect = _this.windowWidth / zcs + ':' + _this.windowHeight / zcs;
                        console.log('畫面比例:' + _this.aspect);
                    }
                });
            },

            //整除數計算
            aliquot(x, y) {
                if (x % y == 0) return y;
                return this.aliquot(y, x % y);
            },

            //開始預覽
            startPreview() {
                this.livePusher.startPreview({
                    success: a => {
                        console.log(a);
                    }
                });
            },

            //停止預覽
            stopPreview() {
                this.livePusher.stopPreview({
                    success: a => {
                        _this.camerastate = false; //標記相機未啟動
                    }
                });
            },

            //狀態
            statechange(e) {
                //狀態改變
                console.log(e);
                if (e.detail.code == 1007) {
                    _this.camerastate = true;
                } else if (e.detail.code == -1301) {
                    _this.camerastate = false;
                }
            },

            //返回
            back() {
                uni.navigateBack();
            },

            //抓拍
            snapshot() {
                this.livePusher.snapshot({
                    success: e => {
                        _this.snapshotsrc = e.message.tempImagePath;
                        _this.stopPreview();
                        _this.setImage();
                        uni.navigateBack();
                    }
                });
            },

            //反轉
            flip() {
                this.livePusher.switchCamera();
            },

            //設置
            setImage() {
                let pages = getCurrentPages();
                let prevPage = pages[pages.length - 2]; //上一個頁面

                //直接調用上一個頁面的setImage()方法,把數據存到上一個頁面中去
                prevPage.$vm.watermark({
                    path: _this.snapshotsrc,
                    info: {
                        username: this.username, 
                        address: this.address,
                        time: this.time
                    }
                });
            },
            dateFormat(fmt, date) {
              let ret;
              const opt = {
                "Y+": date.getFullYear().toString(),        //
                "m+": (date.getMonth() + 1).toString(),     //
                "d+": date.getDate().toString(),            //
                "H+": date.getHours().toString(),           //
                "M+": date.getMinutes().toString(),         //
                "S+": date.getSeconds().toString()          //
                // 有其他格式化字符需求可以繼續添加,必須轉化成字符串
              };
              for (let k in opt) {
                ret = new RegExp("(" + k + ")").exec(fmt);
                if (ret) {
                  fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
                };
              };
              return fmt;
            },
        }
    };
</script>

<style lang="less">
    .live-camera {
        justify-content: center;
        align-items: center;

    }

    .preview {
        justify-content: center;
        align-items: center;

    }

    .remind {
        position: absolute;
        top: 80rpx;
        left: 20rpx;
        
        z-index: 100;
    }

    .remind-text {
        color: #dddddd;
        
        width: 710rpx;
    }
    .remind-name{
        font-size: 40rpx;
    }
    .remind-address{
        font-size: 36rpx;
    }
    .remind-time{
        font-size: 30rpx;
    }
    

    .menu {
        position: absolute;
        left: 0;
        bottom: 0;
        width: 750rpx;
        height: 180rpx;
        z-index: 98;
        align-items: center;
        justify-content: center;
    }

    .menu-mask {
        position: absolute;
        left: 0;
        bottom: 0;
        width: 750rpx;
        height: 180rpx;
        z-index: 98;
    }

    .menu-back {
        position: absolute;
        left: 30rpx;
        bottom: 50rpx;
        width: 80rpx;
        height: 80rpx;
        z-index: 99;
        align-items: center;
        justify-content: center;
    }

    .menu-snapshot {
        width: 130rpx;
        height: 130rpx;
        z-index: 99;
    }

    .menu-flip {
        position: absolute;
        right: 30rpx;
        bottom: 50rpx;
        width: 80rpx;
        height: 80rpx;
        z-index: 99;
        align-items: center;
        justify-content: center;
    }
</style>

相片展示和水印生成頁index.vue

<template>
    <view class="page">
        <nav-bar :background="'#0042b8'" :is-back="true" title="測試"></nav-bar>
        <view style="height: 80rpx;"></view>
        
        <navigator class="buttons" url="./watermarkCamera"><button type="primary">打開定制水印相機</button></navigator>
        <view style="height: 80rpx;"></view>
        
        <view>拍攝結果預覽圖,見下方</view>
        <view class="img-list">
            <view class="img-item" v-for="(item,index) in imgList" :key="index" @click="lookImg(index)">
                <image :src="item"></image>
            </view>
        </view>
        <canvas id="canvas-clipper" canvas-id="canvas-clipper" type="2d" :style="{width: canvasSiz.width+'px',height: canvasSiz.height+'px',position: 'absolute',left:'-500000px',top: '-500000px'}" />
    </view>
</template>

<script>
    var _this;
export default {
    data() {
        return {
            windowWidth:'',
            windowHeight:'',
            imagesrc: null,
            imgList:[],
            canvasSiz:{
                width:188,
                height:273
            }
        };
    },
    onLoad() {
        _this= this;
        this.init();
    },
    methods: {
        //添加照片水印
        watermark(info){
            console.log("獲取到的數據為",info)
            uni.getImageInfo({
                src: info.path,
                success: function(image) {
                    console.log(image);
                    _this.canvasSiz.width =image.width;
                    _this.canvasSiz.height =image.height;
                    let maxWidth = image.width - 60; 
                    console.log("獲取最大寬度",maxWidth)
                    //擔心尺寸重置后還沒生效,故做延遲
                    setTimeout(()=>{
                        let ctx = uni.createCanvasContext('canvas-clipper', _this);
                        
                        ctx.drawImage(
                            info.path,
                            0,
                            0,
                            image.width,
                            image.height
                        );
                        
                        //具體位置如需和相機頁面上一致還需另外做計算,此處僅做大致演示
                        ctx.setFillStyle('white');
                        ctx.setFontSize(50);
                        
                        ctx.fillText(info.info.username, 20, 150);
                        ctx.setFontSize(50);
                        let previousRowHeight =  _this.textPrewrap(ctx,info.info.address,20,220,70,maxWidth,3);

                        //再來加個時間水印
                        ctx.setFontSize(40);
                        ctx.fillText(info.info.time, 20, previousRowHeight+70);

                        ctx.draw(false, () => {
                            uni.canvasToTempFilePath(
                                {
                                    destWidth: image.width,
                                    destHeight: image.height,
                                    canvasId: 'canvas-clipper',
                                    fileType: 'jpg',
                                    success: function(res) {
                                        _this.savePhoto(res.tempFilePath);
                                    }
                                },
                                _this
                            );
                        });
                    },500)
                    
                    
                }
            });
        },
        /**
        ctx: 畫布的上下文環境
        content: 需要繪制的文本內容
        drawX: 繪制文本的x坐標
        drawY: 繪制文本的y坐標
        lineHeight:文本之間的行高
        lineMaxWidth:每行文本的最大寬度
        lineNum:最多繪制的行數
        */
        textPrewrap(ctx, content, drawX, drawY, lineHeight, lineMaxWidth, lineNum) {
            var drawTxt = ''; // 當前繪制的內容
            var drawLine = 1; // 第幾行開始繪制
            var drawIndex = 0; // 當前繪制內容的索引
            // 判斷內容是否可以一行繪制完畢
            if (ctx.measureText(content).width <= lineMaxWidth) {
                ctx.fillText(content.substring(drawIndex, i), drawX, drawY);
            } else {
                    for (var i = 0; i < content.length; i++) {
                    drawTxt += content[i];
                    if (ctx.measureText(drawTxt).width >= lineMaxWidth) {
                        if (drawLine >= lineNum) {
                            ctx.fillText(content.substring(drawIndex, i) + '..', drawX, drawY);
                            break;
                        } else {
                            ctx.fillText(content.substring(drawIndex, i + 1), drawX, drawY);
                            drawIndex = i + 1;
                            drawLine += 1;
                            drawY += lineHeight;
                            drawTxt = '';
                        }
                    } else {
                        // 內容繪制完畢,但是剩下的內容寬度不到lineMaxWidth
                        if (i === content.length - 1) {
                            ctx.fillText(content.substring(drawIndex), drawX, drawY);
                            return drawY;
                            console.log("最后高度為",drawY);
                        }
                    }
                }
            }
        },

        
        //保存圖片到相冊,方便核查
        savePhoto(path){
            this.imgList.push(path)
            // this.imagesrc = path;
            //保存到相冊
            // uni.saveImageToPhotosAlbum({
            //     filePath: path,
            //     success: () => {
            //         uni.showToast({
            //             title: '已保存至相冊',
            //             duration: 2000
            //         });
            //     }
            // });
        },
        lookImg(index){
            // 預覽圖片
            uni.previewImage({
                current:index,
                urls: this.imgList,
            });
        },
        //初始化
        init(){
            let _this = this;
            uni.getSystemInfo({
                success: function(res) {
                    _this.windowWidth = res.windowWidth;
                    _this.windowHeight = res.windowHeight;
                }
            });
        }
        
    }
};
</script>

<style lang="less">
.page {
    width: 750rpx; 
    justify-content: center;
    align-items: center;
    flex-direction:column;
    display: flex;
    .buttons {
        width: 600rpx;
    }
}
.img-list{
    padding: 20rpx;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    flex-wrap: wrap;
}
.img-item{
    width: 100rpx;
    height: 100rpx;
    margin-right: 20rpx;
    margin-bottom: 20rpx;
    
}
.img-item image{
    width: 100%;
    height: 100%;
}

</style>

 canvas文本換行方法:https://segmentfault.com/a/1190000017869922


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM