feComposite 滤镜基元用于将两个图像(或者两个滤镜结果)按照一定的规则进行合成. 这类似于图像编辑软件(如 Photoshop)中的图层混合模式, 但它基于 Porter-Duff 合成操作.
它通常需要两个输入源:
in:背景图in2:前景图它核心属性是 operator, 支持以下取值:
over (默认): 前景图覆盖在背景图之上in: 显示前景图与背景图重叠的部位, 且显示的是前景图的像素, 等同于剪切蒙版效果out: 显示前景图不与背景图重叠的部分, 通常用于镂空效果atop: 前景图显示在背景图之上, 但只显示背景图存在的区域, 但是在重叠区域显示前景图的像素, 就像把贴纸贴在物体表面xor: 显示未重叠的区域(异或), 重叠区域透明lighter: 简单的加色混合arithmetic: 算术混合, 最灵活, 通过 k1-k4 系数控制, 通过调节 k1-k4 的值, 可以实现不同的混合效果1<svg width="0" height="0">2<filter id="my-composite">3<feComposite in="img" in2="SourceGraphic" operator="in" />4</filter>5</svg>
in 操作符显示 输入源 1 位于 输入源 2 内部的区域. 这通常用于实现遮罩效果:利用一个形状(in2)来裁剪另一个图像(in).
此时, in2 是前景图, in 是背景图, 当我们使用 operator="in" 时, 会显示背景图位于前景图内部的区域.
如下案例, 我们将一张风景图限制在文字 "NATURE" 之中.
01<filter id="demo1-composite" x="0" y="0" width="100%" height="100%">02{/* 1. 定义背景图像源 */}03<feImage04href="/images/supercss/81.base/1.png"05x="0" y="0" width="600" height="300"06preserveAspectRatio="xMidYMid slice"07result="img"08/>0910{/*11input1 (in): 背景图12input2 (in2): 前景图:SourceGraphic (即我们的文字)13operator: in => 显示图片, 但只在文字区域显示14*/}15<feComposite in="img" in2="SourceGraphic" operator="in" />16{/* 添加阴影效果 */}17<feDropShadow dx="1" dy="1" stdDeviation="0" floodColor="#FFFFFF"/>18</filter>
out 操作符显示 输入源 1 位于 输入源 2 外部的区域. 也就是说, 相交的部分会被“挖掉”.
这非常适合制作镂空文字效果:在一个实心矩形块中挖出文字形状.
01<filter id="demo2-knockout" x="-10%" y="0" width="120%" height="100%">02{/* 生成一个深色的填充层 */}03<feFlood floodColor="#1f2937" floodOpacity="0.5" result="floodFill" />0405{/*06operator="out"07in="floodFill" (深色层)08in2="SourceAlpha" (文字的轮廓)09结果:显示前景图与背景图不重叠的区域, 结果为挖空效果.10*/}11<feComposite in="floodFill" in2="SourceAlpha" operator="out" />12</filter>
atop 操作符会将 输入源 1 绘制在 输入源 2 之上, 但仅限于输入源 2 不透明的区域.
这与 in 类似, 不同之处在于 atop 会保留输入源 2(背景)的内容, 而 in 只保留交集.
这常用于给对象添加纹理或光照, 同时保持对象的原始轮廓(alpha 通道).
如下案例, 我们给文字添加了一个金色的纹理.
01<filter id="demo3-atop" x="0" y="0" width="100%" height="100%">02{/* 1. 原始图像 (SourceGraphic) 是下层的银色文字 */}0304{/* 2. 创建上层装饰:一个只占据上半部分的矩形 */}05<feFlood floodColor="#ffd700" result="gold" />06<feOffset in="gold" dy="-60" result="goldMoved" />07{/* 这里用 offset 简单模拟移动, 或者直接用 feImage 加 svg rect */}0809{/* 3. 合成:上层装饰 atop 原始文字10效果:装饰层只会显示在文字区域内.11且装饰层透明/未覆盖的地方, 会显示原始文字.12*/}13<feComposite14in="topLayer"15in2="SourceGraphic"16operator="atop"17/>18</filter>
xor 操作符显示两个图像不重叠的区域. 如果两个不透明像素重叠, 则该位置变为全透明.
这可以用于创造有趣的几何图形交互效果.
01<filter id="demo4-xor" x="-50%" y="-50%" width="200%" height="200%">02<feFlood floodColor="#06b6d4" result="color1" />03<feComposite in="color1" in2="SourceGraphic" operator="in" result="shape1" />0405<feOffset in="shape1" dx={-offset.x} dy={-offset.y} result="shifted1" />0607<feFlood floodColor="#ef4444" result="color2" />08<feComposite in="color2" in2="SourceGraphic" operator="in" result="shape2" />0910<feOffset in="shape2" dx={offset.x} dy={offset.y} result="shifted2" />1112{/* XOR 操作:重叠部分透明 */}13<feComposite in="shifted1" in2="shifted2" operator="xor" />14</filter>
arithmetic 是最强大的模式, 它通过以下公式计算每个像素的值:
result = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4
k1: 控制相乘部分(类似正片叠底/相交区域).k2: 控制输入源 1 的贡献.k3: 控制输入源 2 的贡献.k4: 偏移量(亮度).通过动态调节 k2 和 k3, 我们可以实现两个图像的交叉淡入淡出(Cross Fade) 效果.
01<filter id="demo5-arithmetic" x="0" y="0" width="100%" height="100%">02{/* 1. 源图像 */}03<feImage04href="/images/supercss/81.base/1.png"05x="0" y="0" width="400" height="250"06preserveAspectRatio="xMidYMid slice"07result="img1"08/>0910{/* 2. 第二个源:对原图进行反色处理, 模拟另一种风格 */}11<feColorMatrix12in="img1"13type="matrix"14values="-1 0 0 0 1150 -1 0 0 1160 0 -1 0 1170 0 0 1 0"18result="img2"19/>2021{/* 3. 算术混合22公式: result = k1*i1*i2 + k2*i1 + k3*i2 + k423这里我们只用 k2 和 k3 来做线性插值 (Cross Fade)24*/}25<feComposite26in="img1"27in2="img2"28operator="arithmetic"29k1="0"30k2={k2}31k3={k3}32k4="0"33/>34</filter>
我们可以利用 feTurbulence 生成噪点, 然后利用 arithmetic 算术运算, 将噪点从原始图像中减去, 形成斑驳的破损感.
公式:Result=k1∗i1∗i2+k2∗i1+k3∗i2+k4
我们使用 k2 = 1 保留原图, k3 = -1 减去噪点
01<filter id="grunge-text">02{/* 1. 生成粗糙的噪点纹理 */}03<feTurbulence type="fractalNoise" baseFrequency="0.05" numOctaves="3" result="noise" />0405{/* 2. 提高噪点对比度, 让黑白分明 */}06<feColorMatrix type="matrix" values="1 0 0 0 0070 1 0 0 0080 0 1 0 0090 0 0 6 -3"10in="noise" result="high-contrast-noise" />1112{/* 3. 算术合成:原图 - 噪点 */}13{/*14k2=1: 100% 原图15k3=-1.5: 减去 1.5倍的噪点亮度 (腐蚀效果)16这会吃掉文字的一部分17*/}18<feComposite operator="arithmetic" k1="0" k2="1" k3="-1.5" k4="0"19in="SourceGraphic" in2="high-contrast-noise" />20</filter>
使用 arithmetic 算术运算, 我们可以实现光效合成的效果.
公式:Result=i1+i2, 即 k2=1,k3=1
这会让两个重叠的像素亮度相加, 产生发光的效果
01<filter id="cyber-glow">02{/* 1. 提取原图 */}03<feImage href="#source-text" result="original"/>0405{/* 2. 偏移并模糊, 制造残影 A (青色) */}06<feOffset dx="-5" dy="0" in="SourceGraphic" result="off-a"/>07<feGaussianBlur stdDeviation="4" in="off-a" result="blur-a"/>08<feColorMatrix in="blur-a" type="matrix" values="0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0" result="cyan-glow"/>0910{/* 3. 偏移并模糊, 制造残影 B (洋红) */}11<feOffset dx="5" dy="0" in="SourceGraphic" result="off-b"/>12<feGaussianBlur stdDeviation="4" in="off-b" result="blur-b"/>13<feColorMatrix in="blur-b" type="matrix" values="1 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0" result="magenta-glow"/>1415{/* 4. 混合:青色 + 洋红 (Arithmetic Add) */}16<feComposite operator="arithmetic" k1="0" k2="1" k3="1" k4="0" in="cyan-glow" in2="magenta-glow" result="glow-mix"/>1718{/* 5. 混合:发光背景 + 原图 (White Text) */}19<feComposite operator="arithmetic" k1="0" k2="1" k3="1" k4="0" in="glow-mix" in2="SourceGraphic"/>20</filter>
operator="in"operator="out"operator="atop"operator="over"operator="arithmetic" 算术运算