【问题标题】:How to render a GIF from canvas using fabricjs in NodeJS?如何在NodeJS中使用FabryJS渲染画布的GIF?
【发布时间】:2021-11-15 21:06:46
【问题描述】:

我正在使用 fabric.js 来设计一个图像编辑器。我能够将画布转换为 JSON 对象并将其发送到后端。

在后端,我可以从 NodeJS 服务器渲染图像以将其视为静态图像。

这是我的前端代码:

var json = canvas.toJSON();

json 对象被发送到服务器。

我的后端服务器中的代码通过 URL 呈现图像。

app.get('/image', function(req, res) {

let data = {"version":"4.6.0","objects":[{"type":"rect","version":"4.6.0","originX":"left","originY":"top","left":87,"top":24,"width":20,"height":20,"fill":"blue","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":16.48,"scaleY":16.48,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"rx":0,"ry":0},{"type":"textbox","version":"4.6.0","originX":"left","originY":"top","left":148,"top":134,"width":237,"height":45.2,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"fontFamily":"Fontdiner Swanky","fontWeight":"normal","fontSize":40,"text":"Demo Text","underline":false,"overline":false,"linethrough":false,"textAlign":"left","fontStyle":"normal","lineHeight":1.16,"textBackgroundColor":"","charSpacing":0,"styles":{},"direction":"ltr","path":null,"pathStartOffset":0,"pathSide":"left","minWidth":20,"splitByGrapheme":false}]}

res.writeHead(200, { 'Content-Type': 'image/png' });

var canvas = new fabric.StaticCanvas(null, { width: 800, height: 400 });

canvas.loadFromJSON(data, function() {
    canvas.renderAll();

    var stream = canvas.createPNGStream();
    stream.on('data', function(chunk) {
        res.write(chunk);
    });
    stream.on('end', function() {
        res.end();
    });
  });


});

这是图像的渲染方式

当涉及到 GIF 时,我对如何将数据发送到后端有点困惑。

我能够使用 gifuct-js 包将 GIF 添加到画布上。当我将画布转换为 JSON 对象时,大小超过 10mb。我觉得这不是将信息传递到后端的正确方法。另外,如何从后端渲染它?

【问题讨论】:

  • 您是如何将 GIF 图像导入矢量画布的?
  • 不,它显示为图像
  • 那么 gifuct-js 是从哪里进入的呢?
  • 奇怪的这个问题没有关闭...您的代码都是关于 PNG 但您描述的是 GIF 错误和一个不在您的示例代码中的包...标题也很误导

标签: javascript node.js html5-canvas fabricjs


【解决方案1】:

你想要达到的目标听起来很合理,但你走错了路。

您应该自己加载元素/图像/gifs/whatevs,然后在画布中处理它们。

这已经是您问题的答案:不要保存画布,而是保存图像,并在需要时将图像加载到画布上。

如果您需要为画布创建新元素,请单独保存每个元素并适当加载,不要保存整个画布。

奖励:您可以在图像编辑器上免费获得图层

【讨论】:

    【解决方案2】:

    您可以通过在客户端进行渲染来避免整个问题(并节省一些带宽)。下面的函数就足够了:

    function render(canvas, mimeType = 'image/png') {
        const target = document.createElement('canvas');
        target.width = canvas.getWidth();
        target.height = canvas.getHeight();
        
        var wasInteractive = canvas.interactive;
        try {
            // kludge to disable rendering interactive elements
            canvas.interactive = false;
            canvas.renderCanvas(target.getContext('2d'), canvas.getObjects());
        } finally {
            canvas.interactive = wasInteractive;
        }
    
        return new Promise((accept, reject) => {
            try {
                target.toBlob(blob => accept(blob), mimeType);
            } catch (e) {
                reject(e);
            }
        });
    }
    

    上面将返回一个解析为Blob的承诺,然后您可以例如offer for download。但是请注意,注重隐私的浏览器(如 Firefox)可能会拒绝将画布内容转换为 Blob 以阻止指纹识别尝试:解锁功能可能需要先与页面交互和/或回答浏览器提示.如果任何图像不是cross-origin clean,浏览器也可能拒绝渲染画布内容。


    如果你坚持在服务器端渲染画布,你应该已经注意到画布数据只包含图像的 URI,所以问题就变成了服务器是否能够解析它们。如果所有 URI 都指向可从公共 Internet 下载的资源,这应该不是问题:服务器可以自己下载图像。服务器端 fabric.js 依赖 JSDOM 作为 DOM 实现:这个库定义了一个类 ResourceLoader,它负责将 URI 解析为资源。默认情况下,fabric.js 使用的 DOM 环境配置为允许获取外部图像。

    另一方面,如果某些图像是从本地计算机上传的文件,则必须将其内容与上传的画布数据捆绑在一起。

    例如,您可以尝试以下方法:

    function* walkObjects(data) {
        for (const obj of data.objects) {
            yield obj;
            if (obj.type === 'group')
                yield* walkObjects(obj);
        }
    }
    
    function resolveBlob(blobURI) {
        if (!/^blob:/.test(blobURI))
            return null;
    
        /* look up in a private cache of blob URIs */
    }
    
    const formData = new FormData;
    const data = canvas.toObject();
    formData.append('canvas', JSON.stringify(data));
    
    let counter = 0;
    for (const obj of walkObjects(data)) {
        if (obj.type !== 'image')
            continue;
        const blob = resolveBlob(obj.src);
        if (!blob)
            continue;
        formData.append('bundle' + counter, blob);
        obj.src = 'example:attached/bundle' + counter;
        counter++;
    }
    
    const response = await fetch('/image', {
        method: 'post',
        data: formData,
    });
    
    /* e.g. convert into a Blob URI and attach it to <img> */
    

    服务器端可以supply your own ResourceLoader, so that the substituted URLs resolve correctly, and tell fabric.js to use it

    【讨论】:

      【解决方案3】:

      您需要将 GIF 拆分为单独的帧,然后将其传递给 fabric 以进行渲染/动画。

      找到的代码here 可能有用。

      【讨论】:

        猜你喜欢
        • 2020-03-21
        • 2018-04-19
        • 2019-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-03
        • 1970-01-01
        • 2017-12-20
        相关资源
        最近更新 更多