9

First of all I am aware there are standard methods of achieving this (readAsDataURL and drawImage), but unfortunately they are not usable for this specific use case.

I am reading an image using the filereader API as an arraybuffer like so:

    var reader = new fileReader();
    reader.onload = function(e){

          var byteArray = new Uint8ClampedArray(e.target.result);
          //do stuff to this array
    }
    reader.readAsArrayBuffer(file);

I am then creating a clampedarray with this returned data.

What I want to be able to do is now draw this pixel array directly to a canvas using putImageData

Currently I am doing the following:

var byteArray = new Uint8ClampedArray(e.target.result);
var imgdata = ctx.createImageData(img.width, img.height);
var canvdata = imgdata.data;

for (var i = 0; i < canvdata.length; i += 4) {
    canvdata[i] = byteArray[i];
    canvdata[i + 1] = byteArray[i + 1];
    canvdata[i + 2] = byteArray[i + 2];
    canvdata[i + 3] = byteArray[i + 3];
}
ctx.putImageData(imgdata, 0, 0);

Using this method, although the data gets drawn to the canvas, it appears like garbled snow or noise and is not a correct representation of the image.

This leads me to believe that I am constructing the imagedata data incorrectly in my loop or perhaps my initial method of getting the pixel array is incorrect.

To summarize, I would like to be able to take an arraybuffer (of a jpeg) retrieved via the html5 fileReader API and then create a canvas compatible imageData array, so that it can later be pushed into a canvas using putImageData

Thanks in advance.

1 Answer 1

8

Edit

A JPEG file isn't a simple byte-array of colour data, and therefore you can't simply load it in like this. If you want to get around this without importing directly into a canvas you'll have to use a JPEG decoding library, such as this project by notmasteryet which I found via a quick google search.

Original

unfortunately they are not usable for this specific use case

Why are they not usable?

// example array
u = new Uint8ClampedArray(4);
u[0] = 255, u[1] = 56, u[2] = 201, u[3] = 8; // [255, 56, 201, 8]
// to String
str = String.fromCharCode.apply(null, u); // "ÿ8É"
// to Base64
b64 = btoa(str); // "/zjJCA=="
// to DataURI
uri = 'data:image/jpeg;base64,' + b64; // "data:image/jpeg;base64,/zjJCA=="

And the reverse

// uri to Base64
b64 = uri.slice(uri.indexOf(',')+1);
// to String
str = atob(b64);
// to Array
arr = str.split('').map(function (e) {return e.charCodeAt(0);});
// to Uint8ClampedArray
u = new Uint8ClampedArray(arr); // [255, 56, 201, 8]
Sign up to request clarification or add additional context in comments.

8 Comments

I omitted the reason due to it requiring a lengthy explanation. In a nutshell Firefox has a confirmed bug when scaling multiple large images in a canvas using drawImage. e.g try scaling down 100 1920x1080 jpegs in a loop down to half their original size using drawImage. You will see the memory usage grow exponentially up to around 3gb before the browser crashes. Even when removing all references. Although the garbage collector reduces the memory usage after the final image is complete it does not keep it steady throughout the process. In contrast Chromes memory usage stays level.
This is an attempt to workaround this issue by scaling the imagedata down in javascript before it ever hits a canvas. The only other solution I have is to set a 3 second timeout between each image scale to allow the garbage collector to clean up. This unfortunately is not an acceptable waiting time.
The issue is a JPEG file very rarely contains a pixel array - it is compressed. You could load it into a canvas and have the browser's JPEG library decode it, then copy out the pixel-by-pixel data into an array (or into a second canvas).
I see, well that explains the problem. Unfortunately doing as you suggested (loading it into a canvas) causes the memory issue. What I really need is a pure javascript JPEG library to decode the data into a pixel array.
Thanks Paul.... Your first solution unfortunatley causes the same issue, it appears as though Firefox causes a long time to release the original imagedata even when a canvas has been cleared and all references have gone. I have actually just found and tried the the library you have pointed to and it actually works perfectly! albeit a little slow. Hopefully moving this into a webworker will help and keep the UI responsive. If you want to put the library suggestion into an answer I will award it to you. Thanks!
|

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.