uni-app实现水印相机(仅小程序端)

效果展示

点击“拍照”,拍照成功后在底部生成已经添加上水印的图片,点击图片查看图片

在这里插入图片描述

在这里插入图片描述

结构与样式

结构

<template>
	<view>
		<camera :device-position="device" :flash="flash" @error="error" :style="{ width: '100%',position: 'relative', height: getHeight + 'px' }">
			<cover-view class="topBox">
                <!-- 时间 -->
				<cover-view class="topItem">{{nowTime2}}</cover-view>
                <!-- 日期 -->
				<cover-view class="topItem">{{nowTime}}</cover-view>
                <!-- 地址 -->
				<cover-view class="topItem">{{address}}</cover-view>
			</cover-view>

            <!-- 旋转摄像头 -->
			<cover-image @click="xzBtn" class="xzImg" src="https://cdn.zhoukaiwen.com/xz.png"></cover-image>
            <!-- 打开/关闭 闪关灯 -->
			<cover-image @click="sgdBtn" class="sgdImg" :src="sgdUrl"></cover-image>
            <!-- 拍照 -->
			<cover-view class="cameraBtn" @click="takePhoto">
				<cover-view class="cameraBtn2"></cover-view>
			</cover-view>
          
            <!-- 底部预览生成图片 -->
			<cover-view class="bottomBg" v-if="imgList.length > 0">
				<cover-view>
					<cover-view @click="ViewImage(index)" class="imgBox" v-for="(item,index) in imgList" :key="index">
						<cover-image class="imgItem" :src="item.src" mode="aspectFill"></cover-image>
						<cover-view class="cu-tag" @tap.stop="DelImg" :data-index="index">
							<cover-image class="iconClose" src="https://cdn.zhoukaiwen.com/icon_close.png" mode="aspectFill"></cover-image>
						</cover-view>
					</cover-view>
				</cover-view>
			</cover-view>
		</camera>

        <!-- canvas元素,利用它的功能,实现添加水印 -->
		<view style="position: absolute;top: -999999px;">
          <view>
            <canvas :style="{ width: w, height: h }" canvas-id="firstCanvas"></canvas>
          </view>
		</view>

	</view>
</template>

为了让自定义的按钮如:旋转镜头、打开/关闭 闪光灯、拍摄等能够位于camera 组件上层,所以容器都采用 cover-viewcover-image

样式

	.topBox {
		width: 750rpx;
		box-sizing: border-box;
		padding: 30rpx;
		color: #EEEEEE;
		font-size: 34rpx;

		.topItem {
			width: 100%;
			white-space: pre-wrap;
			margin-bottom: 15rpx;
		}
	}

	.cameraBtn {
		width: 120rpx;
		height: 120rpx;
		line-height: 120rpx;
		border: 6rpx #FFFFFF solid;
		border-radius: 50%;
		padding: 8rpx;
		position: absolute;
		left: calc(50% - 60rpx);
		bottom: 210rpx;
	}

	.cameraBtn2 {
		width: 100%;
		height: 100%;
		border-radius: 50%;
		background-color: #FFFFFF;
		text-align: center;
		color: #007AFF;
	}

	.xzImg {
		width: 52rpx;
		height: auto;
		position: absolute;
		right: 44rpx;
		bottom: 580rpx;
	}

	.sgdImg {
		width: 40rpx;
		height: auto;
		position: absolute;
		right: 50rpx;
		bottom: 450rpx;
	}

	.bottomBtn {
		width: 100%;
		height: 150rpx;
		padding-bottom: 15rpx;
		position: absolute;
		bottom: 0;
		left: 0;
		text-align: center;
		display: flex;
		justify-content: space-between;

		.btn {
			width: 30%;
			height: 150rpx;
			font-size: 34rpx;
			color: #FFFFFF;
			line-height: 150rpx;
		}
	}

	.bottomBg {
		width: 100%;
		height: 170rpx;
		box-sizing: border-box;
		padding: 20rpx 30rpx 40rpx;
		position: absolute;
		bottom: 0;
		left: 0;
		background-color: rgba(0, 0, 0, .8);
		display: flex;
		justify-content: space-between;
		align-items: center;

		.imgBox {
			width: 110rpx;
			height: 110rpx;
			float: left;
			margin-right: 40rpx;
			position: relative;

			.cu-tag {
				position: absolute;
				right: 0;
				top: 0;
				border-bottom-left-radius: 2px;
				padding: 3px 5px;
				height: auto;
				background-color: rgba(0, 0, 0, 0.5);
				font-size: 10px;
				vertical-align: middle;
				font-family: Helvetica Neue, Helvetica, sans-serif;
				white-space: nowrap;
				color: #ffffff;
			}
		}

		.imgItem {
			width: 110rpx;
			height: 110rpx;
		}
	}

	.iconClose {
		width: 20rpx;
		height: 20rpx;
	}

绑定数据

data() {
  return {
    getHeight: '200', // camera 组件高度
    device: 'back', //前置或后置摄像头,值为front, back
    flash: 'off', // 闪光灯,值为auto, on, off
    nowTime: '', //日期
    nowTime2: '', //时间
    address: '', //当前地址信息
    sgdUrl: 'https://cdn.zhoukaiwen.com/sgd.png', // 闪光灯图片地址
    imgList: [ // 底部预览图片的列表
      // {
      // 	src: "https://cdn.zhoukaiwen.com/angular.jpg"
      // }
    ],
    w: '', // canvas 元素宽度
    h: '' // canvas 元素高度
  }
},

逻辑代码

需要提前下载腾讯地图微信小程序JavaScript SDK,实现定位功能

// 引入微信小程序JavaScript SDK
import QQMapWX from "@/common/qqmap-wx-jssdk";


onLoad() {
  const that = this;
  var qqmapsdk;
  // 获取系统信息,为 camera 组件设置高度
  uni.getSystemInfo({
    success: function(res) {
      that.getHeight = res.windowHeight;
    }
  });
  // 获取当前日期时间
  this.getTime();
  // 获取当前位置信息 
  uni.getLocation({
    type: 'wgs84',
    success: function(res) {
      console.log('当前位置的经度:' + res.longitude);
      console.log('当前位置的纬度:' + res.latitude);

      qqmapsdk = new QQMapWX({
        key: "xxxxxxxxxxxxxxxxxxx" //自己申请的腾讯地图key
      });
      // 根据经纬度反解析出地址名称
      qqmapsdk.reverseGeocoder({
        location: {
          latitude: res.latitude,
          longitude: res.longitude
        },
        success(addressRes) {
          that.address = addressRes.result.address;
        },
        fail(res) {}
      });
    }
  });

},
methods: {
  // 旋转摄像头
  xzBtn() {
    if (this.device == 'front') {
      this.device = 'back'
    } else {
      this.device = 'front'
    }
  },
  // 打开/关闭 闪光灯
  sgdBtn() {
    if (this.flash == 'off') {
      this.flash = 'on'
      this.sgdUrl = 'https://cdn.zhoukaiwen.com/sgd_on.png'
    } else {
      this.flash = 'off'
      this.sgdUrl = 'https://cdn.zhoukaiwen.com/sgd.png'
    }
  },
  // 删除水印照片
  DelImg(e) {
    uni.showModal({
      content: '确定要删除这张照片吗?',
      cancelText: '取消',
      confirmText: '确认',
      success: res => {
        if (res.confirm) {
          this.imgList.splice(e.currentTarget.dataset.index, 1)
        }
      }
    })
  },
  // 查看照片
  ViewImage(index) {
    const imgList = [this.imgList[index].src];
    uni.previewImage({
      urls: imgList
    });
  },
  // 点击拍照
  takePhoto() {
    var that = this;
    if (this.imgList.length < 3) {
      // 创建并返回 camera 组件的上下文 cameraContext 对象
      const ctx = uni.createCameraContext();
      // 拍照
      ctx.takePhoto({
        quality: 'high', // 图片质量高
        success: (res) => {
          var tempImagePath = res.tempImagePath; // 临时图片路径
          // 获取图片信息
          uni.getImageInfo({
            src: res.tempImagePath,
            success: ress => {
              that.w = ress.width / 3 + 'px'; // 设置 canvas 元素宽度
              that.h = ress.height / 3.01 + 'px'; // 设置 canvas 元素高度
              let ctx = uni.createCanvasContext('firstCanvas'); /** 创建画布 */
              //将图片绘制到cancas内
              ctx.drawImage(res.tempImagePath, 0, 0, ress.width / 3, ress.height / 3);
              
              ctx.setFontSize(10); // 设置字体大小为 10px
              ctx.setFillStyle('#FFFFFF'); // 设置颜色为白色
              
              let textToWidth = (ress.width / 3) * 0.03; // 绘制文本的左上角x坐标位置
              let textToHeight1 = (ress.height / 3) * 0.94; // 绘制文本的左上角y坐标位置
              let textToHeight2 = (ress.height / 3) * 0.98;
              
              // 绘制日期和时间
              ctx.fillText(that.nowTime + ' ' + that.nowTime2, textToWidth, textToHeight1);
              // 绘制地址
              ctx.fillText(that.address, textToWidth, textToHeight2);

              // 绘制完成后,在下一个事件循环将 canvas 内容导出为临时图片地址
              ctx.draw(false, () => {
                setTimeout(() => {
                  uni.canvasToTempFilePath({
                    canvasId: 'firstCanvas',
                    success: res1 => {
                      tempImagePath = res1.tempFilePath
                      this.imgList.push({
                        src: tempImagePath
                      })
                    }
                  });
                }, 1000);
              });
            }
          });
        }
      });
    } else {
      uni.showToast({
        title: '最大上传3张照片',
        duration: 2000,
        icon: 'none'
      });
    }
  },
  // 用户不允许使用摄像头时触发
  error(e) {
    console.log(e.detail);
  },
  // 获取日期时间
  getTime: function() {
    var date = new Date(),
        year = date.getFullYear(),
        month = date.getMonth() + 1,
        day = date.getDate(),
        hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours(),
        minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(),
        second = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
    month >= 1 && month <= 9 ? (month = "0" + month) : "";
    day >= 0 && day <= 9 ? (day = "0" + day) : "";
    var timer = year + '年' + month + '月' + day + '日';
    var timer2 = hour + ':' + minute + ':' + second;
    this.nowTime = timer;
    this.nowTime2 = timer2;
  }
}

注意

本文章代码 90% 以上都是参考开源项目 前端铺子,如帮助到你,可以去大佬项目 gitee地址 点个 star

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹏北海-RemHusband

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值