【问题标题】:Can I let Node.JS generate a canvas without an html page?我可以让 Node.JS 生成没有 html 页面的画布吗?
【发布时间】:2016-02-01 18:43:50
【问题描述】:

我正在尝试制作一个 Twitter 机器人,它可以生成随机的 rgb 颜色,创建此颜色的图片并发布推文。我创建了一段可以生成和推文随机 rgb 值的 JS 和一段可以生成随机颜色图片的 javascript,但我不知道如何将两者结合起来。

我的问题是我无法在没有文档的情况下生成 PNG 图像。如果我使用 Node.JS 在服务器上运行脚本,则没有可在其中创建画布的文档。是否有任何其他方法可以创建 png 图片(可能通过将其临时保存到服务器)并将其附加到推文?

感谢您的帮助!

这是我用于发送随机值的代码:

var Twit = require('twit')

var T = new Twit({
  consumer_key:         '###', 
  consumer_secret:      '###',
  access_token:         '###',
  access_token_secret:  '###'
})

function tweet() {
  //Generate a random colour
  var r = Math.floor((Math.random() * 256));
  var g = Math.floor((Math.random() * 256));
  var b = Math.floor((Math.random() * 256));
  var color = "rgb("+r+","+g+","+b+")";

  // tweet that colour
  T.post('statuses/update', { status: color }); 
}

setTimeout(tweet, 30000);

这是一个在网页上生成随机颜色的PNG文件的JS脚本:

var r = Math.floor((Math.random() * 256));
var g = Math.floor((Math.random() * 256));
var b = Math.floor((Math.random() * 256));
var color = "rgb("+r+","+g+","+b+")";

var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');

// draw box
context.beginPath();
context.moveTo(0, 00);
context.lineTo(0, 800);
context.lineTo(800, 800);
context.lineTo(800, 0);
context.closePath();
context.lineWidth = 5;
context.fillStyle = color;
context.fill();

// save canvas image as data url (png format by default)
var dataURL = canvas.toDataURL();

// set canvasImg image src to dataURL
// so it can be saved as an image
document.getElementById('canvasImg').src = dataURL;

【问题讨论】:

    标签: javascript node.js canvas


    【解决方案1】:

    2020 年更新:

    正如 @Mike'Pomax'Kamermans 在 cmets 中指出的,NodeJS 现在(从 v7 开始)包含与浏览器相同的 URL 对象,可用于将画布数据 URI 放入然后类似地保存到磁盘对此答案:https://stackoverflow.com/a/11335500/2138943

    旧答案(适用于 Node 版本

    您可以使用由 JavaScript DOM 支持的 Node <canvas> 实现,例如 node-canvasjsDom。例如canvas,您的代码应如下所示:

        var Canvas = require('canvas');
        var Image = Canvas.Image;
        var canvas = new Canvas(800, 800);
        var context = canvas.getContext('2d');
        var r = Math.floor((Math.random() * 256));
        var g = Math.floor((Math.random() * 256));
        var b = Math.floor((Math.random() * 256));
        var color = "rgb("+r+","+g+","+b+")";
    
    
        // draw box
        context.beginPath();
        context.moveTo(0, 00);
        context.lineTo(0, 800);
        context.lineTo(800, 800);
        context.lineTo(800, 0);
        context.closePath();
        context.lineWidth = 5;
        context.fillStyle = color;
        context.fill();
    
        // save canvas image as data url (png format by default)
        var dataURL = canvas.toDataURL();
    
        // set canvasImg image src to dataURL
        // so it can be saved as an image
        document.getElementById('canvasImg').src = dataURL;
    

    如果您想摆脱 jsDom 要求,您可以使用 canvas.pngStream(),就像 cmets 中的 @josh3736 建议的那样(如果您没有对文档本身做任何其他事情,即您只需要画布)

    Canvas#pngStream()

    要创建一个PNGStream,只需调用canvas.pngStream(),然后流 将开始发出数据事件,最后在完成时发出结束。如果 发生异常时发出错误事件。

    var fs = require('fs'),
    
      ,  out = fs.createWriteStream(__dirname + '/text.png')   
      , stream = canvas.pngStream();
    
    stream.on('data', function(chunk){out.write(chunk); });
    
    stream.on('end', function(){console.log('saved png'); }); 
    

    目前仅支持同步流,但我们也计划支持异步流(当然 :))。在此之前,Canvas#toBuffer(callback) 替代方案是利用 eio_custom() 进行异步。

    【讨论】:

    • 这很好,尽管因为我们在服务器上,所以没有理由使用数据 URL - 只需将结果保存/提供为常规 PNG 文件 (canvas.pngStream())。跨度>
    • 更简单——通过管道传输到写入流。 canvas.pngStream().pipe(out)
    • 感谢@PeteTNT!我想我了解画布实现的作用,但我不确定如何使用它。确切地说,我不确定我可以将什么传递给T.post('media/upload', { media_data: **here** }。当我使用dataUrl 时,它说参数无效。我试过var b64content = fs.readFileSync('dataUrl', { encoding: 'base64' }) 但这给出了没有这样的文件错误。如何告诉 T.post 图片/画布去了哪里?
    • @josh3736 当我通过管道传输到写入流时会发生什么?我试图让文件像这样发推文,但它不起作用:var fs = require('fs') , out = fs.createWriteStream('/img' + r + g + b + '.png') //__dirname + , stream = canvas.pngStream(); var dataUrl = canvas.pngStream().pipe(out); var b64content = fs.readFileSync('/img' + r + g + b + '.png', { encoding: 'base64' }) // first we must post the media to Twitter T.post('media/upload', { media_data: b64content }, function (err, data, response)
    • 我将把它留给你,添加“2020 年编辑:只做 X”将使社区受益,但这是你的答案,不是我的。如果我要编辑它,我应该写一个新的答案,并且(如果原来的海报还在)会让你的答案不被接受。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多