问题
I want to get the data of an image of a fabric.Image object to loop through each pixel and change its color if it's a given color to another given color. But I don't want to get the data of the entire canvas, only of that specific object. Something like this -
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;
}
}
}
But I do not know how to get the data of an object (I know getData()
is not a real function).
TL;DR: I want a way to get the data of an image of a Fabric object (not the entire canvas) and then be able to manipulate its pixels and put the modified image back in.
回答1:
The best way to do this is with an image filter, I'd say. Fortunately, Fabric provides an image filter with a very similar functionality - RemoveColor
(http://fabricjs.com/docs/fabric.js.html#line23120). We can take that implementation, tweak it a little to replace with a configurable color instead of removing, and that should do the trick.
There are three main changes we make to the RemoveColor
class to create our ReplaceColor
class:
- Adding a
replacementColor
field that takes a 4 wide array of the color to replace with - Modifying the webGL to take in an extra parameter for the replacement color:
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' +
'}',
- Updating the
applyTo2d
method to also use the replacement color:
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/
Note that on the JSFiddle I cranked up the distance field, so it's a pretty drastic modification. The default value is normally 0.02
.
来源:https://stackoverflow.com/questions/65608195/fabric-js-manipulate-image-object-pixel-by-pixel-to-change-color