1

I'm trying to generate a pixelated canvas from image source - but there is a strange behavior of the getImageData() function - on images that are higher than my canvas I keep getting only the max height data [square of max-height * max-height]. is there anything I'm missing here?

function generatePixels(){
    const pixel_size = 10;
    const x = 0; const y = 0;
    const w = temp_ctx.canvas.width;
    const h = temp_ctx.canvas.height;

    let min_width = w,
    min_height = h,
    max_width = 0, max_height = 0;

    for (var j = y; j < (y+h); j += pixel_size) {
        for (var i = x; i < (x+w); i += pixel_size) {

            // get current pixel image data (x,y,10,10);
            var data = temp_ctx.getImageData(j, i, pixel_size, pixel_size).data;

            // draw pixel on rendered canvas 
            rendered_ctx.fillStyle = '#' + (data[2] | (data[1] << 8) | (data[0] << 16) | (1 << 24)).toString(16).slice(1);
            rendered_ctx.fillRect((j + pixel_size), (i + pixel_size), 10, 10);

      }
    }
}

You can find an example of the code here: https://codepen.io/AceDesigns/pen/dZEmjZ

AceDesigns
  • 26
  • 5
  • Dodn't look closely yet, but don'call multiple time getImageData on small surfaces, call it once on the whole and iterate over the results. getImageData is one of the heaviest operations available in ctx2d API. – Kaiido Dec 07 '17 at 09:52
  • 1
    You use j as the y variable at the beginning of the loop, yet use it for x inside it, Hmmmm! – enhzflep Dec 07 '17 at 11:27
  • @kaii I've tried to take the whole image data & run with a loop on the result - but it make the browser crash due to memory issues... – AceDesigns Dec 07 '17 at 11:40
  • @enhzflep - thanks, I've just noticed what you meant exactly... thought about something else... looks like it can work as you said, will check soon and update :) – AceDesigns Dec 07 '17 at 11:40
  • How did you tried to get the whole image? Inside the loop? Yes that will probably crash. But doing it outside will consume less memory. Also, your whole script could be reduced to `ctx.imageSmoothingEnabled=false; ctx.scale(1/pixelSize, 1/pixelSize); ctx.drawImage(canvas, 0,0,canvas.width*pixelSize,canvas.height*pixelSize);`. ([An example](https://stackoverflow.com/a/35793522/3702797)) And if you really want to go pixel per pixel, work on an other imageData to set your pixel values instead of filling a lot of rects like that. – Kaiido Dec 07 '17 at 12:11
  • @Kaiido - when I've tried to take the whole image it was outside the loop as seen here: const imageData = setup.ctx.getImageData(0, 0, w, h).data; let pixelsData = []; for(var i=0; i<= imageData.length; i+4){ pixelsData.push({0: imageData[i], 1: imageData[i+1], 2: imageData[i+2],3: imageData[i+3]}) } In my original code I'm not drawing those rects - I'm using it to be filled in an array for later use, so drawing them won't really help me in this one - but thanks, I'll definitely save your solution for any other time I need to do something like this :) – AceDesigns Dec 07 '17 at 12:15
  • 1
    The codepen was deleted, or the link is bad... – gillyb Dec 07 '17 at 13:53

1 Answers1

0

Please find the workable code below. The issue is with the for loop condition.

for (var j = y; j < (y+h); j += pixel_size) { for (var i = x; i < (x+w); i += pixel_size) {

Saravanan
  • 1
  • 1