胶片颗粒效果需模拟亮度依赖、成簇分布与微色偏三大物理特性:Canvas方案用Box-Muller生成正态噪声并按亮度缩放;SVG用feTurbulence配小baseFrequency与arithmetic混合;WebGL宜用预生成噪声纹理,禁用哈希函数。

filter 本身不支持胶片颗粒效果,硬套 blur()、contrast() 或 sepia() 只能模拟粗略色调,无法还原胶片物理特性——颗粒是亮度相关、成簇分布、带微色偏的噪声,不是均匀扰动。
Canvas 方案:用 getImageData 手动加噪
适合小图、低频更新、需精确控制颗粒行为的场景(如图片编辑器预览)。关键不是“加随机数”,而是模拟胶片响应曲线:
- 别用
Math.random()直接加 ±8 到每个通道——这会出数码噪点,不是胶片感 - 改用 Box-Muller 变换生成正态分布随机值,让 70% 噪声幅度 ≤2,少数达 5–6,更真实
- 颗粒强度要随原始像素亮度变化:
grainScale = 0.03 * (1 - luma)(luma = 0.299*r + 0.587*g + 0.114*b),暗部颗粒显眼,亮部几乎不可见 - 先生成 64×64 的低分辨率噪声图,再双线性缩放到原图尺寸——避免逐像素独立扰动,实现“成簇”物理感
- 噪声 RGB 各通道偏移不等:例如
r += noise.r * 3; g -= noise.g * 1; b -= noise.b * 1,模拟暖粒倾向
SVG feTurbulence:硬件加速但粒度有限
适合全站统一风格、需兼顾性能与兼容性的页面(如产品页 banner)。它不读像素,靠矢量噪声生成,但参数极敏感:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
-
baseFrequency必须设为0.002 0.003这类小值(不是 0.02 或 0.05),否则颗粒大过真实胶片(2–8μm 映射到屏幕≈0.001–0.005) -
type="turbulence"+numOctaves="2",单层 octaves 看起来像水波纹,两层才有层次 - 混合必须用
<feComposite operator="arithmetic" k1="0" k2="1" k3="1" k4="0">,比multiply更线性可控 - 整个
<svg>要设width="0" height="0" position="absolute"隐藏,否则可能触发意外 layout
WebGL 方案:高效但需管线支持
仅推荐已有 Three.js / WebGL 渲染流程的项目(如 3D 展示页、动态海报)。JS 生成噪声纹理比 shader 实时 hash 更稳:
立即学习“前端免费学习笔记(深入)”;
- 噪声纹理尺寸用
128×128或256×256,传入gl.texImage2D()的Uint8Array数据,非 PNG 文件 - 纹理 R 通道控亮度扰动,G/B 控色偏(如 R+2, G−1, B−1),避免纯灰度噪点
- 采样坐标写成
uv + noise.rg * grainScale,其中grainScale是uniform,典型值0.004 - 禁用
fract(sin(...))类哈希函数——移动端精度丢失导致 tile 边界明显,肉眼可见“拼图缝”
真正难的不是选哪种方案,而是理解胶片颗粒本质:它不是图像失真,而是光学+化学响应的结果。亮度依赖、空间相关性、轻微色偏,三者缺一,就只是“加了噪的图”,不是胶片。


















