【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机

效果图

在这里插入图片描述
在这里插入图片描述

template

下方的image图片自行寻找替换!

<template>
  <view>
    <camera
      v-if="!tempImagePath && cameraHeight !== 0"
      :resolution="'high'"
      :frame-size="'large'"
      :device-position="device"
      :flash="flash"
      :style="{
        position: 'fixed',
        top: '0',
        width: cameraWidth + 'px',
        height: cameraHeight + 'px',
      }"
    ></camera>
    <image
      v-else
      :src="tempImagePath"
      mode="widthFix"
      style="width: 100%"
    ></image>

    <view class="watermark" v-if="cameraHeight !== 0">
      <view class="time">
        <text class="times-r">
          {{ time }}
        </text>
        <text class="times-date">
          <text class="year-date">
            {{ date }}
          </text>
          <text class="weeks-date">
            {{ week }}
          </text>
        </text>
      </view>
      <view class="location_box">
        <view class="location">{{ address }}</view>
      </view>
    </view>

    <canvas
      type="2d"
      id="canvas"
      :style="{
        position: 'fixed',
        top: '-10000px',
        left: '-10000px',
        width: canvasWidth + 'px',
        height: canvasHeight + 'px',
      }"
    ></canvas>

    <view class="handle" id="myContainer">
      <button class="handle_card" @click="chooseLocation">
        <image
          class="handle_card_icon"
          :src="require('./image/wz.png')"
          mode="widthFix"
        ></image>
        <view class="handle_card_name">定位</view>
      </button>
      <button class="handle_card" @click="setDevice">
        <image
          class="handle_card_icon"
          :src="require('./image/qh.png')"
          mode="widthFix"
        ></image>
        <view class="handle_card_name">切换</view>
      </button>
      <button class="handle_ps" @click="takePhoto">
        <image
          class="handle_ps_image"
          :src="require('./image/ps.png')"
          mode="widthFix"
        ></image>
        <view class="handle_ps_name">拍摄</view>
      </button>
      <button class="handle_card" @click="setFlash">
        <image
          class="handle_card_icon"
          :src="require('./image/sd.png')"
          mode="widthFix"
        ></image>
        <view class="handle_card_name">闪光</view>
      </button>
      <button class="handle_card" open-type="share">
        <image
          class="handle_card_icon"
          :src="require('./image/fx.png')"
          mode="widthFix"
        ></image>
        <view class="handle_card_name">分享</view>
      </button>
    </view>
  </view>
</template>

js

开发者秘钥key自行填写,用于定位位置功能!
showToast和showLoading为自行封装的弹窗
如果没有直接用官网的uni.showToast

<script>
const mapSDK = new QQMapWX({
  key: "", //申请的开发者秘钥key
});
import { showToast, showLoading } from "@/js/common.js";
export default {
  data() {
    return {
      device: "back",
      flash: "",
      date: "",
      time: "",
      week: "",
      address: "",
      addressName: "",
      cameraWidth: 0,
      cameraHeight: 0,
      canvasWidth: 0,
      canvasHeight: 0,
      tempImagePath: "",
      timer: null,
    };
  },
  created() {
    const systemInfo = wx.getSystemInfoSync();
    const screenWidth = systemInfo.screenWidth;
    const screenHeight = systemInfo.screenHeight;
    const statusBarHeight = systemInfo.statusBarHeight;
    const menuButtonInfo = wx.getMenuButtonBoundingClientRect();
    const cameraWidth = screenWidth;
    uni
      .createSelectorQuery()
      .select("#myContainer")
      .boundingClientRect((rect) => {
        const cameraHeight =
          screenHeight -
          statusBarHeight -
          menuButtonInfo.height -
          (menuButtonInfo.top - systemInfo.statusBarHeight) * 2 -
          rect.height;
        this.cameraWidth = cameraWidth;
        this.cameraHeight = cameraHeight;
        this.getTime();
        this.getLocation();
      })
      .exec();
  },
  methods: {
    // 获取并更新时间的方法
    getTime() {
      this.timer = setInterval(() => {
        const timeData = this.formatTime();
        this.date = timeData.date;
        this.time = timeData.time;
        this.week = timeData.week;
      }, 1000);
    },
    // 获取并更新位置信息的方法
    getLocation() {
      uni.getLocation({
        success: (Locares) => {
	        mapSDK.reverseGeocoder({
		      location: {
		        latitude: Locares.latitude,
		        longitude: Locares.longitude,
		      },
		      get_poi: 1,
		      success:(res)=> {
		        this.address = res.address;
		      }
		    })
          })
        }
      })
    },
    // 拍摄事件
    takePhoto() {
      const ctx = uni.createCameraContext();
      ctx.takePhoto({
        quality: "high",
        success: (res) => {
          this.canvasWidth = res.width;
          this.canvasHeight = res.height;
          this.tempImagePath = res.tempImagePath;
          this.addWatermark(this.tempImagePath)
            .then((addWatermark) => {
              uni.saveImageToPhotosAlbum({
                filePath: addWatermark,
                success: () => {
                  showToast("保存成功");
                  this.tempImagePath = "";
                },
              });
            })
            .catch((e) => {
              showToast(e);
            })
        }
      })
    },
    /**
     * 给图片添加水印
     */
    addWatermark(imageUrl) {
      return new Promise((resolve, reject) => {
        showLoading("图片生成中...");
        const query = uni.createSelectorQuery();
        query
          .select("#canvas")
          .fields({
            node: true,
          })
          .exec((res) => {
            const canvas = res[0].node;
            const ctx = canvas.getContext("2d");
            const { canvasWidth, canvasHeight } = this;
            canvas.width = canvasWidth;
            canvas.height = canvasHeight;
            // 绘制背景图片
            const image = canvas.createImage();
            image.src = imageUrl;
            image.onload = () => {
              const sizeX = this.canvasWidth / 375;
              ctx.drawImage(image, 0, 0);
              ctx.font = `${35 * sizeX}px 黑体`;
              ctx.fillStyle = "#ffffff";
              ctx.textBaseline = "bottom";
              // 绘制时间
              ctx.fillText(this.time, 10 * sizeX, canvasHeight - 30 * sizeX);
              const timeWidth = ctx.measureText(this.time).width;
              // 绘制边框线条
              ctx.beginPath();
              ctx.lineCap = "round";
              ctx.moveTo(timeWidth + 16 * sizeX, canvasHeight - 59 * sizeX);
              ctx.lineTo(timeWidth + 16 * sizeX, canvasHeight - 36 * sizeX);
              ctx.lineWidth = 3 * sizeX;
              ctx.strokeStyle = "#7FCAF4";
              ctx.stroke();
              // 绘制年月日
              ctx.font = `${12 * sizeX}px 黑体`;
              ctx.fillText(
                this.date,
                timeWidth + 22 * sizeX,
                canvasHeight - 49 * sizeX
              );
              // 绘制周几
              ctx.fillText(
                this.week,
                timeWidth + 22 * sizeX,
                canvasHeight - 34 * sizeX
              );
              // 绘制地址
              ctx.font = `${14 * sizeX}px 黑体`;
              ctx.fillText(this.address, 10 * sizeX, canvasHeight - 10 * sizeX);
              uni.canvasToTempFilePath({
                canvas,
                success: (res) => {
                  uni.hideLoading();
                  console.log(canvas, res.tempFilePath, 199);
                  resolve(res.tempFilePath);
                },
                fail: (e) => {
                  uni.hideLoading();
                  reject(new Error(JSON.stringify(e)));
                },
              });
            };
          });
      });
    },
    /**
     * 切换摄像头
     */
    setDevice() {
      this.device = this.device === "back" ? "front" : "back";
      const text = this.device === "back" ? "后置" : "前置";
      showToast(`摄像头${text}`)
    },
    /**
     * 闪光灯开关
     */
    setFlash() {
      this.flash = this.flash === "torch" ? "off" : "torch";
    },
    /**
     * 选择位置信息
     */
    chooseLocation() {
      uni.chooseLocation({
        success: (res) => {
          this.address = res.address;
        },
        fail(err) {
          console.log(err);
        },
      });
    },
    formatTime() {
      const date = new Date();
      const year = date.getFullYear();
      const month = date.getMonth() + 1;
      const day = date.getDate();
      const weekDay = ["日", "一", "二", "三", "四", "五", "六"][date.getDay()];
      const hour = date.getHours();
      const minute = date.getMinutes();
      // const second = date.getSeconds(); 如果需要秒显示,自行修改
      const formatNumber = (n) => {
        const s = n.toString();
        return s[1] ? s : "0" + s;
      };
      return {
        date: [year, month, day].map(formatNumber).join("-"),
        time: [hour, minute].map(formatNumber).join(":"),
        week: "星期" + weekDay,
      };
    },
  },
};
</script>

sass样式

<style lang="scss">
.handle {
  position: fixed;
  bottom: 0;
  width: 100%;
  height: 15%;
  display: flex;
  justify-content: space-around;
  align-items: center;
  font-size: 28rpx;
  background: rgb(255, 255, 255);
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

.handle_ps,
.handle_card {
  display: flex;
  flex-direction: column;
  text-align: center;
  height: 75px;
  line-height: 25px;
  background: #ffffff;
  padding: 0;
  font-size: 25rpx;
}
.handle_ps {
  &::after {
    border: none;
  }
}
.handle_card::after {
  border: none;
}
.handle_ps_image {
  width: 50px;
  height: 50px;
}
.handle_card_name {
  font-size: 25rpx;
}

.handle_card_icon {
  width: 40px;
  height: 40px;
  margin: 5px;
}
.watermark {
  position: fixed;
  bottom: 16%;
  left: 10px;
  color: #fff;
}
.location_box {
  display: flex;
  line-height: 25px;
  height: 25px;
}
.time {
  display: flex;
  .times-r {
    position: relative;
    font-size: 75rpx;
    padding-right: 25rpx;
    &::before {
      content: "";
      position: absolute;
      width: 6rpx;
      height: 53%;
      border-radius: 10rpx;
      background: #7fcaf4;
      right: 8rpx;
      top: 50%;
      transform: translateY(-50%);
    }
  }
  .times-date {
    padding-left: 5rpx;
    display: flex;
    flex-direction: column;
    justify-content: center;
    font-size: 24rpx;
    .year-date,
    .weeks-date {
      display: block;
    }
  }
}
.time,
.location {
  color: #fff;
}
</style>

在这里插入图片描述
感谢你的阅读,如对你有帮助请收藏+关注!
只分享干货实战精品从不啰嗦!!!
如某处不对请留言评论,欢迎指正~
博主可收徒、常玩QQ飞车,可一起来玩玩鸭~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/662284.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ModuleNotFoundError: No module named ‘osgeo‘

显示无osgeo模块 pip install osgeo显示失败 方法&#xff1a; 确保你已经安装了正确的依赖项&#xff0c;例如GDAL、GEOS和PROJ等。 方法1&#xff1a;pip install gdal 失败 方法2&#xff1a;官网下载失败&#xff0c;下载地址&#xff1a;https://www.lfd.uci.edu/~gohl…

vue3学习(四)

前言 接上篇学习笔记&#xff0c;分享3个内置组件&#xff1a;动态组件、缓存组件、分发组件基本用法。大家一起通过code的示例&#xff0c;从现象理解,注意再次理解生命周期。 一、code示例 组件A&#xff1a;CompA <script setup> import {onMounted, onUnmounted} f…

【CTF-Web】XXE学习笔记(附ctfshow例题)

XXE 文章目录 XXE0x01 前置知识汇总XMLDTD &#xff08;Document Type Definition&#xff09; 0x02 XXE0x03 XXE危害0x04 攻击方式1. 通过File协议读取文件Web373(有回显)Web374(无回显) Web375Web376Web377Web378 0x01 前置知识汇总 XML 可扩展标记语言&#xff08;eXtensi…

分享 - 树形dp

树形 d p dp dp 例1 - 基础 链接&#xff1a;树上子链 练手 分析 其实一看题就很显然的树形 d p dp dp子链在这里分为两种情况&#xff0c;如图黑链和红链 思路 d p [ i ] dp[i] dp[i] 表示以 i i i 开头的红链的最大权值易得&#xff1a; d p [ i ] m a x ( d p [ i…

SelfKG论文翻译

SelfKG: Self-Supervised Entity Alignment in Knowledge Graphs SelfKG&#xff1a;知识图中的自监督实体对齐 ABSTRACT 实体对齐旨在识别不同知识图谱&#xff08;KG&#xff09;中的等效实体&#xff0c;是构建网络规模知识图谱的基本问题。在其发展过程中&#xff0c;标…

ubuntu server版 虚拟机根目录磁盘扩容

之前一直使用桌面版ubuntu,因为项目原因需要拉取的代码太大了且项目比较多选择了体量更小的Ubuntu server版,在使用中发现根目录的磁盘很快就用满了 如上,明明分配的300G但是/dev/mapper/ubuntu--vg-ubuntu--lv 只有98G都用满了 server版本与桌面版不同的是在server版安装的时…

MySQL增删查改进阶

数据库约束表的关系增删查改 目录 一.数据库约束类型 NOT NULL约束类型 UNIQUE 唯一约束 DEFAULT 默认值约束 PRIMARY KEY&#xff1a;主键约束 FOREIGN KEY :W外键约束 二&#xff0c;查询 count&#xff08;&#xff09;两种用法 sum&#xff0c;avg&#xff0c;max…

leetcode-设计LRU缓存结构-112

题目要求 思路 双链表哈希表 代码实现 struct Node{int key, val;Node* next;Node* pre;Node(int _key, int _val): key(_key), val(_val), next(nullptr), pre(nullptr){} };class Solution { public: unordered_map<int, Node*> hash; Node* head; Node* tail; int …

朗读亭主要作用有哪些?

朗读亭的主要作用有以下几个方面&#xff1a; 1. 提供朗读服务&#xff1a;朗读亭是一个专门的场所&#xff0c;提供给人们朗读的环境和场地。人们可以在朗读亭中选择自己喜欢的书籍或文章&#xff0c;并通过朗读将其表达出来。这样可以帮助人们提高朗读能力&#xff0c;增强自…

C++学习~~对于二进制文件的读写命名空间再认识异常处理

目录 1.将数据以二进制形式放到磁盘 2.将上述的数据读入内存并且显示在显示器上面 3.异常处理机制 4.抛出异常的应用实例 1.将数据以二进制形式放到磁盘 &#xff08;1&#xff09;使用student定义结构体数组stud,并对其进行初始化&#xff0c;创建输出文件流对象outfile,这…

什么是React?

01 Why React? What is React? I think the one-line description of React on its home page (https://react.dev/) is concise and accurate: “A JavaScript library for building user interfaces.” 我认为React主页(https://react.dev/)上的一行描述既简洁又准确: …

微信聊天内容怎么监控? | 三款可以监控电脑微信聊天记录的软件大盘点

你是否听说过监控微信呢&#xff1f; 有时出于特定需求&#xff0c;比如家长对孩子上网行为的关心&#xff0c;或者企业对员工工作效率的监控&#xff0c;可能需要了解某些情况下的微信聊天记录。 但请注意&#xff0c;任何未经授权的监控行为都是违法的&#xff0c;并且可能…

PFC基础知识1

不同负载 1.当负载是电阻时&#xff0c; 阻值固定&#xff0c;阻性负载&#xff0c;相位相同&#xff0c;并且线性度非常好 &#xff0c;输出的电流全部被利用 2.当负载有电感时&#xff0c;相位有偏差&#xff0c;电流滞后于电压90。电源需要输出电流&#xff0c;但是电感并未…

java Web开发中采用Servlet登录验证,中文用户名始终提示“用户名密码错误”以及输出中文乱码问题

采用Servlet登录验证&#xff0c;中文乱码问题解决 在Java Web开发中&#xff0c;往往采用Servlet完成前后端直接的控制和处理&#xff0c;例如&#xff1a;用户登录验证功能。 在采用如下Servle源码t完成用户名登录验证时&#xff0c;只要用户名涉及中文&#xff0c;对于正确…

APP原生开发与框架开发的优劣势

电话管家APP商用也有几年时间了&#xff0c;但是客户一直都有遇到一些问题。 为什么我们的APP老是要升级&#xff1f; 为什么有些手机使用体验不好&#xff1f; 为什么有些公司的APP几天就开发出来上线了&#xff1f; 为什么有些公司的APP那么便宜&#xff1f; 今天就来从…

Chromium源码学习(1)—— 拉取源码,编译

阅读建议&#xff1a;先简单过一下整个文章目录结构&#xff0c;大致了解一下各个步骤在干什么&#xff0c;然后在上手操作可能会事半功倍。也许你遇到的有些问题文章中已经提及到了&#xff0c;但是由于你没有往下看导致卡进度。 Chromium简介 Chromium项目于2008年发布&…

一个小技巧轻松提升量化精度!IntactKV:保持关键词元无损的大语言模型量化方法

目录 摘要关键词元&#xff08;Pivot Tokens&#xff09;方法概述实验验证1. 权重量化2. KV Cache 量化3. 权重和激活值量化 参考文献 本文介绍我们针对大语言模型量化的工作 IntactKV&#xff0c;可以作为插件有效提升 GPTQ、AWQ、QuaRot 等现有主流量化方法效果。论文作者来自…

Hadoop伪分布式安装教程

Hadoop伪分布式安装教程 一、安装背景1.1 软件列表1.2 系统软件列表 二、安装Hadoop2.1 安装 Java 环境2.1.1 前期准备2.1.2 文件传输2.1.3 解压文件2.1.4 配置 jdk 的环境变量2.1.5 输入 java、javac、java -version 命令检验 jdk 是否安装成功 2.2 Hadoop 下载地址[hadoop](h…

C语言序列化和反序列化--TPL(一)

TPL TPL说明网站 C语言中高效的序列化 您可以使用tpl快速轻松地存储和重新加载C数据。Tpl是一个用于序列化C数据的库。数据以自然二进制形式存储。该API很小&#xff0c;并试图保持“不碍事”。Tpl可以序列化许多C数据类型&#xff0c;包括结构。Tpl与文件、内存缓冲区和文件…

观成科技:Play勒索软件组织加密流量分析

1.概述 近年来&#xff0c;勒索软件组织的作业链条逐渐从“加密数据->收取赎金”转变到“数据窃取->加密数据->暗网披露窃取数据大小和内容描述->收取赎金”[1]。勒索软件组织在获取到受害者的访问权限后&#xff0c;不会立刻进行勒索&#xff0c;而是进行横向移动…