【问题标题】:HTML5 Canvas toDataURL is always the same in a for loopHTML5 Canvas toDataURL 在 for 循环中始终相同
【发布时间】:2016-07-12 18:32:06
【问题描述】:

考虑一下JSFiddle。在其中我选择照片,然后我想使用画布对其进行 base64 编码,以便我可以将它们存储在sessionStorage 中以进行延迟上传。因为我为多个文件设置了它,所以我循环遍历每个文件并创建一个图像和一个画布,但无论如何它似乎每次都输出完全相同的 base64 编码图像。通过测试,我知道在每次循环迭代中,图像都是不同的,并且确实指向不同的文件 blob,但画布只是一遍又一遍地输出相同的东西,我认为这也是文件列表中的最后一个文件。有时它也会输出一个“数据”字符串,仅此而已。如果有人能指出我正确的方向,我会很高兴。

代码如下:

HTML

<style type="text/css">
    input[type="file"] {
        display: none;
    }

    a {
        display: inline-block;
        margin: 6px;
    }
</style>
<form action="#" method="post">
    <input type="file" accept="image/*" multiple />
    <button type="button">Select Photos</button>
</form>
<nav></nav>

JavaScript

console.clear();

$(function () {
  $("button[type=button]").on("click", function (e) {
    $("input[type=file]").trigger("click");
  });
  
  $("input[type=file]").on("change", function (e) {
    var nav = $("nav").empty();
    
    for (var i = 0, l = this.files.length; i < l; i++) {
      var file = this.files[i],
          image = new Image();
          
      $(image).on("load", i, function (e) {
        var canvas = document.createElement("canvas"),
            context = canvas.getContext("2d");
        
      	canvas.height = this.height;
      	canvas.width = this.width;
      	
        context.drawImage(this, 0, 0);
        
        nav.append("<a href=\"" + canvas.toDataURL("image/jpeg") + "\" target=\"_blank\">" + e.data + "</a>");
        
        URL.revokeObjectURL(this.src);
      });
      
      image.src = URL.createObjectURL(file);
    }
  });
});

【问题讨论】:

  • 那是因为你的 .on("load") 处理程序是异步的
  • 我不确定你在问什么。它似乎在我这边工作正常。
  • 当我显示画布时,它会显示每个图像并且内联图像源也是正确的,你需要澄清你想要什么,否则我帮不了你。
  • "image/jpeg".toDataURL() 的问题吗?如果上传的图片不是.jpeg 图片可能无法按预期呈现?
  • 叹息,我发誓,当我离开办公室时,它没有工作。相反,我只是为每个链接上传最后一张图片,不管有多少。我想我是在平行维度或什么的......image/jpeg 不是问题,因为它会像我期望的那样拉起来。此外,这些图像来自 iPad,因此它们始终是 jpeg。

标签: javascript jquery html canvas base64


【解决方案1】:

但不管它似乎输出完全相同的 base64 每次都编码图像。

.load() 事件是异步的。您可以使用$.when()$.Deferred()、用$.map() 替换for 循环来处理异步加载的img 元素。注意显示的a元素文本可能不是数字顺序;可以通过对.then()处的元素进行排序来调整;虽然问题中没有解决,但如果需要,也可以实现图像的顺序列出或加载。

$("input[type=file]").on("change", function(e) {
    var nav = $("nav").empty();
    var file = this.files
    $.when.apply($, $.map(file, function(img, i) {    
      return new $.Deferred(function(dfd) {
        var image = new Image();
        $(image).on("load", i, function(e) {
          var canvas = document.createElement("canvas")
          , context = canvas.getContext("2d");   
          canvas.height = this.height;
          canvas.width = this.width;    
          context.drawImage(this, 0, 0);    
          nav.append("<a href=\"" 
                    + canvas.toDataURL() 
                    + "\" target=\"_blank\">" 
                    + e.data + "</a>");
          dfd.resolve()
          URL.revokeObjectURL(this.src);
        });
        image.src = URL.createObjectURL(img);
        return dfd.promise()
      })
    })).then(function() {
      nav.find("a").each(function() {
        console.log(this.href + "\n");
      })
    })
  });
})

jsfiddle https://jsfiddle.net/bc6x3s02/19/

【讨论】:

  • 我可以接受异步和无序警告。最终,我会将图像存储到 sessionStorage 中,后台上传者会在其中提取它们并继续,因此除了“剩余 x 图像”之外,我不会显示任何视觉问题。
  • “如果上传的图片没有设置“image/jpeg”类型参数,图片可能无法正确渲染”等等,什么!?在画布上绘制的图像是解码图像,无论它们是 jpeg gif png 视频帧还是其他画布,一旦在画布上它只是一组原始像素。这句话的第二部分确实几乎是正确的,只是它不准确地反映图像文件的正确数据URI,因为解码-重新编码过程。如果 OP 想要文件的 dataURI 而不将其重新编码为 jpeg,他应该使用FileReader
  • 不,toDataURL 是一种提取画布上绘制的像素的方法。如果您确实使用fillRect 之类的绘图方法,它也将成为导出数据的一部分。 drawImage 将绘制你传入的 ImageSource 的原始像素。无论它们之前的类型是什么,如果浏览器可以解码它,它就会被绘制。 (您甚至可以在画布上绘制 svg)。但是,一旦在画布上绘制,你就只有像素,没有关于它们来自哪里的更多信息,没有编码,也没有更多的 svg 向量。现在,toDataURL 可以设置用于提取所有这些原始像素的重新编码类型。
  • 对任何图像都不准确!它总是会解码+重新编码它。但这对于将小型 jpeg 或矢量 svg 中的巨大 png 文件转换为 png 很有用。 Ps,您还可以使用getImageData 方法提取像素的原始信息,这将为您提供一个包含每个 r、g、b 和 alpha 通道的每个值的 TypedArray
  • @Gup3rSuR4c "...奇怪的是,文件在每次循环迭代时都是正确的,但读者只是忽略了它们。我该如何解决这个问题?" 注意,@ 987654340@onload 事件也是异步的。见stackoverflow.com/questions/33492797/…stackoverflow.com/questions/28856729/…
猜你喜欢
  • 1970-01-01
  • 2014-11-26
  • 2013-09-19
  • 1970-01-01
  • 2013-07-20
  • 2015-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多