【问题标题】:Draw ajax arraybuffer response into canvas将ajax arraybuffer响应绘制到画布中
【发布时间】:2015-04-01 07:31:40
【问题描述】:

您好,我从我的服务器(binay,arraybuffer)请求一个图像,然后我想将该 arraybuffer 转换为可以在任何画布元素上绘制的有效 imageData。

除了由 ajax 请求生成的 imageData 之外,我还有其他 imageData 对象,我将它们全部组合在画布上(为了使图像变平)并生成我的最终图像。但是,上面提到的来自服务器请求的 imageData 会产生纯噪声,我不确定我在创建有效 imageData 时做错了什么。

这是我尝试将arraybuffer转换为imageData但没有成功的方法。

ImageProcessor.prototype.imageData = function(data, width, height) {

    width = width || this.settings.width;
    height = height || this.settings.width;

    var newData = (data instanceof Uint8ClampedArray) ? data : new Uint8ClampedArray(data);
    var imageData = this.ctx.createImageData(width, height);

    imageData.data.set(newData);

    return imageData;

};

PS:我已经设法将 arrayBuffer 转换为 b64 图像资源 URL,然后从中创建图像,然后将图像绘制到画布元素上,但我对这样的解决方案不感兴趣,因为:

  1. 在我看来太过分了

  2. 使用回调

更新

服务器上的图像是 .png 文件 (RGBA)。

下面是与 jQuery 一起使用的 ajaxTransport,以便对来自服务器的图像执行二进制数组缓冲区请求:

$.ajaxTransport("+binary", function(options, originalOptions, jqXHR){
    // check for conditions and support for blob / arraybuffer response type
    if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob)))))
    {
        return {
            // create new XMLHttpRequest
            send: function(_, callback){
                // setup all variables
                var xhr = new XMLHttpRequest(),
                    url = options.url,
                    type = options.type,
                    // blob or arraybuffer. Default is blob
                    dataType = options.responseType || "blob",
                    data = options.data || null;

                xhr.addEventListener('load', function(){
                    var data = {};
                    data[options.dataType] = xhr.response;
                    // make callback and send data
                    callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
                });

                xhr.open(type, url, true);
                xhr.responseType = dataType;
                xhr.send(data);
            },
            abort: function(){
                jqXHR.abort();
            }
        };
    }
});

【问题讨论】:

  • 数据是原始数据还是代表文件?如果是原始的,数据是什么格式的,它是否包含 RGBA 格式的 8 位值,以什么字节顺序?
  • 我已经更新了我的问题,图像是服务器上的 png 文件,我正在使用上面的 ajax Transport“插件”和 jQuery 来进行图像请求。
  • 我对 png 文件感兴趣只是因为它的透明度

标签: javascript ajax html canvas


【解决方案1】:

您可以使用 Blob 和 blob-url 设置为图像源。这比使用 Base-64 和 Data-URI 稍微好一点,因为您不需要将二进制数据转换为字符串,然后再返回(内部)。

当数据存在于文件容器中时,不能直接将其设置为ImageData对象,因为“文件”(字节数组)必须先进行解析、解压缩、解码和转换。

示例

var blob = new Blob([arrayBufferHere], {type: "image/png"}); // set proper mime-type

var domURL = self.URL || self.webkitURL || self,
    url = domURL.createObjectURL(blob),
    img = new Image;

img.onload = function () {
    domURL.revokeObjectURL(url);  // clean up
    // this = image
};
img.src = url;

演示

// load file:
fetch("http://i.imgur.com/rUeQDjE.png", convert, alert);

function convert(buffer) {
  var blob = new Blob([buffer], {type: "image/png"});

  var domURL = self.URL || self.webkitURL || self,
    url = domURL.createObjectURL(blob),
    img = new Image;

  img.onload = function() {
    domURL.revokeObjectURL(url); // clean up
    document.body.appendChild(this);
    // this = image
  };
  img.src = url;
}

function fetch(url, callback, error) {

  var xhr = new XMLHttpRequest();
  try {
    xhr.open("GET", url);
    xhr.responseType = "arraybuffer";
    xhr.onerror = function() {
      error("Network error")
    };
    xhr.onload = function() {
      if (xhr.status === 200) callback(xhr.response);
      else error(xhr.statusText);
    };
    xhr.send();
  } catch (err) {
    error(err.message)
  }
}

(或者,您可以使用我的 png-toy 解码为原始位图)

【讨论】:

  • 感谢您的宝贵时间和回答。我知道这个解决方案,但我有兴趣学习如何解析响应并将其设置为 ImageData 对象的“数据”,该对象可以直接用于画布元素。我知道我可以将您上面提到的图像绘制到画布和 imageData 中,但这并不是我想要的。 :)
  • 以我的pngtoy为起点(添加回答)
  • @Syd 也看看这个答案stackoverflow.com/questions/28593763/…
  • 我会接受你的回答,看起来很可靠,你最终可能会实现这样的事情,谢谢参考
  • @Syd 谢谢。在任何情况下,SO 都可能超出整个过程的范围。正如您在链接中的 src 目录中看到的,从验证到块类型、gzip、隔行模式、行过滤器、透明度、伽玛等,有许多特殊情况需要解决。
【解决方案2】:

您还可以使用 this library (PNG.js) 解码 PNG,而无需依赖 <img>

希望画布 API 将来可以使用类似于 Web Audio API 中的 decodeAudioData 的本机 decodeImageData 方法进行更新。如果没有计划,也许可以在 WHATWG 跟踪器上请求它?

【讨论】:

  • 这没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
  • @dbugger 怎么会这样? OP 说“我想将该数组缓冲区转换为可以在任何画布元素上绘制的有效 imageData”。我链接的图书馆正是这样做的。虽然我承认我没有编写 Syd 必须用来调用它的代码。
猜你喜欢
  • 2015-05-03
  • 2012-11-09
  • 2013-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多