【问题标题】:Fabric.js loadFromJSON sometimes fails in Node.js if string contains images如果字符串包含图像,Fabric.js loadFromJSON 有时会在 Node.js 中失败
【发布时间】:2015-11-09 05:25:33
【问题描述】:

我在服务器端使用 Fabric.js + Node.js 生成 PNG 图像时遇到问题。我想知道在论坛中找不到类似问题的人。我完全绝望了。在我们的项目中使用 Fabric.js 存在风险。
Fabric.js Node.js 服务中的 PNG 图像生成不定期失败。我无法确定为什么有时会生成,有时不会。
我需要在服务器端生成 PNG。我基于示例 herehere 开发了一个小型 Node.js Web 服务。
我还开发了一个自定义 Fabric.js 图像类“RemoteImage”,基于 Kangax 示例 here
为了最小化 JSON 字符串的大小,我在我的数据库中存储了一个无数据的 JSON,并且应该使用 Fabric.js Image 元素的“src”属性中的提供链接来加载图像。结果,我需要将以下 JSON 加载到包含 3 张图像的画布中:

{"objects":[{"type":"remote-image","originX":"left","originY":"top","left":44,"top":29,"width":976,"height":544,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":0.5,"scaleY":0.5,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","localId":"222c0a8b-46ac-4c01-9c5c-79753937bc24","layerName":"productCanvas","itemName":"mainCanvas","src":"http://localhost:41075/en/RemoteStorage/GetRemoteItemImage/222c0a8b-46ac-4c01-9c5c-79753937bc24","filters":[],"crossOrigin":"use-credentials","alignX":"none","alignY":"none","meetOrSlice":"meet","remoteSrc":"http://localhost:41075/en/RemoteStorage/GetRemoteItemImage/222c0a8b-46ac-4c01-9c5c-79753937bc24","lockUniScaling":true},
{"type":"remote-image","originX":"left","originY":"top","left":382.5,"top":152.25,"width":292,"height":291,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":0.43,"scaleY":0.43,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","localId":"8d97050e-eae8-4e95-b50b-f934f0df2d4c","itemName":"BestDeal.png","src":"http://localhost:41075/en/RemoteStorage/GetRemoteItemImage/8d97050e-eae8-4e95-b50b-f934f0df2d4c","filters":[],"crossOrigin":"use-credentials","alignX":"none","alignY":"none","meetOrSlice":"meet","remoteSrc":"http://localhost:41075/en/RemoteStorage/GetRemoteItemImage/8d97050e-eae8-4e95-b50b-f934f0df2d4c","lockUniScaling":true},
{"type":"remote-image","originX":"left","originY":"top","left":38,"top":38.5,"width":678,"height":370,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":0.21,"scaleY":0.21,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","localId":"42dc0e49-e45f-4aa7-80cf-72d362deebb7","itemName":"simple_car.png","src":"http://localhost:41075/en/RemoteStorage/GetRemoteItemImage/42dc0e49-e45f-4aa7-80cf-72d362deebb7","filters":[],"crossOrigin":"use-credentials","alignX":"none","alignY":"none","meetOrSlice":"meet","remoteSrc":"http://localhost:41075/en/RemoteStorage/GetRemoteItemImage/42dc0e49-e45f-4aa7-80cf-72d362deebb7","lockUniScaling":true}],"background":""}

在 Node.js 服务器端,我使用以下代码。我正在以 base64 编码传输 JSON 字符串以避免一些特殊字符问题:

var fabric = require('fabric').fabric;

function generatePNG(response, postData) {
   var canvas = fabric.createCanvasForNode(1500, 800);
   var decodedData = new Buffer(postData, 'base64').toString('utf8');

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

   console.log("decodedData data: " + JSON.stringify(decodedData));
   console.log("prepare to load");

   canvas.loadFromJSON(decodedData, function () {
       console.log("loaded");
       canvas.renderAll();
       console.log("rendered");

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

在控制台中,我看到“准备加载”消息出现,但“已加载”消息没有出现。我不是 Node.js 方面的专家,这是我确定在 loadFromJSON 调用期间发生错误的唯一方法。但是我不明白,问题出在哪里。
我在服务器端使用fabric v.1.5.0 和node-canvas v.1.1.6。
Node.js + Fabric.js 服务在 Windows 8 机器上运行。我正在使用 POST 请求从 .NET MVC 应用程序发出请求。

备注:可能我需要省略关于 base64 编码的评论,因为它令人困惑。我尝试使用普通的 json 字符串运行,结果相同。

【问题讨论】:

    标签: node.js fabricjs


    【解决方案1】:

    如果 JSON 中引用的图像位于 NodeJS 服务器上,请尝试将文件路径更改为服务器上的目录路径,而不是 Web URL。

    我不确定我是否完全理解您是如何使用 base64 图像的,但是 base64 图像需要进行一些字符更正。我当然不记得具体细节,也没有手边的代码来执行此操作,但 Google 搜索应该会让您朝着正确的方向前进。

    我希望这些想法有所帮助。

    【讨论】:

    • 我只是在 base64 整个织物 json 字符串中编码,而不是特定图像。在调用 loadfromJSON 之前,我将其解码为普通字符串。可能我需要省略关于 base64 编码的评论,因为它令人困惑。我尝试使用普通字符串和相同的结果运行。图像存储在数据库服务器中,我有一个通过 URL 检索它们的服务。在客户端,一切正常。因此我不能改变路径。最令人困惑的是没有抛出任何错误——node.js 服务只是默默地崩溃了。
    • 其他一些想法:在他引用的 Kangax 的教程中,他在他的服务器顶部定义了一个写入流,写入(块)写入 - 我在你的代码中没有看到,并且我假设您的响应变量是标准响应。这可能是问题所在。 var out = fs.createWriteStream(__dirname + '/helloworld.png');另外我想知道问题是否来自使用缓冲区。我认为您可以一起跳过解码的数据变量,只需将 postData 传递给 loadFromJSON 方法。我认为将您的 JSON 设置为 utf8 会导致一些问题。只是一些未经检验的想法。
    【解决方案2】:

    事实证明,问题与 fabric.util.loadImage 方法的工作方式有关。对于外部图像,loadImage mathod 会发出一个 http 请求,假设不会发生错误。用于请求外部图像的方法只是简单地记录一个错误并结束,而不是通过回调方法将错误返回给 loadImage 方法。此时图像加载例程因错误状态而崩溃并且没有任何反馈 - 它只是终止了整个 Node.js 的崩溃。

    我花了 3 天的时间才最终发现,实际上是我的图像提供 web 服务,它只是响应状态码 500,使 Node.js 请求失败。通过浏览器使用我的图像提供网络服务可以正常工作,因此一开始我并没有认为该错误与请求特别相关。

    因此,我重写了自定义 Fabric.js 对象的 fromObject 方法。现在它以更安全的方式工作,如果出现错误,我可以获得更多反馈。这是我的 fromObject 方法的实现。对于 http 请求,我使用模块“请求”。

    fabric.RemoteImage.fromObject = function (object, callback) {
    var requestUrl = object.remoteSrc;
    request({
            url: object.remoteSrc,
            encoding: null
        },
        function(error, response, body) {
            if (error || response.statusCode !== 200) {
                var errorMessage = "Error retrieving image " + requestUrl;
                errorMessage += "\nResponse for a new image returned status code " + response.statusCode;
                if (error) {
                    errorMessage += " " + error.name + " with message: \n" + error.message;
                    console.log(error.stack);
                }
                console.log(errorMessage);
                callback && callback(null, new Error(errorMessage));
            } else {
                var img = new Image();
                var buff = new Buffer(body, 'binary');
                img.src = buff;
                var fabrImg = new fabric.RemoteImage(img, object);
                callback && callback(fabrImg);
            }
        });
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-18
      • 2018-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多