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

Posted

技术标签:

【中文标题】在没有 konva-node 的 nodejs 后端上使用 konva【英文标题】:Using konva on a nodejs backend without konva-node 【发布时间】:2021-11-12 12:04:30 【问题描述】:

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

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

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

我们注意到here konva-node 在短时间内被弃用。 Documentation 说在 node.js 上使用 canvas + konva。但这只是行不通。如果我们不使用 konva-node,我们将无法创建没有 'container' 值的阶段。我们也不能再创建一个原始图像缓冲区,因为stage.toCanvas() 实际上返回一个 htmlCanvas,它没有这个功能。

那么 konva-node 实际上对 konva API 做了什么? 在弃用 konva-node 后是否仍支持 node.js? 如何在 node.js 中不使用 konva-node 获得 toBuffer()new Stage() 功能?

后端(konva-node)

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');

前端(康瓦)

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;。也许这是用来区分浏览器和节点画布的?

【问题讨论】:

【参考方案1】:

那么 konva-node 实际上对 konva API 做了什么?

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

在弃用 konva-node 后是否仍支持 node.js?

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

如何在 node.js 中不使用 konva-node 获得 toBuffer() 和 new Stage() 功能?

你可以试试这个:

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

【讨论】:

感谢您的回复。幸运的是,我们已经找到了另一种方法,但我错过了关于如何从您的身边创建 Konva.Stage 的提示。希望我自己给出的答案能够启发大家对接口类型规范的改进。无论如何,我们现在对 Konva 及其惊人的速度感到非常满意。【参考方案2】:

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

创建阶段(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);
       ;
   );

我们必须做的两件事。

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

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

【讨论】:

有没有办法将视频流渲染成节点环境中的图像? @DenisIvanov - 我认为有多种方法可以做到这一点 - 我个人的建议是使用 ffmpeg - 请参阅此处的示例:***.com/questions/40088222/…。另外我更喜欢使用“child_process”从node.js而不是其他包装器库执行ffmpeg。这样您就可以像使用所有 ffmpeg 命令一样。如果您想要的话,可以在 AWS Lambda 中使用 Ffmpeg。构建容器或使用 lambda 层。

以上是关于在没有 konva-node 的 nodejs 后端上使用 konva的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有root访问权限的情况下部署NodeJS应用程序,以便在服务器重新启动后保持在线状态?

nodeJS学习记录

使用nodejs下载文件后删除文件

使用nodejs下载文件后删除文件

lambda函数电子邮件不通过nodeJS发送

没有NodeJS的vue文件?