MediaStream 图像捕获

W3C 工作草案,

更多关于本文档的详细信息
本版本:
https://www.w3.org/TR/2025/WD-image-capture-20250423/
最新发布版本:
https://www.w3.org/TR/image-capture/
编辑草稿:
https://w3c.github.io/mediacapture-image/
历史版本:
历史记录:
https://www.w3.org/standards/history/image-capture/
反馈:
public-webrtc@w3.org 主题行为 “[image-capture] … message topic …” (存档)
GitHub
编辑:
(Google LLC)
Rijubrata Bhaumik (英特尔公司)
前编辑:
Giridhar Mandyam (高通创新中心有限公司)
参与方式:
邮件列表
GitHub 仓库 (新建议, 开放建议)
实现情况:
实现状态
Image Capture 支持情况?
Polyfill:
GoogleChromeLabs/imagecapture-polyfill

摘要

本文档规定了用于产生照片图像捕获的方法和相机设置。图像的来源是,或可经由 MediaStreamTrack 引用。

本文档状态

本节描述了本文档在发布时的状态。当前 W3C 发布的文档及本技术报告的最新修订版可在 W3C 技术报告索引 https://www.w3.org/TR/ 查阅。

本文档由 Web 实时通信工作组 按照 推荐路线 作为工作草案发布。本文档旨在成为 W3C 推荐标准。

如需对本文档提出意见,请发送至 public-webrtc@w3.org (订阅, 存档)。 邮件发送时,请在主题中注明 “image-capture”,建议格式为: “[image-capture] …评论摘要…”。 欢迎所有意见。

作为工作草案发布并不意味着 W3C 及其成员的认可。本文档为草稿,可能随时被更新、替换或废止。不应将其引用为正式成果,只能视为正在进行的工作。

本文档由遵循 W3C 专利政策 的工作组制作。 W3C 维护着与本组交付物相关的 公开专利披露列表; 该页面也包含专利披露说明。 任何知晓自己所知专利包含 必要权利要求 的个人必须按照 W3C 专利政策第6节 披露相关信息。

本文档遵循 2023年11月3日 W3C 流程文档 管理。

1. 简介

本文件定义的 API 可通过有效的 MediaStreamTrack [GETUSERMEDIA] 引用摄影设备进行图像捕获。 生成的图像可以是 Blob (参见 takePhoto() 方法), 也可以是 ImageBitmap (参见 grabFrame())。

读取能力与设置及应用约束的方式取决于是否影响视频 MediaStreamTrack。 可通过 getPhotoCapabilities()/getPhotoSettings() 获取照片专用能力和当前设置,并通过 takePhoto() 方法的 PhotoSettings 参数进行配置。 而视频相关能力、当前设置和约束则通过 MediaStreamTrack 扩展机制操作。

2. 安全与隐私考量

隐私与安全考量中讨论的 [GETUSERMEDIA] 内容同样适用于本扩展规范。

此外,实施者应注意防止捕获图像泄露额外的隐私敏感数据。例如,将用户位置嵌入数字图像的元数据(如 EXIF)可能会泄漏超出用户预期的隐私信息。

3. 图像捕获 API

用户代理必须支持 Promise,以实现图像捕获 API。任何 Promise 对象均假定有一个解析器对象,并关联 resolve()reject() 方法。

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

   Promise<ImageBitmap>       grabFrame();

   readonly attribute MediaStreamTrack track;
};
takePhoto() 返回以 Blob 形式编码的捕获图像, 而 grabFrame() 返回 track 视频流的快照,形式为未编码的 ImageBitmap

3.1. 属性

track, 类型为 MediaStreamTrack,只读
构造函数中传入的 MediaStreamTrack

3.2. 方法

ImageCapture(MediaStreamTrack videoTrack)
参数 类型 可为空 可选 描述
videoTrack MediaStreamTrack 用于作为数据源的 MediaStreamTrack。 这将作为 track 属性的值。 传入构造函数的 MediaStreamTrackkind 属性必须设置为 "video",否则会抛出 DOMException,类型为 NotSupportedError
takePhoto(optional PhotoSettings photoSettings)
takePhoto() 使用视频捕获设备对 track 源进行单次曝光,并应用配置的 PhotoSettings,成功时返回编码后的 Blob 图像。调用此方法时,用户代理必须执行以下步骤:
  1. 如果构造函数中提供的 readyState 不为 live,则返回 一个被拒绝的 promise,并以 DOMException(名称为 InvalidStateError)拒绝,终止步骤。
  2. p 为一个新的 promise。
  3. 并行执行以下步骤:
    1. track 的底层源收集数据,应用指定的 photoSettings,并生成包含单张静态图像的 Blob。具体方法取决于底层设备。
      设备可暂时停止数据流,按需重新配置照片设置,拍照后再恢复流。此情况下,停止与恢复流应触发 onmuteonunmute 事件。
    2. 如果由于任何原因无法完成操作(如快速连续调用 takePhoto() 方法),则以 DOMException(名称为 UnknownError)拒绝 p,终止步骤。
    3. 用 Blob 对象解析 p
  4. 返回 p
参数 类型 可为空 可选 描述
settings PhotoSettings 要应用的 PhotoSettings 字典。
getPhotoCapabilities()
getPhotoCapabilities() 用于获取可用配置选项的范围(如有)。调用此方法时,用户代理必须执行以下步骤:
  1. 如果构造函数中提供的 readyState 不为 live,则返回 一个被拒绝的 promise,并以 DOMException(名称为 InvalidStateError)拒绝,终止步骤。
  2. p 为一个新的 promise。
  3. 并行执行以下步骤:
    1. track 收集数据,生成包含设备可用能力(包括范围)的 PhotoCapabilities 字典。具体方法取决于底层设备。
    2. 如果因任何原因无法收集数据(如 MediaStreamTrack 异步结束),则以 DOMException(名称为 OperationError)拒绝 p,终止步骤。
    3. PhotoCapabilities 字典解析 p
  4. 返回 p
getPhotoSettings()
getPhotoSettings() 用于获取当前配置设置的值(如有)。调用此方法时,用户代理必须执行以下步骤:
  1. 如果构造函数中提供的 readyState 不为 live,则返回 一个被拒绝的 promise,并以 DOMException(名称为 InvalidStateError)拒绝,终止步骤。
  2. p 为一个新的 promise。
  3. 并行执行以下步骤:
    1. track 收集数据,生成包含设备当前状态的 PhotoSettings 字典。具体方法取决于底层设备。
    2. 如果因任何原因无法收集数据(如 MediaStreamTrack 异步结束),则以 DOMException(名称为 OperationError)拒绝 p,终止步骤。
    3. PhotoSettings 字典解析 p
  4. 返回 p
grabFrame()
grabFrame()track 持有的实时视频进行快照,成功时返回 ImageBitmapgrabFrame() 仅在调用时返回一次数据。调用此方法时,用户代理必须执行以下步骤:
  1. 如果构造函数中提供的 readyState 不为 live,则返回 一个被拒绝的 promise,并以 DOMException(名称为 InvalidStateError)拒绝,终止步骤。
  2. p 为一个新的 promise。
  3. 并行执行以下步骤:
    1. track 收集数据,生成 ImageBitmap 对象。 该对象的 widthheight 来源于 track 的约束。
    2. 如果因任何原因无法完成操作(如快速连续调用 grabFrame()takePhoto()),则以 DOMException(名称为 UnknownError)拒绝 p,终止步骤。
    3. ImageBitmap 对象解析 p
  4. 返回 p

4. 照片能力(PhotoCapabilities)

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

4.1. 成员

redEyeReduction, 类型为 RedEyeReduction
来源的红眼消除能力。
imageHeight, 类型为 MediaSettingsRange
反映 UA 支持的图像高度范围。
imageWidth, 类型为 MediaSettingsRange
反映 UA 支持的图像宽度范围。
fillLightMode, 类型为 sequence<FillLightMode>
反映支持的补光模式(闪光灯)设置(如有)。
支持的分辨率以分离的 imageWidthimageHeight 范围呈现,以防止增加指纹识别面,并允许 UA 根据实际硬件配置做出最佳努力决策。

5. 照片设置(PhotoSettings)

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

5.1. 成员

redEyeReduction, 类型为 boolean
反映是否需要相机红眼消除
imageHeight, 类型为 double
反映期望的图像高度。如果 UA 支持离散高度选项,则必须选择最接近此设置的高度值。
imageWidth, 类型为 double
反映期望的图像宽度。如果 UA 支持离散宽度选项,则必须选择最接近此设置的宽度值。
fillLightMode, 类型为 FillLightMode
反映期望的补光模式(闪光灯)设置。

6. MediaSettingsRange

dictionary MediaSettingsRange {
    double max;
    double min;
    double step;
};

6.1. 成员

max, 类型为 double
该设置的最大值
min, 类型为 double
该设置的最小值
step, 类型为 double
该设置连续值之间的最小差值。

7. RedEyeReduction

enum RedEyeReduction {
    "never",
    "always",
    "controllable"
};

7.1. 取值

never
设备不支持红眼消除
always
设备支持红眼消除,且始终配置为 true。
controllable
设备支持红眼消除,且可通过 redEyeReduction 由用户控制。

8. FillLightMode

enum FillLightMode {
    "auto",
    "off",
    "flash"
};

8.1. 取值

auto
视频设备的补光灯将在需要时启用(通常为低光环境),否则关闭。注意 auto 并不保证在调用 takePhoto() 时闪光灯会触发。使用 flash 可保证 takePhoto() 方法时闪光灯触发。
off
来源的补光灯和/或闪光灯不会被使用。
flash
此值会始终在 takePhoto() 方法时触发闪光灯。

9. 扩展(Extensions)

本节定义了一组新的可约束属性, 可应用于 MediaStreamTrack ,以使其行为更适合拍照。通过 MediaStreamTrackgetCapabilities()getSettings()getConstraints()applyConstraints() 方法使用这些约束,将会修改 ImageCapture 对象的 track 行为。

9.1. MediaTrackSupportedConstraints 字典

MediaTrackSupportedConstraints 在此扩展了 UA 可识别用于控制照片能力的约束列表。可通过 MediaDevicesgetSupportedConstraints() 方法获取该字典。

partial dictionary MediaTrackSupportedConstraints {
    boolean whiteBalanceMode = true;
    boolean exposureMode = true;
    boolean focusMode = true;
    boolean pointsOfInterest = true;

    boolean exposureCompensation = true;
    boolean exposureTime = true;
    boolean colorTemperature = true;
    boolean iso = true;

    boolean brightness = true;
    boolean contrast = true;
    boolean pan = true;
    boolean saturation = true;
    boolean sharpness = true;
    boolean focusDistance = true;
    boolean tilt = true;
    boolean zoom = true;
    boolean torch = true;
};

9.1.1. 成员

whiteBalanceMode, 类型为 boolean,默认值为 true
是否识别白平衡模式约束。
colorTemperature, 类型为 boolean,默认值为 true
是否识别色温约束。
exposureMode, 类型为 boolean,默认值为 true
是否识别曝光约束。
exposureCompensation 类型为 boolean,默认值为 true
是否识别曝光补偿约束。
exposureTime, 类型为 boolean,默认值为 true
是否识别曝光时间约束。
iso, 类型为 boolean,默认值为 true
是否识别ISO约束。
focusMode, 类型为 boolean,默认值为 true
是否识别对焦模式约束。
pointsOfInterest, 类型为 boolean,默认值为 true
是否支持兴趣点
brightness, 类型为 boolean,默认值为 true
是否识别亮度约束。
contrast, 类型为 boolean,默认值为 true
是否识别对比度约束。
pan, 类型为 boolean,默认值为 true
是否识别平移约束。
saturation, 类型为 boolean,默认值为 true
是否识别饱和度约束。
sharpness, 类型为 boolean,默认值为 true
是否识别锐度约束。
focusDistance, 类型为 boolean,默认值为 true
是否识别对焦距离约束。
tilt, 类型为 boolean,默认值为 true
是否识别倾斜约束。
zoom, 类型为 boolean,默认值为 true
是否识别变焦级别的配置。
torch, 类型为 boolean,默认值为 true
是否识别手电筒的配置。

9.2. MediaTrackCapabilities 字典

MediaTrackCapabilities 在此扩展了图像捕获相关的能力。该字典由 UA 通过 getCapabilities() 生成,表示支持的约束的范围和枚举值。

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;

    sequence<boolean> torch;
};

9.2.1. 成员

whiteBalanceMode, 类型为 sequence<DOMString>
支持的白平衡模式序列。每个字符串必须是 MeteringMode 的成员之一。
colorTemperature, 类型为 MediaSettingsRange
该范围反映用于场景白平衡计算的支持的相关色温
exposureMode, 类型为 sequence<DOMString>
支持的曝光模式序列。每个字符串必须是 MeteringMode 的成员之一。
exposureCompensation, 类型为 MediaSettingsRange
反映支持的曝光补偿范围。支持范围通常以 0 EV 为中心。
exposureTime, 类型为 MediaSettingsRange
反映支持的曝光时间范围。值为数值型,值越大表示曝光时间越长。
iso, 类型为 MediaSettingsRange
反映允许的ISO值范围。
focusMode, 类型为 sequence<DOMString>
支持的对焦模式序列。每个字符串必须是 MeteringMode 的成员之一。
brightness, 类型为 MediaSettingsRange
反映相机亮度设置的支持范围。值为数值型,值越大表示亮度越高。
contrast, 类型为 MediaSettingsRange
反映支持的对比度范围。值为数值型,值越大表示对比度越高。
pan, 类型为 MediaSettingsRange
反映 UA 和 track 支持的平移值范围。

如果 track 创建时未请求使用权限(见 [permissions]), PermissionDescriptor 的 name 成员为 camerapanTiltZoom 成员为 true,或权限请求被拒绝,则 track 不支持平移。 UA 此时不得暴露平移值范围,但可以提供空的 MediaSettingsRange 字典以表示底层视频源支持平移

即使 UA 提供空的 MediaSettingsRange 字典以表示底层视频源支持平移倾斜变焦,只有在新的 getUserMedia() 调用后,返回包含支持平移倾斜变焦的视频 track 的 MediaStream 对象后,才能使用这些支持。
saturation, 类型为 MediaSettingsRange
反映允许的饱和度设置范围。值为数值型,值越大表示饱和度越高。
sharpness, 类型为 MediaSettingsRange
反映允许的锐度范围。值为数值型,值越大表示锐度越高,最小值总是表示无锐化增强或处理。
focusDistance, 类型为 MediaSettingsRange
反映 UA 支持的对焦距离值范围。
tilt, 类型为 MediaSettingsRange
反映 UA 和 track 支持的倾斜值范围。

如果 track 创建时未请求使用权限(见 [permissions]), PermissionDescriptor 的 name 成员为 camerapanTiltZoom 成员为 true,或权限请求被拒绝,则 track 不支持倾斜。 UA 此时不得暴露倾斜值范围,但可以提供空的 MediaSettingsRange 字典以表示底层视频源支持倾斜

zoom, 类型为 MediaSettingsRange
反映 UA 和 track 支持的变焦值范围。

如果 track 创建时未请求使用权限(见 [permissions]), PermissionDescriptor 的 name 成员为 camerapanTiltZoom 成员为 true,或权限请求被拒绝,则 track 不支持变焦。 UA 此时不得暴露变焦值范围,但可以提供空的 MediaSettingsRange 字典以表示底层视频源支持变焦

torch, 类型为 sequence<boolean>
如果来源无法打开手电筒,则只报告一个 false。 如果来源无法关闭手电筒,则只报告一个 true。 如果脚本可控制该功能,则来源会报告同时包含 truefalse 的列表作为可能值。

9.3. MediaTrackConstraintSet 字典

MediaTrackConstraintSet [GETUSERMEDIA] 字典既用于通过 getConstraints() 读取当前状态,也用于通过 applyConstraints() 应用约束集。

可通过 MediaTrackSettings 验证 UA 对请求的 MediaTrackConstraints 的应用效果。某些约束(如 变焦)可能不会立即生效。
partial dictionary MediaTrackConstraintSet {
    ConstrainDOMString           whiteBalanceMode;
    ConstrainDOMString           exposureMode;
    ConstrainDOMString           focusMode;
    ConstrainPoint2D             pointsOfInterest;

    ConstrainDouble              exposureCompensation;
    ConstrainDouble              exposureTime;
    ConstrainDouble              colorTemperature;
    ConstrainDouble              iso;

    ConstrainDouble              brightness;
    ConstrainDouble              contrast;
    ConstrainDouble              saturation;
    ConstrainDouble              sharpness;

    ConstrainDouble              focusDistance;
    (boolean or ConstrainDouble) pan;
    (boolean or ConstrainDouble) tilt;
    (boolean or ConstrainDouble) zoom;

    ConstrainBoolean             torch;
};

9.3.1. 成员

whiteBalanceMode, 类型为 ConstrainDOMString
该字符串必须是 MeteringMode 的成员之一。参见白平衡模式可约束属性。
exposureMode, 类型为 ConstrainDOMString
该字符串必须是 MeteringMode 的成员之一。参见曝光可约束属性。
focusMode, 类型为 ConstrainDOMString
该字符串必须是 MeteringMode 的成员之一。参见对焦模式可约束属性。
colorTemperature, 类型为 ConstrainDouble
参见色温可约束属性。
exposureCompensation, 类型为 ConstrainDouble
参见曝光补偿可约束属性。
exposureTime, 类型为 ConstrainDouble
参见曝光时间可约束属性。
iso, 类型为 ConstrainDouble
参见iso可约束属性。
pointsOfInterest, 类型为 ConstrainPoint2D
参见兴趣点可约束属性。
brightness, 类型为 ConstrainDouble
参见亮度可约束属性。
contrast, 类型为 ConstrainDouble
参见对比度可约束属性。
pan, 类型为 (boolean or ConstrainDouble)
参见平移可约束属性。
saturation, 类型为 ConstrainDouble
参见饱和度可约束属性。
sharpness, 类型为 ConstrainDouble
参见锐度可约束属性。
focusDistance, 类型为 ConstrainDouble
参见对焦距离可约束属性。
tilt, 类型为 (boolean or ConstrainDouble)
参见倾斜可约束属性。
zoom, 类型为 (boolean or ConstrainDouble)
参见变焦可约束属性。
torch, 类型为 ConstrainBoolean
参见手电筒可约束属性。

9.4. MediaTrackSettings 字典

当在视频流轨道上调用 getSettings() 方法时,用户代理必须返回扩展的 MediaTrackSettings 字典,表示底层用户代理的当前状态。

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;
};

9.4.1. 成员

whiteBalanceMode, of type DOMString
当前 white balance mode 设置。该字符串 MUST 是 MeteringMode 的成员之一。
exposureMode, of type DOMString
当前 exposure 模式设置。该字符串 MUST 是 MeteringMode 的成员之一。
colorTemperature, of type double
用于场景白平衡计算的色温。仅当 whiteBalanceModemanual 时,此字段才有意义。
exposureCompensation, of type double
当前 曝光补偿 设置。0 EV 表示没有曝光补偿。仅当 exposureModecontinuoussingle-shot 时,此字段才有意义。
exposureTime, of type double
当前 曝光时间 设置。仅当 exposureModemanual 时,此字段才有意义。
iso, of type double
当前相机的 ISO 设置。
focusMode, of type DOMString
当前 focus mode 设置。该字符串 MUST 是 MeteringMode 的成员之一。
pointsOfInterest, of type sequence<Point2D>
正在作为其他设置(例如聚焦、曝光和自动白平衡)的 关注点 使用的一系列 Point2D
brightness, of type double
反映相机当前的 亮度 设置。
contrast, of type double
反映相机当前的 对比度 设置。
pan, of type double
反映相机当前的 pan 设置。

如果在创建轨道时没有按照 请求使用权限(如文献 [permissions] 所定义)为其请求了一个 name 成员为 camera 且其 panTiltZoom 成员被设为 true,或者该权限请求被拒绝,则该轨道不支持 pan

在这种情况下,UA MUST NOT 暴露 pan 设置。

saturation, of type double
反映相机当前的 饱和度 设置。
sharpness, of type double
反映相机当前的 锐度 设置。
focusDistance, of type double
反映相机当前的 对焦距离 设置。
tilt, of type double
反映相机当前的 tilt 设置。

如果在创建轨道时没有按照 请求使用权限(如文献 [permissions] 所定义)为其请求了一个 name 成员为 camera 且其 panTiltZoom 成员被设为 true,或者该权限请求被拒绝,则该轨道不支持 tilt。 在这种情况下,UA MUST NOT 暴露 tilt 设置。

zoom, of type double
反映相机当前的 zoom 设置。

如果在创建轨道时没有按照 请求使用权限(如文献 [permissions] 所定义)为其请求了一个 name 成员为 camera 且其 panTiltZoom 成员被设为 true,或者该权限请求被拒绝,则该轨道不支持 zoom

在这种情况下,UA MUST NOT 暴露 zoom 设置。

torch, of type boolean
当前相机的 torch 配置设置。

9.5. 附加可约束属性

dictionary ConstrainPoint2DParameters {
  sequence<Point2D> exact;
  sequence<Point2D> ideal;
};

typedef (sequence<Point2D> or ConstrainPoint2DParameters) ConstrainPoint2D;

9.5.1. 成员

exact, of type sequence<Point2D>
所需的 关注点 的精确值。
ideal, of type sequence<Point2D>
关注点 的理想(目标)值。

10. 照片能力及可约束属性

上述许多照片和视频能力反映了难以明确定义的硬件特性,因为它们可以通过多种方式实现。此外,厂商通常会发布模糊的定义以保护其知识产权。
这些照片能力和可约束属性的名称均不在设备选择的允许必需约束列表中。 因此,在 getUserMedia() 中, 这些照片能力和可约束属性只能使用可选基本约束高级约束进行约束,而不能使用必需约束
  1. 白平衡模式 是相机用来针对不同色温进行调整的设置。 色温 指背景光的色温(通常以开尔文计)。该设置通常由实现自动且连续地确定,但也常见提供一种 manual 模式,在该模式下场景照明的估计色温作为提示传递给实现。常见模式的典型温度范围如下:
    模式 开尔文范围
    incandescent 2500-3500
    fluorescent 4000-5000
    warm-fluorescent 5000-5500
    daylight 5500-6500
    cloudy-daylight 6500-8000
    twilight 8000-9000
    shade 9000-10000
  2. 曝光 指允许落在感光元件上的光量。在自动曝光模式下(single-shotcontinuousexposureMode), 曝光时间和/或相机光圈会由实现根据拍摄主体自动调整。在 manualexposureMode 中, 这些参数被设置为固定的绝对值。
  3. 对焦模式 描述捕获设备的对焦设置(例如 automanual)。
  4. 关注点 描述在其他设置中使用的测光区域中心,例如 曝光白平衡模式对焦模式,每个关注点都是一个 Point2D (通常这三个控制由所谓的 3A 算法同时修改:自动对焦、自动曝光、自动白平衡)。

    A Point2D 点的关注点被解释为在归一化方形空间内的像素位置({x,y} &isin; [0.0, 1.0])。坐标原点 {x,y} = {0.0, 0.0} 表示左上角,而 {x,y} = {1.0, 1.0} 表示右下角:x 坐标(列)向右增加,y 坐标(行)向下增加。超出上述范围的值将被夹取到最接近的允许值。

  5. 曝光补偿 是一个数值相机设置,用于将曝光级别相对于实现当前使用的值进行调整。该值可用于偏置自动曝光启用的曝光级别,通常围绕 0 EV(无补偿)对称。该值仅在 single-shotcontinuousexposureMode 中使用。
  6. 曝光时间 是一个数值相机设置,用于控制允许光照射到感光元件的时间长度。该值在 manualexposureMode 中用于控制曝光。该值以 100 微秒为单位。也就是说,值为 1.0 表示 1/10000 秒的曝光时间,值为 10000.0 表示 1 秒的曝光时间。
  7. 相机的 ISO 设置描述了相机对光的灵敏度。它是一个数值,值越低灵敏度越高。该值应遵循 [iso12232] 标准。
  8. 红眼减少 是相机中的一项功能,旨在限制或防止由于相机闪光灯的瞬时强光导致拍摄对象出现红色瞳孔(“红眼”)的现象。
  9. [LIGHTING-VOCABULARY]亮度 定义为“视觉感受的属性,根据该属性某一区域看起来发出更多或更少的光”,在本 API 的上下文中,它指相机的数值设置,用于调整照片对象所感知的发光量。较高的亮度设置会增加场景中较暗区域的强度,同时压缩场景中较亮部分的强度。此设置的范围和效果依赖于实现,但通常它会转换为添加到每个像素上的数值并进行饱和处理。
  10. 对比度 是控制场景中明暗区域亮度差异的数值相机设置。较高的对比度表示亮度差异的扩大。此设置的范围和效果依赖于实现,但可以将其理解为对像素值进行变换以使直方图中的亮度范围变大;该变换有时简单为一个增益因子。
  11. [LIGHTING-VOCABULARY]饱和度 定义为“与其亮度成比例判断的区域色彩度”,在此上下文中指控制场景中色彩强度(即场景中灰度的多少)的数值相机设置。非常低的饱和度会导致更接近黑白的照片。饱和度类似于对比度,但针对颜色,因此其实现(尽管依赖于平台)可被理解为应用于图像色度分量的增益因子。
  12. 锐度 是控制场景中边缘强度的数值相机设置。较高的锐度设置会提高边缘处的对比度,而较低的设置则导致较小的对比度和更模糊的边缘(即浅焦)。实现依赖于平台,但可以将其理解为对原始图像应用边缘检测操作并与原始图像线性组合;相对权重由此锐度 控制。
    亮度对比度饱和度锐度[UVC] 中有规范。
  13. 图像宽度图像高度 表示在可能的传感器校正和其他算法运行后生成照片的支持/期望分辨率。
    支持的分辨率是分开管理的,例如 imageWidthimageHeight 的值/范围分开管理,以防止增加指纹识别表面,并允许 UA 根据实际硬件配置对请求的约束做出尽力而为的决定。
  14. 对焦距离 是一个数值相机设置,用于控制镜头的对焦距离。该设置通常以米为单位表示到最佳对焦距离的距离。
  15. 平移(Pan) 是控制相机平移的数值设置。该设置表示以角秒为单位的平移量,角秒为度的 1/3600。取值范围为 -180*3600 到 +180*3600 角秒。正值表示从上方视角顺时针平移相机,负值表示从上方视角逆时针平移相机。

    对 pan 的约束通过对具有平移能力的相机的适配距离(fitness distance)影响相机选择。为了在不覆盖当前平移设置的情况下施加这种影响,可以将 pan 约束为 true。相反,将其约束为 false 会不利于具有平移能力的相机。

    任何使用包含其 MediaTrackConstraintSet 对象且该对象的 pan 字典成员存在且其值不是 false 的算法,必须要么请求使用权限(按 [permissions] 定义)——请求一个其 name 成员被设为 camera 且其 panTiltZoom 成员被设为 true 的 PermissionDescriptor, 或决定不暴露 pan 设置。

    如果顶层浏览上下文的 visibilityState 为 "hidden",则当 applyConstraints() 算法遇到 pan 字典成员存在且其值不是 false 时,必须抛出一个 SecurityError

  16. 俯仰(Tilt) 是控制相机俯仰的数值设置。该设置以角秒为单位表示俯仰,角秒为度的 1/3600。取值范围为 -180*3600 到 +180*3600 角秒。正值在从正面观察时使相机向上俯仰,负值在从正面观察时使相机向下俯仰。

    对 tilt 的约束通过对具有俯仰能力的相机的适配距离(fitness distance)影响相机选择。为了在不覆盖当前俯仰设置的情况下施加这种影响,可以将 tilt 约束为 true。相反,将其约束为 false 会不利于具有俯仰能力的相机。

    任何使用包含其 MediaTrackConstraintSet 对象且该对象的 tilt 字典成员存在且其值不是 false 的算法,必须要么请求使用权限(按 [permissions] 定义)——请求一个其 name 成员被设为 camera 且其 panTiltZoom 成员被设为 true 的 PermissionDescriptor, 或决定不暴露 tilt 设置。

    如果顶层浏览上下文的 visibilityState 为 "hidden",则当 applyConstraints() 算法遇到 tilt 字典成员存在且其值不是 false 时,必须抛出一个 SecurityError

    应用 pantilt 时没有定义的顺序,UA 可以以任意顺序应用它们。实际上这通常无关紧要,因为这些值是绝对的,顺序不会影响最终位置。但如果应用 pan 和 tilt 的速度足够慢,应用顺序可能会在视觉上变得明显。
  17. 变焦(Zoom) 是控制镜头焦距的数值相机设置。该设置通常表示一个比率,例如 4 表示 4:1 的变焦比。最小值通常为 1,表示 1:1 比率(即无变焦)。

    对 zoom 的约束通过对具有变焦能力的相机的适配距离(fitness distance)影响相机选择。为了在不覆盖当前变焦设置的情况下施加这种影响,可以将 zoom 约束为 true。相反,将其约束为 false 会不利于具有变焦能力的相机。

    任何使用包含其 MediaTrackConstraintSet 对象且该对象的 zoom 字典成员存在且其值不是 false 的算法,必须要么请求使用权限(按 [permissions] 定义)——请求一个其 name 成员被设为 camera 且其 panTiltZoom 成员被设为 true 的 PermissionDescriptor, 或决定不暴露 zoom 设置。

    如果顶层浏览上下文的 visibilityState 为 "hidden",则当 applyConstraints() 算法遇到 zoom 字典成员存在且其值不是 false 时,必须抛出一个 SecurityError

  18. 补光模式 描述捕获设备的闪光灯设置(例如 autooffon)。 手电(Torch) 描述该光源的补光灯作为持续连接的设置,只要 track 处于活动状态时保持点亮。

11. MeteringMode

enum MeteringMode {
  "none",
  "manual",
  "single-shot",
  "continuous"
};

11.1. 取值

none
该来源不提供对焦/曝光/白平衡模式。设置为此值时,表示关闭该功能。
manual
捕获设备设置为手动控制镜头位置/曝光时间/白平衡,或请求配置为此模式。
single-shot
捕获设备配置为单次自动对焦/单次曝光/单次白平衡计算,或请求配置为此模式。
continuous
捕获设备配置为连续对焦以实现近零快门延迟/连续自动曝光/连续白平衡计算,或请求配置为此连续对焦/曝光/白平衡计算模式。

12. Point2D

Point2D 表示二维空间中的一个位置。坐标原点位于空间的左上角。

dictionary Point2D {
  double x = 0.0;
  double y = 0.0;
};

12.1. 成员

x, 类型为 double, 默认值为 0.0
水平(横坐标)值。
y, 类型为 double, 默认值为 0.0
垂直(纵坐标)值。

13. 示例

这些示例的略微修改版本可在 此 codepen 集合中找到。

13.1. 更新摄像头的平移、俯仰和变焦,并调用 takePhoto()

下列示例也可在 此 codepen中找到,几乎无修改。
<html>
<body>
<video autoplay></video>
<img>
<div>
  <input id="pan" title="Pan" type="range" disabled />
  <label for="pan">平移</label>
</div>
<div>
  <input id="tilt" title="Tilt" type="range" disabled />
  <label for="tilt">俯仰</label>
</div>
<div>
  <input id="zoom" title="Zoom" type="range" disabled />
  <label for="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']) {
        // 检查是否支持平移/俯仰/变焦。
        if (!(ptz in settings)) continue;

        // 映射到滑块控件。
        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 {
            // 注意:Chrome 需要使用高级约束。
            await track.applyConstraints({[ptz]: input.value});
          } catch (err) {
            console.error("applyConstraints() 失败: ", err);
          }
        };
      }
    } catch (err) {
      console.error(err);
    }
  }

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

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

13.2. 使用 grabFrame() 重复抓取帧

下列示例也可在 此 codepen中找到,几乎无修改。
<html>
<body>
<canvas></canvas>
<button id="stopButton">停止抓帧</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>

13.3. 抓取帧并进行后处理

下列示例也可在 此 codepen中找到,几乎无修改。
<html>
<body>
<canvas></canvas>
<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);
        const imageBitmap = await imageCapture.grabFrame();

        // |imageBitmap| 的像素无法直接访问:需先绘制到 <canvas>,再用 getImageData() 读取。
        const ctx = canvas.getContext('2d');
        canvas.width = imageBitmap.width;
        canvas.height = imageBitmap.height;
        ctx.drawImage(imageBitmap, 0, 0);

        // 从 <canvas> 读取像素并反转颜色。
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

        const data = imageData.data;
        for (let i = 0; i < data.length; i += 4) {
          data[i] ^= 255;     // 红色
          data[i + 1] ^= 255; // 绿色
          data[i + 2] ^= 255; // 蓝色
        }
        // 最后将反色图像绘制到 <canvas>
        ctx.putImageData(imageData, 0, 0);
      } finally {
        track.stop();
      }
    } catch (err) {
      console.error(err);
    }
  }
</script>
</body>
</html>

13.4. 更新摄像头对焦距离并调用 takePhoto()

<html>
<body>
<video autoplay></video>
<img>
<input type="range" hidden>
<script>
  let imageCapture;

  async function getMedia() {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({video: 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();

      // 检查是否支持对焦距离。
      if (!capabilities.focusDistance) {
        return;
      }

      // 映射对焦距离到滑块控件。
      const input = document.querySelector('input[type="range"]');
      input.min = capabilities.focusDistance.min;
      input.max = capabilities.focusDistance.max;
      input.step = capabilities.focusDistance.step;
      input.value = settings.focusDistance;
      input.oninput = async event => {
        try {
          await track.applyConstraints({
            focusMode: "manual",
            focusDistance: input.value
          });
        } catch (err) {
          console.error("applyConstraints() 失败: ", err);
        }
      };
      input.parentElement.hidden = false;
    } catch (err) {
      console.error(err);
    }
  }

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

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

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语的组合表达。 规范性部分中的关键词 “MUST”(必须)、“MUST NOT”(禁止)、“REQUIRED”(要求)、“SHALL”(应)、“SHALL NOT”(不得)、“SHOULD”(应该)、“SHOULD NOT”(不应)、“RECOMMENDED”(推荐)、“MAY”(可以)、“OPTIONAL”(可选) 应按照 RFC 2119 的说明进行解释。 但为了可读性,本规范未将这些词全部大写。

除明确标记为非规范性、示例和注释的章节外,本规范的所有文本均为规范性内容。[RFC2119]

本规范中的示例以 “例如” 开头,或通过 class="example" 与规范性文本区分, 如下所示:

这是一个信息性示例。

信息性注释以 “注意” 开头,并通过 class="note" 与规范性文本区分, 如下所示:

注意,这是一个信息性注释。

一致性算法

作为算法一部分的命令式要求(如 “去除所有前导空格字符” 或 “返回 false 并终止这些步骤”), 应根据引入算法时所用关键词(“must”、“should”、“may”等)进行解释。

以算法或具体步骤表述的一致性要求可以以任何方式实现, 只要最终结果等效即可。 特别地,本规范中定义的算法旨在易于理解,并非为了高性能。 鼓励实现者进行优化。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[FileAPI]
Marijn Kruisselbrink. File API. 2024年12月4日. WD. URL: https://www.w3.org/TR/FileAPI/
[GETUSERMEDIA]
Cullen Jennings 等. Media Capture and Streams. 2024年12月19日. CRD. URL: https://www.w3.org/TR/mediacapture-streams/
[HTML]
Anne van Kesteren 等. HTML Standard. 活标准. URL: https://html.spec.whatwg.org/multipage/
[PERMISSIONS]
Marcos Caceres; Mike Taylor. Permissions. 2024年12月20日. WD. URL: https://www.w3.org/TR/permissions/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. 活标准. URL: https://webidl.spec.whatwg.org/

信息性引用

[ISO12232]
摄影 - 数码静态相机 - 曝光指数、ISO速度等级、标准输出灵敏度和推荐曝光指数的测定. 2006年4月15日. URL: http://www.iso.org/iso/catalogue_detail.htm?csnumber=37777
[LIGHTING-VOCABULARY]
CIE 国际照明词汇:IEC 国际电工词汇。. 1987年12月15日.
[UVC]
USB 视频设备类定义. 2012年8月9日. URL: http://www.usb.org/developers/docs/devclass_docs/

IDL 索引

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

   Promise<ImageBitmap>       grabFrame();

   readonly attribute MediaStreamTrack track;
};

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

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

dictionary MediaSettingsRange {
    double max;
    double min;
    double step;
};

enum RedEyeReduction {
  "never",
  "always",
  "controllable"
};

enum FillLightMode {
  "auto",
  "off",
  "flash"
};

partial dictionary MediaTrackSupportedConstraints {
  boolean whiteBalanceMode = true;
  boolean exposureMode = true;
  boolean focusMode = true;
  boolean pointsOfInterest = true;

  boolean exposureCompensation = true;
  boolean exposureTime = true;
  boolean colorTemperature = true;
  boolean iso = true;

  boolean brightness = true;
  boolean contrast = true;
  boolean pan = true;
  boolean saturation = true;
  boolean sharpness = true;
  boolean focusDistance = true;
  boolean tilt = true;
  boolean zoom = true;
  boolean torch = true;
};

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;

  sequence<boolean> torch;
};

partial dictionary MediaTrackConstraintSet {
  ConstrainDOMString           whiteBalanceMode;
  ConstrainDOMString           exposureMode;
  ConstrainDOMString           focusMode;
  ConstrainPoint2D             pointsOfInterest;

  ConstrainDouble              exposureCompensation;
  ConstrainDouble              exposureTime;
  ConstrainDouble              colorTemperature;
  ConstrainDouble              iso;

  ConstrainDouble              brightness;
  ConstrainDouble              contrast;
  ConstrainDouble              saturation;
  ConstrainDouble              sharpness;

  ConstrainDouble              focusDistance;
  (boolean or ConstrainDouble) pan;
  (boolean or ConstrainDouble) tilt;
  (boolean or ConstrainDouble) zoom;

  ConstrainBoolean             torch;
};

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;
};

dictionary ConstrainPoint2DParameters {
  sequence<Point2D> exact;
  sequence<Point2D> ideal;
};

typedef (sequence<Point2D> or ConstrainPoint2DParameters) ConstrainPoint2D;

enum MeteringMode {
  "none",
  "manual",
  "single-shot",
  "continuous"
};

dictionary Point2D {
  double x = 0.0;
  double y = 0.0;
};