3

Hello I request an Image from my server (binay, arraybuffer) and then I would like to convert that arraybuffer to valid imageData that can be drawn on any canvas element.

Besides the imageData made from the ajax request, I also have other imageData objects which I combine all together on a canvas (in order to flatten the image) and produce my final image. However the imageData as mentioned above from the server request results in pure noise I"m not sure what I'm doing wrong to create valid imageData.

Here is my method that tries to convert the arraybuffer into imageData without success.

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: I've managed to convert the arrayBuffer into a b64 image resource-URL and then create an image out of it and then draw th image on to the canvas element, but I'm not interested in such a solution because:

  1. overkill in my opinion

  2. uses callbacks

UPDATE

The images on the server are .png files (RGBA).

And bellow is the ajaxTransport used with jQuery in order to do the binary - arraybuffer requests for images from the server:

$.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();
            }
        };
    }
});
3
  • Is the data raw data or does it represent a file? if raw, in what format is the data, does it contain 8-bit values in RGBA format, in what byte-order? Commented Apr 1, 2015 at 7:33
  • I have updated my question, the image is png a file on the server and I'm using the above ajax Transport "plugin" with jQuery to do an image request. Commented Apr 1, 2015 at 7:43
  • I'm interesetd in png files only because of the transparency Commented Apr 1, 2015 at 7:44

2 Answers 2

2

You can use a Blob and a blob-url to set as image source. This is slightly better than using Base-64 and a Data-URI as you don't need to convert binary data to string, and then back (internally).

The data cannot be set directly to an ImageData object when it exist in a file container, as the "file" (byte-array) must be parsed, decompressed, decoded and converted first.

Example:

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;

Demo

// 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)
  }
}

(Optionally, you can use my png-toy to decode to raw bitmaps)

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you for your time and your answer. I'm aware of this solution but I'm interested in learning how to parse the response and set it as "data" to an ImageData object which can be used directly to a canvas element. I'm aware that I can draw the image you mentioned above into a canvas and the imageData but it's not exactly what I'm looking for. :)
Look at my pngtoy as a starting point (added to answer)
@Syd also look at this answer stackoverflow.com/questions/28593763/…
I will accept your answer, looks solid in any way you might implement such thing at the end, and thnx for the references
@Syd thanks. it would probably be out-of-scope for SO to go through the whole process in any case. As you can see in src directory in the link, there are many special cases that needs to be addressed from validation to chunk types, gzip, interlace mode, line filters, transparency, gamma etc. etc.
0

You can also decode the PNG with this library (PNG.js) without relying on an <img>.

Hopefully the canvas API will be updated in the future with a native decodeImageData method similar to decodeAudioData in the Web Audio API. If it's not planned, maybe request it on the WHATWG tracker?

2 Comments

This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post.
@dbugger how so? the OP says "I would like to convert that arraybuffer to valid imageData that can be drawn on any canvas element". The library I linked does exactly that. Though I'll grant you that I didn't write the code Syd would have to use to call it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.