live_beauty_filter 1.0.1
live_beauty_filter: ^1.0.1 copied to clipboard
A Flutter plugin for iOS that applies a real-time milky/soft beauty filter to the live camera feed, entirely on the GPU. Built on AVFoundation + CoreImage + Metal — zero CPU pixel processing.
live_beauty_filter #
A Flutter plugin for iOS that applies a real-time milky/soft beauty filter to the live camera feed, entirely on the GPU. Built on AVFoundation + CoreImage + Metal — zero CPU pixel processing.
Features #
- Live camera preview with milky filter applied in real-time
- GPU-only pipeline — no frame drops, no battery drain from CPU processing
- Adjustable filter intensity at runtime (0.0 → 1.0)
- Front camera with correct mirroring and portrait orientation
- Zero-copy frame delivery to Flutter via
Texturewidget - Filter chain: Gaussian blur → Bloom/Glow → Color grade (brightness + contrast lift)
Platform support #
| Platform | Supported |
|---|---|
| iOS | ✅ iOS 14+ |
| Android | ❌ Not supported |
Installation #
This is a local plugin — add it to your pubspec.yaml:
dependencies:
live_beauty_filter:
path: ../live_beauty_filter
Add camera permission to your app's ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera is used for the live beauty filter preview.</string>
Plugin registration is automatic via Flutter's GeneratedPluginRegistrant — no AppDelegate.swift changes needed.
Usage #
Basic live preview #
import 'package:live_beauty_filter/live_beauty_filter.dart';
class CameraScreen extends StatefulWidget {
const CameraScreen({super.key});
@override
State<CameraScreen> createState() => _CameraScreenState();
}
class _CameraScreenState extends State<CameraScreen> {
final _controller = MilkyFilterController();
@override
void initState() {
super.initState();
_controller.initialize().then((_) => setState(() {}));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!_controller.isInitialized) {
return const Center(child: CircularProgressIndicator());
}
return Texture(textureId: _controller.textureId!);
}
}
Adjusting filter intensity #
// intensity: 0.0 = no filter, 1.0 = full milky
await _controller.setFilterIntensity(0.7);
Drop-in widget with built-in intensity slider #
MilkyCameraView()
How the filter works #
The milky look is achieved by chaining three CoreImage GPU passes on every frame:
CVPixelBuffer (raw frame)
│
▼
CIGaussianBlur — light softening (radius scales with intensity)
│
▼
Bloom / Screen blend — blurred copy composited over original for glow
│
▼
CIColorControls — brightness +, contrast -, saturation slight -
│
▼
CIColorPolynomial — raises black point (lifted shadows, milky whites)
│
▼
CVPixelBuffer (filtered) → FlutterTexture → Texture() widget
All operations run on the Metal GPU via a CIContext created with useSoftwareRenderer: false. Frames are pooled with CVPixelBufferPool to eliminate per-frame heap allocation.
API reference #
MilkyFilterController #
| Method | Description |
|---|---|
initialize() |
Starts the camera session and registers the GPU texture |
setFilterIntensity(double) |
Updates filter strength live (0.0–1.0, default 0.7) |
dispose() |
Stops capture and releases the texture |
textureId |
The Flutter texture ID — pass to Texture(textureId: ...) |
isInitialized |
Whether the camera and filter pipeline are ready |
MilkyFilterPipeline (iOS internal) #
| Property | Type | Description |
|---|---|---|
intensity |
Float |
Master filter strength, updated from Flutter via MethodChannel |
Tuning the filter #
Edit the constants in MilkyFilterPipeline.swift to adjust the look:
// MilkyFilterPipeline.swift
// Blur softness (max radius at intensity 1.0)
let blurRadius = Double(intensity) * 4.0 // increase for dreamier blur
// Bloom strength (how much glow blends back in)
let bloomStrength = Double(intensity) * 0.45 // increase for stronger glow
// Color grade
let brightnessBoost = Double(intensity) * 0.08 // raise for brighter
let contrastReduction = 1.0 - Double(intensity) * 0.15 // lower = flatter/milkier
let saturationReduction = 1.0 - Double(intensity) * 0.12 // lower = more faded
// Blue channel lift in CIColorPolynomial
// inputBlueCoefficients: CIVector(x: intensity * 0.06, ...)
// Increase x for a cooler (more blue-white) milky tone
// Decrease for a warmer tone
Testing #
Integration tests must run on a physical device — the camera does not work on Simulator.
Grant camera permission by running the example app once manually first:
cd example
flutter run -d <your-device-id>
Then run the integration tests:
flutter test integration_test/plugin_integration_test.dart -d <your-device-id>
Expected output:
+2: All tests passed!
Requirements #
- iOS 14.0+
- Xcode 14+
- A physical device (camera does not work on Simulator)
- Swift 5.7+
File structure #
live_beauty_filter/
├── ios/
│ ├── Classes/
│ │ ├── LiveBeautyFilterPlugin.swift # Flutter plugin entry + MethodChannel
│ │ ├── MilkyCameraController.swift # AVCapture session + frame delivery
│ │ └── MilkyFilterPipeline.swift # CIFilter GPU chain (blur + bloom + grade)
│ ├── Resources/
│ │ └── PrivacyInfo.xcprivacy # App Store privacy manifest
│ └── live_beauty_filter.podspec
├── lib/
│ ├── live_beauty_filter.dart # Barrel export (main entry point)
│ ├── milky_filter_controller.dart # MethodChannel Dart wrapper
│ ├── milky_camera_view.dart # Drop-in Flutter widget with slider
│ ├── live_beauty_filter_platform_interface.dart
│ └── live_beauty_filter_method_channel.dart
├── example/
│ ├── lib/
│ │ └── main.dart # Example app — fullscreen filter preview
│ ├── integration_test/
│ │ └── plugin_integration_test.dart # Integration tests (run on physical device)
│ └── ios/
│ └── Runner/
│ └── Info.plist # Must contain NSCameraUsageDescription
├── pubspec.yaml
└── README.md
License #
This project is licensed under the MIT License see the LICENSE file for details.