最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - speed up canvas's getImageData - Stack Overflow

programmeradmin4浏览0评论

I need to extract chunks of pixels from the canvas and process them. Currently I am calling getImageData multiple times in nested loops.

_getBinaryStringFromCanvas(canvas) {
  let ctx = canvas.getContext('2d')
  let { xMaxBlock, yMaxBlock, blockSize } = this.metrics;
  let results = '';
  for (let y = 0; y < yMaxBlock; y++) {
    for (let x = 0; x < xMaxBlock; x++) {
      let data = ctx.getImageData(x * blockSize, y * blockSize, blockSize, blockSize);
      let digit = this._somehowProcessTheData(data);
      binaryString += digit;
    }
  }
  return binaryString;
}

This is very slow as xMaxBlock and yMaxBlock can be pretty big. Ideally, I would want to do something like this -

_getChunkFromCache(cache, x, y, width, height){
  // need help implementing this function
}

_getBinaryStringFromCanvas(canvas) {
  let ctx = canvas.getContext('2d')
  let { xMaxBlock, yMaxBlock, blockSize } = this.metrics;
  let results = '';
  let cache = ctx.getImageData(0, 0, xMaxBlock * blockSize, yMaxBlock * blockSize);
  for (let y = 0; y < yMaxBlock; y++) {
    for (let x = 0; x < xMaxBlock; x++) {
      let data = this._getChunkFromCache(cache, x * blockSize, y * blockSize, blockSize, blockSize);
      let digit = this._somehowProcessTheData(data);
      binaryString += digit;
    }
  }
  return binaryString;
}

But I can't seem to prehend the logic required to address the region specified by x, y, width, height in the flat array returned by getImageData.

Any help implementing _getChunkFromCache is highly appreciated.

I need to extract chunks of pixels from the canvas and process them. Currently I am calling getImageData multiple times in nested loops.

_getBinaryStringFromCanvas(canvas) {
  let ctx = canvas.getContext('2d')
  let { xMaxBlock, yMaxBlock, blockSize } = this.metrics;
  let results = '';
  for (let y = 0; y < yMaxBlock; y++) {
    for (let x = 0; x < xMaxBlock; x++) {
      let data = ctx.getImageData(x * blockSize, y * blockSize, blockSize, blockSize);
      let digit = this._somehowProcessTheData(data);
      binaryString += digit;
    }
  }
  return binaryString;
}

This is very slow as xMaxBlock and yMaxBlock can be pretty big. Ideally, I would want to do something like this -

_getChunkFromCache(cache, x, y, width, height){
  // need help implementing this function
}

_getBinaryStringFromCanvas(canvas) {
  let ctx = canvas.getContext('2d')
  let { xMaxBlock, yMaxBlock, blockSize } = this.metrics;
  let results = '';
  let cache = ctx.getImageData(0, 0, xMaxBlock * blockSize, yMaxBlock * blockSize);
  for (let y = 0; y < yMaxBlock; y++) {
    for (let x = 0; x < xMaxBlock; x++) {
      let data = this._getChunkFromCache(cache, x * blockSize, y * blockSize, blockSize, blockSize);
      let digit = this._somehowProcessTheData(data);
      binaryString += digit;
    }
  }
  return binaryString;
}

But I can't seem to prehend the logic required to address the region specified by x, y, width, height in the flat array returned by getImageData.

Any help implementing _getChunkFromCache is highly appreciated.

Share asked Oct 21, 2017 at 13:23 Sayem ShafayetSayem Shafayet 1691 silver badge11 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 9

Don`t copy, index the array directly.

Getting a subsection of the original data array will need to be a copy as type arrays (The array in ImageData.data is a typed array Uint8ClampedArray) are only one dimensional and can not index a 2D section of another array. Creating a copy will only add more work and increase memory usage, slowing your app even further.

Your best option is for the somehowProcessTheData function to work directly with the image data and just index the array to the bounds you supply.

function somehowProcessTheData(imageData, x, y, w, h){
    var i,j;
    var result = ""; 
    var r,g,b,a;
    const data = imageData.data;

    for(j = 0; j < h; j++){
        var idx = (x + (y + j) * imageData.width) * 4;  // get left most byte index for row at y + j
        for(i = 0; i < w; i++){
             r = data[idx ++];
             g = data[idx ++];
             b = data[idx ++];
             a = data[idx ++];
             // do the processing
        }
     }
     return result;
 }
         

Or

function somehowProcessTheData(imageData, x, y, w, h){
    var i,j;
    var result = ""; 
    const data = imageData.data;

    for(j = 0; j < h; j++){
        var idx = (x + (y + j) * imageData.width) * 4;  
        for(i = 0; i < w; i++){
             // get the red green blue values
             var blah = data[idx] + data[idx + 1] + data[idx + 2];
             // do the processing
             // ...
             // increment the index to the next pixel.
             idx += 4;

        }
     }
     return result;
 }

Then in the calling loop

 let data = this.processTheData(cache, x * blockSize, y * blockSize, blockSize, blockSize);
  

 

You can cache the whole area you're working on. It's still slow but hopefully you won't need to do it often. Below is an example to get an int for each pixel instead of 4 bytes.

const pixels = new Int32Array(ctx.getImageData(0, 0, w, h).data.buffer)
pixels[x + y * w]
发布评论

评论列表(0)

  1. 暂无评论