vue3视频拍照生成图片

主要流程

视频拍照功能需要拆分成视频 / 拍照        ↓

视频使用video标签配合煤气输入完成,拍照使用canvas标签生成图片        ↓

在点击拍照的时候获取到video当前容器对象绘制一张图片,将图片存储为file/blob/base64都行

1.开启摄像头(注:如果当前摄像头在工作中是需要关闭正在工作中的摄像头,要不然无法开启

  const MediaStreamTrack = ref([]);
// 开启摄像头:tagRef是video元素
  function openCamera(tagRef: any) {
    console.log('正在启动摄像头')
    // 存储跟踪列表,在关闭摄像头的时候使用
    return new Promise((resolve, reject) => {
      // 检查设备是否支持摄像头
      navigator.mediaDevices.enumerateDevices().then((devicesList) => {
        const kindList = devicesList.map((item) => item.kind);
        if (!kindList.includes("videoinput")) {
          feedback.msgError('系统不支持摄像操作')
          reject("系统不支持摄像操作");
        } else {
          // 开启摄像头操作
          navigator.mediaDevices
            .getUserMedia({ video: true })
            .then(function (stream) {
              /* 使用这个 stream 传递到成功回调中 */
              tagRef.srcObject = stream;
              tagRef.play();
              // 存储摄像头的跟踪信息(需要定义一个MediaStreamTrack的ref变量)
              MediaStreamTrack.value = stream.getTracks() as any;
            })
            .catch(function (err) {
              /* 处理 error 信息 */
              reject(err);
            });
        }
      });
    });
  }

2.拍照(canvas可以转换成很多种方式,blob/base64/file,根据自身情况去选择)

// 拍摄:videoRef是viedo元素,canvasRef是canvas元素
  function capture(videoRef: any, canvasRef: any) {
    return new Promise((resolve, reject) => {
      // 绘制画布
      context = canvasRef.getContext("2d");
      try {
        var radius = 8;
        context.beginPath();
        // 左上角
        context.arc(radius, radius, radius, Math.PI, Math.PI * 1.5);
        // 右上角
        context.arc(
          videoRef.offsetWidth - radius,
          radius,
          radius,
          Math.PI * 1.5,
          Math.PI * 2
        );
        // 右下角
        context.arc(
          videoRef.offsetWidth - radius,
          videoRef.offsetHeight - radius,
          radius,
          0,
          Math.PI * 0.5
        );
        // 左下角
        context.arc(
          radius,
          videoRef.offsetHeight - radius,
          radius,
          Math.PI * 0.5,
          Math.PI
        );
        // 结束绘制路径
        context.closePath();
        // 将路径限制到绘图区域内
        context.clip();
        // 不需要圆角的话可以忽略上面这一段

        /* 要跟video的宽高一致 */
        context.drawImage(
          videoRef,
          0,
          0,
          videoRef.offsetWidth,
          videoRef.offsetHeight
        );
        // 将cavans对象转化为Blod对象
        canvasRef.toBlob(
          (blob: Blob) => {
            const formData = new FormData()
            formData.append('file', blob)
            resolve(formData.get('file'));
          },
          "image/png/webp",
          1
        );
      } catch (err) {
        reject("图片截取失败" + err);
      }
    });
  }

3.关闭摄像头(在离开页面后需要关闭摄像头)

// 关闭摄像头
  function closeCamera(videoRef: any) {
    if (MediaStreamTrack.value.length) {
      MediaStreamTrack.value.forEach((track: { stop: () => void }) => {
        track.stop();
      });
      videoRef.srcObject = null;
    }
  }

4.完整hook文件

import { ref } from "vue";
// 这一块是封装的消息提示文件
import feedback from "@/utils/feedback";

export default () => {
  const MediaStreamTrack = ref([]);
  let context: any = null;
  // 开启摄像头
  function openCamera(tagRef: any) {
    feedback.notify('正在启动摄像头')
    // 存储跟踪列表,在关闭摄像头的时候使用
    return new Promise((resolve, reject) => {
      // 检查设备是否支持摄像头
      navigator.mediaDevices.enumerateDevices().then((devicesList) => {
        const kindList = devicesList.map((item) => item.kind);
        if (!kindList.includes("videoinput")) {
          feedback.msgError('系统不支持摄像操作')
          reject("系统不支持摄像操作");
        } else {
          // 开启摄像头操作
          navigator.mediaDevices
            .getUserMedia({ video: true })
            .then(function (stream) {
              /* 使用这个 stream 传递到成功回调中 */
              tagRef.srcObject = stream;
              // 存储摄像头的跟踪信息
              tagRef.play();
              MediaStreamTrack.value = stream.getTracks() as any;
            })
            .catch(function (err) {
              /* 处理 error 信息 */
              feedback.msgError(err)
              reject(err);
            });
        }
      });
    });
  }

  // 拍摄
  function capture(videoRef: any, canvasRef: any) {
    return new Promise((resolve, reject) => {
      // 绘制画布
      context = canvasRef.getContext("2d");
      try {
        /* 要跟video的宽高一致 */
        var radius = 8;
        context.beginPath();
        // 左上角
        context.arc(radius, radius, radius, Math.PI, Math.PI * 1.5);
        // 右上角
        context.arc(
          videoRef.offsetWidth - radius,
          radius,
          radius,
          Math.PI * 1.5,
          Math.PI * 2
        );
        // 右下角
        context.arc(
          videoRef.offsetWidth - radius,
          videoRef.offsetHeight - radius,
          radius,
          0,
          Math.PI * 0.5
        );
        // 左下角
        context.arc(
          radius,
          videoRef.offsetHeight - radius,
          radius,
          Math.PI * 0.5,
          Math.PI
        );
        // 结束绘制路径
        context.closePath();
        // 将路径限制到绘图区域内
        context.clip();
        context.drawImage(
          videoRef,
          0,
          0,
          videoRef.offsetWidth,
          videoRef.offsetHeight
        );
        // 将cavans对象转化为Blod对象
        canvasRef.toBlob(
          (blob: Blob) => {
            const formData = new FormData()
            formData.append('file', blob)
            resolve(formData.get('file'));
          },
          "image/png/webp",
          1
        );
      } catch (err) {
        reject("图片截取失败" + err);
      }
    });
  }

  // 关闭摄像头
  function closeCamera(videoRef: any) {
    if (MediaStreamTrack.value.length) {
      MediaStreamTrack.value.forEach((track: { stop: () => void }) => {
        track.stop();
      });
      videoRef.srcObject = null;
    }
  }

  return {
    openCamera,
    capture,
    closeCamera
  };
};

5.页面中使用(大致的使用方式就是如下代码,根据不同情况调整就好)

<video
 ref="videoRef"
 class="video-item"
 ></video>
<canvas
 class="cavcas-img"
 ref="canvasRef"
 ></canvas>


// 引入useCamera
import useCamera from "@/hooks/useCamera";

// 调用userCamera
const { openCamera, capture, closeCamera } = useCamera();

// 开启摄像头
const openVideo = () => {
  openCamera(videoRef.value);
};


// 拍照
const videoClick = async () => {
  const rews = await (await capture(videoRef.value, canvasRef.value)) as FormData;
  console.log(rews);
};

onBeforeUnmount(() => {
  // 关闭摄像头
  closeCamera(videoRef.value);
});

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值