【问题标题】:Fabric.js manipulate Image object pixel by pixel to change colorFabric.js 逐像素操作 Image 对象以改变颜色
【发布时间】:2025-12-20 09:45:11
【问题描述】:

我想获取 fabric.Image 对象的图像数据,以循环遍历每个像素并将其颜色(如果它是给定颜色)更改为另一种给定颜色。但我不想获取整个画布的数据,只获取那个特定对象的数据。像这样 -

changeColor = (object, targetColor, replacementColor) => {
  data = object.getData();

  for(var i = 0, n = data.length; i<n; i+=4){
    let r = data[i];
    let g = data[i + 1];
    let b = data[i + 2];
    
    if(r === targetColor.r && g === targetColor.g && b === targetColor.b){
      imgd[i] = replacementColor.r;
      imgd[i + 1] = replacementColor.g;
      imgd[i + 2] = replacementColor.b;
      imgd[i + 3] = replacementColor.a;
    }
  }
}

但我不知道如何获取对象的数据(我知道getData()不是真正的函数)。

TL;DR:我想要一种方法来获取 Fabric 对象(而不是整个画布)的图像数据,然后能够操纵其像素并将修改后的图像放回原处。

【问题讨论】:

    标签: javascript image fabricjs todataurl


    【解决方案1】:

    我想说,最好的方法是使用图像过滤器。幸运的是,Fabric 提供了一个具有非常相似功能的图像过滤器 - RemoveColor (http://fabricjs.com/docs/fabric.js.html#line23120)。我们可以采用该实现,稍微调整一下以替换为可配置的颜色而不是删除,这样就可以了。

    我们对RemoveColor 类进行了三个主要更改以创建我们的ReplaceColor 类:

    • 添加一个 replacementColor 字段,该字段采用 4 个宽数组替换颜色
    • 修改 webGL 以获取替换颜色的额外参数:
            fragmentSource: 'precision highp float;\n' +
                'uniform sampler2D uTexture;\n' +
                'uniform vec4 uLow;\n' +
                'uniform vec4 uHigh;\n' +
                'uniform vec4 uRep;\n' + // New variable for replacement color
                'varying vec2 vTexCoord;\n' +
                'void main() {\n' +
                'gl_FragColor = texture2D(uTexture, vTexCoord);\n' +
                'if(all(greaterThan(gl_FragColor.rgb,uLow.rgb)) && all(greaterThan(uHigh.rgb,gl_FragColor.rgb))) {\n' +
                'gl_FragColor.rgb = uRep.rgb;\n' + // Here we set the color instead of 0-ing out the alpha
                'gl_FragColor.a = uRep.a;\n' +
                '}\n' +
                '}',
    
    • 更新applyTo2d 方法以也使用替换颜色:
            applyTo2d: function (options) {
                var imageData = options.imageData,
                    data = imageData.data, i,
                    distance = this.distance * 255,
                    r, g, b,
                    source = new fabric.Color(this.color).getSource(),
                    lowC = [
                        source[0] - distance,
                        source[1] - distance,
                        source[2] - distance,
                    ],
                    highC = [
                        source[0] + distance,
                        source[1] + distance,
                        source[2] + distance,
                    ];
    
                for (i = 0; i < data.length; i += 4) {
                    r = data[i];
                    g = data[i + 1];
                    b = data[i + 2];
                    if (r > lowC[0] &&
                        g > lowC[1] &&
                        b > lowC[2] &&
                        r < highC[0] &&
                        g < highC[1] &&
                        b < highC[2]) {
                        data[i] = this.replacementColor[0]; // Here we also modify the color directly instead of 0-ing out the alpha
                        data[i + 1] = this.replacementColor[1];
                        data[i + 2] = this.replacementColor[2];
                        data[i + 3] = this.replacementColor[3];
                    }
                }
            }
    

    JSFiddle:https://jsfiddle.net/8coka6yv/

    请注意,我在 JSFiddle 上调高了距离场,所以这是一个相当大的修改。默认值通常为0.02

    【讨论】:

    • 嗨,我测试了它,它似乎适用于相对矩形的图像,但对于弯曲的图像,结果似乎像这样块状 - link(我也尝试减少距离)我尝试了解决这个问题的几种方法,但不能。 (我正在尝试将这里的白色替换为红色)
    • 尝试减小distance 的值。 distance 的值乘以 255 以确定要替换的有效像素的范围。如果你将它设置为 1/255,它应该只替换那个确切的颜色。