自定义webIpad证件相机(webRTC)

news2024/11/16 6:04:09
该技术方案可用于各浏览器自定义相机开发

相机UI(index.html)

<!DOCTYPE html>
<html lang="zh" prew="-1">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
        content="user-scalable=no, initial-scale=1, maximum-scale=5, minimum-scale=1, width=device-width" />
    <title>自定义相机</title>
    <link rel="stylesheet" href="./style.css">
    <script src="./tools.js"></script>
    <script src="./index.js"></script>
</head>

<body>
    <div class="errTip">
        <p>Failed to obtain the rear camera of the device. Please try another solution to obtain resources!</p>
        <button class="errBtn">GO Back</button>
    </div>
    <div class="takeOffTip"></div>
    <div class="imgBoxDom">
        <div class="imgBox">
            <img src="./center.png" style="width: 4vw;">
        </div>
    </div>
    <div class="rightBtnBox">
        <div class="takeBtn"></div>
        <div class="cancleBtn btn"></div>
    </div>
    <div class="bottomBtnBox">
        <div class="reTakeBtn btn bottonSize"></div>
        <div class="nextBtn btn bottonSize"></div>
    </div>
    <div class="loading-css">
        Loading...
    </div>
</body>

</html>

 相机UI样式(style.css)

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    border: 0;
}

html,
body {
    width: 100%;
    height: 100%;
    overflow: hidden;
    background-color: #000;
    color: #fff;
}

.cancleBtn {
    padding: 2vw 0;
    width: 100%;
}

.takeOffTip {
    position: fixed;
    padding-top: 2vw;
    top: 0;
    left: 0;
    width: 100%;
    font-size: 1.8vw;
    text-align: center;
    color: #fff;
}

.bottonSize {
    height: 100%;
    line-height: 6vw;
    line-height: 6dvw;
    padding: 0 1.5vw;
}

.bottomBtnBox,
.rightBtnBox {
    position: fixed;
    right: 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #000;
    z-index: 10;
}

.bottomBtnBox {
    bottom: 0;
    width: 100%;
    height: 6vw;
    height: 6dvw;
}

.rightBtnBox {
    flex-direction: column;
    top: 0;
    height: 100%;
    width: 6vw;
    width: 6dvw;
}

html[prew='-1'] .bottomBtnBox,
html[prew='0'] .bottomBtnBox,
html[prew='-1'] .rightBtnBox,
html[prew='1'] .rightBtnBox,
html[prew='1'] .customer_carema {
    display: none;
}

html[prew='1'] .imgBox {
    border: 0;
    font-size: 0;
    opacity: 0;
}

.takeBtn {
    padding: 4px;
    width: 5vw;
    width: 5dvw;
    height: 5vw;
    height: 5dvw;
    background-color: #fff;
    border-radius: 50%;
}

.takeBtn::before {
    content: '';
    display: block;
    width: 100%;
    height: 100%;
    border: 5px solid #000;
    background-color: #fff;
    border-radius: 50%;
    box-sizing: border-box;
}

.rightBtnBox::before {
    content: '';
    display: block;
}

.btn {
    background-color: #000;
    text-align: center;
    font-size: 1.5vw;
    color: #fff;
}

.customer_video,
.carema_img,
.cuteImg {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.imgBoxDom {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 9;
}

.imgBox {
    width: var(--carema-box-width);
    height: var(--carema-box-height);
    border: 2px solid #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 10vw;
    z-index: 10;
    border-radius: 2vw;
}

.errTip {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 8888;
    display: none;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background-color: #000;
}

.errTip>p {
    padding-bottom: 20px;
    color: #fff;
}

.errTip button {
    padding: 10px 30px;
}

html[prew='2'] .errTip {
    display: flex;
}

html[loaded='1'] .loading-css {
    display: none;
}

.loading-css {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background-color: #000;
    z-index: 9999;
}

.loading-css::before {
    margin-bottom: 10px;
    content: '';
    width: 50px;
    height: 50px;
    display: inline-block;
    border: 3px solid #f3f3f3;
    border-top: 3px solid rgb(160, 155, 155);
    border-radius: 50%;
    animation: loading-360 0.8s infinite linear;
}

@keyframes loading-360 {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}

调试UI(carema.html)
 

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
        content="user-scalable=no, initial-scale=1, maximum-scale=5, minimum-scale=1, width=device-width" />
    <title>调试相机</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            border: 0;
        }

        img {
            max-width: 100%;
        }

        .btnList {
            padding: 10px;
        }

        label[type='file'],
        button {
            padding: 0 10px;
            height: 32px;
            line-height: 32px;
            display: inline-block;
            font-size: 14px;
            appearance: auto;
            border: 1px solid #999;
            background-color: #dcdcdc;
        }

        label>input {
            font-size: 0;
            width: 0;
            height: 0;
            overflow: hidden;
        }

        .showImg {
            padding: 5px;
            display: flex;
            flex-wrap: wrap;

        }

        .showImg>.box {
            width: 33.33%;
            padding: 5px;
        }

        .showImg>.box>.img {
            width: 100%;
            height: 20vw;
            overflow: hidden;
            border-radius: 10px;
            border: 2px solid #888;
        }

        .showImg>.box>.img>img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        html,
        body {
            height: 100%;
            height: 100%;
        }

        body {
            display: flex;
            flex-direction: column;
        }

        .showImg {
            flex: 1;
            overflow-x: hidden;
        }
    </style>
</head>

<body>
    <div class="btnList">
        <button onclick="openCarema('HK_ID')">COMM_ID_IMG</button>
        <button onclick="openCarema('LANDING')">LANDING_IMG</button>
        <label name="upload" type="file">
            LOCAL_IMG
            <input type="file" id="upload">
        </label>
    </div>
    <div class="showImg" id="showImg"></div>
</body>
<script>
    function fileToBase64(file) {
        return new Promise((resolve, reject) => {
            // 创建一个新的 FileReader 对象
            var reader = new FileReader();
            // 读取 File 对象
            reader.readAsDataURL(file);
            // 加载完成后
            reader.onload = function () {
                // 将读取的数据转换为 base64 编码的字符串
                var base64String = reader.result.split(",")[1];
                // 解析为 Promise 对象,并返回 base64 编码的字符串
                resolve(base64String);
            };

            // 加载失败时
            reader.onerror = function () {
                reject(new Error("Failed to load file"));
            };
        });
    }
    function showImg(url) {
        var showImgDom = document.getElementById('showImg');
        var img = document.createElement('img');
        img.src = `data:image/jpeg;base64,${url}`;
        var div = document.createElement('div');
        var cDiv = document.createElement('div');
        div.append(cDiv);
        cDiv.append(img);
        div.className = 'box';
        cDiv.className = "img";
        showImgDom.insertBefore(div, showImgDom.firstChild);
    }
    document.getElementById('upload').addEventListener('change', function ($event) {
        var file = $event.target.files[0];
        fileToBase64(file).then(showImg);
    })
    function openCarema(idType) {
        var openId = Date.now() + '';
        window.open(`./index.html?openId=${openId}&idType=${idType}&isDev=1`);
        window.addEventListener('message', function (res) {
            var resOpenId = res.data.openId;
            var mothod = res.data.mothod;
            var file = res.data.imgUrl;
            console.log(resOpenId, mothod, file);
            if (mothod === "success_file" && openId === resOpenId) fileToBase64(file).then(showImg);
        })
    }
</script>

</html>

相机逻辑基础(index.js)

function WbCRM() {
    this.body = document.body;
    this.html = document.documentElement;
    this.takeBtn = document.querySelector('.takeBtn');
    this.imgBox = document.querySelector('.imgBox');
    this.reTakeBtn = document.querySelector('.reTakeBtn');
    this.cancleBtn = document.querySelector('.cancleBtn');
    this.nextBtn = document.querySelector('.nextBtn');
    var errBtn = document.querySelector('.errBtn');
    this.video = null;
    this.err = null;
    this.fullImg = null;
    this.file = '';
    this.idType = '';
    this.isDev = false;

    this.stream = null;
    this.openId = '';

    this.ratio = window.devicePixelRatio || 1;
    this.videoWidth = this.body.clientWidth * this.ratio;
    this.videoHeight = this.body.clientHeight * this.ratio;

    this.html.setAttribute('prew', '-1');
    var isMp3 = !(navigator.userAgent.match(/Firefox/));
    var audio = new Audio();
    audio.autoplay = isMp3 ? './shutter.mp3' : './shutter.ogg';
    this.audio = audio;
    console.log(isMp3,audio);

    this.mediaDevices = (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) ?
        navigator.mediaDevices : ((navigator.mozGetUserMedia || navigator.webkitGetUserMedia) ? {
            getUserMedia: function (c) {
                return new Promise(function (y, n) {
                    (navigator.mozGetUserMedia ||
                        navigator.webkitGetUserMedia).call(navigator, c, y, n);
                });
            }
        } : null);
    this.setDom();
    this.setCarema();
    this.takeBtn.addEventListener('click', this.takePhoto.bind(this));
    this.nextBtn.addEventListener('click', this.next.bind(this));
    this.reTakeBtn.addEventListener('click', this.reTake.bind(this));
    this.cancleBtn.addEventListener('click', this.cancle.bind(this));
    errBtn.addEventListener('click', this.openErro.bind(this));
}
WbCRM.prototype.openErro = function () {
    this.sendMsg('open_erro');
}
WbCRM.prototype.cancle = function () {
    this.removeStream();
    this.sendMsg('off_carema');
}
WbCRM.prototype.next = function () {
    if (this.fullImg) this.fullImg.remove();
    this.removeStream();
    this.sendMsg('success_file');
}
WbCRM.prototype.reTake = function () {
    this.file = null;
    this.err = null;
    if (this.fullImg) this.fullImg.remove();
    this.html.setAttribute('loaded', 0);
    this.removeStream();
    this.setCarema();
}
WbCRM.prototype.cutImage = function () {
    var boxWidth = this.imgBox.clientWidth * this.ratio;
    var boxHeight = this.imgBox.clientHeight * this.ratio;
    var vLeft = (this.videoWidth - boxWidth) / 2;
    var vTop = (this.videoHeight - boxHeight) / 2;
    var nCanvas = wbCRMTools.drawHighDefinitionImg(boxWidth, boxHeight);
    var nCtx = nCanvas.getContext('2d');
    nCtx.drawImage(this.fullImg, -vLeft, -vTop);
    var cutImage = nCtx.getImageData(0, 0, boxWidth, boxHeight);
    wbCRMTools.changeImgData(cutImage?.data || [], this.idType || '');
    nCtx.putImageData(cutImage, 0, 0);
    reImgUrl = nCanvas.toDataURL('image/jpeg');
    var cImg = document.createElement('img');
    cImg.src = reImgUrl;
    this.file = wbCRMTools.canvas2File(reImgUrl);
    wbCRMTools.clearCanvas(nCtx, nCanvas);
    cImg.className = "cuteImg";
    this.imgBox.append(cImg);
    this.html.setAttribute('prew', '1');
    this.removeStream();
}
WbCRM.prototype.takePhoto = function () {
    var gCanvas = wbCRMTools.drawHighDefinitionImg(this.videoWidth, this.videoHeight);
    var originalCtx = gCanvas.getContext('2d');
    originalCtx.drawImage(this.video, 0, 0, this.videoWidth, this.videoHeight);

    var imgUrl = gCanvas.toDataURL('image/jpeg');
    var fullImg = document.createElement("img");
    fullImg.className = "carema_img";
    fullImg.src = imgUrl;
    this.fullImg = fullImg;
    this.body.append(fullImg);
    wbCRMTools.clearCanvas(originalCtx, gCanvas);
    this.audio.play();
    fullImg.onload = this.cutImage.bind(this);
}

WbCRM.prototype.sendMsg = function (mothod) {
    this.audio.remove();
    const origin = this.isDev ? undefined : window.location.origin;
    window.opener.postMessage({ mothod: mothod, file: this.file, openId: this.openId, error: this.err }, origin);
    window.close();
}

WbCRM.prototype.removeStream = function () {
    var self = this;
    if (self.stream) {
        self.stream.getTracks().forEach(function (track) {
            if (track.readyState === 'live') track.stop();
            self.stream.removeTrack(track);
        });
    }
    if (this.video) this.video.remove();
    var cuteImgList = document.querySelectorAll('.cuteImg');
    cuteImgList.forEach(function (dom) {
        dom.remove();
    })
}

WbCRM.prototype.setDom = function () {
    this.openId = wbCRMTools.getUrlParam('openId');
    var okText = wbCRMTools.getUrlParam('continue');
    var cancelText = wbCRMTools.getUrlParam('cancel');
    var retakeText = wbCRMTools.getUrlParam('retake');
    var idType = wbCRMTools.getUrlParam('idType') || '';
    var takeOffTip = wbCRMTools.getUrlParam('takeOffTip');
    const isDev = wbCRMTools.getUrlParam('isDev');
    this.isDev = isDev === '1';
    this.nextBtn.innerText = okText || 'Cuntinue';
    this.cancleBtn.innerText = cancelText || 'Cancel';
    this.reTakeBtn.innerText = retakeText || 'Retake';
    document.querySelector('.takeOffTip').innerHTML = takeOffTip;
    this.html.setAttribute('loaded', 0);
    this.html.style.setProperty('--carema-box-width', '64.512vw');
    this.html.style.setProperty('--carema-box-height', '40.6789vw');
    if (idType === "LANDING") {
        this.html.style.setProperty('--carema-box-width', '51.2vw');
        this.html.style.setProperty('--carema-box-height', '44.5935vw');
    }
    this.idType = idType;
}

WbCRM.prototype.setVideo = function (stream) {
    var video = document.createElement('video');
    video.setAttribute('autoplay', 'autoplay');
    video.setAttribute('playsinline', 'playsinline');
    video.className = 'customer_video';
    this.video = video;
    this.stream = stream;
    this.body.append(video);
    var self = this;
    video.onloadedmetadata = function (e) {
        self.stream = stream;
        self.loaded = true;
        self.html.setAttribute('loaded', 1);
    };
    video.onplay = function () {
        self.html.setAttribute('prew', '0');
    }
    // as window.URL.createObjectURL() is deprecated, adding a check so that it works in Safari.
    // older browsers may not have srcObject
    if ("srcObject" in video) {
        video.srcObject = stream;
    } else {
        // using URL.createObjectURL() as fallback for old browsers
        video.src = window.URL.createObjectURL(stream);
    }
}

WbCRM.prototype.setCarema = function () {
    const videoConf = this.isDev ? {} : {
        width: { min: 1024, ideal: 2360, max: 2732 },
        height: { min: 776, ideal: 1640, max: 2048 },
        facingMode: { exact: "environment" }
    }
    var self = this;
    this.mediaDevices.getUserMedia({
        audio: false,
        video: videoConf
    }).then(this.setVideo.bind(this)).catch(function (error) {
        self.err = error.toString();
        self.html.setAttribute('prew', '2');
        self.html.setAttribute('loaded', '1');
    })
}

window.addEventListener('load', function () {
    var wbCRM = new WbCRM();
    window.addEventListener('visibilitychange', function () {
        wbCRM.removeStream();
        window.close();
    });
});

图片出路和文件生成工具(tools.js) 

var wbCRMTools = {
    drawHighDefinitionImg: function (width, height) {
        const canvas = document.createElement('canvas');
        canvas.style.width = width + 'px';
        canvas.style.height = height + 'px';
        canvas.width = width;
        canvas.height = height;
        return canvas;
    },
    clearCanvas: function (ctx, canvas) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.beginPath();
        canvas.height = 0;
        canvas.width = 0;
        canvas.remove();
        canvas.parentNode?.removeChild(canvas);
    },

    changeImgData: function (data, idType) {
        const isGrayscale = ['PASSPORT', 'LANDING', 'ENTRYPERMIT', 'SUP_LEGAL_ID'].some(imgType => idType.indexOf(imgType) !== -1);
        let contrast = 35;
        const thereshold = 20;
        if ('LANDING' === idType) contrast = 45;
        // gaussBlur will use in the feature, cancel this fun now, don`t delete please
        // this.gaussBlur(imageData, 1);
        // If MacId and HK-LANDING change cavans-img-code.
        const factor = (255 + contrast) / (255.01 - contrast);  //add .1 to avoid /0 error
        const denominator = 1 / (1 - contrast / 255) - 1;
        const setCV = cv => cv + (cv - thereshold) * denominator;
        const setCTV = cv => cv + (cv - thereshold) * contrast / 255;
        const getRGB = cv => factor * (cv - 128) + 128;
        // Data array data-length.
        const len = data?.length || 0;
        // loop value to change cavans imgData;
        for (let index = 0; index < len; index += 4) {
            let R = data[index];     //r value
            let G = data[index + 1]; //g value
            let B = data[index + 2] //b value
            if (contrast || thereshold) {
                R = getRGB(R); //r value
                G = getRGB(G); //g value
                B = getRGB(B); //b value
            }
            const isColorNum = index % 4 === 0;
            if (isColorNum) {
                R = contrast ? setCV(R) : setCTV(R);
                G = contrast ? setCV(G) : setCTV(G);
                B = contrast ? setCV(B) : setCTV(B);
                if (isGrayscale) {
                    const vNum = Math.round((R + G + B) / 3);
                    R = vNum;
                    G = vNum;
                    B = vNum;
                    data[index + 3] = 255;
                }
                data[index] = R;
                data[index + 1] = G;
                data[index + 2] = B;
            }
        }
    },
    getUrlParam: function (urlKey) {
        var url = window.location.search;
        var reg = new RegExp("(^|&)" + urlKey + "=([^&]*)(&|$)");
        var result = url.substring(1).match(reg);
        return result ? decodeURIComponent(result[2]) : null;
    },
    canvas2File: function (dataUrl) {
        let arr = dataUrl.split(','),
            mime = arr[0].match(/:(.*?);/)[1],
            bstr = atob(arr[1]),
            n = bstr.length,
            u8arr = new Uint8Array(n);
        while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }
        const nowId = Date.now();
        const fileName = `takePhoto_${nowId}.jpeg`;
        const blob = new Blob([u8arr], { type: mime, name: fileName });
        blob.lastModifiedDate = new Date();
        return new File([blob], fileName, { type: "image/jpeg" });
    }
}

 文件目录

效果图

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

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

相关文章

江苏 | 南京恒建视角下混凝土企业的根基和未来

第一视角带您走进本期标杆企业&#xff1a;南京恒建混凝土有限公司 “有根基才有未来。” ——走进南京恒建混凝土有限公司的办公楼&#xff0c;首先映入眼帘的就是这句话。所谓万丈高楼平地起&#xff0c;一砖一瓦皆根基。简单几个字&#xff0c;既能看到脚踏实地的坚守&…

机器学习笔记-01-初识基础(问题-解答自查版)

前言 以下问题以Q&A形式记录&#xff0c;基本上都是笔者在初学一轮后&#xff0c;掌握不牢或者频繁忘记的点 Q&A的形式有助于学习过程中时刻关注自己的输入与输出关系&#xff0c;也适合做查漏补缺和复盘。 本文对读者可以用作自查&#xff0c;答案在后面&#xff0…

DNS续集

1、DNS多域名解析 [rootdns ~]# vim /etc/named.rfc1912.zones 复制5行放在最后面 zone "z.a" IN { type master; file "z.a.zone"; allow-update { none; }; }; zone "4.168.192.in-addr.arpa" IN { type ma…

<数据集>玉米地杂草识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;9900张 标注数量(xml文件个数)&#xff1a;9900 标注数量(txt文件个数)&#xff1a;9900 标注类别数&#xff1a;2 标注类别名称&#xff1a;[Maize, Weed] 序号类别名称图片数框数1Maize8439125142Weed959231048…

rk3588s 定制版 USB adb , USB2.0与USB3.0 区别,adb 由typeC 转换到USB3.0(第二部分)

硬件资源&#xff1a; rk3588s 核心板定制的地板 软件资源&#xff1a; 网盘上的 android12 源码 1 硬件上 客户只想使用 type c 接口中的 usb2.0 OTG 。在硬件上&#xff0c;甚至连 CC芯片都没有连接。 关于一些前置的知识。 1 USB2.0 与 USB3.0 的区别。 usb3.0 兼容2.0 …

USUART代码例程和库函数

USUART代码例程和库函数 一、USUART中重要的寄存器二、USART中发送数据。三、接收数据四、USART发送数据示例代码&#xff08;print重定向&#xff09;五、USART接收数据示例代码六、USART常用的库函数usart_deinit&#xff08;&#xff09;&#xff1a;复位外设USARTusart_bau…

什么是大型语言模型 (LLM)

本章探讨下&#xff0c;人工智能如何彻底改变我们理解和与语言互动的方式 大型语言模型 (LLM) 代表了人工智能的突破&#xff0c;它采用具有广泛参数的神经网络技术进行高级语言处理。 本文探讨了 LLM 的演变、架构、应用和挑战&#xff0c;重点关注其在自然语言处理 (NLP) 领…

【ARM】MDK-STM32g0xx.h文件与Define规则记录

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 记录问题STM32g0xx.h等有关ST的可读文件&#xff0c;尽量勿修改文件格式及对其代码进行添加和删减&#xff0c;记录查找问题的过程中的疑惑&#xff0c;并如何给予客户正确的回复&#xff0c;帮助销售完成验收&…

VBA实例-从Excel整理数据到Word

实现目录 功能需求数据结构复制数据到新sheet并分类数据添加序号、日期、时间三列数据添加序号列添加时间列 将名称和类别复制到word文件中将参数5和参数9中的一个复制到word文件中 实例 功能需求 1、将原始数据中不要的数据剔除 2、原始数据中增加序号、日期和时间三列数据&a…

富唯智能转运机器人:高效、智能、未来的选择

在现代工业中&#xff0c;高效的物流和物料处理是提升生产效率的关键。富唯智能转运机器人&#xff0c;以其卓越的技术和智能化的设计&#xff0c;为各行业提供了完美的解决方案。 产品概述 富唯智能转运机器人搭载ICD系列核心控制器&#xff0c;拥有多种移载平台&#xff0c…

【目标检测】Yolo5基本使用

前言 默认安装好所有配置&#xff0c;只是基于Yolo5项目文件开始介绍的。基于配置好的PyCharm进行讲解配置。写下的只是些基本内容&#xff0c;方便以后回忆用。避免配置好Yolo5的环境&#xff0c;拉取好Yolo5项目后&#xff0c;不知道该如何下手。如果有时间&#xff0c;我还是…

我在Vscode学Java集合类

Java集合类 一、集合1.1 集合和数组之间的对比1.2 集合框架的核心接口1.3 集合框架中的实现类单列集合双列集合 1.4 集合框架的特点 二、 Collection集合与Iterator迭代器2.1 Collection的概述2.1.1 常用方法增加元素的方法修改元素的方法删除元素的方法查询元素的方法遍历集合…

Delphi5实现鱼C屏幕保护程序

效果图 鱼C屏幕保护程序 添加背景图片 在additional添加image组件&#xff0c;修改picture属性上传图片。 这个图片可以截屏桌面&#xff0c;方便后面满屏不留白操作。实现无边框 即上面的“- □ ”不显示 将Form1的borderstyle属性改为bsnone实现最大化&#xff0c;满屏 将…

mac OS matplotlib missing from font(s) DejaVu Sans

如果能搜索到这篇文章&#xff0c;我猜你遇到了和我一样的问题&#xff1a;matplotlib绘图中文乱码。如下&#xff1a; 出现这个问题的原因是&#xff1a;matplotlib使用的字体列表中默认没有中文字体。 这里说一种解决方案&#xff1a;我们可以在文件中手动指定matplotlib使用…

springcloud接入skywalking作为应用监控

下载安装包 需要下载SkyWalking APM 和 Java Agent 链接: skywalking 安装 下载JDK17&#xff08;可不配置环境变量&#xff09; 目前skywalking 9.0及以上版本基本都不支持JDK8&#xff0c;需要JDK11-21&#xff0c;具体版本要求在官网查看。 我这里使用的是skywalking9.…

开发桌面程序-Electron入门

Electron是什么 来自官网的介绍 Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。 总…

Audio Mixer Examples

简介 Audio Mixer 是在 Unity 5.0 版本中首次引入的音频混合器工具&#xff0c;它可以帮我们处理声音的分组管理、音效模拟、情景再现等重要业务。 功能入口 在资产视口单击鼠标右键 选择 Create 选项 选择 Audio 选项 点击 Audio Mixer Audio Mixer Assets 的属性面板 …

第一讲:NJ本地配置

本地配置:就是和CPU本地放在一起的系统配置,不是通过网络通信等方式配置的。 NJ本地系统配置 一、CPU机架(即CPU所在的机架) 如图所示最右边数量是有限制的,每个机架最多可放置10个扩展IO单元 二、扩展机架(1个本地的NJ扩展系统中,最多可以扩展3个机架,且每个机架最多…

从数据时代到智能时代,星环科技信雅达联合发布金融全栈解决方案

近年来&#xff0c;星环科技与信雅达在金融行业的多个关键领域展开了广泛而深入的合作&#xff0c;推出了一系列面向金融科技领域的联合解决方案。此次合作基于星环科技在大数据、人工智能和云计算领域的先进技术&#xff0c;以及信雅达在金融领域的深厚积累&#xff0c;围绕数…

数据科学统计面试问题 -40问

前 40 名数据科学统计面试问题 一、介绍 正如 Josh Wills 曾经说过的那样&#xff0c;“数据科学家是一个比任何程序员都更擅长统计、比任何统计学家都更擅长编程的人”。统计学是数据科学中处理数据及其分析的基本工具。它提供了工具和方法&#xff0c;可帮助数据科学家获得…