【问题标题】: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。我基于示例 here 和 here 开发了一个小型 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
      相关资源
      最近更新 更多