使用nodeJS的跨浏览器画布没有找到该功能的签名

时间:2014-02-27 17:11:55

标签: javascript html5 node.js canvas

我正在尝试在页面上构建一个画布,只要用户在其上绘制内容就会自动更新。但是看起来好像下面的一段代码(来自index.html)导致错误

  socket.on("drawn_complete",function(data){
    ctx.putImageData(data.image,0,0);
    console.log("Everthing worked technically");
});

以下是在我的控制台中输出的错误:

Uncaught TypeError: Failed to execute 'putImageData' on 'CanvasRenderingContext2D': No function was found that matched the signature provided

我的data.image是从以下代码返回的内容:

ctx.getImageData(0,0,200,100); // ctx is canvas.getContext("2d")

这是我的html中的画布:

 <canvas id="myCanvas" width="200" height="100"
style="border:1px solid #000000;">
</canvas>

这是完整的nodeJS:

    var http = require("http")
var server = http.createServer(handler).listen(1337);
console.log("Server created at 127.0.0.1:1337");
var io = require("socket.io").listen(server);


function handler(req,res)
{
    console.log("Client Connected");
    res.writeHead(200,{"Content-type": "text/plain"});
    res.end("Hello World");
}


io.sockets.on("connection",function(socket){
    socket.on("drawing",function(data){
        var image = data["image"];
        io.sockets.emit("drawn_complete",image);
    });
});

当用户握住并在我的画布中移动鼠标时,绘图就会被激活:

以下是代码:

  c.onmousedown = function(evt){
moving = true
};
c.onmousemove = function(evt){
    if(moving == true)
    {
        console.log("holding and moving");

        var x = evt.clientX - rect.left;
        var y = evt.clientY - rect.top;
        console.log("X: " + x + " Y: " + y);
        ctx.fillRect(x,y,1,1);
        socket.emit("drawing",{"image": ctx.getImageData(0,0,200,100)});

    }
};
c.onmouseup = function(evt){
    moving = false;
};

更新

这是enitre脚本:

<script>

window.onload = function(){
var socket = io.connect("http://localhost:1337");
socket.on("drawn_complete",function(data){
    ctx.putImageData(data.image,0,0);
    console.log("Everthing worked technically");
});


var c = document.getElementById("myCanvas");
var moving = false;
console.log(c);
 var ctx = c.getContext("2d");
 var rect = c.getBoundingClientRect();
c.onmousedown = function(evt){
moving = true
};
c.onmousemove = function(evt){
    if(moving == true)
    {
        console.log("holding and moving");

        var x = evt.clientX - rect.left;
        var y = evt.clientY - rect.top;
        console.log("X: " + x + " Y: " + y);
        ctx.fillRect(x,y,1,1);
        socket.emit("drawing",{"image": ctx.getImageData(0,0,200,100)});

    }
};
c.onmouseup = function(evt){
    moving = false;
};
};



</script>

更新 正如Palanik建议我在发射图像之前将其序列化:

 var stringfy = JSON.stringify(ctx.getImageData(0,0,200,100));
        socket.emit("drawing",{"image": stringfy});

看起来控制台仍然会抛出相同的错误

更新(2) 正如@Palanik建议我尝试序列化该对象。我知道下面的代码并不完全是他推荐的,但我只是想强调一些非常特殊的代码:

发信人:

var stringfy = ctx.getImageData(0,0,200,100);
        console.log(stringfy)
        var sent = JSON.stringify(stringfy);
        socket.emit("drawing",{"image": sent});

Reciever

socket.on("drawn_complete",function(data){
imageData = JSON.parse(data.image);
console.log(imageData);
ctx.putImageData(imageData,0,0);
console.log("Everthing worked technically");

});

这里有趣的是,imageData的console.log打印出一个具有与ImageData相同的确切属性的对象。高度,宽度和原始。看看这里:

{"height":100,"width":200,"data":{"0":0,"1":0,"2":0,"3":0,"4":0,"5 etc... }

因此,从这里我可以看到,我能够恢复对象。如果我在java中,演员就足够了;

ImageData object = (ImageData) imageData // Is there a way to do this?

2 个答案:

答案 0 :(得分:9)

此处的解决方案是使用canvas.toDataURL();

这将返回一个Base64编码的图像字符串(头部有MIME类型和编码)。

var canvas = getMyCanvas(),
    ctx = canvas.getContext("2d"),
    encodedImageData = canvas.toDataURL(),
    image = new Image();

image.src = encodedImageData;
ctx.drawImage(image, x, y, w, h...);

您可以愉快地将这些编码的字符串传入和传出服务器 您也可以在常规HTML <img src="data:image/png;base64,...">中使用它们。

此外,您可以传递toDataURL几个参数:

 canvas.toDataURL("image/jpeg", 0.5);`

其中,第一个参数是请求的文件类型,第二个参数是请求的图像质量级别(介于0和1之间)。

不能保证任何浏览器都会支持您所要求的内容,但无论如何您可能只会获得一个.png文件(这可能是您想要的游戏,透明胶片,无论如何)。

另外,Android 2.2浏览器和更低版本以及IE9,我认为Mobile Safari 5.1(原版iPad)不支持.toDataURL
我可能错了iPad,但它们不支持其他HTML5 API,它们可以结合使用。

答案 1 :(得分:2)

ImageData可能无法移植。尝试在发送和反序列化之前序列化imagedata并在接收端创建imagedata。

===更新===

类似的东西:

发件人

canvasData = ctx.getImageData(0,0,200,100)}
myData = {
        height : canvasData.height,
        width : canvasData.width,
        raw : canvasData.data
};
socket.emit("drawing",{"image": myData});

接收机

imgData = ctx.getImageData(myData.width, myData.height);
for (var i = 0; i < myData.raw.length) {
        imgData.data[i] = myData.raw[i];
}
ctx.putImageData(imgData, 0, 0);

这是未经测试的代码。只是一个想法让你尝试一下。