uniapp水印相机(水印照片,图片加水印)

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

在实际开发的项目中,我们有时候会遇到相机拍照上传照片的时候需要带有水印的功能。下面整理了我在自己的项目中做的水印相机(完整源码)功能实战分享给大家。

水印中内容包含如下(实际包含的内容根据你的实际需求而定,这里只是以我的项目需求为例):

  • 具体日期时间,如:2023-05-25 12:00:00 星期四
  • 地理位置,如:江苏省南京市雨花台区软件大道19号
  • 经纬度,如:纬度: 32.08405200000000,经度: 118.76358600000000

------↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓---上源码---↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓------

1. 申请功能(父组件)

<template>
  <view class="container">
    <!-- 背景渐变 -->
    <view class="bg_gradient"></view>
    <!-- 申报信息 -->
    <view class="applyInfo">
      <view class="applyTable">
        <u-form :model="model1" ref="form1">
          <u-form-item label="申请单位(人)" labelWidth="130rpx" borderBottom prop="name">
            <u-input
              clearable
              placeholder="请输入申请单位(人)"
              v-model="model1.name"
            ></u-input>
          </u-form-item>
          <u-form-item label="通讯地址" labelWidth="130rpx" borderBottom prop="address">
            <u-input
              clearable
              placeholder="请输入通讯地址"
              v-model="model1.address"
            ></u-input>
          </u-form-item>
          <u-form-item label="联系电话" labelWidth="130rpx" borderBottom prop="tel">
            <u-input
              clearable
              placeholder="请输入联系电话"
              v-model="model1.tel"
            ></u-input>
          </u-form-item>
          <u-form-item label="调入地点" labelWidth="130rpx" borderBottom prop="addressIn" @click="addressShow = true">
            <u-input disabled disabledColor="#fff" placeholder="请选择省市区" v-model="model1.addressIn"></u-input>
            <!-- 省市区选择器 -->
            <u-picker 
              ref="uPicker"
              :show="addressShow" 
              :columns="addressColumn" 
              @change="addressChange" 
              @confirm="addressConfirm" 
              @cancel="addressShow = false"
            ></u-picker>
          </u-form-item>
          <u-form-item label="收货单位(人)" labelWidth="130rpx" borderBottom prop="nameOut">
            <u-input
              clearable
              placeholder="请输入收货单位(人)"
              v-model="model1.nameOut"
            ></u-input>
          </u-form-item>
          <u-form-item label="收货人" labelWidth="130rpx" borderBottom prop="nameOut2">
            <u-input
              clearable
              placeholder="请输入收货人姓名"
              v-model="model1.nameOut2"
            ></u-input>
          </u-form-item>
          <u-form-item label="身份证号" labelWidth="130rpx" borderBottom prop="idCard">
            <u-input
              clearable
              placeholder="请输入身份证号码"
              v-model="model1.idCard"
            ></u-input>
          </u-form-item>
          <u-form-item label="手机号" labelWidth="130rpx" borderBottom prop="telOut">
            <u-input
              clearable
              placeholder="请输入手机号"
              v-model="model1.telOut"
            ></u-input>
          </u-form-item>
          <u-form-item label="调入时间" labelWidth="130rpx" borderBottom prop="applyTime" @click="datetimeShow=true">
            <u-input disabled disabledColor="#fff" placeholder="请选择时间" v-model="model1.applyTime"></u-input>
            <!-- 时间选择器 -->
            <u-datetime-picker
              ref="datetimePicker"
              mode="datetime"
              :formatter="formatter2"
              :show="datetimeShow"
              v-model="model1.timeIn"
              @confirm="datetimeConfirm"
              @cancel="datetimeShow=false"
            ></u-datetime-picker>
          </u-form-item>
          <u-form-item label="车牌号" labelWidth="130rpx" borderBottom prop="carNo">
            <u-input
              clearable
              placeholder="请输入车牌号"
              v-model="model1.carNo"
            ></u-input>
          </u-form-item>
          <button style="margin-top: 10px;" @click="addShow=true">新增产品</button>
          <view class="addProduct" v-for="it,index in model1.treeInfoVO" :key="index">
            <view class="deleteProduct" @click="delProduct(it)">x</view>
            <view class="p">
              <view>产品名称:</view>
              <view>{{ it.tname }}</view>
            </view>
            <view class="p">
              <view>品名/材种:</view>
              <view>{{ it.kind }}</view>
            </view>
            <view class="p">
              <view>规格:</view>
              <view>{{ it.spec }}</view>
            </view>
            <view class="p">
              <view>数量:</view>
              <view>{{ it.num }}</view>
            </view>
            <view class="p">
              <view>备注:</view>
              <view>{{ it.remark }}</view>
            </view>
          </view>
        </u-form>
      </view>
      <view class="title">
        <view class="up">
          <b>*</b><view>照片说明</view>
        </view>
        <view style="margin: 20rpx 0;color: #444;">
          <text>车头正面照、车头左侧45度照、车头右侧45度照、车尾正面照、车尾左侧45度照、车尾右侧45度照、细节照1、细节照2</text>
        </view>
      </view>
      <view style="margin: 3px 0 10px;"><u-line></u-line></view>
      <view class="photo">
        <view class="up">
          <b>*</b><view>照片列表</view>
        </view>
        <view class="down">
          <watermark @cameraCloseEvent="cameraCloseBtn" @cameraEvent="cameraBtn" @finishEvent="afterReadHandler" @deleteEvent="deletePhoto" :imgUrls="imgUrls" :submitDisabled="submitDisabled"></watermark>
        </view>
      </view>
      <!-- 提交按钮 -->
      <view class="submitBtn">
        <view>
          <u-button type="primary" shape="circle" color="#00c39c" text="提交" :disabled="submitDisabled" @click="submit"></u-button>
        </view>
      </view>
    </view>
    <!-- 新增产品模态框 -->
    <u-modal 
      :show="addShow" 
      title="植物产品"
      showCancelButton 
      @cancel="addCancel"
      @confirm="addConfirm"
    >
    <view style="display: flex;flex-direction: column;">
      <u-form :model="model2" ref="form2">
        <u-form-item label="产品名称" labelWidth="120rpx" borderBottom prop="tname">
          <u-input placeholder="请输入植物产品名称" v-model="model2.tname"></u-input>
        </u-form-item>
        <u-form-item label="品名/材种" labelWidth="130rpx" borderBottom prop="kind">
          <u-input placeholder="请输入品名/材种" v-model="model2.kind"></u-input>
        </u-form-item>
        <u-form-item label="规格类型" labelWidth="120rpx" borderBottom prop="" @click="specShow=true">
          <u-input disabled disabledColor="#fff" placeholder="请选择规格类型" v-model="specVal"></u-input>
          <u-picker 
            title="规格类型"
            :show="specShow" 
            :columns="specColumns"
            @confirm="specSelect"
            @cancel="specShow = false"
          ></u-picker>
        </u-form-item>
        <u-form-item label="规格" labelWidth="120rpx" borderBottom prop="spec">
          <u-input placeholder="请输入规格内容" v-model="model2.spec"></u-input>
        </u-form-item>
        <u-form-item label="数量" labelWidth="120rpx" borderBottom prop="num">
          <u-input placeholder="请输入数量" v-model="model2.num"></u-input>
        </u-form-item>
        <u-form-item label="备注" labelWidth="100rpx" borderBottom prop="remark">
          <u-textarea count maxlength="80" height="75" placeholder="请输入备注内容" v-model="model2.remark"></u-textarea>
        </u-form-item>
      </u-form>
    </view>
    </u-modal>
    <!-- 提示信息 -->
    <u-toast ref="uToast"></u-toast>
  </view>
</template>

<script>
import {sendApplication,getAddress,getInformation,getImgsByIds} from '../../../api/applicant/index.js'
import watermark from './watermark.vue'
export default {
  components: {watermark},
  data() {
    return {
      model1: {
        name: '',      // 申请单位(人)
        address: '',   // 通讯地址
        tel: '',       // 联系电话
        addressIn: '', // 调入地点
        nameOut: '',   // 收货单位(人)
        nameOut2: '',  // 收货人
        idCard: '',    // 身份证号
        telOut: '',    // 手机号
        timeIn: '',    // 调入时间
        carNo: '',     // 车牌号
        treeInfoVO: [],// 新增产品内容 
        title: '',     // 标题内容
        rid: '',       // 上传照片
        applyTime: '', // 时间选择器选择时间后页面展示的调入时间
      },
      rules1: {
        'name': {
          whitespace: true,
          required: true,
          message: '请输入申请单位(人)',
          trigger: ['blur', 'change']
        },
        'address': {
          whitespace: true,
          required: true,
          message: '请输入通讯地址',
          trigger: ['blur', 'change']
        },
        'tel': [
          {
            required: true,
            message: '请输入联系电话',
            trigger: ['blur', 'change']
				  },
          {
            pattern: /(^\d{3}-\d{8}$|^\d{4}-\d{7}$)|(^1[3-9]\d{9}$)/,
            message: `电话号码规则错误,正确格式:
            XXXX-XXXXXXX、XXX-XXXXXXXX
            或者11位手机号码`,
            trigger: ['blur']
          }
				],
        'addressIn': {
          required: true,
          message: '请选择省市区',
          trigger: ['blur', 'change']
        },
        'nameOut': {
          whitespace: true,
          required: true,
          message: '请输入收货单位(人)',
          trigger: ['blur', 'change']
        },
        'nameOut2': {
          whitespace: true,
          required: true,
          message: '请输入收货人',
          trigger: ['blur', 'change']
        },
        'idCard': [
          {
            required: true,
            message: '请输入身份证号',
            trigger: ['blur', 'change']
				  },
          {
            pattern: /^[1-9]\d{5}(19\d{2}|20[0-2][0-9])(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]$/,
            message: `请输入正确的身份证号码`,
            trigger: ['blur']
          }
				],
        'telOut': [
          {
            required: true,
            message: '请输入手机号',
            trigger: ['blur', 'change']
				  },
          {
            pattern: /^1[3-9]\d{9}$/,
            message: "请输入合法的手机号码",
            trigger: ['blur']
          }
				],
        'carNo': [
          {
            pattern: /^([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[a-zA-Z](([DF]((?![IO])[a-zA-Z0-9](?![IO]))[0-9]{4})|([0-9]{5}[DF]))|[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1})$/,
            message: "请输入合法的车牌号码",
            trigger: ['blur']
          }
				],
        'applyTime': {
          required: true,
          message: '请选择时间',
          trigger: ['blur', 'change']
        },
      },
      model2: {
        tname: '', // 植物产品名称
        kind: '',  // 品名/材种
        spec: '',  // 规格
        num: '',   // 数量
        remark: '',// 备注
      },
      rules2: {
        'tname': {
          whitespace: true,
          required: true,
          message: '请输入植物产品名称',
          trigger: ['blur', 'change']
        },
        'kind': {
          whitespace: true,
          required: true,
          message: '请输入品名/材种',
          trigger: ['blur', 'change']
        },
        'spec': [
          {
            whitespace: true,
            required: true,
            message: '请输入规格内容',
            trigger: ['blur', 'change']
          }
        ],
        'num': [
          {
            required: true,
            message: '请输入数量',
            trigger: ['blur', 'change']
          },
          {
            pattern: /^[0-9]+$/,
            message: "数量必须是非负整数",
            trigger: ['blur']
          }
        ]
      },
      datetimeShow: false,  // 是否显示 时间选择器
      addressShow: false,   // 是否显示 省市区选择器
      addressColumn: [['请选择'],['请选择'],['请选择']],// 省市区
      province: [],         // 省
      city: [],             // 市
      area: [],             // 区
      addShow: false,       // 是否显示 新增产品模态框
      specShow: false,      // 是否显示 规格类型选择器
      specColumns: [['胸径','地径','冠幅','其他']],
      specVal: '胸径',      // 规格类型
      imgsRelation: [],     // 存放(水印照片图片路径与rid对应关系)数组
      submitDisabled: false,// 提交按钮是否禁用
      imgUrls: [],          // 照片url
      imgIds: [],           // 照片id
      isSubmit: false,      // 是否执行了(提交按钮)
    }
  },
  methods: {
    /* 通过传进来的rid获取照片 */
    getImgs() {
      getImgsByIds({ids: this.imgIds}).then(res=>{
        if(res.code==200) {
          this.imgUrls = [];
          let resData = res.data;
          for(let i=0;i<resData.length;i++) {
            this.imgUrls.push(resData[i].url);
            for(let ii=0;ii<this.imgIds.length;ii++) {
              if(i==ii) {
                let relation = {[resData[i].url]: this.imgIds[ii]}; //水印照片图片路径与rid对应关系
                this.imgsRelation.push(relation);
              }
            }
          }
        }
      })
    },
    /* 时间选择器确认 */
    datetimeConfirm(val) {
      this.model1.timeIn = val.value;
      let d = new Date(this.model1.timeIn*1);
      this.model1.applyTime = d.getFullYear() +'年'+ (d.getMonth() + 1) +'月'+ d.getDate() +'日'+ d.getHours() +'时'+ d.getMinutes() +'分';
      this.$refs.form1.validateField('applyTime');
      this.datetimeShow = false;
    },
    /* 时间格式化 */
    formatter2(type, value) {
      if (type === 'year') {return `${value}年`};
      if (type === 'month') {return `${value}月`};
      if (type === 'day') {return `${value}日`};
      if (type === 'hour') {return `${value}时`};
      if (type === 'minute') {return `${value}分`};
      return value;
    },
    /* 省市区选择器确认 */
    addressConfirm(e) {
      if(e.value[0]=='请选择') {
        this.addressShow = false;
      } else {
        if(e.value[1] == '请选择' || e.value[2] == '请选择') {
          this.$refs.uToast.show({
            type: 'error',
            message: '省市区不完整',
            duration: 2500,
          })
        } else {
          this.addressShow = false;
          this.model1.addressIn = e.value[0] + e.value[1] + e.value[2];
          this.$refs.form1.validateField('addressIn');
        }
      }
    },
    /* 省市区选择器改变 */
    async addressChange(e) {
      // 当第一列(省)值发生变化时
      if (e.columnIndex === 0) {
        this.addressColumn[1].splice(1);
        this.addressColumn[2].splice(1);
        if(e.index==0) return;
        this.$refs.uPicker.setColumnValues(1, this.addressColumn[1][e.index])
        // 选中的省份数据
        let selectProvince = this.province.find(item=>{
          return item.address == e.value[0];
        })
        // 获取城市列表
        await getAddress({addressType: 2,code: selectProvince.code}).then(res=>{
          if(res.code==200) {
            this.city = res.data;
            res.data.forEach(item=>{
              this.addressColumn[1].push(item.address);
            })
          }
        })
      }
      // 当第二列(市)值发生变化时
      if (e.columnIndex === 1) {
        this.addressColumn[2].splice(1);
        if(e.index==0) return;
        this.$refs.uPicker.setColumnValues(2, this.addressColumn[2][e.index])
        // 选中的城市数据
        let selectCity = this.city.find(item=>{
          return item.address == e.value[1];
        })
        // 获取区域列表
        await getAddress({addressType: 3,code: selectCity.code}).then(res=>{
          if(res.code==200) {
            this.area = res.data;
            res.data.forEach(item=>{
              this.addressColumn[2].push(item.address);
            })
          }
        })
      }
    },
    /* 关闭水印相机触发 */
    cameraCloseBtn() {
      this.submitDisabled = false;
    },
    /* 点击水印相机触发 */
    cameraBtn() {
      uni.setStorageSync('cacheApplyInfo',JSON.stringify(this.model1));
      this.submitDisabled = true;
    },
    /* 照片完成后的处理函数 */
    afterReadHandler(e) {
      uni.uploadFile({
        url: `${this.$upload}`,
        filePath: e,
        name: 'file',
        header: {
          Authorization: uni.getStorageSync('token'),
          'Content-Type': 'multipart/form-data',
        },
        success: res => {
          if(res.statusCode==200) {
            if(this.model1.rid=='') {
              this.model1.rid += JSON.parse(res.data).data.id;
            } else {
              this.model1.rid += ',' + JSON.parse(res.data).data.id;
            }
            let relation = {[e]: JSON.parse(res.data).data.id}; //水印照片图片路径与rid对应关系
            this.imgsRelation.push(relation);
            this.submitDisabled = false;
          }
        }
      })
    },
    /* 删除照片 */
    deletePhoto(srcVal) {
      let tempArr = this.model1.rid.split(',');
      let tempRid = '';
      this.imgsRelation.forEach(outIt=>{
        for(let inIt in outIt) {
          if(inIt == srcVal) {
            tempRid = outIt[inIt];
          }
        }
      })
      tempArr = tempArr.filter(item=>{
        if(item!=tempRid) return item;
      })
      this.model1.rid = tempArr.join(',');
    },
    /* 规格类型下拉选择触发 */
    specSelect(val) {
      this.specShow = false;
      this.specVal = val.value[0];
    },
    /* 新增产品取消 */
    addCancel() {
      this.addShow = false;
      this.model2.tname = "";
      this.model2.kind = "";
      this.model2.spec = "";
      this.model2.num = "";
      this.model2.remark = "";
      this.$refs.form2.clearValidate();
    },
    /* 新增产品确定 */
    addConfirm() {
      this.$refs.form2.validate().then(() => {
        this.model2.spec = this.specVal +":"+ this.model2.spec;
        this.model1.treeInfoVO.push({...this.model2});
        this.addCancel();
      }).catch(()=>{});
    },
    /* 删除产品 */
    delProduct(itVal) {
      this.model1.treeInfoVO = this.model1.treeInfoVO.filter(item=>{
        if(itVal!=item) return item;
      })
    },
    /* 提交 */
    submit() {
      this.$refs.form1.validate().then(() => {
        if(this.model1.treeInfoVO.length==0) {
          this.$refs.uToast.show({type: 'error',message: '请新增产品'});
        } else if(this.model1.rid.split(',').length<2) {
          this.$refs.uToast.show({type: 'error',message: '照片不得少于2张'});
        } else {
          this.submitDisabled = true;
          this.model1.title = '';
          this.model1.treeInfoVO.forEach(it=>{//每次的新增品种都给title一份,用来搜索查询
            if(this.model1.title=='') {
              this.model1.title += it.kind;
            } else {
              this.model1.title += ',' + it.kind;
            }
          })
          sendApplication(this.model1).then(res=>{
            if(res.code==200) {
              this.isSubmit = true;
              this.$refs.uToast.show({
                type: 'success',
                message: '提交成功',
                duration: 1000,
                complete() {
                  uni.removeStorageSync('cacheApplyInfo');
                  uni.setStorageSync('submitEvent',1);
                  uni.navigateBack({delta: 1});
                }
              });
            }
          })
        }
      }).catch(()=>{});
    }
  },
  beforeDestroy() {
    if(!this.isSubmit) {
      uni.setStorageSync('cacheApplyInfo',JSON.stringify(this.model1));
    }
  },
  onShow() {
    /* 获取省份列表 */
    getAddress({addressType: 1}).then(res=>{
      if(res.code==200) {
        this.province = res.data;
        res.data.forEach(item=>{
          this.addressColumn[0].push(item.address);
        })
      }
    })
    this.model1.timeIn = new Date().getTime();
    /* 获取申请人备案信息 */
    if(uni.getStorageSync('cacheApplyInfo')=="") {
      getInformation().then(res=>{
        if(res.code==200) {
          let data = res.data;
          if(data.perType==1) {
            this.model1.name = data.name;
            this.model1.address = data.addr;
            this.model1.tel = data.tel;
          } else if(data.perType==2) {
            this.model1.name = data.businessName;
            this.model1.address = data.addr;
            this.model1.tel = data.tel;
          }
        }
      })
    } else {
      this.model1 = JSON.parse(uni.getStorageSync('cacheApplyInfo'));
      let d = new Date(this.model1.timeIn*1);
      this.model1.timeIn = this.model1.timeIn*1;
      this.model1.applyTime = d.getFullYear() +'年'+ (d.getMonth() + 1) +'月'+ d.getDate() +'日'+ d.getHours() +'时'+ d.getMinutes() +'分';
      this.imgIds = this.model1.rid.split(',');
      this.getImgs();
    }
  },
  onReady() {
    this.$refs.form1.setRules(this.rules1);// 如果需要兼容微信小程序,并且校验规则中含有方法等,只能通过setRules方法设置规则。
    this.$refs.form2.setRules(this.rules2);// 如果需要兼容微信小程序,并且校验规则中含有方法等,只能通过setRules方法设置规则。
	this.$refs.datetimePicker.setFormatter(this.formatter2);// 微信小程序需要用此写法(时间格式化)
  }
}
</script>

<style lang="scss" scoped>
.container {
  /deep/.u-input {
    padding-left: 0 !important;
  }
  /deep/.u-form-item__body__left__content__label,
  /deep/.u-input__content__field-wrapper__field,
  /deep/.u-textarea__field {
    font-size: 13px !important;
  }
  .bg_gradient {
    width: 100%;
    height: 100px;
    background-image: linear-gradient(to bottom,#00c39c,#F9F9F9);
    position: fixed;
    top: 0;
    z-index: -1;
  }
  .applyInfo {
    background-color: #fff;
    border-radius: 8px;
    margin: 16px 16px 0;
    padding: 12px;
    .applyTable {
      .addProduct {
        border: 1px solid #EAEBEC;margin: 5px 0; padding: 3px; color: #303133;
        position: relative;
        .deleteProduct {
          width: 20px;
          height: 20px;
          line-height: 15px;
          text-align: center;
          font-size: 15px;
          background-color: #373737;
          color: #fff;
          border-bottom-left-radius: 20px;
          z-index: 3;
          position: absolute;
          right: 0;
          top: 0;
        }
        .p {
          margin: 0 0 3px 0;
          display: flex;
          view:nth-child(1) {
            width: 70px;
          }
          view:nth-child(2) {
            margin: 0 15px 0 3px;
            width: calc(100% - 80px);
            word-wrap: break-word;
          }
        }
      }
    }
    .title {
      margin: 10px 0 0 0;
    }
    .title,.photo {
      .up {
        font-size: 13px;
        color: #666666;
        display: flex;
        b {
          margin-right: 6px;
          color: #f10000;
        }
      }
      .down {
        margin-top: 10px;
      }
    }
    .submitBtn {
      margin: 20px 0 0 0;
    }
  }
}
</style>

2. 水印相机(子组件)文章来源地址https://www.toymoban.com/news/detail-773573.html

<template>
  <view class="container">
    <button @click="openCamera" :disabled="submitDisabled">水印相机</button>
    <view class="myImgs">
      <view class="screenImgs" v-for="(it,index) in imgSrcArr" :key="index">
        <view class="deleteImg" @click="delImg(it)">x</view>
        <u-album :urls="[it]"></u-album>
      </view>
    </view>
    <canvas 
      canvas-id="myCanvasId"
      :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }" 
      v-show="canvasShow"
    ></canvas>
  </view>
</template>
<script>
export default {
  props: {
    imgUrls: {
      type: Array,
      default() {
        return [];
      }
    },
    submitDisabled: {
      type: Boolean,
      default: false,
    }
  },
  data() {
    return {
      context: null,     // canvas上下文
      canvasWidth: 0,    // canvas容器宽度
      canvasHeight: 0,   // canvas容器高度
      canvasShow: true,  // canvas容器是否存在
      imgSrcArr: [],     // 本地展示的图片路径(canvas容器图片)
      addressInfo: '',   // 位置
      longitude: '',     // 经度 
      latitude: '',      // 纬度
      imageInfo: '',     // 拍照得到的照片信息
    }
  },
  methods: {
    /* 删除照片 */
    delImg(srcVal) {
      this.$emit('deleteEvent',srcVal);
      this.imgSrcArr = this.imgSrcArr.filter(item=>{
        if(srcVal!=item) return item;
      })
    },
    /* 点击水印相机按钮 */
    async openCamera() {
      this.$emit('cameraEvent');
      if(this.imgSrcArr.length>7) {
        uni.showToast({icon: 'none',duration: 2500,title: `最多上传【8】张`});
        this.$emit('cameraCloseEvent');
        return;
      }
      try {
        const res = await uni.chooseImage({
          count: 1,
          sizeType: ['compressed'],
          sourceType: ['camera'],
        })
        if(res[1]===undefined) {
          this.$emit('cameraCloseEvent');
        }
        this.imageInfo = await uni.getImageInfo({
          src: res[1].tempFilePaths[0],
        })
        const { width, height } = this.imageInfo[1];
        // 计算canvas宽高,照片横拍与竖拍的比例自适应规则
        const ratio = width / height;
        const maxWidth = uni.upx2px(960); // 最大宽度为960rpx
        const maxHeight = uni.upx2px(720);// 最大高度为720rpx
        /**
         * 规则:1.照片宽度大于最大宽度,以最大宽度为准
         * 规则:2.照片高度大于最大高度,以最大高度为准
         * 规则:3.照片高度或照片宽度任意一个超出最值范围,以最大高度和宽度为准
         */
        if (width > maxWidth) {
          this.canvasWidth = maxWidth;
          this.canvasHeight = this.canvasWidth / ratio;
        } else if (height > maxHeight) {
          this.canvasHeight = maxHeight;
          this.canvasWidth = this.canvasHeight * ratio;
        } else {
          this.canvasWidth = width;
          this.canvasHeight = height;
        }
        this.locationInfo(); // 获取定位信息
      } catch (err) {}
    },
    /* 当前定位信息 */
    locationInfo() {
      uni.getLocation({
        type: 'gcj02',
        success: res => {
          this.latitude = res.latitude;
          this.longitude = res.longitude;
          this.placeInfo(); // 获取位置信息
        },
        fail: () => {
          uni.showToast({ icon: 'none', duration: 2500, title: `获取位置信息失败` });
        },
      })
    },
    /* 当前位置信息 */
    placeInfo() {
      let getAddressUrl = `https://apis.map.qq.com/ws/geocoder/v1/?location=${this.latitude},${this.longitude}&key=你的key值`;
      uni.$u.http.get(getAddressUrl).then(res=>{
        this.addressInfo = res.result.address;
        this.createCanvas(); // 创建canvas容器
      })
    },
    /* canvas容器 */
    createCanvas() {
      this.context = uni.createCanvasContext('myCanvasId',this);
      this.context.drawImage(this.imageInfo[1].path, 0, 0, this.canvasWidth, this.canvasHeight);
      this.context.setFontSize(16);
      this.context.setFillStyle('#ffffff');
      this.context.fillText(this.currentTime(), 10, this.canvasHeight - 30);
      this.context.fillText(`${this.addressInfo}`, 10, this.canvasHeight - 60);
      this.context.fillText(`经度: ${this.longitude}`, 10, this.canvasHeight - 90);
      this.context.fillText(`纬度: ${this.latitude}`, 10, this.canvasHeight - 120);
      this.canvasShow = false;
      this.watermarkPhoto(); // 获取水印照片
    },
    /* 水印照片 */
    watermarkPhoto() {
      let that = this;
      this.context.draw(false, () => {
        // 将canvas转成图片路径
        uni.canvasToTempFilePath({
          canvasId: 'myCanvasId',
          success: function(res) {
            // 将图片路径赋值给image标签的src属性
            that.imgSrcArr.push(res.tempFilePath);
            that.canvasShow = true;
            that.canvasWidth = 0;
            that.canvasHeight = 0;
            that.$emit('finishEvent',res.tempFilePath);
          }
        },this);
      });
    },
    /* 当前日期时间 */
    currentTime() {
      let d = new Date();
      // 年
      let year = d.getFullYear();
      // 月
      let month = d.getMonth() + 1;
      month = month > 9 ? month : '0'+month;
      // 日
      let date = d.getDate();
      date = date > 9 ? date : '0'+date;
      // 时
      let hours = d.getHours();
      hours = hours > 9 ? hours : '0'+hours;
      // 分
      let minutes = d.getMinutes();
      minutes = minutes > 9 ? minutes : '0'+minutes;
      // 秒
      let seconds = d.getSeconds();
      seconds = seconds > 9 ? seconds : '0'+seconds;
      // 星期
      let weekdayArr = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
      let weekday = weekdayArr[d.getDay()];
      return year+"-"+month+"-"+date+" "+hours+":"+minutes+":"+seconds+" "+weekday;
    },
  },
  watch: {
    imgUrls: {
      deep: true,
      handler() {
        this.imgSrcArr = [...this.imgUrls];
      }
    }
  }
}
</script>

<style lang="scss" scoped>
/deep/[role=img] {
  width: 80px !important;
  height: 80px !important;
}
.container {
  .myImgs {
    margin: 10px 0 0 0;
    display: flex;
    flex-wrap: wrap;
    .screenImgs {
      margin: 0 4px 4px 0;
      position: relative;
      .deleteImg {
        width: 20px;
        height: 20px;
        line-height: 15px;
        text-align: center;
        font-size: 15px;
        background-color: #373737;
        color: #fff;
        border-bottom-left-radius: 20px;
        z-index: 3;
        position: absolute;
        right: 0;
        top: 0;
      }
    }
  }
}
</style>

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

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

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

相关文章

  • uni-app微信小程序-利用canvas给图片添加水印

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

    2024年02月06日
    浏览(59)
  • uni-app 调用相机或相册图片并转为base64格式上传图片

    1、调用相机或相册上传图片 2、图片文件转base64 (1)下载插件 (2)页面引入插件 3、image-tools/index.js源码

    2024年02月11日
    浏览(62)
  • uniapp制作水印相机给图片添加水印并且保存图片至本地

    文件主要分为两大类: 1.代码包文件:代码包文件指的是在项目目录中添加的文件。 2.本地文件:通过调用接口本地产生,或通过网络下载下来,存储到本地的文件。 其中本地文件又分为三种: 1.本地临时文件:临时产生,随时会被回收的文件。运行时最多存储 4GB,结束运

    2024年02月11日
    浏览(55)
  • uni-app 之 图片

    uni-app 之 图片 获取图片 v-bind 动态绑定 image.png

    2024年02月10日
    浏览(59)
  • 『UniApp』uni-app-打包成App

    大家好,我是 BNTang, 在上一节文章中,我给大家详细的介绍了如何将我开发好的项目打包为微信小程序并且发布到微信小程序商店 趁热打铁,在来一篇文章,给大家详细的介绍如何将项目打包成APP。 打包 App 也是一样的,首先需要配置关于 App 应用的基础信息,打开 manifest

    2024年02月04日
    浏览(108)
  • 【UniApp】-uni-app-网络请求

    经过上个章节的介绍,大家可以了解到 uni-app-pinia存储数据的基本使用方法 那本章节来给大家介绍一下 uni-app-网络请求 的基本使用方法 首先我们打开官方文档,我先带着大家看一下官方文档的介绍:https://uniapp.dcloud.net.cn/api/request/request.html 从官方文档中我们可以看到,可以

    2024年02月04日
    浏览(53)
  • uni-app实现图片上传功能

    效果 代码  

    2024年02月13日
    浏览(74)
  • 【UniApp】-uni-app-打包成网页

    经过上一篇文章的介绍,已经将这个计算器的计算功能实现了,接下来就是我们项目当中的一个发包上线阶段,我模拟一下,目的就是为了给大家介绍一下,uni-app是如何打包成网页的。 除了可以打包成网页,uni-app还可以打包成小程序、App、H5、快应用等等,后面在单独开文

    2024年02月04日
    浏览(72)
  • uni-app base64转图片

    首先将插件引入项目。按照image-tools - DCloud 插件市场上面的操作即可;

    2024年02月13日
    浏览(57)
  • uni-app 中使用背景图片

    uni-app 中使用背景图片 一 : H5 上使用(但是在微信小程序中报错) 二 : 微信小程序中可以 1,使用网络图片(对不同环境需要不同配置), 2,或者 base64(需要本地转换), 3,或者使用标签(推荐使用)

    2024年02月16日
    浏览(50)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包