Web前端之浏览器拍照实现-浏览器原生API实现全像素拍照(不同于论坛大多数的拍照方法)

24 篇文章 0 订阅

浏览器拍照

上面一篇是利用mediaStream获取视频流,通过视频流截图实现拍照功能,但是问题是像素和画质较差,对于有较高要求的场景不能满足,因此继续搜索相关资料 ,这方面的权威肯定是MDN,因此在MDN上搜素能够实现拍照的API,终于在搜素过程中发现了一个实验性功能,只有chromium webkit内核的浏览器才支持该功能。

ImageCapture() constructor

这个就是本次要讨论的功能,这个API能够调用相机实现拍照,也是从mediaStream中获取视屏流,但是这个是为了显示当前传感器中的内容,同时通过这个函数可以获取到视频支持的一些参数

 navigator.mediaDevices.getUserMedia({video: true})
  .then(mediaStream => {
    document.querySelector('video').srcObject = mediaStream
    const track = mediaStream.getVideoTracks()[0];
    imageCapture = new ImageCapture(track);
  })
  .catch(error => console.log(error));
ImageCapture

ImageCapture的接口如下:

[Exposed=Window]
interface ImageCapture {
   constructor(MediaStreamTrack videoTrack);
   Promise<Blob>              takePhoto(optional PhotoSettings photoSettings = {});
   Promise<PhotoCapabilities> getPhotoCapabilities();
   Promise<PhotoSettings>     getPhotoSettings();

   Promise<ImageBitmap>       grabFrame();

   readonly attribute MediaStreamTrack track;
};

对于拍照来说需要获取的是当前摄像头能够支持的图像以及摄像头设置

PhotoCapabilities

该Promise方法能够返回浏览器支持的返回图像的长宽,红眼消除功能,以及补光模式

dictionary PhotoCapabilities {
  RedEyeReduction         redEyeReduction;
  MediaSettingsRange      imageHeight;
  MediaSettingsRange      imageWidth;
  sequence<FillLightMode> fillLightMode;
};
PhotoSetting

获取到相机能够提供的图像参数后,就可以设置需要的图像设置了

dictionary PhotoSettings {
  FillLightMode   fillLightMode;
  double          imageHeight;
  double          imageWidth;
  boolean         redEyeReduction;
};
MediaSettingsRange

图像能够提供的参数类型

dictionary MediaSettingsRange {
    double max;
    double min;
    double step;
};
RedEyeReduction
enum RedEyeReduction {
  "never",
  "always",
  "controllable"
};
FillLightMode
enum FillLightMode {
  "auto",
  "off",
  "flash"
};
MediaStreamTrack

这个是浏览器中关于音视频的一个重要api,它能够获取到当前浏览器下所有的支持的音视频设备,详细信息可以查看mdn,主要是能够提供关于视屏流的一些参数信息,接口如下:

  • MediaTrackCapabilities dictionary

partial dictionary MediaTrackCapabilities {
  sequence<DOMString>  whiteBalanceMode;
  sequence<DOMString>  exposureMode;
  sequence<DOMString>  focusMode;

  MediaSettingsRange   exposureCompensation;
  MediaSettingsRange   exposureTime;
  MediaSettingsRange   colorTemperature;
  MediaSettingsRange   iso;

  MediaSettingsRange   brightness;
  MediaSettingsRange   contrast;
  MediaSettingsRange   saturation;
  MediaSettingsRange   sharpness;

  MediaSettingsRange   focusDistance;
  MediaSettingsRange   pan;
  MediaSettingsRange   tilt;
  MediaSettingsRange   zoom;

  boolean              torch;
};
  • MediaTrackSettings dictionary
    调用getSetting()能够返回的设置信息

partial dictionary MediaTrackSettings {
  DOMString         whiteBalanceMode;
  DOMString         exposureMode;
  DOMString         focusMode;
  sequence<Point2D> pointsOfInterest;

  double            exposureCompensation;
  double            exposureTime;
  double            colorTemperature;
  double            iso;

  double            brightness;
  double            contrast;
  double            saturation;
  double            sharpness;

  double            focusDistance;
  double            pan;
  double            tilt;
  double            zoom;

  boolean           torch;
};
TakePhoto(PhotoSetting?)

调用该接口,会进行图像采集(拍照),如果不传递PhotoSetting,将会使用默认设置,如果传递上面设置的参数,相机将会拍出设置的图像,包含Exif信息(如果支持的话)-该方法能够实现全分辨率拍照

  • 如果成功,则会返回一个blob对象
demo

在这里插入图片描述

codepen

<html>
<body>
<video autoplay></video>
<img>
<div>
  <input id="pan" title="Pan" type="range" disabled />
  <label for="pan">Pan</label>
</div>
<div>
  <input id="tilt" title="Tilt" type="range" disabled />
  <label for="tilt">Tilt</label>
</div>
<div>
  <input id="zoom" title="Zoom" type="range" disabled />
  <label for="zoom">Zoom</label>
</div>
<script>
  let imageCapture;

  async function getMedia() {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: {pan: true, tilt: true, zoom: true},
      });
      const video = document.querySelector('video');
      video.srcObject = stream;

      const [track] = stream.getVideoTracks();
      imageCapture = new ImageCapture(track);

      const capabilities = track.getCapabilities();
      const settings = track.getSettings();

      for (const ptz of ['pan', 'tilt', 'zoom']) {
        // Check whether pan/tilt/zoom is available or not.
        if (!(ptz in settings)) continue;

        // Map it to a slider element.
        const input = document.getElementById(ptz);
        input.min = capabilities[ptz].min;
        input.max = capabilities[ptz].max;
        input.step = capabilities[ptz].step;
        input.value = settings[ptz];
        input.disabled = false;
        input.oninput = async event => {
          try {
            // Warning: Chrome requires advanced constraints.
            await track.applyConstraints({[ptz]: input.value});
          } catch (err) {
            console.error("applyConstraints() failed: ", err);
          }
        };
      }
    } catch (err) {
      console.error(err);
    }
  }

  async function takePhoto() {
    try {
      const blob = await imageCapture.takePhoto();
      console.log("Photo taken: " + blob.type + ", " + blob.size + "B");

      const image = document.querySelector('img');
      image.src = URL.createObjectURL(blob);
    } catch (err) {
      console.error("takePhoto() failed: ", err);
    }
  }
</script>
</body>
</html>

demo2 code pen

在这里插入图片描述

<html>
<body>
<canvas></canvas>
<button id="stopButton">Stop frame grab</button>
<script>
  async function grabFrames() {
    try {
      const canvas = document.querySelector('canvas');
      const video = document.querySelector('video');

      const stream = await navigator.mediaDevices.getUserMedia({video: true});
      video.srcObject = stream;
      const [track] = stream.getVideoTracks();
      try {
        const imageCapture = new ImageCapture(track);

        stopButton.onclick = () => track.stop();

        while (track.readyState == 'live') {
          const imgData = await imageCapture.grabFrame();
          canvas.width = imgData.width;
          canvas.height = imgData.height;
          canvas.getContext('2d').drawImage(imgData, 0, 0);
          await new Promise(r => setTimeout(r, 1000));
        }
      } finally {
        track.stop();
      }
    } catch (err) {
      console.error(err);
    }
  }
</script>
</body>
</html>

兼容性

推荐Chrome或者chromium内核的Edge浏览器使用
在这里插入图片描述

参考

网络视频编解码器指南
ImageCapture() constructor
MediaStreamTrack
CodePen Home
ImageCapture: Update camera pan, tilt and zoom and takePhoto()

ImageCapture: timed grabFrame()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值