从包含图像引用的JSON对象加载图像

时间:2018-10-01 16:11:25

标签: konvajs

我正在构建一个API,该API将从Konva阶段获取JSON对象输出并将其转换为服务器端的图像。我正在使用konva-node npm软件包,并且在加载可能是原始“设计”一部分的远程图像之前,它确实工作得很好。我可以看到from this answer关于我们如何解决浏览器中的问题的方法,但是在Konva的nodejs实现中,这似乎不能以相同的方式起作用。

JSON输入示例如下:

let json = {
"attrs": {
    "width": 600,
    "height": 600
},
"className": "Stage",
"children": [{
    "attrs": {},
    "className": "Layer",
    "children": [{
        "attrs": {
            "src": "https://ichef.bbci.co.uk/onesport/cps/480/cpsprodpb/1859A/production/_101883799_gettyimages-844211624.jpg"
        },
        "className": "Image"
    }]
}, {
    "attrs": {},
    "className": "Layer",
    "children": [{
        "attrs": {
            "text": "Hello world.",
            "x": 50,
            "y": 50,
            "fontSize": 20,
            "fill": "blue"
        },
        "className": "Text"
    }]
}]

}

如您所见,当我们再次将数据加载到画布中时,我已经归类到src属性中,作为一种占位符。

我遇到的问题是,一旦我在服务器端处理了JSON,实际上又要重新加载这些图像。

这是我当前的代码

var fs = require('fs')
const Konva = require('konva-node')
var Request = require('pixl-request')

let json = {"attrs":{"width":600,"height":600},"className":"Stage","children":[{"attrs":{},"className":"Layer","children":[{"attrs":{"src":"https://ichef.bbci.co.uk/onesport/cps/480/cpsprodpb/1859A/production/_101883799_gettyimages-844211624.jpg"},"className":"Image"}]},{"attrs":{},"className":"Layer","children":[{"attrs":{"text":"Hello world.","x":50,"y":50,"fontSize":20,"fill":"blue"},"className":"Text"}]}] }

var stage = new Konva.Stage()

let loadedDesign = Konva.Node.create(json)


loadedDesign.find('Image').forEach((imageNode) => {
  const imageURL = imageNode.getAttr('src')
  var request = new Request();

  request.get(imageURL, function(err, resp, data) {
    var img = new Konva.window.Image()
    img.onerror = err => { throw err }
    img.onload = () => {
      imageNode.image(img);
      imageNode.getLayer().batchDraw();
    }

    img.src = data;
  });
});

loadedDesign.toDataURL({
  callback: function(data) {
    var base64Data = data.replace(/^data:image\/png;base64,/, '');
    fs.writeFile('./images/out.png', base64Data, 'base64', function(err) {
      err && console.log(err)
      console.log('See out.png')
    });
  }
});

当前输出结果是在画布上显示带有文本的图像,但是该图像从不进入。

1 个答案:

答案 0 :(得分:2)

您需要加载所有图像,然后再使用toDataURL()。我猜您的图片不可见,因为您在加载和撕裂图片之前将Stage转换为dataURL

var request = new Request();

function loadImage(url) {
  return new Promise(resolve => {
    request.get(url, function(err, resp, data) {
      var img = new Konva.window.Image();
      img.onerror = err => {
        throw err;
      };
      img.onload = () => {
        resolve(img);
      };
      img.src = data;
    });
  });
}

async function run() {
  const stage = Konva.Node.create(json);
  const images = stage.find('Image');

  for (const imageNode of images) {
    const imageURL = imageNode.getAttr('src');
    const img = await loadImage(imageURL);
    imageNode.setImage(img);
  }

  stage.findOne('Layer').draw();
  const data = stage.toDataURL();
  var base64Data = data.replace(/^data:image\/png;base64,/, '');
  fs.writeFile('out.png', base64Data, 'base64', function(err) {
    err && console.log(err);
    console.log('See out.png');
  });
}

run().catch(e => {
  console.error(e);
});