uniapp自定义水印相机

这篇具有很好参考价值的文章主要介绍了uniapp自定义水印相机。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

上一篇文章实现了uniapp中给页面添加水印,今天我们实现一个自定义水印相机(最近跟水印杠上了,哈哈)。主要使用了camera组件来实现取景框预览,最后用canvas将自定义水印绘制到拍好的照片上面,先上图镇楼。
vue+uniapp 拍照+水印,uniapp,uni-app水印相机,uniapp照片水印,微信小程序水印相机,微信小程序照片水印vue+uniapp 拍照+水印,uniapp,uni-app水印相机,uniapp照片水印,微信小程序水印相机,微信小程序照片水印

实现

页面分为取景框和拍照完成后预览

UI实现

1、我们首先打开微信,哈哈哈哈,没错就是打开微信,这个取景框页面参考微信拍照界面UI。
2、取景界面分为上下两个部分,上部分为camera取景框组件,下部分为操作区域。

取景框组件上的关闭和水印,以及拍完照片后的略缩图展示需要通过cover-view和cover-image来展示。
代码如下:

<camera :device-position="position" 
        :flash="flash"
        @error="error"
        class="camera" 
        :style="'height:'+cHei+'px;'">
        <cover-image 
            class="close-img active" 
            @click="close" 
            src="/static/miniprogram/custom-camera/close.png"/>
        <cover-view class="water-marker">
            <cover-view class="time">11:09</cover-view>
            <cover-view class="div"></cover-view>
            <cover-view class="date">2023-09-11</cover-view>
            <cover-view class="week">星期一</cover-view>
            <cover-view class="address">江西省南昌市东湖区广场北路2</cover-view>
        </cover-view>
        <cover-image 
            class="result"
            @click="handlePre" 
            :src="photo"
            v-show="photo"/>
    </camera>

下半部分操作区域包含左边闪光灯控制按钮,中间拍照按钮(通过css实现同心圆)以及右边切换摄像头按钮。
实现代码如下:

<view class="bottom layout-row less-center">
        <image :src="'/static/miniprogram/custom-camera/light-'+(flash == 'off' ? 'on' : 'off')+'.png'"
            :class="'light-img active '+(position == 'front' ? 'hidden' : '')"
            @click="handleLight"/>
        <view class="layout-row center cicle-outside">
            <view class="cicle-inside active"
            @click="doTakePhoto"/>
        </view>
        <image src="/static/miniprogram/custom-camera/switch.png"
            class="switch-img active"
            @click="handlePosition"/>
    </view>

这波操作过后,取景页面就是开头你看到的效果了。

功能实现

先定义好控制变量

...
const position = ref('back')//摄像头
const flash = ref('off')//闪光灯
const photo = ref('')//拍完后的图片
const canvasW = ref(0)//绘制水印的canvas宽度
const canvasH = ref(0)//绘制水印的canvas高度
const fristTimedraw = ref(true)//是否为首次绘制
const working = ref(false)//是否正在生成水印
...

关闭按钮事件

...
const close = () => {
        uni.navigateBack({
            delta: 1
        })
    }
...

摄像头切换事件

...
const handlePosition = () => {
        if(working.value){
            return
        }
        if(position.value == 'back'){
            position.value = 'front'
            //切换成前置摄像头关闭闪光灯
            flash.value = 'off'
        }else {
            position.value = 'back'
        }
    }
...

闪光灯事件

...
const handleLight = () => {
        if(working.value){
            return
        }
        if(flash.value == 'off'){
            flash.value = 'on'
        }else {
            flash.value = 'off'
        }
    }
...

拍完后预览

...
const handlePre = () => {
        if(working.value){
            return
        }
        uni.previewImage({
            current: 0,
            urls: [photo.value],
            success: (res) => {
                console.log(res);
            },
        });
    }
...

最终要的拍照功能来了,因为我们camera组件拍出的照片本身是不带水印的, 所以我们需要在界面上放一个canvas组件,后期将水印和图片都绘制到canvas里面,再通过canvas来生成图片。

先在界面上添加一个canvas,且此canvas在界面不可见

...
<canvas canvas-id="firstCanvas"
        class="canvas"
        :style="'width:'+canvasW+'px;height: '+canvasH+'px'"/>
...

全部实现代码

然后就是拍照之后,将照片和水印相关内容绘制到canvas上面,这里包括绘制矩形,文字等,canvas绘图可参考我之前文章canvas绘图API。绘制好了之后通过uni.canvasToTempFilePath将canvas生成位图片。

vue+uniapp 拍照+水印,uniapp,uni-app水印相机,uniapp照片水印,微信小程序水印相机,微信小程序照片水印

我知道的,谁愿意看你瞎BB这么多,有没有能一键复制的全部代码?哎,别走啊,必须安排!!!
接下来就是全部实现代码

<template>
  <view class="layout-column">
    <camera :device-position="position" 
        :flash="flash"
        @error="error"
        class="camera" 
        :style="'height:'+cHei+'px;'">
        <cover-image 
            class="close-img active" 
            @click="close" 
            src="/static/miniprogram/custom-camera/close.png"/>
        <cover-view class="water-marker">
            <cover-view class="time">11:09</cover-view>
            <cover-view class="div"></cover-view>
            <cover-view class="date">2023-09-11</cover-view>
            <cover-view class="week">星期一</cover-view>
            <cover-view class="address">江西省南昌市东湖区广场北路2</cover-view>
        </cover-view>
        <cover-image 
            class="result"
            @click="handlePre" 
            :src="photo"
            v-show="photo"/>
    </camera>
    <view class="bottom layout-row less-center">
        <image :src="'/static/miniprogram/custom-camera/light-'+(flash == 'off' ? 'on' : 'off')+'.png'"
            :class="'light-img active '+(position == 'front' ? 'hidden' : '')"
            @click="handleLight"/>
        <view class="layout-row center cicle-outside">
            <view class="cicle-inside active"
            @click="doTakePhoto"/>
        </view>
        <image src="/static/miniprogram/custom-camera/switch.png"
            class="switch-img active"
            @click="handlePosition"/>
    </view>
    <canvas canvas-id="firstCanvas"
        class="canvas"
        :style="'width:'+canvasW+'px;height: '+canvasH+'px'"/>
  </view>
</template>

<script setup lang="ts">
    import {
        onLoad
    } from "@dcloudio/uni-app";
    import { 
        ref
    } from 'vue'
    const cHei = ref(0)
    const position = ref('back')
    const flash = ref('off')
    const photo = ref('')
    const canvasW = ref(0)
    const canvasH = ref(0)
    const fristTimedraw = ref(true)
    //是否正在生成水印
    const working = ref(false)
    onLoad(() => {
        cHei.value = uni.getSystemInfoSync().windowHeight - uni.upx2px(300)
    })
    const close = () => {
        uni.navigateBack({
            delta: 1
        })
    }
    const error = (e) => {
        console.log('camera error',e)
    }
    const takePhoto = () => {
        const ctx = uni.createCameraContext();
        ctx.takePhoto({
            quality: 'high',
            success: (res) => {
                console.log('takePhoto success',res)
                drawPhoto(res.tempImagePath)
            }
        });
    }
    const doTakePhoto = () => {
        working.value = true
        takePhoto()
        //这里真机上面第一次绘制水印图片可能需要很久,所以延迟500毫秒再执行一次
        if(fristTimedraw.value){
            setTimeout(()=>{
                takePhoto()
                fristTimedraw.value = false
            },500)
        }
    }
    const drawPhoto = (path) => {
        uni.getImageInfo({
            src: path,
            success: res => {
                let ctx = uni.createCanvasContext('firstCanvas');
                //设置画布宽高
                canvasW.value = res.width
                canvasH.value = res.height
                ctx.drawImage(path, 0, 0, res.width, res.height)
                //水印框的大小
                let w = 460
                let h = 180
                //水印框左上角坐标
                let x = 30
                let y = res.height - 210
                //圆角半径
                let r = 20
                let time = "14:30"
                let date = "2023-09-12"
                let week = "星期二"
                let address = "江西省南昌市东湖区广场北路2号"
                ctx.beginPath()
                // 因为边缘描边存在锯齿,最好指定使用 transparent 填充
                ctx.setFillStyle('transparent')
                // 左上角
                ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)

                // border-top
                ctx.moveTo(x + r, y)
                ctx.lineTo(x + w - r, y)
                ctx.lineTo(x + w, y + r)
                // 右上角
                ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)

                // border-right
                ctx.lineTo(x + w, y + h - r)
                ctx.lineTo(x + w - r, y + h)
                // 右下角
                ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)

                // border-bottom
                ctx.lineTo(x + r, y + h)
                ctx.lineTo(x, y + h - r)
                // 左下角
                ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)

                // border-left
                ctx.lineTo(x, y + r)
                ctx.lineTo(x + r, y)

                // 这里是使用 fill 或者 stroke都可以
                ctx.fill()
                // ctx.stroke()
                ctx.closePath()
                // 剪切
                ctx.clip()
                ctx.setFillStyle('rgba(255, 255, 255, 0.2)')
                ctx.fillRect(x, y, w, h)
                
                //字体加粗真机不起作用?
                //ctx.font = "normal bold 50px Arial"
                ctx.setFontSize(55); // 设置字体大小
                ctx.setFillStyle('#FFFFFF'); // 设置颜色为白色
                ctx.fillText(time, x+30, y+70);

                let timeW = ctx.measureText(time).width
                ctx.setFillStyle('#FFFF00'); // 设置颜色为
                ctx.fillRect(x+30+timeW+30, y+20, 8, 70)

                ctx.setFontSize(30); // 设置字体大小
                ctx.setFillStyle('#FFFFFF'); // 设置颜色为白色
                ctx.fillText(date, x+30+timeW+30+50, y+45);

                ctx.setFontSize(28); // 设置字体大小
                ctx.setFillStyle('#FFFFFF'); // 设置颜色为白色
                ctx.fillText(week, x+30+timeW+30+50, y+85);

                ctx.setFontSize(24); // 设置字体大小
                ctx.fillText(address, 60, y+140);

                ctx.draw(false, () => {
                    uni.showLoading({
                        title: '正在生成水印照片'
                    })
                    uni.canvasToTempFilePath({
                        canvasId: 'firstCanvas',
                        destWidth: canvasW.value*2,   //展示图片尺寸=画布尺寸1*像素比2
                        destHeight: canvasH.value*2,
                        success: res1 => {
                            working.value = false
                            uni.hideLoading()
                            photo.value = res1.tempFilePath
                        }
                    });
                })
            }
        })
    }
    //照片保存到相册
    const savePhoto = (path) => {
        uni.saveImageToPhotosAlbum({
			filePath: path,
			success: res=> {
				uni.showToast({
                    title: '照片已保存到相册',
                    icon: 'none',
                    duration: 2000
                });
			}
		})
    }
    const handleLight = () => {
        if(working.value){
            return
        }
        if(flash.value == 'off'){
            flash.value = 'on'
        }else {
            flash.value = 'off'
        }
    }
    const handlePosition = () => {
        if(working.value){
            return
        }
        if(position.value == 'back'){
            position.value = 'front'
            //切换成前置摄像头关闭闪光灯
            flash.value = 'off'
        }else {
            position.value = 'back'
        }
    }
    const handlePre = () => {
        if(working.value){
            return
        }
        uni.previewImage({
            current: 0,
            urls: [photo.value],
            success: (res) => {
                console.log(res);
            },
        });
    }
</script>

<style scoped lang="scss">
    page {
        width: 100%;
        height: 100%;
    }
    .camera {
        width: 100%;
        background: #999999;
    }
    .close-img {
        width: 48rpx;
        height: 48rpx;
        margin-top: 110rpx;
        margin-left: 40rpx;
    }
    .light-img {
        width: 48rpx;
        height: 48rpx;
    }
    .switch-img {
        width: 57rpx;
        height: 48rpx;
    }
    .bottom {
        width: 100%;
        height: 300rpx;
        background: black;
        justify-content: space-around;
    }
    .cicle-outside {
        width: 150rpx;
        height: 150rpx;
        border: 5rpx solid #fff;
        border-radius: 50%;
    }
    .cicle-inside {
        width: 130rpx;
        height: 130rpx;
        border-radius: 50%;
        background: #fff;
    }
    .hidden {
        visibility: hidden;
    }
    .water-marker {
        position: absolute;
        left: 30rpx;
        bottom: 30rpx;
        width: 430rpx;
        height: 180rpx;
        background: rgba($color: #ffffff, $alpha: 0.2);
        border-radius: 20rpx;
    }
    .time {
        font-size: 55rpx;
        color: white;
        position: absolute;
        top: 20rpx;
        left: 30rpx;
    }
    .div {
        border-radius: 3rpx;
        width: 8rpx;
        height: 70rpx;
        background: yellow;
        position: absolute;
        top: 20rpx;
        left: 200rpx;
    }
    .date {
        font-size: 28rpx;
        color: white;
        position: absolute;
        top: 20rpx;
        left: 240rpx;
        width: 180rpx;
    }
    .week {
        font-size: 28rpx;
        color: white;
        position: absolute;
        top: 60rpx;
        left: 240rpx
    }
    .address {
        font-size: 24rpx;
        color: white;
        position: absolute;
        top: 120rpx;
        left: 30rpx;
        bottom: 30rpx;
        word-break: break-all;
		word-wrap: break-word;
		white-space: pre-line;
    }
    .canvas {
        position: absolute;
        top: -999999rpx;
        width: 100%;
    }
    .result{
        width: 100rpx;
        height:100rpx;
        position: absolute;
        right:30rpx;
        bottom:30rpx;
        background:white;
        border-radius: 50%;
    }
</style>

里面有些样式是全局实现了引用的,其实就是flex布局然后row或者column,自己实现即可。目前为止,所有功能就已经实现了。

尾巴

页面上用到的图标是从阿里巴巴iconfont图标库下载。
今天的文章就到这里了,希望能给大家帮助,如果喜欢我的文章,欢迎给我点赞,评论,关注,谢谢大家!文章来源地址https://www.toymoban.com/news/detail-764092.html

到了这里,关于uniapp自定义水印相机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • uni-app 实现图片上传添加水印操作

    改进原因: 1、Canvas 2D(新接口)需要显式设置画布宽高,默认:300 150,最大:1365 1365 ios 无法上传较大图片的尺寸,固对超过此尺寸的图片进行了等比缩放的处理; 2、在页面中设置canvas宽高,导致页面有滚动条;现在采用离屏的canvas,但是离屏的canvas,canvasToTempFilePath方法

    2024年02月07日
    浏览(106)
  • uni-app web端使用getUserMedia,摄像头拍照

    摄像头显示在video标签上 拍照 npm i html2canvas

    2024年04月16日
    浏览(40)
  • 模仿dcloudio/uni-preset-vue 自定义基于uni-app的小程序框架

    我们知道通过 可以创建小程序框架。这个是DCloud 基于vue-cli 来实现的uni-app框架。使用过的都知道,有好几个模板进行选择。如果我们有自己的项目框架,如何做成预设模板,一行命令一键生成项目框架呢?例如提供给其他团队项目框架,只需要告诉一下命令就可以了,方便

    2024年02月12日
    浏览(79)
  • 微信小程序给图片加水印【使用uni-app】

    选择图片后使用canvas绘制图片,再绘制需要的水印文字,将绘制好的画布转化为图片即可 最终效果

    2024年02月10日
    浏览(65)
  • uni-app微信小程序-利用canvas给图片添加水印

    选择图片 → 将图片绘制到 canvas 中并绘制水印 →将添加水印的图片绘制到 canvas 中 → 将 canvas 画布转换为图片地址 → 上传/展示操作 注意:微信小程序在选择照片或者唤起相机之前需要获取相应的 权限 利用 uni.getSetting 查看用户是否调用相机的权限(有就选择图片,没有就

    2024年02月06日
    浏览(59)
  • uniapp自定义水印相机

    上一篇文章实现了uniapp中给页面添加水印,今天我们实现一个自定义水印相机(最近跟水印杠上了,哈哈)。主要使用了camera组件来实现取景框预览,最后用canvas将自定义水印绘制到拍好的照片上面,先上图镇楼。 页面分为取景框和拍照完成后预览 1、我们首先打开微信,哈

    2024年02月04日
    浏览(36)
  • uniapp小程序开发自定义相机、拍照、上传

    功能背景 项目开发小程序,想要实现一个自定义相机的功能,需要可以拍照,并且显示经纬度等一些其他信息在相机画面上。而且拍照上传,是可以将文字叠加在图片上(目前我这里是由后端实现的,前端应该也是可以做的,利用canvas,这个后面再研究)。这里仅仅是介绍小

    2024年02月16日
    浏览(43)
  • #Uniapp:uni.chooseImage(OBJECT)--从本地相册选择图片或使用相机拍照 & uni.uploadFile(OBJECT) --- 上传文件&onPageScroll滚动

    uni.chooseImage(OBJECT)–从本地相册选择图片或使用相机拍照 OBJECT 参数说明 参数名 类型 必填 说明 平台差异说明 count Number 否 最多可以选择的图片张数,默认9 见下方说明 sizeType Array 否 original 原图,compressed 压缩图,默认二者都有 App、微信小程序、支付宝小程序、百度小程序

    2024年04月23日
    浏览(43)
  • 基于uniapp+vite4+vue3搭建跨端项目|uni-app+uview-plus模板

    最近得空学习了下uniapp结合vue3搭建跨端项目。之前也有使用uniapp开发过几款聊天/仿抖音/后台管理等项目,但都是基于vue2开发。随着vite.js破局出圈,越来越多的项目偏向于vue3开发,就想着uniapp搭配vite4.x构建项目效果会如何?经过一番尝试果然真香~ uniapp官网提供了  HBuild

    2024年02月09日
    浏览(87)
  • (小程序)基于uniapp+vite4+vue3搭建跨端项目|uni-app+uview-plus模板

    版本信息: 点击编辑器的文件 新建 项目(快捷键Ctrl+N) 2.选择uni-app项目,输入项目名/路径,选择项目模板,勾选vue3版本,点击创建,即可成功创建。 3.点击编辑器的运行 运行到浏览器 选择浏览器 当然也可以运行到手机或模拟器、运行到小程序工具。 到这里一个简单的

    2024年02月16日
    浏览(102)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包