在没有 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,它没有这个功能。
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的主要内容,如果未能解决你的问题,请参考以下文章