1. 8.10 图片
    2. 8.11 动画帧

8.10 图片

ImageBitmap

所有当前引擎均支持。

Firefox42+Safari15+Chrome50+
Opera?Edge79+
Edge (传统)?Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
[Exposed=(Window,Worker), Serializable, Transferable]
interface ImageBitmap {
  readonly attribute unsigned long width;
  readonly attribute unsigned long height;
  undefined close();
};

typedef (CanvasImageSource or
         Blob or
         ImageData) ImageBitmapSource;

enum ImageOrientation { "from-image", "flipY" };
enum PremultiplyAlpha { "none", "premultiply", "default" };
enum ColorSpaceConversion { "none", "default" };
enum ResizeQuality { "pixelated", "low", "medium", "high" };

dictionary ImageBitmapOptions {
  ImageOrientation imageOrientation = "from-image";
  PremultiplyAlpha premultiplyAlpha = "default";
  ColorSpaceConversion colorSpaceConversion = "default";
  [EnforceRange] unsigned long resizeWidth;
  [EnforceRange] unsigned long resizeHeight;
  ResizeQuality resizeQuality = "low";
};

一个 ImageBitmap 对象表示一个可以绘制到画布上的位图图像,而不会造成过度的延迟。

对什么算过度延迟的具体判断留给实现者,但一般来说,如果使用位图需要网络 I/O,甚至本地磁盘 I/O,那么延迟很可能过大;而如果它只需要从 GPU 或系统 RAM 中进行阻塞读取,那么延迟很可能可以接受。

promise = self.createImageBitmap(image [, options ])

createImageBitmap

所有当前引擎均支持。

Firefox42+Safari15+Chrome50+
Opera?Edge79+
Edge (传统)?Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?
promise = self.createImageBitmap(image, sx, sy, sw, sh [, options ])

接收 image,它可以是 img 元素、SVG image 元素、video 元素、canvas 元素、Blob 对象、ImageData 对象或另一个 ImageBitmap 对象,并返回一个在创建新的 ImageBitmap 时被解析的 promise。

如果无法构建 ImageBitmap 对象,例如提供的 image 数据实际上不是图像,则 promise 会被拒绝。

如果提供了 sxsyswsh 参数,则源图像会被裁剪到给定的像素,任何原始图像中缺失的像素都会被 透明黑色 替换。这些坐标位于源图像的像素坐标空间中,而不是 CSS 像素 中。

如果提供了 options,则 ImageBitmap 对象的位图数据会根据 options 进行修改。例如,如果 premultiplyAlpha 选项被设置为 "premultiply",则 位图数据 的颜色通道会 与其 alpha 通道相乘

如果源图像处于无效状态(例如,尚未成功加载的 img 元素、其 [[Detached]] 内部槽值 为 true 的 ImageBitmap 对象、其 data 属性值的 [[ViewedArrayBuffer]] 内部槽已分离的 ImageData 对象,或数据无法解释为位图图像的 Blob),则使用 "InvalidStateError" DOMException 拒绝 promise。

如果脚本无法访问源图像的图像数据(例如,CORS 跨域video,或来自不同 的 worker 中脚本绘制的 canvas),则使用 "SecurityError" DOMException 拒绝 promise。

imageBitmap.close()

ImageBitmap/close

所有当前引擎均支持。

Firefox46+Safari15+Chrome52+
Opera37+Edge79+
Edge (传统)?Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android37+

释放 imageBitmap 的底层 位图数据

imageBitmap.width

ImageBitmap/width

所有当前引擎均支持。

Firefox42+Safari15+Chrome50+
Opera?Edge79+
Edge (传统)?Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

返回图像的 自然宽度,单位为 CSS 像素

imageBitmap.height

ImageBitmap/height

所有当前引擎均支持。

Firefox42+Safari15+Chrome50+
Opera?Edge79+
Edge (传统)?Internet Explorer不支持
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

返回图像的 自然高度,单位为 CSS 像素

[[Detached]] 内部槽值 为 false 的 ImageBitmap 对象始终具有关联的 位图数据,并具有宽度和高度。但是,这些数据可能会损坏。如果 ImageBitmap 对象的媒体数据可以在没有错误的情况下解码,则称其为 完全可解码

ImageBitmap 对象的位图具有一个 origin-clean 标志,该标志指示位图是否被来自不同 的内容污染。该标志最初设置为 true,可能由 createImageBitmap() 的步骤更改为 false。


ImageBitmap 对象是 可序列化对象 也是 可传输对象

给定 valueserialized,它们的 序列化步骤

  1. 如果 valueorigin-clean 标志未设置,则抛出 "DataCloneError" DOMException

  2. serialized.[[BitmapData]] 设置为 value位图数据 的副本。

给定 serializedvaluetargetRealm,它们的 反序列化步骤

  1. value位图数据 设置为 serialized.[[BitmapData]]。

给定 valuedataHolder,它们的 传输步骤

  1. 如果 valueorigin-clean 标志未设置,则抛出 "DataCloneError" DOMException

  2. dataHolder.[[BitmapData]] 设置为 value位图数据

  3. 取消设置 value位图数据

给定 dataHoldervalue,它们的 传输接收步骤

  1. value位图数据 设置为 dataHolder.[[BitmapData]]。


当调用 createImageBitmap(image, options)createImageBitmap(image sx, sy, sw, sh, options) 方法时,必须运行以下步骤

  1. 如果提供了 swsh 且值为 0,则返回 使用 RangeError 拒绝的 promise

  2. 如果提供了 optionsresizeWidthoptionsresizeHeight 且值为 0,则返回 使用 "InvalidStateError" DOMException 拒绝的 promise

  3. 检查 image 参数的可用性。如果这抛出异常或返回 bad,则返回 使用 "InvalidStateError" DOMException 拒绝的 promise

  4. p 为一个新的 promise。

  5. imageBitmap 为一个新的 ImageBitmap 对象。

  6. 根据 image 进行切换

    img
    SVG image
    1. 如果 image 的媒体数据没有 自然尺寸(例如,它是一个没有指定内容大小的矢量图形)且 optionsresizeWidthoptionsresizeHeight 未提供,则返回 使用 "InvalidStateError" DOMException 拒绝的 promise

    2. 如果 image 的媒体数据没有 自然尺寸(例如,它是一个没有指定内容大小的矢量图形),它应该被渲染为一个大小由 resizeWidthresizeHeight 选项指定的位图。

    3. imageBitmap位图数据 设置为 image 的媒体数据的副本,裁剪到带有格式的源矩形。如果这是一个动画图像,imageBitmap位图数据 只能从动画的默认图像(格式定义的图像在不支持或禁用动画时使用)中获取,或者,如果没有这样的图像,则从动画的第一帧获取。

    4. 如果 image 不是 origin-clean,则将 imageBitmap 的位图的 origin-clean 标志设置为 false。

    5. 并行运行此步骤 in parallel

      1. p 解析为 imageBitmap

    video
    1. 如果 imagenetworkState 属性为 NETWORK_EMPTY,则返回 一个被拒绝的 promise,并附带 "InvalidStateError" DOMException

    2. imageBitmap位图数据 设置为当前播放位置处的帧的副本,在 媒体资源自然宽度自然高度(即,在应用任何纵横比校正之后),裁剪到带有格式的源矩形

    3. 如果 image 不是 origin-clean,则将 imageBitmap 的位图的 origin-clean 标志设置为 false。

    4. 并行运行此步骤 in parallel

      1. p 解析为 imageBitmap

    canvas
    1. imageBitmap位图数据 设置为 image位图数据 的副本,裁剪到带有格式的源矩形

    2. imageBitmap 的位图的 origin-clean 标志设置为与 image 的位图的 origin-clean 标志相同的值。

    3. 并行运行此步骤 in parallel

      1. p 解析为 imageBitmap

    Blob

    并行运行以下步骤 in parallel

    1. imageData 设置为读取 image 数据的结果。如果在读取对象时 发生错误,则使用 "InvalidStateError" DOMException 拒绝 p 并中止以下步骤。

    2. 应用 图像嗅探规则 来确定 imageData 的文件格式,使用 image 的 MIME 类型(由 imagetype 属性给出)给出官方类型。

    3. 如果 imageData 不在受支持的图像文件格式中(例如,它根本不是图像),或者如果 imageData 以某种致命方式损坏,以至于无法获得图像尺寸(例如,没有自然大小的矢量图形),则使用 "InvalidStateError" DOMException 拒绝 p 并中止以下步骤。

    4. imageBitmap位图数据 设置为 imageData裁剪到带有格式的源矩形。如果这是一个动画图像,imageBitmap位图数据 只能从动画的默认图像(格式定义的图像在不支持或禁用动画时使用)中获取,或者,如果没有这样的图像,则从动画的第一帧获取。

    5. p 解析为 imageBitmap

    ImageData
    1. buffer 设置为 imagedata 属性值的 [[ViewedArrayBuffer]] 内部槽。

    2. 如果 IsDetachedBuffer(buffer) 为 true,则返回 一个被拒绝的 promise,并附带 "InvalidStateError" DOMException

    3. imageBitmap位图数据 设置为 image 的图像数据,裁剪到带有格式的源矩形

    4. 并行运行此步骤 in parallel

      1. p 解析为 imageBitmap

    ImageBitmap
    1. imageBitmap位图数据 设置为 image位图数据 的副本,裁剪到带有格式的源矩形

    2. imageBitmap 的位图的 origin-clean 标志设置为与 image 的位图的 origin-clean 标志相同的值。

    3. 并行运行此步骤 in parallel

      1. p 解析为 imageBitmap

    VideoFrame
    1. imageBitmap位图数据 设置为 image 的可见像素数据的副本,裁剪到带有格式的源矩形

    2. 并行运行此步骤 in parallel

      1. p 解析为 imageBitmap

  7. 返回 p

当上述步骤要求用户代理 将位图数据裁剪到带有格式的源矩形 时,用户代理必须运行以下步骤

  1. input 设置为正在转换的 位图数据

  2. 如果指定了 sxsyswsh,则将 sourceRectangle 设置为一个矩形,其角点是四个点 (sx, sy)、(sx+sw, sy)、(sx+sw, sy+sh)、(sx, sy+sh)。否则,将 sourceRectangle 设置为一个矩形,其角点是四个点 (0, 0)、( input 的宽度, 0)、( input 的宽度, input 的高度)、(0, input 的高度)。

    如果 swsh 为负,则该矩形的左上角将位于 (sx, sy) 点的左侧或上方。

  3. outputWidth 确定如下

    如果 optionsresizeWidth 成员已指定
    optionsresizeWidth 成员的值
    如果 optionsresizeWidth 成员未指定,但 optionsresizeHeight 成员已指定
    sourceRectangle 的宽度乘以 optionsresizeHeight 成员的值,除以 sourceRectangle 的高度,向上取整到最近的整数
    如果 optionsresizeWidthresizeHeight 都未指定
    sourceRectangle 的宽度
  4. outputHeight 确定如下

    如果 optionsresizeHeight 成员已指定
    optionsresizeHeight 成员的值
    如果 optionsresizeHeight 成员未指定,但 optionsresizeWidth 成员已指定
    sourceRectangle 的高度乘以 optionsresizeWidth 成员的值,除以 sourceRectangle 的宽度,向上取整到最近的整数
    如果 optionsresizeWidthresizeHeight 都未指定
    sourceRectangle 的高度
  5. input 放置在一个无限的 透明黑色 网格平面上,定位使其左上角位于平面的原点,x 坐标向右增加,y 坐标向下增加,并且 input 图像数据中的每个像素都占据平面上网格的一个单元。

  6. output 设置为平面上由 sourceRectangle 表示的矩形。

  7. output 缩放为 outputWidthoutputHeight 指定的大小。用户代理应该使用 resizeQuality 选项的值来指导缩放算法的选择。

  8. 如果 optionsimageOrientation 成员的值为 "flipY",则必须垂直翻转 output,不考虑任何源的图像方向元数据(例如 EXIF 元数据),如果有的话。 [EXIF]

    如果该值为 "from-image",则不需要额外的步骤。

    曾经存在一个 "none" 枚举值。它已重命名为 "from-image"。将来,"none" 将以不同的含义添加回来。

  9. 如果 image 是一个 img 元素或一个 Blob 对象,则将 val 设置为 optionscolorSpaceConversion 成员的值,然后运行以下子步骤

    1. 如果 val 为 "default",颜色空间转换行为由实现决定,应根据实现用于将图像绘制到画布上的默认颜色空间进行选择。

    2. 如果 val 为 "none",则必须在不执行任何颜色空间转换的情况下解码 output。这意味着图像解码算法必须忽略嵌入在源数据中的颜色配置文件元数据以及显示设备颜色配置文件。

  10. valoptionspremultiplyAlpha 成员的值,然后执行以下子步骤

    1. 如果 val 为 "default",则 alpha 预乘行为由实现决定,应根据实现认为最适合将图像绘制到画布上的方式进行选择。

    2. 如果 val 为 "premultiply",则未预乘 alpha 的 output 必须将其颜色分量 乘以 alpha,而预乘 alpha 的 output 必须保持不变。

    3. 如果 val 为 "none",则未预乘 alpha 的 output 必须保持不变,而预乘 alpha 的 output 必须将其颜色分量 除以 alpha

  11. 返回 output

以下为 close() 方法的步骤

  1. this[[Detached]] 内部槽位的值设置为 true。

  2. 取消 this位图数据

以下为 width 获取器的步骤

  1. 如果 this[[Detached]] 内部槽位的值为 true,则返回 0。

  2. 返回 this 的宽度,以 CSS 像素 为单位。

以下为 height 获取器的步骤

  1. 如果 this[[Detached]] 内部槽位的值为 true,则返回 0。

  2. 返回 this 的高度,以 CSS 像素 为单位。

ResizeQuality 枚举用于表达对缩放图像时使用的插值质量的偏好。

值 "pixelated" 表示对尽可能保留原始图像像素化的缩放图像的偏好,并根据需要进行少量平滑以避免在目标大小不是原始大小的整倍数时扭曲图像。

为了实现 "pixelated",对于每个轴独立地,首先确定其自然大小的整倍数,该整倍数使其最接近目标大小,并且大于零。使用最近邻将其缩放至此整倍数大小,然后使用双线性插值将其缩放至剩余的目标大小。

值 "low" 表示对较低图像插值质量的偏好。与更高设置相比,低质量图像插值可能在计算上更有效。

值 "medium" 表示对中等图像插值质量的偏好。

值 "high" 表示对较高图像插值质量的偏好。与较低设置相比,高质量图像插值可能在计算上更昂贵。

双线性缩放是相对较快、较低质量的图像平滑算法的示例。双三次或兰索斯缩放是生成更高质量输出的图像缩放算法的示例。本规范不强制要求使用特定的插值算法,除了上述 "pixelated"。

使用此 API,可以预切割和准备精灵图

var sprites = {};
function loadMySprites() {
  var image = new Image();
  image.src = 'mysprites.png';
  var resolver;
  var promise = new Promise(function (arg) { resolver = arg });
  image.onload = function () {
    resolver(Promise.all([
      createImageBitmap(image,  0,  0, 40, 40).then(function (image) { sprites.person = image }),
      createImageBitmap(image, 40,  0, 40, 40).then(function (image) { sprites.grass  = image }),
      createImageBitmap(image, 80,  0, 40, 40).then(function (image) { sprites.tree   = image }),
      createImageBitmap(image,  0, 40, 40, 40).then(function (image) { sprites.hut    = image }),
      createImageBitmap(image, 40, 40, 40, 40).then(function (image) { sprites.apple  = image }),
      createImageBitmap(image, 80, 40, 40, 40).then(function (image) { sprites.snake  = image })
    ]));
  };
  return promise;
}

function runDemo() {
  var canvas = document.querySelector('canvas#demo');
  var context = canvas.getContext('2d');
  context.drawImage(sprites.tree, 30, 10);
  context.drawImage(sprites.snake, 70, 10);
}

loadMySprites().then(runDemo);

8.11 动画帧

某些对象包含 AnimationFrameProvider 接口混合。

callback FrameRequestCallback = undefined (DOMHighResTimeStamp time);

interface mixin AnimationFrameProvider {
  unsigned long requestAnimationFrame(FrameRequestCallback callback);
  undefined cancelAnimationFrame(unsigned long handle);
};
Window includes AnimationFrameProvider;
DedicatedWorkerGlobalScope includes AnimationFrameProvider;

每个 AnimationFrameProvider 对象还有一个 目标对象,用于存储提供者的内部状态。定义如下

如果 AnimationFrameProvider 是一个 Window
Window关联的 Document
如果 AnimationFrameProvider 是一个 DedicatedWorkerGlobalScope
DedicatedWorkerGlobalScope

每个 目标对象 都有一个 动画帧回调映射,它是一个 有序映射,最初必须为空,还有一个 动画帧回调标识符,它是一个数字,最初必须为零。

如果以下任何条件为真,则 AnimationFrameProvider provider 被认为是 支持的


Window/requestAnimationFrame

所有当前引擎均支持。

Firefox23+Safari7+Chrome24+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android23+Safari iOS?Chrome Android?WebView Android4.4+Samsung Internet?Opera Android?

以下为 requestAnimationFrame(callback) 方法的步骤

  1. 如果 this 不是 支持的,则抛出 "NotSupportedError" DOMException

  2. targetthis目标对象

  3. target动画帧回调标识符 加 1,并令 handle 为结果。

  4. callbackstarget动画帧回调映射

  5. 设置 callbacks[handle] 为 callback

  6. 返回 handle

Window/cancelAnimationFrame

所有当前引擎均支持。

Firefox23+Safari7+Chrome24+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

以下为 cancelAnimationFrame(handle) 方法的步骤

  1. 如果 this 不是 支持的,则抛出 "NotSupportedError" DOMException

  2. callbacksthis目标对象动画帧回调映射

  3. 移除 callbacks[handle]。

运行动画帧回调,对于 目标对象 target,使用时间戳 now

  1. callbackstarget动画帧回调映射

  2. callbackHandles获取 callbacks 的键的结果。

  3. 对于 callbackHandles 中的每个 handle,如果 handle 存在callbacks

    1. callbackcallbacks[handle]。

    2. 移除 callbacks[handle]。

    3. 调用 callback,参数为 « now » 和 "report"。

在 worker 中,requestAnimationFrame() 可以与从 canvas 元素传输的 OffscreenCanvas 一起使用。首先,在文档中,将控制权转移到 worker

const offscreenCanvas = document.getElementById("c").transferControlToOffscreen();
worker.postMessage(offscreenCanvas, [offscreenCanvas]);

然后,在 worker 中,以下代码将绘制一个从左到右移动的矩形

let ctx, pos = 0;
function draw(dt) {
  ctx.clearRect(0, 0, 100, 100);
  ctx.fillRect(pos, 0, 10, 10);
  pos += 10 * dt;
  requestAnimationFrame(draw);
}

self.onmessage = function(ev) {
  const transferredCanvas = ev.data;
  ctx = transferredCanvas.getContext("2d");
  draw();
};