Fabric JS滤镜与CSS滤镜效果不一致问题求助
解决Fabric JS滤镜与CSS滤镜行为一致的问题
核心问题
CSS的brightness()和contrast()采用乘法/比例型计算逻辑,而Fabric JS默认的对应滤镜是加法/偏移型逻辑,导致同参数下效果差异明显。要实现无缝迁移,需自定义Fabric JS滤镜,匹配CSS的计算规则。
1. 适配CSS风格的亮度滤镜
CSS brightness(n)的逻辑是将每个像素的RGB值乘以n(默认值1),黑色(0,0,0)乘以任何值仍为黑色。Fabric JS默认的Brightness滤镜是给每个像素加固定偏移,不符合需求,需自定义乘法逻辑的滤镜:
// 自定义匹配CSS brightness的滤镜 fabric.Image.filters.BrightnessCSS = fabric.util.createClass(fabric.Image.filters.BaseFilter, { type: 'BrightnessCSS', /** * Brightness value, same as CSS brightness() parameter (default 1) * @type Number * @default 1 */ brightness: 1, fragmentSource: ` precision highp float; uniform sampler2D uTexture; uniform float uBrightness; varying vec2 vTexCoord; void main() { vec4 color = texture2D(uTexture, vTexCoord); // 匹配CSS brightness的乘法逻辑,同时保持alpha通道不变 gl_FragColor = vec4(color.rgb * uBrightness, color.a); } `, applyTo2d: function(options) { var imageData = options.imageData, data = imageData.data, brightness = this.brightness; for (var i = 0, len = data.length; i < len; i += 4) { data[i] = data[i] * brightness; // R data[i + 1] = data[i + 1] * brightness; // G data[i + 2] = data[i + 2] * brightness; // B // alpha通道保持不变 } }, getUniforms: function() { return { uBrightness: this.brightness }; }, toObject: function() { return fabric.util.object.extend(this.callSuper('toObject'), { brightness: this.brightness }); } }); // 注册滤镜,支持从JSON反序列化 fabric.Image.filters.BrightnessCSS.fromObject = fabric.Image.filters.BaseFilter.fromObject;
使用方式
代替默认的Brightness滤镜:
// 示例:设置亮度为1.33(对应CSS filter: brightness(1.33)) const brightnessFilter = new fabric.Image.filters.BrightnessCSS({ brightness: 1.33 }); image.filters.push(brightnessFilter); image.applyFilters(); canvas.renderAll();
2. 适配CSS风格的对比度滤镜
CSS contrast(n)的计算逻辑是:clamp((color - 0.5) * n + 0.5, 0, 1),其中n默认值为1。Fabric JS默认的Contrast滤镜是通过偏移灰度中点实现的,需自定义滤镜匹配CSS逻辑:
// 自定义匹配CSS contrast的滤镜 fabric.Image.filters.ContrastCSS = fabric.util.createClass(fabric.Image.filters.BaseFilter, { type: 'ContrastCSS', /** * Contrast value, same as CSS contrast() parameter (default 1) * @type Number * @default 1 */ contrast: 1, fragmentSource: ` precision highp float; uniform sampler2D uTexture; uniform float uContrast; varying vec2 vTexCoord; void main() { vec4 color = texture2D(uTexture, vTexCoord); // 匹配CSS contrast的计算逻辑:(color - 0.5) * contrast + 0.5,然后 clamp 到0-1 vec3 adjusted = clamp((color.rgb - 0.5) * uContrast + 0.5, 0.0, 1.0); gl_FragColor = vec4(adjusted, color.a); } `, applyTo2d: function(options) { var imageData = options.imageData, data = imageData.data, contrast = this.contrast; for (var i = 0, len = data.length; i < len; i += 4) { // 先将RGB值归一到0-1范围,应用公式后转回0-255 var r = data[i] / 255; var g = data[i + 1] / 255; var b = data[i + 2] / 255; r = Math.min(Math.max((r - 0.5) * contrast + 0.5, 0), 1); g = Math.min(Math.max((g - 0.5) * contrast + 0.5, 0), 1); b = Math.min(Math.max((b - 0.5) * contrast + 0.5, 0), 1); data[i] = r * 255; data[i + 1] = g * 255; data[i + 2] = b * 255; } }, getUniforms: function() { return { uContrast: this.contrast }; }, toObject: function() { return fabric.util.object.extend(this.callSuper('toObject'), { contrast: this.contrast }); } }); // 注册滤镜 fabric.Image.filters.ContrastCSS.fromObject = fabric.Image.filters.BaseFilter.fromObject;
使用方式
代替默认的Contrast滤镜:
// 示例:设置对比度为1.5(对应CSS filter: contrast(1.5)) const contrastFilter = new fabric.Image.filters.ContrastCSS({ contrast: 1.5 }); image.filters.push(contrastFilter); image.applyFilters(); canvas.renderAll();
验证要点
- 默认值(brightness=1、contrast=1)下,图像效果与无滤镜完全一致,和CSS默认行为匹配。
- 调整参数后,黑色区域在亮度滤镜下保持黑色,对比度滤镜的明暗拉伸逻辑和CSS完全对齐。
内容的提问来源于stack exchange,提问作者Ewajs
相关产品推荐
相关产品推荐

