被污染的画布可出口:Canvas 的图片导出技术

在前端开发中,我们经常会用到 Canvas 来绘制各种图形,但是有时候我们需要将 Canvas 中的图形导出为图片,以便于分享、打印等用途。本文将介绍如何实现 Canvas 图片导出,并解决在此过程中可能遇到的问题。

常规方法:toDataURL

Canvas 对象提供了 toDataURL 方法,可以将 Canvas 导出为一张 base64 格式的图片。使用方法如下:

----- ------ - ---------------------------------
----- --- - ------------------------

-- -------

----- ------- - ------------------- -- -- ------ ------

这个方法看起来非常简单,但是它存在以下问题:

  1. 性能问题:toDataURL 生成的是一个非常大的字符串,如果 Canvas 非常大,就会造成浏览器崩溃或者卡顿。
  2. 跨域问题:如果 Canvas 中包含跨域图片,toDataURL 会抛出安全错误。
  3. 质量问题:默认情况下,toDataURL 导出的图片质量比较差,因为它使用的是 image/png 格式,而不是更好的 image/jpeg 或者 image/webp 格式。

为了解决这些问题,我们需要使用其他的方法。

使用 OffscreenCanvas

OffscreenCanvas 是 Web Worker 中的一个概念,它可以在后台线程中进行绘制操作,从而减轻主线程压力。但是 OffscreenCanvas 也可以在主线程中使用,并且它提供了 toBlob 方法,可以将 Canvas 导出为 Blob 对象,这样就不会产生过大的字符串了。

----- --------------- - --- ---------------------- --------
----- --- - ---------------------------------

-- -------

----------------------------- -- -
  -- -- ---- -------------------
-- ------------- ---------

注意,虽然 OffscreenCanvas 的设计初衷是用于 web worker 中,但是并不是所有浏览器都支持 OffscreenCanvas,所以在使用之前需要进行兼容性检查。

解决跨域问题

如果 Canvas 中包含跨域图片,即使使用 OffscreenCanvas,导出图片时仍然会抛出安全错误。这时候我们需要通过设置 CORS 来解决这个问题。

CORS(Cross-Origin Resource Sharing)是一种机制,允许网页向其他域名的服务器请求数据,从而避免了浏览器的同源策略限制。只需要在服务器端设置 Access-Control-Allow-Origin 头部,就可以开启 CORS 机制。

如果你没有掌握 CORS 的相关知识,建议先学习一下。

解决质量问题

我们可以使用 canvas.toBlob 方法的第三个参数,来指定输出图片的质量。这个参数是一个 0~1 的浮点数,表示图片的质量,值越大,图片质量越好,文件大小也越大。

----- --------------- - --- ---------------------- --------
----- --- - ---------------------------------

-- -------

----------------------------- -- -
  -- -- ---- -------------------
-- ------------- ---------

示例代码

下面是一个完整的 Canvas 导出为 Blob 对象的例子:

-------- -------------------------- ------- - --- -
  ----- - ---- - ------------ ------- - - - - --------

  -- --------- ---------- ------------------- -
    ----- --- ------------- ----- ------ -----
  -

  ------ --- ----------------- -- -
    -----

- ----------------------------------------------------------- --------
---------------------------------------------------------------------------------------