最小化canvas“位图”数据大小
上下文:多用户应用程序(node.js) – 1个画家,n个客户
帆布尺寸: 650×400像素(= 260,000像素)
为了更频繁地更新canvas(我每秒思考10次),我需要保持尽可能小的数据大小,特别是在考虑上传速率时。
返回一个base64string的toDataURL()
方法很好,但它包含了大量我不需要的数据(每像素23位)。 它的长度是8,088(没有前面的MIME信息),假设JavaScriptstring有8位编码,即8.1千字节的数据,每秒10次。
我接下来的尝试是使用JS对象来处理moveTo(x, y)
或lineTo(x, y)
等不同的上下文动作,并将它们发送到服务器,让客户端通过delta更新(通过时间戳)接收数据。 但是,结果是比base64string效率更低。
{ "timestamp": 0, "what": { "name": LINE_TO, "args": {"x": x, "y": y} } }
它并不stream畅,也不准确,因为当你刷你的画笔时已经有近300条lineTo
命令了。 有时会有一部分运动缺失(使一条直线而不是四舍五入),有时事件甚至不能被脚本客户端识别,因为它似乎已经被已经触发的大量事件“淹没”了。
所以我必须最终使用8.1 KB的base64string。 我不想担心这一点 – 但即使与增量更新asynchronous完成,实际服务器上也会出现严重滞后,更不用说偶尔带宽超限。
我使用的唯一颜色是#000和#FFF,所以我只考虑一个1位的数据结构 ,只使用增量更新。 这基本上就足够了,我不介意任何“颜色”的精度损失(毕竟是黑色的 )。
大部分的canvas都是白色的,你可以考虑额外的霍夫曼游程编码来进一步减小尺寸。 像一个尺寸为50×2像素的canvas,在(26,2)处的单个黑色像素将返回以下string: 75W1B74W
(50 + 25白色像素,然后是1黑色像素,然后是24白色像素)
如果canvas由如下的1位string组成,那甚至会有所帮助:
00000000000000000000000000000000000000000000000000 00000000000000000000000001000000000000000000000000
这将有助于很多。
我的第一个问题是:如何编写一个algorithm来有效地获取这些数据?
第二个是:我怎样才能将纯二进制canvas数据传递给客户端(通过节点服务器 )? 我怎样才能发送一个1位的数据结构到服务器? 我需要将我的位转换为hex(或更多)的数字并重新parsing吗?
有可能将其用作数据结构吗?
提前致谢,
哈尔蒂
我需要保持尽可能小的数据大小
那么不要发送整个数据。 只发送更改,接近你自己提出的build议。
制作框架,使每个用户只能做“行动”,如“从X1,Y1到X2,Y2绘制黑色笔画宽度2”。
我不会打扰一些纯粹的二进制的东西。 如果只有两种颜色,那么很容易以string“1,2,x,y,x2,y2”发送,其他人将以与本地客户端完全相同的方式进行parsing,并且将以相同方式绘制。
我不会推翻这一点。 在你担心任何聪明的编码之前,先用简单的string来处理它。 首先尝试简单的事情是值得的。 也许performance会相当不错,不会经历很多麻烦!
我最后把它整理出来。 我使用一种algorithm来获取指定区域(即当前绘制的区域)内的图像数据,然后将图像数据粘贴到相同的坐标上。
-
在绘图时,我通知我的应用程序有多大的修改区域和开始(存储在
currentDrawingCoords
)。 -
pixels
是一个ImageData数组,通过调用context.getImageData(left, top, width, height)
和存储的绘图坐标来获得。 -
getDeltaUpdate
被调用onmouseup
(是的,这是该地区的想法的缺点) :getDeltaUpdate = function(pixels, currentDrawingCoords) { var image = "" + currentDrawingCoords.left + "," + // x currentDrawingCoords.top + "," + // y (currentDrawingCoords.right - currentDrawingCoords.left) + "," + // width (currentDrawingCoords.bottom - currentDrawingCoords.top) + ""; // height var blk = 0, wht = 0, d = "|"; // http://stackoverflow.com/questions/667045/getpixel-from-html-canvas for (var i=0, n=pixels.length; i < n; i += 4) { if( pixels[i] > 0 || pixels[i+1] > 0 || pixels[i+2] > 0 || pixels[i+3] > 0 ) { // pixel is black if(wht > 0 || (i == 0 && wht == 0)) { image = image + d + wht; wht = 0; d = ","; } blk++; //console.log("Pixel " + i + " is BLACK (" + blk + "-th in a row)"); } else { // pixel is white if(blk > 0) { image = image + d + blk; blk = 0; d = ","; } wht++; //console.log("Pixel " + i + " is WHITE (" + blk + "-th in a row)"); } } return image; }
-
image
是一个带有标题部分(x,y,width,height|...
)和数据体部分(...|w,b,w,b,w,[...]
)的string -
结果是string比base64string的字符less(与8k字符string相反,delta更新有1k-6k字符,取决于修改区域有多less东西)
-
该string被发送到服务器,推送到所有其他客户端,并通过使用
getImageData
恢复到ImageData:getImageData = function(imagestring) { var data = imagestring.split("|"); var header = data[0].split(","); var body = data[1].split(","); var where = {"x": header[0], "y": header[1]}; var image = context.createImageData(header[2], header[3]); // create ImageData object (width, height) var currentpixel = 0, pos = 0, until = 0, alpha = 0, white = true; for(var i=0, n=body.length; i < n; i++) { var pixelamount = parseInt(body[i]); // amount of pixels with the same color in a row if(pixelamount > 0) { pos = (currentpixel * 4); until = pos + (pixelamount * 4); // exclude if(white) alpha = 0; else alpha = 255; while(pos < until) { image.data[pos] = 0; image.data[pos+1] = 0; image.data[pos+2] = 0; image.data[pos+3] = alpha; pos += 4; } currentpixel += pixelamount; white = (white ? false : true); } else { white = false; } } return {"image": image, "where": where}; }
-
调用
context.putImageData(data.image, data.where.x, data.where.y);
把这个区域放在一切的上面!
如前所述,由于修改区域仅提交onmouseup
,因此这可能不是适用于各种单色canvas绘制应用的最佳select。 不过,我可以忍受这种折衷,因为服务器的压力远远小于问题中提出的所有其他方法。
我希望我能帮助人们跟随这个问题。
- 多人游戏HTML5,Node.js,Socket.IO
- 如何提交HTML5canvas作为表单发布的一部分?
- 在Node.js中如何将multipart / form-data上传的图像转换为base64格式
- 图像没有方法'getContext'
- 在EC2上安装node-canvas – fontconfig.h生成错误
- 如何捕捉canvas中的小变化,并将它们发送给所有使用该canvas的相互连接的用户?
- 绘制多个套接字实例以在移动(多人)上进行canvas和更新
- node-o3-canvas与node-canvas?
- 试图使hmac-sha256与Powershell for Canvas API一起工作