javascript - 即使 Canvas 没有改变,canvas.toDataURL()值也会改变

标签 javascript html canvas base64

我一直在研究并尝试编写一个应用程序,该应用程序可以获取 HTML5 Canvas 元素上的任何图像并将其发送给客户端。当尝试使用 canvas.toDataURL() 获取图像、压缩并将其发送回服务器时,客户端有时显示图像,有时不显示发送的内容。首先,我认为可能是数据已损坏,但在本地服务器上工作并拥有 29/30 损坏的数据对我来说没有意义,所以我尝试查看发生了什么并注册了长度Base64 图像并注意到它的长度正在改变,尽管 Canvas 的内容没有改变。为什么会发生这种情况?

我编写了一个简单的页面,您可以在其中通过在 Canvas 上绘图来编辑 Canvas 内容,以显示正在发生的情况:

<!DOCTYPE html>
<html>
    <head>
        <title>Draw</title>
        <style>
            body{margin:0;}
        </style>
        <script>
            addEventListener("load", Load, false);

            var board = undefined;
            var ctx = undefined;

            var loaded = false;

            var mousehold = false;
            var mousex = 0;
            var mousey = 0;
            var lastx = 0;
            var lasty = 0;
            var firstclick = false;

            function Load(e)
            {
                loaded = true;
                board = document.getElementById("board");
                ctx = board.getContext("2d");

                board.width = window.innerWidth;
                board.height = window.innerHeight;

                addEventListener("mousedown", function(e)
                {
                    mousehold = true;
                }, false);

                addEventListener("mouseup", function(e)
                {
                    mousehold = false;
                    firstclick = false;
                }, false);

                addEventListener("mousemove", function(e)
                {
                    mousex = e.clientX;
                    mousey = e.clientY;

                    // if(mousehold == true) console.log(mousex + " " + mousey);
                }, false);

                ctx.beginPath();
                ctx.lineWidth = 5;
                UpdateBoard();
            }

            function UpdateBoard()
            {
                if(mousehold == true)
                {
                    if(firstclick == false)
                    {
                        lastx = mousex;
                        lasty = mousey;
                        firstclick = true;
                    }

                    ctx.moveTo(lastx, lasty);
                    ctx.lineTo(mousex, mousey);
                    ctx.stroke();

                    lastx = mousex, lasty = mousey;
                }

                window.requestAnimationFrame(UpdateBoard);
            }

            function send()
            {
                var img = board.toDataURL();
                console.log(img.length);
            }
        </script>
    </head>
    <body>
        <canvas id="board"></canvas>
        <button style="right:10px;bottom:10px;position:fixed;z-index:999999;" onclick="send();">Send</button>
    </body>
</html>

单击“发送”按钮将在控制台上记录 Base64 图像长度。如果你在屏幕上绘制一些东西, Canvas 的内容会明显改变,但是如果你停止绘制并单击“发送”按钮几次(不接触 Canvas 内容),你会发现它似乎生成了不同的base64图像。为什么会发生这种情况?有可能防止这种情况发生吗?我的应用程序需要不断更新内容(压缩,但我尝试过不压缩,问题是一样的)。

为了演示该问题,我将图像上传到 imgur: http://imgur.com/a/iQ70T (忽略图像中的拼写错误)。

感谢您的关注。

最佳答案

发生这种情况的原因是您已将所有事件监听器附加到 window 对象而不是 Canvas (mousedown,其他事件监听器可以在 window 上)当您点击发送按钮时,mousedown 也会被注册。

这意味着每帧都会重新绘制最后一条路径,因为 mousehold 将为 true,累积影响 Alpha channel 的抗锯齿像素,因此会更改位图。

示例修复(只需将 mousedown 处理程序附加到 Canvas ):

addEventListener("load", Load, false);

var board = undefined;
var ctx = undefined;

var loaded = false;

var mousehold = false;
var mousex = 0;
var mousey = 0;
var lastx = 0;
var lasty = 0;
var firstclick = false;

function Load(e) {
  loaded = true;
  board = document.getElementById("board");
  ctx = board.getContext("2d");

  board.width = window.innerWidth;
  board.height = window.innerHeight;

  // this must be at canvas element
  board.addEventListener("mousedown", function(e) {
    mousehold = true;
  }, false);

  addEventListener("mouseup", function(e) {
    mousehold = false;
    firstclick = false;
  }, false);

  addEventListener("mousemove", function(e) {
    mousex = e.clientX;
    mousey = e.clientY;

    // if(mousehold == true) console.log(mousex + " " + mousey);
  }, false);

  ctx.beginPath();
  ctx.lineWidth = 5;
  UpdateBoard();
}

function UpdateBoard() {
  if (mousehold == true) {
    if (firstclick == false) {
      lastx = mousex;
      lasty = mousey;
      firstclick = true;
    }

    ctx.moveTo(lastx, lasty);
    ctx.lineTo(mousex, mousey);
    ctx.stroke();

    lastx = mousex, lasty = mousey;
  }

  window.requestAnimationFrame(UpdateBoard);
}

function send() {
  var img = board.toDataURL();
  console.log(img.length);
}
body {margin:0}
<canvas id="board"></canvas>
<button style="right:10px;bottom:10px;position:fixed;z-index:999999;" onclick="send();">Send</button>

关于javascript - 即使 Canvas 没有改变,canvas.toDataURL()值也会改变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45247330/

相关文章:

html - 如何清除 <canvas> 元素中的文本?

javascript - 相交后延长线

javascript - Highcharts 使用 Dom 控制基本 DrillDown

javascript - Extent翻转卡片功能——Jquery

javascript - 为 NW.js 编译的 SQLITE - SQL CRUD 的一个命令

javascript - 当我单击链接时,jQuery 表行单击事件也会触发

html - 菜单格式 HTML

html - 强制浏览器呈现网页的打印样式表

html - 如何像网格一样排列 css::before 伪元素

javascript - Ajax Canvas 图表不显示变化?