English | 中文
Offline ID photo tool: import a photo → one-tap AI background removal → pick a size → automatic face alignment + manual fine-tuning → background color → layout sheets → export with format and DPI.
The core image pipeline is ported from myidphoto-py (the Python version) into pure Dart. All inference runs locally — no data ever leaves your machine.
Main window: parameter sections on the left (import / size / background / crop / layout / export), single and sheet previews on the right (wheel pans, Ctrl+wheel zooms):
Live session: RMBG-2.0 cutout on a red background with the "Compare with original" wipe enabled in the crop pane (left of the line shows the cutout, right shows the original):
Sample outputs (single photo + 6-inch 3×3 sheet; white, white, custom light-purple and dark-red backgrounds):
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
- Import: drag & drop or pick a jpg/png; transparency detected automatically
- One-tap cutout: built-in u2netp model (onnxruntime CPU inference); switchable to RMBG-1.4 / RMBG-2.0 (in-app download); edge-refinement parameters (foreground/background thresholds + erosion) adjustable
- Size: 12 common ID photo presets (1-inch / 2-inch / visas…) + custom mm/px + DPI
- Crop: auto anchors (top/bottom/center/left/right); automatic alignment (YuNet face detection — eyes at 40% height, chin near 78%); manual box with drag/resize/wheel/arrow keys; "Compare with original" wipe slider for edge inspection
- Background: preset and custom colors; transparent export
- Layout: rows × columns, 6-inch / 5-inch / A4 paper, margins/spacing, crop marks
- Export: JPG (adjustable quality) / PNG, DPI-based pixel sizing, optional no-upscaling; remembered output folder
- History: undo/redo for cutout and restore — before/after comparison never loses the result
- Persistent settings: parameters and output folder survive restarts (shared_preferences)
- Log panel: status-bar button shows recent operations
- Bilingual UI (zh / en), switchable in the status bar; "About" shows version and licenses
- Help: the button at the bottom of the sidebar opens a full usage guide and author info
Windows is the primary target (windows/); the code stays buildable on macOS/Linux.
Every v* tag is built automatically by GitHub Actions and published to the Releases page (no installer, binaries are unsigned):
| Platform | File | Notes |
|---|---|---|
| Windows 10/11 x64 | myidphoto-<ver>-windows-x64.zip |
Unzip anywhere, run myidphoto_app.exe |
| Linux x64 | myidphoto-<ver>-linux-x86_64.AppImage |
chmod +x and run (needs FUSE/libfuse2, or extract with --appimage-extract) |
| Linux x64 | myidphoto-<ver>-linux-x64.tar.gz |
Extract and run myidphoto_app (GTK 3 required) |
- Windows SmartScreen: the binaries are not code-signed, so the first launch may show "Windows protected your PC" — click More info → Run anyway.
- Models directory: u2netp and YuNet are bundled; RMBG models download in-app at first use. The directory is
models/next to the exe when writable (portable layout), otherwise%APPDATA%\myidphoto\modelson Windows or~/.local/share/myidphoto/modelson Linux (AppImage mounts are read-only). - Every release includes a
SHA256SUMS.txtchecksum file.
flutter pub get
flutter run -d windows # development run
flutter test # unit / widget tests
flutter test integration_test/matting_test.dart -d windows # integration test (real inference)
flutter build windows --release # release buildBuild output: build/windows/x64/runner/Release/myidphoto_app.exe
- Unit/widget tests:
flutter testall green (97 tests) —- core pure functions: crop geometry (cross-checked against the Python version), size/canvas parsing, matting refinement (trimap/erosion), sheet composition
- state layer: parameter persistence, matting settings, proxy detection, model download state, cutout/restore history (undo/redo)
- UI interaction: box drag/handle resize/repeated Ctrl+wheel zoom (frame stays put on screen), preview zoom without tab flips, compare wipe toggle & drag, NumField typing, language switching persistence, layout-overflow hint, About dialog
- Static analysis:
flutter analyzezero issues - Integration tests (
-d windows): real onnxruntime inference regression (u2netp cutout + face alignment); RMBG cases run when the model file is present and are skipped otherwise
| Model | File | License |
|---|---|---|
| u2netp (portrait matting, bundled) | assets/models/u2netp.onnx |
Apache-2.0 (xuebinqin/U-2-Net) |
| YuNet (face detection, bundled) | assets/models/face_detection_yunet_2023mar.onnx |
Apache-2.0 (opencv/opencv_zoo) |
| RMBG-1.4 (optional, in-app ~176MB) | <model dir>/rmbg-1.4.onnx |
Non-commercial (briaai/RMBG-1.4) |
| RMBG-2.0 (optional, gated, in-app ~1GB) | <model dir>/rmbg-2.0.onnx |
Non-commercial (briaai/RMBG-2.0) |
Bundled models ship with the app; RMBG models download on demand into the model directory (system proxy auto-detected; gated models need a Hugging Face token). Inference runs on the local CPU via onnxruntime.
The integration-test portrait integration_test/fixtures/pd_portrait_960x1199.jpg is an official White House photo (US government work, public domain).
lib/
├── core/ # pure Dart core library (no Flutter deps, Isolate-safe)
│ # specs presets/parsing · geometry crop math · processor pipeline
├── state/ # Riverpod state: photo_source / editor_params / preview /
│ # matting_settings / matting_worker / export / app_locale
├── features/ # UI sections: import/size/background/crop/layout/export/home
├── widgets/ # shared widgets (NumField / ZoomableView etc.)
└── l10n/ # gen-l10n (zh template + en)
Design notes in docs/PLAN.md: core has no Flutter dependency; Isolate boundaries pass bytes and pure data only; preview and export share the same ProcessSpec.
Rafael.ren — GitHub: konosubakonoakua









