首页 > 解决方案 > ImageCapture API 的替代方案以获得更好的浏览器支持

问题描述

我使用 OCR 来识别图像中的文本。我使用MediaStream中的ImageCapture API从用户的相机/视频输入中拍摄照片/快照。这是负责的代码:

function getBlobFromMediaStream() {
    const videoTrack = mediaStream.getVideoTracks()[0]

    const imageCapture = new ImageCapture(videoTrack);

    return imageCapture.takePhoto().then(blob => {
        if (!blob) throw "Photo could not be taken";

        return blob;
    })
}

太糟糕了,这个 API 在很多浏览器(Firefox、IE、Safari)上都不起作用。有没有可以使用的替代品?

标签: javascriptocrtesseractvideo-capturemediastream

解决方案


您可以使用 aHTMLVideoElement和 a进行后备HTMLCanvasElement
首先通过检查窗口对象中是否存在构造函数来检查您的浏览器是否支持 MediaStream Image Capture API。

if ('ImageCapture' in window) { 
  // Has support for API.
} else {
  // No support, use fallback.
}

然后基于此使用 API 或使用您的后备。

在后备中创建一个视频元素、画布元素和画布上下文。将 设置MediaStreamTracksrcObject视频元素的。视频能够解码数据并制作实际图片。

使用视频的图像通过该方法将图像绘制到画布元素CanvasRenderingContext2D.drawImage()。这样,canvas 元素将绘制视频中当前帧的图像。

现在您可以提取画布上绘制的数据并Blob使用HTMLCanvasElement.toBlob()方法将其转换为a。

将函数调用包装在 a 内有Promise两个原因:

  1. 您需要从回调中提取 blob,Promise 包装器可以帮助您做到这一点。
  2. ImageCapture.takePhoto()方法还返回一个 Promise。因此,您将拥有与支持 API 时相同的行为。

所有放在一起它看起来像这样。

function getBlobFromMediaStream(stream) {

  if ('ImageCapture' in window) {

    const videoTrack = stream.getVideoTracks()[0];
    const imageCapture = new ImageCapture(videoTrack);
    return imageCapture.takePhoto();
    
  } else {

    const video = document.createElement('video');
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');

    video.srcObject = stream;

    return new Promise((resolve, reject) => {
      video.addEventListener('loadeddata', async () => {
        const { videoWidth, videoHeight } = video;
        canvas.width = videoWidth;
        canvas.height = videoHeight;

        try {
          await video.play();
          context.drawImage(video, 0, 0, videoWidth, videoHeight);
          canvas.toBlob(resolve, 'image/png');
        } catch (error) {
          reject(error);
        }
      });
    });

  }
  
}

如下例所示调用您的函数。我已经放弃了该throw语句,以便在您调用该函数时在同一点捕获所有被拒绝的状态。getBlobFromMediaStream

根据 的文档ImageCapture.takePhoto(),您要么Blob在承诺履行时得到一个,要么在承诺被拒绝时得到一个错误。

后备也是如此。唯一的区别是,如果画布的位图不是原点干净的,则该HTMLCanvasElement.toBlob()函数会抛出一个。SecurityError

getBlobFromMediaStream(mediaStream).then(blob => {
  // Work with your blob.
}).catch(error => {
  console.log(`Photo could not be taken. ${error}`);
})

推荐阅读