【HTML】基于jsQR实现的HTML单页面扫码功能

前言

最近做了一个扫码签到的功能涉及到获取浏览器摄像头并扫码识别的功能。

选择jsQR的原因:

html5-qrcode:使用简单,识别率低,二维码小不可解析

@zxing/library: 识别率优于html5-qrcode,部分安卓模糊无法使用

jsQR:轻量小巧实用简单,识别率高,小型二维码也可解析,可以自动对焦

实现效果

点击扫码功能进入扫码页面

代码实现

完整代码如下,复制即可运行。

<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
  name="viewport"
  content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<!-- 引入样式 自己的服务器资源,可自行替换CDN -->
<link rel="stylesheet" href="https://s3.gendome.net/shopify/css/element.css" />
<!-- 引入组件库 -->
<script src="https://s3.gendome.net/shopify/js/vue.js"></script>
<!-- 引入组件库 -->
<script src="https://s3.gendome.net/shopify/js/element.js"></script>
<script src="https://s3.gendome.net/shopify/js/axios.min.js"></script>
<script src="https://s3.gendome.net/activity/js/jsQR.js"></script>
<title></title>
<style>
  body {
    margin: 0;
    position: relative;
  }

  .cz-header {
    width: 100%;
    height: calc(100vw * 520 / 390);
    /* background-image: url("./images/header.png"); */
    background-repeat: no-repeat;
    background-position: center center;
    background-size: 100% 100%;
    box-sizing: border-box;
    padding-top: calc(100vw * 130 / 390);
  }
  .cz-header-title {
    font-size: calc(100vw * 30 / 390);
    font-family: Poppins, Poppins;
    font-weight: 600;
    color: #ffffff;
    line-height: calc(100vw * 30 / 390);
    text-align: center;
    padding: 0 calc(100vw * 39 / 390);
  }
  .cz-nav {
    width: 100%;
    height: calc(100vw * 50 / 390);
    text-align: center;
    background-color: #181818;
    overflow: hidden;
  }
  .cz-nav-box {
    overflow-y: scroll;
    display: flex;
    height: 100%;
  }
  .cz-nav-item {
    /* display: inline-block; */
    padding: 0 calc(100vw * 20 / 390);
    font-size: calc(100vw * 12 / 390);
    font-family: Poppins, Poppins;
    font-weight: 600;
    color: #ffffff;
    white-space: nowrap;
    height: 100%;
    line-height: calc(100vw * 50 / 390);
  }
  .cz-nav-box::-webkit-scrollbar {
    display: none;
  }
  .cz-nav-item-act {
    background: linear-gradient(180deg, #0b95ec 0%, #0962cb 100%);
  }
  .cz-b4 {
    width: 100%;
    box-sizing: border-box;
    padding: calc(100vw * 40 / 390) calc(100vw * 20 / 390);
  }
  .cz-b4-title {
    font-size: calc(100vw * 30 / 390);
    font-family: Poppins, Poppins;
    font-weight: 600;
    color: #000000;
    line-height: calc(100vw * 35 / 390);
  }
  .cz-b4-subTxt {
    font-size: calc(100vw * 12 / 390);
    font-family: Poppins, Poppins;
    font-weight: 500;
    color: #212223;
    line-height: calc(100vw * 15 / 390);
    margin-top: calc(100vw * 9 / 390);
    margin-bottom: calc(100vw * 30 / 390);
  }
  .cz-input .el-input__inner {
    width: 100%;
    height: calc(100vw * 60 / 390);
    border-radius: calc(100vw * 9 / 390);
    font-size: calc(100vw * 16 / 390);
  }
  .cz-input .el-form-item__label {
    height: calc(100vw * 60 / 390);
    font-size: calc(100vw * 20 / 390);
    font-weight: bold;
    line-height: calc(100vw * 60 / 390);
  }
  .cz-form-btn {
    height: calc(100vw * 60 / 390);
    background: linear-gradient(180deg, #0b95ec 0%, #0962cb 100%);
    border-radius: calc(100vw * 9 / 390);
    font-size: calc(100vw * 20 / 390);
    font-family: Poppins, Poppins;
    font-weight: 500;
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: calc(100vw * 40 / 390);
  }
  .cz-content {
    width: 100%;
    /* height: calc(100vw * 100 / 390); */
    box-sizing: border-box;
    border: 1px solid #dcdfe6;
    border-radius: calc(100vw * 9 / 390);
    padding: calc(100vw * 20 / 390);
    margin-top: calc(100vw * 40 / 390);
  }
  .cz-content-item {
    margin-bottom: calc(100vw * 10 / 390);
  }
  .cz-mask {
    width: 100vw;
    height: 100vh;
    background: white;
    position: fixed;
    left: 0;
    top: 0;
  }
  .el-icon-close {
    position: absolute;
    top: calc(100vw * 30 / 390);
    right: calc(100vw * 30 / 390);
    z-index: 11;
    color: white;
  }
  .canvasBox {
    width: 100vw;
    height: 100vh;
    position: relative;

    background-image: linear-gradient(
        0deg,
        transparent 24%,
        rgba(32, 255, 77, 0.1) 25%,
        rgba(32, 255, 77, 0.1) 26%,
        transparent 27%,
        transparent 74%,
        rgba(32, 255, 77, 0.1) 75%,
        rgba(32, 255, 77, 0.1) 76%,
        transparent 77%,
        transparent
      ),
      linear-gradient(
        90deg,
        transparent 24%,
        rgba(32, 255, 77, 0.1) 25%,
        rgba(32, 255, 77, 0.1) 26%,
        transparent 27%,
        transparent 74%,
        rgba(32, 255, 77, 0.1) 75%,
        rgba(32, 255, 77, 0.1) 76%,
        transparent 77%,
        transparent
      );
    background-size: 3rem 3rem;
    background-position: -1rem -1rem;
    z-index: 10;
    background-color: #1110;
  }

  .box {
    width: 200px;
    height: 200px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    overflow: hidden;
    border: 0.1rem solid rgba(0, 255, 51, 0.2);
    z-index: 11;
  }

  .line {
    height: calc(100% - 2px);
    width: 100%;
    background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
    border-bottom: 3px solid #00ff33;
    transform: translateY(-100%);
    animation: radar-beam 2s infinite alternate;
    animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
    animation-delay: 1.4s;
  }

  .box:after,
  .box:before,
  .angle:after,
  .angle:before {
    content: "";
    display: block;
    position: absolute;
    width: 3vw;
    height: 3vw;
    z-index: 12;
    border: 0.2rem solid transparent;
  }

  .box:after,
  .box:before {
    top: 0;
    border-top-color: #00ff33;
  }

  .angle:after,
  .angle:before {
    bottom: 0;
    border-bottom-color: #00ff33;
  }

  .box:before,
  .angle:before {
    left: 0;
    border-left-color: #00ff33;
  }

  .box:after,
  .angle:after {
    right: 0;
    border-right-color: #00ff33;
  }

  @keyframes radar-beam {
    0% {
      transform: translateY(-100%);
    }

    100% {
      transform: translateY(0);
    }
  }

  .msg {
    text-align: center;
    padding: 20rpx 0;
  }

  .box2 {
    width: 300px;
    height: 200px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 20;
  }

  .track {
    position: absolute;
    bottom: -100px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 20;
    color: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .mask {
    position: absolute;
    z-index: 10;
    background-color: rgba(0, 0, 0, 0.55);
  }

  .mask1 {
    top: 0;
    left: 0;
    right: 0;
  }

  .mask2 {
    right: 0;
  }

  .mask3 {
    right: 0;
    left: 0;
    bottom: 0;
  }

  .mask4 {
    left: 0;
  }

  .error {
    color: #fff;
    padding: 40rpx;
    font-size: 24rpx;
    background-color: #333333;
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 550rpx;
    border-radius: 20rpx;
  }

  .error .on1 {
    font-size: 30rpx;
  }
</style>
<div id="app">
  <div class="phone">
    <div class="cz-b4">
      <div class="cz-b4-title">CSDN <br />Clock in!</div>
      <div class="cz-b4-subTxt">Persist in creation!</div>

      <div v-on:click="startScan" class="cz-form-btn" v-loading="loading">
        扫码
      </div>
    </div>
  </div>

  <div class="cz-mask" v-if="scanVisible">
    <div class="canvasBox">
      <template v-if="isUse">
        <div class="box">
          <div class="line"></div>
          <div class="angle"></div>
        </div>
        <div class="box2" v-if="isUseTorch">
          <div class="track" @click="openTrack">
            <svg
              t="1653920715959"
              class="icon"
              divBox="0 0 1024 1024"
              version="1.1"
              xmlns="http://www.w3.org/2000/svg"
              p-id="1351"
              width="32"
              height="32"
            >
              <path
                d="M651.353043 550.479503H378.752795L240.862609 364.315031c-3.688944-4.897391-5.660621-10.876025-5.660621-17.045466v-60.040745c0-15.773416 12.847702-28.621118 28.621118-28.621118h502.459627c15.773416 0 28.621118 12.847702 28.621118 28.621118v59.977143c0 6.105839-1.971677 12.084472-5.660621 17.045466l-137.890187 186.228074zM378.752795 598.308571v398.024348c0 15.328199 12.402484 27.667081 27.667081 27.667081h217.266087c15.328199 0 27.667081-12.402484 27.66708-27.667081V598.308571H378.752795z m136.300124 176.942112c-14.564969 0-26.331429-11.76646-26.331428-26.331428v-81.283975c0-14.564969 11.76646-26.331429 26.331428-26.331429 14.564969 0 26.331429 11.76646 26.331429 26.331429v81.283975c0 14.564969-11.76646 26.331429-26.331429 26.331428zM512 222.608696c-17.554286 0-31.801242-14.246957-31.801242-31.801243V31.801242c0-17.554286 14.246957-31.801242 31.801242-31.801242s31.801242 14.246957 31.801242 31.801242v159.006211c0 17.554286-14.246957 31.801242-31.801242 31.801243zM280.932174 205.881242c-9.47677 0-18.889938-4.197764-25.122981-12.275279L158.242981 67.991056a31.864845 31.864845 0 0 1 5.597019-44.648944 31.864845 31.864845 0 0 1 44.648944 5.597018l97.502609 125.551305a31.864845 31.864845 0 0 1-5.597019 44.648944c-5.787826 4.579379-12.656894 6.741863-19.46236 6.741863zM723.987081 205.881242c-6.805466 0-13.674534-2.162484-19.462361-6.678261a31.794882 31.794882 0 0 1-5.597018-44.648944l97.566211-125.551304a31.794882 31.794882 0 0 1 44.648944-5.597019 31.794882 31.794882 0 0 1 5.597019 44.648944l-97.566211 125.551305c-6.360248 8.077516-15.709814 12.27528-25.186584 12.275279z"
                fill="#ffffff"
                p-id="1352"
              ></path>
            </svg>
            {{ trackStatus ? '关闭闪光灯' : '打开闪光灯' }}
          </div>
        </div>

        <div class="mask1 mask" :style="'height:' + maskHeight + 'px;'"></div>
        <div
          class="mask2 mask"
          :style="'width:' + maskWidth + 'px;top:' + maskHeight + 'px;height:' + canvasHeight + 'px'"
        ></div>
        <div class="mask3 mask" :style="'height:' + maskHeight + 'px;'"></div>
        <div
          class="mask4 mask"
          :style="'width:' + maskWidth + 'px;top:' + maskHeight + 'px;height:' + canvasHeight + 'px'"
        ></div>
      </template>
      <template v-else>
        <slot name="error">
          <div class="error">
            <div class="on1">相机权限被拒绝,请尝试如下操作:</div>
            <div>· 刷新页面后重试;</div>
            <div>· 在系统中检测当前App或浏览器的相机权限是否被禁用;</div>
            <div>· 如果依然不能体验,建议在微信中打开链接;</div>
          </div>
        </slot>
      </template>
    </div>
    <i class="el-icon-close" v-on:click="stopScan"></i>
  </div>
</div>

<script>
  new Vue({
    el: "#app",
    data() {
      return {
        continue: false, // false 监听一次   true 持续监听,
        exact: "environment", // environment 后摄像头  user 前摄像头,
        size: "whole", // whole 全屏  balf 半屏,
        definition: false, // fasle 正常  true 高清

        windowWidth: 0,
        windowHeight: 0,
        video: null,
        canvas2d: null,
        canvas2d2: null,
        canvasWidth: 200,
        canvasHeight: 200,
        maskWidth: 0,
        maskHeight: 0,
        inter: 0,

        track: null,
        isUseTorch: false,
        trackStatus: false,

        isParse: false,
        isUse: true,

        scanVisible: false,
        loading: false,
      };
    },
    computed: {},
    mounted() {
      if (origin.indexOf("https") === -1)
        throw "请在 https 环境中使用摄像头组件。";

      this.windowWidth =
        document.documentElement.clientWidth || document.body.clientWidth;
      this.windowHeight =
        document.documentElement.clientHeight || document.body.clientHeight;
      this.windowHeight =
        this.size === "whole" ? this.windowHeight : this.windowHeight / 2;
      this.isParse = true;
    },
    destroyed() {
      this.closeCamera();
    },
    methods: {
      // 成功回调
      success(data) {
        this.scanVisible = false;
        this.closeCamera();
        this.$alert(data, "扫码结果", {
          confirmButtonText: "确定",
          callback: (action) => {
            //do things...
          },
        });
      },
      // 失败回调
      error() {
        //do things...
      },
      // 打开扫码
      startScan() {
        this.scanVisible = true;
        this.$nextTick(() => {
          this.createMsk();
          this.openScan();
        });
      },
      //关闭扫码
      stopScan() {
        this.scanVisible = false;
        this.closeCamera();
      },
      openScan() {
        const width = this.transtion(this.windowHeight);
        const height = this.transtion(this.windowWidth);
        const videoParam = {
          audio: false,
          video: {
            facingMode: { exact: this.exact },
            width,
            height,
          },
        };
        navigator.mediaDevices
          .getUserMedia(videoParam)
          .then((stream) => {
            this.video = document.createElement("video");
            this.video.width = this.windowWidth;
            this.video.height = this.windowHeight;

            const canvas = document.createElement("canvas");
            canvas.id = "canvas";
            canvas.width = this.transtion(this.canvasWidth);
            canvas.height = this.transtion(this.canvasHeight);
            canvas.style = "display:none;";
            //canvas.style = 'position: fixed;top: 0;z-index: 999;left:0'
            this.canvas2d = canvas.getContext("2d");

            // 设置当前宽高 满屏
            const canvasBox = document.querySelector(".canvasBox");
            canvasBox.append(this.video);
            canvasBox.append(canvas);
            canvasBox.style = `width:${this.windowWidth}px;height:${this.windowHeight}px;`;

            // 创建第二个canvas
            const canvas2 = document.createElement("canvas");
            canvas2.id = "canvas2";
            canvas2.width = this.canvasWidth;
            canvas2.height = this.canvasHeight;
            canvas2.style =
              "position: absolute;top: 50%;left: 50%;z-index: 20;transform: translate(-50%, -50%);";
            this.canvas2d2 = canvas2.getContext("2d");
            canvasBox.append(canvas2);

            this.video.srcObject = stream;
            this.video.setAttribute("playsinline", true);
            this.video.play();
            this.tick();

            this.track = stream.getVideoTracks()[0];
            setTimeout(() => {
              this.isUseTorch = this.track.getCapabilities().torch || null;
            }, 500);
          })
          .catch((err) => {
            this.isUse = false;
            // this.$emit("error", err);
            this.error(err);
          });
      },

      closeCamera() {
        this.isParse = false;
        if (this.video && this.video.srcObject) {
          this.video.srcObject.getTracks().forEach((track) => {
            track.stop();
          });
        }
      },

      tick() {
        if (!this.isParse) return;
        if (this.video.readyState === this.video.HAVE_ENOUGH_DATA) {
          this.canvas2d.drawImage(
            this.video,
            this.transtion(this.maskWidth),
            this.transtion(this.maskHeight),
            this.transtion(200),
            this.transtion(200),
            0,
            0,
            this.transtion(this.canvasWidth),
            this.transtion(this.canvasHeight)
          );

          const imageData = this.canvas2d.getImageData(
            0,
            0,
            this.transtion(this.canvasWidth),
            this.transtion(this.canvasHeight)
          );

          const code = jsQR(imageData.data, imageData.width, imageData.height, {
            inversionAttempts: "dontInvert",
          });

          this.canvas2d2.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
          if (code) {
            this.drawLine(
              code.location.topLeftCorner,
              code.location.topRightCorner
            );
            this.drawLine(
              code.location.topRightCorner,
              code.location.bottomRightCorner
            );
            this.drawLine(
              code.location.bottomRightCorner,
              code.location.bottomLeftCorner
            );
            this.drawLine(
              code.location.bottomLeftCorner,
              code.location.topLeftCorner
            );
            if (code.data) {
              this.getData(code.data);
            }
          }
        }
        requestAnimationFrame(this.tick);
      },
      drawLine(begin, end, color = "#FF3B58") {
        this.canvas2d2.beginPath();
        this.canvas2d2.moveTo(
          this.nutranstion(begin.x),
          this.nutranstion(begin.y)
        );
        this.canvas2d2.lineTo(this.nutranstion(end.x), this.nutranstion(end.y));
        this.canvas2d2.lineWidth = 4;
        this.canvas2d2.strokeStyle = color;
        this.canvas2d2.stroke();
      },

      getData(data) {
        // this.$emit("success", data);
        this.success(data);
        if (!this.continue) {
          this.closeCamera();
        }
      },

      openTrack() {
        this.trackStatus = !this.trackStatus;
        this.track.applyConstraints({
          advanced: [{ torch: this.trackStatus }],
        });
      },

      createMsk() {
        this.maskWidth = this.windowWidth / 2 - this.canvasWidth / 2;
        this.maskHeight = this.windowHeight / 2 - this.canvasHeight / 2;
      },

      transtion(number) {
        return this.definition ? number * 2.8 : number * 1.8;
      },
      nutranstion(number) {
        return this.definition ? number / 2.8 : number / 1.8;
      },
    },
  });
</script>

注意: 需要https环境才能使用!!!

结语

完整代码,详细注释,拒绝废话,看官自取,动动小手,留下鼓励~

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

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

相关文章

Linux系统编程:高级IO总结

非阻塞IO基本概念 高级IO核心就一个概念&#xff1a;非阻塞IO。 与该概念相对的&#xff0c;就是我们之前学习过的阻塞IO。 非阻塞IO&#xff08;Non-blocking I/O&#xff09;是一种IO模型&#xff0c;用于实现异步IO操作&#xff0c;使应用程序能够在等待IO操作完成的同时…

Ubuntu部署EMQX开源版MQTT服务器-Orange Pi部署-服务器部署

一、前言 作为全球最具扩展性的 MQTT 消息服务器&#xff0c;EMQX 提供了高效可靠海量物联网设备连接&#xff0c;能够高性能实时移动与处理消息和事件流数据&#xff0c;本文将介绍如何在Ubuntu 22.04上部署MQTT服务器。我们本次选择开源版&#xff0c;使用离线安装方式部署。…

d2l绘图不显示的问题

之前试了各种方法都不行 在pycharm中还是不行&#xff0c;但是在anaconda中的命令行是可以的 anaconda prompt conda activaye py39 #进入f盘 F: #运行文件 python F:\python_code\softmax.py

Linux Ubuntu 手动搭建webDav

1、安装 因为需要跟 zotero 进行交互&#xff0c;因此需要在服务器搭建一个webDav 以下是搭建步骤&#xff1a; sudo apt-get update sudo apt-get install apache2 Ubuntu 安装apache2来实现 不同于Centos 安装好了之后&#xff0c;运行 a2enmod dav_fs a2enmod dav 激…

Linux shell编程学习笔记34:eval 命令

0 前言 在JavaScript语言中&#xff0c;有一个很特别的函数eval&#xff0c;eval函数可以将字符串当做 JavaScript 代码执行&#xff0c;返回表达式或值。 在Linux Shell 中也提供了内建命令eval&#xff0c;它是否具有JavaScript语言中eval函数的功能呢&#xff1f; 1 eval命…

【flink番外篇】3、fflink的source(内置、mysql、kafka、redis、clickhouse)介绍及示例(2)- 自定义、mysql

Flink 系列文章 一、Flink 专栏 Flink 专栏系统介绍某一知识点&#xff0c;并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分&#xff0c;比如术语、架构、编程模型、编程指南、基本的…

LeetCode 1631. 最小体力消耗路径:广度优先搜索BFS

【LetMeFly】1631.最小体力消耗路径&#xff1a;广度优先搜索BFS 力扣题目链接&#xff1a;https://leetcode.cn/problems/path-with-minimum-effort/ 你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights &#xff0c;其中 heights[row][col] 表示格子 (ro…

Leetcode—2961.双模幂运算【中等】

2023每日刷题&#xff08;五十六&#xff09; Leetcode—2961.双模幂运算 实现代码 class Solution { public:int func(int a, int b) {int ans 1;for(int i 0; i < b; i) {ans * a;ans % 10;}return ans;}int func2(int a, int b, int m) {int ans 1;for(int i 0; i …

使用Kali Linux端口扫描

端口扫描 【实训目的】 掌握端口扫描的基本概念和端口扫描的原理&#xff0c;掌握各种类型端口扫描的方法及其区别。 【场景描述】 在虚拟机环境下配置4个虚拟系统“Win XP1” “Win XP2” “Kali Linux”和“Metasploitable2”&#xff0c;使得4个系统之间能够相互通信。实…

深度学习(生成式模型)——ADM:Diffusion Models Beat GANs on Image Synthesis

文章目录 前言基础模型结构UNet结构Timestep Embedding关于为什么需要timestep embedding global attention layer 如何提升diffusion model生成图像的质量Classifier guidance实验结果 前言 在前几篇博文中&#xff0c;我们已经介绍了DDPM、DDIM、Classifier guidance等相关的…

EasyV易知微助力智慧城市未来趋势发展——数字孪生城市

“智慧城市的未来趋势就是数字孪生”——《基于数字孪生的智慧城市》 城市数字化管理、智慧城市和数字孪生城市的发展是相互促进、逐步深化的过程。 城市数字化管理作为起点&#xff0c;奠定了信息化、数据化的基础&#xff1b;而智慧城市则将数字城市管理进一步升级&#xff…

Could not resolve all dependencies for configuration ‘:app:androidApis‘.

android studio出现Could not resolve all dependencies for configuration ‘:app:androidApis’. 试过很多种方法&#xff0c;但是都不好使&#xff0c;不管怎么样都是提示如下报错&#xff1a; Using insecure protocols with repositories, without explicit opt-in, is un…

nginx配置正向代理支持https

操作系统版本&#xff1a; Alibaba Cloud Linux 3.2104 LTS 64位 nginx版本&#xff1a; nginx-1.25.3 1. 下载软件 切换目录 cd /server wget http://nginx.org/download/nginx-1.25.3.tar.gz 1.1解压 tar -zxvf nginx-1.25.3.tar.gz 1.2切换到源码所在目录…

Wireshark中的http协议包分析

Wireshark可以跟踪网络协议的通讯过程&#xff0c;本节通过http协议&#xff0c;在了解Wireshark使用的基础上&#xff0c;重温http协议的通讯过程。 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于 字节流…

lwIP 细节之三:errf 回调函数是何时调用的

使用 lwIP 协议栈进行 TCP 裸机编程&#xff0c;其本质就是编写协议栈指定的各种回调函数。将你的应用逻辑封装成函数&#xff0c;注册到协议栈&#xff0c;在适当的时候&#xff0c;由协议栈自动调用&#xff0c;所以称为回调。 注&#xff1a;除非特别说明&#xff0c;以下内…

评论送书:以企业架构为中心的SABOE数字化转型五环法

01 传统企业数字化转型面临诸多挑战 即将过去的2023年&#xff0c;chatGPT大模型、数据资产入表等事件的发生&#xff0c;标志着数字经济正在加速发展。数字经济是人类社会继农业经济、工业经济之后的第三种经济形态&#xff0c;将推动生产方式、生活方式和治理方式深刻变革&a…

Goby 漏洞发布| 亿赛通电子文档安全管理系统 LinkFilterService 接口权限绕过漏洞

漏洞名称&#xff1a;亿赛通电子文档安全管理系统 LinkFilterService 接口权限绕过漏洞 English Name&#xff1a;Esafenet Electronic Document Security Management System LinkFilterService API Permission Bypass Vulnerability CVSS core: 9.3 影响资产数&#xff1a;…

玩转大数据12:大数据安全与隐私保护策略

1. 引言 大数据的快速发展&#xff0c;为各行各业带来了巨大的变革&#xff0c;也带来了新的安全和隐私挑战。大数据系统通常处理大量敏感数据&#xff0c;包括个人身份信息、财务信息、健康信息等。如果这些数据被泄露或滥用&#xff0c;可能会对个人、企业和社会造成严重的损…

《opencv实用探索·十八》Camshift进行目标追踪流程

CamShift&#xff08;Continuously Adaptive Mean Shift&#xff09;是一种用于目标跟踪的方法&#xff0c;它是均值漂移&#xff08;Mean Shift&#xff09;的扩展&#xff0c;支持对目标的旋转跟踪&#xff0c;能够对目标的大小和形状进行自适应调整。 cv::CamShift和cv::me…

051:vue项目webpack打包后查看各个文件大小

第050个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…
最新文章