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

news2024/11/28 8:45:44

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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【K8s】Service详解

文章目录 一、Service介绍1、认识Service2、kube-proxy的三种工作模式3、Service的类型 二、Service的使用1、实验数据准备2、Service类型为ClusterIP补充&#xff1a;Endpoints补充&#xff1a;负载分发策略 3、Service类型为HeadLiness3、Service类型为NodePort4、Service的类…

Ovito渲染技巧之体系边界识别

关注 M r . m a t e r i a l , \color{Violet} \rm Mr.material\ , Mr.material , 更 \color{red}{更} 更 多 \color{blue}{多} 多 精 \color{orange}{精} 精 彩 \color{green}{彩} 彩&#xff01; 主要专栏内容包括&#xff1a; †《LAMMPS小技巧》&#xff1a; ‾ \textbf…

性能、性能还是性能---下一代Android性能框架分析

性能优化的重要性和难度毋庸置疑&#xff0c;事实上&#xff0c;性能优化也是一个永无止境的游戏&#xff0c;总会发现有一些东西需要优化。但是不可避免的是&#xff0c;这也是一个边际效益递减的事情&#xff0c;项目或应用获得的收益在一定程度上也会逐渐降低。What’s new …

ReentrantLock 原理

目录 ReentrantLock 概述 ReentrantLock 的原理 什么是 AQS ? 获取锁资源(以⾮公平锁为例) tryAcquire addWaiter acquireQueued 释放锁资源 ⾮公平锁体现在哪⾥&#xff1f; 调试代码 总结 ReentrantLock 概述 ReentrantLock是Lock接⼝的默认实现&#xff0c;是⼀…

【Linux】-关于Linux的指令(下)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树 ❤️‍&#x1fa79;作者宣言&#xff1a;认真写好每一篇博客 &#x1f4a8;作者gitee:gitee &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 文章目录 前言一、时间相关的指令二、cal指令三、find -name指…

Centos7 经典模式安装GBase 8s 图文教程

Centos7安装GBase 8s 图文教程 前言1.1 硬件要求1.2 系统要求1.3 虚拟 PC 软件1.4 安装及配置数据库服务器1.4.1 创建 gbasedbt 组和用户1.4.2 创建 GBase 8s 数据库安装目录1.4.3 上传并解压安装包1.4.4 执行安装 参考文献 前言 本篇博文分享如何在Centos7 x86架构的系统中安…

第2章-Selenium-API操作

目标&#xff1a; 1. 熟练应用八种元素定位方式 2. 掌握对元素和浏览器的操作方法 3. 掌握键盘鼠标的操作 4. 掌握元素等待的操作 5. 掌握下拉选择框、 警告框和滚动条的操作 6. 掌握如何切换frame框架和多窗口 7. 掌握如何实现窗口截图 1.元素定位 1. 掌握id、 name、 cla…

【leetcode】622 二叉树的最大宽度

题目描述 给你一棵二叉树的根节点 root &#xff0c;返回树的 最大宽度 。 树的 最大宽度 是所有层中最大的 宽度 。 每一层的 宽度 被定义为该层最左和最右的非空节点&#xff08;即&#xff0c;两个端点&#xff09;之间的长度。将这个二叉树视作与满二叉树结构相同&#…

MATLAB 之 M 文件和程序控制结构(顺序、选择、循环)

文章目录 一、M 文件1. M 文件的建立与打开1.1 建立新的 M 文件1.2 打开已有的 M 文件 2. M 文件的分类 二、 程序控制之顺序结构1. 数据的输入2. 数据的输出3. 程序的暂停 三、程序控制之选择结构1. if 语句2. switch 语句3. try 语句 四、程序控制之循环结构1. for 语句2. wh…

畸变像差校正技术(畸变相位补偿)发展现状及其仿真实验研究-技术汇总-Matlab代码

▒▒本文目录▒▒ 一、引言二、物理方法2.1 基于二次曝光法的畸变像差补偿仿真实验验证 三、数值方法3.1 基于主成分分析法的畸变像差补偿仿真实验验证3.2 基于标准多项式拟合法的畸变像差校正仿真实验验证3.3 基于最小二乘拟合法的畸变像差校正仿真实验验证3.4 基于泽尼克多项…

Simulink 自动代码生成电机控制——永磁同步电机参数获取

目录 前言 极对数测量 电阻测量&#xff08;Rs&#xff09; 电感测量&#xff08;Ld和Lq&#xff09; 磁链测量 总结 前言 在建模之前或者需要更换一个新电机&#xff0c;需要获取目标电机的电气参数&#xff0c;如果参数不对&#xff0c;对于电流环参数的整定&#xff0…

2023/05/08~14 刷题记录

A - Plus and Multiply 题意&#xff1a; 题解&#xff1a; 题目说可以将集合里面的数字 *a 或者 b 操作&#xff0c;并将新的值放进集合中&#xff0c;首先想到 dfs 暴力求解&#xff0c;但是太暴力了&#xff0c;直接 时间超限 。通过观察我们可以知道&#xff0c;要求 n 是否…

前端模块化

什么是模块化 事实上模块化开发最终目的是将程序划分成一个个小的结构在这个结构中编写属于自己的逻辑代码&#xff0c;有自己的作用域&#xff0c;不会影响到其他的结构这个结构可以将自己希望暴露的变量、函数、对象等导出给其他结构使用。可以通过某种方式&#xff0c;导入…

电脑软件:国内最好用解压缩软件 7-Zip 新版本发布

5 月 9 日消息&#xff0c;7-Zip 是一款拥有极高压缩比的的开源压缩软件&#xff0c;支持 LZMA2 等 7 种开源算法&#xff0c;以及支持较广泛的压缩格式 .7z&#xff0c;体积不大&#xff08;1.5MB&#xff09;、功能完善&#xff0c;除了默认 UI 不符合国内审美外几乎没什么可…

Oracle数据库安装教程,并实现公网远程连接【内网穿透】

✨ 目录 &#x1f388; 前言&#x1f388; 1. 数据库搭建&#x1f388; 2. 内网穿透&#x1f388; 2.1 安装cpolar内网穿透&#x1f388; 2.2 创建隧道映射 &#x1f388; 3. 公网远程访问&#x1f388; 4. 配置固定TCP端口地址&#x1f388; 4.1 保留一个固定的公网TCP端口地址…

Java经典笔试题—day08

Java经典笔试题—day08 &#x1f50e;选择题&#x1f50e;编程题&#x1f95d;两种排序方法&#x1f95d;求最小公倍数 &#x1f50e;结尾 &#x1f50e;选择题 (1)下列选项中关于Java中super关键字的说法正确的是&#xff08;&#xff09; A.super关键字是在子类对象内部指代…

JAVA JDK下载安装手册

JDK的介绍与安装 JDK简介 JDK是 Java 语言的软件开发工具包&#xff0c;主要用于移动设备、嵌入式设备上的java应用程序。编写 Java 程序必须使用 JDK&#xff0c;它提供了编译和运行 Java 程序的环境。是整个java开发的核心。 准备JDK 本次使用的是JDK1.8 如下所示: 下载完…

记两道AES-CBC题

文章目录 知识导入&#xff08;AES-CBC模式&#xff09;题一(buu [ACTF新生赛2020]crypto-aes 1)题目描述&#xff1a;题目分析&#xff1a;知识导入os.urandom(n)函数比特&#xff0c;字节&#xff0c;二进制数之间的关系AES.new(key,AES.MODE_CBC,iv) 题二(crack AES-CBC IV)…

小黑子—Java从入门到入土过程:第九章-IO流

Java零基础入门9.0 Java系列第九章- IO流1. 初识IO流2. IO流的体系2.1 字节流2.1.1 FileOutputStream 字符串输出流2.1.1 - I 字符串输出流的细节2.1.1 - II FileOutputStream写数据的3种方式2.1.1 -III FileOutputStream写数据的两个小问题 2.1.2 FileInputStream 字符串输入流…

点线面产生局部坐标系以及计算到世界坐标系的旋转矩阵

欢迎关注更多精彩 问题描述 给定点O&#xff0c;线段AB&#xff0c;平面OP&#xff0c;求以OP法向为某一轴&#xff0c;以AB在OP上的投影为另一轴&#xff0c;O为原点的局部坐标系。要求给出X,Y,Z轴的单位向量&#xff0c;以及原点O. 求出转换到世界坐标系的旋转矩阵RT。 如…