A clean, minimal desktop application for film photographers to easily fix camera metadata in scanned film images. Built with Electron and React, inspired by ImageOptim's simple drag-and-drop interface.
This repository is organized as a monorepo containing:
- 🖥️ Desktop App - Electron application for EXIF editing
- 🌐 Marketing Website - Next.js landing page
- 📦 Shared - Common types and utilities
- Simple Drag & Drop Interface: Drop images anywhere in the window to process them
- Camera Profile Management: Create and save camera/lens combinations for reuse
- Batch Processing: Process multiple images simultaneously
- Real-time Feedback: See processing results for each file instantly
- Dark Mode Support: Light, dark, and system theme options
- Persistent Storage: Profiles are saved between app sessions
- Cross-platform: Works on macOS, Windows, and Linux
- JPEG (.jpg, .jpeg)
- TIFF (.tiff, .tif)
✅ No external dependencies required! ExifTool is bundled with the application.
-
Clone the repository:
git clone https://github.com/yourusername/film-exif-editor.git cd film-exif-editor -
Install dependencies for all packages:
npm install
-
Start development servers:
# Start both desktop app and website concurrently npm run dev # Or start individually: npm run dev:desktop # Electron app on localhost:5173 npm run dev:website # Next.js site on localhost:3001
npm run buildnpm run build:desktop # Build Electron app
npm run build:website # Build Next.js websitenpm run dist # Package for current platformBuilt applications will be available in the release/ directory at the repository root.
The built website will be in packages/website/.next/ directory.
The project includes automated CI/CD with GitHub Actions:
-
Create a release:
./scripts/create-release.sh
-
GitHub Actions automatically:
- Builds for macOS, Windows, and Linux
- Creates a GitHub Release
- Uploads installers for all platforms
-
Download URLs available at:
https://github.com/YOUR_USERNAME/film-exif-editor/releases/latest
See DEPLOYMENT.md for complete deployment guide including:
- Setting up GitHub Actions
- Code signing (optional)
- Linking downloads from website
- Versioning and release management
- Click the "+" button in the footer
- Fill in the camera details:
- Profile Name: A descriptive name (e.g., "Nikon FM")
- Camera Make: Manufacturer (e.g., "Nikon")
- Camera Model: Model number (e.g., "FM")
- Lens: Optional lens information (e.g., "50mm f/1.8")
- Click "Save Profile"
- Select a camera profile from the dropdown (⋯ button)
- Drag and drop image files onto the window, or click to browse
- View processing results in real-time
- Click "Clear Results" to reset for the next batch
Click the theme button in the footer to switch between:
- ☀️ Light mode
- 🌙 Dark mode
- 🖥️ System (follows your OS preference)
- Frontend: React 18 + TypeScript + Vite
- Backend: Electron (main process)
- EXIF Processing: ExifTool (bundled via exiftool-vendored)
- Styling: Tailwind CSS v4 (website) / custom CSS (desktop)
- Icons: Iconify React
- Storage: electron-store
- Build: electron-builder
film-exif-editor/
├── packages/
│ ├── desktop/ # Electron desktop application
│ │ ├── electron/ # Electron main process
│ │ ├── src/ # React UI components
│ │ ├── package.json
│ │ └── vite.config.ts
│ ├── website/ # Next.js marketing website
│ │ ├── app/ # Next.js app directory
│ │ ├── public/ # Static assets
│ │ └── package.json
│ └── shared/ # Shared code and types
│ ├── src/
│ │ ├── types.ts # Common TypeScript interfaces
│ │ ├── utils.ts # Utility functions
│ │ └── index.ts # Package exports
│ └── package.json
├── package.json # Root workspace configuration
└── README.md
Root workspace commands:
npm run dev- Start both desktop app and website concurrentlynpm run dev:desktop- Start only the desktop appnpm run dev:website- Start only the marketing websitenpm run build- Build all packagesnpm run build:desktop- Build desktop appnpm run build:website- Build websitenpm run dist- Package desktop app for distributionnpm run clean- Clean all build outputsnpm run typecheck- Run TypeScript checks on all packages
The app uses Electron's IPC for secure communication. window.electronAPI (exposed via contextBridge in packages/desktop/electron/preload.ts) includes: profile CRUD, EXIF read/write with backups, geocoding, thumbnail extraction/caching, processing log, custom values, saved locations, GPX import, Mapbox token management, and window controls. See preload.ts for the full ElectronAPI interface.
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes and test thoroughly
- Commit with descriptive messages:
git commit -m "Add feature description" - Push to your fork:
git push origin feature-name - Submit a pull request
The app needs read/write access to image files. On macOS, you may need to grant permissions in System Preferences > Security & Privacy.
For processing many images, be patient as ExifTool processes each file individually for accuracy.
MIT License - see LICENSE file for details.
- Inspired by ImageOptim's clean interface design
- Uses ExifTool by Phil Harvey for EXIF manipulation (bundled via exiftool-vendored)
- Icons provided by Iconify
Built for film photographers, by film photographers 📸