Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

实现高斯模糊效果 #13

Open
i-zxl opened this issue Jun 15, 2021 · 0 comments
Open

实现高斯模糊效果 #13

i-zxl opened this issue Jun 15, 2021 · 0 comments

Comments

@i-zxl
Copy link
Owner

i-zxl commented Jun 15, 2021

image

设计思路,将背景图缩小为16*16的图片,减小计算图片大小的像素点。

/**
 * 
 * 高斯模糊模块
 */

/**
 * -------------------------------------------
 * @param { ImageData } imgData 图片数据
 * @param { Number }    radius  模糊半径
 * @param { Number }    sigma   权重参数
 * @return { ImageData }
 */
export const gaussBlur = function(imgData, radius, sigma) {
  const pixes = imgData.data;
  const width = imgData.width;
  const height = imgData.height;
  const gaussMatrix = [];
  let gaussSum = 0;
  let x;
  let y;
  let r;
  let g;
  let b;
  let a;
  let i;
  let j;
  let k;

  radius = Math.floor(radius) || 3;
  sigma = sigma || radius / 3;

  a = 1 / (Math.sqrt(2 * Math.PI) * sigma);
  b = -1 / (2 * sigma * sigma);

  // 生成高斯矩阵
  for (i = 0, x = -radius; x <= radius; x++, i++) {
    g = a * Math.exp(b * x * x);
    gaussMatrix[i] = g;
    gaussSum += g;
  }

  // x 方向一维高斯运算
  for (y = 0; y < height; y++) {
    for (x = 0; x < width; x++) {
      r = g = b = a = 0;
      gaussSum = 0;
      for (j = -radius; j <= radius; j++) {
        k = x + j;
        if (k >= 0 && k < width) {
          // 确保 k 没超出 x 的范围
          // r,g,b,a 四个一组
          i = (y * width + k) * 4;
          r += pixes[i] * gaussMatrix[j + radius];
          g += pixes[i + 1] * gaussMatrix[j + radius];
          b += pixes[i + 2] * gaussMatrix[j + radius];
          // 计算权和
          gaussSum += gaussMatrix[j + radius];
        }
      }
      i = (y * width + x) * 4;
      // 计算加权均值
      pixes[i] = r / gaussSum;
      pixes[i + 1] = g / gaussSum;
      pixes[i + 2] = b / gaussSum;
    }
  }
  // y 方向一维高斯运算
  for (x = 0; x < width; x++) {
    for (y = 0; y < height; y++) {
      r = g = b = a = 0;
      gaussSum = 0;
      for (j = -radius; j <= radius; j++) {
        k = y + j;
        if (k >= 0 && k < height) {
          // 确保 k 没超出 y 的范围
          i = (k * width + x) * 4;
          r += pixes[i] * gaussMatrix[j + radius];
          g += pixes[i + 1] * gaussMatrix[j + radius];
          b += pixes[i + 2] * gaussMatrix[j + radius];
          gaussSum += gaussMatrix[j + radius];
        }
      }
      i = (y * width + x) * 4;
      pixes[i] = r / gaussSum;
      pixes[i + 1] = g / gaussSum;
      pixes[i + 2] = b / gaussSum;
    }
  }
  return imgData;
};

/**
 * 对远程图片进行高斯模糊,并输出为指定尺寸
 * @deprecated
 * 新的API会在 utils/blur 中提供
 * ------------------------------------
 * @param { String }    URL 图片URL
 * @param { Number }    w   输出宽度
 * @param { Number }    h   输出高度
 * @param { Number }    r   模糊半径
 * @return {Promise<String>}  返回图片的 base64 URL
 */
export const blurG = (URL, w = 16, h = 16, r = 12) => {
  return new Promise((resolve, reject) => {
    const IMG = new Image();
    IMG.crossOrigin = '*';
    IMG.onload = function() {
      const Canvas = document.createElement('CANVAS');
      try {
        Canvas.width = w;
        Canvas.height = h;
        const ctx = Canvas.getContext('2d');
        ctx.fillStyle = '#fff';
        ctx.fillRect(0, 0, w, h);
        ctx.drawImage(IMG, 0, 0, w, h);

        const d = ctx.getImageData(0, 0, w, h);
        const gd = gaussBlur(d, r, 0);
        ctx.putImageData(gd, 0, 0);
        resolve(Canvas.toDataURL());
      } catch (e) {
        reject({});
      }
    };
    IMG.src = URL;
  });
};

尽管上边执行本身还是挺快的,但是涉及到原图的加载,可以使用小图的加载,优化执行速度。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant