【问题标题】:Alternative for the ImageCapture API for better browser supportImageCapture API 的替代方案以获得更好的浏览器支持
【发布时间】:2020-06-18 09:04:14
【问题描述】:

我使用 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;
    })
}

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

【问题讨论】:

    标签: javascript ocr tesseract video-capture mediastream


    【解决方案1】:

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

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

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

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

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

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

    将函数调用包装在 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 函数时,所有rejected 状态都会在同一点被捕获。

    根据ImageCapture.takePhoto() 的文档,当promise 实现时你会得到一个Blob,当它被拒绝时你会得到一个错误。

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

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

    【讨论】:

    • 太棒了,感谢您的全面解释! HTMLVideoElement 和 HTMLCanvasElement 是具有95%+ 浏览器支持的非常好的替代品
    猜你喜欢
    • 2017-06-23
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多