detectRegion(stage, regionToFind) {
    if (!stage.srcCtx) {
      return null;
    }

    const srcData = stage.srcCtx.getImageData(0, 0, stage.srcSize.w, stage.srcSize.h);

    let x, y;

    // First find optical bounds
    // This works by taking an alpha value histogram and finding two maxima to determine
    // low and high alphas.
    let alphaHistogram = [];
    for (x = 0; x < stage.srcSize.w; x++) {
      for (y = 0; y < stage.srcSize.h; y++) {
        let alpha = srcData.data[(y * stage.srcSize.w + x) * 4 + 3];
        alphaHistogram[alpha] = alphaHistogram[alpha] ? alphaHistogram[alpha] + 1 : 1;
      }
    }

    let max1 = 0, max1Freq = 0, max2 = 0, max2Freq = 0;
    for (let i = 0; i < 256; i++) {
      if (alphaHistogram[i] > max1Freq) {
        max2 = max1;
        max2Freq = max1Freq;
        max1 = i;
        max1Freq = alphaHistogram[i];
      } else if (alphaHistogram[i] > max2Freq) {
        max2 = i;
        max2Freq = alphaHistogram[i];
      }
    }

    let alphaMin = (max1 < max2) ? max1 : max2;
    let alphaMax = (max1 > max2) ? max1 : max2;

    const ALPHA_THRESHOLD = 5;

    var opticalBoundsRect = {l:-1, r:-1, t:-1, b:-1};

    // Find left optical bound
    obrLeft:
    for (x = 0; x < stage.srcSize.w; x++) {
      for (y = 0; y < stage.srcSize.h; y++) {
        var alpha = srcData.data[(y * stage.srcSize.w + x) * 4 + 3];
        if (alpha >= alphaMax - ALPHA_THRESHOLD) {
          opticalBoundsRect.l = x;
          break obrLeft;
        }
      }
    }
    // Find right optical bound
    obrRight:
    for (x = stage.srcSize.w - 1; x >= 0; x--) {
      for (y = 0; y < stage.srcSize.h; y++) {
        var alpha = srcData.data[(y * stage.srcSize.w + x) * 4 + 3];
        if (alpha >= alphaMax - ALPHA_THRESHOLD) {
          opticalBoundsRect.r = x;
          break obrRight;
        }
      }
    }
    // Find top optical bound
    obrTop:
    for (y = 0; y < stage.srcSize.h; y++) {
      for (x = 0; x < stage.srcSize.w; x++) {
        var alpha = srcData.data[(y * stage.srcSize.w + x) * 4 + 3];
        if (alpha >= alphaMax - ALPHA_THRESHOLD) {
          opticalBoundsRect.t = y;
          break obrTop;
        }
      }
    }
    // Find bottom optical bound
    obrBottom:
    for (y = stage.srcSize.h - 1; y >= 0; y--) {
      for (x = 0; x < stage.srcSize.w; x++) {
        let alpha = srcData.data[(y * stage.srcSize.w + x) * 4 + 3];
        if (alpha >= alphaMax - ALPHA_THRESHOLD) {
          opticalBoundsRect.b = y;
          break obrBottom;
        }
      }
    }

    let returnRect;

    if (opticalBoundsRect.l >= 0 && opticalBoundsRect.r > opticalBoundsRect.l
        && opticalBoundsRect.t >= 0 && opticalBoundsRect.b > opticalBoundsRect.t) {
      let rect = {
        x: opticalBoundsRect.l,
        y: opticalBoundsRect.t,
        w: opticalBoundsRect.r - opticalBoundsRect.l + 1,
        h: opticalBoundsRect.b - opticalBoundsRect.t + 1
      };

      if (regionToFind == 'opticalbounds' || regionToFind == 'padding') {
        return rect;
      }
    }

    // Next find stretch regions. Only use them if they're within the optical bounds
    if (regionToFind == 'stretch') {
      let newStretchRect = Object.assign({}, stage.stretchRect);

      const summer = new Summer();
      let sums = [];
      for (y = 0; y < stage.srcSize.h; y++) {
        // Compute row
        summer.reset();
        for (let x = 0; x < stage.srcSize.w; x++) {
          summer.addNext(getPixel_(stage, srcData, x, y));
        }
        sums.push(summer.compute());
      }

      let ranges = getEqualRanges_(sums);
      for (let i = 0; i < ranges.length; i++) {
        let range = ranges[i];
        let passesThreshold = false;
        // Check if this row has a minimum alpha
        for (x = 0; x < stage.srcSize.w; x++) {
          let alpha = srcData.data[(range.start * stage.srcSize.w + x) * 4 + 3];
          if (alpha >= alphaMax - ALPHA_THRESHOLD) {
            passesThreshold = true;
            break;
          }
        }
        if (passesThreshold) {
          newStretchRect.y = range.start;
          newStretchRect.h = range.length;
          if (range.length >= 4) {
            // inset a bit to prevent scaling artifacts
            newStretchRect.y++;
            newStretchRect.h -= 2;
          }
          break;
        }
      }

      summer.reset();
      sums = [];
      for (x = 0; x < stage.srcSize.w; x++) {
        // Compute column
        summer.reset();
        for (y = 0; y < stage.srcSize.h; y++) {
          summer.addNext(getPixel_(stage, srcData, x, y));
        }
        sums.push(summer.compute());
      }

      ranges = getEqualRanges_(sums);
      for (let i = 0; i < ranges.length; i++) {
        let range = ranges[i];
        let passesThreshold = false;
        // Check if this column has a minimum alpha
        for (y = 0; y < stage.srcSize.h; y++) {
          let alpha = srcData.data[(y * stage.srcSize.w + range.start) * 4 + 3];
          if (alpha >= alphaMax - ALPHA_THRESHOLD) {
            passesThreshold = true;
            break;
          }
        }

        if (passesThreshold) {
          newStretchRect.x = range.start;
          newStretchRect.w = range.length;
          if (range.length >= 4) {
            // inset a bit to prevent scaling artifacts
            newStretchRect.x++;
            newStretchRect.w -= 2;
          }
          break;
        }
      }

      return newStretchRect;
    }

    return null;
  }
Tries to automatically detect the given region.

Region should be one of 'stretch', 'padding', or 'opticalbounds'