将ajax的arraybuffer响应绘制到画布中

3

你好,我需要从我的服务器请求一个图像(二进制、数组缓冲器),然后我想将该数组缓冲器转换为有效的imageData,以便在任何画布元素上绘制。

除了来自ajax请求的imageData之外,我还有其他的imageData对象,我将它们组合在一起放在画布上(为了压平图像)并生成我的最终图像。然而,如上所述来自服务器请求的imageData结果纯粹是噪音,我不确定我做错了什么来创建有效的imageData。

这是我的方法,试图将数组缓冲器转换为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;

};

提示: 我已经成功将arrayBuffer转换为b64图像资源URL,然后将其创建为图像,并将其绘制到画布元素上,但我对这种解决方案不感兴趣,因为:

  1. 在我看来有点过度设计

  2. 使用回调函数

更新

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

以下是使用jQuery中的ajaxTransport进行二进制 - arraybuffer请求从服务器获取图像的代码:

$.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位值?字节顺序是什么? - user1693593
我已更新我的问题,该图片是服务器上的 png 文件,并且我正在使用以上 Ajax 传输“插件”与 jQuery 进行图像请求。 - 0x_Anakin
我只对 PNG 文件感兴趣,因为它具有透明度。 - 0x_Anakin
2个回答

2
您可以使用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将其解码为原始位图。


1
谢谢您的时间和回答。我知道这个解决方案,但我想学习如何解析响应并将其设置为“数据”,以便直接用于Canvas元素的ImageData对象。 我知道我可以将您上面提到的图像绘制到画布上,并获取该图像的imageData,但这并不完全是我要找的。 :) - 0x_Anakin
以我的pngtoy作为起点(添加到答案中) - user1693593
@Syd 还可以看看这个答案 https://dev59.com/DsHrs4cB2Jgan1znmjpL#28595070 - user1693593
我会接受你的答案,无论你最终如何实现这件事情,看起来都很不错。感谢提供参考资料。 - 0x_Anakin
1
@Syd 谢谢。无论如何,让 SO 完全通过整个过程可能都超出了范围。正如您在链接中的 src 目录中所看到的,有许多特殊情况需要解决,包括验证、块类型、gzip、交错模式、行滤镜、透明度、伽马等等。 - user1693593

0

你也可以使用这个库(PNG.js)来解码PNG,而不依赖于<img>标签。

希望将来Canvas API会更新,添加一个类似于Web Audio API中的decodeAudioData方法的本地decodeImageData方法。如果没有计划,或许可以在WHATWG跟踪器上提出请求?


这并没有回答问题。如需对作者进行批评或请求澄清,请在他们的帖子下留言。 - dbugger
@dbugger 怎么了?OP说:“我想将那个arraybuffer转换为有效的imageData,以便可以在任何画布元素上绘制”。我提供的库正好可以做到这一点。虽然我承认我没有编写Syd需要使用的调用代码。 - Touffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接