在线体验:seamys.github.io/grainlab/ GitHub:github.com/seamys/grai…
为什么做这个
我喜欢胶片摄影,但胶片的感觉很难用手机照片还原——要么买昂贵的 Lightroom 预设, 要么用某些 App 加水印、逼你订阅。
所以我做了 GrainLab,免费、开源、不上传任何照片,直接在浏览器里跑。
功能介绍
- 🎞 胶片颗粒:基于亮度分布的颗粒,而不是简单的随机噪声
- 🌅 光晕(Halation):模拟胶片高光区域的红橙色渗透效果
- 💡 漏光(Light Leak):随机光斑效果
- 🔲 暗角(Vignette)
- 📈 色调曲线:RGB 独立曲线调整
- 🎨 色彩分级(Color Grading)
- ✨ 20+ 胶片预设:Kodak Portra、Fuji 400H、Ilford HP5 等风格
技术实现
技术栈
- Vue 3 + Composition API
- TypeScript
- Vite
- Canvas API
- Web Workers
- Pinia(状态管理)
核心:Web Worker 图像处理管线
所有滤镜运行在独立的 Worker 线程里,主线程不阻塞。
每个滤镜是一个纯函数 (ImageData, params) => ImageData,可以任意组合、调整顺序。
// 管线示例
const pipeline = [
applyToneCurve,
applyColorGrade,
applyGrain,
applyHalation,
applyVignette,
]
result = pipeline.reduce((img, fn) => fn(img, params), source)
胶片颗粒算法
真实胶片的颗粒分布和画面亮度相关——暗部和高光的颗粒结构不同。 我通过对每个像素的亮度值进行加权采样来模拟这一特性:
const luminance = (r * 0.299 + g * 0.587 + b * 0.114) / 255
const grainAmount = params.intensity * (1 - Math.abs(luminance - 0.5) * 0.8)
Halation(胶片光晕)实现
Halation 是光线穿透胶片乳剂层后在背面反射产生的红橙色光晕。 实现方式:提取高光区域 → 高斯模糊 → 染色(偏红橙)→ 叠加回原图。
部署
纯静态站,托管在 GitHub Pages,零运维成本。
后续计划
- 移动端手势优化
- 更多胶片预设
- 自定义预设保存与分享
欢迎 Star ⭐ 和提 Issue,有任何胶片效果的建议都可以留言!
GitHub:github.com/seamys/grai…
发帖设置
- 标签:
Vue.js前端开源Canvas工具 - 封面图:
docs/images/social-preview.png - 发布时间:工作日上午 10 点或下午 3 点