Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
279 views
in Technique[技术] by (71.8m points)

javascript - Can I let Node.JS generate a canvas without an html page?

I'm trying to make a Twitter bot that generates a random rgb colour, creates a picture of this colour and tweets it. I've created a piece of JS that can generate and tweet a random rgb value and a piece of javascript that can generate a picture of a random colour but I'm not sure how to combine the two.

My problem is that I can't generate the PNG image without having a document. If I run the script on a server using Node.JS there isn't a document to create the canvas in. Is there any other way to create a png picture (maybe by temporarily saving it to the server) and attaching it to a tweet?

Thanks for your help!

This is the code I have for tweeting a random value:

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);

And this is a JS script that generates a PNG file of a random colour on a web page:

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;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Updated for 2020:

As pointed by @Mike'Pomax'Kamermans in the comments, NodeJS now (since v7) contains the same URL object as the browser, which can be used for putting the canvas data URI into and then saved to disk similarly to this answer: https://stackoverflow.com/a/11335500/2138943

Old answer (for Node versions < 7)

You can use an Node <canvas> implementation backed with a JavaScript DOM, such as node-canvas with jsDom. For example with canvas, your code should look something like this:

    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;

If you want to get rid of the jsDom requirement you can use canvas.pngStream() like @josh3736 suggests in the comments (if you aren't doing anything else with the document itself ie. you only need the canvas)

Canvas#pngStream()

To create a PNGStream simply call canvas.pngStream(), and the stream will start to emit data events, finally emitting end when finished. If an exception occurs the error event is emitted.

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'); }); 

Currently only sync streaming is supported, however we plan on supporting async streaming as well (of course :) ). Until then the Canvas#toBuffer(callback) alternative is async utilizing eio_custom().


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...