ImageCapture API 的替代方案以获得更好的浏览器支持

Mee*_*ees 3 javascript ocr tesseract video-capture mediastream

我使用 OCR 来识别图像中的文本。我使用来自MediaStreamImageCapture 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;
    })
}
Run Code Online (Sandbox Code Playgroud)

太糟糕了,这个 API 不能在很多浏览器(Firefox、IE、Safari)上运行。有没有可以使用的替代方法?

Emi*_*ier 5

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

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

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

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

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

现在你可以将已经绘制在画布上的数据提取出来,并把它变成一个BlobwithHTMLCanvasElement.toBlob()方法。

将函数调用包裹在 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);
        }
      });
    });

  }
  
}
Run Code Online (Sandbox Code Playgroud)

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

根据 的文档ImageCapture.takePhoto(),您要么Blob在承诺完成时得到 ,要么在拒绝时得到错误。

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

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

  • 太棒了,感谢您的全面解释!HTMLVideoElement 和 HTMLCanvasElement 是非常好的替代品,具有 [95%+](https://caniuse.com/#search=HTMLCanvasElement) 浏览器支持 (2认同)