为HTML画布制作自己的过滤器 [英] Make your own filter for HTML Canvas

查看:166
本文介绍了为HTML画布制作自己的过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


未能在'CanvasRenderingContext2D'上执行'putImageData':参数1不是'ImageData'类型


但如果在结尾处更改 return outputData; filter(输入值){} with

for(let i = 0; i< outputData.length; i ++ ){
inputData [i] = outputData [i];
}



一切正常,但我想, filter(input,values){} 返回值。我该怎么做?

  ////////////////////////// //////失真过滤器////本来由JoelBesada // ////////////////////////////// class FilterDistortion {构造函数(){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();让size =(values.size === undefined)? this.defaultValues.size:parseInt(values.size,10);如果(大小<1)大小= 1;常量密度=(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  = 0& amp ;& x< width&& y> = 0&& y< height){const rgb1 = [outputData [(((y * width)+ x)* 4)+ 0] [((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]);返回[r,g,b,a]; }} ///////////////////驱动代码/////////////////// var img = new Image(); img.onload =绘制; img.src =//i.imgur.com/Kzz84cr.png\";function draw(){c.width = this.width; c.height = this.height; var ctx = c.getContext(2d); //主循环ctx.drawImage(this,0,0); //绘制视频帧var data = ctx.getImageData(0,0,c.width,c.height); ctx.putImageData(new FilterDistortion()。filter(data),0,0); ctx.globalCompositeOperation =source-over; //reset//漂洗,重复}  

< ; canvas id = c>< / canvas>

解决方案

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

在这里你传递一个UInt8ClampedArray。



因此,您必须创建一个新的ImageData (当ImageData构造函数可用时)或者从您的画布上下文创建一个空的ImageData ,然后设置其所有 .data 的值到新值。

///// ///////////////////////////失真过滤器////最初由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();让size =(values.size === undefined)? this.defaultValues.size:parseInt(values.size,10);如果(大小<1)大小= 1;常量密度=(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 = 0& amp ;& x< width&& y> = 0&& y< height){const rgb1 = [outputData [(((y * width)+ x)* 4)+ 0] [((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]);返回[r,g,b,a]; }} ///////////////////驱动代码/////////////////// var img = new Image(); img.crossOrigin = 1; img.onload =绘制; img.src =//i.imgur.com/Kzz84cr.png\";function draw(){c.width = this.width; c.height = this.height; var ctx = c.getContext(2d); //主循环ctx.drawImage(this,0,0); //绘制视频帧var data = ctx.getImageData(0,0,c.width,c.height); var distortedData = new FilterDistortion()。filter(data); var distortedImg;尝试{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//漂洗,重复}

< ; canvas id = c>< / canvas>

I wanna create my own filter for HTML Canvas. Code Below. I get error:

Failed to execute 'putImageData' on 'CanvasRenderingContext2D': parameter 1 is not of type 'ImageData'

But if I change return outputData; at end of filter(input, values){} with

for (let i = 0; i < outputData.length; i++){ inputData[i] = outputData[i]; }

Everything works fine, but I wanna, that filter(input, values){} returns value. How I can do that?

//////////////////////////////
// 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
}

<canvas id=c></canvas>

解决方案

The error message says it all, you need to pass an ImageData as the first param of putImageData.
Here you are passing an UInt8ClampedArray.

So you would have to either create a new ImageData from this TypedArray (when the ImageData constructor is available), or to create an empty ImageData from your canvas context and then set all its .data's values to the new values.

//////////////////////////////
// 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>

这篇关于为HTML画布制作自己的过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆