3

Using the Javascript canvas element, is it possible to copy a 2-dimensional array of RGB values to a canvas?

<html>
<body>
<canvas id="canvas" height="200" width="200"></canvas>
<script type = "text/javascript">

//copy the following array to the canvas:
var arr1 = [
[[255, 255, 255],[200, 200, 0],[200, 200, 200]],
[[200, 0, 0],[200, 200, 0],[200, 200, 0]],
[[200, 200, 0],[200, 0, 0],[200, 200, 0]]
]

<script>
</body>
</html>
Anderson Green
  • 30,230
  • 67
  • 195
  • 328
  • I found a relevant example: http://jsfiddle.net/Z6CHB/1/ Now I just need to modify it so that it will copy an array to the canvas. – Anderson Green Dec 11 '12 at 18:38
  • The inverse of this would be getting the pixels from the canvas: http://stackoverflow.com/questions/6727090/return-pixels-of-a-canvas-object – Anderson Green Dec 14 '12 at 06:51

1 Answers1

4

You can use getImageData/putImageData. Just calculate the right index (it's RGBA values in one big array): http://jsfiddle.net/zjypd/ (the jsFiddle has an enlarged canvas to show the pixels).

var arr1 = [
    [[255, 255, 255],[200, 200, 0],[]],
    [[200, 0, 0],[200, 200, 0],[200, 200, 0]],
    [[200, 200, 0],[200, 0, 0],[200, 200, 0]]
];

var ctx = document.querySelector("canvas").getContext("2d");

var height = arr1.length;
var width = arr1[0].length;

var h = ctx.canvas.height;
var w = ctx.canvas.width;

var imgData = ctx.getImageData(0, 0, w, h);
var data = imgData.data;  // the array of RGBA values

for(var i = 0; i < height; i++) {
    for(var j = 0; j < width; j++) {
        var s = 4 * i * w + 4 * j;  // calculate the index in the array
        var x = arr1[i][j];  // the RGB values
        data[s] = x[0];
        data[s + 1] = x[1];
        data[s + 2] = x[2];
        data[s + 3] = 255;  // fully opaque
    }
}

ctx.putImageData(imgData, 0, 0);
pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • One of the arrays in my example was empty - sorry for the typo! (The empty array should be `[200, 200, 200]`). – Anderson Green Dec 11 '12 at 18:42
  • To change the array scale (in this example), you only need to change the pixel value in the css section. :) – Anderson Green Dec 11 '12 at 18:49
  • 1
    @AndersonGreen: I just realized you can better use `(0, 0, w, h)` instead of the hardcoded `(0, 0, 3, 3)` for the arguments of `getImageData`. – pimvdb Dec 11 '12 at 18:56
  • It's also possible to resize the canvas so that it matches the dimensions of the array: http://stackoverflow.com/a/331462/975097 – Anderson Green Dec 16 '12 at 20:16
  • Here's my first attempt at getting the array to resize automatically. I'm still not sure whether it's working correctly. http://jsfiddle.net/zjypd/4/ – Anderson Green Dec 16 '12 at 21:40
  • @AndersonGreen: It looks fine. The only issue I can think of is the white space above the canvas. That's because `` is an inline element, so it is positioned at the text baseline. – pimvdb Dec 16 '12 at 21:46
  • I meant to write "canvas" when I wrote "array" in the above post. – Anderson Green Dec 16 '12 at 21:47
  • I filled the array with a horizontal stripe pattern, and the canvas showed a diagonal stripe pattern instead. There must be an error somewhere: http://jsfiddle.net/zjypd/5/ – Anderson Green Dec 16 '12 at 21:58
  • I've found the problem: your code only works properly for square arrays of RGB values. It needs to be modified so that it will work with arrays of other dimensions (such as 100x200.) – Anderson Green Dec 16 '12 at 22:14
  • @Anderson Green: Woops, you're completely right. The index calculation is wrong - it has to be `4 * i * w + 4 * j`: advancing one height pixel means advancing one row, which is one full *width*. This just wasn't noticeable in the case `w === h`. – pimvdb Dec 17 '12 at 07:36
  • @pimvdb of course what you _should_ have done was just set `s = 0` outside the loops and just increment it with every write. There's absolutely no need to recalculate it for every pixel, since the offset into `data` just goes up monotonically. – Alnitak Jul 08 '13 at 19:05