为HTML Canvas制作自己的过滤器

时间:2018-03-16 00:04:14

标签: javascript html css image canvas

我想为HTML Canvas创建自己的过滤器。代码如下。我收到错误:

  

无法执行' putImageData' on' CanvasRenderingContext2D':参数1的类型不是' ImageData'

但是,如果我使用

更改SELECT ActualName, lower(regexp_replace(column_name, E'([A-Z])', E'\_\\1','g')) As corrected_name FROM Tablename 末尾的return outputData;

filter(input, values){}

一切正常,但我想,for (let i = 0; i < outputData.length; i++){ inputData[i] = outputData[i]; }返回值。我怎么能这样做?

&#13;
&#13;
filter(input, values){}
&#13;
//////////////////////////////
// Distortion Filter        //
// Originally by JoelBesada // 
//////////////////////////////
class FilterDistortion {
  constructor() {
    this.name = 'Distortion';
    this.defaultValues = {
      size: 4,
      density: 0.5,
      mix: 0.5,
    };
    this.valueRanges = {
      size: { min: 1, max: 10 },
      density: { min: 0.0, max: 1.0 },
      mix: { min: 0.0, max: 1.0 },
    };
  }

  filter(input, values = this.defaultValues) {
    const { width, height } = input;

    const inputData = input.data;
    const outputData = inputData.slice();

    let size = (values.size === undefined)
      ? this.defaultValues.size
      : parseInt(values.size, 10);
    if (size < 1) size = 1;

    const density = (values.density === undefined)
      ? this.defaultValues.density
      : Number(values.density);

    const mix = (values.mix === undefined)
      ? this.defaultValues.mix
      : Number(values.mix);

    const radius = size + 1;
    const numShapes = parseInt(((((2 * density) / 30) * width) * height) / 2, 10);

    for (let i = 0; i < numShapes; i++) {
      const sx = (Math.random() * (2 ** 32) & 0x7fffffff) % width;
      const sy = (Math.random() * (2 ** 32) & 0x7fffffff) % height;

      const rgb2 = [
        inputData[(((sy * width) + sx) * 4) + 0],
        inputData[(((sy * width) + sx) * 4) + 1],
        inputData[(((sy * width) + sx) * 4) + 2],
        inputData[(((sy * width) + sx) * 4) + 3],
      ];

      for (let x = sx - radius; x < sx + radius + 1; x++) {
        for (let y = sy - radius; y < sy + radius + 1; y++) {
          if (x >= 0 && x < width && y >= 0 && y < height) {
            const rgb1 = [
              outputData[(((y * width) + x) * 4) + 0],
              outputData[(((y * width) + x) * 4) + 1],
              outputData[(((y * width) + x) * 4) + 2],
              outputData[(((y * width) + x) * 4) + 3],
            ];
            const mixedRGB = this.mixColors(mix, rgb1, rgb2);

            for (let k = 0; k < 3; k++) {
              outputData[(((y * width) + x) * 4) + k] = mixedRGB[k];
            }
          }
        }
      }
    }

    return outputData;
  }

  linearInterpolate(t, a, b) {
    return a + (t * (b - a));
  }

  mixColors(t, rgb1, rgb2) {
    const r = this.linearInterpolate(t, rgb1[0], rgb2[0]);
    const g = this.linearInterpolate(t, rgb1[1], rgb2[1]);
    const b = this.linearInterpolate(t, rgb1[2], rgb2[2]);
    const a = this.linearInterpolate(t, rgb1[3], rgb2[3]);

    return [r, g, b, a];
  }
}

/////////////////
// Driver Code //
/////////////////
var img = new Image(); img.onload = draw; img.src = "//i.imgur.com/Kzz84cr.png";
function draw() {
  c.width = this.width; c.height = this.height;
  
  var ctx = c.getContext("2d");
  // main loop
  ctx.drawImage(this, 0, 0);                     // draw video frame
  var data = ctx.getImageData(0, 0, c.width, c.height);
  ctx.putImageData(new FilterDistortion().filter(data), 0, 0);
  ctx.globalCompositeOperation = "source-over";  // "reset"
  // rinse, repeat
}
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

错误消息说明了这一切,您需要传递ImageData作为putImageData的第一个参数。
在这里你传递一个UInt8ClampedArray。

因此,您必须从此TypedArray创建new ImageData(当ImageData构造函数可用时),或者从画布上下文创建create an empty ImageData,然后设置其所有.data' s值为新值。

//////////////////////////////
// Distortion Filter        //
// Originally by JoelBesada // 
//////////////////////////////
class FilterDistortion {
  constructor() {
    this.name = 'Distortion';
    this.defaultValues = {
      size: 4,
      density: 0.5,
      mix: 0.5,
    };
    this.valueRanges = {
      size: { min: 1, max: 10 },
      density: { min: 0.0, max: 1.0 },
      mix: { min: 0.0, max: 1.0 },
    };
  }

  filter(input, values = this.defaultValues) {
    const { width, height } = input;

    const inputData = input.data;
    const outputData = inputData.slice();

    let size = (values.size === undefined)
      ? this.defaultValues.size
      : parseInt(values.size, 10);
    if (size < 1) size = 1;

    const density = (values.density === undefined)
      ? this.defaultValues.density
      : Number(values.density);

    const mix = (values.mix === undefined)
      ? this.defaultValues.mix
      : Number(values.mix);

    const radius = size + 1;
    const numShapes = parseInt(((((2 * density) / 30) * width) * height) / 2, 10);

    for (let i = 0; i < numShapes; i++) {
      const sx = (Math.random() * (2 ** 32) & 0x7fffffff) % width;
      const sy = (Math.random() * (2 ** 32) & 0x7fffffff) % height;

      const rgb2 = [
        inputData[(((sy * width) + sx) * 4) + 0],
        inputData[(((sy * width) + sx) * 4) + 1],
        inputData[(((sy * width) + sx) * 4) + 2],
        inputData[(((sy * width) + sx) * 4) + 3],
      ];

      for (let x = sx - radius; x < sx + radius + 1; x++) {
        for (let y = sy - radius; y < sy + radius + 1; y++) {
          if (x >= 0 && x < width && y >= 0 && y < height) {
            const rgb1 = [
              outputData[(((y * width) + x) * 4) + 0],
              outputData[(((y * width) + x) * 4) + 1],
              outputData[(((y * width) + x) * 4) + 2],
              outputData[(((y * width) + x) * 4) + 3],
            ];
            const mixedRGB = this.mixColors(mix, rgb1, rgb2);

            for (let k = 0; k < 3; k++) {
              outputData[(((y * width) + x) * 4) + k] = mixedRGB[k];
            }
          }
        }
      }
    }

    return outputData;
  }

  linearInterpolate(t, a, b) {
    return a + (t * (b - a));
  }

  mixColors(t, rgb1, rgb2) {
    const r = this.linearInterpolate(t, rgb1[0], rgb2[0]);
    const g = this.linearInterpolate(t, rgb1[1], rgb2[1]);
    const b = this.linearInterpolate(t, rgb1[2], rgb2[2]);
    const a = this.linearInterpolate(t, rgb1[3], rgb2[3]);

    return [r, g, b, a];
  }
}

/////////////////
// Driver Code //
/////////////////
var img = new Image(); img.crossOrigin=1; img.onload = draw; img.src = "//i.imgur.com/Kzz84cr.png";
function draw() {
  c.width = this.width; c.height = this.height;
  
  var ctx = c.getContext("2d");
  // main loop
  ctx.drawImage(this, 0, 0);                     // draw video frame
  var data = ctx.getImageData(0, 0, c.width, c.height);
  var distortedData = new FilterDistortion().filter(data);
  var distortedImg;
  try{
    distortedImg = new window.ImageData(distortedData, c.width, c.height);
  }
  catch(e) {
    distortedImg = ctx.createImageData(c.width, c.height);
    distortedImg.data.set(distortedData);
  }
  ctx.putImageData(distortedImg, 0, 0);
  ctx.globalCompositeOperation = "source-over";  // "reset"
  // rinse, repeat
}
<canvas id=c></canvas>