多路视频每一个视频进行截屏并且上传到后台

发布于:2025-05-24 ⋅ 阅读:(13) ⋅ 点赞:(0)

<template>

    <div class="meetingRoom-content">

        <div class="meetingRoom-content-box" v-if="domReady">

            <div

                class="meeting-box"

                :style="`width: ${videoStyle.width + '%'};height: ${

                    videoStyle.height + '%'

                }`"

                v-for="(i, index) in participants"

                :key="'participants' + index"

                :id="i.userId"

                @mouseover="

                    () => {

                        participants[index].hoverButtonShow = true;

                    }

                "

                @mouseleave="

                    () => {

                        participants[index].hoverButtonShow = false;

                    }

                "

            >

                <el-card>

                    <div class="camera-box" v-loading="i.loading">

                        <div

                            class="camera-box-inner"

                            v-for="(x, y) in i.children"

                            :key="y + 'children' + x.featureCode"

                            v-show="x.isShow"

                            :style="`width: ${i.videoInnerStyle!.width + '%'};max-height: ${i.videoInnerStyle!.height + '%'

              };`"

                        >

                            <div class="userName-box" v-if="!i.isApp">

                                {{

                                    `${i.userName} — ${

                                        x.cameraName || i.cameraName

                                    }`

                                }}

                            </div>

                            <div class="userName-box" v-else>

                                {{ `${i.userName}` }}

                            </div>

                            <video

                                :class="{ appVideo: i.isApp }"

                                :id="x.featureCode"

                                muted

                                autoplay

                                controls

                                v-show="x.camera"

                            ></video>

                        </div>

                    </div>

                    <div class="camera-mask-box" v-show="!i.camera">

                        <div class="userName-icon-box">

                            <div class="userName-icon">

                                {{ formatterUserName(i.userName!) }}

                            </div>

                        </div>

                    </div>

                    <div

                        class="btn-gray-small cusp"

                        @click="fullScreen(i.userId)"

                        style="right: 16px; z-index: 999; padding: 0 10px"

                        v-if="i.isMultiple && i.hoverButtonShow"

                    >

                        <el-icon>

                            <FullScreen />

                        </el-icon>

                    </div>

                    <div

                        class="btn-gray-small cusp"

                        @click="openPicInPic(i.userId)"

                        style="right: 64px; z-index: 999; padding: 0 10px"

                        v-if="i.isMultiple && i.hoverButtonShow"

                    >

                        <el-icon>

                            <CopyDocument />

                        </el-icon>

                    </div>

                    <div

                        class="btn-gray-small cusp"

                        @click="captureParticipantFrame(i.userId)"

                        style="right: 112px; z-index: 999; padding: 0 10px"

                        v-if="i.hoverButtonShow"

                    >

                        <el-icon>

                            <Camera />

                        </el-icon>

                    </div>

                </el-card>

            </div>

        </div>

    </div>

</template>

<script lang="ts" setup>

function formatterUserName(userName: string) {

    if (userName.length > 4) {

        return userName.slice(0, 3) + "...";

    } else {

        return userName;

    }

}

// 截图并保存到本地的工具函数

const captureAndSaveFrame = (video, fileName) => {

    // 创建canvas元素

    const canvas = document.createElement("canvas");

    const ctx = canvas.getContext("2d")!;

    // 设置canvas尺寸与视频一致

    canvas.width = video.videoWidth;

    canvas.height = video.videoHeight;

    // 将视频帧绘制到canvas

    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

    // 生成图片数据URL(支持PNG格式)

    const imageDataUrl = canvas.toDataURL("image/png");

    // 创建下载链接

    const link = document.createElement("a");

    link.href = imageDataUrl;

    const imageName = `${fileName}_${Date.now()}.png`;

    link.download = imageName; // 带时间戳的文件名

    //上传到系统管理图片管理

    const imgFile = base64ToFile(imageDataUrl, imageName);

    // 模拟点击下载

    document.body.appendChild(link);

    link.click();

    document.body.removeChild(link);

    const formData = new FormData()[图片];

    // 将文件添加到 FormData 中,以便后续发送请求

    formData.append("file", imgFile);

    // 添加额外的请求参数,这里 dir 为空字符串

    formData.append("dir", "");

    // 添加额外的请求参数,这里 type 为 20

    formData.append("type", "10");

    request({

        url: "/admin/sys-file/upload",

        method: "post",

        headers: {

            "Content-Type": "multipart/form-data",

            Authorization: "Bearer " + Session.get("token"),

            "TENANT-ID": Session.getTenant(),

        },

        data: formData,

    })

        .then((data) => {

            // 请求成功时的处理,打印返回的数据

            console.log("success", data);

        })

        .catch((err) => {

            // 请求失败时的处理,打印错误信息

            console.log("error", err);

        });

    // 清理canvas

    canvas.remove();

};

/**

 * 将Base64字符串转换为File对象

 * @param {string} base64 - Base64编码的字符串

 * @param {string} filename - 生成文件的名称

 * @param {string} [mimeType] - 文件的MIME类型,默认为'image/png'

 * @returns {File} - 返回的File对象

 */

function base64ToFile(base64, filename, mimeType = "image/png") {

    // 1. 移除Base64前缀(如果有)

    const base64WithoutPrefix = base64.replace(/^data:.+;base64,/, "");

    // 2. 将Base64字符串转换为字节数组

    const byteCharacters = atob(base64WithoutPrefix);

    const byteArrays = [] as any;

    for (let offset = 0; offset < byteCharacters.length; offset += 512) {

        const slice = byteCharacters.slice(offset, offset + 512);

        const byteNumbers = new Array(slice.length);

        for (let i = 0; i < slice.length; i++) {

            byteNumbers[i] = slice.charCodeAt(i);

        }

        const byteArray = new Uint8Array(byteNumbers);

        byteArrays.push(byteArray);

    }

    // 3. 创建Blob对象

    const blob = new Blob(byteArrays, { type: mimeType });

    // 4. 将Blob转换为File对象

    return new File([blob], filename, { type: mimeType });

}

// 为单个参与者截图并保存

const captureParticipantFrame = (userId) => {

    const participantElement = document.getElementById(userId);

    if (!participantElement) return;

    const videoElements = participantElement.querySelectorAll("video");

    videoElements.forEach((video, index) => {

        if (video.videoWidth > 0 && video.videoHeight > 0) {

            const fileName = `${userId}_camera_${index + 1}`;

            captureAndSaveFrame(video, fileName);

        }

    });

};

</script>


网站公告

今日签到

点亮在社区的每一天
去签到