uniapp制作水印相机给图片添加水印并且保存图片至本地

uniapp保存文件的三种方式

  • 文件主要分为两大类:

1.代码包文件:代码包文件指的是在项目目录中添加的文件。

2.本地文件:通过调用接口本地产生,或通过网络下载下来,存储到本地的文件。

  • 其中本地文件又分为三种:

1.本地临时文件:临时产生,随时会被回收的文件。运行时最多存储 4GB,结束运行后,如果已使用超过 2GB,会以文件为维度按照最近使用时间从远到近进行清理至少于2GB。
2.本地缓存文件:小程序通过接口把本地临时文件缓存后产生的文件,不能自定义目录和文件名。跟本地用户文件共计,小程序(含小游戏)最多可存储 200MB。
3.本地用户文件:小程序通过接口把本地临时文件缓存后产生的文件,允许自定义目录和文件名。跟本地缓存文件共计,小程序(含小游戏)最多可存储 200MB。
注意:不管是使用那种存储方式,只要是小程序被删除了,那么所有的保存在用户本地的信息都将会被清空!!!
在这里插入图片描述

官方对文件存储的详细介绍可以点击这里进行查看
由于这里需要将图片保存到本地然后再将图片内容进行回显,所以直接不考虑本地临时文件存储的方式,下面我将会从本地缓存文件以及用户本地文件两个角度分别演示如何将添加过图片的水印保存到本地。

代码说明

1.由于微信小程序的定位只能获取到经纬度,无法获取到地区的城市去和街道,这里的采用的腾讯地图的经纬度逆解析,建议大家先看完这篇文章,不然下面我引入的QQMapWX,大家可能会感到一些疑惑。
2.代码还有很多优化的空间:比如每次点击拍照都要重新打开相机,这里可以使用unaipp的camera专门之所一个属于自己的水印相机来解决这个问题,而不是使用微信自带的相机去拍摄,这些问题大家可以自行按需解决。
3.本文只是一个引导,给大家提供一些解决问题的私立,也许代码会有很多不妥,希望大家取其精华,弃之糟粕。

采给图片添加水印

下面的代码只是添加水印,水印的效果见下文

    // 添加水印
    setImageText() {
    
    
      var that = this;
      // 绘制前清空画布
      this.context.clearRect(
        0,
        0,
        this.canvasView.width,
        this.canvasView.height
      );
      // 将图片src放到cancas内,宽高必须为图片大小
      this.context.drawImage(
        this.canvasView.canvasImg,
        0,
        0,
        this.canvasView.width,
        this.canvasView.height,
        this.canvasView.width,
        this.canvasView.height
      );
      // 设置上下两个边框的透明度
      this.context.setGlobalAlpha(0.5);

      this.context.beginPath();
      // 1.绘制顶部的白色背景
      this.context.rect(
        0,
        0,
        this.canvasView.width,
        this.canvasView.contentHeight
      );
      this.context.setFillStyle("white");
      this.context.fill();

      // 2.绘制底部的白色背景
      this.context.rect(
        0,
        this.canvasView.height - this.canvasView.contentHeight,
        this.canvasView.width,
        this.canvasView.contentHeight
      );
      // this.context.setFillStyle("white");
      this.context.fill("white");
      // 设置文字的透明度
      this.context.setGlobalAlpha(1);
      // 3.绘制顶部的文字
      this.context.setFontSize(26);
      this.context.setTextAlign("left");
      this.context.setFillStyle("black");
      this.context.fillText("拍摄人:李帅豪", 50, 60);
      this.context.fillText(
        "拍摄时间:" + this.$u.timeFormat(new Date(), "yyyy-mm-dd hh:MM:ss"),
        50,
        110
      );

      // 4.绘制顶部的图片
      that.context.drawImage(
        "/static/image/lshlogo.png",
        that.canvasView.width - that.canvasView.logoWidth - 10,
        20,
        that.canvasView.logoWidth,
        that.canvasView.contentHeight - 40
      );
      // 5.绘制底部的文字
      // 5.1绘制定位以及网络状态
      this.context.setFontSize(33);
      this.context.setFillStyle("black");
      this.context.fillText(
        "定位:" + this.positionInfo.formatLongitude,
        50,
        this.canvasView.height - 100
      );
      this.context.fillText(
        this.positionInfo.formatLatitude,
        this.canvasView.width - 450,
        this.canvasView.height - 100
      );
      var systemimg = "";
      var networkimg = "";
      if (that.systemInfo.platform == "android") {
    
    
        systemimg = "anzhuo";
      } else if (that.systemInfo.platform == "ios") {
    
    
        systemimg = "ios";
      } else {
    
    
        systemimg = "anzhuo";
      }
      if (that.networkType == "unknown" || that.networkType == "none") {
    
    
        networkimg = "network1";
      } else if (that.networkType == "none") {
    
    
        networkimg = "flyMode";
      } else {
    
    
        networkimg = "network2";
      }
      console.log("systemimg,networkimg", systemimg, networkimg);
      that.context.drawImage(
        "/static/image/" + systemimg + ".png",
        this.canvasView.width - 150,
        this.canvasView.height - 140,
        50,
        50
      );
      that.context.drawImage(
        "/static/image/" + networkimg + ".png",
        this.canvasView.width - 90,
        this.canvasView.height - 140,
        50,
        50
      );
      // 5.2绘制所在村位置
      // 5.3绘制拍摄地址
      this.context.setFontSize(33);
      this.context.setFillStyle("black");
      this.context.fillText(
        "拍摄地址:北京市xxxxxx",
        50,
        this.canvasView.height - 50,
        this.canvasView.width - 100
      );

      // 绘制图片并保存至相册
      this.drawSave();
    },

采用本地缓存文件将水印图片保存至本地

优点:可以直接读取图片没不需要转变为base64去显示图片,读取效率快,不会存在性能问题。
缺点:使用这种方式虽然可以将图片保存至本地,不过他的缺点就是还不够灵活,如果我们想要在保存当前图片至本地的过程中顺便将当前图片的一些业务信息至本地那么就会变得非常困难。而且我们会将所有使用saveFileSync保存的文件全部读取出来,无法批量读取。
效果图如下:
在这里插入图片描述
在这里插入图片描述

代码如下:

<template>
  <view class="pages">
    <!-- 这个canvas一定不可以将一出的部分隐藏掉,否则就会有一些部分加载不出来 -->
    <canvas
      id="mycanvas"
      :style="
        'width:' + canvasView.width + 'px;height:' + canvasView.height + 'px;'
      "
      canvas-id="Canvas"
    />
    <!-- <u-loading :show="isLoading"></u-loading> -->
    <u-loadmore status="loading" v-if="isLoading" />
    <view class="imgContainer">
      <view v-for="(item1, index1) in imgList" :key="index1" class="imgDayItem">
        <view class="imgTime"
          >拍摄时间:{
    
    {
    
     item1[0].time }}({
    
    {
    
     item1.length }})</view
        >
        <div class="imgGroup">
          <view
            class="itemImg"
            v-for="(item2, index2) in item1"
            @click="previewImage(item2, index2, index1)"
            :key="index2"
          >
            <image :src="item2.path" alt="" srcset="" />
            <view class="imgName">图片{
    
    {
    
     index2 }}</view>
            <view
              class="removeImg"
              @click.stop.prevent="removeCurrentImg(item2)"
            >
              x
            </view>
          </view>
        </div>
      </view>
    </view>
    <!-- 定位的拍摄图片 -->
    <image
      src="@/static/image/cameraImg.png"
      class="cameraBtn"
      @click="TakeAPicture()"
      mode=""
    ></image>
    <!-- 测试用的删除本地文件 -->
    <button @click="deleteImg">删除本地所有图片</button>
  </view>
</template>

<script>
import QQMapWX from "../../../../js_sdk/qqmap-wx-jssdk1.2/qqmap-wx-jssdk";

export default {
    
    
  data() {
    
    
    return {
    
    
      // canvas的一些信息
      canvasView: {
    
    
        // 当前要绘制的图片
        canvasImg: undefined,
        // 将要被绘制的图片的宽度
        width: undefined,
        // 将要被绘制的图片的高度
        height: undefined,
        // 将要被绘制到图像中的上下两个矩形的高度(px)
        contentHeight: 150,
        // 将要被绘制到图像中的顶部logo的高度(px)
        logoWidth: 400,
      },
      // 当前的经纬度信息
      positionInfo: {
    
    
        mapAddress: "", // 所在村位置
        address: "", // 拍摄地址
        longitude: "", //经度(坐标)
        latitude: "", //纬度(坐标)
        formatLongitude: "", //转变过后的经度(度分秒形式)
        formatLatitude: "", //转变过后的纬度(度分秒形式)
      },
      // 当前要被绘制的图片的信息
      fileUrl: undefined,
      // canvas对象
      context: undefined,
      // 图片列表
      imgList: [],
      // 是否是正在加载中
      isLoading: true,
      // 网络类型
      networkType: "",
      // 系统信息
      systemInfo: "",
    };
  },
  created() {
    
    
    this.getCurrentLocation();
    this.getNetworkType();
    this.getSystemInfo();
  },
  mounted() {
    
    
    uni.showLoading({
    
    
      title: "正在加载图片",
    });
    this.isLoading = true;
    this.context = uni.createCanvasContext("Canvas", this);
    this.getSavedFileList();
  },
  methods: {
    
    
    // 获取本地的图片列表
    getSavedFileList() {
    
    
      var that = this;
      uni.getFileSystemManager().getSavedFileList({
    
    
        success: function (res) {
    
    
          console.log("获取本地小程序下载的文件如下:", res);

          that.imgList = res.fileList.map((item) => {
    
    
            console.log("res.fileList", item);
            return {
    
    
              path: item.filePath,
              time: that.$u.timeFormat(
                item.createTime * 1000,
                "yyyy年mm月dd日"
              ),
            };
          });
          console.log("========222==", that.imgList);
          that.formatImgList(that.imgList);
          uni.hideLoading();
          that.isLoading = false;
        },
      });
    },
    // 通过微信小程序自带的方法获取到当前的经纬度,然后通过腾讯sdk获取详细位置
    getCurrentLocation() {
    
    
      let that = this; //在uniapp中药定义一下this才能使用
      uni.getLocation({
    
    
        type: "gcj02",
        altitude: true,
        geocode: true,
        isHighAccuracy: true,
        success: function (res) {
    
    
          console.log("微信小程序定位信息", res);
          that.positionInfo.longitude = res.longitude;
          that.positionInfo.latitude = res.latitude;
          that.positionInfo.formatLongitude = that.convertToDMS(
            res.latitude,
            res.longitude
          ).longitude;
          that.positionInfo.formatLatitude = that.convertToDMS(
            res.latitude,
            res.longitude
          ).latitude;
          that.loAcquire(
            that.positionInfo.longitude,
            that.positionInfo.latitude
          );
        },
      });
    },
    // 获取网络类型
    getNetworkType() {
    
    
      var that = this;
      uni.getNetworkType({
    
    
        success: function (res) {
    
    
          console.log(res);
          that.networkType = res.networkType;
        },
      });
    },
    // 获取系统信息
    getSystemInfo() {
    
    
      var that = this;
      uni.getSystemInfo({
    
    
        success: function (res) {
    
    
          // console.log(res.appName)
          that.systemInfo = res;
          console.log("当前使用的系统是:", res.platform);
        },
      });
    },
    // 获取当前地址
    loAcquire(longitude, latitude) {
    
    
      let that = this;
      // 腾讯地图Api
      const qqmapsdk = new QQMapWX({
    
    
        key: "5IPBZ-2OA3Q-7UR5Y-4XVMJ-IIEDQ-EDFRN", //这里填写自己申请的key
      });
      console.log({
    
     longitude, latitude });
      qqmapsdk.reverseGeocoder({
    
    
        location: {
    
     longitude, latitude },
        success(response) {
    
    
          uni.hideLoading();
          that.isLoading = false;
          console.log("腾讯sdk获取的定位信息:", response);
          that.positionInfo.mapAddress =
            response.result.address_component.province +
            response.result.address_component.city +
            response.result.address_component.district +
            response.result.address_component.street;
          response.result.address_component.street_number;
          that.positionInfo.address =
            response.result.address_component.city +
            response.result.formatted_addresses.recommend;
        },
        fail() {
    
    
          that.isLoading = false;
          uni.showToast({
    
    
            icon: "none",
            title: "定位失败请检查网络状态",
            duration: 4000,
          });
        },
      });
    },
    // 添加水印
    setImageText(image) {
    
    
      var that = this;
      // 绘制前清空画布
      this.context.clearRect(
        0,
        0,
        this.canvasView.width,
        this.canvasView.height
      );
      // 将图片src放到cancas内,宽高必须为图片大小
      this.context.drawImage(
        this.canvasView.canvasImg,
        0,
        0,
        this.canvasView.width,
        this.canvasView.height,
        this.canvasView.width,
        this.canvasView.height
      );
      // 设置上下两个边框的透明度
      this.context.setGlobalAlpha(0.5);

      this.context.beginPath();
      // 1.绘制顶部的白色背景
      this.context.rect(
        0,
        0,
        this.canvasView.width,
        this.canvasView.contentHeight
      );
      this.context.setFillStyle("white");
      this.context.fill();

      // 2.绘制底部的白色背景
      this.context.rect(
        0,
        this.canvasView.height - this.canvasView.contentHeight,
        this.canvasView.width,
        this.canvasView.contentHeight
      );
      // this.context.setFillStyle("white");
      this.context.fill("white");
      // 设置文字的透明度
      this.context.setGlobalAlpha(1);
      // 3.绘制顶部的文字
      this.context.setFontSize(26);
      this.context.setTextAlign("left");
      this.context.setFillStyle("black");
      this.context.fillText("拍摄人:李帅豪", 50, 60);
      this.context.fillText(
        "拍摄时间:" + this.$u.timeFormat(new Date(), "yyyy-mm-dd hh:MM:ss"),
        50,
        110
      );

      // 4.绘制顶部的图片
      that.context.drawImage(
        "/static/image/lshlogo.png",
        that.canvasView.width - that.canvasView.logoWidth - 10,
        20,
        that.canvasView.logoWidth,
        that.canvasView.contentHeight - 40
      );
      // 5.绘制底部的文字
      // 5.1绘制定位以及网络状态
      this.context.setFontSize(33);
      this.context.setFillStyle("black");
      console.log('下面需要填写具体的位置信息');
      this.context.fillText(
        "定位:" + this.positionInfo.formatLongitude,
        50,
        this.canvasView.height - 100
      );
      this.context.fillText(
        this.positionInfo.formatLatitude,
        this.canvasView.width - 450,
        this.canvasView.height - 100
      );
      var systemimg = "";
      var networkimg = "";
      if (that.systemInfo.platform == "android") {
    
    
        systemimg = "anzhuo";
      } else if (that.systemInfo.platform == "ios") {
    
    
        systemimg = "ios";
      } else {
    
    
        systemimg = "anzhuo";
      }
      if (that.networkType == "unknown" || that.networkType == "none") {
    
    
        networkimg = "network1";
      } else if (that.networkType == "none") {
    
    
        networkimg = "flyMode";
      } else {
    
    
        networkimg = "network2";
      }
      console.log("systemimg,networkimg", systemimg, networkimg);
      that.context.drawImage(
        "/static/image/" + systemimg + ".png",
        this.canvasView.width - 150,
        this.canvasView.height - 140,
        50,
        50
      );
      that.context.drawImage(
        "/static/image/" + networkimg + ".png",
        this.canvasView.width - 90,
        this.canvasView.height - 140,
        50,
        50
      );
      // 5.3绘制拍摄地址
      this.context.setFontSize(33);
      this.context.setFillStyle("black");
      console.log('在这里填写拍摄的地址',this.positionInfo.address);
      this.context.fillText(
        "拍摄地址:北京市xxxxxxxxx" ,
        50,
        this.canvasView.height - 50,
        this.canvasView.width - 100
      );

      this.drawSave();
    },
    // 绘制图片并保存至相册
    drawSave() {
    
    
      var that = this;
      // 一定要加上一个定时器否则进入到页面第一次可能会无法正常拍照,后几次才正常
      setTimeout(() => {
    
    
        // 本次回画完重开开始绘画,并且在绘画完毕之后再保存图片,不然页面可能会出现白屏等情况
        this.context.draw(false, () => {
    
    
          console.log(
            "!!!!!!!!!1开始绘画",
            this.canvasView.width,
            this.canvasView.height
          );

          uni.canvasToTempFilePath(
            {
    
    
              canvasId: "Canvas",
              fileType: "png",
              width: this.canvasView.width,
              height: this.canvasView.height,
              destWidth: this.canvasView.width,
              destHeight: this.canvasView.height,
              success: async (path) => {
    
    
                console.log("path", path);

                let imageInfo = await that.getImageInfo({
    
    
                  imgSrc: path.tempFilePath,
                });
                console.log("==========", imageInfo);
                that.fileUrl = imageInfo.path;

                // console.log("这一步如果换成png那么就可以显示出真是的图片");
                // console.log(
                //   "lshlsh",
                //   `data:image/png;base64,${uni
                //     .getFileSystemManager()
                //     .readFileSync(imageInfo.path, "base64")}`
                // );
                var respath = uni
                  .getFileSystemManager()
                  .saveFileSync(imageInfo.path);
                console.log("拥挤存储的路径saveFileSync", respath);
                uni.saveImageToPhotosAlbum({
    
    
                  filePath: respath,
                  complete: (res) => {
    
    
                    console.log(res);
                  },
                });
                that.imgList = [];
                that.getSavedFileList();
              },
            },
            that
          );
        });
      }, 1000);
    },
    //检查相机权限
    TakeAPicture() {
    
    
      var that = this;
      uni.authorize({
    
    
        scope: "scope.camera",
        success() {
    
    
          console.log("scope.camera用户授权成功小程序");

          uni.getSetting({
    
    
            success(res) {
    
    
              console.log("authSetting", res);
              if (res.authSetting["scope.camera"] == true) {
    
    
                console.log("111当前用户已经个授权过了scope.camera");
                that.openCamera();
              } else {
    
    
                console.log("22当前用户没用授权过scope.camera");
                uni.openSetting({
    
    
                  success(res) {
    
    
                    console.log("openSetting", res);
                    if (res.authSetting["scope.camera"] == true) {
    
    
                      console.log("openSetting打开设置成功打开了摄像头权限");
                      that.openCamera();
                    } else {
    
    
                      uni.showToast({
    
    
                        title: "未获取到相机权限",
                      });
                    }
                  },
                });
              }
            },
          });
        },
        fail() {
    
    
          console.log("拒绝");
          uni.showToast({
    
    
            icon: "none",
            title: "您已拒绝相机权限,暂无法使用水印相机",
            duration: 4000,
          });
        },
      });
    },
    //获取图片信息
    async getImageInfo({
     
      imgSrc }) {
    
    
      return new Promise((resolve, errs) => {
    
    
        uni.getImageInfo({
    
    
          src: imgSrc,
          success: function (image) {
    
    
            resolve(image);
          },
          fail(err) {
    
    
            errs(err);
          },
        });
      });
    },
    //打开相机
    async openCamera() {
    
    
      var that = this;
      // 一定要使用chooseMedia,如果使用chooseImage那么部分IOS手机就没法正常使用了
      uni.chooseMedia({
    
    
        count: 1,
        mediaType: ["image"],
        sourceType: ["camera"],
        camera: "back",
        success: async (res) => {
    
    
          uni.showLoading({
    
    
            title: "正在加载图片资源",
          });
          that.isLoading = true;
          console.log(res);
          let imgInfo = await that.getImageInfo({
    
    
            imgSrc: res.tempFiles[0].tempFilePath,
          });
          console.log("这一步可以获取到真正的base图片不过还没有转化");
          // console.log(
          //   `data:image/jpg;base64,${uni
          //     .getFileSystemManager()
          //     .readFileSync(res.tempFilePaths[0], "base64")}`
          // );
          console.log("==========imgInfo", imgInfo);
          that.canvasView.canvasImg = imgInfo.path;
          that.canvasView.width = imgInfo.width;
          that.canvasView.height = imgInfo.height;
          console.log(this.canvasView);
          console.log(
            "!!!!!!!!!!当前图片信息canvasView",
            that.canvasView
          );
          that.setImageText();
        },
        fail: function (res) {
    
    
          console.log("选择图片失败", res);
        },
      });
    },
    // 删除当前的图片(测试节点使用的)
    removeCurrentImg(item) {
    
    
      // 等会儿在处理这个问题,这个需要二维为数组中寻找并且删除元素
      var that = this;
      uni.getFileSystemManager().removeSavedFile({
    
    
        filePath: item.path,
        success(res) {
    
    
          console.log("单个删除成功", res);
          that.getSavedFileList();
        },
      });
    },
    // 删除所有的图片(测试节点使用的)
    deleteImg() {
    
    
      var that = this;
      this.imgList.forEach((item) => {
    
    
        item.forEach((item2, index2) => {
    
    
          uni.getFileSystemManager().removeSavedFile({
    
    
            filePath: item2.path,
            success(res) {
    
    
              console.log("全部删除成功", res);
              that.getSavedFileList();
            },
          });
        });
      });
    },
    // 预览图片
    // 第一个参数是当前项的图片信息,
    // 第二个参数为当前图片的索引
    // 第三个参数为当前图片所在时间组的索引
    previewImage(item, index2, index1) {
    
    
      console.log("图片预览", item, index2, index1);
      var that = this;
      // 预览图片
      uni.previewImage({
    
    
        current: index2,
        urls: that.imgList[index1].map((item) => item.path),
      });
    },
    // 将获取到的图片按照日期进行格式化
    formatImgList(arr) {
    
    
      // this.imgList = Object.values(
      //   arr.reduce((obj, item) => {
    
    
      //     obj[item.time] = obj[item.time] || [item];
      //     obj[item.time].push(item);
      //     return obj;
      //   }, {})
      // ).filter((item) => item.length > 1);
      this.imgList = arr.reduce((prev, item) => {
    
    
        const index = prev.findIndex((value) => {
    
    
          return value.length > 0 && value[0].time === item.time;
        });

        if (index !== -1) {
    
    
          prev[index].push(item);
        } else {
    
    
          prev.push([item]);
        }

        return prev;
      }, []);
      console.log("formatImgList", this.imgList);
    },
    // 将经纬度转化为度分秒
    convertToDMS(lat, lng) {
    
    
      let latDirection = lat >= 0 ? "N" : "S";
      let lngDirection = lng >= 0 ? "E" : "W";

      lat = Math.abs(lat);
      lng = Math.abs(lng);

      let latDegrees = Math.floor(lat);
      let latMinutes = Math.floor((lat - latDegrees) * 60);
      let latSeconds = ((lat - latDegrees - latMinutes / 60) * 3600).toFixed(4);

      let lngDegrees = Math.floor(lng);
      let lngMinutes = Math.floor((lng - lngDegrees) * 60);
      let lngSeconds = ((lng - lngDegrees - lngMinutes / 60) * 3600).toFixed(4);

      return {
    
    
        latitude: `${
      
      latDirection}:${
      
      latDegrees}°${
      
      latMinutes}'${
      
      latSeconds}"`,
        longitude: `${
      
      lngDirection}:${
      
      lngDegrees}°${
      
      lngMinutes}'${
      
      lngSeconds}"`,
      };
    },
  },
};
</script>

<style lang="scss" scoped>
.pages {
    
    
  overflow: scroll;
}
.imgContainer {
    
    
  .imgDayItem {
    
    
    padding: 30rpx 30rpx 0;
    .imgTime {
    
    
      padding: 20rpx 0 20rpx 0;
      margin-bottom: 20rpx;
      background-color: rgb(249, 249, 249);
    }
    .imgGroup {
    
    
      // border: 2rpx solid red;
      display: flex;
      align-items: center;
      justify-content: flex-start;
      flex-wrap: wrap;

      .itemImg {
    
    
        width: 30%;
        border-radius: 25rpx;
        // border: 1rpx solid red;
        position: relative;
        margin-right: 35rpx;
        margin-bottom: 35rpx;
        &:nth-child(3n) {
    
    
          margin-right: 0rpx;
        }
        image {
    
    
          width: 100%;
          height: 200rpx;
          display: block;
        }
        .imgName {
    
    
          text-align: center;
          position: absolute;
          left: 50%;
          transform: translateX(-50%);
          bottom: 0;
        }
        .removeImg {
    
    
          color: white;
          border-radius: 50%;
          background-color: red;
          width: 40rpx;
          height: 40rpx;
          line-height: 40rpx;
          text-align: center;
          position: absolute;
          top: -24rpx;
          right: -20rpx;
        }
      }
    }
  }
}

.cameraBtn {
    
    
  position: fixed;
  right: 40rpx;
  bottom: 50rpx;
  width: 120rpx;
  height: 120rpx;
  border-radius: 50%;
  z-index: 30;
}
#mycanvas {
    
    
  position: fixed;
  left: 9999rpx;
  // opacity: 0;
  // visibility: hidden;
  // opacity: 0;
}
</style>

采用本地用户文件将水印图片保存至本地

在阅读下面的代码之前建议先把小程序官方uni.getFileSystemManager()的api先看一遍,不然可能会有一些疑惑。
优点:可以在保存图片的时候顺便将一些信息保存保存到本地(这里没有体现出来,只是大家演示一下他得最基本的用法),比如我们可以创建一个用户保存经纬度的一个文件夹,在拍照的时候可以将当前图片的经纬度一块保存至本地,他的文件名称和保存图片时的名称一致。之后我们获取这个图片的所有信息的时候,直接读取保存图片的文件夹和保存经纬度的文件夹,这样一个图片的所有的信息就都读取出来了。
优点:我们可以自己创建文件夹,然后自己给文件命名进行保存(注意这里并不是直接在用户本地的文件管理那里传建一个可见的文件夹,直接在哪里新建的文件夹,我也不知道)。在业务增多的时候就体现出来了他的强大的地方了。
效果图如下:
在这里插入图片描述
在这里插入图片描述
代码如下:

<template>
  <view class="pages">
    <!-- 这个canvas一定不可以将一出的部分隐藏掉,否则就会有一些部分加载不出来 -->
    <canvas
      id="mycanvas"
      :style="
        'width:' + canvasView.width + 'px;height:' + canvasView.height + 'px;'
      "
      canvas-id="Canvas"
    />
    <!-- <u-loading :show="isLoading"></u-loading> -->
    <u-loadmore status="loading" v-if="isLoading" />
    <view class="imgContainer">
      <view v-for="(item1, index1) in imgList" :key="index1" class="imgDayItem">
        <view class="imgTime"
          >拍摄时间:{
    
    {
    
     item1[0].time }}({
    
    {
    
     item1.length }})</view
        >
        <div class="imgGroup">
          <view
            class="itemImg"
            v-for="(item2, index2) in item1"
            @click="previewImage(item2, index2, index1)"
            :key="index2"
          >
            <image :src="item2.path" alt="" srcset="" />
            <view class="imgName">{
    
    {
    
     item2.detailTime }}</view>
            <view
              class="removeImg"
              @click.stop.prevent="removeCurrentImg(item2)"
            >
              x
            </view>
          </view>
        </div>
      </view>
    </view>
    <!-- 定位的拍摄图片 -->
    <image
      src="@/static/image/cameraImg.png"
      class="cameraBtn"
      @click="TakeAPicture()"
      mode=""
    ></image>
    <!-- 测试用的删除本地文件 -->
    <!-- <button @click="deleteImg">删除本地所有图片</button> -->

    <u-back-top
      :scroll-top="scrollTop"
      :custom-style="backTopStyle"
    ></u-back-top>
  </view>
</template>

<script>
import QQMapWX from "../../../../js_sdk/qqmap-wx-jssdk1.2/qqmap-wx-jssdk";

export default {
    
    
  data() {
    
    
    return {
    
    
      // canvas的一些信息
      // 照片即将要被保存到的系统文件路径
      savePath: `${
      
      wx.env.USER_DATA_PATH}/watermarkCameraImages`,
      canvasView: {
    
    
        // 当前要绘制的图片
        canvasImg: undefined,
        // 将要被绘制的图片的宽度
        width: undefined,
        // 将要被绘制的图片的高度
        height: undefined,
        // 将要被绘制到图像中的上下两个矩形的高度(px)
        contentHeight: 150,
        // 将要被绘制到图像中的顶部logo的高度(px)
        logoWidth: 400,
      },
      // 当前的经纬度信息
      positionInfo: {
    
    
        mapAddress: "", // 所在村位置
        address: "", // 拍摄地址
        longitude: "", //经度(坐标)
        latitude: "", //纬度(坐标)
        formatLongitude: "", //转变过后的经度(度分秒形式)
        formatLatitude: "", //转变过后的纬度(度分秒形式)
      },
      // 当前要被绘制的图片的信息
      fileUrl: undefined,
      // canvas对象
      context: undefined,
      // 文件管理对象
      systemManager: "",
      // 图片列表
      imgList: [],
      // 是否是正在加载中
      isLoading: true,
      // 网络类型
      networkType: "",
      // 系统信息
      systemInfo: "",
      // 页面滚动值顶部
      scrollTop: 0,

      backTopStyle: {
    
    
        right: "60rpx",
      },
    };
  },
  created() {
    
    
    this.systemManager = uni.getFileSystemManager();
    // 判断需不需要穿件新的文件夹
    this.addDir();
    // 获取所有的文件
    this.getSavedFileList();

    this.getCurrentLocation();
    this.getNetworkType();
    this.getSystemInfo();
  },
  mounted() {
    
    
    // uni.showLoading({
    
    
    //   title: "资源加载中请稍后",
    // });
    this.isLoading = true;
    this.context = uni.createCanvasContext("Canvas", this);
  },
  onPageScroll(e) {
    
    
    this.scrollTop = e.scrollTop;
  },
  methods: {
    
    
    // 获取所有的文件
    getSavedFileList() {
    
    
      var that = this;
      that.imgList = [];
      console.log(`${
      
      wx.env.USER_DATA_PATH}`);
      var res = uni.getFileSystemManager().readdir({
    
    
        dirPath: that.savePath,
        success(res) {
    
    
          console.log("获取文件列表成功aaaaaaa", res);
          res.files.forEach((item, index) => {
    
    
            var timeStr = Number(item.slice(0, -4));
            console.log(timeStr);
            that.imgList.push({
    
    
              path: `${
      
      that.savePath}/${
      
      item}`,
              time: that.$u.timeFormat(timeStr, "yyyy年mm月dd日"),
              detailTime: that.$u.timeFormat(timeStr, "hh时MM分ss秒"),
              url: "/" + item,
            });
          });
          that.formatImgList(that.imgList);
          uni.hideLoading();
          that.isLoading = false;
        },
        fail() {
    
    
          uni.showLoading({
    
    
            title: "图片加载失败请退出后重试",
          });
        },
      });
    },
    // 判断需不需要添加文件夹
    addDir() {
    
    
      var that = this;
      uni.getFileSystemManager().stat({
    
    
        path: that.savePath,
        success: function (res) {
    
    
          console.log(res);
          console.log("已经有这个文件了");
        },
        fail() {
    
    
          console.log("需要传建一个这样的文件夹");
          // 创建一个文件夹用于存储图片
          var res = uni.getFileSystemManager().mkdir({
    
    
            dirPath: that.savePath,
            success(res) {
    
    
              console.log("aaaaaaa", res);
            },
          });
        },
      });
    },
    // 通过微信小程序自带的方法获取到当前的经纬度,然后通过腾讯sdk获取详细位置
    getCurrentLocation() {
    
    
      let that = this; //在uniapp中药定义一下this才能使用
      uni.getLocation({
    
    
        type: "gcj02",
        altitude: true,
        geocode: true,
        isHighAccuracy: true,
        success: function (res) {
    
    
          console.log("微信小程序定位信息", res);
          that.positionInfo.longitude = res.longitude;
          that.positionInfo.latitude = res.latitude;
          that.positionInfo.formatLongitude = that.convertToDMS(
            res.latitude,
            res.longitude
          ).longitude;
          that.positionInfo.formatLatitude = that.convertToDMS(
            res.latitude,
            res.longitude
          ).latitude;
          that.loAcquire(
            that.positionInfo.longitude,
            that.positionInfo.latitude
          );
        },
        fail: function (res) {
    
    
          console.log("定位失败信息res", res);
          uni.showToast({
    
    
            icon: "none",
            duration: 4000,
            title: "请检查手机是否开启定位",
          });
        },
      });
    },
    // 获取网络类型
    getNetworkType() {
    
    
      var that = this;
      uni.getNetworkType({
    
    
        success: function (res) {
    
    
          console.log(res);
          that.networkType = res.networkType;
        },
      });
    },
    // 获取系统信息
    getSystemInfo() {
    
    
      var that = this;
      uni.getSystemInfo({
    
    
        success: function (res) {
    
    
          // console.log(res.appName)
          that.systemInfo = res;
          console.log("当前使用的系统是:", res.platform);
        },
      });
    },
    // 获取当前地址
    loAcquire(longitude, latitude) {
    
    
      let that = this;
      // 腾讯地图Api
      const qqmapsdk = new QQMapWX({
    
    
        key: "5IPBZ-2OA3Q-7UR5Y-4XVMJ-IIEDQ-EDFRN", //这里填写自己申请的key
      });
      console.log({
    
     longitude, latitude });
      qqmapsdk.reverseGeocoder({
    
    
        location: {
    
     longitude, latitude },
        success(response) {
    
    
          uni.hideLoading();
          that.isLoading = false;
          console.log("腾讯sdk获取的定位信息:", response);
          that.positionInfo.mapAddress =
            response.result.address_component.province +
            response.result.address_component.city +
            response.result.address_component.district +
            response.result.address_component.street;
          response.result.address_component.street_number;
          that.positionInfo.address =
            response.result.address_component.city +
            response.result.formatted_addresses.recommend;
        },
        fail() {
    
    
          that.isLoading = false;
          uni.showToast({
    
    
            icon: "none",
            title: "定位失败请检查网络状态",
            duration: 4000,
          });
        },
      });
    },
    // 添加水印
    setImageText(image) {
    
    
      var that = this;
      // 绘制前清空画布
      this.context.clearRect(
        0,
        0,
        this.canvasView.width,
        this.canvasView.height
      );
      // 将图片src放到cancas内,宽高必须为图片大小
      this.context.drawImage(
        this.canvasView.canvasImg,
        0,
        0,
        this.canvasView.width,
        this.canvasView.height,
        this.canvasView.width,
        this.canvasView.height
      );
      // 设置上下两个边框的透明度
      this.context.setGlobalAlpha(0.5);

      this.context.beginPath();
      // 1.绘制顶部的白色背景
      this.context.rect(
        0,
        0,
        this.canvasView.width,
        this.canvasView.contentHeight
      );
      this.context.setFillStyle("white");
      this.context.fill();

      // 2.绘制底部的白色背景
      this.context.rect(
        0,
        this.canvasView.height - this.canvasView.contentHeight,
        this.canvasView.width,
        this.canvasView.contentHeight
      );
      // this.context.setFillStyle("white");
      this.context.fill("white");
      // 设置文字的透明度
      this.context.setGlobalAlpha(1);
      // 3.绘制顶部的文字
      this.context.setFontSize(26);
      this.context.setTextAlign("left");
      this.context.setFillStyle("black");
      this.context.fillText("拍摄人:李帅豪", 50, 60);
      this.context.fillText(
        "拍摄时间:" + this.$u.timeFormat(new Date(), "yyyy-mm-dd hh:MM:ss"),
        50,
        110
      );

      // 4.绘制顶部的图片
      that.context.drawImage(
        "/static/image/lshlogo.png",
        that.canvasView.width - that.canvasView.logoWidth - 10,
        20,
        that.canvasView.logoWidth,
        that.canvasView.contentHeight - 40
      );
      // 5.绘制底部的文字
      // 5.1绘制定位以及网络状态
      this.context.setFontSize(33);
      this.context.setFillStyle("black");
      this.context.fillText(
        "定位:" + this.positionInfo.formatLongitude,
        50,
        this.canvasView.height - 100
      );
      this.context.fillText(
        this.positionInfo.formatLatitude,
        this.canvasView.width - 450,
        this.canvasView.height - 100
      );
      var systemimg = "";
      var networkimg = "";
      if (that.systemInfo.platform == "android") {
    
    
        systemimg = "anzhuo";
      } else if (that.systemInfo.platform == "ios") {
    
    
        systemimg = "ios";
      } else {
    
    
        systemimg = "anzhuo";
      }
      if (that.networkType == "unknown" || that.networkType == "none") {
    
    
        networkimg = "network1";
      } else if (that.networkType == "none") {
    
    
        networkimg = "flyMode";
      } else {
    
    
        networkimg = "network2";
      }
      console.log("systemimg,networkimg", systemimg, networkimg);
      that.context.drawImage(
        "/static/image/" + systemimg + ".png",
        this.canvasView.width - 150,
        this.canvasView.height - 140,
        50,
        50
      );
      that.context.drawImage(
        "/static/image/" + networkimg + ".png",
        this.canvasView.width - 90,
        this.canvasView.height - 140,
        50,
        50
      );
      // 5.2绘制所在村位置
      // 5.3绘制拍摄地址
      this.context.setFontSize(33);
      this.context.setFillStyle("black");
      this.context.fillText(
        "拍摄地址:北京市xxxxxx",
        50,
        this.canvasView.height - 50,
        this.canvasView.width - 100
      );

      this.drawSave();
    },
    // 绘制图片并保存至相册
    drawSave() {
    
    
      var that = this;
      // 一定要加上一个定时器否则进入到页面第一次可能会无法正常拍照,后几次才正常
      setTimeout(() => {
    
    
        // 本次回画完重开开始绘画,并且在绘画完毕之后再保存图片,不然页面可能会出现白屏等情况
        this.context.draw(false, () => {
    
    
          console.log(
            "!!!!!!!!!1开始绘画",
            this.canvasView.width,
            this.canvasView.height
          );

          uni.canvasToTempFilePath(
            {
    
    
              canvasId: "Canvas",
              fileType: "jpg",
              width: this.canvasView.width,
              height: this.canvasView.height,
              destWidth: this.canvasView.width,
              destHeight: this.canvasView.height,
              success: async (path) => {
    
    
                console.log("path", path);

                let imageInfo = await that.getImageInfo({
    
    
                  imgSrc: path.tempFilePath,
                });
                console.log("==========", imageInfo);
                that.fileUrl = imageInfo.path;
                // var respath = uni
                //   .getFileSystemManager()
                //   .saveFileSync(imageInfo.path);
                // console.log("拥挤存储的路径saveFileSync", respath);

                // 压缩图片
                uni.compressImage({
    
    
                  src: imageInfo.path,
                  quality: 30,
                  success: (res) => {
    
    
                    console.log(res.tempFilePath);

                    var fileName = Date.now() + ".jpg";
                    var bufferData = that.systemManager.readFileSync(
                      res.tempFilePath,
                      "base64"
                    );
                    var a1 = that.systemManager.writeFileSync(
                      `${
      
      that.savePath}/${
      
      fileName}`,
                      bufferData,
                      "base64"
                    );
                    console.log(a1);
                    uni.saveImageToPhotosAlbum({
    
    
                      filePath: res.tempFilePath,
                      complete: (res) => {
    
    
                        console.log(res);
                      },
                    });

                    // 有性能问题
                    // that.getSavedFileList();
                    // 优化方向:不重新获取列表
                    that.addImgToList({
    
     fileName });
                  },
                });
              },
            },
            that
          );
        });
      }, 1000);
    },
    // 将当前图片添加至图片列表
    addImgToList({
     
      fileName }) {
    
    
      console.log("@@@@@@", "addImgToList");
      var that = this;
      var path = `${
      
      that.savePath}/${
      
      fileName}`;
      var time = that.$u.timeFormat(
        Number(fileName.slice(0, -4)),
        "yyyy年mm月dd日"
      );

      var detailTime = that.$u.timeFormat(
        Number(fileName.slice(0, -4)),
        "hh时MM分ss秒"
      );
      var url = "/" + fileName;
      var obj = {
    
    
        path,
        time,
        url,
        detailTime,
      };

      if (that.imgList.length > 0) {
    
    
        // 当前需要被添加的数组
        var currentArr = [];
        // 当前需要被添加的数组的索引
        var currentArrIndex = "";
        console.log(obj);
        that.imgList.forEach((item, index) => {
    
    
          item.forEach((item2, index2) => {
    
    
            if (item2.time == obj.time) {
    
    
              currentArr = item;
              currentArrIndex = index;
            }
          });
        });
        if (currentArr.length > 0) {
    
    
          currentArr.push(obj);
          console.log("currentArr", currentArr);
          that.$set(that.imgList, currentArrIndex, currentArr);
        } else {
    
    
          that.imgList.push([obj]);
        }
        console.log("可能会出问题的地方", currentArr, currentArrIndex);
        console.log("currentArr", currentArr);
      } else {
    
    
        that.imgList.push([obj]);
      }
      uni.hideLoading();
      that.isLoading = false;
    },
    //检查相机权限
    TakeAPicture() {
    
    
      var that = this;
      uni.authorize({
    
    
        scope: "scope.camera",
        success() {
    
    
          console.log("scope.camera用户授权成功小程序");

          uni.getSetting({
    
    
            success(res) {
    
    
              console.log("authSetting", res);
              if (res.authSetting["scope.camera"] == true) {
    
    
                console.log("111当前用户已经个授权过了scope.camera");
                that.openCamera();
              } else {
    
    
                console.log("22当前用户没用授权过scope.camera");
                uni.openSetting({
    
    
                  success(res) {
    
    
                    console.log("openSetting", res);
                    if (res.authSetting["scope.camera"] == true) {
    
    
                      console.log("openSetting打开设置成功打开了摄像头权限");
                      that.openCamera();
                    } else {
    
    
                      uni.showToast({
    
    
                        title: "未获取到相机权限",
                      });
                    }
                  },
                });
              }
            },
          });
        },
        fail() {
    
    
          console.log("拒绝");
          uni.showToast({
    
    
            icon: "none",
            title: "您已拒绝相机权限,暂无法使用水印相机",
            duration: 4000,
          });
        },
      });
    },
    //获取图片信息
    async getImageInfo({
     
      imgSrc }) {
    
    
      return new Promise((resolve, errs) => {
    
    
        uni.getImageInfo({
    
    
          src: imgSrc,
          success: function (image) {
    
    
            resolve(image);
          },
          fail(err) {
    
    
            errs(err);
          },
        });
      });
    },
    //打开相机
    async openCamera() {
    
    
      var that = this;
      // 一定要使用chooseMedia,如果使用chooseImage那么部分IOS手机就没法正常使用了
      uni.chooseMedia({
    
    
        count: 1,
        mediaType: ["image"],
        sourceType: ["camera"],
        camera: "back",
        success: async (res) => {
    
    
          uni.showLoading({
    
    
            title: "正在加载图片资源",
          });
          that.isLoading = true;
          console.log(res);
          let imgInfo = await that.getImageInfo({
    
    
            imgSrc: res.tempFiles[0].tempFilePath,
          });
          console.log("这一步可以获取到真正的base图片不过还没有转化");
          // console.log(
          //   `data:image/jpg;base64,${uni
          //     .getFileSystemManager()
          //     .readFileSync(res.tempFilePaths[0], "base64")}`
          // );
          console.log("==========imgInfo", imgInfo);
          that.canvasView.canvasImg = imgInfo.path;
          that.canvasView.width = imgInfo.width;
          that.canvasView.height = imgInfo.height;
          console.log(this.canvasView);
          console.log(
            "!!!!!!!!!!当前图片信息canvasView",
            that.canvasView
          );
          that.setImageText();
        },
        fail: function (res) {
    
    
          console.log("选择图片失败", res);
        },
      });
    },
    // 删除当前的图片(测试节点使用的)
    removeCurrentImg(item) {
    
    
      // 等会儿在处理这个问题,这个需要二维为数组中寻找并且删除元素
      var that = this;
      // uni.getFileSystemManager().removeSavedFile({
    
    
      //   filePath: item.path,
      //   success(res) {
    
    
      //     console.log("单个删除成功", res);
      //     that.getSavedFileList();
      //   },
      // });

      this.systemManager.unlink({
    
    
        filePath: this.savePath + item.url,
        success(res) {
    
    
          console.log("单个删除成功", res);
          that.getSavedFileList();
        },
        fail(res) {
    
    
          console.error(res);
        },
      });
    },
    // 删除所有的图片(这种方式不支持,不发对非空文件夹直接删除)
    deleteImg() {
    
    },
    // 预览图片
    // 第一个参数是当前项的图片信息,
    // 第二个参数为当前图片的索引
    // 第三个参数为当前图片所在时间组的索引
    previewImage(item, index2, index1) {
    
    
      console.log("图片预览", item, index2, index1);
      var that = this;
      // 预览图片
      uni.previewImage({
    
    
        current: index2,
        urls: that.imgList[index1].map((item) => item.path),
      });
    },
    // 将获取到的图片按照日期进行格式化
    formatImgList(arr) {
    
    
      // this.imgList = Object.values(
      //   arr.reduce((obj, item) => {
    
    
      //     obj[item.time] = obj[item.time] || [item];
      //     obj[item.time].push(item);
      //     return obj;
      //   }, {})
      // ).filter((item) => item.length > 1);
      this.imgList = arr.reduce((prev, item) => {
    
    
        const index = prev.findIndex((value) => {
    
    
          return value.length > 0 && value[0].time === item.time;
        });

        if (index !== -1) {
    
    
          prev[index].push(item);
        } else {
    
    
          prev.push([item]);
        }

        return prev;
      }, []);
      console.log("formatImgList", this.imgList);
    },
    // 将经纬度转化为度分秒
    convertToDMS(lat, lng) {
    
    
      let latDirection = lat >= 0 ? "N" : "S";
      let lngDirection = lng >= 0 ? "E" : "W";

      lat = Math.abs(lat);
      lng = Math.abs(lng);

      let latDegrees = Math.floor(lat);
      let latMinutes = Math.floor((lat - latDegrees) * 60);
      let latSeconds = ((lat - latDegrees - latMinutes / 60) * 3600).toFixed(4);

      let lngDegrees = Math.floor(lng);
      let lngMinutes = Math.floor((lng - lngDegrees) * 60);
      let lngSeconds = ((lng - lngDegrees - lngMinutes / 60) * 3600).toFixed(4);

      return {
    
    
        latitude: `${
      
      latDirection}:${
      
      latDegrees}°${
      
      latMinutes}'${
      
      latSeconds}"`,
        longitude: `${
      
      lngDirection}:${
      
      lngDegrees}°${
      
      lngMinutes}'${
      
      lngSeconds}"`,
      };
    },
  },
};
</script>

<style lang="scss" scoped>
.pages {
    
    
  overflow: scroll;
}
.imgContainer {
    
    
  .imgDayItem {
    
    
    padding: 30rpx 30rpx 0;
    .imgTime {
    
    
      padding: 20rpx 0 20rpx 0;
      margin-bottom: 20rpx;
      background-color: rgb(249, 249, 249);
    }
    .imgGroup {
    
    
      // border: 2rpx solid red;
      display: flex;
      align-items: center;
      justify-content: flex-start;
      flex-wrap: wrap;

      .itemImg {
    
    
        width: 30%;
        border-radius: 25rpx;
        // border: 1rpx solid red;
        position: relative;
        margin-right: 35rpx;
        margin-bottom: 35rpx;
        &:nth-child(3n) {
    
    
          margin-right: 0rpx;
        }
        image {
    
    
          width: 100%;
          height: 200rpx;
          display: block;
        }
        .imgName {
    
    
          width: 100%;
          text-align: center;
          position: absolute;
          left: 50%;
          transform: translateX(-50%);
          bottom: 0;
        }
        .removeImg {
    
    
          color: white;
          border-radius: 50%;
          background-color: red;
          width: 40rpx;
          height: 40rpx;
          line-height: 40rpx;
          text-align: center;
          position: absolute;
          top: -24rpx;
          right: -20rpx;
        }
      }
    }
  }
}

.cameraBtn {
    
    
  position: fixed;
  right: 40rpx;
  bottom: 50rpx;
  width: 120rpx;
  height: 120rpx;
  border-radius: 50%;
  z-index: 30;
}
#mycanvas {
    
    
  position: fixed;
  left: 9999rpx;
  // opacity: 0;
  // visibility: hidden;
  // opacity: 0;
}
</style>

猜你喜欢

转载自blog.csdn.net/ksjdbdh/article/details/130669206
今日推荐