【问题标题】:Execute Function After Canvas toDataURL() Function is CompleteCanvas toDataURL()函数完成后执行函数
【发布时间】:2017-08-03 18:22:33
【问题描述】:

我正在使用画布将图像转换为 base64。我需要做的是转换这些图像,然后将结果显示给用户(原始图像和 base64 版本)。小图像一切正常,但是当我尝试转换大图像(> 3MB)并且转换时间增加时,base64版本为空。 这可能是 is 导致的,因为结果在 toDataURL() 函数完成之前显示。

为了测试目的,我需要在所有需要的处理结束后显示结果。

这是我的代码:

var convertToBase64 = function(url, callback)
{
    var image = new Image();

    image.onload = function ()
    {
        //create canvas and draw image...

        var imageData = canvas.toDataURL('image/png');          
        callback(imageData);
    };

    image.src = url;
};


convertToBase64('img/circle.png', function(imageData)
{
    window.open(imageData);
});

即使我使用带有回调的 image.onload(),在处理 toDataURL() 后我也无法显示结果。

我做错了什么?

更新:我尝试了以下两种解决方案,但均无效。我在这个项目中使用 AngularJS 和 Electron。 我可以通过什么方式强制代码同步? 或者使用 Promises 的一些解决方案?

更新 #2:@Kaiido 指出 toDataURL() 实际上是同步的,这个问题更可能是由于最大 URI 长度。由于我使用的是 Electron 并且图像预览仅用于测试目的,我将把文件保存在一个文件夹中并从那里进行分析。

【问题讨论】:

  • “这是因为在 toDataURL() 函数完成之前结果显示出来的。” 不,toDataURL 方法是同步的。这更有可能是由于位置的最大 URI 长度,您使用的是什么浏览器?为什么需要 base64 版本?如果只是在新页面中打开图像,则首选blobURI(IE 为msSaveorOpenBlob)和canvas.toBlob 方法。
  • 感谢您的回复。因为这个应用程序是在 Electron 中运行的,所以我真的必须使用 Chrome。我想要 dataURL 因为我认为这将是查看结果图像的最快方式(用于测试目的)。无论如何,我改变了我的方法,而不是在新窗口中显示图像,而是将其保存到文件中。
  • No toDataURL 比 toBlob 慢,并且是同步的(可能会冻结您的屏幕)。应该始终首选 toBlob。 chrome 确实支持 toBlob 和 blobURI(使用 URL.createObjectURL(blob) 创建)
  • 我最初采用这种方法是因为我使用的是小图像并且一切都可以无缝运行。感谢您的提示:)

标签: javascript canvas callback base64 todataurl


【解决方案1】:

您的代码看起来绝对没问题。不知道为什么对你不起作用。可能是您的浏览器有问题。也许尝试使用不同的。您也可以使用custom event,它会在图像转换完成时触发。

// using jQuery for custom event

function convertToBase64(url) {
    var image = new Image();
    image.src = url;
    image.onload = function() {
        var canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        var ctx = canvas.getContext('2d');
        ctx.drawImage(image, 0, 0);
        var imageData = canvas.toDataURL();
        $(document).trigger('conversionCompleted', imageData);
    };
};

convertToBase64('4mb.jpg');
$(document).on('conversionCompleted', function(e, d) {
    window.open(d);
});

【讨论】:

  • 你的 image.src 行应该在 image.onload 的定义之后。
  • 似乎有很多与此相关的帖子。这个概念是,如果一个图像被缓存,那么它可以在执行前进之前立即加载以设置 image.onload,因此 onload 永远不会触发。这是一篇这样的帖子,但也有好几篇……stackoverflow.com/questions/14648598/…
  • @siam 感谢您的建议。我正在使用在 Chrome 上运行的 Electron。您的解决方案无效,我可以尝试其他选项吗?如果有帮助,我正在使用 AngularJS...
【解决方案2】:

这种方法可能适合您。它使用原生 html 元素在屏幕上显示图像,然后将其绘制到画布上,然后将画布转换为 Base64,然后清除画布并将转换后的图像绘制到画布上。然后,您可以在顶部图像(原始)和底部图像(转换后)之间滚动。我在大图像上尝试过,第二张图像需要一两秒钟才能绘制,但它似乎工作......

HTML 在这里:

<img id="imageID">
<canvas id="myCanvas" style="width:400;height:400;">
</canvas>

脚本在这里:

var ctx;
function convertToBase64(url, callback)
{
  var image = document.getElementById("imageID");
  image.onload = function() {
    var canvas = document.getElementById("myCanvas");
    canvas.width = image.naturalWidth;
    canvas.height = image.naturalHeight;
    ctx = canvas.getContext("2d");
    ctx.drawImage(image,0,0);
    var imageData = canvas.toDataURL('image/png');
    ctx.fillStyle ="#FFFFFF";
    ctx.fillRect(0,0,canvas.width,canvas.height);
    callback(imageData);
  };
  image.src = url;
};

var imagename = 'images/bigfiletest.jpg';

window.onload = function () {
  convertToBase64(imagename, function(imageData) {
    var myImage = new Image();
    myImage.src = imageData;
    ctx.drawImage(myImage,0,0);    
  });
}

请注意,我也尝试过不使用回调,并且效果也很好......

【讨论】:

  • 感谢您的帮助。不幸的是,您的解决方案也不起作用。我可以尝试任何其他选择吗?如果有帮助,我正在使用 AngularJS 和 Electron。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-09
  • 2015-12-06
  • 1970-01-01
  • 2018-08-25
  • 2020-01-31
  • 2014-06-10
相关资源
最近更新 更多