在没有 konva-node 的 nodejs 后端上使用 konva

Using konva on a nodejs backend without konva-node

我们是一个由 5 名开发人员组成的团队,致力于视频渲染实现。此实现由两部分组成。

  1. 使用 angular + konva 在浏览器中进行实时视频预览。
  2. node.js(节点 14)无服务器(AWS lambda 容器)实现使用 konva-node 将帧通过管道传输到 ffmpeg 以呈现更高质量的 mp4 视频供以后下载。

两种方式都适合我们。现在我们将前端和后端实现相同的动画部分提取到内部库中。我们在 BE 和 FE 中导入它们。这也适用于大多数部分。

我们注意到 here that konva-node is deprecated since a short time. Documentation 说要使用 canvas + konva 而不是 node.js。但这行不通。如果我们不使用 konva-node,我们将无法创建没有 'container' 值的阶段。此外,我们不能再创建原始图像缓冲区,因为 stage.toCanvas() 实际上 returns HTMLCanvas,它没有此功能。

后端(konva 节点)

import konvaNode = require('konva-node');  
this.stage = new konvaNode.Stage({
     width: stageSize.width,
     height: stageSize.height
});

// [draw stuff on stage here]

// create raw frames to pipe to ffmpeg
const frame = await this.stage.toCanvas();
const buffer: Buffer = frame.toBuffer('raw');

前端 (konva)

import Konva from 'konva';
this.stage = new Konva.Stage({
     width: stageSize.width,
     height: stageSize.height,
     // connect stage to html element in browser
     container: 'container'
});

// [draw stuff on stage here]

终于在一个理想的世界中(如果我们可以在没有 konva-node 的情况下在前端和后端使用 Konva,那么共享代码应该可以实现以下内容。

正在加载图像

public static loadKonvaImage(element, canvas): Promise<any> {
    return new Promise(resolve => {
        let image;
        if (canvas) {
            // node.js canvas image
            image = new canvas.Image();
        } else {
            // html browser image
            image = new Image();
        }
        image.src = element.url;
        image.onload = function () {
            const konvaImage = new Konva.Image(
            {image, element.width, element.height});
            konvaImage.cache();
            resolve(konvaImage);
        };
    });
}

开发人员的许多支持,感谢他们的出色工作。我们会期待长期使用这个库,但是如果我们依赖的一些核心功能在我们开始项目后不久就已经过时了,我们怎么办?

另一个堆栈溢出 answer 提到 Konva.isBrowser = false;。也许这是用来区分浏览器和节点的 canvas?

So what does konva-node actually do to konva API?

它稍微修补了 Konva 代码以使用 canvas nodejs 库以使用 2d canvas API。所以,Konva 不会使用浏览器 DOM API.

Is node.js still supported after deprecation of konva-node?

是的。 https://github.com/konvajs/konva#4-nodejs-env

How can we get toBuffer() and new Stage() functionality without konva-node in node.js?

你可以试试这个:

const canvas = layer.getNativeCanvasElement();
const buffer = canvas.toBuffer();

我们已经通过以下方式解决了我们遇到的问题:

创建阶段(Be+FE 共享)

public static createStage(stageWidth: number, stageHeight: number, canvas?: any): Konva.Stage {
    const stage = new Konva.Stage({
        width: stageWidth,
        height: stageHeight,
        container: canvas ? canvas : 'container'
    });
    return stage;
}

创建原始图像缓冲区 (BE)

const frame: any = await this.stage.toCanvas();
const buffer: Buffer = frame.toBuffer('raw');

正在加载图像(在 Be+FE 之间共享)

public static loadKonvaImage(element, canvas?: any): Promise<Konva.Image> {
   return new Promise(resolve => {
       const image = canvas ? new canvas.Image() : new Image();
       image.src = element.url;
       image.onload = function () {
           const konvaImage = new Konva.Image(
           {image, element.width, element.height});
           konvaImage.cache();
           resolve(konvaImage);
       };
   });
}

我们必须做两件事。

  1. 我们重写了整个后端和库代码以使用 ESM 模块,并且我们总体上摆脱了 konva-node 和 konva 7。
  2. 我们将所有地方的节点模块canvas定义为any。似乎 Konva 接受了比预期更多的输入,并且与 类 的类型接口中指定的一样。 canvas 仅安装在后端并插入如上所示的一些库方法。

@lavrton 很高兴收到你的来信。您的答案也可能适用于获取缓冲区,但您没有回答如何创建舞台。幸运的是,我们找到了解决这两个问题的方法。