【问题标题】:Cross-Browser Canvas using nodeJS no signature found for the function使用 nodeJS 的跨浏览器画布未找到该函数的签名
【发布时间】:2014-02-27 17:11:54
【问题描述】:

我正在尝试在页面上构建一个画布,每当用户在其上绘制某些内容时,该画布就会自行更新。但是,看起来好像以下代码(来自 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;
};

更新

这是整个脚本:

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

更新 正如帕拉尼克建议的那样,我已尝试在发出图像之前对其进行序列化:

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

接收者

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?

【问题讨论】:

  • 在客户端,你如何初始化画布的ctx
  • @jibsales ctx = canvas.getContext("2d")
  • 对不起,我应该更具体一些。你在哪里初始化?这可能与套接字尚未准备好有关。
  • @jibsales 我已经包含了整个脚本。检查更新
  • @bula 当您进行更新时,您不必用粗体书写:Update # 并再次放置相同的代码并进行一些更改。您可以编辑之前的文本并保持问题清晰。

标签: javascript html node.js canvas


【解决方案1】:

这里的解决方案是使用canvas.toDataURL();

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

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

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

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

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

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

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

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

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

【讨论】:

  • 又是一个惊人而深入的答案。谢谢
  • 对不起。我认为接受答案可以为您提供赏金。我已经给你赏金了。很抱歉
  • 为什么要使用toDataURL 技巧? developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/… 提到“您可以使用另一个 元素作为您的图像源。”。
  • @cherouvim 如果您阅读了问题中包含的代码,您会看到它是通过 WebSockets 传输的。这当然不是每个人都需要考虑的;使用画布或图像作为在另一个画布上绘制操作的源是完全可以的... ...除非您尝试更新 每个人的 画布,当 通过 WebSockets 进行编辑。或者,也许您想通过云保存来保持状态……这背后有很多原因;他们只是不是drawImage( ) 特定的。
【解决方案2】:

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

这是未经测试的代码。只是一个想法供您尝试。

【讨论】:

  • 不字符串化图像数据。创建具有宽度、高度和像素数据的新 obj 对其进行序列化。稍后根据宽度、高度和像素数据创建新的 ImageData。
  • 如何在 javascript 中序列化一个对象?我能找到的只是字符串化
  • 我只是觉得你可能对我的更新感兴趣,因为我觉得它很奇怪。如果我没记错的话,我认为你的代码会产生同样的结果?
  • 我试过了。结果如下: Uncaught NotSupportedError:实现不支持请求的对象或操作类型。 index.html:15 (匿名函数) index.html:15 EventEmitter.emit socket.io.js:633 SocketNamespace.onPacket socket.io.js:2248 Socket.onPacket socket.io.js:1930 Transport.onPacket socket.io .js:1332 Transport.onData socket.io.js:1303 websocket.onmessage
猜你喜欢
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 2011-09-19
  • 2014-02-19
  • 2010-10-02
  • 1970-01-01
相关资源
最近更新 更多