使用toBlob下载CanvasAPI生成的图像

来自菜鸟教程
跳转至:导航、​搜索

对于 Purple11,我使用 Gatsby 构建的一个副项目,我创建了一个简单的 云纹理生成器 ,它在后台使用 SVG 过滤器和 Canvas API。 SVG 过滤器部分让我能够轻松创建云纹理效果本身,这在很大程度上要归功于 feTurbulence 过滤器,但我将在另一篇文章中保留 SVG 过滤器的迷人主题 .

为了让用户将生成的纹理作为 Jpeg 文件下载到他们的机器上,首先需要在画布对象上绘制内联 SVG(应用了过滤器),因为不幸的是,无法直接从内联生成可下载文件SVG 图形。 显然,如果您只是想知道如何下载使用带有 的 Canvas API 直接绘制的图像,您可以直接跳过整个 SVG 到 Canvas 部分 [[#creating-a-downloadable-jpeg-or-png-image-using-toblob|]] X207X]。

如果您是 Canvas API 的新手,并且想获得概览,查看这篇文章


内联 SVG 到画布

首先,您需要使用 DOM 方法来选择您的内联 SVG 元素。 假设我们的 SVG 有 my-svgid

const mySVG = document.getElementById('my-svg');

然后您将使用 XMLSerializer 序列化 SVG 的内容并使用 btoa(二进制到 ascii)来创建它的 base64 版本:

const xml = new XMLSerializer().serializeToString(mySVG);
const svg64 = btoa(xml);

然后,您可以直接从 base64 编码的字符串生成可下载的文件,但我面临的问题是大多数浏览器都对要作为文件下载的这种 base64 编码的字符串的大小施加了限制。 所以我不得不从那一点开始努力绕过这个限制。

创建一个新的 HTML Image 元素并将其 src 属性设置为我们的 SVG 的 base64 版本:

const image = new Image();
const b64Start = 'data:image/svg+xml;base64,';
image.src = b64Start + svg64;

现在我们在页面上有一个带有 SVG 镜像的实际 HTML 图像元素,我们可以将它绘制到 Canvas 2D 上下文中。

首先,我们需要为我们的图像大小创建一个 Canvas 2D 上下文。 假设页面上已经有一个画布元素,其 idmy-canvas

const canvas = document.getElementById('my-canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, image.naturalWidth, image.naturalHeight);

我们可以在我们创建的图像元素上监听 onload 事件,以便在画布上下文对象上实际绘制它:

image.onload = () => {
  ctx.drawImage(image, 0, 0, image.naturalWidth, image.naturalHeight);
};

好的,现在有了所有这些恶作剧,我们终于将内联 SVG 结果绘制到画布对象中。 由于 canvas 的 toBlob 方法,我们可以继续进行有趣的部分并实际生成一个可下载的文件。

使用 toBlob 创建可下载的 JPEG 或 PNG 图像

顾名思义,toBlob 方法将画布绘制的图像转换为 blob。 Blob 是字符串的二进制表示,然后可以将其作为文件下载到您的计算机上。

toBlob 首先将一个回调函数作为参数,它接收 blob 本身,在回调中你可以继续对 blob 做任何你想做的事情。 toBlob 还可以有 2 个附加参数,mime 类型(默认为 image/png)和质量,它期望一个介于 0(0% 质量)和 1(100% 质量)之间的数字变得有用当使用像 image/jpeg 这样的有损 mime 类型时。

例如,这将创建一个质量为 90% 的 Jpeg blob:

canvas.toBlob(
  blob => {
    // do something with the blob here...
  },
  'image/jpeg',
  0.9,
);

URL.createObjectURL

我们可以做的是使用 URL.createObjectURL 从现在内存中的 blob 创建一个 URL。

我们可以在页面上选择一个锚标记并将其 href 属性设置为 URL:

canvas.toBlob(
  blob => {
    const anchor = document.getElementById('download-link');
    anchor.href = URL.createObjectURL(blob);
  },
  'image/jpeg',
  0.9,
);

然后用户只需单击锚点即可启动文件下载。



但是我们可以做得更好,让文件下载自动开始,所以我们将使用一个小技巧,我们以编程方式创建一个锚元素(a),并以编程方式单击它以自动触发下载:

canvas.toBlob(
  blob => {
    const anchor = document.createElement('a');
    anchor.download = 'my-file-name.jpg'; // optional, but you can give the file a name
    anchor.href = URL.createObjectURL(blob);

    anchor.click(); // ✨ magic!

    URL.revokeObjectURL(anchor.href); // remove it from memory and save on memory! 😎
  },
  'image/jpeg',
  0.9,
);

您还会注意到,使用我们自动下载的图像,我们可以从内存释放/清理生成的 blob 到 URL 的映射,因为 blob 现在已作为文件下载到机器上,因此我们完成了它。

包起来

为了得到我们需要的东西,这似乎需要很多杂耍,但这是你要做的那种设置,然后重新专注于你花哨的裤子应用程序的实际功能。 另外,一旦我们想要保存的内容被绘制到画布上下文中,toBlob 方法可以很容易地允许以最适合您的应用程序需求的任何格式和质量保存文件。